django-restit 4.2.85__py3-none-any.whl → 4.2.87__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.
account/models/member.py CHANGED
@@ -554,11 +554,11 @@ class Member(User, RestModel, MetaDataModel):
554
554
  if auth_session is not None and auth_session.location is not None:
555
555
  try:
556
556
  if auth_session.location.country != loc.country:
557
- details = f"user login from new country {loc.country} vs previous {auth_session.location.country}"
558
- self.reportIncident("account", details)
557
+ details = f"user({self.username}) login from new country {loc.country} vs previous {auth_session.location.country}"
558
+ self.reportIncident("account", details, details=details, error_code=491)
559
559
  elif auth_session.location.state != loc.state:
560
- details = f"user login from new state {loc.state} vs previous {auth_session.location.state}"
561
- self.reportIncident("account", details)
560
+ details = f"user({self.username}) login from new state {loc.state} vs previous {auth_session.location.state}"
561
+ self.reportIncident("account", details, details=details, error_code=491)
562
562
  except Exception:
563
563
  rh.log_exception(self.username)
564
564
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-restit
3
- Version: 4.2.85
3
+ Version: 4.2.87
4
4
  Summary: A Rest Framework for DJANGO
5
5
  License: MIT
6
6
  Author: Ian Starnes
@@ -28,7 +28,7 @@ account/models/device.py,sha256=TloXvvrx3khF3BeGFuVYn6DhXjOW0AMZb4F9Fl5nBII,5491
28
28
  account/models/feeds.py,sha256=vI7fG4ASY1M0Zjke24RdnfDcuWeATl_yR_25jPmT64g,2011
29
29
  account/models/group.py,sha256=iDD_oSgswKV_t_gXZuVK80MvICrZZqdANm2jtGtOFy8,21985
30
30
  account/models/legacy.py,sha256=zYdtv4LC0ooxPVqWM-uToPwV-lYWQLorSE6p6yn1xDw,2720
31
- account/models/member.py,sha256=fzSVVAdbUa1knp1O4JTnYZFYRas7-zDZaOPjZAMCC1Q,52992
31
+ account/models/member.py,sha256=8xi-NahJipic_ut81vCFG-hY9x1U-trZ9KhnhIHAaFM,53092
32
32
  account/models/membership.py,sha256=90EpAhOsGaqphDAkONP6j_qQ0OWSRaQsI8H7E7fgMkE,9249
33
33
  account/models/notify.py,sha256=TOkuVBLAsbzT58FOxII_G3Cj_IDQx16vyehyEsNrDcY,15306
34
34
  account/models/passkeys.py,sha256=TJxITUi4DT4_1tW2K7ZlOcRjJuMVl2NtKz7pKQU8-Tw,1516
@@ -154,7 +154,7 @@ location/providers/timezones/google.py,sha256=HyATVCGJ3wHwfc47jQRLnwa8nPeBlmpHOG
154
154
  location/providers/zillow.py,sha256=nCV_q_9ULRkgxi4HTZHioP6nWDDmApvSf1DcwNLcOxk,1935
155
155
  location/rpc/__init__.py,sha256=MDs0Qntwff3d128BhjHEFcGTWSomshHQ1VToqMT0YVA,166
156
156
  location/rpc/address.py,sha256=ivkdG5Oc8YnJowEQ8dmiOnZr5OOaIuiw9fuwbrC7gUQ,219
157
- location/rpc/ip.py,sha256=TbRRgh4_hykT_Z0PDQrMnCdp_x0nK0Zm_WnvzXuweF4,1305
157
+ location/rpc/ip.py,sha256=7BaMSq3TYy1_f_aPJTnv8l2sLdXRDm19xV7WPEbnoRM,1452
158
158
  location/rpc/location.py,sha256=D5R54nnmmp8NaHQRkP_TF921Ej6j9nmTUNzX1K5WVPc,779
