django-restit 4.1.70__py3-none-any.whl → 4.1.72__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-restit
3
- Version: 4.1.70
3
+ Version: 4.1.72
4
4
  Summary: A Rest Framework for DJANGO
5
5
  License: MIT
6
6
  Author: Ian Starnes
@@ -114,7 +114,7 @@ location/migrations/0002_geoip_subnet_alter_geoip_ip.py,sha256=n-oJrEnIqN9VnMhiZ
114
114
  location/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
115
  location/models/__init__.py,sha256=rZhldkoKmoJQXjBAK1IIQn7K_OOJvFtIGOGVl_szqbE,230
116
116
  location/models/address.py,sha256=GFMyGg9md0y6Szj6bue7sx7ucVjhOgpwJAaz6lYtQEs,2028
117
- location/models/ip.py,sha256=HZGYG-lchEtU0Stdvb7dXrnOiIqqi_EcCxO3eSIhxUk,3560
117
+ location/models/ip.py,sha256=ramy2mr4pLq_OzwcvLMfVPNEIa0YlAYtJ5l1af7do_8,3619
118
118
  location/models/legacy.py,sha256=8ROsUSZrjGQkUyXeJvoxPdKAWaKfUH-AL9TIeJb7krg,1994
119
119
  location/models/location.py,sha256=01dJPJecbp5orExsIGWOsBC_KkwFRIW0rGDIwyx1r0w,2316
120
120
  location/models/track.py,sha256=OdhRL1KVXlPcZkp4S6QpKc7Ctoth8VjwHs_dlZ8XHI4,1474
@@ -132,7 +132,7 @@ location/providers/timezones/__init__.py,sha256=enslc1cVTju3GKrvpLoAxSHUKkLeREhe
132
132
  location/providers/timezones/google.py,sha256=HyATVCGJ3wHwfc47jQRLnwa8nPeBlmpHOGTxetfg7FU,619
133
133
  location/providers/zillow.py,sha256=nCV_q_9ULRkgxi4HTZHioP6nWDDmApvSf1DcwNLcOxk,1935
134
134
  location/rpc/__init__.py,sha256=74T2Y3Zw7ZOl_h67Gdb-tfkyKJAJFSDFHjv04FRKsjQ,123
135
- location/rpc/ip.py,sha256=DtFiRNGm9wnNz8Bed2hxANFMcQhfd6BH6v7c89IVx5c,875
135
+ location/rpc/ip.py,sha256=TbRRgh4_hykT_Z0PDQrMnCdp_x0nK0Zm_WnvzXuweF4,1305
136
136
  location/rpc/location.py,sha256=D5R54nnmmp8NaHQRkP_TF921Ej6j9nmTUNzX1K5WVPc,779
137
137
  location/rpc/track.py,sha256=jSS9_eiKayM_8iW_4Ldojg9a2_trjfXhnLe_a261x5E,3735
138
138
  medialib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -350,14 +350,14 @@ pushit/utils.py,sha256=IeTCGa-164nmB1jIsK1lu1O1QzUhS3BKfuXHGjCW-ck,2121
350
350
  rest/.gitignore,sha256=TbEvWRMnAiajCTOdhiNrd9eeCAaIjRp9PRjE_VkMM5g,118
351
351
  rest/README.md,sha256=V3ETc-cJu8PZIbKr9xSe_pA4JEUpC8Dhw4bQeVCDJPw,5460
352
352
  rest/RemoteEvents.py,sha256=nL46U7AuxIrlw2JunphR1tsXyqi-ep_gD9CYGpYbNgE,72
353
- rest/__init__.py,sha256=BYWlN8oGM865Ufx-c18Jzkieb3YQ4Yx7fiEnNw4ANOw,121
353
+ rest/__init__.py,sha256=yKUhy4QLzfRVHXFOkJ5gTp1ZH-VLHdi4d6I5qBr-PWI,121
354
354
  rest/arc4.py,sha256=y644IbF1ec--e4cUJ3KEYsewTCITK0gmlwa5mJruFC0,1967
355
355
  rest/cache.py,sha256=1Qg0rkaCJCaVP0-l5hZg2CIblTdeBSlj_0fP6vlKUpU,83
356
356
  rest/crypto/__init__.py,sha256=Tl0U11rgj1eBYqd6OXJ2_XSdNLumW_JkBZnaJqI6Ldw,72
357
357
  rest/crypto/aes.py,sha256=f7UgiTGCfgjCc7dL94vnxkPhq_5NzooI-kw0B8_nA58,3605
