udata 10.6.1.dev36082__py2.py3-none-any.whl → 10.6.1.dev36098__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 (100) hide show
  1. udata/api/fields.py +0 -17
  2. udata/auth/views.py +22 -24
  3. udata/core/activity/api.py +1 -1
  4. udata/core/dataservices/api.py +3 -3
  5. udata/core/dataservices/models.py +11 -11
  6. udata/core/dataservices/rdf.py +3 -18
  7. udata/core/dataset/api.py +4 -3
  8. udata/core/dataset/api_fields.py +14 -25
  9. udata/core/dataset/apiv2.py +8 -11
  10. udata/core/dataset/csv.py +2 -2
  11. udata/core/dataset/models.py +18 -20
  12. udata/core/dataset/rdf.py +5 -38
  13. udata/core/dataset/search.py +1 -1
  14. udata/core/discussions/api.py +3 -1
  15. udata/core/discussions/models.py +11 -15
  16. udata/core/linkable.py +16 -0
  17. udata/core/organization/api.py +1 -0
  18. udata/core/organization/api_fields.py +14 -26
  19. udata/core/organization/csv.py +1 -1
  20. udata/core/organization/models.py +13 -16
  21. udata/core/organization/rdf.py +1 -5
  22. udata/core/post/api.py +8 -8
  23. udata/core/post/models.py +9 -16
  24. udata/core/reports/models.py +2 -2
  25. udata/core/reuse/api.py +4 -3
  26. udata/core/reuse/api_fields.py +1 -7
  27. udata/core/reuse/csv.py +1 -1
  28. udata/core/reuse/models.py +15 -22
  29. udata/core/site/rdf.py +2 -3
  30. udata/core/spatial/models.py +2 -9
  31. udata/core/topic/api.py +4 -8
  32. udata/core/topic/apiv2.py +3 -8
  33. udata/core/topic/models.py +0 -5
  34. udata/core/user/api_fields.py +14 -14
  35. udata/core/user/models.py +10 -16
  36. udata/core/user/rdf.py +1 -3
  37. udata/features/territories/models.py +1 -17
  38. udata/rdf.py +1 -2
  39. udata/routing.py +3 -2
  40. udata/settings.py +2 -0
  41. udata/static/chunks/{10.471164b2a9fe15614797.js → 10.8ca60413647062717b1e.js} +3 -3
  42. udata/static/chunks/{10.471164b2a9fe15614797.js.map → 10.8ca60413647062717b1e.js.map} +1 -1
  43. udata/static/chunks/{11.83535504cd650ea08f65.js → 11.0f04e49a40a0a381bcce.js} +3 -3
  44. udata/static/chunks/{11.83535504cd650ea08f65.js.map → 11.0f04e49a40a0a381bcce.js.map} +1 -1
  45. udata/static/chunks/{13.d9c1735d14038b94c17e.js → 13.f29411b06be1883356a3.js} +2 -2
  46. udata/static/chunks/{13.d9c1735d14038b94c17e.js.map → 13.f29411b06be1883356a3.js.map} +1 -1
  47. udata/static/chunks/{17.81c57c0dedf812e43013.js → 17.3bd0340930d4a314ce9c.js} +2 -2
  48. udata/static/chunks/{17.81c57c0dedf812e43013.js.map → 17.3bd0340930d4a314ce9c.js.map} +1 -1
  49. udata/static/chunks/{19.df16abde17a42033a7f8.js → 19.0586efa786ebf09fb288.js} +3 -3
  50. udata/static/chunks/{19.df16abde17a42033a7f8.js.map → 19.0586efa786ebf09fb288.js.map} +1 -1
  51. udata/static/chunks/{8.462bb3029de008497675.js → 8.b966402f5d680d4bdf4a.js} +2 -2
  52. udata/static/chunks/{8.462bb3029de008497675.js.map → 8.b966402f5d680d4bdf4a.js.map} +1 -1
  53. udata/static/chunks/{9.07515e5187f475bce828.js → 9.033d7e190ca9e226a5d0.js} +3 -3
  54. udata/static/chunks/{9.07515e5187f475bce828.js.map → 9.033d7e190ca9e226a5d0.js.map} +1 -1
  55. udata/static/common.js +1 -1
  56. udata/static/common.js.map +1 -1
  57. udata/templates/api/oauth_error.html +1 -1
  58. udata/templates/macros/metadata.html +0 -1
  59. udata/templates/mail/account_inactivity.html +1 -1
  60. udata/templates/mail/account_inactivity.txt +1 -1
  61. udata/templates/mail/badge_added_association.html +3 -3
  62. udata/templates/mail/badge_added_association.txt +1 -1
  63. udata/templates/mail/badge_added_certified.html +3 -3
  64. udata/templates/mail/badge_added_certified.txt +1 -1
  65. udata/templates/mail/badge_added_company.html +3 -3
  66. udata/templates/mail/badge_added_company.txt +1 -1
  67. udata/templates/mail/badge_added_local_authority.html +3 -3
  68. udata/templates/mail/badge_added_local_authority.txt +1 -1
  69. udata/templates/mail/badge_added_public_service.html +3 -3
  70. udata/templates/mail/badge_added_public_service.txt +1 -1
  71. udata/templates/mail/discussion_closed.html +3 -3
  72. udata/templates/mail/discussion_closed.txt +1 -1
  73. udata/templates/mail/frequency_reminder.html +1 -1
  74. udata/templates/mail/frequency_reminder.txt +1 -1
  75. udata/templates/mail/membership_refused.html +1 -1
  76. udata/templates/mail/membership_request.html +3 -3
  77. udata/templates/mail/membership_request.txt +1 -1
  78. udata/templates/mail/new_discussion.html +3 -3
  79. udata/templates/mail/new_discussion.txt +1 -1
  80. udata/templates/mail/new_discussion_comment.html +3 -3
  81. udata/templates/mail/new_discussion_comment.txt +1 -1
  82. udata/templates/mail/new_member.html +2 -2
  83. udata/templates/mail/new_member.txt +1 -1
  84. udata/templates/mail/new_reuse.html +2 -12
  85. udata/templates/mail/new_reuse.txt +1 -3
  86. udata/templates/mail/user_mail_card.html +1 -1
  87. udata/tests/api/test_dataservices_api.py +2 -2
  88. udata/tests/api/test_datasets_api.py +2 -2
  89. udata/tests/api/test_reuses_api.py +2 -2
  90. udata/tests/api/test_topics_api.py +4 -4
  91. udata/tests/dataset/test_dataset_rdf.py +1 -9
  92. udata/tests/test_discussions.py +3 -3
  93. udata/tests/test_mail.py +8 -0
  94. udata/uris.py +28 -7
  95. {udata-10.6.1.dev36082.dist-info → udata-10.6.1.dev36098.dist-info}/METADATA +1 -1
  96. {udata-10.6.1.dev36082.dist-info → udata-10.6.1.dev36098.dist-info}/RECORD +100 -99
  97. {udata-10.6.1.dev36082.dist-info → udata-10.6.1.dev36098.dist-info}/LICENSE +0 -0
  98. {udata-10.6.1.dev36082.dist-info → udata-10.6.1.dev36098.dist-info}/WHEEL +0 -0
  99. {udata-10.6.1.dev36082.dist-info → udata-10.6.1.dev36098.dist-info}/entry_points.txt +0 -0
  100. {udata-10.6.1.dev36082.dist-info → udata-10.6.1.dev36098.dist-info}/top_level.txt +0 -0