159
159
  location/rpc/track.py,sha256=jSS9_eiKayM_8iW_4Ldojg9a2_trjfXhnLe_a261x5E,3735
160
160
  medialib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -331,7 +331,7 @@ medialib/youtube/upload.py,sha256=MTuPxm1ZC-y5pXAGtLNtp1hBSNZgCKYt1ewP5hwMQHI,28
331
331
  medialib/youtube/uritemplate/__init__.py,sha256=ONWR_KRz9au0O-XUUTrO_UN7GHTmZCTKyvflUQb8wxM,4996
332
332
  metrics/README.md,sha256=YwbCA2y6xJBlaO6yEtl1zWpqrQ4ZzkQSuQT-h6btET8,2307
333
333
  metrics/__init__.py,sha256=70sdDZGOwGIEFWgDkHWPMVODFelo206jp1g-BFV2u_4,90
334
- metrics/client.py,sha256=VChtWtjjSxINhJzoA8mep4YBrHQQMY37DfggCjsPiEE,24337
334
+ metrics/client.py,sha256=-cbOdOIJoE8Q5DH_sMv-Ia_tD7w15SXt3pBnNUGPNPo,25251
335
335
  metrics/eod.py,sha256=gnq-tNE7xfm2ah52e2TUyERgUQNwkFuT2rtDv8XOUVQ,9182
336
336
  metrics/examples/eod_example.py,sha256=gYtansjsKILVxe8XJD12XPaxmBJ-B6dOXGZG2JTGWA8,1664
337
337
  metrics/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -353,10 +353,10 @@ metrics/models.py,sha256=lD9nVzfwdav70ENulqJ8rE8Ui8EWlzdVp05rg8bAlMA,13444
353
353
  metrics/periodic.py,sha256=VmL0YG05D6k5fcNsF4QqPEU-BBPbZXjbOrp3b8EHZ-U,651
354
354
  metrics/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
355
355
  metrics/providers/aws.py,sha256=RDM5RLeFADHexm4cHaJdAm3K6iz1NwMSNcV9GYuGtjY,7432
356
- metrics/rpc.py,sha256=aPgE1yEIHM_9rdj0onMQZngxduq2Dr8EU8P2eFXPCBk,20558
356
+ metrics/rpc.py,sha256=nY7TQPOXJ-CcFbv5uvrCicGbsvEdrIooD0rFKS8Ma1E,21300
357
357
  metrics/settings.py,sha256=wwHA9Z7BAHNeu3tFVn8Fh5j46KR-eGx0E8r5dzCFlAU,132
358
358
  metrics/tq.py,sha256=WHBRYSinmTuxF9l-_-lx0yfzEYkb0ffVMt_uvCj9bYo,825
359
- metrics/utils.py,sha256=w6H2v8zjlOZ5uqZsJOQvZoN-2Kyv1h8PN76gMGow7AE,11995
359
+ metrics/utils.py,sha256=PSydxeI983udULUTcbeWG-_ulPSOac6Q_t_8k_Vjn1I,12606
360
360
  pushit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
361
361
  pushit/admin.py,sha256=69HdDZU_Iz8Fm72M8r8FUztsZvW37zdGwVmj8VTqr0c,451
362
362
  pushit/migrations/0001_initial.py,sha256=kYF1ksOlKf9ElrlagGhpNf5GbKEq6SORWGreMH9A7as,4555
@@ -387,7 +387,7 @@ rest/extra/__init__.py,sha256=YzmNsch5H5FFLkUK9mIAKyoRK_rJCA9HGb0kubp4h30,54
387
387
  rest/extra/json_metadata.py,sha256=p_ffzmANmOFix_oC3voR6_NNTjcn7-T7aXcH-I4_Npg,1078
388
388
  rest/fields.py,sha256=_v1TJVc6vyWlqmwFRJ6mtuR5Fo-lS0KcUhPWIrzKZUo,9719
