udata 10.4.2.dev35274__py2.py3-none-any.whl → 10.4.2.dev35386__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.

Files changed (40) hide show
  1. udata/core/activity/__init__.py +1 -0
  2. udata/core/activity/api.py +10 -2
  3. udata/core/activity/models.py +28 -1
  4. udata/core/activity/tasks.py +19 -4
  5. udata/core/dataservices/activities.py +53 -0
  6. udata/core/dataservices/models.py +16 -20
  7. udata/core/dataset/activities.py +52 -5
  8. udata/core/dataset/models.py +43 -42
  9. udata/core/metrics/models.py +1 -0
  10. udata/core/organization/activities.py +3 -2
  11. udata/core/organization/models.py +31 -31
  12. udata/core/owned.py +1 -1
  13. udata/core/reuse/activities.py +6 -5
  14. udata/core/reuse/models.py +8 -16
  15. udata/core/user/activities.py +17 -1
  16. udata/core/user/models.py +39 -32
  17. udata/mongo/datetime_fields.py +1 -0
  18. udata/static/chunks/{11.8a2f7828175824bcd74b.js → 11.b6f741fcc366abfad9c4.js} +3 -3
  19. udata/static/chunks/{11.8a2f7828175824bcd74b.js.map → 11.b6f741fcc366abfad9c4.js.map} +1 -1
  20. udata/static/chunks/{13.39e106d56f794ebd06a0.js → 13.2d06442dd9a05d9777b5.js} +2 -2
  21. udata/static/chunks/{13.39e106d56f794ebd06a0.js.map → 13.2d06442dd9a05d9777b5.js.map} +1 -1
  22. udata/static/chunks/{17.70cbb4a91b002338007e.js → 17.e8e4caaad5cb0cc0bacc.js} +2 -2
  23. udata/static/chunks/{17.70cbb4a91b002338007e.js.map → 17.e8e4caaad5cb0cc0bacc.js.map} +1 -1
  24. udata/static/chunks/{19.df16abde17a42033a7f8.js → 19.f03a102365af4315f9db.js} +3 -3
  25. udata/static/chunks/{19.df16abde17a42033a7f8.js.map → 19.f03a102365af4315f9db.js.map} +1 -1
  26. udata/static/chunks/{5.5660483641193b7f8295.js → 5.0fa1408dae4e76b87b2e.js} +3 -3
  27. udata/static/chunks/{5.5660483641193b7f8295.js.map → 5.0fa1408dae4e76b87b2e.js.map} +1 -1
  28. udata/static/chunks/{6.30dce49d17db07600b06.js → 6.d663709d877baa44a71e.js} +3 -3
  29. udata/static/chunks/{6.30dce49d17db07600b06.js.map → 6.d663709d877baa44a71e.js.map} +1 -1
  30. udata/static/chunks/{8.54e44b102164ae5e7a67.js → 8.778091d55cd8ea39af6b.js} +2 -2
  31. udata/static/chunks/{8.54e44b102164ae5e7a67.js.map → 8.778091d55cd8ea39af6b.js.map} +1 -1
  32. udata/static/common.js +1 -1
  33. udata/static/common.js.map +1 -1
  34. udata/tests/api/test_activities_api.py +29 -1
  35. {udata-10.4.2.dev35274.dist-info → udata-10.4.2.dev35386.dist-info}/METADATA +4 -2
  36. {udata-10.4.2.dev35274.dist-info → udata-10.4.2.dev35386.dist-info}/RECORD +40 -39
  37. {udata-10.4.2.dev35274.dist-info → udata-10.4.2.dev35386.dist-info}/LICENSE +0 -0
  38. {udata-10.4.2.dev35274.dist-info → udata-10.4.2.dev35386.dist-info}/WHEEL +0 -0
  39. {udata-10.4.2.dev35274.dist-info → udata-10.4.2.dev35386.dist-info}/entry_points.txt +0 -0
  40. {udata-10.4.2.dev35274.dist-info → udata-10.4.2.dev35386.dist-info}/top_level.txt +0 -0
@@ -33,17 +33,18 @@ class UserDeletedReuse(ReuseRelatedActivity, Activity):
33
33
 
34
34
  @Reuse.on_create.connect
35
35
  def on_user_created_reuse(reuse):
36
- if not reuse.private and current_user and current_user.is_authenticated:
36
+ if current_user and current_user.is_authenticated:
37
37
  UserCreatedReuse.emit(reuse, reuse.organization)
38
38
 
39
39
 
40
40
  @Reuse.on_update.connect
