",
71 | },
72 | "DEFAULT_GATEWAY": "ses", # use amazon ses as the default gateway
73 | "FALLBACKS": ["default"] # if the default gateway fails, fallback to these gateways
74 | },
75 | "WHATSAPP": {
76 | "DEFAULT_GATEWAY": "waha",
77 | "GATEWAYS": {
78 | "waha": {
79 | "BASE_URL": "http://localhost:3000",
80 | "API_KEY": "xxxxxxx"
81 | }
82 | }
83 | },
84 | "TELEGRAM": {
85 | "DEFAULT_GATEWAY": "default",
86 | "GATEWAYS": {
87 | "default": {
88 | "API_ID": "xxxxxx",
89 | "API_HASH": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
90 | }
91 | }
92 | },
93 | "SMS": {
94 | "DEFAULT_GATEWAY": "TWILIO",
95 | "GATEWAYS": {
96 | "TWILIO": {
97 | "CLIENT": "magic_notifier.sms_clients.twilio_client.TwilioClient",
98 | "ACCOUNT": "account_sid",
99 | "TOKEN": "auth_token",
100 | "FROM_NUMBER": "+1234567890"
101 | }
102 | }
103 | },
104 | "USER_FROM_WS_TOKEN_FUNCTION": "magic_notifier.utils.get_user_from_ws_token",
105 | "GET_USER_NUMBER": "magic_notifier.utils.get_user_number",
106 | "THREADED": True
107 | }
108 | ```
109 |
110 | ### Key Settings
111 |
112 | - **EMAIL**: Configure your email gateway, including host, port, and credentials.
113 | - **WHATSAPP**: Define the WhatsApp gateway with its base URL.
114 | - **TELEGRAM**: Configure Telegram with API credentials.
115 | - **SMS**: Specify SMS gateways such as Twilio, Nexa, or others.
116 | - **THREADED**: Enable background processing for notifications.
117 |
118 | ---
119 |
120 | ## Usage
121 |
122 | ### Sending Notifications
123 |
124 | The `notify()` function is your gateway to all notification types.
125 |
126 | #### Basic Email Notification
127 | ```python
128 | from magic_notifier.notifier import notify
129 |
130 | user = User.objects.get(email="testuser@localhost")
131 | subject = "Welcome!"
132 | notify(["email"], subject, [user], final_message="Welcome to our platform!")
133 | ```
134 |
135 | #### SMS Notification with Template
136 | ```python
137 | notify(["sms"], "Account Alert", [user], template="account_alert")
138 | ```
139 |
140 | #### Multi-Channel Notification
141 | ```python
142 | notify(["email", "sms"], "System Update", [user], final_message="The system will be down for maintenance.")
143 | ```
144 |
145 | #### WhatsApp Notification
146 | ```python
147 | notify(["whatsapp"], "Welcome", [user], final_message="Hello! This is a WhatsApp test message.")
148 | ```
149 |
150 | #### Telegram Notification
151 | ```python
152 | notify(["telegram"], "Welcome", [user], final_message="Hello! This is a Telegram test message.")
153 | ```
154 |
155 | ### Passing Context to Templates
156 | You can pass additional context to your templates via the `context` argument, note that the `user`
157 | object is automatically passed:
158 |
159 | ```python
160 | context = {
161 | "discount": 20
162 | }
163 | notify(["email"], "Special Offer", [user], template="special_offer", context=context)
164 | ```
165 |
166 | In the template:
167 | ```html
168 | {% block content %}
169 | Hi {{ user.first_name }},
170 | We are excited to offer you a {{ discount }}% discount on your next purchase!
171 | {% endblock %}
172 | ```
173 |
174 | ### Overriding Gateways
175 | You can override default gateways directly when sending notifications:
176 |
177 | #### Override Email Gateway
178 | ```python
179 | notify(["email"], "Custom Email Gateway", [user], final_message="This uses a custom email gateway.", email_gateway="custom_gateway")
180 | ```
181 |
182 | #### Override SMS Gateway
183 | ```python
184 | notify(["sms"], "Custom SMS Gateway", [user], final_message="This uses a custom SMS gateway.", sms_gateway="custom_sms_gateway")
185 | ```
186 |
187 | #### Override WhatsApp Gateway
188 | ```python
189 | notify(["whatsapp"], "Custom WhatsApp Gateway", [user], final_message="This uses a custom WhatsApp gateway.", whatsapp_gateway="custom_whatsapp_gateway")
190 | ```
191 |
192 | #### Override Telegram Gateway
193 | ```python
194 | notify(["telegram"], "Custom Telegram Gateway", [user], final_message="This uses a custom Telegram gateway.", telegram_gateway="custom_telegram_gateway")
195 | ```
196 |
197 | ### Template Creation and Resolution
198 | When using templates, Django Magic Notifier looks for specific files depending on the notification channels. The template value designates a folder, not a file. Files are checked in the following order for each channel:
199 |
200 | - **Email**: `email.mjml` -> `email.html` -> `email.txt`
201 | - **SMS**: `sms.txt`
202 | - **WhatsApp**: `whatsapp.txt` -> `sms.txt`
203 | - **Telegram**: `telegram.txt` -> `sms.txt`
204 |
205 | If a file is not found, the next file in the sequence is checked. If no files are found, an error is raised.
206 |
207 | #### Example
208 | Suppose `notify()` is called as follows:
209 | ```python
210 | notify(["telegram"], "Welcome", [user], template="welcome")
211 | ```
212 |
213 | The following files will be checked in order:
214 | 1. `notifier/welcome/telegram.txt`
215 | 2. `notifier/welcome/sms.txt`
216 |
217 | Ensure that at least one of these files exists in your templates directory.
218 |
219 | ---
220 |
221 | ## Advanced Features
222 |
223 | ### Sending Files
224 | Attach files to your notifications:
225 | ```python
226 | files = ["/path/to/file.pdf"]
227 | notify(["email"], "Invoice", [user], final_message="Your invoice is attached.", files=files)
228 | ```
229 |
230 | ### Sending to Specific Receiver Groups
231 | The `notify()` function supports predefined values for the `receivers` argument to target specific user groups:
232 |
233 | #### Sending to Admin Users
234 | ```python
235 | notify(["email"], "Admin Alert", "admins", final_message="This is a message for all admin users.")
236 | ```
237 |
238 | #### Sending to Staff Users
239 | ```python
240 | notify(["email"], "Staff Notification", "staff", final_message="This message is for all staff members.")
241 | ```
242 |
243 | #### Sending to All Users
244 | ```python
245 | notify(["email"], "Global Announcement", "all", final_message="This is a message for all users.")
246 | ```
247 |
248 | #### Sending to Non-Staff Users
249 | ```python
250 | notify(["email"], "Non-Staff Update", "all-staff", final_message="This message is for users who are not staff.")
251 | ```
252 |
253 | #### Sending to Non-Admin Users
254 | ```python
255 | notify(["email"], "User Alert", "all-admins", final_message="This is a message for all users except admins.")
256 | ```
257 |
258 | ### Asynchronous Processing
259 | Enable threaded notifications for better performance:
260 | ```python
261 | notify(["sms"], "Alert", [user], final_message="This is a test.", threaded=True)
262 | ```
263 |
264 | ---
265 |
266 | ## Testing
267 |
268 | DMN includes comprehensive test cases for all features. To run tests:
269 | ```bash
270 | python manage.py test
271 | ```
272 |
273 | ---
274 |
275 | ## Roadmap
276 |
277 | - Extend support for additional messaging platforms.
278 |
279 | ---
280 |
281 | ## Contributing
282 |
283 | We welcome contributions! To get started, fork the repository, make your changes, and submit a pull request. Refer to our [contributing guidelines](CONTRIBUTING.md) for more details.
284 |
285 | ---
286 |
287 | ## License
288 |
289 | This project is licensed under the MIT License. See the LICENSE file for details.
290 |
291 | ---
292 |
293 | ## Support
294 |
295 | File an issue on [GitHub](https://github.com/jefcolbi/django-magic-notifier/issues).
296 |
297 |
--------------------------------------------------------------------------------
/magic_notifier/templates/base_notifier/email.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
46 |
56 |
61 |
62 |
63 |
66 |
67 |
80 |
91 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | |
109 | {% block product_name %}{% trans "Product Name" %}{% endblock %}
110 | |
111 |
112 |
113 | |
114 |
115 |
116 |
118 | |
119 |
120 |
121 |
122 |
123 |
124 | |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | |
141 | {% block h1_title %}{% trans "H1 title" %}{% endblock %}
142 | |
143 |
144 |
145 |
146 |
147 |
148 | |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 | {% block content %}
164 |
165 | {% endblock %}
166 |
167 |
168 |
169 |
170 | |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | |
187 |
188 | |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 | |
199 |
200 | |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 | |
211 |
212 | |
213 |
214 |
215 |
216 |
217 |
218 | |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
--------------------------------------------------------------------------------
/tests/core/tests.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import time
4 | from pathlib import Path
5 | from unittest import mock
6 | from unittest.mock import patch
7 |
8 | import requests
9 | from django.contrib.auth import get_user_model
10 | from django.core import mail
11 | from django.core.management import call_command
12 | from django.template.loader import render_to_string
13 | from django.test import TestCase, override_settings, LiveServerTestCase
14 |
15 | from magic_notifier.models import NotifyProfile, Notification
16 | from magic_notifier.notifier import notify
17 | from magic_notifier.pusher import Pusher
18 | from magic_notifier.telegramer import Telegramer
19 | from magic_notifier.telegram_clients.telethon import TelethonClient
20 | from magic_notifier.utils import NotificationBuilder
21 | from magic_notifier.serializers import NotificationSerializer
22 | from magic_notifier.whatsapp_clients.waha_client import WahaClient
23 | from magic_notifier.whatsapper import Whatsapper
24 | User = get_user_model()
25 |
26 |
27 | class EmailTestCase(TestCase):
28 | """Class to test emails sending"""
29 |
30 | @classmethod
31 | def setUpClass(cls):
32 | User.objects.create(username="user1", email="user1@localhost")
33 | User.objects.create(username="user2", email="user2@localhost")
34 | User.objects.create(username="user3", email="user3@localhost")
35 |
36 | User.objects.create(username="user4", email="user4@localhost", is_staff=True)
37 | User.objects.create(username="user5", email="user5@localhost", is_staff=True)
38 |
39 | User.objects.create(username="user6", email="user6@localhost",
40 | is_superuser=True, is_staff=True)
41 | return super().setUpClass()
42 |
43 | @classmethod
44 | def tearDownClass(cls):
45 | User.objects.all().delete()
46 | return super().tearDownClass()
47 |
48 | def test_simple_with_user(self):
49 | user = User(email="testuser@localhost", username="testuser")
50 |
51 | subject = "Test magic notifier"
52 | notify(["email"], subject, [user], final_message="Nice if you get this")
53 |
54 | self.assertGreater(len(mail.outbox), 0) # type: ignore
55 | first_message = mail.outbox[0] # type: ignore
56 | self.assertEqual(first_message.to, [user.email])
57 | self.assertEqual(first_message.subject, subject)
58 |
59 | def test_simple_with_user_threaded(self):
60 | user = User(email="testuser@localhost", username="testuser")
61 |
62 | subject = "Test magic notifier"
63 | notify(["email"], subject, [user], final_message="Nice if you get this",
64 | threaded=True)
65 | time.sleep(2)
66 |
67 | self.assertGreater(len(mail.outbox), 0) # type: ignore
68 | first_message = mail.outbox[0] # type: ignore
69 | self.assertEqual(first_message.to, [user.email])
70 | self.assertEqual(first_message.subject, subject)
71 |
72 | def test_simple_direct_email(self):
73 | subject = "Test magic notifier"
74 | notify(["email"], subject, ["testuser@localhost"], final_message="Nice if you get this")
75 |
76 | self.assertGreater(len(mail.outbox), 0) # type: ignore
77 | first_message = mail.outbox[0] # type: ignore
78 | self.assertEqual(first_message.to, ["testuser@localhost"])
79 | self.assertEqual(first_message.subject, subject)
80 |
81 | def test_template_html_txt_with_user(self):
82 | user = User(email="testuser@localhost", username="testuser")
83 |
84 | subject = "Test magic notifier"
85 | notify(["email"], subject, [user], template='base')
86 |
87 | self.assertGreater(len(mail.outbox), 0) # type: ignore
88 | first_message = mail.outbox[0] # type: ignore
89 | self.assertEqual(first_message.to, [user.email])
90 | self.assertEqual(first_message.subject, subject)
91 | self.assertEqual(len(first_message.alternatives), 1)
92 |
93 | def test_template_txt_with_user(self):
94 | user = User(email="testuser@localhost", username="testuser")
95 |
96 | subject = "Test magic notifier"
97 | notify(["email"], subject, [user], template='hello')
98 |
99 | self.assertGreater(len(mail.outbox), 0) # type: ignore
100 | first_message = mail.outbox[0] # type: ignore
101 | self.assertEqual(first_message.to, [user.email])
102 | self.assertEqual(first_message.subject, subject)
103 | self.assertEqual(len(first_message.alternatives), 0)
104 |
105 | def test_template_not_exist_with_user(self):
106 | user = User(email="testuser@localhost", username="testuser")
107 |
108 | subject = "Test magic notifier"
109 | notify(["email"], subject, [user], template='notexist')
110 |
111 | self.assertEqual(len(mail.outbox), 0) # type: ignore
112 |
113 | def test_command_test_email_template(self):
114 | call_command('test_email_template', 'hello', 'testuser@localhost')
115 |
116 | self.assertGreater(len(mail.outbox), 0) # type: ignore
117 | first_message = mail.outbox[0] # type: ignore
118 | self.assertEqual(first_message.to, ['testuser@localhost'])
119 | self.assertEqual(first_message.subject, 'Testing email template')
120 | self.assertEqual(len(first_message.alternatives), 0)
121 |
122 | def test_template_txt_with_user_with_files_filename(self):
123 | user = User(email="testuser@localhost", username="testuser")
124 |
125 | subject = "Test magic notifier"
126 | notify(["email"], subject, [user], template='hello',
127 | files=[str(Path(__file__).parent / "models.py")])
128 |
129 | self.assertGreater(len(mail.outbox), 0) # type: ignore
130 | first_message = mail.outbox[0] # type: ignore
131 | self.assertEqual(first_message.to, [user.email])
132 | self.assertEqual(first_message.subject, subject)
133 | self.assertEqual(len(first_message.alternatives), 0)
134 | self.assertGreater(len(first_message.attachments), 0)
135 |
136 | def test_template_txt_with_user_with_files_tuple_string(self):
137 | user = User(email="testuser@localhost", username="testuser")
138 |
139 | subject = "Test magic notifier"
140 | notify(["email"], subject, [user], template='hello',
141 | files=[("test.txt", "")])
142 |
143 | self.assertGreater(len(mail.outbox), 0) # type: ignore
144 | first_message = mail.outbox[0] # type: ignore
145 | self.assertEqual(first_message.to, [user.email])
146 | self.assertEqual(first_message.subject, subject)
147 | self.assertEqual(len(first_message.alternatives), 0)
148 | self.assertEqual(len(first_message.attachments), 0) # it failed
149 |
150 | def test_template_txt_with_user_with_files_tuple_filelike(self):
151 | user = User(email="testuser@localhost", username="testuser")
152 |
153 | subject = "Test magic notifier"
154 | with open(str(Path(__file__).parent / "models.py")) as fp:
155 | notify(["email"], subject, [user], template='hello',
156 | files=[("models.py", fp)])
157 |
158 | self.assertGreater(len(mail.outbox), 0) # type: ignore
159 | first_message = mail.outbox[0] # type: ignore
160 | self.assertEqual(first_message.to, [user.email])
161 | self.assertEqual(first_message.subject, subject)
162 | self.assertEqual(len(first_message.alternatives), 0)
163 | self.assertGreater(len(first_message.attachments), 0)
164 |
165 | def test_template_txt_with_user_with_files_bad(self):
166 | user = User(email="testuser@localhost", username="testuser")
167 |
168 | subject = "Test magic notifier"
169 | with open(str(Path(__file__).parent / "models.py")) as fp:
170 | notify(["email"], subject, [user], template='hello',
171 | files=[1])
172 |
173 | self.assertGreater(len(mail.outbox), 0) # type: ignore
174 | first_message = mail.outbox[0] # type: ignore
175 | self.assertEqual(first_message.to, [user.email])
176 | self.assertEqual(first_message.subject, subject)
177 | self.assertEqual(len(first_message.alternatives), 0)
178 | self.assertEqual(len(first_message.attachments), 0)
179 |
180 | def test_template_txt_with_user_with_files_filelike(self):
181 | user = User(email="testuser@localhost", username="testuser")
182 |
183 | subject = "Test magic notifier"
184 | with open(str(Path(__file__).parent / "models.py")) as fp:
185 | notify(["email"], subject, [user], template='hello',
186 | files=[fp])
187 |
188 | self.assertGreater(len(mail.outbox), 0) # type: ignore
189 | first_message = mail.outbox[0] # type: ignore
190 | self.assertEqual(first_message.to, [user.email])
191 | self.assertEqual(first_message.subject, subject)
192 | self.assertEqual(len(first_message.alternatives), 0)
193 | self.assertGreater(len(first_message.attachments), 0)
194 |
195 | def test_simple_with_string_all(self):
196 | subject = "Test magic notifier"
197 | notify(["email"], subject, "all", final_message="Nice if you get this")
198 |
199 | self.assertEqual(len(mail.outbox), 6) # type: ignore
200 |
201 | def test_simple_with_string_staff(self):
202 | subject = "Test magic notifier"
203 | notify(["email"], subject, "staff", final_message="Nice if you get this")
204 |
205 | self.assertEqual(len(mail.outbox), 3) # type: ignore
206 |
207 | def test_simple_with_string_admins(self):
208 | subject = "Test magic notifier"
209 | notify(["email"], subject, "admins", final_message="Nice if you get this")
210 |
211 | self.assertEqual(len(mail.outbox), 1) # type: ignore
212 |
213 | def test_simple_with_string_all_minus_admins(self):
214 | subject = "Test magic notifier"
215 | notify(["email"], subject, "all-admins", final_message="Nice if you get this")
216 |
217 | self.assertEqual(len(mail.outbox), 5) # type: ignore
218 |
219 | def test_simple_with_string_all_minius_staff(self):
220 | subject = "Test magic notifier"
221 | notify(["email"], subject, "all-staff", final_message="Nice if you get this")
222 |
223 | self.assertEqual(len(mail.outbox), 3) # type: ignore
224 |
225 | def test_simple_with_string_unknown(self):
226 | subject = "Test magic notifier"
227 | self.assertRaises(ValueError, notify, ["email"], subject, "unknown", final_message="Nice if you get this")
228 |
229 | def test_unknown_method(self):
230 | subject = "Test magic notifier"
231 | notify(["unknown"], subject, "all-staff", final_message="Nice if you get this")
232 | self.assertEqual(len(mail.outbox), 0) # type: ignore
233 |
234 | def test_amazon_ses(self):
235 | user = User(email=os.environ['TEST_EMAIL'], username="testuser")
236 |
237 | subject = "Test magic notifier"
238 | notify(["email"], subject, [user], final_message="Nice if you get this")
239 |
240 | self.assertGreater(len(mail.outbox), 0) # type: ignore
241 | first_message = mail.outbox[0] # type: ignore
242 | self.assertEqual(first_message.to, [user.email])
243 | self.assertEqual(first_message.subject, subject)
244 |
245 |
246 | sms_outbox = []
247 |
248 | class Sms:
249 |
250 | def __init__(self, number, message):
251 | self.number = number
252 | self.message = message
253 |
254 | def send_to_sms_outbox(*args, **kwargs):
255 | print(*args)
256 | try:
257 | url = args[-1]
258 | except:
259 | url = None
260 | params = kwargs.get('params')
261 | data = kwargs.get('data')
262 | if url:
263 | if url == 'https://smsvas.com/bulk/public/index.php/api/v1/sendsms':
264 | data = kwargs['json']
265 | sms_outbox.append(Sms(data['mobiles'], data['sms']))
266 | res = requests.Response()
267 | res.status_code = 200
268 | return res
269 | elif url == 'http://cheapglobalsms.com/api_v1':
270 | params = kwargs['params']
271 | sms_outbox.append(Sms(params['recipients'], params['message']))
272 | else:
273 | sms_outbox.append(Sms(data['To'], data['Body']))
274 | from twilio.http.response import Response
275 |
276 | return mock.MagicMock(spec=Response, status_code=200,
277 | text=json.dumps({
278 | "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
279 | "api_version": "2010-04-01",
280 | "body": "Hi there",
281 | "date_created": "Thu, 30 Jul 2015 20:12:31 +0000",
282 | "date_sent": "Thu, 30 Jul 2015 20:12:33 +0000",
283 | "date_updated": "Thu, 30 Jul 2015 20:12:33 +0000",
284 | "direction": "outbound-api",
285 | "error_code": None,
286 | "error_message": None,
287 | "from": "+15017122661",
288 | "messaging_service_sid": "MGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
289 | "num_media": "0",
290 | "num_segments": "1",
291 | "price": None,
292 | "price_unit": None,
293 | "sid": "SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
294 | "status": "sent",
295 | "subresource_uris": {
296 | "media": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages/SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Media.json"
297 | },
298 | "to": "+15558675310",
299 | "uri": "/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages/SMXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.json"
300 | }))
301 |
302 |
303 | def notifier_settings_for_global_cheap(*args, **kwargs):
304 | if args[0] == "SMS::DEFAULT_GATEWAY":
305 | return "CGS"
306 | elif args[0] == "SMS":
307 | return {
308 | "GATEWAYS": {
309 | "CGS": {
310 | "CLIENT": "magic_notifier.sms_clients.cgsms_client.CGSmsClient",
311 | "SUB_ACCOUNT": "sub_account",
312 | "SUB_ACCOUNT_PASSWORD": "sub_account_password"
313 | }
314 | }
315 | }
316 | elif args[0] == "GET_USER_NUMBER":
317 | return "magic_notifier.utils.get_user_number"
318 |
319 |
320 | def notifier_settings_for_nexa(*args, **kwargs):
321 | if args[0] == "SMS::DEFAULT_GATEWAY":
322 | return "NEXA"
323 | elif args[0] == "SMS":
324 | return {
325 | "GATEWAYS": {
326 | "NEXA": {
327 | "CLIENT": "magic_notifier.sms_clients.nexa_client.NexaSmsClient",
328 | "EMAIL": "sub_account",
329 | "PASSWORD": "sub_account_password",
330 | "SENDERID": "senderid"
331 | }
332 | }
333 | }
334 | elif args[0] == "GET_USER_NUMBER":
335 | return "magic_notifier.utils.get_user_number"
336 |
337 |
338 | def notifier_settings_for_twilio(*args, **kwargs):
339 | if args[0] == "SMS::DEFAULT_GATEWAY":
340 | return "TWILIO"
341 | elif args[0] == "SMS":
342 | return {
343 | "GATEWAYS": {
344 | "TWILIO": {
345 | "CLIENT": "magic_notifier.sms_clients.twilio_client.TwilioClient",
346 | "ACCOUNT": "sub_account",
347 | "TOKEN": "token",
348 | "FROM_NUMBER": "from_number"
349 | }
350 | }
351 | }
352 | elif args[0] == "GET_USER_NUMBER":
353 | return "magic_notifier.utils.get_user_number"
354 |
355 |
356 | class SmsTestCase(TestCase):
357 |
358 | @patch('magic_notifier.smser.get_settings', side_effect=notifier_settings_for_global_cheap)
359 | @patch('magic_notifier.sms_clients.cgsms_client.requests.get', side_effect=send_to_sms_outbox)
360 | def test_global_cheap_sms_client(self, mock_get_request, mock_get_settings):
361 | NOTIFIER = {
362 | "SMS":{
363 | "GATEWAYS": {
364 | "CGS": {
365 | "CLIENT": "magic_notifier.sms_clients.cgsms_client.CGSmsClient",
366 | "SUB_ACCOUNT": "sub_account",
367 | "SUB_ACCOUNT_PASSWORD": "sub_account_password"
368 | }
369 | },
370 | "DEFAULT_GATEWAY": "CGS"
371 | }
372 | }
373 |
374 | with self.settings(NOTIFIER=NOTIFIER):
375 | user = User.objects.create(email="testuser@localhost", username="testuser")
376 | not_profile = NotifyProfile.objects.create(phone_number="+237600000000",
377 | user=user)
378 |
379 | subject = "Test magic notifier"
380 | notify(["sms"], subject, [user], final_message="Nice if you get this")
381 |
382 | self.assertGreater(len(sms_outbox), 0) # type: ignore
383 | first_message = sms_outbox[0] # type: ignore
384 | self.assertEqual(first_message.number, not_profile.phone_number)
385 | self.assertEqual(first_message.message, "Nice if you get this")
386 |
387 | @patch('magic_notifier.smser.get_settings', side_effect=notifier_settings_for_twilio)
388 | @patch('twilio.http.http_client.TwilioHttpClient.request', side_effect=send_to_sms_outbox)
389 | def test_twilio_sms_client(self, mock_get_request, mock_get_settings):
390 | NOTIFIER = {
391 | "SMS": {
392 | "GATEWAYS": {
393 | "TWILIO": {
394 | "CLIENT": "magic_notifier.sms_clients.twilio_client.TwilioClient",
395 | "ACCOUNT": "sub_account",
396 | "TOKEN": "token",
397 | "FROM_NUMBER": "from_number"
398 | }
399 | },
400 | "DEFAULT_GATEWAY": "TWILIO"
401 | }
402 | }
403 |
404 | with self.settings(NOTIFIER=NOTIFIER):
405 | user = User.objects.create(email="testuser@localhost", username="testuser")
406 | not_profile = NotifyProfile.objects.create(phone_number="+237600000000",
407 | user=user)
408 |
409 | subject = "Test magic notifier"
410 | notify(["sms"], subject, [user], final_message="Nice if you get this")
411 |
412 | self.assertGreater(len(sms_outbox), 0) # type: ignore
413 | first_message = sms_outbox[0] # type: ignore
414 | self.assertEqual(first_message.number, not_profile.phone_number)
415 | self.assertEqual(first_message.message, "Nice if you get this")
416 |
417 | @patch('magic_notifier.smser.get_settings', side_effect=notifier_settings_for_nexa)
418 | @patch('magic_notifier.sms_clients.cgsms_client.requests.post', side_effect=send_to_sms_outbox)
419 | def test_nexa_sms_client(self, mock_get_request, mock_get_settings):
420 | NOTIFIER = {
421 | "SMS": {
422 | "GATEWAYS": {
423 | "NEXA": {
424 | "CLIENT": "magic_notifier.sms_clients.nexa_client.NexaSmsClient",
425 | "EMAIL": "sub_account",
426 | "PASSWORD": "sub_account_password",
427 | "SENDERID": "senderid"
428 | }
429 | },
430 | "DEFAULT_GATEWAY": "NEXA"
431 | }
432 | }
433 |
434 | with self.settings(NOTIFIER=NOTIFIER):
435 | user = User.objects.create(email="testuser@localhost", username="testuser")
436 | not_profile = NotifyProfile.objects.create(phone_number="+237600000000",
437 | user=user)
438 |
439 | subject = "Test magic notifier"
440 | notify(["sms"], subject, [user], final_message="Nice if you get this")
441 |
442 | self.assertGreater(len(sms_outbox), 0) # type: ignore
443 | first_message = sms_outbox[0] # type: ignore
444 | self.assertEqual(first_message.number, not_profile.phone_number)
445 | self.assertEqual(first_message.message, "Nice if you get this")
446 |
447 |
448 | class PushNotificationTestCase(TestCase):
449 |
450 | def test_load_json(self):
451 | ctx = {
452 | 'text': 'yes',
453 | 'actions': [
454 | {
455 | 'text': 'wow',
456 | 'url': 'accept',
457 | 'method': 'post'
458 | },
459 | {
460 | 'text': 'meow',
461 | 'url': 'deny',
462 | 'method': 'get'
463 | }
464 | ],
465 | 'data': {
466 | 'love': 'you',
467 | 'hate': 'no-one'
468 | }
469 | }
470 | push_content = render_to_string(f"notifier/base/push.json", ctx)
471 | print(push_content)
472 | self.assertIsInstance(json.loads(push_content), dict)
473 |
474 | def test_notification_builder_class(self):
475 | notif = NotificationBuilder("just a test").text("This is just a test").type('test', 'test_sub')\
476 | .link("http://lol").save()
477 | self.assertIsInstance(notif, Notification)
478 | seria = NotificationSerializer(instance=notif)
479 | print(notif)
480 | print(seria.data)
481 |
482 | def test_send_push_via_fcm(self):
483 | user = User.objects.create_user('testuser')
484 | notify(['push'], "Super cool", [user], template="testfcm", remove_notification_fields=['action', 'link',
485 | 'is_visible', 'is_encrypted'])
486 |
487 |
488 | class LivePushNotificationTestCase(LiveServerTestCase):
489 | port = 8001
490 |
491 | def test_pusher_class(self):
492 | user = User.objects.create_user('testuser')
493 | NotifyProfile.objects.create(user=user)
494 | pusher = Pusher("just a test", [user], 'base', {'data': {'love': 'you', 'hate': 'no-one'},
495 | 'actions': [{'text':'accept', 'method':'post', 'url': 'http://'}]})
496 | notif = pusher.send()
497 | self.assertIsInstance(notif, Notification)
498 | seria = NotificationSerializer(instance=notif)
499 | print(notif)
500 | print(seria.data)
501 |
502 |
503 | class WhatsappNotificationTestCase(LiveServerTestCase):
504 |
505 | def test_waha_client(self):
506 | WahaClient.send("+237693138363", "Bonjour Jeff")
507 |
508 | def test_whatsapper(self):
509 | user = User.objects.create(email="testuser@localhost", username="testuser",
510 | first_name="Jeff", last_name="Matt")
511 | not_profile = NotifyProfile.objects.create(phone_number="+237693138363",
512 | user=user)
513 | whatsapper = Whatsapper([user], {},
514 | final_message="Bonjour Jeff Matt. Votre code est XXXX")
515 | whatsapper.send()
516 |
517 |
518 | class TelegramNotificationTestCase(LiveServerTestCase):
519 |
520 | def test_telethon_client(self):
521 | TelethonClient.send("+237693138363", "Jeff", "Matt",
522 | "Bonjour Jeff. Voici ton code XXXX.", "default")
523 |
524 | def test_telegramer(self):
525 | user = User.objects.create(email="testuser@localhost", username="testuser",
526 | first_name="Jeff", last_name="Matt")
527 | not_profile = NotifyProfile.objects.create(phone_number="+237693138363",
528 | user=user)
529 | telegramer = Telegramer([user], {},
530 | final_message="Bonjour Jeff Matt")
531 | telegramer.send()
532 |
533 |
534 | class AllNotificationTestCase(LiveServerTestCase):
535 |
536 | def test_01_send_to_sms_whatsapp_telegram(self):
537 | user = User.objects.create(email="testuser@localhost", username="testuser",
538 | first_name="Jeff", last_name="Matt")
539 | not_profile = NotifyProfile.objects.create(phone_number="+237698948836",
540 | user=user)
541 | notify(['sms', 'whatsapp', 'telegram'], "Code",[user],
542 | final_message="Salut Fedim Stephane. Ceci est un test d'envoi de code")
543 |
--------------------------------------------------------------------------------