Skip to content
This repository was archived by the owner on Aug 8, 2023. It is now read-only.

Commit cc77c89

Browse files
author
Samuel Mendes
authored
Merge pull request #12 from TwilioDevEd/upgrade_dependencies
Upgrade to Django 2+ and remove Whitenoise
2 parents 83c65d2 + 02ed564 commit cc77c89

File tree

11 files changed

+160
-88
lines changed

11 files changed

+160
-88
lines changed

.coveragerc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ omit =
99
*/migrations/*
1010
*/tests.py
1111
*/tests/*.py
12+
venv/*

.travis.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
language: python
22
python:
3-
- '2.7'
4-
- '3.3'
5-
- '3.4'
3+
- '3.6'
4+
- '3.7'
65
install:
76
- pip install -r requirements.txt
87
- pip install coveralls

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2015 Twilio Inc.
3+
Copyright (c) 2019 Twilio Inc.
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ Use Twilio to send SMS alerts so that you never miss a critical issue.
99

1010
## Quickstart
1111

12-
This project is built using the [Django](https://www.djangoproject.com/) web framework. It runs on Python 2.7+ and Python 3.4+.
12+
This project is built using the [Django](https://www.djangoproject.com/) web framework. It runs on Python 3.6+.
1313

1414
To run the app locally, first clone this repository and `cd` into its directory. Then:
1515

1616
1. Create a new virtual environment:
17-
- If using vanilla [virtualenv](https://virtualenv.pypa.io/en/latest/):
17+
- If using vanilla with Python 3 [virtualenv](https://docs.python.org/3/library/venv.html):
1818

1919
```
20-
virtualenv venv
20+
python -m venv venv
2121
source venv/bin/activate
2222
```
2323
@@ -35,14 +35,14 @@ To run the app locally, first clone this repository and `cd` into its directory.
3535
3636
1. Copy the `.env_example` file to `.env`, and edit it to include your Twilio API credentials (found at https://www.twilio.com/user/account/voice)
3737
1. For the TWILIO_NUMBER variable you'll need to provision a new number in the [Manage Numbers page](https://www.twilio.com/user/account/phone-numbers/incoming) under your account. The phone number should be in E.164 format
38-
1. Run `source .env` to apply the environment variables (or even better, use [autoenv](https://github.com/kennethreitz/autoenv))
38+
1. (Optional) This project integrate [python-dotenv](https://github.com/theskumar/python-dotenv) to automatically load the `.env` file. Alternatively, you can run `source .env` to apply the environment variables (or even use [autoenv](https://github.com/kennethreitz/autoenv))
3939
1. Customize `config/administrators.json` with your phone number.
4040
1. Start the development server
4141
4242
```
4343
python manage.py runserver
4444
```
45-
1. Go to [http://localhost:8000/error](http://localhost:8000/error). You'll receive a text shortly with details on the exception.
45+
1. Go to [http://localhost:8000/error](http://localhost:8000/error/). You'll receive a text shortly with details on the exception.
4646
4747
## Run the tests
4848

requirements.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Requirements for server-notifications-django
22

3-
# Django (1.8 is a long-term support release)
4-
Django==1.8
5-
twilio==6.9.0
6-
whitenoise
3+
Django==2.2.5
4+
twilio==6.29.4
5+
python-dotenv==0.10.3
76

87
# Production dependencies
98
gunicorn
109

1110
# Test dependencies
11+
black
1212
coverage
13+
flake8
1314
mock
14-
six

twilio_notifications/middleware.py

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,89 @@
1-
from __future__ import unicode_literals
1+
import json
2+
import logging
3+
import os
24

5+
from django.conf import settings
6+
from django.core.exceptions import ImproperlyConfigured
7+
from django.http import HttpResponse
8+
from dotenv import load_dotenv
39
from twilio.rest import Client
4-
from django.core.exceptions import MiddlewareNotUsed
5-
import os
6-
import logging
7-
import json
810

911
logger = logging.getLogger(__name__)
1012

13+
dotenv_path = settings.PROJECT_PATH / '.env'
14+
logger.debug(f'Reading .env file at: {dotenv_path}')
15+
load_dotenv(dotenv_path=dotenv_path)
16+
17+
1118
MESSAGE = """[This is a test] ALERT! It appears the server is having issues.
12-
Exception: %s. Go to: http://newrelic.com for more details."""
19+
Exception: {0}"""
1320

14-
NOT_CONFIGURED_MESSAGE = """Cannot initialize Twilio notification
15-
middleware. Required enviroment variables TWILIO_ACCOUNT_SID, or
16-
TWILIO_AUTH_TOKEN or TWILIO_NUMBER missing"""
21+
NOT_CONFIGURED_MESSAGE = (
22+
"Required enviroment variables "
23+
"TWILIO_ACCOUNT_SID or TWILIO_AUTH_TOKEN or TWILIO_NUMBER missing."
24+
)
1725

1826

1927
def load_admins_file():
20-
with open('config/administrators.json') as adminsFile:
21-
admins = json.load(adminsFile)
22-
return admins
28+
admins_json_path = settings.PROJECT_PATH / 'config' / 'administrators.json'
29+
logger.debug(f'Loading administrators info from: {admins_json_path}')
30+
return json.loads(admins_json_path.read_text())
2331

2432

2533
def load_twilio_config():
26-
twilio_account_sid = os.environ.get('TWILIO_ACCOUNT_SID')
27-
twilio_auth_token = os.environ.get('TWILIO_AUTH_TOKEN')
28-
twilio_number = os.environ.get('TWILIO_NUMBER')
34+
logger.debug('Loading Twilio configuration')
35+
36+
twilio_account_sid = os.getenv('TWILIO_ACCOUNT_SID')
37+
twilio_auth_token = os.getenv('TWILIO_AUTH_TOKEN')
38+
twilio_number = os.getenv('TWILIO_NUMBER')
2939

3040
if not all([twilio_account_sid, twilio_auth_token, twilio_number]):
31-
logger.error(NOT_CONFIGURED_MESSAGE)
32-
raise MiddlewareNotUsed
41+
raise ImproperlyConfigured(NOT_CONFIGURED_MESSAGE)
3342

3443
return (twilio_number, twilio_account_sid, twilio_auth_token)
3544

3645

37-
class MessageClient(object):
46+
class MessageClient:
3847
def __init__(self):
39-
(twilio_number, twilio_account_sid,
40-
twilio_auth_token) = load_twilio_config()
48+
logger.debug('Initializing messaging client')
49+
50+
(
51+
twilio_number,
52+
twilio_account_sid,
53+
twilio_auth_token,
54+
) = load_twilio_config()
4155

4256
self.twilio_number = twilio_number
43-
self.twilio_client = Client(twilio_account_sid,
44-
twilio_auth_token)
57+
self.twilio_client = Client(twilio_account_sid, twilio_auth_token)
58+
59+
logger.debug('Twilio client initialized')
4560

4661
def send_message(self, body, to):
47-
self.twilio_client.messages.create(body=body, to=to,
48-
from_=self.twilio_number,
49-
# media_url=['https://demo.twilio.com/owl.png'])
50-
)
62+
self.twilio_client.messages.create(
63+
body=body, to=to, from_=self.twilio_number
64+
)
5165

5266

53-
class TwilioNotificationsMiddleware(object):
54-
def __init__(self):
67+
class TwilioNotificationsMiddleware:
68+
def __init__(self, get_response):
69+
logger.debug('Initializing Twilio notifications middleware')
70+
5571
self.administrators = load_admins_file()
5672
self.client = MessageClient()
73+
self.get_response = get_response
74+
75+
logger.debug('Twilio notifications middleware initialized')
76+
77+
def __call__(self, request):
78+
return self.get_response(request)
5779

5880
def process_exception(self, request, exception):
59-
exception_message = str(exception)
60-
message_to_send = MESSAGE % exception_message
81+
message_to_send = MESSAGE.format(exception)
6182

6283
for admin in self.administrators:
6384
self.client.send_message(message_to_send, admin['phone_number'])
6485

65-
logger.info('Administrators notified')
66-
67-
return None
86+
logger.info('Administrators notified!')
87+
return HttpResponse(
88+
"An error occured. Don't panic! Administrators are notified."
89+
)
Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
1-
from __future__ import unicode_literals
2-
from mock import patch, Mock
3-
from django.core.exceptions import MiddlewareNotUsed
4-
import unittest
51
import os
2+
import unittest
63

7-
from twilio_notifications.middleware import TwilioNotificationsMiddleware
8-
from twilio_notifications.middleware import MessageClient, load_twilio_config
9-
from twilio_notifications.middleware import MESSAGE
4+
from django.core.exceptions import ImproperlyConfigured
5+
from mock import Mock, patch
6+
from twilio_notifications.middleware import (
7+
MESSAGE,
8+
MessageClient,
9+
TwilioNotificationsMiddleware,
10+
load_admins_file,
11+
load_twilio_config,
12+
)
1013

1114

1215
class TestNotificationMiddleware(unittest.TestCase):
13-
1416
@patch('twilio_notifications.middleware.load_twilio_config')
1517
@patch('twilio_notifications.middleware.load_admins_file')
16-
def test_notify_on_exception(self, mock_load_admins_file,
17-
mock_load_twilio_config):
18+
def test_notify_on_exception(
19+
self, mock_load_admins_file, mock_load_twilio_config
20+
):
1821

1922
# Given
2023
admin_number = '+15550005555'
@@ -25,10 +28,13 @@ def test_notify_on_exception(self, mock_load_admins_file,
2528
]
2629

2730
mock_message_client = Mock(spec=MessageClient)
28-
mock_load_twilio_config.return_value = (sending_number,
29-
'4ccou1s1d', 'som3tok3n')
31+
mock_load_twilio_config.return_value = (
32+
sending_number,
33+
'4ccou1s1d',
34+
'som3tok3n',
35+
)
3036

31-
middleware = TwilioNotificationsMiddleware()
37+
middleware = TwilioNotificationsMiddleware(None)
3238
middleware.client = mock_message_client
3339

3440
exception_message = 'Some exception message'
@@ -38,7 +44,7 @@ def test_notify_on_exception(self, mock_load_admins_file,
3844

3945
# Then
4046
mock_message_client.send_message.assert_called_once_with(
41-
MESSAGE % exception_message, admin_number
47+
MESSAGE.format(exception_message), admin_number
4248
)
4349

4450
def test_correct_load_twilio_config(self):
@@ -48,13 +54,18 @@ def test_correct_load_twilio_config(self):
4854

4955
try:
5056
load_twilio_config()
51-
except MiddlewareNotUsed:
57+
except ImproperlyConfigured:
5258
self.fail('MiddlewareNotUsed when correctly configured')
5359

5460
def test_fail_load_twilio_config(self):
5561
os.environ['TWILIO_ACCOUNT_SID'] = 'some4acc0un1s1d'
5662
os.environ['TWILIO_AUTH_TOKEN'] = 'sometok3n'
5763
os.environ.pop('TWILIO_NUMBER')
5864

59-
with self.assertRaises(MiddlewareNotUsed):
65+
with self.assertRaises(ImproperlyConfigured):
6066
load_twilio_config()
67+
68+
def test_load_admins_file(self):
69+
administrators = load_admins_file()
70+
self.assertIsInstance(administrators, list)
71+
self.assertGreater(len(administrators), 0)

0 commit comments

Comments
 (0)