41
- def on_user_updated_reuse(reuse):
42
- if not reuse.private and current_user and current_user.is_authenticated:
43
- UserUpdatedReuse.emit(reuse, reuse.organization)
41
+ def on_user_updated_reuse(reuse, **kwargs):
42
+ changed_fields = kwargs.get("changed_fields", [])
43
+ if current_user and current_user.is_authenticated:
44
+ UserUpdatedReuse.emit(reuse, reuse.organization, changed_fields)
44
45
 
45
46
 
46
47
  @Reuse.on_delete.connect
47
48
  def on_user_deleted_reuse(reuse):
48
- if not reuse.private and current_user and current_user.is_authenticated:
49
+ if current_user and current_user.is_authenticated:
49
50
  UserDeletedReuse.emit(reuse, reuse.organization)
@@ -3,6 +3,7 @@ from mongoengine.signals import post_save, pre_save
3
3
  from werkzeug.utils import cached_property
4
4
 
5
5
  from udata.api_fields import field, function_field, generate_fields
6
+ from udata.core.activity.models import Auditable
6
7
  from udata.core.dataset.api_fields import dataset_fields
7
8
  from udata.core.owned import Owned, OwnedQuerySet
8
9
  from udata.core.reuse.api_fields import BIGGEST_IMAGE_SIZE
@@ -60,7 +61,7 @@ class ReuseBadgeMixin(BadgeMixin):
60
61
  additional_filters={"organization_badge": "organization.badges"},
61
62
  mask="*,datasets{id,title,uri,page}",
62
63
  )
63
- class Reuse(db.Datetimed, WithMetrics, ReuseBadgeMixin, Owned, db.Document):
64
+ class Reuse(db.Datetimed, Auditable, WithMetrics, ReuseBadgeMixin, Owned, db.Document):
64
65
  title = field(
65
66
  db.StringField(required=True),
66
67
  sortable=True,
@@ -71,6 +72,7 @@ class Reuse(db.Datetimed, WithMetrics, ReuseBadgeMixin, Owned, db.Document):
71
72
  max_length=255, required=True, populate_from="title", update=True, follow=True
72
73
  ),
73
74
  readonly=True,
75
+ auditable=False,
74
76
  )
