udata 10.4.2.dev35441__py2.py3-none-any.whl → 10.4.2.dev35451__py2.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.
Potentially problematic release.
This version of udata might be problematic. Click here for more details.
- udata/core/metrics/commands.py +1 -0
- udata/core/metrics/helpers.py +102 -0
- udata/core/metrics/tasks.py +1 -0
- udata/core/site/models.py +33 -0
- udata/settings.py +4 -0
- udata/static/chunks/{10.471164b2a9fe15614797.js → 10.8ca60413647062717b1e.js} +3 -3
- udata/static/chunks/{10.471164b2a9fe15614797.js.map → 10.8ca60413647062717b1e.js.map} +1 -1
- udata/static/chunks/{11.0f04e49a40a0a381bcce.js → 11.51d706fb9521c16976bc.js} +3 -3
- udata/static/chunks/{11.0f04e49a40a0a381bcce.js.map → 11.51d706fb9521c16976bc.js.map} +1 -1
- udata/static/chunks/{13.2d06442dd9a05d9777b5.js → 13.d9c1735d14038b94c17e.js} +2 -2
- udata/static/chunks/{13.2d06442dd9a05d9777b5.js.map → 13.d9c1735d14038b94c17e.js.map} +1 -1
- udata/static/chunks/{17.e8e4caaad5cb0cc0bacc.js → 17.81c57c0dedf812e43013.js} +2 -2
- udata/static/chunks/{17.e8e4caaad5cb0cc0bacc.js.map → 17.81c57c0dedf812e43013.js.map} +1 -1
- udata/static/chunks/{19.df16abde17a42033a7f8.js → 19.a348a5fff8fe2801e52a.js} +3 -3
- udata/static/chunks/{19.df16abde17a42033a7f8.js.map → 19.a348a5fff8fe2801e52a.js.map} +1 -1
- udata/static/chunks/{8.0f42630e6d8ff782928e.js → 8.462bb3029de008497675.js} +2 -2
- udata/static/chunks/{8.0f42630e6d8ff782928e.js.map → 8.462bb3029de008497675.js.map} +1 -1
- udata/static/chunks/{9.07515e5187f475bce828.js → 9.033d7e190ca9e226a5d0.js} +3 -3
- udata/static/chunks/{9.07515e5187f475bce828.js.map → 9.033d7e190ca9e226a5d0.js.map} +1 -1
- udata/static/common.js +1 -1
- udata/static/common.js.map +1 -1
- {udata-10.4.2.dev35441.dist-info → udata-10.4.2.dev35451.dist-info}/METADATA +2 -1
- {udata-10.4.2.dev35441.dist-info → udata-10.4.2.dev35451.dist-info}/RECORD +27 -26
- {udata-10.4.2.dev35441.dist-info → udata-10.4.2.dev35451.dist-info}/LICENSE +0 -0
- {udata-10.4.2.dev35441.dist-info → udata-10.4.2.dev35451.dist-info}/WHEEL +0 -0
- {udata-10.4.2.dev35441.dist-info → udata-10.4.2.dev35451.dist-info}/entry_points.txt +0 -0
- {udata-10.4.2.dev35441.dist-info → udata-10.4.2.dev35451.dist-info}/top_level.txt +0 -0
udata/core/metrics/commands.py
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from collections import OrderedDict
|
|
3
|
+
from datetime import datetime, timedelta
|
|
4
|
+
from typing import Dict, List, Union
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from bson import ObjectId
|
|
8
|
+
from dateutil.rrule import MONTHLY, rrule
|
|
9
|
+
from flask import current_app
|
|
10
|
+
from mongoengine import QuerySet
|
|
11
|
+
from pymongo.command_cursor import CommandCursor
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_last_13_months() -> List[str]:
|
|
17
|
+
dstart = datetime.today().replace(day=1) - timedelta(days=365)
|
|
18
|
+
months = rrule(freq=MONTHLY, count=13, dtstart=dstart)
|
|
19
|
+
return [month.strftime("%Y-%m") for month in months]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def compute_monthly_metrics(metrics_data: List[Dict], metrics_labels: List[str]) -> OrderedDict:
|
|
23
|
+
# Initialize default monthly_metrics
|
|
24
|
+
monthly_metrics = OrderedDict(
|
|
25
|
+
(month, {label: 0 for label in metrics_labels}) for month in get_last_13_months()
|
|
26
|
+
)
|
|
27
|
+
# Update monthly_metrics with metrics_data values
|
|
28
|
+
for entry in metrics_data:
|
|
29
|
+
entry_month = entry["metric_month"]
|
|
30
|
+
if entry_month in monthly_metrics:
|
|
31
|
+
for metric_label in metrics_labels:
|
|
32
|
+
label = f"monthly_{metric_label}"
|
|
33
|
+
monthly_metrics[entry_month][metric_label] = entry.get(label) or 0
|
|
34
|
+
return monthly_metrics
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def metrics_by_label(monthly_metrics: Dict, metrics_labels: List[str]) -> List[OrderedDict]:
|
|
38
|
+
metrics_by_label = []
|
|
39
|
+
for label in metrics_labels:
|
|
40
|
+
metrics_by_label.append(
|
|
41
|
+
OrderedDict((month, monthly_metrics[month][label]) for month in monthly_metrics)
|
|
42
|
+
)
|
|
43
|
+
return metrics_by_label
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_metrics_for_model(
|
|
47
|
+
model: str, id: Union[str, ObjectId, None], metrics_labels: List[str]
|
|
48
|
+
) -> List[OrderedDict]:
|
|
49
|
+
"""
|
|
50
|
+
Get distant metrics for a particular model object
|
|
51
|
+
"""
|
|
52
|
+
if not current_app.config["METRICS_API"]:
|
|
53
|
+
# TODO: How to best deal with no METRICS_API, prevent calling or return empty?
|
|
54
|
+
# raise ValueError("missing config METRICS_API to use this function")
|
|
55
|
+
return [{} for _ in range(len(metrics_labels))]
|
|
56
|
+
models = model + "s" if id else model # TODO: not clean of a hack
|
|
57
|
+
model_metrics_api = f"{current_app.config['METRICS_API']}/{models}/data/"
|
|
58
|
+
try:
|
|
59
|
+
params = {"metric_month__sort": "desc"}
|
|
60
|
+
if id:
|
|
61
|
+
params[f"{model}_id__exact"] = id
|
|
62
|
+
res = requests.get(model_metrics_api, params)
|
|
63
|
+
res.raise_for_status()
|
|
64
|
+
monthly_metrics = compute_monthly_metrics(res.json()["data"], metrics_labels)
|
|
65
|
+
return metrics_by_label(monthly_metrics, metrics_labels)
|
|
66
|
+
except requests.exceptions.RequestException as e:
|
|
67
|
+
log.exception(f"Error while getting metrics for {model}({id}): {e}")
|
|
68
|
+
return [{} for _ in range(len(metrics_labels))]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def compute_monthly_aggregated_metrics(aggregation_res: CommandCursor) -> OrderedDict:
|
|
72
|
+
monthly_metrics = OrderedDict((month, 0) for month in get_last_13_months())
|
|
73
|
+
for monthly_count in aggregation_res:
|
|
74
|
+
year, month = monthly_count["_id"].split("-")
|
|
75
|
+
monthly_label = year + "-" + month.zfill(2)
|
|
76
|
+
if monthly_label in monthly_metrics:
|
|
77
|
+
monthly_metrics[monthly_label] = monthly_count["count"]
|
|
78
|
+
return monthly_metrics
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_stock_metrics(objects: QuerySet, date_label: str = "created_at") -> OrderedDict:
|
|
82
|
+
"""
|
|
83
|
+
Get stock metrics for a particular model object
|
|
84
|
+
"""
|
|
85
|
+
pipeline = [
|
|
86
|
+
{"$match": {date_label: {"$gte": datetime.now() - timedelta(days=365)}}},
|
|
87
|
+
{
|
|
88
|
+
"$group": {
|
|
89
|
+
"_id": {
|
|
90
|
+
"$concat": [
|
|
91
|
+
{"$substr": [{"$year": f"${date_label}"}, 0, 4]},
|
|
92
|
+
"-",
|
|
93
|
+
{"$substr": [{"$month": f"${date_label}"}, 0, 12]},
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"count": {"$sum": 1},
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
]
|
|
100
|
+
aggregation_res = objects.aggregate(*pipeline)
|
|
101
|
+
|
|
102
|
+
return compute_monthly_aggregated_metrics(aggregation_res)
|
udata/core/metrics/tasks.py
CHANGED
udata/core/site/models.py
CHANGED
|
@@ -3,6 +3,7 @@ from werkzeug.local import LocalProxy
|
|
|
3
3
|
|
|
4
4
|
from udata.core.dataservices.models import Dataservice
|
|
5
5
|
from udata.core.dataset.models import Dataset
|
|
6
|
+
from udata.core.metrics.helpers import get_metrics_for_model, get_stock_metrics
|
|
6
7
|
from udata.core.organization.models import Organization
|
|
7
8
|
from udata.core.reuse.models import Reuse
|
|
8
9
|
from udata.models import WithMetrics, db
|
|
@@ -36,15 +37,23 @@ class Site(WithMetrics, db.Document):
|
|
|
36
37
|
"max_org_reuses",
|
|
37
38
|
"max_org_datasets",
|
|
38
39
|
"datasets",
|
|
40
|
+
"datasets_visits_by_months",
|
|
39
41
|
"discussions",
|
|
40
42
|
"followers",
|
|
41
43
|
"organizations",
|
|
42
44
|
"public-service",
|
|
43
45
|
"resources",
|
|
46
|
+
"resources_downloads_by_months",
|
|
44
47
|
"reuses",
|
|
45
48
|
"dataservices",
|
|
46
49
|
"users",
|
|
47
50
|
"harvesters",
|
|
51
|
+
"users_by_months",
|
|
52
|
+
"datasets_by_months",
|
|
53
|
+
"harvesters_by_months",
|
|
54
|
+
"reuses_by_months",
|
|
55
|
+
"organizations_by_months",
|
|
56
|
+
"discussions_by_months",
|
|
48
57
|
]
|
|
49
58
|
|
|
50
59
|
def __str__(self):
|
|
@@ -72,6 +81,9 @@ class Site(WithMetrics, db.Document):
|
|
|
72
81
|
from udata.models import Dataset
|
|
73
82
|
|
|
74
83
|
self.metrics["datasets"] = Dataset.objects.visible().count()
|
|
84
|
+
self.metrics["datasets_visits_by_months"] = get_metrics_for_model(
|
|
85
|
+
"site", None, ["visit_dataset"]
|
|
86
|
+
)[0]
|
|
75
87
|
self.save()
|
|
76
88
|
|
|
77
89
|
def count_resources(self):
|
|
@@ -83,6 +95,9 @@ class Site(WithMetrics, db.Document):
|
|
|
83
95
|
),
|
|
84
96
|
{},
|
|
85
97
|
).get("count", 0)
|
|
98
|
+
self.metrics["resources_downloads_by_months"] = get_metrics_for_model(
|
|
99
|
+
"site", None, ["download_resource"]
|
|
100
|
+
)[0]
|
|
86
101
|
self.save()
|
|
87
102
|
|
|
88
103
|
def count_reuses(self):
|
|
@@ -172,6 +187,24 @@ class Site(WithMetrics, db.Document):
|
|
|
172
187
|
self.metrics["max_org_datasets"] = org.metrics["datasets"] if org else 0
|
|
173
188
|
self.save()
|
|
174
189
|
|
|
190
|
+
def count_stock_metrics(self):
|
|
191
|
+
from udata.harvest.models import HarvestSource
|
|
192
|
+
from udata.models import Discussion, User
|
|
193
|
+
|
|
194
|
+
self.metrics["users_by_months"] = get_stock_metrics(User.objects())
|
|
195
|
+
self.metrics["datasets_by_months"] = get_stock_metrics(
|
|
196
|
+
Dataset.objects().visible(), date_label="created_at_internal"
|
|
197
|
+
)
|
|
198
|
+
self.metrics["harvesters_by_months"] = get_stock_metrics(HarvestSource.objects())
|
|
199
|
+
self.metrics["reuses_by_months"] = get_stock_metrics(Reuse.objects().visible())
|
|
200
|
+
self.metrics["organizations_by_months"] = get_stock_metrics(
|
|
201
|
+
Organization.objects().visible()
|
|
202
|
+
)
|
|
203
|
+
self.metrics["discussions_by_months"] = get_stock_metrics(
|
|
204
|
+
Discussion.objects(), date_label="created"
|
|
205
|
+
)
|
|
206
|
+
self.save()
|
|
207
|
+
|
|
175
208
|
|
|
176
209
|
def get_current_site():
|
|
177
210
|
if getattr(g, "site", None) is None:
|
udata/settings.py
CHANGED
|
@@ -574,6 +574,10 @@ class Defaults(object):
|
|
|
574
574
|
###########################################################################
|
|
575
575
|
MAX_RESOURCES_IN_JSON_LD = 20
|
|
576
576
|
|
|
577
|
+
# Metrics settings
|
|
578
|
+
###########################################################################
|
|
579
|
+
METRICS_API = None
|
|
580
|
+
|
|
577
581
|
|
|
578
582
|
class Testing(object):
|
|
579
583
|
"""Sane values for testing. Should be applied as override"""
|