389
389
  rest/forms.py,sha256=66Wm5cdy8tKib_mGicjq_yd-gNVMFWRECnrDksnNnwU,6316
390
- rest/helpers.py,sha256=l_vA0mdY4gZmOwzmqt-qB3DcF3aKkmteerXzJd2Qq7Q,28369
390
+ rest/helpers.py,sha256=PQ6-zTKZo85-TTI5BOO1sQVUFScirArnMz3X7_OpZN4,29450
391
391
  rest/joke.py,sha256=0PpKaX2iN7jlS62kgjfmmqkFBYLPURz15aQ8R7OJkJ8,260
392
392
  rest/jwtoken.py,sha256=6AIe9IpsOn44sodiV0OPYeTZZNhS8VRiakV-rOuCyGw,2444
393
393
  rest/log.py,sha256=hd1_4HBOS395sfXJIL6BTw9yekm1SLgBwYx_PdfIhKA,20930
@@ -506,7 +506,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
506
506
  ws4redis/settings.py,sha256=K0yBiLUuY81iDM4Yr-k8hbvjn5VVHu5zQhmMK8Dtz0s,1536
507
507
  ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
508
508
  ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
509
- django_restit-4.2.85.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
510
- django_restit-4.2.85.dist-info/METADATA,sha256=c0_tpMC4ULCMJwzo_QfuVOwW3MRdLMhy6k1gqDHUaec,7645
511
- django_restit-4.2.85.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
512
- django_restit-4.2.85.dist-info/RECORD,,
509
+ django_restit-4.2.87.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
510
+ django_restit-4.2.87.dist-info/METADATA,sha256=QnVcOPqf4_jJ5FgPcmrhhxiq4LmwQo-2WOwL0rY2oCI,7645
511
+ django_restit-4.2.87.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
512
+ django_restit-4.2.87.dist-info/RECORD,,
location/rpc/ip.py CHANGED
@@ -27,11 +27,16 @@ def on_ip_lookup(request):
27
27
 
28
28
  @rd.urlGET('geo/ip')
29
29
  @rd.urlGET('geo/ip/<int:pk>')
30
- @rd.login_required
31
30
  def rest_on_geoip(request, pk=None):
32
31
  return location.GeoIP.on_rest_request(request, pk)
33
32
 
34
33
 
34
+ @rd.urlPOST('geo/ip/<int:pk>')
35
+ @rd.perm_required(["manage_location"])
36
+ def rest_save_geoip(request, pk=None):
37
+ return location.GeoIP.on_rest_request(request, pk)
38
+
39
+
35
40
  @rd.urlPOST('geo/ip')
36
41
  @rd.login_required
37
42
  @rd.requires_params(["ip"])
metrics/client.py CHANGED
@@ -38,8 +38,10 @@ def set_metric(slug, value, category=None, expire=None, date=None):
38
38
  get_r().set_metric(slug, value, category=category, expire=expire, date=date)
39
39
 
40
40
 
41
- def get_metric(slug, min_granularity=None, max_granularity=None):
41
+ def get_metric(slug, min_granularity=None, max_granularity=None, category=None):
42
42
  """get a metric."""
43
+ if category is not None:
44
+ return get_r().get_metric_by_category(category, min_granularity, max_granularity)
43
45
  return get_r().get_metric(slug, min_granularity, max_granularity)
44
46
 
45
47
 