75
77
  description = field(
76
78
  db.StringField(required=True),
@@ -126,15 +128,17 @@ class Reuse(db.Datetimed, WithMetrics, ReuseBadgeMixin, Owned, db.Document):
126
128
  private = field(db.BooleanField(default=False), filterable={})
127
129
 
128
130
  ext = db.MapField(db.GenericEmbeddedDocumentField())
129
- extras = field(db.ExtrasField())
131
+ extras = field(db.ExtrasField(), auditable=False)
130
132
 
131
133
  featured = field(
132
134
  db.BooleanField(),
133
135
  filterable={},
134
136
  readonly=True,
137
+ auditable=False,
135
138
  )
136
139
  deleted = field(
137
140
  db.DateTimeField(),
141
+ auditable=False,
138
142
  )
139
143
  archived = field(
140
144
  db.DateTimeField(),
@@ -181,18 +185,6 @@ class Reuse(db.Datetimed, WithMetrics, ReuseBadgeMixin, Owned, db.Document):
181
185
  # Emit before_save
182
186
  cls.before_save.send(document)
183
187
 
184
- @classmethod
185
- def post_save(cls, sender, document, **kwargs):
186
- if "post_save" in kwargs.get("ignores", []):
187
- return
188
- cls.after_save.send(document)
189
- if kwargs.get("created"):
190
- cls.on_create.send(document)
191
- else:
192
- cls.on_update.send(document)
193
- if document.deleted:
194
- cls.on_delete.send(document)
195
-
196
188
  def url_for(self, *args, **kwargs):
197
189
  return endpoint_for("reuses.show", "api.reuse", reuse=self, *args, **kwargs)
198
190
 
@@ -289,13 +281,13 @@ class Reuse(db.Datetimed, WithMetrics, ReuseBadgeMixin, Owned, db.Document):
289
281
  from udata.models import Discussion
290
282
 
291
283
  self.metrics["discussions"] = Discussion.objects(subject=self, closed=None).count()
292
- self.save()
284
+ self.save(signal_kwargs={"ignores": ["post_save"]})
293
285
 
294
286
  def count_followers(self):
295
287
  from udata.models import Follow
296
288
 
297
289
  self.metrics["followers"] = Follow.objects(until=None).followers(self).count()
298
- self.save()
290
+ self.save(signal_kwargs={"ignores": ["post_save"]})
299
291
 
300
292
 
301
293
  pre_save.connect(Reuse.pre_save, sender=Reuse)
@@ -1,5 +1,7 @@
1
1
  from flask_security import current_user
2
2
 
3
+ from udata.core.dataservices.activities import DataserviceRelatedActivity
4
+ from udata.core.dataservices.models import Dataservice
3
5
  from udata.core.dataset.activities import DatasetRelatedActivity
4
6
  from udata.core.discussions.signals import on_new_discussion, on_new_discussion_comment
5
7
  from udata.core.followers.signals import on_follow
@@ -40,6 +42,11 @@ class UserFollowedUser(FollowActivity, Activity):
40
42
  template = "activity/user.html"
41
43
 
42
44
 
45
+ class UserDiscussedDataservice(DiscussActivity, DataserviceRelatedActivity, Activity):
46
+ key = "dataservice:discussed"
47
+ label = _("discussed a dataservice")
48
+
49
+
43
50
  class UserDiscussedDataset(DiscussActivity, DatasetRelatedActivity, Activity):
44
51
  key = "dataset:discussed"
45
52
  label = _("discussed a dataset")
@@ -50,6 +57,11 @@ class UserDiscussedReuse(DiscussActivity, ReuseRelatedActivity, Activity):
50
57
  label = _("discussed a reuse")
51
58
 
52
59
 
60
+ class UserFollowedDataservice(FollowActivity, DataserviceRelatedActivity, Activity):
61
+ key = "dataservice:followed"
62
+ label = _("followed a dataservice")
63
+
64
+
53
65
  class UserFollowedDataset(FollowActivity, DatasetRelatedActivity, Activity):
54
66
  key = "dataset:followed"
55
67
  label = _("followed a dataset")
@@ -68,7 +80,9 @@ class UserFollowedOrganization(FollowActivity, OrgRelatedActivity, Activity):
68
80
  @on_follow.connect
69
81
  def write_activity_on_follow(follow, **kwargs):
70
82
  if current_user.is_authenticated:
71
- if isinstance(follow.following, Dataset):
83
+ if isinstance(follow.following, Dataservice):
84
+ UserFollowedDataservice.emit(follow.following)
85
+ elif isinstance(follow.following, Dataset):
72
86
  UserFollowedDataset.emit(follow.following)
73
87
  elif isinstance(follow.following, Reuse):
74
88
  UserFollowedReuse.emit(follow.following)
@@ -82,6 +96,8 @@ def write_activity_on_follow(follow, **kwargs):
82
96
  @on_new_discussion_comment.connect
83
97
  def write_activity_on_discuss(discussion, **kwargs):
84
98
  if current_user.is_authenticated:
99
+ if isinstance(discussion.subject, Dataservice):
100
+ UserDiscussedDataservice.emit(discussion.subject)
85
101
  if isinstance(discussion.subject, Dataset):
86
102
  UserDiscussedDataset.emit(discussion.subject)
87
103
  elif isinstance(discussion.subject, Reuse):
udata/core/user/models.py CHANGED
@@ -12,6 +12,7 @@ from mongoengine.signals import post_save, pre_save
12
12
  from werkzeug.utils import cached_property
13
13
 
14
14
  from udata import mail
15
+ from udata.api_fields import field
15
16
  from udata.core import storages
16
17
  from udata.core.discussions.models import Discussion
17
18
  from udata.core.storages import avatars, default_image_basename
@@ -42,49 +43,53 @@ class UserSettings(db.EmbeddedDocument):
42
43
 
43
44
 
44
45
  class User(WithMetrics, UserMixin, db.Document):
45
- slug = db.SlugField(max_length=255, required=True, populate_from="fullname")
46
- email = db.StringField(max_length=255, required=True, unique=True)
47
- password = db.StringField()
48
- active = db.BooleanField()
49
- fs_uniquifier = db.StringField(max_length=64, unique=True, sparse=True)
50
- roles = db.ListField(db.ReferenceField(Role), default=[])
46
+ slug = field(
47
+ db.SlugField(max_length=255, required=True, populate_from="fullname"), auditable=False
48
+ )
49
+ email = field(db.StringField(max_length=255, required=True, unique=True))
50
+ password = field(db.StringField())
51
+ active = field(db.BooleanField())
52
+ fs_uniquifier = field(db.StringField(max_length=64, unique=True, sparse=True))
53
+ roles = field(db.ListField(db.ReferenceField(Role), default=[]))
51
54
 
52
- first_name = db.StringField(max_length=255, required=True)
53
- last_name = db.StringField(max_length=255, required=True)
55
+ first_name = field(db.StringField(max_length=255, required=True))
56
+ last_name = field(db.StringField(max_length=255, required=True))
54
57
 
55
- avatar_url = db.URLField()
56
- avatar = db.ImageField(fs=avatars, basename=default_image_basename, thumbnails=AVATAR_SIZES)
57
- website = db.URLField()
58
- about = db.StringField()
58
+ avatar_url = field(db.URLField())
59
+ avatar = field(
60
+ db.ImageField(fs=avatars, basename=default_image_basename, thumbnails=AVATAR_SIZES)
61
+ )
62
+ website = field(db.URLField())
63
+ about = field(db.StringField())
59
64
 
60
- prefered_language = db.StringField()
65
+ prefered_language = field(db.StringField())
61
66
 
62
- apikey = db.StringField()
67
+ apikey = field(db.StringField())
63
68
 
64
- created_at = db.DateTimeField(default=datetime.utcnow, required=True)
69
+ created_at = field(db.DateTimeField(default=datetime.utcnow, required=True), auditable=False)
65
70
 
66
71
  # The field below is required for Flask-security
67
72
  # when SECURITY_CONFIRMABLE is True
68
- confirmed_at = db.DateTimeField()
73
+ confirmed_at = field(db.DateTimeField(), auditable=False)
69
74
 
70
- password_rotation_demanded = db.DateTimeField()
71
- password_rotation_performed = db.DateTimeField()
75
+ password_rotation_demanded = field(db.DateTimeField(), auditable=False)
76
+ password_rotation_performed = field(db.DateTimeField(), auditable=False)
72
77
 
73
78
  # The 5 fields below are required for Flask-security
74
79
  # when SECURITY_TRACKABLE is True
75
- last_login_at = db.DateTimeField()
76
- current_login_at = db.DateTimeField()
77
- last_login_ip = db.StringField()
78
- current_login_ip = db.StringField()
79
- login_count = db.IntField()
80
+ last_login_at = field(db.DateTimeField(), auditable=False)
81
+ current_login_at = field(db.DateTimeField(), auditable=False)
82
+ last_login_ip = field(db.StringField(), auditable=False)
83
+ current_login_ip = field(db.StringField(), auditable=False)
84
+ login_count = field(db.IntField(), auditable=False)
80
85
 
81
- deleted = db.DateTimeField()
82
- ext = db.MapField(db.GenericEmbeddedDocumentField())
83
- extras = db.ExtrasField()
86
+ deleted = field(db.DateTimeField())
87
+ ext = field(db.MapField(db.GenericEmbeddedDocumentField()))
88
+ extras = field(db.ExtrasField(), auditable=False)
84
89
 
85
90
  # Used to track notification for automatic inactive users deletion
86
91
  # when YEARS_OF_INACTIVITY_BEFORE_DELETION is set
87
- inactive_deletion_notified_at = db.DateTimeField()
92
+ inactive_deletion_notified_at = field(db.DateTimeField(), auditable=False)
88
93
 
89
94
  before_save = Signal()
90
95
  after_save = Signal()
@@ -209,6 +214,8 @@ class User(WithMetrics, UserMixin, db.Document):
209
214
 
210
215
  @classmethod
211
216
  def post_save(cls, sender, document, **kwargs):
217
+ if "post_save" in kwargs.get("ignores", []):
218
+ return
212
219
  cls.after_save.send(document)
213
220
  if kwargs.get("created"):
214
221
  cls.on_create.send(document)
@@ -294,31 +301,31 @@ class User(WithMetrics, UserMixin, db.Document):
294
301
  from udata.models import Dataset
295
302
 
296
303
  self.metrics["datasets"] = Dataset.objects(owner=self).visible().count()
297
- self.save()
304
+ self.save(signal_kwargs={"ignores": ["post_save"]})
298
305
 
299
306
  def count_reuses(self):
300
307
  from udata.models import Reuse
301
308
 
302
309
  self.metrics["reuses"] = Reuse.objects(owner=self).visible().count()
303
- self.save()
310
+ self.save(signal_kwargs={"ignores": ["post_save"]})
304
311
 
305
312
  def count_dataservices(self):
306
313
  from udata.core.dataservices.models import Dataservice
307
314
 
308
315
  self.metrics["dataservices"] = Dataservice.objects(owner=self).visible().count()
309
- self.save()
316
+ self.save(signal_kwargs={"ignores": ["post_save"]})
310
317
 
311
318
  def count_followers(self):
312
319
  from udata.models import Follow
313
320
 
314
321
  self.metrics["followers"] = Follow.objects(until=None).followers(self).count()
315
- self.save()
322
+ self.save(signal_kwargs={"ignores": ["post_save"]})
316
323
 
317
324
  def count_following(self):
318
325
  from udata.models import Follow
319
326
 
320
327
  self.metrics["following"] = Follow.objects.following(self).count()
321
- self.save()
328
+ self.save(signal_kwargs={"ignores": ["post_save"]})
322
329
 
323
330
 
324
331
  datastore = MongoEngineUserDatastore(db, User, Role)
@@ -67,6 +67,7 @@ class Datetimed(object):
67
67
  ),
68
68
  sortable=True,
69
69
  readonly=True,
70
+ auditable=False,
70
71
  )
71
72
 
72
73