udata 11.0.2.dev13__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.

Files changed (28) hide show
  1. udata/core/topic/activities.py +57 -1
  2. udata/core/topic/apiv2.py +2 -4
  3. udata/core/topic/models.py +19 -2
  4. udata/static/chunks/{11.51d706fb9521c16976bc.js → 11.b6f741fcc366abfad9c4.js} +3 -3
  5. udata/static/chunks/{11.51d706fb9521c16976bc.js.map → 11.b6f741fcc366abfad9c4.js.map} +1 -1
  6. udata/static/chunks/{13.39e106d56f794ebd06a0.js → 13.2d06442dd9a05d9777b5.js} +2 -2
  7. udata/static/chunks/{13.39e106d56f794ebd06a0.js.map → 13.2d06442dd9a05d9777b5.js.map} +1 -1
  8. udata/static/chunks/{17.70cbb4a91b002338007e.js → 17.e8e4caaad5cb0cc0bacc.js} +2 -2
  9. udata/static/chunks/{17.70cbb4a91b002338007e.js.map → 17.e8e4caaad5cb0cc0bacc.js.map} +1 -1
  10. udata/static/chunks/{19.a348a5fff8fe2801e52a.js → 19.f03a102365af4315f9db.js} +3 -3
  11. udata/static/chunks/{19.a348a5fff8fe2801e52a.js.map → 19.f03a102365af4315f9db.js.map} +1 -1
  12. udata/static/chunks/{5.343ca020a2d38cec1a14.js → 5.0fa1408dae4e76b87b2e.js} +3 -3
  13. udata/static/chunks/{5.343ca020a2d38cec1a14.js.map → 5.0fa1408dae4e76b87b2e.js.map} +1 -1
  14. udata/static/chunks/{6.a3b07de9dd2ca2d24e85.js → 6.d663709d877baa44a71e.js} +3 -3
  15. udata/static/chunks/{6.a3b07de9dd2ca2d24e85.js.map → 6.d663709d877baa44a71e.js.map} +1 -1
  16. udata/static/chunks/{8.462bb3029de008497675.js → 8.778091d55cd8ea39af6b.js} +2 -2
  17. udata/static/chunks/{8.462bb3029de008497675.js.map → 8.778091d55cd8ea39af6b.js.map} +1 -1
  18. udata/static/common.js +1 -1
  19. udata/static/common.js.map +1 -1
  20. udata/tests/api/test_activities_api.py +22 -0
  21. udata/tests/apiv2/test_topics.py +75 -0
  22. udata/tests/test_topics.py +68 -1
  23. {udata-11.0.2.dev13.dist-info → udata-11.0.2.dev14.dist-info}/METADATA +1 -1
  24. {udata-11.0.2.dev13.dist-info → udata-11.0.2.dev14.dist-info}/RECORD +28 -28
  25. {udata-11.0.2.dev13.dist-info → udata-11.0.2.dev14.dist-info}/WHEEL +0 -0
  26. {udata-11.0.2.dev13.dist-info → udata-11.0.2.dev14.dist-info}/entry_points.txt +0 -0
  27. {udata-11.0.2.dev13.dist-info → udata-11.0.2.dev14.dist-info}/licenses/LICENSE +0 -0
  28. {udata-11.0.2.dev13.dist-info → udata-11.0.2.dev14.dist-info}/top_level.txt +0 -0
@@ -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__ = ("UserCreatedTopic", "UserUpdatedTopic", "TopicRelatedActivity")
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
@@ -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)