udata 11.0.2.dev12__py3-none-any.whl → 11.0.2.dev14__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/commands/fixtures.py +0 -1
- udata/core/dataset/api.py +8 -0
- udata/core/dataset/constants.py +5 -0
- udata/core/dataset/models.py +13 -0
- udata/core/topic/activities.py +57 -1
- udata/core/topic/apiv2.py +2 -4
- udata/core/topic/models.py +19 -2
- 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.51d706fb9521c16976bc.js → 11.b6f741fcc366abfad9c4.js} +3 -3
- udata/static/chunks/{11.51d706fb9521c16976bc.js.map → 11.b6f741fcc366abfad9c4.js.map} +1 -1
- udata/static/chunks/{13.f29411b06be1883356a3.js → 13.2d06442dd9a05d9777b5.js} +2 -2
- udata/static/chunks/{13.f29411b06be1883356a3.js.map → 13.2d06442dd9a05d9777b5.js.map} +1 -1
- udata/static/chunks/{17.3bd0340930d4a314ce9c.js → 17.e8e4caaad5cb0cc0bacc.js} +2 -2
- udata/static/chunks/{17.3bd0340930d4a314ce9c.js.map → 17.e8e4caaad5cb0cc0bacc.js.map} +1 -1
- udata/static/chunks/{19.8da42e8359d72afc2618.js → 19.f03a102365af4315f9db.js} +3 -3
- udata/static/chunks/{19.8da42e8359d72afc2618.js.map → 19.f03a102365af4315f9db.js.map} +1 -1
- udata/static/chunks/{8.54e44b102164ae5e7a67.js → 8.778091d55cd8ea39af6b.js} +2 -2
- udata/static/chunks/{8.54e44b102164ae5e7a67.js.map → 8.778091d55cd8ea39af6b.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/tests/api/test_activities_api.py +22 -0
- udata/tests/apiv2/test_datasets.py +15 -0
- udata/tests/apiv2/test_topics.py +75 -0
- udata/tests/test_topics.py +68 -1
- {udata-11.0.2.dev12.dist-info → udata-11.0.2.dev14.dist-info}/METADATA +1 -1
- {udata-11.0.2.dev12.dist-info → udata-11.0.2.dev14.dist-info}/RECORD +33 -33
- {udata-11.0.2.dev12.dist-info → udata-11.0.2.dev14.dist-info}/WHEEL +0 -0
- {udata-11.0.2.dev12.dist-info → udata-11.0.2.dev14.dist-info}/entry_points.txt +0 -0
- {udata-11.0.2.dev12.dist-info → udata-11.0.2.dev14.dist-info}/licenses/LICENSE +0 -0
- {udata-11.0.2.dev12.dist-info → udata-11.0.2.dev14.dist-info}/top_level.txt +0 -0
udata/commands/fixtures.py
CHANGED
udata/core/dataset/api.py
CHANGED
|
@@ -115,6 +115,12 @@ class DatasetApiParser(ModelApiParser):
|
|
|
115
115
|
self.parser.add_argument("granularity", type=str, location="args")
|
|
116
116
|
self.parser.add_argument("temporal_coverage", type=str, location="args")
|
|
117
117
|
self.parser.add_argument("organization", type=str, location="args")
|
|
118
|
+
self.parser.add_argument(
|
|
119
|
+
"badge",
|
|
120
|
+
type=str,
|
|
121
|
+
choices=list(Dataset.__badges__),
|
|
122
|
+
location="args",
|
|
123
|
+
)
|
|
118
124
|
self.parser.add_argument(
|
|
119
125
|
"organization_badge",
|
|
120
126
|
type=str,
|
|
@@ -178,6 +184,8 @@ class DatasetApiParser(ModelApiParser):
|
|
|
178
184
|
)
|
|
179
185
|
if args.get("featured") is not None:
|
|
180
186
|
datasets = datasets.filter(featured=args["featured"])
|
|
187
|
+
if args.get("badge"):
|
|
188
|
+
datasets = datasets.with_badge(args["badge"])
|
|
181
189
|
if args.get("organization"):
|
|
182
190
|
if not ObjectId.is_valid(args["organization"]):
|
|
183
191
|
api.abort(400, "Organization arg must be an identifier")
|
udata/core/dataset/constants.py
CHANGED
|
@@ -78,6 +78,11 @@ CHECKSUM_TYPES = ("sha1", "sha2", "sha256", "md5", "crc")
|
|
|
78
78
|
DEFAULT_CHECKSUM_TYPE = "sha1"
|
|
79
79
|
|
|
80
80
|
PIVOTAL_DATA = "pivotal-data"
|
|
81
|
+
SPD = "spd"
|
|
82
|
+
INSPIRE = "inspire"
|
|
83
|
+
HVD = "hvd"
|
|
84
|
+
SL = "sl"
|
|
85
|
+
SR = "sr"
|
|
81
86
|
CLOSED_FORMATS = ("pdf", "doc", "docx", "word", "xls", "excel", "xlsx")
|
|
82
87
|
|
|
83
88
|
# Maximum acceptable Damerau-Levenshtein distance
|
udata/core/dataset/models.py
CHANGED
|
@@ -36,12 +36,17 @@ from .constants import (
|
|
|
36
36
|
CLOSED_FORMATS,
|
|
37
37
|
DEFAULT_LICENSE,
|
|
38
38
|
DESCRIPTION_SHORT_SIZE_LIMIT,
|
|
39
|
+
HVD,
|
|
40
|
+
INSPIRE,
|
|
39
41
|
LEGACY_FREQUENCIES,
|
|
40
42
|
MAX_DISTANCE,
|
|
41
43
|
PIVOTAL_DATA,
|
|
42
44
|
RESOURCE_FILETYPES,
|
|
43
45
|
RESOURCE_TYPES,
|
|
44
46
|
SCHEMA_CACHE_DURATION,
|
|
47
|
+
SL,
|
|
48
|
+
SPD,
|
|
49
|
+
SR,
|
|
45
50
|
UPDATE_FREQUENCIES,
|
|
46
51
|
)
|
|
47
52
|
from .exceptions import (
|
|
@@ -61,6 +66,11 @@ __all__ = (
|
|
|
61
66
|
|
|
62
67
|
BADGES: dict[str, str] = {
|
|
63
68
|
PIVOTAL_DATA: _("Pivotal data"),
|
|
69
|
+
SPD: _("Reference data public service"),
|
|
70
|
+
INSPIRE: _("Inspire"),
|
|
71
|
+
HVD: _("High value datasets"),
|
|
72
|
+
SL: _("Certified statistic series"),
|
|
73
|
+
SR: _("Statistical series of general interest"),
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
NON_ASSIGNABLE_SCHEMA_TYPES = ["datapackage"]
|
|
@@ -334,6 +344,9 @@ class DatasetQuerySet(OwnedQuerySet):
|
|
|
334
344
|
def hidden(self):
|
|
335
345
|
return self(db.Q(private=True) | db.Q(deleted__ne=None) | db.Q(archived__ne=None))
|
|
336
346
|
|
|
347
|
+
def with_badge(self, kind):
|
|
348
|
+
return self(badges__kind=kind)
|
|
349
|
+
|
|
337
350
|
|
|
338
351
|
class Checksum(db.EmbeddedDocument):
|
|
339
352
|
type = db.StringField(choices=CHECKSUM_TYPES, required=True)
|
udata/core/topic/activities.py
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
from flask_security import current_user
|
|
2
2
|
|
|
3
|
+
from udata.core.topic.models import TopicElement
|
|
3
4
|
from udata.i18n import lazy_gettext as _
|
|
4
5
|
from udata.models import Activity, Topic, db
|
|
5
6
|
|
|
6
|
-
__all__ = (
|
|
7
|
+
__all__ = (
|
|
8
|
+
"UserCreatedTopic",
|
|
9
|
+
"UserUpdatedTopic",
|
|
10
|
+
"UserCreatedTopicElement",
|
|
11
|
+
"UserUpdatedTopicElement",
|
|
12
|
+
"UserDeletedTopicElement",
|
|
13
|
+
"TopicRelatedActivity",
|
|
14
|
+
)
|
|
7
15
|
|
|
8
16
|
|
|
9
17
|
class TopicRelatedActivity(object):
|
|
@@ -23,6 +31,26 @@ class UserUpdatedTopic(TopicRelatedActivity, Activity):
|
|
|
23
31
|
label = _("updated a topic")
|
|
24
32
|
|
|
25
33
|
|
|
34
|
+
class UserCreatedTopicElement(TopicRelatedActivity, Activity):
|
|
35
|
+
key = "topic:element:created"
|
|
36
|
+
icon = "fa fa-plus"
|
|
37
|
+
badge_type = "success"
|
|
38
|
+
label = _("added an element to a topic")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class UserUpdatedTopicElement(TopicRelatedActivity, Activity):
|
|
42
|
+
key = "topic:element:updated"
|
|
43
|
+
icon = "fa fa-pencil"
|
|
44
|
+
label = _("updated an element in a topic")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class UserDeletedTopicElement(TopicRelatedActivity, Activity):
|
|
48
|
+
key = "topic:element:deleted"
|
|
49
|
+
icon = "fa fa-remove"
|
|
50
|
+
badge_type = "error"
|
|
51
|
+
label = _("removed an element from a topic")
|
|
52
|
+
|
|
53
|
+
|
|
26
54
|
@Topic.on_create.connect
|
|
27
55
|
def on_user_created_topic(topic):
|
|
28
56
|
if current_user and current_user.is_authenticated:
|
|
@@ -34,3 +62,31 @@ def on_user_updated_topic(topic, **kwargs):
|
|
|
34
62
|
changed_fields = kwargs.get("changed_fields", [])
|
|
35
63
|
if current_user and current_user.is_authenticated:
|
|
36
64
|
UserUpdatedTopic.emit(topic, topic.organization, changed_fields)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@TopicElement.on_create.connect
|
|
68
|
+
def on_user_created_topic_element(topic_element):
|
|
69
|
+
if current_user and current_user.is_authenticated and topic_element.topic:
|
|
70
|
+
extras = {"element_id": str(topic_element.id)}
|
|
71
|
+
UserCreatedTopicElement.emit(
|
|
72
|
+
topic_element.topic, topic_element.topic.organization, extras=extras
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@TopicElement.on_update.connect
|
|
77
|
+
def on_user_updated_topic_element(topic_element, **kwargs):
|
|
78
|
+
changed_fields = kwargs.get("changed_fields", [])
|
|
79
|
+
if current_user and current_user.is_authenticated and topic_element.topic:
|
|
80
|
+
extras = {"element_id": str(topic_element.id)}
|
|
81
|
+
UserUpdatedTopicElement.emit(
|
|
82
|
+
topic_element.topic, topic_element.topic.organization, changed_fields, extras=extras
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@TopicElement.on_delete.connect
|
|
87
|
+
def on_user_deleted_topic_element(topic_element):
|
|
88
|
+
if current_user and current_user.is_authenticated and topic_element.topic:
|
|
89
|
+
extras = {"element_id": str(topic_element.id)}
|
|
90
|
+
UserDeletedTopicElement.emit(
|
|
91
|
+
topic_element.topic, topic_element.topic.organization, extras=extras
|
|
92
|
+
)
|
udata/core/topic/apiv2.py
CHANGED
|
@@ -130,16 +130,13 @@ class TopicElementsAPI(API):
|
|
|
130
130
|
else:
|
|
131
131
|
element = TopicElement()
|
|
132
132
|
form.populate_obj(element)
|
|
133
|
+
element.topic = topic
|
|
133
134
|
element.save()
|
|
134
135
|
elements.append(element)
|
|
135
136
|
|
|
136
137
|
if errors:
|
|
137
138
|
apiv2.abort(400, errors=errors)
|
|
138
139
|
|
|
139
|
-
for element in elements:
|
|
140
|
-
element.topic = topic
|
|
141
|
-
element.save()
|
|
142
|
-
|
|
143
140
|
topic.save()
|
|
144
141
|
|
|
145
142
|
return topic, 201
|
|
@@ -157,6 +154,7 @@ class TopicElementsAPI(API):
|
|
|
157
154
|
if not TopicEditPermission(topic).can():
|
|
158
155
|
apiv2.abort(403, "Forbidden")
|
|
159
156
|
|
|
157
|
+
# TODO: this triggers performance issues on a huge topic (too many tasks, too many activities)
|
|
160
158
|
topic.elements.delete()
|
|
161
159
|
|
|
162
160
|
return None, 204
|
udata/core/topic/models.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from blinker import Signal
|
|
2
|
+
from flask import url_for
|
|
2
3
|
from mongoengine.signals import post_delete, post_save
|
|
3
4
|
|
|
4
5
|
from udata.api_fields import field
|
|
5
6
|
from udata.core.activity.models import Auditable
|
|
6
7
|
from udata.core.dataset.models import Dataset
|
|
8
|
+
from udata.core.linkable import Linkable
|
|
7
9
|
from udata.core.owned import Owned, OwnedQuerySet
|
|
8
10
|
from udata.core.reuse.models import Reuse
|
|
9
11
|
from udata.models import SpatialCoverage, db
|
|
@@ -13,7 +15,7 @@ from udata.tasks import as_task_param
|
|
|
13
15
|
__all__ = ("Topic", "TopicElement")
|
|
14
16
|
|
|
15
17
|
|
|
16
|
-
class TopicElement(db.Document):
|
|
18
|
+
class TopicElement(Auditable, db.Document):
|
|
17
19
|
title = field(db.StringField(required=False))
|
|
18
20
|
description = field(db.StringField(required=False))
|
|
19
21
|
tags = field(db.ListField(db.StringField()))
|
|
@@ -31,9 +33,16 @@ class TopicElement(db.Document):
|
|
|
31
33
|
"auto_create_index_on_save": True,
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
after_save = Signal()
|
|
37
|
+
on_create = Signal()
|
|
38
|
+
on_update = Signal()
|
|
39
|
+
on_delete = Signal()
|
|
40
|
+
|
|
34
41
|
@classmethod
|
|
35
42
|
def post_save(cls, sender, document, **kwargs):
|
|
36
43
|
"""Trigger reindex when element is saved"""
|
|
44
|
+
# Call parent post_save for Auditable functionality
|
|
45
|
+
super().post_save(sender, document, **kwargs)
|
|
37
46
|
if document.topic and document.element and hasattr(document.element, "id"):
|
|
38
47
|
reindex.delay(*as_task_param(document.element))
|
|
39
48
|
|
|
@@ -42,9 +51,10 @@ class TopicElement(db.Document):
|
|
|
42
51
|
"""Trigger reindex when element is deleted"""
|
|
43
52
|
if document.topic and document.element and hasattr(document.element, "id"):
|
|
44
53
|
reindex.delay(*as_task_param(document.element))
|
|
54
|
+
cls.on_delete.send(document)
|
|
45
55
|
|
|
46
56
|
|
|
47
|
-
class Topic(db.Datetimed, Auditable, db.Document, Owned):
|
|
57
|
+
class Topic(db.Datetimed, Auditable, Linkable, db.Document, Owned):
|
|
48
58
|
name = field(db.StringField(required=True))
|
|
49
59
|
slug = field(
|
|
50
60
|
db.SlugField(max_length=255, required=True, populate_from="name", update=True, follow=True),
|
|
@@ -108,6 +118,13 @@ class Topic(db.Datetimed, Auditable, db.Document, Owned):
|
|
|
108
118
|
# Useful for Discussions to call self_web_url on their `subject`
|
|
109
119
|
return None
|
|
110
120
|
|
|
121
|
+
def self_api_url(self, **kwargs):
|
|
122
|
+
return url_for(
|
|
123
|
+
"apiv2.topic",
|
|
124
|
+
topic=self._link_id(**kwargs),
|
|
125
|
+
**self._self_api_url_kwargs(**kwargs),
|
|
126
|
+
)
|
|
127
|
+
|
|
111
128
|
|
|
112
129
|
post_save.connect(Topic.post_save, sender=Topic)
|
|
113
130
|
post_save.connect(TopicElement.post_save, sender=TopicElement)
|