django-restit 4.2.84__py3-none-any.whl → 4.2.86__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 +4 -4
- {django_restit-4.2.84.dist-info → django_restit-4.2.86.dist-info}/METADATA +1 -1
- {django_restit-4.2.84.dist-info → django_restit-4.2.86.dist-info}/RECORD +12 -12
- incident/models/incident.py +12 -6
- incident/rpc.py +3 -3
- location/rpc/ip.py +6 -1
- metrics/client.py +29 -11
- metrics/rpc.py +23 -3
- metrics/utils.py +23 -8
- rest/helpers.py +32 -1
- {django_restit-4.2.84.dist-info → django_restit-4.2.86.dist-info}/LICENSE.md +0 -0
- {django_restit-4.2.84.dist-info → django_restit-4.2.86.dist-info}/WHEEL +0 -0
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
|
|
@@ -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=
|
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
|
@@ -112,14 +112,14 @@ incident/migrations/0015_rule_title_template_alter_incident_state.py,sha256=FPUD
|
|
112
112
|
incident/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
113
113
|
incident/models/__init__.py,sha256=NMphuhb0RTMf7Ov4QkNv7iv6_I8Wtr3xQ54yjX_a31M,209
|
114
114
|
incident/models/event.py,sha256=Dw6fUi2tbLeA_ZRDcvGQNFkCkMGMBdtNeaLikXdAyE8,7769
|
115
|
-
incident/models/incident.py,sha256=
|
115
|
+
incident/models/incident.py,sha256=XB7FgyV26sgxSOHu69UTlLmLs1vljf0O6KyN114Rf2I,19585
|
116
116
|
incident/models/ossec.py,sha256=eUDRGawzuLWobKEVGKfdZisDnyjS_Hlxi0T_GCSLCCI,2252
|
117
117
|
incident/models/rules.py,sha256=aRkJ0ZnTv87nAUC1sHVkPExfb3OJ8fgHQIhnCIpIbhQ,7001
|
118
118
|
incident/models/ticket.py,sha256=S3kqGQpYLE6Y4M9IKu_60sgW-f592xNr8uufqHnvDoU,2302
|
119
119
|
incident/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
120
120
|
incident/parsers/ossec.py,sha256=jyJmNBwnQS1tjZMwYhslnCpZviCHXnozv88BPT-ytCw,11592
|
121
121
|
incident/periodic.py,sha256=eX1rQK6v65A9ugofTvJPSmAWei6C-3EYgzCMuGZ03jM,381
|
122
|
-
incident/rpc.py,sha256=
|
122
|
+
incident/rpc.py,sha256=6JVWTTAr4CN2tAjjIUcXug1z3RhU_ar5CDLzedkduA4,8187
|
123
123
|
incident/templates/email/incident_change.html,sha256=tQYphypwLukkVdwH0TB2Szz2VEJ7GnsfRS3_ZJ-MYeE,13895
|
124
124
|
incident/templates/email/incident_msg.html,sha256=MZdKhTddUF2MpiH8Z3RTQEmW_ko1n3ajeZ11KLtiLlU,13780
|
125
125
|
incident/templates/email/incident_new.html,sha256=W6nwFQROnyDfMlXub8s02ws4hGnJp16pfgp9xTm_aEc,15185
|
@@ -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=
|
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
|
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=
|
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=
|
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=
|
390
|
+
rest/helpers.py,sha256=Ok4qUhSgepo3HjMe1EPwv5ZCWyMhM-HVFGUMnQclT00,29424
|
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.
|
510
|
-
django_restit-4.2.
|
511
|
-
django_restit-4.2.
|
512
|
-
django_restit-4.2.
|
509
|
+
django_restit-4.2.86.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
|
510
|
+
django_restit-4.2.86.dist-info/METADATA,sha256=VgZXfFw-5VGQ9LfHhDDTKtJSJ056KXbmDThinDakpIU,7645
|
511
|
+
django_restit-4.2.86.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
512
|
+
django_restit-4.2.86.dist-info/RECORD,,
|
incident/models/incident.py
CHANGED
@@ -4,7 +4,7 @@ from rest import settings
|
|
4
4
|
from rest import models as rm
|
5
5
|
from rest import helpers as rh
|
6
6
|
from taskqueue.models import Task
|
7
|
-
from account.models import Member
|
7
|
+
from account.models import Member, Group
|
8
8
|
from objict import objict
|
9
9
|
from datetime import datetime, timedelta
|
10
10
|
from rest import log
|
@@ -255,10 +255,16 @@ class Incident(models.Model, rm.RestModel, rm.MetaDataModel):
|
|
255
255
|
rh.log_exception("triggerSMS")
|
256
256
|
|
257
257
|
def triggerGroup(self):
|
258
|
+
if self.rule.action.count(":") == 2:
|
259
|
+
action, gid, perm = self.rule.action.split(":")
|
260
|
+
self.group = Group.objects.filter(pk=int(gid)).last()
|
261
|
+
self.save()
|
262
|
+
else:
|
263
|
+
action, perm = self.rule.action.split(":")
|
264
|
+
|
258
265
|
if not self.group:
|
259
266
|
self.notifyWith("notify.unknown_incidents")
|
260
267
|
return
|
261
|
-
action, perm = self.rule.action.split(":")
|
262
268
|
self.action_sent = datetime.now()
|
263
269
|
self.save()
|
264
270
|
|
@@ -472,13 +478,13 @@ class IncidentHistory(models.Model, rm.RestModel):
|
|
472
478
|
SEARCH_FIELDS = ["to__username", "note"]
|
473
479
|
GRAPHS = {
|
474
480
|
"default": {
|
475
|
-
"extra":[
|
481
|
+
"extra": [
|
476
482
|
("get_state_display", "state_display"),
|
477
483
|
("get_priority_display", "priority_display"),
|
478
484
|
],
|
479
|
-
"graphs":{
|
480
|
-
"by":"basic",
|
481
|
-
"to":"basic",
|
485
|
+
"graphs": {
|
486
|
+
"by": "basic",
|
487
|
+
"to": "basic",
|
482
488
|
"media": "basic"
|
483
489
|
}
|
484
490
|
},
|
incident/rpc.py
CHANGED
@@ -18,7 +18,7 @@ def patched_restPermissionDenied(request, error="permission denied",
|
|
18
18
|
component=None, component_id=None):
|
19
19
|
|
20
20
|
description = f"permission denied: {error_code} '{error}' for {request.user} {request.method}:{request.path}"
|
21
|
-
rh.log_error(description)
|
21
|
+
# rh.log_error(description)
|
22
22
|
if error_code == 404:
|
23
23
|
if not request.path.startswith(LOG_REST_PREFIX) and not request.path.startswith("/rpc"):
|
24
24
|
# just ignore these
|
@@ -61,7 +61,7 @@ def ossec_alert_creat_from_request(request):
|
|
61
61
|
if payload:
|
62
62
|
try:
|
63
63
|
# TODO make this a task (background it)
|
64
|
-
rh.log_error("parsing payload", payload)
|
64
|
+
# rh.log_error("parsing payload", payload)
|
65
65
|
od = ossec.parseAlert(request, payload)
|
66
66
|
# lets now create a local event
|
67
67
|
if od is not None:
|
@@ -118,7 +118,7 @@ def ossec_alert_creat_from_request(request):
|
|
118
118
|
"category": "ossec_error",
|
119
119
|
"metadata": metadata
|
120
120
|
})
|
121
|
-
rh.log_error("ossec alert", request.DATA.asDict())
|
121
|
+
# rh.log_error("ossec alert", request.DATA.asDict())
|
122
122
|
return rv.restStatus(request, False, error="no alert data")
|
123
123
|
|
124
124
|
|
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 =
|
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
|
-
|
64
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
if
|
105
|
-
|
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)[: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))):
|
File without changes
|
File without changes
|