358
358
  rest/crypto/privpub.py,sha256=_FioylVcbMmDP80yPYjURmafEiDmEAMkskbc7WF10ac,4082
359
359
  rest/crypto/util.py,sha256=agFN2OCPHC70tHNGWrMkkZX4Tt_Ty6imoKEMdTkZpKA,4514
360
- rest/datem.py,sha256=Pfzq1VByvV7zR3nJ7A41pUlkgf5cTnK70CReErsQ-U0,9328
360
+ rest/datem.py,sha256=boG5a1PeK1q51Pf7vHhLZHItbQOlzTc9bC4bdbhiOFE,9330
361
361
  rest/decorators.py,sha256=3RB1ZkJ0dxZhdUyYr8v9QQ4xk_zXB7fn97Y68ZeeMqo,15177
362
362
  rest/encryption.py,sha256=x6Kiez0tVqfxK26MSsRL3k8OS05ni1gEX2aj3I0S9V0,788
363
363
  rest/errors.py,sha256=Jy7Hld3d0Ooc-nJ995N5SDx0EXQLWKac7g6VLJpVJf0,501
@@ -395,10 +395,10 @@ rest/serializers/collection.py,sha256=86AaICz8JylFUzhqouRpp_7v0cNzWcZpsW9yWZQ3w6
395
395
  rest/serializers/csv.py,sha256=CVD0erB2Ebl7mqgrMAZ2FxZSZpyVDCoSS4FHiEjuvDM,3252
396
396
  rest/serializers/excel.py,sha256=KtxqZZU5Huzo31tyVVWbshMudeSAImKLO71ufQQt0-c,1077
397
397
  rest/serializers/json.py,sha256=R1has2PZQuXacA6WwfdrBnMG4rSM6CrnXQOhGoAU6Dk,1736
398
- rest/serializers/legacy.py,sha256=LgU8Sr7yFoiOso1Tb-LkJ-vphGcbEc4BKuSCCuD62R8,61800
398
+ rest/serializers/legacy.py,sha256=JMv1eWhUJveBGO0E80PrsxvROGDl9EYAlx407tmVt7g,61872
399
399
  rest/serializers/model.py,sha256=08HJeqpmytjxvyiJFfsSRRG0uH-iK2mXCw6w0oMfWrI,8598
400
400
  rest/serializers/profiler.py,sha256=OxOimhEyvCAuzUBC9Q1dz2xaakjAqmSnekMATsjduXM,997
401
- rest/serializers/response.py,sha256=W_N-t0GHoRvxFweqYyyTfIF19bVypj-Q-p_xFdxZhHQ,6766
401
+ rest/serializers/response.py,sha256=9zIgIYj_Y47X001_Ujwul4-xE2wMGw3hZ4B_g62NSBI,6840
402
402
  rest/serializers/util.py,sha256=-In89fpuVTd6_Ul8nwEUt3DjVKdpeoEyAxudlyB8K6Y,2734
403
403
  rest/settings_helper.py,sha256=_Vn9nmL5_GPss9zIsXzacbTQkn99NbO42CqvOZC3ge4,1532
404
404
  rest/ssl_check.py,sha256=kH4Pk4upUEwKTAnBLR0DIKezNJHjkW3g2TdQAObEgW4,1419
@@ -445,10 +445,11 @@ telephony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
445
445
  telephony/admin.py,sha256=iOdsBfFFbBisdqKSZ36bIrh_z5sU0Wx_PkaFi8wd1iA,243
446
446
  telephony/decorators.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
447
447
  telephony/migrations/0001_initial.py,sha256=YRiNtpeqj-4uvq19sfI64Q-KRnQ_T53kNzyt-CZUl14,3030
448
+ telephony/migrations/0002_alter_sms_sid.py,sha256=QAnMG-UZ5emssZwdJ8XwfaRh3872zUUR55maDMD4RkE,424
448
449
  telephony/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
449
- telephony/models.py,sha256=Sigr87Sz7TgXp3hsb67YBEjVzV6QV16UytDzu6F8-DE,7753
450
+ telephony/models.py,sha256=C6TTG24FADIWCJJunScvzYyp6t4fYEMuxdUYaN0KfLU,7894
450
451
  telephony/phone_util.py,sha256=aJ4hXjDCauwrSaI_qWa5HVCgD2CCdWx6TA_ikJ6kC7w,2126
