udata 10.7.1.dev36555__py2.py3-none-any.whl → 10.8.1__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/__init__.py +1 -1
- udata/core/dataservices/models.py +3 -1
- udata/core/dataset/models.py +3 -1
- udata/core/discussions/api.py +6 -0
- udata/core/discussions/models.py +11 -1
- udata/core/reuse/models.py +3 -1
- udata/migrations/2025-07-18-redo-count-discussion.py +26 -0
- udata/mongo/slug_fields.py +24 -7
- udata/static/chunks/{11.33f00815743ef2ea9e06.js → 11.51d706fb9521c16976bc.js} +3 -3
- udata/static/chunks/{11.33f00815743ef2ea9e06.js.map → 11.51d706fb9521c16976bc.js.map} +1 -1
- udata/static/chunks/{13.f29411b06be1883356a3.js → 13.39e106d56f794ebd06a0.js} +2 -2
- udata/static/chunks/{13.f29411b06be1883356a3.js.map → 13.39e106d56f794ebd06a0.js.map} +1 -1
- udata/static/chunks/{17.3bd0340930d4a314ce9c.js → 17.70cbb4a91b002338007e.js} +2 -2
- udata/static/chunks/{17.3bd0340930d4a314ce9c.js.map → 17.70cbb4a91b002338007e.js.map} +1 -1
- udata/static/chunks/{19.8d03c06efcac6884bebe.js → 19.a348a5fff8fe2801e52a.js} +3 -3
- udata/static/chunks/{19.8d03c06efcac6884bebe.js.map → 19.a348a5fff8fe2801e52a.js.map} +1 -1
- udata/static/chunks/{5.0fa1408dae4e76b87b2e.js → 5.343ca020a2d38cec1a14.js} +3 -3
- udata/static/chunks/{5.0fa1408dae4e76b87b2e.js.map → 5.343ca020a2d38cec1a14.js.map} +1 -1
- udata/static/chunks/{6.d663709d877baa44a71e.js → 6.a3b07de9dd2ca2d24e85.js} +3 -3
- udata/static/chunks/{6.d663709d877baa44a71e.js.map → 6.a3b07de9dd2ca2d24e85.js.map} +1 -1
- udata/static/chunks/{8.0b54a9e3084c9636c58f.js → 8.462bb3029de008497675.js} +2 -2
- udata/static/chunks/{8.0b54a9e3084c9636c58f.js.map → 8.462bb3029de008497675.js.map} +1 -1
- udata/static/common.js +1 -1
- udata/static/common.js.map +1 -1
- udata/tests/test_discussions.py +41 -1
- {udata-10.7.1.dev36555.dist-info → udata-10.8.1.dist-info}/METADATA +8 -2
- {udata-10.7.1.dev36555.dist-info → udata-10.8.1.dist-info}/RECORD +31 -30
- {udata-10.7.1.dev36555.dist-info → udata-10.8.1.dist-info}/LICENSE +0 -0
- {udata-10.7.1.dev36555.dist-info → udata-10.8.1.dist-info}/WHEEL +0 -0
- {udata-10.7.1.dev36555.dist-info → udata-10.8.1.dist-info}/entry_points.txt +0 -0
- {udata-10.7.1.dev36555.dist-info → udata-10.8.1.dist-info}/top_level.txt +0 -0
udata/__init__.py
CHANGED
|
@@ -288,6 +288,7 @@ class Dataservice(Auditable, WithMetrics, Linkable, Owned, db.Document):
|
|
|
288
288
|
|
|
289
289
|
__metrics_keys__ = [
|
|
290
290
|
"discussions",
|
|
291
|
+
"discussions_open",
|
|
291
292
|
"followers",
|
|
292
293
|
"followers_by_months",
|
|
293
294
|
"views",
|
|
@@ -310,7 +311,8 @@ class Dataservice(Auditable, WithMetrics, Linkable, Owned, db.Document):
|
|
|
310
311
|
}
|
|
311
312
|
|
|
312
313
|
def count_discussions(self):
|
|
313
|
-
self.metrics["discussions"] = Discussion.objects(subject=self
|
|
314
|
+
self.metrics["discussions"] = Discussion.objects(subject=self).count()
|
|
315
|
+
self.metrics["discussions_open"] = Discussion.objects(subject=self, closed=None).count()
|
|
314
316
|
self.save(signal_kwargs={"ignores": ["post_save"]})
|
|
315
317
|
|
|
316
318
|
def count_followers(self):
|
udata/core/dataset/models.py
CHANGED
|
@@ -611,6 +611,7 @@ class Dataset(Auditable, WithMetrics, DatasetBadgeMixin, Owned, Linkable, db.Doc
|
|
|
611
611
|
|
|
612
612
|
__metrics_keys__ = [
|
|
613
613
|
"discussions",
|
|
614
|
+
"discussions_open",
|
|
614
615
|
"reuses",
|
|
615
616
|
"reuses_by_months",
|
|
616
617
|
"followers",
|
|
@@ -1086,7 +1087,8 @@ class Dataset(Auditable, WithMetrics, DatasetBadgeMixin, Owned, Linkable, db.Doc
|
|
|
1086
1087
|
def count_discussions(self):
|
|
1087
1088
|
from udata.models import Discussion
|
|
1088
1089
|
|
|
1089
|
-
self.metrics["discussions"] = Discussion.objects(subject=self
|
|
1090
|
+
self.metrics["discussions"] = Discussion.objects(subject=self).count()
|
|
1091
|
+
self.metrics["discussions_open"] = Discussion.objects(subject=self, closed=None).count()
|
|
1090
1092
|
self.save(signal_kwargs={"ignores": ["post_save"]})
|
|
1091
1093
|
|
|
1092
1094
|
def count_reuses(self):
|
udata/core/discussions/api.py
CHANGED
|
@@ -130,6 +130,7 @@ discussion_page_fields = api.model("DiscussionPage", fields.pager(discussion_fie
|
|
|
130
130
|
parser = api.parser()
|
|
131
131
|
sorting_keys: list[str] = ["created", "title", "closed", "discussion.posted_on"]
|
|
132
132
|
sorting_choices: list[str] = sorting_keys + ["-" + k for k in sorting_keys]
|
|
133
|
+
parser.add_argument("q", type=str, location="args", help="The search query")
|
|
133
134
|
parser.add_argument(
|
|
134
135
|
"sort",
|
|
135
136
|
type=str,
|
|
@@ -331,6 +332,11 @@ class DiscussionsAPI(API):
|
|
|
331
332
|
discussions = discussions(closed=None)
|
|
332
333
|
elif args["closed"] is True:
|
|
333
334
|
discussions = discussions(closed__ne=None)
|
|
335
|
+
|
|
336
|
+
if args["q"]:
|
|
337
|
+
phrase_query = " ".join([f'"{elem}"' for elem in args["q"].split(" ")])
|
|
338
|
+
discussions = discussions.search_text(phrase_query).order_by("$text_score")
|
|
339
|
+
|
|
334
340
|
discussions = discussions.order_by(args["sort"])
|
|
335
341
|
return discussions.paginate(args["page"], args["page_size"])
|
|
336
342
|
|
udata/core/discussions/models.py
CHANGED
|
@@ -82,8 +82,18 @@ class Discussion(SpamMixin, Linkable, db.Document):
|
|
|
82
82
|
extras = db.ExtrasField()
|
|
83
83
|
|
|
84
84
|
meta = {
|
|
85
|
-
"indexes": [
|
|
85
|
+
"indexes": [
|
|
86
|
+
{
|
|
87
|
+
"fields": ["$title", "$discussion.content"],
|
|
88
|
+
"default_language": "french",
|
|
89
|
+
"weights": {"title": 10, "discussion.content": 5},
|
|
90
|
+
},
|
|
91
|
+
"user",
|
|
92
|
+
"subject",
|
|
93
|
+
"-created",
|
|
94
|
+
],
|
|
86
95
|
"ordering": ["-created"],
|
|
96
|
+
"auto_create_index_on_save": True,
|
|
87
97
|
}
|
|
88
98
|
|
|
89
99
|
@property
|
udata/core/reuse/models.py
CHANGED
|
@@ -151,6 +151,7 @@ class Reuse(db.Datetimed, Auditable, WithMetrics, ReuseBadgeMixin, Linkable, Own
|
|
|
151
151
|
|
|
152
152
|
__metrics_keys__ = [
|
|
153
153
|
"discussions",
|
|
154
|
+
"discussions_open",
|
|
154
155
|
"datasets",
|
|
155
156
|
"followers",
|
|
156
157
|
"followers_by_months",
|
|
@@ -287,7 +288,8 @@ class Reuse(db.Datetimed, Auditable, WithMetrics, ReuseBadgeMixin, Linkable, Own
|
|
|
287
288
|
def count_discussions(self):
|
|
288
289
|
from udata.models import Discussion
|
|
289
290
|
|
|
290
|
-
self.metrics["discussions"] = Discussion.objects(subject=self
|
|
291
|
+
self.metrics["discussions"] = Discussion.objects(subject=self).count()
|
|
292
|
+
self.metrics["discussions_open"] = Discussion.objects(subject=self, closed=None).count()
|
|
291
293
|
self.save(signal_kwargs={"ignores": ["post_save"]})
|
|
292
294
|
|
|
293
295
|
def count_followers(self):
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This migration does a `count_discussions` on all objets with discussions.
|
|
3
|
+
It follows the change of `metrics.discussions` to track all discussions and not onyl the opened ones.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from udata.core.discussions.models import Discussion
|
|
11
|
+
from udata.mongo import db as udata_db
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def migrate(db):
|
|
17
|
+
objects_with_discussions = Discussion.objects.aggregate(
|
|
18
|
+
[{"$group": {"_id": "$subject._ref", "_cls": {"$first": "$subject._cls"}}}]
|
|
19
|
+
)
|
|
20
|
+
with click.progressbar(objects_with_discussions) as objects_with_discussions:
|
|
21
|
+
for object in objects_with_discussions:
|
|
22
|
+
related_to = udata_db.resolve_model(object["_cls"]).objects.get(pk=object["_id"].id)
|
|
23
|
+
try:
|
|
24
|
+
related_to.count_discussions()
|
|
25
|
+
except Exception as err:
|
|
26
|
+
log.error(f"Cannot count discussions for {object['_cls']} {object['_id'].id} {err}")
|
udata/mongo/slug_fields.py
CHANGED
|
@@ -172,21 +172,38 @@ def populate_slug(instance, field):
|
|
|
172
172
|
# Ensure uniqueness
|
|
173
173
|
if field.unique:
|
|
174
174
|
base_slug = slug
|
|
175
|
-
index = 1
|
|
176
175
|
qs = instance.__class__.objects
|
|
177
176
|
if previous:
|
|
178
177
|
qs = qs(id__ne=previous.id)
|
|
179
178
|
|
|
180
|
-
def exists(
|
|
181
|
-
return qs(**{field.db_field:
|
|
179
|
+
def exists(slug):
|
|
180
|
+
return qs(**{field.db_field: slug}).clear_cls_query().limit(1).count(True) > 0
|
|
182
181
|
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
def get_existing_slug_suffixes(slug):
|
|
183
|
+
qs_suffix = qs(slug__regex=f"^{slug}-\d*$").clear_cls_query().only(field.db_field)
|
|
184
|
+
return [getattr(obj, field.db_field) for obj in qs_suffix]
|
|
185
|
+
|
|
186
|
+
def trim_base_slug(base_slug, index):
|
|
185
187
|
slug_overflow = len("{0}-{1}".format(base_slug, index)) - field.max_length
|
|
186
188
|
if slug_overflow >= 1:
|
|
187
189
|
base_slug = base_slug[:-slug_overflow]
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
return base_slug
|
|
191
|
+
|
|
192
|
+
if exists(base_slug):
|
|
193
|
+
# We'll iterate to get the first free slug suffix
|
|
194
|
+
index = 1
|
|
195
|
+
existing_slugs = None
|
|
196
|
+
while True:
|
|
197
|
+
# Keep space for index suffix, trim slug if needed
|
|
198
|
+
trimmed_slug = trim_base_slug(base_slug, index)
|
|
199
|
+
# Find all existing slugs with suffixes
|
|
200
|
+
if existing_slugs is None or trimmed_slug != base_slug:
|
|
201
|
+
base_slug = trimmed_slug
|
|
202
|
+
existing_slugs = set(sorted(get_existing_slug_suffixes(base_slug)))
|
|
203
|
+
slug = "{0}-{1}".format(base_slug, index)
|
|
204
|
+
if slug not in existing_slugs:
|
|
205
|
+
break
|
|
206
|
+
index += 1
|
|
190
207
|
|
|
191
208
|
if is_uuid(slug):
|
|
192
209
|
slug = "{0}-uuid".format(slug)
|