django-nativemojo 0.1.10__py3-none-any.whl → 0.1.16__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.
- django_nativemojo-0.1.16.dist-info/METADATA +138 -0
- django_nativemojo-0.1.16.dist-info/RECORD +302 -0
- mojo/__init__.py +1 -1
- mojo/apps/account/management/__init__.py +5 -0
- mojo/apps/account/management/commands/__init__.py +6 -0
- mojo/apps/account/management/commands/serializer_admin.py +651 -0
- mojo/apps/account/migrations/0004_user_avatar.py +20 -0
- mojo/apps/account/migrations/0005_group_last_activity.py +18 -0
- mojo/apps/account/migrations/0006_add_device_tracking_models.py +72 -0
- mojo/apps/account/migrations/0007_delete_userdevicelocation.py +16 -0
- mojo/apps/account/migrations/0008_userdevicelocation.py +33 -0
- mojo/apps/account/migrations/0009_geolocatedip_subnet.py +18 -0
- mojo/apps/account/migrations/0010_group_avatar.py +20 -0
- mojo/apps/account/migrations/0011_user_org_registereddevice_pushconfig_and_more.py +118 -0
- mojo/apps/account/migrations/0012_remove_pushconfig_apns_key_file_and_more.py +21 -0
- mojo/apps/account/migrations/0013_pushconfig_test_mode_alter_pushconfig_apns_enabled_and_more.py +28 -0
- mojo/apps/account/migrations/0014_notificationdelivery_data_payload_and_more.py +48 -0
- mojo/apps/account/models/__init__.py +2 -0
- mojo/apps/account/models/device.py +281 -0
- mojo/apps/account/models/group.py +319 -15
- mojo/apps/account/models/member.py +29 -5
- mojo/apps/account/models/push/__init__.py +4 -0
- mojo/apps/account/models/push/config.py +112 -0
- mojo/apps/account/models/push/delivery.py +93 -0
- mojo/apps/account/models/push/device.py +66 -0
- mojo/apps/account/models/push/template.py +99 -0
- mojo/apps/account/models/user.py +369 -19
- mojo/apps/account/rest/__init__.py +2 -0
- mojo/apps/account/rest/device.py +39 -0
- mojo/apps/account/rest/group.py +9 -0
- mojo/apps/account/rest/push.py +187 -0
- mojo/apps/account/rest/user.py +100 -6
- mojo/apps/account/services/__init__.py +1 -0
- mojo/apps/account/services/push.py +363 -0
- mojo/apps/aws/migrations/0001_initial.py +206 -0
- mojo/apps/aws/migrations/0002_emaildomain_can_recv_emaildomain_can_send_and_more.py +28 -0
- mojo/apps/aws/migrations/0003_mailbox_is_domain_default_mailbox_is_system_default_and_more.py +31 -0
- mojo/apps/aws/migrations/0004_s3bucket.py +39 -0
- mojo/apps/aws/migrations/0005_alter_emaildomain_region_delete_s3bucket.py +21 -0
- mojo/apps/aws/models/__init__.py +19 -0
- mojo/apps/aws/models/email_attachment.py +99 -0
- mojo/apps/aws/models/email_domain.py +218 -0
- mojo/apps/aws/models/email_template.py +132 -0
- mojo/apps/aws/models/incoming_email.py +197 -0
- mojo/apps/aws/models/mailbox.py +288 -0
- mojo/apps/aws/models/sent_message.py +175 -0
- mojo/apps/aws/rest/__init__.py +7 -0
- mojo/apps/aws/rest/email.py +33 -0
- mojo/apps/aws/rest/email_ops.py +183 -0
- mojo/apps/aws/rest/messages.py +32 -0
- mojo/apps/aws/rest/s3.py +64 -0
- mojo/apps/aws/rest/send.py +101 -0
- mojo/apps/aws/rest/sns.py +403 -0
- mojo/apps/aws/rest/templates.py +19 -0
- mojo/apps/aws/services/__init__.py +32 -0
- mojo/apps/aws/services/email.py +390 -0
- mojo/apps/aws/services/email_ops.py +548 -0
- mojo/apps/docit/__init__.py +6 -0
- mojo/apps/docit/markdown_plugins/syntax_highlight.py +25 -0
- mojo/apps/docit/markdown_plugins/toc.py +12 -0
- mojo/apps/docit/migrations/0001_initial.py +113 -0
- mojo/apps/docit/migrations/0002_alter_book_modified_by_alter_page_modified_by.py +26 -0
- mojo/apps/docit/migrations/0003_alter_book_group.py +20 -0
- mojo/apps/docit/models/__init__.py +17 -0
- mojo/apps/docit/models/asset.py +231 -0
- mojo/apps/docit/models/book.py +227 -0
- mojo/apps/docit/models/page.py +319 -0
- mojo/apps/docit/models/page_revision.py +203 -0
- mojo/apps/docit/rest/__init__.py +10 -0
- mojo/apps/docit/rest/asset.py +17 -0
- mojo/apps/docit/rest/book.py +22 -0
- mojo/apps/docit/rest/page.py +22 -0
- mojo/apps/docit/rest/page_revision.py +17 -0
- mojo/apps/docit/services/__init__.py +11 -0
- mojo/apps/docit/services/docit.py +315 -0
- mojo/apps/docit/services/markdown.py +44 -0
- mojo/apps/fileman/README.md +8 -8
- mojo/apps/fileman/backends/base.py +76 -70
- mojo/apps/fileman/backends/filesystem.py +86 -86
- mojo/apps/fileman/backends/s3.py +409 -108
- mojo/apps/fileman/migrations/0001_initial.py +106 -0
- mojo/apps/fileman/migrations/0002_filemanager_parent_alter_filemanager_max_file_size.py +24 -0
- mojo/apps/fileman/migrations/0003_remove_file_fileman_fil_upload__c4bc35_idx_and_more.py +25 -0
- mojo/apps/fileman/migrations/0004_remove_file_original_filename_and_more.py +39 -0
- mojo/apps/fileman/migrations/0005_alter_file_upload_token.py +18 -0
- mojo/apps/fileman/migrations/0006_file_download_url_filemanager_forever_urls.py +23 -0
- mojo/apps/fileman/migrations/0007_remove_filemanager_forever_urls_and_more.py +22 -0
- mojo/apps/fileman/migrations/0008_file_category.py +18 -0
- mojo/apps/fileman/migrations/0009_rename_file_path_file_storage_file_path.py +18 -0
- mojo/apps/fileman/migrations/0010_filerendition.py +33 -0
- mojo/apps/fileman/migrations/0011_alter_filerendition_original_file.py +19 -0
- mojo/apps/fileman/models/__init__.py +1 -5
- mojo/apps/fileman/models/file.py +240 -58
- mojo/apps/fileman/models/manager.py +427 -31
- mojo/apps/fileman/models/rendition.py +118 -0
- mojo/apps/fileman/renderer/__init__.py +111 -0
- mojo/apps/fileman/renderer/audio.py +403 -0
- mojo/apps/fileman/renderer/base.py +205 -0
- mojo/apps/fileman/renderer/document.py +404 -0
- mojo/apps/fileman/renderer/image.py +222 -0
- mojo/apps/fileman/renderer/utils.py +297 -0
- mojo/apps/fileman/renderer/video.py +304 -0
- mojo/apps/fileman/rest/__init__.py +1 -18
- mojo/apps/fileman/rest/upload.py +22 -32
- mojo/apps/fileman/signals.py +58 -0
- mojo/apps/fileman/tasks.py +254 -0
- mojo/apps/fileman/utils/__init__.py +40 -16
- mojo/apps/incident/migrations/0005_incidenthistory.py +39 -0
- mojo/apps/incident/migrations/0006_alter_incident_state.py +18 -0
- mojo/apps/incident/migrations/0007_event_uid.py +18 -0
- mojo/apps/incident/migrations/0008_ticket_ticketnote.py +55 -0
- mojo/apps/incident/migrations/0009_incident_status.py +18 -0
- mojo/apps/incident/migrations/0010_event_country_code.py +18 -0
- mojo/apps/incident/migrations/0011_incident_country_code.py +18 -0
- mojo/apps/incident/migrations/0012_alter_incident_status.py +18 -0
- mojo/apps/incident/models/__init__.py +2 -0
- mojo/apps/incident/models/event.py +35 -0
- mojo/apps/incident/models/history.py +36 -0
- mojo/apps/incident/models/incident.py +3 -1
- mojo/apps/incident/models/ticket.py +62 -0
- mojo/apps/incident/reporter.py +21 -1
- mojo/apps/incident/rest/__init__.py +1 -0
- mojo/apps/incident/rest/event.py +7 -1
- mojo/apps/incident/rest/ticket.py +43 -0
- mojo/apps/jobs/__init__.py +489 -0
- mojo/apps/jobs/adapters.py +24 -0
- mojo/apps/jobs/cli.py +616 -0
- mojo/apps/jobs/daemon.py +370 -0
- mojo/apps/jobs/examples/sample_jobs.py +376 -0
- mojo/apps/jobs/examples/webhook_examples.py +203 -0
- mojo/apps/jobs/handlers/__init__.py +5 -0
- mojo/apps/jobs/handlers/webhook.py +317 -0
- mojo/apps/jobs/job_engine.py +734 -0
- mojo/apps/jobs/keys.py +203 -0
- mojo/apps/jobs/local_queue.py +363 -0
- mojo/apps/jobs/management/__init__.py +3 -0
- mojo/apps/jobs/management/commands/__init__.py +3 -0
- mojo/apps/jobs/manager.py +1327 -0
- mojo/apps/jobs/migrations/0001_initial.py +97 -0
- mojo/apps/jobs/migrations/0002_alter_job_max_retries_joblog.py +39 -0
- mojo/apps/jobs/models/__init__.py +6 -0
- mojo/apps/jobs/models/job.py +441 -0
- mojo/apps/jobs/rest/__init__.py +2 -0
- mojo/apps/jobs/rest/control.py +466 -0
- mojo/apps/jobs/rest/jobs.py +421 -0
- mojo/apps/jobs/scheduler.py +571 -0
- mojo/apps/jobs/services/__init__.py +6 -0
- mojo/apps/jobs/services/job_actions.py +465 -0
- mojo/apps/jobs/settings.py +209 -0
- mojo/apps/logit/migrations/0004_alter_log_level.py +18 -0
- mojo/apps/logit/models/log.py +7 -1
- mojo/apps/metrics/__init__.py +8 -1
- mojo/apps/metrics/redis_metrics.py +198 -0
- mojo/apps/metrics/rest/__init__.py +3 -0
- mojo/apps/metrics/rest/categories.py +266 -0
- mojo/apps/metrics/rest/helpers.py +48 -0
- mojo/apps/metrics/rest/permissions.py +99 -0
- mojo/apps/metrics/rest/values.py +277 -0
- mojo/apps/metrics/utils.py +19 -2
- mojo/decorators/auth.py +6 -1
- mojo/decorators/http.py +47 -3
- mojo/helpers/aws/__init__.py +45 -0
- mojo/helpers/aws/ec2.py +804 -0
- mojo/helpers/aws/iam.py +748 -0
- mojo/helpers/aws/inbound_email.py +309 -0
- mojo/helpers/aws/kms.py +413 -0
- mojo/helpers/aws/s3.py +451 -11
- mojo/helpers/aws/ses.py +483 -0
- mojo/helpers/aws/ses_domain.py +959 -0
- mojo/helpers/aws/sns.py +461 -0
- mojo/helpers/crypto/__init__.py +1 -1
- mojo/helpers/crypto/utils.py +15 -0
- mojo/helpers/dates.py +18 -0
- mojo/helpers/location/__init__.py +2 -0
- mojo/helpers/location/countries.py +262 -0
- mojo/helpers/location/geolocation.py +196 -0
- mojo/helpers/logit.py +37 -0
- mojo/helpers/redis/__init__.py +2 -0
- mojo/helpers/redis/adapter.py +606 -0
- mojo/helpers/redis/client.py +48 -0
- mojo/helpers/redis/pool.py +225 -0
- mojo/helpers/request.py +8 -0
- mojo/helpers/response.py +14 -2
- mojo/helpers/settings/__init__.py +2 -0
- mojo/helpers/{settings.py → settings/helper.py} +1 -37
- mojo/helpers/settings/parser.py +132 -0
- mojo/middleware/auth.py +1 -1
- mojo/middleware/cors.py +40 -0
- mojo/middleware/logging.py +131 -12
- mojo/middleware/mojo.py +10 -0
- mojo/models/rest.py +494 -65
- mojo/models/secrets.py +98 -3
- mojo/serializers/__init__.py +106 -0
- mojo/serializers/core/__init__.py +90 -0
- mojo/serializers/core/cache/__init__.py +121 -0
- mojo/serializers/core/cache/backends.py +518 -0
- mojo/serializers/core/cache/base.py +102 -0
- mojo/serializers/core/cache/disabled.py +181 -0
- mojo/serializers/core/cache/memory.py +287 -0
- mojo/serializers/core/cache/redis.py +533 -0
- mojo/serializers/core/cache/utils.py +454 -0
- mojo/serializers/core/manager.py +550 -0
- mojo/serializers/core/serializer.py +475 -0
- mojo/serializers/examples/settings.py +322 -0
- mojo/serializers/formats/csv.py +393 -0
- mojo/serializers/formats/localizers.py +509 -0
- mojo/serializers/{models.py → simple.py} +38 -15
- mojo/serializers/suggested_improvements.md +388 -0
- testit/client.py +1 -1
- testit/helpers.py +35 -4
- testit/runner.py +23 -6
- django_nativemojo-0.1.10.dist-info/METADATA +0 -96
- django_nativemojo-0.1.10.dist-info/RECORD +0 -194
- mojo/apps/metrics/rest/db.py +0 -0
- mojo/apps/notify/README.md +0 -91
- mojo/apps/notify/README_NOTIFICATIONS.md +0 -566
- mojo/apps/notify/admin.py +0 -52
- mojo/apps/notify/handlers/example_handlers.py +0 -516
- mojo/apps/notify/handlers/ses/__init__.py +0 -25
- mojo/apps/notify/handlers/ses/bounce.py +0 -0
- mojo/apps/notify/handlers/ses/complaint.py +0 -25
- mojo/apps/notify/handlers/ses/message.py +0 -86
- mojo/apps/notify/management/commands/__init__.py +0 -1
- mojo/apps/notify/management/commands/process_notifications.py +0 -370
- mojo/apps/notify/mod +0 -0
- mojo/apps/notify/models/__init__.py +0 -12
- mojo/apps/notify/models/account.py +0 -128
- mojo/apps/notify/models/attachment.py +0 -24
- mojo/apps/notify/models/bounce.py +0 -68
- mojo/apps/notify/models/complaint.py +0 -40
- mojo/apps/notify/models/inbox.py +0 -113
- mojo/apps/notify/models/inbox_message.py +0 -173
- mojo/apps/notify/models/outbox.py +0 -129
- mojo/apps/notify/models/outbox_message.py +0 -288
- mojo/apps/notify/models/template.py +0 -30
- mojo/apps/notify/providers/aws.py +0 -73
- mojo/apps/notify/rest/ses.py +0 -0
- mojo/apps/notify/utils/__init__.py +0 -2
- mojo/apps/notify/utils/notifications.py +0 -404
- mojo/apps/notify/utils/parsing.py +0 -202
- mojo/apps/notify/utils/render.py +0 -144
- mojo/apps/tasks/README.md +0 -118
- mojo/apps/tasks/__init__.py +0 -11
- mojo/apps/tasks/manager.py +0 -489
- mojo/apps/tasks/rest/__init__.py +0 -2
- mojo/apps/tasks/rest/hooks.py +0 -0
- mojo/apps/tasks/rest/tasks.py +0 -62
- mojo/apps/tasks/runner.py +0 -174
- mojo/apps/tasks/tq_handlers.py +0 -14
- mojo/helpers/aws/setup_email.py +0 -0
- mojo/helpers/redis.py +0 -10
- mojo/models/meta.py +0 -262
- mojo/ws4redis/README.md +0 -174
- mojo/ws4redis/__init__.py +0 -2
- mojo/ws4redis/client.py +0 -283
- mojo/ws4redis/connection.py +0 -327
- mojo/ws4redis/exceptions.py +0 -32
- mojo/ws4redis/redis.py +0 -183
- mojo/ws4redis/servers/base.py +0 -86
- mojo/ws4redis/servers/django.py +0 -171
- mojo/ws4redis/servers/uwsgi.py +0 -63
- mojo/ws4redis/settings.py +0 -45
- mojo/ws4redis/utf8validator.py +0 -128
- mojo/ws4redis/websocket.py +0 -403
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.16.dist-info}/LICENSE +0 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.16.dist-info}/NOTICE +0 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.16.dist-info}/WHEEL +0 -0
- /mojo/apps/{notify → aws}/__init__.py +0 -0
- /mojo/apps/{notify/handlers → aws/migrations}/__init__.py +0 -0
- /mojo/apps/{notify/management → docit/markdown_plugins}/__init__.py +0 -0
- /mojo/apps/{notify/providers → docit/migrations}/__init__.py +0 -0
- /mojo/apps/{notify/rest → fileman/migrations}/__init__.py +0 -0
- /mojo/{ws4redis/servers → apps/jobs/examples}/__init__.py +0 -0
- /mojo/apps/{fileman/models/render.py → jobs/migrations/__init__.py} +0 -0
- /mojo/{serializers → rest}/openapi.py +0 -0
- /mojo/{apps/fileman/rest/__init__ → serializers/formats/__init__.py} +0 -0
@@ -0,0 +1,262 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
Provides a simple lookup for converting ISO 3166-1 alpha-2 country codes to country names.
|
4
|
+
"""
|
5
|
+
|
6
|
+
COUNTRY_CODES = {
|
7
|
+
'AF': 'Afghanistan',
|
8
|
+
'AX': 'Åland Islands',
|
9
|
+
'AL': 'Albania',
|
10
|
+
'DZ': 'Algeria',
|
11
|
+
'AS': 'American Samoa',
|
12
|
+
'AD': 'Andorra',
|
13
|
+
'AO': 'Angola',
|
14
|
+
'AI': 'Anguilla',
|
15
|
+
'AQ': 'Antarctica',
|
16
|
+
'AG': 'Antigua and Barbuda',
|
17
|
+
'AR': 'Argentina',
|
18
|
+
'AM': 'Armenia',
|
19
|
+
'AW': 'Aruba',
|
20
|
+
'AU': 'Australia',
|
21
|
+
'AT': 'Austria',
|
22
|
+
'AZ': 'Azerbaijan',
|
23
|
+
'BS': 'Bahamas',
|
24
|
+
'BH': 'Bahrain',
|
25
|
+
'BD': 'Bangladesh',
|
26
|
+
'BB': 'Barbados',
|
27
|
+
'BY': 'Belarus',
|
28
|
+
'BE': 'Belgium',
|
29
|
+
'BZ': 'Belize',
|
30
|
+
'BJ': 'Benin',
|
31
|
+
'BM': 'Bermuda',
|
32
|
+
'BT': 'Bhutan',
|
33
|
+
'BO': 'Bolivia, Plurinational State of',
|
34
|
+
'BQ': 'Bonaire, Sint Eustatius and Saba',
|
35
|
+
'BA': 'Bosnia and Herzegovina',
|
36
|
+
'BW': 'Botswana',
|
37
|
+
'BV': 'Bouvet Island',
|
38
|
+
'BR': 'Brazil',
|
39
|
+
'IO': 'British Indian Ocean Territory',
|
40
|
+
'BN': 'Brunei Darussalam',
|
41
|
+
'BG': 'Bulgaria',
|
42
|
+
'BF': 'Burkina Faso',
|
43
|
+
'BI': 'Burundi',
|
44
|
+
'CV': 'Cabo Verde',
|
45
|
+
'KH': 'Cambodia',
|
46
|
+
'CM': 'Cameroon',
|
47
|
+
'CA': 'Canada',
|
48
|
+
'KY': 'Cayman Islands',
|
49
|
+
'CF': 'Central African Republic',
|
50
|
+
'TD': 'Chad',
|
51
|
+
'CL': 'Chile',
|
52
|
+
'CN': 'China',
|
53
|
+
'CX': 'Christmas Island',
|
54
|
+
'CC': 'Cocos (Keeling) Islands',
|
55
|
+
'CO': 'Colombia',
|
56
|
+
'KM': 'Comoros',
|
57
|
+
'CG': 'Congo',
|
58
|
+
'CD': 'Congo, the Democratic Republic of the',
|
59
|
+
'CK': 'Cook Islands',
|
60
|
+
'CR': 'Costa Rica',
|
61
|
+
'CI': "Côte d'Ivoire",
|
62
|
+
'HR': 'Croatia',
|
63
|
+
'CU': 'Cuba',
|
64
|
+
'CW': 'Curaçao',
|
65
|
+
'CY': 'Cyprus',
|
66
|
+
'CZ': 'Czechia',
|
67
|
+
'DK': 'Denmark',
|
68
|
+
'DJ': 'Djibouti',
|
69
|
+
'DM': 'Dominica',
|
70
|
+
'DO': 'Dominican Republic',
|
71
|
+
'EC': 'Ecuador',
|
72
|
+
'EG': 'Egypt',
|
73
|
+
'SV': 'El Salvador',
|
74
|
+
'GQ': 'Equatorial Guinea',
|
75
|
+
'ER': 'Eritrea',
|
76
|
+
'EE': 'Estonia',
|
77
|
+
'SZ': 'Eswatini',
|
78
|
+
'ET': 'Ethiopia',
|
79
|
+
'FK': 'Falkland Islands (Malvinas)',
|
80
|
+
'FO': 'Faroe Islands',
|
81
|
+
'FJ': 'Fiji',
|
82
|
+
'FI': 'Finland',
|
83
|
+
'FR': 'France',
|
84
|
+
'GF': 'French Guiana',
|
85
|
+
'PF': 'French Polynesia',
|
86
|
+
'TF': 'French Southern Territories',
|
87
|
+
'GA': 'Gabon',
|
88
|
+
'GM': 'Gambia',
|
89
|
+
'GE': 'Georgia',
|
90
|
+
'DE': 'Germany',
|
91
|
+
'GH': 'Ghana',
|
92
|
+
'GI': 'Gibraltar',
|
93
|
+
'GR': 'Greece',
|
94
|
+
'GL': 'Greenland',
|
95
|
+
'GD': 'Grenada',
|
96
|
+
'GP': 'Guadeloupe',
|
97
|
+
'GU': 'Guam',
|
98
|
+
'GT': 'Guatemala',
|
99
|
+
'GG': 'Guernsey',
|
100
|
+
'GN': 'Guinea',
|
101
|
+
'GW': 'Guinea-Bissau',
|
102
|
+
'GY': 'Guyana',
|
103
|
+
'HT': 'Haiti',
|
104
|
+
'HM': 'Heard Island and McDonald Islands',
|
105
|
+
'VA': 'Holy See',
|
106
|
+
'HN': 'Honduras',
|
107
|
+
'HK': 'Hong Kong',
|
108
|
+
'HU': 'Hungary',
|
109
|
+
'IS': 'Iceland',
|
110
|
+
'IN': 'India',
|
111
|
+
'ID': 'Indonesia',
|
112
|
+
'IR': 'Iran, Islamic Republic of',
|
113
|
+
'IQ': 'Iraq',
|
114
|
+
'IE': 'Ireland',
|
115
|
+
'IM': 'Isle of Man',
|
116
|
+
'IL': 'Israel',
|
117
|
+
'IT': 'Italy',
|
118
|
+
'JM': 'Jamaica',
|
119
|
+
'JP': 'Japan',
|
120
|
+
'JE': 'Jersey',
|
121
|
+
'JO': 'Jordan',
|
122
|
+
'KZ': 'Kazakhstan',
|
123
|
+
'KE': 'Kenya',
|
124
|
+
'KI': 'Kiribati',
|
125
|
+
'KP': "Korea, Democratic People's Republic of",
|
126
|
+
'KR': 'Korea, Republic of',
|
127
|
+
'KW': 'Kuwait',
|
128
|
+
'KG': 'Kyrgyzstan',
|
129
|
+
'LA': "Lao People's Democratic Republic",
|
130
|
+
'LV': 'Latvia',
|
131
|
+
'LB': 'Lebanon',
|
132
|
+
'LS': 'Lesotho',
|
133
|
+
'LR': 'Liberia',
|
134
|
+
'LY': 'Libya',
|
135
|
+
'LI': 'Liechtenstein',
|
136
|
+
'LT': 'Lithuania',
|
137
|
+
'LU': 'Luxembourg',
|
138
|
+
'MO': 'Macao',
|
139
|
+
'MG': 'Madagascar',
|
140
|
+
'MW': 'Malawi',
|
141
|
+
'MY': 'Malaysia',
|
142
|
+
'MV': 'Maldives',
|
143
|
+
'ML': 'Mali',
|
144
|
+
'MT': 'Malta',
|
145
|
+
'MH': 'Marshall Islands',
|
146
|
+
'MQ': 'Martinique',
|
147
|
+
'MR': 'Mauritania',
|
148
|
+
'MU': 'Mauritius',
|
149
|
+
'YT': 'Mayotte',
|
150
|
+
'MX': 'Mexico',
|
151
|
+
'FM': 'Micronesia, Federated States of',
|
152
|
+
'MD': 'Moldova, Republic of',
|
153
|
+
'MC': 'Monaco',
|
154
|
+
'MN': 'Mongolia',
|
155
|
+
'ME': 'Montenegro',
|
156
|
+
'MS': 'Montserrat',
|
157
|
+
'MA': 'Morocco',
|
158
|
+
'MZ': 'Mozambique',
|
159
|
+
'MM': 'Myanmar',
|
160
|
+
'NA': 'Namibia',
|
161
|
+
'NR': 'Nauru',
|
162
|
+
'NP': 'Nepal',
|
163
|
+
'NL': 'Netherlands',
|
164
|
+
'NC': 'New Caledonia',
|
165
|
+
'NZ': 'New Zealand',
|
166
|
+
'NI': 'Nicaragua',
|
167
|
+
'NE': 'Niger',
|
168
|
+
'NG': 'Nigeria',
|
169
|
+
'NU': 'Niue',
|
170
|
+
'NF': 'Norfolk Island',
|
171
|
+
'MK': 'North Macedonia',
|
172
|
+
'MP': 'Northern Mariana Islands',
|
173
|
+
'NO': 'Norway',
|
174
|
+
'OM': 'Oman',
|
175
|
+
'PK': 'Pakistan',
|
176
|
+
'PW': 'Palau',
|
177
|
+
'PS': 'Palestine, State of',
|
178
|
+
'PA': 'Panama',
|
179
|
+
'PG': 'Papua New Guinea',
|
180
|
+
'PY': 'Paraguay',
|
181
|
+
'PE': 'Peru',
|
182
|
+
'PH': 'Philippines',
|
183
|
+
'PN': 'Pitcairn',
|
184
|
+
'PL': 'Poland',
|
185
|
+
'PT': 'Portugal',
|
186
|
+
'PR': 'Puerto Rico',
|
187
|
+
'QA': 'Qatar',
|
188
|
+
'RE': 'Réunion',
|
189
|
+
'RO': 'Romania',
|
190
|
+
'RU': 'Russian Federation',
|
191
|
+
'RW': 'Rwanda',
|
192
|
+
'BL': 'Saint Barthélemy',
|
193
|
+
'SH': 'Saint Helena, Ascension and Tristan da Cunha',
|
194
|
+
'KN': 'Saint Kitts and Nevis',
|
195
|
+
'LC': 'Saint Lucia',
|
196
|
+
'MF': 'Saint Martin (French part)',
|
197
|
+
'PM': 'Saint Pierre and Miquelon',
|
198
|
+
'VC': 'Saint Vincent and the Grenadines',
|
199
|
+
'WS': 'Samoa',
|
200
|
+
'SM': 'San Marino',
|
201
|
+
'ST': 'Sao Tome and Principe',
|
202
|
+
'SA': 'Saudi Arabia',
|
203
|
+
'SN': 'Senegal',
|
204
|
+
'RS': 'Serbia',
|
205
|
+
'SC': 'Seychelles',
|
206
|
+
'SL': 'Sierra Leone',
|
207
|
+
'SG': 'Singapore',
|
208
|
+
'SX': 'Sint Maarten (Dutch part)',
|
209
|
+
'SK': 'Slovakia',
|
210
|
+
'SI': 'Slovenia',
|
211
|
+
'SB': 'Solomon Islands',
|
212
|
+
'SO': 'Somalia',
|
213
|
+
'ZA': 'South Africa',
|
214
|
+
'GS': 'South Georgia and the South Sandwich Islands',
|
215
|
+
'SS': 'South Sudan',
|
216
|
+
'ES': 'Spain',
|
217
|
+
'LK': 'Sri Lanka',
|
218
|
+
'SD': 'Sudan',
|
219
|
+
'SR': 'Suriname',
|
220
|
+
'SJ': 'Svalbard and Jan Mayen',
|
221
|
+
'SE': 'Sweden',
|
222
|
+
'CH': 'Switzerland',
|
223
|
+
'SY': 'Syrian Arab Republic',
|
224
|
+
'TW': 'Taiwan, Province of China',
|
225
|
+
'TJ': 'Tajikistan',
|
226
|
+
'TZ': 'Tanzania, United Republic of',
|
227
|
+
'TH': 'Thailand',
|
228
|
+
'TL': 'Timor-Leste',
|
229
|
+
'TG': 'Togo',
|
230
|
+
'TK': 'Tokelau',
|
231
|
+
'TO': 'Tonga',
|
232
|
+
'TT': 'Trinidad and Tobago',
|
233
|
+
'TN': 'Tunisia',
|
234
|
+
'TR': 'Turkey',
|
235
|
+
'TM': 'Turkmenistan',
|
236
|
+
'TC': 'Turks and Caicos Islands',
|
237
|
+
'TV': 'Tuvalu',
|
238
|
+
'UG': 'Uganda',
|
239
|
+
'UA': 'Ukraine',
|
240
|
+
'AE': 'United Arab Emirates',
|
241
|
+
'GB': 'United Kingdom of Great Britain and Northern Ireland',
|
242
|
+
'US': 'United States of America',
|
243
|
+
'UM': 'United States Minor Outlying Islands',
|
244
|
+
'UY': 'Uruguay',
|
245
|
+
'UZ': 'Uzbekistan',
|
246
|
+
'VU': 'Vanuatu',
|
247
|
+
'VE': 'Venezuela, Bolivarian Republic of',
|
248
|
+
'VN': 'Viet Nam',
|
249
|
+
'VG': 'Virgin Islands, British',
|
250
|
+
'VI': 'Virgin Islands, U.S.',
|
251
|
+
'WF': 'Wallis and Futuna',
|
252
|
+
'EH': 'Western Sahara',
|
253
|
+
'YE': 'Yemen',
|
254
|
+
'ZM': 'Zambia',
|
255
|
+
'ZW': 'Zimbabwe',
|
256
|
+
}
|
257
|
+
|
258
|
+
def get_country_name(code):
|
259
|
+
"""Returns the full country name for a given alpha-2 code."""
|
260
|
+
if not code or not isinstance(code, str):
|
261
|
+
return None
|
262
|
+
return COUNTRY_CODES.get(code.upper(), code)
|
@@ -0,0 +1,196 @@
|
|
1
|
+
import requests
|
2
|
+
import ipaddress
|
3
|
+
import random
|
4
|
+
from mojo.helpers.settings import settings
|
5
|
+
from .countries import get_country_name
|
6
|
+
|
7
|
+
# Lazy-load model to avoid circular imports
|
8
|
+
_GeoLocatedIP = None
|
9
|
+
GEOLOCATION_PROVIDERS = settings.get('GEOLOCATION_PROVIDERS', ['ipinfo'])
|
10
|
+
|
11
|
+
|
12
|
+
def get_geo_located_ip_model():
|
13
|
+
global _GeoLocatedIP
|
14
|
+
if _GeoLocatedIP is None:
|
15
|
+
from mojo.apps.account.models.device import GeoLocatedIP
|
16
|
+
_GeoLocatedIP = GeoLocatedIP
|
17
|
+
return _GeoLocatedIP
|
18
|
+
|
19
|
+
|
20
|
+
def geolocate_ip(ip_address):
|
21
|
+
"""
|
22
|
+
Fetches geolocation data for a given IP address. It handles both
|
23
|
+
public IPs (by calling an external provider) and private IPs.
|
24
|
+
Returns a normalized dictionary of geolocation data.
|
25
|
+
"""
|
26
|
+
# 1. Handle private/reserved IPs
|
27
|
+
try:
|
28
|
+
ip_obj = ipaddress.ip_address(ip_address)
|
29
|
+
if ip_obj.is_private or ip_obj.is_reserved:
|
30
|
+
return {
|
31
|
+
'provider': 'internal',
|
32
|
+
'country_name': 'Private Network',
|
33
|
+
'region': 'Private' if ip_obj.is_private else 'Reserved',
|
34
|
+
}
|
35
|
+
except ValueError:
|
36
|
+
return None # Invalid IP
|
37
|
+
|
38
|
+
# 2. Handle public IPs by dispatching to a randomly selected provider
|
39
|
+
providers = GEOLOCATION_PROVIDERS
|
40
|
+
provider = random.choice(providers)
|
41
|
+
api_key_setting_name = f'GEOLOCATION_API_KEY_{provider.upper()}'
|
42
|
+
api_key = getattr(settings, api_key_setting_name, None)
|
43
|
+
|
44
|
+
provider_map = {
|
45
|
+
'ipinfo': fetch_from_ipinfo,
|
46
|
+
'ipstack': fetch_from_ipstack,
|
47
|
+
'ip-api': fetch_from_ipapi,
|
48
|
+
'maxmind': fetch_from_maxmind,
|
49
|
+
}
|
50
|
+
|
51
|
+
fetch_function = provider_map.get(provider)
|
52
|
+
|
53
|
+
if fetch_function:
|
54
|
+
return fetch_function(ip_address, api_key)
|
55
|
+
else:
|
56
|
+
# In a real app, you might want to log this or handle it differently
|
57
|
+
print(f"[Geolocation Error] Provider '{provider}' is not supported.")
|
58
|
+
return None
|
59
|
+
|
60
|
+
|
61
|
+
def refresh_geolocation_for_ip(ip_address):
|
62
|
+
"""
|
63
|
+
This function is the entry point for the background task.
|
64
|
+
It gets or creates a GeoLocatedIP record and refreshes it if necessary.
|
65
|
+
"""
|
66
|
+
GeoLocatedIP = get_geo_located_ip_model()
|
67
|
+
|
68
|
+
# Get or create the record, then call its internal refresh logic.
|
69
|
+
geo_record, created = GeoLocatedIP.objects.get_or_create(ip_address=ip_address)
|
70
|
+
|
71
|
+
if created or geo_record.is_expired:
|
72
|
+
geo_record.refresh()
|
73
|
+
|
74
|
+
return geo_record
|
75
|
+
|
76
|
+
|
77
|
+
def fetch_from_ipinfo(ip_address, api_key):
|
78
|
+
"""
|
79
|
+
Fetches geolocation data from the ipinfo.io API and normalizes it.
|
80
|
+
Fails gracefully by returning None if any error occurs.
|
81
|
+
"""
|
82
|
+
try:
|
83
|
+
url = f"https://ipinfo.io/{ip_address}"
|
84
|
+
if api_key:
|
85
|
+
url += f"?token={api_key}"
|
86
|
+
|
87
|
+
response = requests.get(url, timeout=5)
|
88
|
+
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
|
89
|
+
data = response.json()
|
90
|
+
|
91
|
+
# Normalize the data to our model's schema
|
92
|
+
loc_parts = data.get('loc', '').split(',')
|
93
|
+
latitude = float(loc_parts[0]) if len(loc_parts) == 2 else None
|
94
|
+
longitude = float(loc_parts[1]) if len(loc_parts) == 2 else None
|
95
|
+
country_code = data.get('country')
|
96
|
+
|
97
|
+
return {
|
98
|
+
'provider': 'ipinfo',
|
99
|
+
'country_code': country_code,
|
100
|
+
'country_name': get_country_name(country_code),
|
101
|
+
'region': data.get('region'),
|
102
|
+
'city': data.get('city'),
|
103
|
+
'postal_code': data.get('postal'),
|
104
|
+
'latitude': latitude,
|
105
|
+
'longitude': longitude,
|
106
|
+
'timezone': data.get('timezone'),
|
107
|
+
'data': data # Store the raw response
|
108
|
+
}
|
109
|
+
|
110
|
+
except Exception as e:
|
111
|
+
# In a real application, you would want to log this error.
|
112
|
+
print(f"[Geolocation Error] Failed to fetch from ipinfo.io for IP {ip_address}: {e}")
|
113
|
+
return None
|
114
|
+
|
115
|
+
|
116
|
+
def fetch_from_ipstack(ip_address, api_key):
|
117
|
+
"""
|
118
|
+
Fetches geolocation data from the ipstack.com API and normalizes it.
|
119
|
+
"""
|
120
|
+
if not api_key:
|
121
|
+
print("[Geolocation Error] ipstack provider requires an API key (GEOLOCATION_API_KEY_IPSTACK).")
|
122
|
+
return None
|
123
|
+
try:
|
124
|
+
url = f"http://api.ipstack.com/{ip_address}?access_key={api_key}"
|
125
|
+
response = requests.get(url, timeout=5)
|
126
|
+
response.raise_for_status()
|
127
|
+
data = response.json()
|
128
|
+
|
129
|
+
if data.get('success') is False:
|
130
|
+
error_info = data.get('error', {}).get('info', 'Unknown error')
|
131
|
+
print(f"[Geolocation Error] ipstack API error: {error_info}")
|
132
|
+
return None
|
133
|
+
|
134
|
+
country_code = data.get('country_code')
|
135
|
+
return {
|
136
|
+
'provider': 'ipstack',
|
137
|
+
'country_code': country_code,
|
138
|
+
'country_name': data.get('country_name') or get_country_name(country_code),
|
139
|
+
'region': data.get('region_name'),
|
140
|
+
'city': data.get('city'),
|
141
|
+
'postal_code': data.get('zip'),
|
142
|
+
'latitude': data.get('latitude'),
|
143
|
+
'longitude': data.get('longitude'),
|
144
|
+
'data': data
|
145
|
+
}
|
146
|
+
except Exception as e:
|
147
|
+
print(f"[Geolocation Error] Failed to fetch from ipstack.com for IP {ip_address}: {e}")
|
148
|
+
return None
|
149
|
+
|
150
|
+
|
151
|
+
def fetch_from_ipapi(ip_address, api_key=None):
|
152
|
+
"""
|
153
|
+
Fetches geolocation data from the ip-api.com API and normalizes it.
|
154
|
+
Note: The free tier does not require an API key.
|
155
|
+
"""
|
156
|
+
try:
|
157
|
+
url = f"http://ip-api.com/json/{ip_address}"
|
158
|
+
response = requests.get(url, timeout=5)
|
159
|
+
response.raise_for_status()
|
160
|
+
data = response.json()
|
161
|
+
|
162
|
+
if data.get('status') == 'fail':
|
163
|
+
error_info = data.get('message', 'Unknown error')
|
164
|
+
print(f"[Geolocation Error] ip-api.com API error: {error_info}")
|
165
|
+
return None
|
166
|
+
|
167
|
+
country_code = data.get('countryCode')
|
168
|
+
return {
|
169
|
+
'provider': 'ip-api',
|
170
|
+
'country_code': country_code,
|
171
|
+
'country_name': data.get('country') or get_country_name(country_code),
|
172
|
+
'region': data.get('regionName'),
|
173
|
+
'city': data.get('city'),
|
174
|
+
'postal_code': data.get('zip'),
|
175
|
+
'latitude': data.get('lat'),
|
176
|
+
'longitude': data.get('lon'),
|
177
|
+
'timezone': data.get('timezone'),
|
178
|
+
'data': data
|
179
|
+
}
|
180
|
+
except Exception as e:
|
181
|
+
print(f"[Geolocation Error] Failed to fetch from ip-api.com for IP {ip_address}: {e}")
|
182
|
+
return None
|
183
|
+
|
184
|
+
|
185
|
+
def fetch_from_maxmind(ip_address, api_key):
|
186
|
+
"""
|
187
|
+
Placeholder for MaxMind GeoIP2 web service integration.
|
188
|
+
"""
|
189
|
+
# MaxMind's GeoIP2 web services are best accessed via their official client library.
|
190
|
+
# See: https://github.com/maxmind/geoip2-python
|
191
|
+
# This is a placeholder for where you would integrate the geoip2.webservice.Client.
|
192
|
+
# You would typically fetch account_id and license_key from settings here instead of a single api_key.
|
193
|
+
raise NotImplementedError(
|
194
|
+
"MaxMind provider requires the 'geoip2' client library. "
|
195
|
+
"Set GEOLOCATION_API_KEY_MAXMIND_ACCOUNT_ID and GEOLOCATION_API_KEY_MAXMIND_LICENSE_KEY in your settings."
|
196
|
+
)
|
mojo/helpers/logit.py
CHANGED
@@ -48,6 +48,40 @@ def color_print(msg, color, end="\n"):
|
|
48
48
|
ConsoleLogger.print_message(msg, color, end)
|
49
49
|
|
50
50
|
|
51
|
+
# Convenience logging functions with automatic logger routing
|
52
|
+
_mojo_logger = None
|
53
|
+
_debug_logger = None
|
54
|
+
_error_logger = None
|
55
|
+
|
56
|
+
def info(*args):
|
57
|
+
"""Log info messages to mojo.log"""
|
58
|
+
global _mojo_logger
|
59
|
+
if _mojo_logger is None:
|
60
|
+
_mojo_logger = get_logger("mojo", "mojo.log")
|
61
|
+
_mojo_logger.info(*args)
|
62
|
+
|
63
|
+
def warn(*args):
|
64
|
+
"""Log warning messages to mojo.log"""
|
65
|
+
global _mojo_logger
|
66
|
+
if _mojo_logger is None:
|
67
|
+
_mojo_logger = get_logger("mojo", "mojo.log")
|
68
|
+
_mojo_logger.warning(*args)
|
69
|
+
|
70
|
+
def debug(*args):
|
71
|
+
"""Log debug messages to debug.log"""
|
72
|
+
global _debug_logger
|
73
|
+
if _debug_logger is None:
|
74
|
+
_debug_logger = get_logger("debug", "debug.log", debug=True)
|
75
|
+
_debug_logger.info(*args)
|
76
|
+
|
77
|
+
def error(*args):
|
78
|
+
"""Log error messages to error.log"""
|
79
|
+
global _error_logger
|
80
|
+
if _error_logger is None:
|
81
|
+
_error_logger = get_logger("error", "error.log")
|
82
|
+
_error_logger.error(*args)
|
83
|
+
|
84
|
+
|
51
85
|
# Mask sensitive data in the log
|
52
86
|
def mask_sensitive_data(text):
|
53
87
|
sensitive_patterns = [
|
@@ -142,6 +176,9 @@ class Logger:
|
|
142
176
|
def warning(self, *args):
|
143
177
|
self.logger.warning(self._build_log(*args))
|
144
178
|
|
179
|
+
def warn(self, *args):
|
180
|
+
self.logger.warning(self._build_log(*args))
|
181
|
+
|
145
182
|
def error(self, *args):
|
146
183
|
self.logger.error(self._build_log(*args))
|
147
184
|
|