listmonk-api 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,734 @@
1
+ #!/usr/bin/python
2
+ # coding: utf-8
3
+
4
+ import json
5
+ import requests
6
+ import urllib3
7
+ from base64 import b64encode
8
+
9
+ try:
10
+ from agent_utilities.decorators import require_auth
11
+ except ModuleNotFoundError:
12
+ from decorators import require_auth
13
+ try:
14
+ from agent_utilities.exceptions import (
15
+ AuthError,
16
+ UnauthorizedError,
17
+ ParameterError,
18
+ MissingParameterError,
19
+ )
20
+ except ModuleNotFoundError:
21
+ from exceptions import (
22
+ AuthError,
23
+ UnauthorizedError,
24
+ ParameterError,
25
+ MissingParameterError,
26
+ )
27
+
28
+
29
+ class Api(object):
30
+ def __init__(self, url=None, username=None, password=None, token=None, verify=True):
31
+ if url is None:
32
+ raise MissingParameterError
33
+
34
+ self._session = requests.Session()
35
+ self.url = url
36
+ self.headers = None
37
+ self.verify = verify
38
+
39
+ if self.verify is False:
40
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
41
+
42
+ if token:
43
+ self.headers = {
44
+ "Authorization": f"Bearer {token}",
45
+ "Content-Type": "application/json",
46
+ }
47
+ elif username and password:
48
+ user_pass = f"{username}:{password}".encode()
49
+ user_pass_encoded = b64encode(user_pass).decode()
50
+ self.headers = {
51
+ "Authorization": f"Basic {user_pass_encoded}",
52
+ "Content-Type": "application/json",
53
+ }
54
+ else:
55
+ raise MissingParameterError
56
+
57
+ response = self._session.get(
58
+ f"{self.url}/subscribers", headers=self.headers, verify=self.verify
59
+ )
60
+
61
+ if response.status_code == 403:
62
+ raise UnauthorizedError
63
+ elif response.status_code == 401:
64
+ raise AuthError
65
+ elif response.status_code == 404:
66
+ raise ParameterError
67
+
68
+ ####################################################################################################################
69
+ # Subscribers API #
70
+ ####################################################################################################################
71
+ @require_auth
72
+ def get_subscribers(self, query=None, list_id=None, max_pages=0, per_page=100):
73
+ data = None
74
+ response = self._session.get(
75
+ f"{self.url}/subscribers?per_page={per_page}&x-total-pages",
76
+ headers=self.headers,
77
+ verify=self.verify,
78
+ )
79
+ total_pages = int(response.headers["X-Total-Pages"])
80
+ response = []
81
+ subscriber_filter = f"?per_page={per_page}"
82
+ if query:
83
+ try:
84
+ data = json.dumps(query, indent=4)
85
+ except ValueError:
86
+ raise ParameterError
87
+ if list_id:
88
+ if not isinstance(list_id, int) and not isinstance(list_id, list):
89
+ raise ParameterError
90
+ if isinstance(list_id, list):
91
+ for single_list_id in list_id:
92
+ subscriber_filter = f"{subscriber_filter}&list_id={single_list_id}"
93
+ else:
94
+ subscriber_filter = f"{subscriber_filter}&list_id={list_id}"
95
+ if max_pages == 0 or max_pages > total_pages:
96
+ max_pages = total_pages
97
+ for page in range(0, max_pages):
98
+ response_page = self._session.get(
99
+ f"{self.url}/subscribers{subscriber_filter}&page={page}",
100
+ headers=self.headers,
101
+ data=data,
102
+ verify=self.verify,
103
+ )
104
+ response_page = json.loads(response_page.text.replace('"', '"'))
105
+ response = response + response_page
106
+ try:
107
+ return response.json()
108
+ except ValueError or AttributeError:
109
+ return response
110
+
111
+ @require_auth
112
+ def get_subscriber(self, subscriber_id=None):
113
+ if subscriber_id is None:
114
+ raise MissingParameterError
115
+ response = self._session.get(
116
+ f"{self.url}/subscribers/{subscriber_id}",
117
+ headers=self.headers,
118
+ verify=self.verify,
119
+ )
120
+ try:
121
+ return response.json()
122
+ except ValueError or AttributeError:
123
+ return response
124
+
125
+ @require_auth
126
+ def get_subscribers_from_list(self, list_id=None):
127
+ if list_id is None:
128
+ raise MissingParameterError
129
+ response = self._session.get(
130
+ f"{self.url}/subscribers/lists/{list_id}",
131
+ headers=self.headers,
132
+ verify=self.verify,
133
+ )
134
+ try:
135
+ return response.json()
136
+ except ValueError or AttributeError:
137
+ return response
138
+
139
+ @require_auth
140
+ def create_subscriber(
141
+ self,
142
+ email=None,
143
+ name=None,
144
+ status=None,
145
+ lists=None,
146
+ attributes=None,
147
+ preconfirm_subscriptions=True,
148
+ ):
149
+ if email is None or name is None or status is None:
150
+ raise MissingParameterError
151
+ if isinstance(email, str) and isinstance(name, str) and isinstance(status, str):
152
+ data = {"email": email, "name": name, "status": status}
153
+ else:
154
+ raise ParameterError
155
+ if lists and isinstance(lists, list):
156
+ data["lists"] = lists
157
+ if attributes and isinstance(attributes, dict):
158
+ data["attribs"] = attributes
159
+ if isinstance(preconfirm_subscriptions, bool):
160
+ data["preconfirm_subscriptions"] = preconfirm_subscriptions
161
+ try:
162
+ data = json.dumps(data, indent=4)
163
+ except ValueError:
164
+ raise ParameterError
165
+ response = self._session.post(
166
+ f"{self.url}/subscribers",
167
+ headers=self.headers,
168
+ data=data,
169
+ verify=self.verify,
170
+ )
171
+ try:
172
+ return response.json()
173
+ except ValueError or AttributeError:
174
+ return response
175
+
176
+ ####################################################################################################################
177
+ # Lists API #
178
+ ####################################################################################################################
179
+ @require_auth
180
+ def get_lists(
181
+ self, query=None, order_by=None, order=None, max_pages=0, per_page=100
182
+ ):
183
+ data = None
184
+ response = self._session.get(
185
+ f"{self.url}/lists?per_page={per_page}&x-total-pages",
186
+ headers=self.headers,
187
+ verify=self.verify,
188
+ )
189
+ total_pages = int(response.headers["X-Total-Pages"])
190
+ response = []
191
+ list_filter = f"?per_page={per_page}"
192
+ if query:
193
+ try:
194
+ data = json.dumps(query, indent=4)
195
+ except ValueError:
196
+ raise ParameterError
197
+ if order_by and order_by in ["name", "status", "created_at", "updated_at"]:
198
+ list_filter = f"{list_filter}&order_by={order_by}"
199
+ if order and order.upper() in ["ASC", "DESC"]:
200
+ list_filter = f"{list_filter}&order={order}"
201
+ if max_pages == 0 or max_pages > total_pages:
202
+ max_pages = total_pages
203
+ for page in range(0, max_pages):
204
+ response_page = self._session.get(
205
+ f"{self.url}/lists{list_filter}&page={page}",
206
+ headers=self.headers,
207
+ data=data,
208
+ verify=self.verify,
209
+ )
210
+ response_page = json.loads(response_page.text.replace('"', '"'))
211
+ response = response + response_page
212
+ try:
213
+ return response.json()
214
+ except ValueError or AttributeError:
215
+ return response
216
+
217
+ @require_auth
218
+ def get_list(self, list_id=None):
219
+ if list_id is None:
220
+ raise MissingParameterError
221
+ response = self._session.get(
222
+ f"{self.url}/lists/{list_id}", headers=self.headers, verify=self.verify
223
+ )
224
+ try:
225
+ return response.json()
226
+ except ValueError or AttributeError:
227
+ return response
228
+
229
+ @require_auth
230
+ def create_list(self, name=None, visibility_type=None, optin=None, tags=None):
231
+ if name is None or type is None or optin is None:
232
+ raise MissingParameterError
233
+ data = {}
234
+ if name:
235
+ if not isinstance(name, str):
236
+ raise ParameterError
237
+ else:
238
+ data["name"] = name
239
+ if visibility_type:
240
+ if not isinstance(visibility_type, str) and optin not in [
241
+ "private",
242
+ "public",
243
+ ]:
244
+ raise ParameterError
245
+ else:
246
+ data["type"] = visibility_type
247
+ if optin:
248
+ if not isinstance(optin, str) and optin not in ["single", "double"]:
249
+ raise ParameterError
250
+ else:
251
+ data["optin"] = optin
252
+ if tags:
253
+ if not isinstance(tags, list):
254
+ raise ParameterError
255
+ else:
256
+ data["tags"] = tags
257
+ try:
258
+ data = json.dumps(data, indent=4)
259
+ except ValueError:
260
+ raise ParameterError
261
+ response = self._session.post(
262
+ f"{self.url}/lists", data=data, headers=self.headers, verify=self.verify
263
+ )
264
+ try:
265
+ return response.json()
266
+ except ValueError or AttributeError:
267
+ return response
268
+
269
+ @require_auth
270
+ def edit_list(
271
+ self, list_id=None, name=None, visibility_type=None, optin=None, tags=None
272
+ ):
273
+ if list_id is None:
274
+ raise MissingParameterError
275
+ data = {}
276
+ if name:
277
+ if not isinstance(name, str):
278
+ raise ParameterError
279
+ else:
280
+ data["name"] = name
281
+ if visibility_type:
282
+ if not isinstance(visibility_type, str) and optin not in [
283
+ "private",
284
+ "public",
285
+ ]:
286
+ raise ParameterError
287
+ else:
288
+ data["type"] = visibility_type
289
+ if optin:
290
+ if not isinstance(optin, str) and optin not in ["single", "double"]:
291
+ raise ParameterError
292
+ else:
293
+ data["optin"] = optin
294
+ if tags:
295
+ if not isinstance(tags, list):
296
+ raise ParameterError
297
+ else:
298
+ data["tags"] = tags
299
+ try:
300
+ data = json.dumps(data, indent=4)
301
+ except ValueError:
302
+ raise ParameterError
303
+ response = self._session.put(
304
+ f"{self.url}/lists/{list_id}",
305
+ data=data,
306
+ headers=self.headers,
307
+ verify=self.verify,
308
+ )
309
+ try:
310
+ return response.json()
311
+ except ValueError or AttributeError:
312
+ return response
313
+
314
+ ####################################################################################################################
315
+ # Import API #
316
+ ####################################################################################################################
317
+ @require_auth
318
+ def get_subscriber_import_status(self):
319
+ response = self._session.get(
320
+ f"{self.url}/import/subscribers", headers=self.headers, verify=self.verify
321
+ )
322
+ try:
323
+ return response.json()
324
+ except ValueError or AttributeError:
325
+ return response
326
+
327
+ @require_auth
328
+ def get_subscriber_import_logs(self):
329
+ response = self._session.get(
330
+ f"{self.url}/import/subscribers/logs",
331
+ headers=self.headers,
332
+ verify=self.verify,
333
+ )
334
+ try:
335
+ return response.json()
336
+ except ValueError or AttributeError:
337
+ return response
338
+
339
+ @require_auth
340
+ def import_subscribers(
341
+ self, file=None, mode=None, delimiter=",", id_list=None, overwrite=True
342
+ ):
343
+ if file is None or mode is None or id_list is None:
344
+ raise MissingParameterError
345
+ if not isinstance(id_list, list):
346
+ raise ParameterError
347
+ if mode not in ["subscribe", "blocklist"]:
348
+ raise ParameterError
349
+ if not isinstance(delimiter, str):
350
+ raise ParameterError
351
+ if not isinstance(overwrite, bool):
352
+ raise ParameterError
353
+ data = {
354
+ "file": file,
355
+ "mode": mode,
356
+ "delim": delimiter,
357
+ "lists": id_list,
358
+ "overwrite": overwrite,
359
+ }
360
+ try:
361
+ data = json.dumps(data, indent=4)
362
+ except ValueError:
363
+ raise ParameterError
364
+ response = self._session.get(
365
+ f"{self.url}/import/subscribers/",
366
+ headers=self.headers,
367
+ data=data,
368
+ verify=self.verify,
369
+ )
370
+ try:
371
+ return response.json()
372
+ except ValueError or AttributeError:
373
+ return response
374
+
375
+ @require_auth
376
+ def delete_subscriber_import(self):
377
+ response = self._session.delete(
378
+ f"{self.url}/import/subscribers/logs",
379
+ headers=self.headers,
380
+ verify=self.verify,
381
+ )
382
+ try:
383
+ return response.json()
384
+ except ValueError or AttributeError:
385
+ return response
386
+
387
+ ####################################################################################################################
388
+ # Campaigns API #
389
+ ####################################################################################################################
390
+ @require_auth
391
+ def get_campaigns(
392
+ self, query=None, order_by=None, order=None, max_pages=0, per_page=100
393
+ ):
394
+ data = None
395
+ response = self._session.get(
396
+ f"{self.url}/campaigns?per_page={per_page}&x-total-pages",
397
+ headers=self.headers,
398
+ verify=self.verify,
399
+ )
400
+ total_pages = int(response.headers["X-Total-Pages"])
401
+ response = []
402
+ campaign_filter = f"?per_page={per_page}"
403
+ if query:
404
+ try:
405
+ data = json.dumps(query, indent=4)
406
+ except ValueError:
407
+ raise ParameterError
408
+ if order_by and order_by in ["name", "status", "created_at", "updated_at"]:
409
+ campaign_filter = f"{campaign_filter}&order_by={order_by}"
410
+ if order and order.upper() in ["ASC", "DESC"]:
411
+ campaign_filter = f"{campaign_filter}&order={order}"
412
+ if max_pages == 0 or max_pages > total_pages:
413
+ max_pages = total_pages
414
+ for page in range(0, max_pages):
415
+ response_page = self._session.get(
416
+ f"{self.url}/campaigns{campaign_filter}&page={page}",
417
+ headers=self.headers,
418
+ data=data,
419
+ verify=self.verify,
420
+ )
421
+ response_page = json.loads(response_page.text.replace('"', '"'))
422
+ response = response + response_page
423
+ try:
424
+ return response.json()
425
+ except ValueError or AttributeError:
426
+ return response
427
+
428
+ @require_auth
429
+ def get_campaign(self, campaign_id=None):
430
+ if campaign_id is None:
431
+ raise MissingParameterError
432
+ response = self._session.get(
433
+ f"{self.url}/campaigns/{campaign_id}",
434
+ headers=self.headers,
435
+ verify=self.verify,
436
+ )
437
+ try:
438
+ return response.json()
439
+ except ValueError or AttributeError:
440
+ return response
441
+
442
+ @require_auth
443
+ def get_campaign_preview(self, campaign_id=None):
444
+ if campaign_id is None:
445
+ raise MissingParameterError
446
+ response = self._session.get(
447
+ f"{self.url}/campaigns/{campaign_id}/preview",
448
+ headers=self.headers,
449
+ verify=self.verify,
450
+ )
451
+ try:
452
+ return response.json()
453
+ except ValueError or AttributeError:
454
+ return response
455
+
456
+ @require_auth
457
+ def get_campaign_stats(self, campaign_id=None):
458
+ if campaign_id is None:
459
+ raise MissingParameterError
460
+ response = self._session.get(
461
+ f"{self.url}/campaigns/{campaign_id}/running/stats?campaign_id={campaign_id}",
462
+ headers=self.headers,
463
+ verify=self.verify,
464
+ )
465
+ try:
466
+ return response.json()
467
+ except ValueError or AttributeError:
468
+ return response
469
+
470
+ @require_auth
471
+ def create_campaign(
472
+ self,
473
+ name=None,
474
+ subject=None,
475
+ lists=None,
476
+ from_email=None,
477
+ send_type=None,
478
+ content_type=None,
479
+ body=None,
480
+ altbody=None,
481
+ send_at=None,
482
+ messenger=None,
483
+ template_id=None,
484
+ tags=None,
485
+ ):
486
+ if (
487
+ name is None
488
+ or subject is None
489
+ or lists is None
490
+ or send_type is None
491
+ or content_type is None
492
+ or body is None
493
+ ):
494
+ raise MissingParameterError
495
+ data = {}
496
+ if isinstance(name, str):
497
+ data["name"] = name
498
+ if isinstance(subject, str):
499
+ data["subject"] = subject
500
+ if isinstance(lists, list):
501
+ data["lists"] = lists
502
+ if isinstance(from_email, str):
503
+ data["from_email"] = from_email
504
+ if send_type in ["regular", "optin"]:
505
+ data["send_type"] = send_type
506
+ else:
507
+ raise ParameterError
508
+ if content_type in ["richtext", "html", "markdown", "plain"]:
509
+ data["content_type"] = content_type
510
+ else:
511
+ raise ParameterError
512
+ if isinstance(body, str):
513
+ data["body"] = body
514
+ if isinstance(altbody, str):
515
+ data["altbody"] = altbody
516
+ if isinstance(send_at, str):
517
+ data["send_at"] = send_at
518
+ if isinstance(messenger, str):
519
+ data["messenger"] = messenger
520
+ if isinstance(template_id, int):
521
+ data["template_id"] = template_id
522
+ if isinstance(tags, list):
523
+ data["tags"] = tags
524
+ try:
525
+ data = json.dumps(data, indent=4)
526
+ except ValueError or AttributeError:
527
+ raise ParameterError
528
+ response = self._session.post(
529
+ f"{self.url}/campaigns", data=data, headers=self.headers, verify=self.verify
530
+ )
531
+ try:
532
+ return response.json()
533
+ except ValueError or AttributeError:
534
+ return response
535
+
536
+ @require_auth
537
+ def set_campaign_status(self, campaign_id=None, status=None):
538
+ if campaign_id is None or status is None:
539
+ raise MissingParameterError
540
+ if status and status in ["scheduled", "running", "paused", "cancelled"]:
541
+ data = {"status": status}
542
+ try:
543
+ data = json.dumps(data, indent=4)
544
+ except ValueError or AttributeError:
545
+ raise ParameterError
546
+ else:
547
+ raise ParameterError
548
+ response = self._session.put(
549
+ f"{self.url}/campaigns/{campaign_id}/status",
550
+ data=data,
551
+ headers=self.headers,
552
+ verify=self.verify,
553
+ )
554
+ try:
555
+ return response.json()
556
+ except ValueError or AttributeError:
557
+ return response
558
+
559
+ @require_auth
560
+ def delete_campaign(self, campaign_id=None):
561
+ if campaign_id is None:
562
+ raise MissingParameterError
563
+ response = self._session.delete(
564
+ f"{self.url}/campaigns/{campaign_id}",
565
+ headers=self.headers,
566
+ verify=self.verify,
567
+ )
568
+ try:
569
+ return response.json()
570
+ except ValueError or AttributeError:
571
+ return response
572
+
573
+ ####################################################################################################################
574
+ # Media API #
575
+ ####################################################################################################################
576
+ @require_auth
577
+ def get_media(self, media_id=None):
578
+ if media_id is None:
579
+ raise MissingParameterError
580
+ response = self._session.get(
581
+ f"{self.url}/media", headers=self.headers, verify=self.verify
582
+ )
583
+ try:
584
+ return response.json()
585
+ except ValueError or AttributeError:
586
+ return response
587
+
588
+ @require_auth
589
+ def upload_media(self, file=None):
590
+ if file is None:
591
+ raise MissingParameterError
592
+ data = {"file": file}
593
+ response = self._session.post(
594
+ f"{self.url}/media", data=data, headers=self.headers, verify=self.verify
595
+ )
596
+ try:
597
+ return response.json()
598
+ except ValueError or AttributeError:
599
+ return response
600
+
601
+ @require_auth
602
+ def delete_media(self, media_id=None):
603
+ if media_id is None:
604
+ raise MissingParameterError
605
+ response = self._session.delete(
606
+ f"{self.url}/media/{media_id}", headers=self.headers, verify=self.verify
607
+ )
608
+ try:
609
+ return response.json()
610
+ except ValueError or AttributeError:
611
+ return response
612
+
613
+ ####################################################################################################################
614
+ # Templates API #
615
+ ####################################################################################################################
616
+ @require_auth
617
+ def get_templates(self, max_pages=0, per_page=100):
618
+ data = None
619
+ response = self._session.get(
620
+ f"{self.url}/templates?per_page={per_page}&x-total-pages",
621
+ headers=self.headers,
622
+ verify=self.verify,
623
+ )
624
+ total_pages = int(response.headers["X-Total-Pages"])
625
+ response = []
626
+ campaign_filter = f"?per_page={per_page}"
627
+ if max_pages == 0 or max_pages > total_pages:
628
+ max_pages = total_pages
629
+ for page in range(0, max_pages):
630
+ response_page = self._session.get(
631
+ f"{self.url}/templates{campaign_filter}&page={page}",
632
+ headers=self.headers,
633
+ data=data,
634
+ verify=self.verify,
635
+ )
636
+ response_page = json.loads(response_page.text.replace('"', '"'))
637
+ response = response + response_page
638
+ try:
639
+ return response.json()
640
+ except ValueError or AttributeError:
641
+ return response
642
+
643
+ @require_auth
644
+ def get_template(self, template_id=None):
645
+ if template_id is None:
646
+ raise MissingParameterError
647
+ response = self._session.get(
648
+ f"{self.url}/templates/{template_id}",
649
+ headers=self.headers,
650
+ verify=self.verify,
651
+ )
652
+ try:
653
+ return response.json()
654
+ except ValueError or AttributeError:
655
+ return response
656
+
657
+ @require_auth
658
+ def get_template_preview(self, template_id=None):
659
+ if template_id is None:
660
+ raise MissingParameterError
661
+ response = self._session.get(
662
+ f"{self.url}/templates/{template_id}/preview",
663
+ headers=self.headers,
664
+ verify=self.verify,
665
+ )
666
+ try:
667
+ return response.json()
668
+ except ValueError or AttributeError:
669
+ return response
670
+
671
+ @require_auth
672
+ def set_default_template(self, template_id=None):
673
+ if template_id is None:
674
+ raise MissingParameterError
675
+ response = self._session.put(
676
+ f"{self.url}/templates/{template_id}/default",
677
+ headers=self.headers,
678
+ verify=self.verify,
679
+ )
680
+ try:
681
+ return response.json()
682
+ except ValueError or AttributeError:
683
+ return response
684
+
685
+ @require_auth
686
+ def delete_template(self, template_id=None):
687
+ if template_id is None:
688
+ raise MissingParameterError
689
+ response = self._session.delete(
690
+ f"{self.url}/templates/{template_id}",
691
+ headers=self.headers,
692
+ verify=self.verify,
693
+ )
694
+ try:
695
+ return response.json()
696
+ except ValueError or AttributeError:
697
+ return response
698
+
699
+ ####################################################################################################################
700
+ # Transactional API #
701
+ ####################################################################################################################
702
+ @require_auth
703
+ def transactional_message(
704
+ self,
705
+ template_id=None,
706
+ subscriber_email=None,
707
+ subscriber_id=None,
708
+ additional_data=None,
709
+ headers=None,
710
+ content_type=None,
711
+ ):
712
+ if template_id is None:
713
+ raise MissingParameterError
714
+ data = {"template_id": template_id}
715
+ if subscriber_id:
716
+ data["subscriber_id"]: subscriber_id
717
+ elif subscriber_email:
718
+ data["subscriber_email"]: subscriber_email
719
+ if additional_data:
720
+ data["data"]: additional_data
721
+ if headers:
722
+ data["headers"]: headers
723
+ if content_type:
724
+ if content_type in ["html", "markdown", "plain"]:
725
+ data["content_type"]: content_type
726
+ else:
727
+ raise ParameterError
728
+ response = self._session.post(
729
+ f"{self.url}/tx", data=data, headers=self.headers, verify=self.verify
730
+ )
731
+ try:
732
+ return response.json()
733
+ except ValueError or AttributeError:
734
+ return response