451
- telephony/rpc.py,sha256=dHpTFjyy6lv7AS_MyYurJu0XIRBES-A3A-beqnPhKHQ,2659
452
+ telephony/rpc.py,sha256=GVPWH5XSPNar-ICu5oq-yF6FBmJbju3XJr6gSXA6ZVU,3535
452
453
  wiki/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
453
454
  wiki/migrations/0001_initial.py,sha256=9jvUyjrbJrbDilRnwzQUPhPV8Xi_olEPBk_N0nycvM0,3606
454
455
  wiki/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -481,7 +482,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
481
482
  ws4redis/settings.py,sha256=K0yBiLUuY81iDM4Yr-k8hbvjn5VVHu5zQhmMK8Dtz0s,1536
482
483
  ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
483
484
  ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
484
- django_restit-4.1.70.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
485
- django_restit-4.1.70.dist-info/METADATA,sha256=6za46qp_8SDCN52LyLQw6bpuiUJwYiS9hv50f8FZHOY,7573
486
- django_restit-4.1.70.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
487
- django_restit-4.1.70.dist-info/RECORD,,
485
+ django_restit-4.1.72.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
486
+ django_restit-4.1.72.dist-info/METADATA,sha256=ldiAuTSzPz2ky_RTBIK7XqA8oDCa45x_RsvEmIvQtqQ,7573
487
+ django_restit-4.1.72.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
488
+ django_restit-4.1.72.dist-info/RECORD,,
location/models/ip.py CHANGED
@@ -8,6 +8,9 @@ GEOIP_LOOKUP_BY_SUBNET = settings.get("GEOIP_LOOKUP_BY_SUBNET", True)
8
8
 
9
9
 
10
10
  class GeoIP(models.Model, rm.RestModel):
11
+ class RestMeta:
12
+ SEARCH_FIELDS = ["ip", "isp"]
13
+
11
14
  created = models.DateTimeField(auto_now_add=True)
12
15
  modified = models.DateTimeField(auto_now=True)
13
16
  hostname = models.CharField(max_length=255, blank=True, null=True, default=None)
location/rpc/ip.py CHANGED
@@ -25,8 +25,21 @@ def on_ip_lookup(request):
25
25
  return gip.restGet(request, graph)
26
26
 
27
27
 
28
- @rd.url(r'^geo/ip$')
29
- @rd.url(r'^geo/ip/(?P<pk>\d+)$')
28
+ @rd.urlGET('geo/ip')
29
+ @rd.urlGET('geo/ip/<int:pk>')
30
30
  @rd.login_required
31
31
  def rest_on_geoip(request, pk=None):
32
32
  return location.GeoIP.on_rest_request(request, pk)
33
+
34
+
35
+ @rd.urlPOST('geo/ip')
36
+ @rd.login_required
37
+ @rd.requires_params(["ip"])
38
+ def rest_on_geoip_lookup(request, pk=None):
39
+ ip = request.DATA.get("ip", request.ip)
40
+ gip = location.GeoIP.get(
41
+ ip,
42
+ force_refresh=request.DATA.get("refresh", 0, field_type=bool),
43
+ stale_after=request.DATA.get("stale_after", 90, field_type=int))
44
+ graph = request.DATA.get("graph", "default")
45
+ return gip.restGet(request, graph)
rest/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  from .uberdict import UberDict # noqa: F401
2
2
  from .settings_helper import settings # noqa: F401
3
3
 