udata/core/linkable.py ADDED
@@ -0,0 +1,16 @@
1
+ class Linkable:
2
+ def _link_id(self, **kwargs):
3
+ return self.id if kwargs.get("_useId", False) else self.slug
4
+
5
+ def _self_api_url_kwargs(self, **kwargs):
6
+ # Default to external
7
+ kwargs["_external"] = kwargs.pop("_external", True)
8
+
9
+ # Remove own private data
10
+ kwargs.pop("_useId", None)
11
+ kwargs.pop("_mailCampaign", None)
12
+
13
+ return kwargs
14
+
15
+ def url_for(self, **kwargs):
16
+ return self.self_web_url(**kwargs) or self.self_api_url(**kwargs)
@@ -498,6 +498,7 @@ class OrganizationSuggestAPI(API):
498
498
  "acronym": org.acronym,
499
499
  "slug": org.slug,
500
500
  "image_url": org.logo,
501
+ "page": org.self_web_url(),
501
502
  }
502
503
  for org in orgs.order_by(SUGGEST_SORTING).limit(args["size"])
503
504
  ]
@@ -13,21 +13,18 @@ org_ref_fields = api.inherit(
13
13
  {
14
14
  "name": fields.String(description="The organization name", readonly=True),
15
15
  "acronym": fields.String(description="The organization acronym"),
16
- "uri": fields.UrlFor(
17
- "api.organization",
18
- lambda o: {"org": o},
19
- description="The organization API URI",
20
- readonly=True,
21
- ),
22
16
  "slug": fields.String(
23
17
  description="The organization string used as permalink", required=True
24
18
  ),
25
- "page": fields.UrlFor(
26
- "organizations.show",
27
- lambda o: {"org": o},
19
+ "uri": fields.String(
20
+ attribute=lambda o: o.self_api_url(),
21
+ description="The API URI for this organization",
22
+ readonly=True,
23
+ ),
24
+ "page": fields.String(
25
+ attribute=lambda o: o.self_web_url(),
28
26
  description="The organization web page URL",
29
27
  readonly=True,
30
- fallback_endpoint="api.organization",
31
28
  ),
32
29
  "logo": fields.ImageField(original=True, description="The organization logo URL"),
33
30
  "logo_thumbnail": fields.ImageField(
@@ -151,18 +148,15 @@ org_fields = api.model(
151
148
  description="The organization metrics",
152
149
  readonly=True,
153
150
  ),
154
- "uri": fields.UrlFor(
155
- "api.organization",
156
- lambda o: {"org": o},
157
- description="The organization API URI",
151
+ "uri": fields.String(
152
+ attribute=lambda o: o.self_api_url(),
153
+ description="The API URI for this organization",
158
154
  readonly=True,
159
155
  ),
160
- "page": fields.UrlFor(
161
- "organizations.show",
162
- lambda o: {"org": o},
163
- description="The organization page URL",
156
+ "page": fields.String(
157
+ attribute=lambda o: o.self_web_url(),
158
+ description="The organization web page URL",
164
159
  readonly=True,
165
- fallback_endpoint="api.organization",
166
160
  ),
167
161
  "logo": fields.ImageField(original=True, description="The organization logo URL"),
168
162
  "logo_thumbnail": fields.ImageField(
@@ -211,12 +205,6 @@ org_suggestion_fields = api.model(
211
205
  "image_url": fields.ImageField(
212
206
  size=BIGGEST_LOGO_SIZE, description="The organization logo URL", readonly=True
213
207
  ),
214
- "page": fields.UrlFor(
215
- "organizations.show_redirect",
216
- lambda o: {"org": o["slug"]},
217
- description="The organization web page URL",
218
- readonly=True,
219
- fallback_endpoint="api.organization",
220
- ),
208
+ "page": fields.String(description="The organization web page URL", readonly=True),
221
209
  },
222
210
  )
@@ -13,7 +13,7 @@ class OrganizationCsvAdapter(csv.Adapter):
13
13
  "name",
14
14
  "acronym",
15
15
  "slug",
16
- ("url", "external_url"),
16
+ ("url", lambda o: o.url_for()),
17
17
  "description",
18
18
  ("logo", lambda o: o.logo(external=True)),
19
19
  ("badges", lambda o: ",".join([badge.kind for badge in o.badges])),
@@ -2,20 +2,21 @@ from datetime import datetime
2
2
  from itertools import chain
3
3
 
4
4
  from blinker import Signal
5
+ from flask import url_for
5
6
  from mongoengine.signals import post_save, pre_save
6
7
  from werkzeug.utils import cached_property
7
8
 
8
9
  from udata.api_fields import field
9
10
  from udata.core.activity.models import Auditable
10
11
  from udata.core.badges.models import Badge, BadgeMixin, BadgesList
12
+ from udata.core.linkable import Linkable
11
13
  from udata.core.metrics.helpers import get_stock_metrics
12
14
  from udata.core.metrics.models import WithMetrics
13
15
  from udata.core.storages import avatars, default_image_basename
14
16
  from udata.frontend.markdown import mdstrip
15
17
  from udata.i18n import lazy_gettext as _
16
- from udata.mail import get_mail_campaign_dict
17
18
  from udata.mongo import db
18
- from udata.uris import endpoint_for
19
+ from udata.uris import cdata_url
19
20
 
20
21
  from .constants import (
21
22
  ASSOCIATION,
@@ -112,7 +113,9 @@ class OrganizationBadgeMixin(BadgeMixin):
112
113
  __badges__ = BADGES
113
114
 
114
115
 
115
- class Organization(Auditable, WithMetrics, OrganizationBadgeMixin, db.Datetimed, db.Document):
116
+ class Organization(
117
+ Auditable, WithMetrics, OrganizationBadgeMixin, Linkable, db.Datetimed, db.Document
118
+ ):
116
119
  name = field(db.StringField(required=True))
117
120
  acronym = field(db.StringField(max_length=128))
118
121
  slug = field(
@@ -189,19 +192,13 @@ class Organization(Auditable, WithMetrics, OrganizationBadgeMixin, db.Datetimed,
189
192
  def pre_save(cls, sender, document, **kwargs):
190
193
  cls.before_save.send(document)
191
194
 
192
- def url_for(self, *args, **kwargs):
193
- return endpoint_for("organizations.show", "api.organization", org=self, *args, **kwargs)
195
+ def self_web_url(self, **kwargs):
196
+ return cdata_url(f"/organizations/{self._link_id(**kwargs)}/", **kwargs)
194
197
 
195
- display_url = property(url_for)
196
-
197
- @property
198
- def external_url(self):
199
- return self.url_for(_external=True)
200
-
201
- @property
202
- def external_url_with_campaign(self):
203
- extras = get_mail_campaign_dict()
204
- return self.url_for(_external=True, **extras)
198
+ def self_api_url(self, **kwargs):
199
+ return url_for(
200
+ "api.organization", org=self._link_id(**kwargs), **self._self_api_url_kwargs(**kwargs)
201
+ )
205
202
 
206
203
  @property
207
204
  def pending_requests(self):
@@ -283,7 +280,7 @@ class Organization(Auditable, WithMetrics, OrganizationBadgeMixin, db.Datetimed,
283
280
  "@type": type_,
284
281
  "@id": str(self.id),
285
282
  "alternateName": self.slug,
286
- "url": endpoint_for("organizations.show", "api.organization", org=self, _external=True),
283
+ "url": self.url_for(),
287
284
  "name": self.name,
288
285
  "dateCreated": self.created_at.isoformat(),
289
286
  "dateModified": self.last_modified.isoformat(),
@@ -10,7 +10,6 @@ from rdflib.namespace import FOAF, RDF, RDFS
10
10
  from udata.core.dataservices.rdf import dataservice_to_rdf
11
11
  from udata.core.dataset.rdf import dataset_to_rdf
12
12
  from udata.rdf import DCAT, DCT, namespace_manager, paginate_catalog
13
- from udata.uris import endpoint_for
14
13
  from udata.utils import Paginable
15
14
 
16
15
 
@@ -20,10 +19,7 @@ def organization_to_rdf(org, graph=None):
20
19
  """
21
20
  graph = graph or Graph(namespace_manager=namespace_manager)
22
21
  if org.id:
23
- org_url = endpoint_for(
24
- "organizations.show_redirect", "api.organization", org=org.id, _external=True
25
- )
26
- id = URIRef(org_url)
22
+ id = URIRef(org.url_for(_useId=True))
27
23
  else:
28
24
  id = BNode()
29
25
  o = graph.resource(id)
udata/core/post/api.py CHANGED
@@ -48,15 +48,15 @@ post_fields = api.model(
48
48
  ),
49
49
  "published": fields.ISODateTime(description="The post publication date", readonly=True),
50
50
  "body_type": fields.String(description="HTML or markdown body type", default="markdown"),
51
- "uri": fields.UrlFor(
52
- "api.post", lambda o: {"post": o}, description="The post API URI", readonly=True
51
+ "uri": fields.String(
52
+ attribute=lambda p: p.self_api_url(),
53
+ description="The API URI for this post",
54
+ readonly=True,
53
55
  ),
54
- "page": fields.UrlFor(
55
- "posts.show",
56
- lambda o: {"post": o},
57
- description="The post page URL",
56
+ "page": fields.String(
57
+ attribute=lambda p: p.self_web_url(),
58
+ description="The post web page URL",
58
59
  readonly=True,
59
- fallback_endpoint="api.post",
60
60
  ),
61
61
  },
62
62
  mask="*,datasets{id,title,acronym,uri,page},reuses{id,title,image,image_thumbnail,uri,page}",
@@ -130,7 +130,7 @@ class PostsAtomFeedAPI(API):
130
130
  description=post.headline,
131
131
  content=md(post.content),
132
132
  author_name="data.gouv.fr",
133
- link=post.external_url,
133
+ link=post.url_for(),
134
134
  updateddate=post.last_modified,
135
135
  pubdate=post.published,
136
136
  )
udata/core/post/models.py CHANGED
@@ -1,9 +1,10 @@
1
1
  from flask import url_for
2
2
 
3
+ from udata.core.linkable import Linkable
3
4
  from udata.core.storages import default_image_basename, images
4
5
  from udata.i18n import lazy_gettext as _
5
- from udata.mail import get_mail_campaign_dict
6
6
  from udata.mongo import db
7
+ from udata.uris import cdata_url
7
8
 
8
9
  from .constants import BODY_TYPES, IMAGE_SIZES
9
10
 
@@ -15,7 +16,7 @@ class PostQuerySet(db.BaseQuerySet):
15
16
  return self(published__ne=None).order_by("-published")
16
17
 
17
18
 
18
- class Post(db.Datetimed, db.Document):
19
+ class Post(db.Datetimed, Linkable, db.Document):
19
20
  name = db.StringField(max_length=255, required=True)
20
21
  slug = db.SlugField(
21
22
  max_length=255, required=True, populate_from="name", update=True, follow=True
@@ -56,21 +57,13 @@ class Post(db.Datetimed, db.Document):
56
57
  def __str__(self):
57
58
  return self.name or ""
58
59
 
59
- def url_for(self, *args, **kwargs):
60
- return url_for("posts.show", post=self, *args, **kwargs)
60
+ def self_web_url(self, **kwargs):
61
+ return cdata_url(f"/posts/{self._link_id(**kwargs)}/", **kwargs)
61
62
 
62
- @property
63
- def display_url(self):
64
- return self.url_for()
65
-
66
- @property
67
- def external_url(self):
68
- return self.url_for(_external=True)
69
-
70
- @property
71
- def external_url_with_campaign(self):
72
- extras = get_mail_campaign_dict()
73
- return self.url_for(_external=True, **extras)
63
+ def self_api_url(self, **kwargs):
64
+ return url_for(
65
+ "api.post", post=self._link_id(**kwargs), **self._self_api_url_kwargs(**kwargs)
66
+ )
74
67
 
75
68
  def count_discussions(self):
76
69
  # There are no metrics on Post to store discussions count
@@ -1,13 +1,13 @@
1
1
  from datetime import datetime
2
2
 
3
3
  from bson import DBRef
4
+ from flask import url_for
4
5
  from mongoengine import DO_NOTHING, NULLIFY, signals
5
6
 
6
7
  from udata.api_fields import field, function_field, generate_fields
7
8
  from udata.core.user.api_fields import user_ref_fields
8
9
  from udata.core.user.models import User
9
10
  from udata.mongo import db
10
- from udata.uris import endpoint_for
11
11
 
12
12
  from .constants import REPORT_REASONS_CHOICES, REPORTABLE_MODELS
13
13
 
@@ -48,7 +48,7 @@ class Report(db.Document):
48
48
 
49
49
  @function_field(description="Link to the API endpoint for this report")
50
50
  def self_api_url(self):
51
- return endpoint_for("api.report", report=self, _external=True)
51
+ return url_for("api.report", report=self, _external=True)
52
52
 
53
53
  @classmethod
54
54
  def mark_as_deleted_soft_delete(cls, sender, document, **kwargs):
udata/core/reuse/api.py CHANGED
@@ -150,10 +150,10 @@ class ReusesAtomFeedAPI(API):
150
150
  author_uri = None
151
151
  if reuse.organization:
152
152
  author_name = reuse.organization.name
153
- author_uri = reuse.organization.external_url
153
+ author_uri = reuse.organization.url_for()
154
154
  elif reuse.owner:
155
155
  author_name = reuse.owner.fullname
156
- author_uri = reuse.owner.external_url
156
+ author_uri = reuse.owner.url_for()
157
157
  feed.add_item(
158
158
  reuse.title,
159
159
  unique_id=reuse.id,
@@ -161,7 +161,7 @@ class ReusesAtomFeedAPI(API):
161
161
  content=md(reuse.description),
162
162
  author_name=author_name,
163
163
  author_link=author_uri,
164
- link=reuse.external_url,
164
+ link=reuse.url_for(),
165
165
  updateddate=reuse.last_modified,
166
166
  pubdate=reuse.created_at,
167
167
  )
@@ -320,6 +320,7 @@ class ReusesSuggestAPI(API):
320
320
  "title": reuse.title,
321
321
  "slug": reuse.slug,
322
322
  "image_url": reuse.image,
323
+ "page": reuse.self_web_url(),
323
324
  }
324
325
  for reuse in reuses.order_by(SUGGEST_SORTING).limit(args["size"])
325
326
  ]
@@ -30,13 +30,7 @@ reuse_suggestion_fields = api.model(
30
30
  "image_url": fields.ImageField(
31
31
  size=BIGGEST_IMAGE_SIZE, description="The reuse thumbnail URL", readonly=True
32
32
  ),
33
- "page": fields.UrlFor(
34
- "reuses.show_redirect",
35
- lambda o: {"reuse": o["slug"]},
36
- description="The reuse page URL",
37
- readonly=True,
38
- fallback_endpoint="api.reuse",
39
- ),
33
+ "page": fields.String(description="The reuse web page URL", readonly=True),
40
34
  },
41
35
  )
42
36
 
udata/core/reuse/csv.py CHANGED
@@ -9,7 +9,7 @@ class ReuseCsvAdapter(csv.Adapter):
9
9
  "id",
10
10
  "title",
11
11
  "slug",
12
- ("url", "external_url"),
12
+ ("url", lambda r: r.url_for()),
13
13
  "type",
14
14
  "description",
15
15
  ("remote_url", "url"),
@@ -1,20 +1,21 @@
1
1
  from blinker import Signal
2
+ from flask import url_for
2
3
  from mongoengine.signals import post_save, pre_save
3
4
  from werkzeug.utils import cached_property
4
5
 
5
6
  from udata.api_fields import field, function_field, generate_fields
6
7
  from udata.core.activity.models import Auditable
7
8
  from udata.core.dataset.api_fields import dataset_fields
9
+ from udata.core.linkable import Linkable
8
10
  from udata.core.metrics.helpers import get_stock_metrics
9
11
  from udata.core.owned import Owned, OwnedQuerySet
10
12
  from udata.core.reuse.api_fields import BIGGEST_IMAGE_SIZE, reuse_permissions_fields
11
13
  from udata.core.storages import default_image_basename, images
12
14
  from udata.frontend.markdown import mdstrip
13
15
  from udata.i18n import lazy_gettext as _
14
- from udata.mail import get_mail_campaign_dict
15
16
  from udata.models import Badge, BadgeMixin, BadgesList, WithMetrics, db
16
17
  from udata.mongo.errors import FieldValidationError
17
- from udata.uris import endpoint_for
18
+ from udata.uris import cdata_url
18
19
  from udata.utils import hash_url
19
20
 
20
21
  from .constants import IMAGE_MAX_SIZE, IMAGE_SIZES, REUSE_TOPICS, REUSE_TYPES
@@ -62,7 +63,7 @@ class ReuseBadgeMixin(BadgeMixin):
62
63
  additional_filters={"organization_badge": "organization.badges"},
63
64
  mask="*,datasets{id,title,uri,page}",
64
65
  )
65
- class Reuse(db.Datetimed, Auditable, WithMetrics, ReuseBadgeMixin, Owned, db.Document):
66
+ class Reuse(db.Datetimed, Auditable, WithMetrics, ReuseBadgeMixin, Linkable, Owned, db.Document):
66
67
  title = field(
67
68
  db.StringField(required=True),
68
69
  sortable=True,
@@ -187,20 +188,21 @@ class Reuse(db.Datetimed, Auditable, WithMetrics, ReuseBadgeMixin, Owned, db.Doc
187
188
  # Emit before_save
188
189
  cls.before_save.send(document)
189
190
 
190
- def url_for(self, *args, **kwargs):
191
- return endpoint_for("reuses.show", "api.reuse", reuse=self, *args, **kwargs)
191
+ def self_web_url(self, **kwargs):
192
+ return cdata_url(f"/reuses/{self._link_id(**kwargs)}/", **kwargs)
192
193
 
193
- display_url = property(url_for)
194
+ def self_api_url(self, **kwargs):
195
+ return url_for(
196
+ "api.reuse", reuse=self._link_id(**kwargs), **self._self_api_url_kwargs(**kwargs)
197
+ )
194
198
 
195
199
  @function_field(description="Link to the API endpoint for this reuse", show_as_ref=True)
196
- def uri(self):
197
- return endpoint_for("api.reuse", reuse=self, _external=True)
200
+ def uri(self, *args, **kwargs):
201
+ return self.self_api_url(*args, **kwargs)
198
202
 
199
203
  @function_field(description="Link to the udata web page for this reuse", show_as_ref=True)
200
- def page(self):
201
- return endpoint_for(
202
- "reuses.show", reuse=self, _external=True, fallback_endpoint="api.reuse"
203
- )
204
+ def page(self, *args, **kwargs):
205
+ return self.self_web_url(*args, **kwargs)
204
206
 
205
207
  @property
206
208
  @function_field(
@@ -222,15 +224,6 @@ class Reuse(db.Datetimed, Auditable, WithMetrics, ReuseBadgeMixin, Owned, db.Doc
222
224
  def is_hidden(self):
223
225
  return len(self.datasets) == 0 or self.private or self.deleted
224
226
 
225
- @property
226
- def external_url(self):
227
- return self.url_for(_external=True)
228
-
229
- @property
230
- def external_url_with_campaign(self):
231
- extras = get_mail_campaign_dict()
232
- return self.url_for(_external=True, **extras)
233
-
234
227
  @property
235
228
  def type_label(self):
236
229
  return REUSE_TYPES[self.type]
@@ -263,7 +256,7 @@ class Reuse(db.Datetimed, Auditable, WithMetrics, ReuseBadgeMixin, Owned, db.Doc
263
256
  "alternateName": self.slug,
264
257
  "dateCreated": self.created_at.isoformat(),
265
258
  "dateModified": self.last_modified.isoformat(),
266
- "url": endpoint_for("reuses.show", "api.reuse", reuse=self, _external=True),
259
+ "url": self.url_for(),
267
260
  "name": self.title,
268
261
  "isBasedOnUrl": self.url,
269
262
  }
udata/core/site/rdf.py CHANGED
@@ -11,13 +11,12 @@ from udata.core.dataset.rdf import dataset_to_rdf
11
11
  from udata.core.organization.rdf import organization_to_rdf
12
12
  from udata.core.user.rdf import user_to_rdf
13
13
  from udata.rdf import DCAT, DCT, namespace_manager, paginate_catalog
14
- from udata.uris import endpoint_for
14
+ from udata.uris import homepage_url
15
15
  from udata.utils import Paginable
16
16
 
17
17
 
18
18
  def build_catalog(site, datasets, dataservices=[], format=None):
19
19
  """Build the DCAT catalog for this site"""
20
- site_url = endpoint_for("site.home_redirect", "api.site", _external=True)
21
20
  catalog_url = url_for("api.site_rdf_catalog", _external=True)
22
21
  graph = Graph(namespace_manager=namespace_manager)
23
22
  catalog = graph.resource(URIRef(catalog_url))
@@ -26,7 +25,7 @@ def build_catalog(site, datasets, dataservices=[], format=None):
26
25
  catalog.set(DCT.title, Literal(site.title))
27
26
  catalog.set(DCT.description, Literal(f"{site.title}"))
28
27
  catalog.set(DCT.language, Literal(current_app.config["DEFAULT_LANGUAGE"]))
29
- catalog.set(FOAF.homepage, URIRef(site_url))
28
+ catalog.set(FOAF.homepage, URIRef(homepage_url(_external=True)))
30
29
 
31
30
  publisher = graph.resource(BNode())
32
31
  publisher.set(RDF.type, FOAF.Organization)
@@ -6,9 +6,7 @@ from werkzeug.utils import cached_property
6
6
  from udata.app import cache
7
7
  from udata.core.metrics.models import WithMetrics
8
8
  from udata.i18n import _, get_locale, language
9
- from udata.mail import get_mail_campaign_dict
10
9
  from udata.mongo import db
11
- from udata.uris import endpoint_for
12
10
 
13
11
  from . import geoids
14
12
  from .constants import ADMIN_LEVEL_MAX, ADMIN_LEVEL_MIN, BASE_GRANULARITIES
@@ -93,16 +91,11 @@ class GeoZone(WithMetrics, db.Document):
93
91
 
94
92
  @property
95
93
  def url(self):
96
- return endpoint_for("territories.territory", territory=self)
94
+ return None
97
95
 
98
96
  @property
99
97
  def external_url(self):
100
- return endpoint_for("territories.territory", territory=self, _external=True)
101
-
102
- @property
103
- def external_url_with_campaign(self):
104
- extras = get_mail_campaign_dict()
105
- return endpoint_for("territories.territory", territory=self, _external=True, **extras)
98
+ return None
106
99
 
107
100
  def count_datasets(self):
108
101
  from udata.models import Dataset
udata/core/topic/api.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import mongoengine
2
+ from flask import url_for
2
3
  from flask_security import current_user
3
4
 
4
5
  from udata.api import API, api, fields
@@ -58,15 +59,10 @@ topic_fields = api.model(
58
59
  "owner": fields.Nested(
59
60
  user_ref_fields, description="The owner user", readonly=True, allow_null=True
60
61
  ),
61
- "uri": fields.UrlFor(
62
- "api.topic", lambda o: {"topic": o}, description="The topic API URI", readonly=True
63
- ),
64
- "page": fields.UrlFor(
65
- "topics.display",
66
- lambda o: {"topic": o},
67
- description="The topic page URL",
62
+ "uri": fields.String(
63
+ attribute=lambda t: url_for("api.topic", topic=t),
64
+ description="The topic API URI",
68
65
  readonly=True,
69
- fallback_endpoint="api.topic",
70
66
  ),
71
67
  "extras": fields.Raw(description="Extras attributes as key-value pairs"),
72
68
  },
udata/core/topic/apiv2.py CHANGED
@@ -93,15 +93,10 @@ topic_fields = apiv2.model(
93
93
  "owner": fields.Nested(
94
94
  user_ref_fields, description="The owner user", readonly=True, allow_null=True
95
95
  ),
96
- "uri": fields.UrlFor(
97
- "api.topic", lambda o: {"topic": o}, description="The topic API URI", readonly=True
98
- ),
99
- "page": fields.UrlFor(
100
- "topics.display",
101
- lambda o: {"topic": o},
102
- description="The topic page URL",
96
+ "uri": fields.String(
97
+ attribute=lambda t: url_for("api.topic", topic=t),
98
+ description="The topic API URI",
103
99
  readonly=True,
104
- fallback_endpoint="api.topic",
105
100
  ),
106
101
  "extras": fields.Raw(description="Extras attributes as key-value pairs"),
107
102
  },
@@ -1,5 +1,4 @@
1
1
  from blinker import Signal
2
- from flask import url_for
3
2
  from mongoengine.signals import post_save, pre_save
4
3
 
5
4
  from udata.api_fields import field
@@ -57,10 +56,6 @@ class Topic(db.Datetimed, Auditable, db.Document, Owned):
57
56
  for dataset in datasets_list_dif:
58
57
  reindex.delay("Dataset", str(dataset.pk))
59
58
 
60
- @property
61
- def display_url(self):
62
- return url_for("topics.display", topic=self)
63
-
64
59
  def count_discussions(self):
65
60
  # There are no metrics on Topic to store discussions count
66
61
  pass
@@ -10,15 +10,15 @@ user_ref_fields = api.inherit(
10
10
  "first_name": fields.String(description="The user first name", readonly=True),
11
11
  "last_name": fields.String(description="The user larst name", readonly=True),
12
12
  "slug": fields.String(description="The user permalink string", required=True),
13
- "page": fields.UrlFor(
14
- "users.show",
15
- lambda u: {"user": u},
16
- description="The user profile page URL",
13
+ "uri": fields.String(
14
+ attribute=lambda u: u.self_api_url(),
15
+ description="The API URI for this user",
17
16
  readonly=True,
18
- fallback_endpoint="api.user",
19
17
  ),
20
- "uri": fields.UrlFor(
21
- "api.user", lambda o: {"user": o}, description="The user API URI", required=True
18
+ "page": fields.String(
19
+ attribute=lambda u: u.self_web_url(),
20
+ description="The user web page URL",
21
+ readonly=True,
22
22
  ),
23
23
  "avatar": fields.ImageField(original=True, description="The user avatar URL"),
24
24
  "avatar_thumbnail": fields.ImageField(
@@ -66,15 +66,15 @@ user_fields = api.model(
66
66
  description="The user last connection date (only present for global admins and on /me)",
67
67
  readonly=True,
68
68
  ),
69
- "page": fields.UrlFor(
70
- "users.show",
71
- lambda u: {"user": u},
72
- description="The user profile page URL",
69
+ "uri": fields.String(
70
+ attribute=lambda u: u.self_api_url(),
71
+ description="The API URI for this user",
73
72
  readonly=True,
74
- fallback_endpoint="api.user",
75
73
  ),
76
- "uri": fields.UrlFor(
77
- "api.user", lambda o: {"user": o}, description="The user API URI", required=True
74
+ "page": fields.String(
75
+ attribute=lambda u: u.self_web_url(),
76
+ description="The user web page URL",
77
+ readonly=True,
78
78
  ),
79
79
  "metrics": fields.Raw(
80
80
  attribute=lambda o: o.get_metrics(), description="The user metrics", readonly=True