@@ -52,7 +54,7 @@ def get_metrics(slugs, since=None, granularity="daily", group=None, samples=None
52
54
  def get_category_metrics(category, since=None, granularity="daily", samples=None):
53
55
  """Create/Increment a metric."""
54
56
  r = get_r()
55
- slugs = [utils.to_string(s) for s in list(r.category_slugs(category))]
57
+ slugs = r.category_slugs(category, True)
56
58
  return r.get_metric_history_chart_data(
57
59
  slugs, since, granularity, samples=samples)
58
60
 
@@ -60,8 +62,10 @@ def get_category_metrics(category, since=None, granularity="daily", samples=None
60
62
  def get_slugs(category=None):
61
63
  """get slug list"""
62
64
  if category:
63
- return list(get_r().category_slugs(category))
64
- return list(get_r().metric_slugs())
65
+ slugs = list(get_r().category_slugs(category))
66
+ else:
67
+ slugs = list(get_r().metric_slugs())
68
+ return [utils.to_string(s) for s in list(slugs)]
65
69
 
66
70
 
67
71
  def get_gauge(slug):
@@ -173,10 +177,12 @@ class R(object):
173
177
  def _category_key(self, category):
174
178
  return u"c:{0}".format(category)
175
179
 
176
- def category_slugs(self, category):
180
+ def category_slugs(self, category, as_string=False):
177
181
  """Returns a set of the metric slugs for the given category"""
178
182
  key = self._category_key(category)
179
183
  slugs = self.r.smembers(key)
184
+ if as_string:
185
+ return [utils.to_string(s) for s in slugs]
180
186
  return slugs
181
187
 
182
188
  def _categorize(self, slug, category):
@@ -210,7 +216,7 @@ class R(object):
210
216
  result = utils.OrderedDict()
211
217
  categories = sorted(self.r.smembers(self._categories_key))
212
218
  for category in categories:
213
- result[category] = self.category_slugs(category)
219
+ result[category] = self.category_slugs(category, True)
214
220
 
215
221
  # We also need to see the uncategorized metric slugs, so need some way
216
222
  # to check which slugs are not already stored.
@@ -354,6 +360,12 @@ class R(object):
354
360
  pipe.expireat(key, d_expireat)
355
361
  pipe.execute()
356
362
 
363
+ def get_metric_by_category(self, category, min_granularity=None, max_granularity=None):
364
+ results = UberDict()
365
+ for slug in self.category_slugs(category, True):
366
+ results[slug] = self.get_metric(slug, min_granularity, max_granularity)
367
+ return results
368
+
357
369
  def get_metric(self, slug, min_granularity=None, max_granularity=None):
358
370
  """Get the current values for a metric.
359
371
 
@@ -363,12 +375,17 @@ class R(object):
363
375
  """
364
376
  results = UberDict()
365
377
  granularities = utils.granularities(min_granularity, max_granularity)
366
- keys = utils.build_keys(slug)
378
+ keys = utils.build_keys(slug, min_granularity=min_granularity, max_granularity=max_granularity)
379
+
367
380
  for granularity, key in zip(granularities, keys):
381
+ rh.debug("-- get_metric --", granularity, key)
368
382
  try:
369
383
  results[granularity] = int(self.r.get(key))
370
384
  except Exception:
371
- pass
385
+ results[granularity] = 0
386
+ rh.log_exception("get_metric", granularity, key)
387
+ if min_granularity and min_granularity == max_granularity:
388
+ return results[min_granularity]
372
389
  return results
373
390
 
374
391
  def get_metrics(self, slug_list):
@@ -401,8 +418,9 @@ class R(object):
401
418
 
402
419
  def get_category_metrics(self, category):
403
420
  """Get metrics belonging to the given category"""
404
- slug_list = self.category_slugs(category)
405
- return self.get_metrics(slug_list)
421
+ slug_list = self.category_slugs(category, True)
422
+ res = self.get_metrics(slug_list)
423
+ return res
406
424
 
407
425
  def delete_category(self, category):
408
426
  """Removes the category from Redis. This doesn't touch the metrics;
@@ -571,7 +589,7 @@ class R(object):
571
589
  since = date_util.convertToLocalTime(settings.METRICS_TIMEZONE, since)
572
590
 
573
591
  slugs = sorted(slugs)
574
- rh.debug(f"get_metric_history {since}")
592
+ # rh.debug(f"get_metric_history {since}", slugs)
575
593
  history = self.get_metric_history(slugs, since, granularity=granularity)
576
594
 
577
595
  # Convert the history into an intermediate data structure organized
metrics/rpc.py CHANGED
@@ -48,14 +48,29 @@ def rest_on_new_metric(request):
48
48
  def rest_on_get_metric(request):
49
49
  # slug, num=1, category=None, expire=None, date=None
50
50
  data = request.DATA.toObject()
51
- if data.slug is None:
51
+ if data.slug is None and data.category is None:
52
52
  return rv.restStatus(request, False)
53
- result = metrics.get_metric(data.slug)
53
+ if data.granularity:
54
+ data.min_granularity = data.granularity
55
+ data.max_granularity = data.granularity
56
+ result = metrics.get_metric(
57
+ data.slug, category=data.category,
58
+ min_granularity=data.min_granularity,
59
+ max_granularity=data.max_granularity)
54
60
  if result is None:
55
61
  return rv.restStatus(request, False)
62
+ if data.prefix:
63
+ result = {key[len(data.prefix):]:value for key, value in result.items()}
56
64
  return rv.restReturn(request, dict(data=result))
57
65
 
58
66
 
67
+ def truncatePrefix(prefix, data):
68
+ # rh.debug("prefix", prefix, data)
69
+ for values in data["data"]:
70
+ if values["slug"].startswith(prefix):
71
+ values["slug"] = values["slug"][len(prefix):]
72
+
73
+
59
74
  @rd.urlGET('metrics')
60
75
  @rd.login_required
61
76
  def rest_on_get_metrics(request, pk=None):
@@ -64,9 +79,12 @@ def rest_on_get_metrics(request, pk=None):
64
79
  granularity = request.DATA.get(["granularity", "period"], default="daily")
65
80
  samples = request.DATA.get("samples", field_type=int)
66
81
  category = request.DATA.get("category")
67
- rh.debug(f"rest_on_get_metrics: {since}, {granularity}, {samples}, {category}")
82
+ prefix = request.DATA.get("prefix")
83
+ # rh.debug(f"rest_on_get_metrics: {since}, {granularity}, {samples}, {category}")
68
84
  if category:
69
85
  result = metrics.get_category_metrics(category, since, granularity, samples=samples)
86
+ if prefix:
87
+ truncatePrefix(prefix, result)
70
88
  return rv.restReturn(request, dict(data=result))
71
89
  slugs = request.DATA.getlist(["slugs", "slug"])
72
90
  if slugs is None:
@@ -75,6 +93,8 @@ def rest_on_get_metrics(request, pk=None):
75
93
  result = metrics.get_metrics(slugs, since, granularity, samples=samples)
76
94
  if result is None:
77
95
  return rv.restStatus(request, False)
96
+ if prefix:
97
+ truncatePrefix(prefix, result)
78
98
  return rv.restReturn(request, dict(data=result))
79
99
 
80
100
 
metrics/utils.py CHANGED
@@ -90,21 +90,36 @@ def metric_slug(value):
90
90
  def granularities(min_granularity=None, max_granularity=None):
91
91
  """Returns a generator of all possible granularities based on the
92
92
  MIN_GRANULARITY and MAX_GRANULARITY settings.
93
+
94
+ Args:
95
+ min_granularity (str): Optional; the minimum granularity to include.
96
+ max_granularity (str): Optional; the maximum granularity to include.
97
+
98
+ Yields:
99
+ str: A granularity level from the predefined list of granularities.
93
100
  """
101
+ # Use default settings if no values are provided
94
102
  if min_granularity is None:
95
103
  min_granularity = app_settings.MIN_GRANULARITY
96
104
  if max_granularity is None:
97
105
  max_granularity = app_settings.MAX_GRANULARITY
98
- keep = False
106
+
107
+ # Initialize a flag to determine when to start yielding granularities
108
+ start_yielding = False
109
+
110
+ # Loop through each granularity in the list of all granularities
99
111
  for g in GRANULARITIES:
100
- if g == min_granularity and not keep:
101
- keep = True
102
- elif g == max_granularity and keep:
103
- keep = False
104
- if keep:
105
- if g == max_granularity:
106
- keep = False
112
+ # Start yielding when the minimum granularity is reached
113
+ if g == min_granularity:
114
+ start_yielding = True
115
+
116
+ # Yield the current granularity if the flag is true
117
+ if start_yielding:
107
118
  yield g
119
+
120
+ # Stop yielding after the maximum granularity has been yielded
121
+ if g == max_granularity:
122
+ break
108
123
 
109
124
 
110
125
  def get_metric_key_pattern(granularity, slug, date):
rest/helpers.py CHANGED
@@ -6,9 +6,9 @@ from .settings_helper import settings
6
6
  import importlib
7
7
  from django.db.models import Count, Q, Avg, Sum, Max, Min
8
8
  from django.db.models.query import QuerySet
9
+ # from django.db.models.functions import TruncWeek, TruncMonth, TruncYear
9
10
  from io import StringIO
10
11
  import base64
11
- import binascii
12
12
 
13
13
  from objict import objict
14
14
  from .datem import *
@@ -518,24 +518,28 @@ def filterByDates(qset, start=None, end=None, date_field="created"):
518
518
  return qset.filter(**q)
519
519
  return qset
520
520
 
521
+
521
522
  def getAverage(qset, field_name):
522
523
  res = qset.aggregate(avg_result=Avg(field_name))
523
524
  if "avg_result" in res and res["avg_result"] != None:
524
525
  return res["avg_result"]
525
526
  return 0.0
526
527
 
528
+
527
529
  def getMin(qset, field_name):
528
530
  res = qset.aggregate(min_result=Min(field_name))
529
531
  if "min_result" in res and res["min_result"] != None:
530
532
  return res["min_result"]
531
533
  return 0.0
532
534
 
535
+
533
536
  def getMax(qset, field_name):
534
537
  res = qset.aggregate(max_result=Max(field_name))
535
538
  if "max_result" in res and res["max_result"] != None:
536
539
  return res["max_result"]
537
540
  return 0.0
538
541
 
542
+
539
543
  def getSum(qset, *args):
540
544
  params = {}
541
545
  for field_name in args:
@@ -555,6 +559,33 @@ def getSum(qset, *args):
555
559
  return results
556
560
 
557
561
 
562
+ def getGroupLeaders(Model, timeframe="week", date_field="created",
563
+ size=10, field="id", action="count", out_field="value"):
564
+ today = datetime.now()
565
+ # FIXME: yes timerange to deal with timezone issues
566
+ q = {f"{date_field}__year": today.year}
567
+ if timeframe == "week":
568
+ q[f"{date_field}__week"] = today.isocalendar()[1]
569
+ elif timeframe == "month":
570
+ q[f"{date_field}__month"] = today.month
571
+ elif timeframe == "day":
572
+ q[f"{date_field}__day"] = today.day
573
+ qset = Model.objects.filter(**q).values('group__name', 'group')
574
+ if field == "id":
575
+ return list(qset.annotate(value=Count('id')).order_by('-value')[:size])
576
+ field_key = f"{field}_{action}"
577
+ if out_field:
578
+ field_key = out_field
579
+ aq = {}
580
+ if action == "sum":
581
+ aq[field_key] = Sum(field)
582
+ elif action == "average":
583
+ aq[field_key] = Avg(field)
584
+ else:
585
+ aq[field_key] = Count(field)
586
+ return list(qset.annotate(**aq).order_by(f"-{field_key}")[:size])
587
+
588
+
558
589
  def countOccurences(qset, field_name):
559
590
  output = objict()
560
591
  for item in list(qset.values(field_name).annotate(count=Count(field_name))):