4
- __version__ = "4.1.70"
4
+ __version__ = "4.1.72"
rest/datem.py CHANGED
@@ -290,7 +290,7 @@ def getDateRange(start, end=None, kind=None, zone=None, hour=0, eod=None, end_eo
290
290
  start = end - timedelta(days=int(kind))
291
291
 
292
292
  if end is None:
293
- end = start + timedelta(days=1)
293
+ end = start + timedelta(hours=24)
294
294
 
295
295
  if zone and zone.lower() == "utc":
296
296
  zone = None
@@ -1549,6 +1549,9 @@ def restOK(request):
1549
1549
  def restError(request, error, error_code=None):
1550
1550
  return restStatus(request, False, error=error, error_code=error_code)
1551
1551
 
1552
+ def restSuccessNoContent(request):
1553
+ return HttpResponse(status=204)
1554
+
1552
1555
  def restStatus(request, status, data={}, accept_list=None, **kwargs):
1553
1556
  """
1554
1557
  request: HttpRequest object
@@ -13,6 +13,7 @@ from . import csv
13
13
  from . import excel
14
14
  # from . import profiler
15
15
 
16
+
16
17
  def restStatus(request, status, data={}, **kwargs):
17
18
  if isinstance(data, str):
18
19
  if status:
@@ -25,6 +26,10 @@ def restStatus(request, status, data={}, **kwargs):
25
26
  return restResult(request, data)
26
27
 
27
28
 
29
+ def restSuccessNoContent(request):
30
+ return HttpResponse(status=204)
31
+
32
+
28
33
  # @profiler.timeit
29
34
  def restGet(request, obj, fields=None, extra=[], exclude=[], recurse_into=[], **kwargs):
30
35
  data = ms.to_dict(obj, fields, extra, exclude, recurse_into)
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.1.4 on 2023-11-27 22:03
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('telephony', '0001_initial'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='sms',
15
+ name='sid',
16
+ field=models.CharField(blank=True, db_index=True, default=None, max_length=125, null=True),
17
+ ),
18
+ ]
telephony/models.py CHANGED
@@ -41,15 +41,28 @@ class SMS(models.Model, RestModel):
41
41
  }
42
42
  }
43
43
 
44
- sid = models.CharField(max_length=125, blank=True, null=True, default=None)
44
+ sid = models.CharField(
45
+ max_length=125, blank=True, null=True,
46
+ default=None, db_index=True)
45
47
  created = models.DateTimeField(auto_now_add=True, editable=False)
46
- group = models.ForeignKey(Group, related_name="telephony_sms", blank=True, null=True, default=None, on_delete=models.CASCADE)
47
- by = models.ForeignKey(Member, related_name="telephony_sms_out", blank=True, null=True, default=None, on_delete=models.CASCADE)
48
- to = models.ForeignKey(Member, related_name="telephony_sms_in", blank=True, null=True, default=None, on_delete=models.CASCADE)
48
+ group = models.ForeignKey(
49
+ Group, related_name="telephony_sms",
50
+ blank=True, null=True, default=None,
51
+ on_delete=models.CASCADE)
52
+ by = models.ForeignKey(
53
+ Member, related_name="telephony_sms_out",
54
+ blank=True, null=True, default=None,
55
+ on_delete=models.CASCADE)
56
+ to = models.ForeignKey(
57
+ Member, related_name="telephony_sms_in",
58
+ blank=True, null=True, default=None,
59
+ on_delete=models.CASCADE)
49
60
  # the mechanism , sms, push, etc
50
61
  transport = models.CharField(max_length=125, blank=True, null=True, default=None)
51
62
  # this can be email, phone, etc
52
- endpoint = models.CharField(max_length=200, blank=True, null=True, default=None, db_index=True)
63
+ endpoint = models.CharField(
64
+ max_length=200, blank=True,
65
+ null=True, default=None, db_index=True)
53
66
  # this can be email, phone, etc
54
67
  srcpoint = models.CharField(max_length=200, blank=True, null=True, default=None)
55
68
 
@@ -92,12 +105,13 @@ class SMS(models.Model, RestModel):
92
105
  "ToZip": "92656"
93
106
  }
94
107
  """
95
- msg = SMS(endpoint=request.DATA.get("To"),
108
+ msg = SMS(
109
+ endpoint=request.DATA.get("To"),
96
110
  message=request.DATA.get("Body"),
97
111
  srcpoint=request.DATA.get("From"),
98
112
  transport="sms", is_inbound=True)
99
113
  msg.sid = request.DATA.get("MessageSid")
100
- msg.status = request.DATA.get("SmsStatus")
114
+ msg.status = request.DATA.get("MessageStatus")
101
115
  msg.save()
102
116
  return None
103
117
 
telephony/rpc.py CHANGED
@@ -3,10 +3,10 @@ from django.conf import settings
3
3
  from django.http import HttpResponse
4
4
 
5
5
  from telephony.models import SMS, PhonenumberInfo
6
-
6
+ from account import models as am
7
7
  from rest import helpers
8
- from rest.views import *
9
- from rest.decorators import *
8
+ from rest import views as rv
9
+ from rest import decorators as rd
10
10
  import importlib
11
11
 
12
12
  try:
@@ -15,41 +15,59 @@ except ImportError:
15
15
  pass
16
16
 
17
17
 
18
- @url(r'^sms/msg$')
19
- @url(r'^sms/msg/(?P<pk>\d+)$')
20
- @perm_required("view_logs")
18
+ @rd.url('sms/msg')
19
+ @rd.url('sms/msg/<int:pk>')
20
+ @rd.perm_required("view_logs")
21
21
  def handle_sms_list(request, pk=None):
22
22
  return SMS.on_rest_request(request, pk)
23
23
 
24
24
 
25
- @urlPOST(r'^sms$')
26
- @urlPOST(r'^sms/$')
27
- @login_required
25
+ @rd.urlGET('info')
26
+ @rd.urlGET('info/<int:pk>')
27
+ @rd.perm_required("view_logs")
28
+ def handle_number_info(request, pk=None):
29
+ return PhonenumberInfo.on_rest_request(request, pk)
30
+
31
+
32
+ @rd.urlPOST('info')
33
+ @rd.login_required
34
+ @rd.requires_params(["phone_number"])
35
+ def handle_number_lookup(request, pk=None):
36
+ number = request.DATA.get("phone_number")
37
+ info = PhonenumberInfo.lookup(number)
38
+ if info.pk is None:
39
+ return rv.restStatus(request, False, error="Invalid number")
40
+ return info.restGet(request)
41
+
42
+
43
+ @rd.urlPOST(r'^sms$')
44
+ @rd.urlPOST(r'^sms/$')
45
+ @rd.login_required
28
46
  def sendSMS(request):
29
47
  me = request.member
30
48
  group = request.group
31
49
  # for now you can only send msgs to a member
32
50
  if "to" in request.DATA:
33
51
  to = request.DATA.getlist("to")
34
- members = Member.objects.filter(pk__in=to)
52
+ members = am.Member.objects.filter(pk__in=to)
35
53
  message = request.DATA.get("message")
36
- return restGet(request, SMS.broadcast(members, message, by=me, group=group, transport="sms"))
54
+ return rv.restGet(request, SMS.broadcast(members, message, by=me, group=group, transport="sms"))
37
55
 
38
56
  if "message" not in request.DATA:
39
- return restStatus(request, False, error="permission denied")
57
+ return rv.restStatus(request, False, error="permission denied")
40
58
 
41
- member = Member.getFromRequest(request)
59
+ member = am.Member.getFromRequest(request)
42
60
  if not member:
43
- return restStatus(request, False, error="requires valid member")
61
+ return rv.restStatus(request, False, error="requires valid member")
44
62
  phone = member.getProperty("phone")
45
63
  if not phone:
46
- return restStatus(request, False, error="member has no phone number")
64
+ return rv.restStatus(request, False, error="member has no phone number")
47
65
  message = request.DATA.get("message")
48
66
  # send(endpoint, message, by=None, group=None, to=None, transport="sms", srcpoint=None):
49
- return restGet(request, SMS.send(phone, message, me, group, member))
67
+ return rv.restGet(request, SMS.send(phone, message, me, group, member))
50
68
 
51
69
 
52
- @urlPOST(r'^sms/incoming$')
70
+ @rd.urlPOST(r'^sms/incoming$')
53
71
  def receiveSMS(request):
54
72
  helpers.log_print(request.DATA.asDict())
55
73
  SMS.log_incoming(request)
@@ -67,22 +85,25 @@ def receiveSMS(request):
67
85
  return HttpResponse(resp.to_xml(), content_type='text/xml')
68
86
 
69
87
 
70
- @url(r'^info$')
71
- @url(r'^info/(?P<pk>\d+)$')
72
- @login_required
73
- def handle_info(request, pk=None):
74
- return PhonenumberInfo.on_rest_request(request, pk)
75
-
76
-
77
- @url(r'^lookup$')
78
- @login_required
88
+ @rd.url(r'^lookup$')
89
+ @rd.login_required
79
90
  def handle_lookup(request, pk=None):
80
91
  number = request.DATA.get(["number", "phone"])
81
92
  if number is None:
82
- return restPermissionDenied(request)
93
+ return rv.restPermissionDenied(request)
83
94
  info = PhonenumberInfo.lookup(number)
84
95
  return info.restGet(request)
85
96
 
86
97
 
87
-
98
+ @rd.urlPOST('sms/twilio/status')
99
+ def handle_twilio_status(request, pk=None):
100
+ sid = request.DATA.get("MessageSid", None)
101
+ msd = None
102
+ if sid is not None:
103
+ msg = SMS.objects.filter(sid=sid).last()
104
+ if msg is not None:
105
+ msg.status = request.DATA.get("MessageStatus", None)
106
+ msg.reason = request.DATA.get("ErrorCode", None)
107
+ msg.save()
108
+ return rv.restSuccessNoContent(request)
88
109