udata 10.0.3__py2.py3-none-any.whl → 10.0.3.dev32541__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 (67) hide show
  1. udata/__init__.py +1 -1
  2. udata/commands/fixtures.py +2 -4
  3. udata/core/dataservices/rdf.py +0 -24
  4. udata/core/dataset/constants.py +0 -2
  5. udata/core/dataset/models.py +0 -6
  6. udata/core/dataset/rdf.py +1 -44
  7. udata/core/discussions/models.py +0 -8
  8. udata/core/organization/models.py +0 -6
  9. udata/core/post/models.py +0 -6
  10. udata/core/reuse/models.py +0 -6
  11. udata/core/spatial/models.py +0 -6
  12. udata/core/user/models.py +0 -6
  13. udata/features/territories/models.py +0 -6
  14. udata/harvest/backends/dcat.py +5 -9
  15. udata/mail.py +1 -17
  16. udata/static/chunks/{11.bb1c1fb39f740fbbeec0.js → 11.ffe19f0319ffd1bc9737.js} +3 -3
  17. udata/static/chunks/{11.bb1c1fb39f740fbbeec0.js.map → 11.ffe19f0319ffd1bc9737.js.map} +1 -1
  18. udata/static/chunks/{13.bef5fdb3e147e94fea99.js → 13.645dd0b7c0b9210f1b56.js} +2 -2
  19. udata/static/chunks/{13.bef5fdb3e147e94fea99.js.map → 13.645dd0b7c0b9210f1b56.js.map} +1 -1
  20. udata/static/chunks/{17.b91d28f550dc44bc4979.js → 17.8e19985c4d12a3b7b0c0.js} +2 -2
  21. udata/static/chunks/{17.b91d28f550dc44bc4979.js.map → 17.8e19985c4d12a3b7b0c0.js.map} +1 -1
  22. udata/static/chunks/{19.a2ab343453156343fe37.js → 19.825a43c330157e351fca.js} +3 -3
  23. udata/static/chunks/{19.a2ab343453156343fe37.js.map → 19.825a43c330157e351fca.js.map} +1 -1
  24. udata/static/chunks/{5.5ceafbe5d5db2c8e7c64.js → 5.860362216c0ce3ec565f.js} +3 -3
  25. udata/static/chunks/{5.5ceafbe5d5db2c8e7c64.js.map → 5.860362216c0ce3ec565f.js.map} +1 -1
  26. udata/static/chunks/{6.a6183760bba4a984a92d.js → 6.6617c697f229f362d732.js} +3 -3
  27. udata/static/chunks/{6.a6183760bba4a984a92d.js.map → 6.6617c697f229f362d732.js.map} +1 -1
  28. udata/static/chunks/{8.2109f27ae53f737a3398.js → 8.05a0db37aa4ed53ea45e.js} +2 -2
  29. udata/static/chunks/{8.2109f27ae53f737a3398.js.map → 8.05a0db37aa4ed53ea45e.js.map} +1 -1
  30. udata/static/common.js +1 -1
  31. udata/static/common.js.map +1 -1
  32. udata/templates/mail/badge_added_association.html +3 -3
  33. udata/templates/mail/badge_added_association.txt +2 -2
  34. udata/templates/mail/badge_added_certified.html +3 -3
  35. udata/templates/mail/badge_added_certified.txt +1 -1
  36. udata/templates/mail/badge_added_company.html +3 -3
  37. udata/templates/mail/badge_added_company.txt +2 -2
  38. udata/templates/mail/badge_added_local_authority.html +3 -3
  39. udata/templates/mail/badge_added_local_authority.txt +2 -2
  40. udata/templates/mail/badge_added_public_service.html +3 -3
  41. udata/templates/mail/badge_added_public_service.txt +1 -1
  42. udata/templates/mail/discussion_closed.html +3 -3
  43. udata/templates/mail/discussion_closed.txt +1 -1
  44. udata/templates/mail/frequency_reminder.html +1 -1
  45. udata/templates/mail/frequency_reminder.txt +1 -1
  46. udata/templates/mail/membership_refused.html +1 -1
  47. udata/templates/mail/membership_request.html +3 -3
  48. udata/templates/mail/membership_request.txt +1 -1
  49. udata/templates/mail/new_discussion.html +3 -3
  50. udata/templates/mail/new_discussion.txt +1 -1
  51. udata/templates/mail/new_discussion_comment.html +3 -3
  52. udata/templates/mail/new_discussion_comment.txt +1 -1
  53. udata/templates/mail/new_member.html +2 -2
  54. udata/templates/mail/new_member.txt +1 -1
  55. udata/templates/mail/new_reuse.html +3 -3
  56. udata/templates/mail/new_reuse.txt +2 -2
  57. udata/templates/mail/user_mail_card.html +1 -1
  58. udata/tests/dataset/test_dataset_rdf.py +0 -28
  59. udata/tests/test_mail.py +1 -61
  60. {udata-10.0.3.dist-info → udata-10.0.3.dev32541.dist-info}/METADATA +4 -8
  61. {udata-10.0.3.dist-info → udata-10.0.3.dev32541.dist-info}/RECORD +65 -67
  62. udata/migrations/2024-11-19-keep-only-local_authority-if-also-public_service-organization-badges.py +0 -22
  63. udata/tests/dataservice/test_dataservice_rdf.py +0 -68
  64. {udata-10.0.3.dist-info → udata-10.0.3.dev32541.dist-info}/LICENSE +0 -0
  65. {udata-10.0.3.dist-info → udata-10.0.3.dev32541.dist-info}/WHEEL +0 -0
  66. {udata-10.0.3.dist-info → udata-10.0.3.dev32541.dist-info}/entry_points.txt +0 -0
  67. {udata-10.0.3.dist-info → udata-10.0.3.dev32541.dist-info}/top_level.txt +0 -0
udata/__init__.py CHANGED
@@ -4,5 +4,5 @@
4
4
  udata
5
5
  """
6
6
 
7
- __version__ = "10.0.3"
7
+ __version__ = "10.0.3.dev"
8
8
  __description__ = "Open data portal"
@@ -39,7 +39,7 @@ COMMUNITY_RES_URL = "/api/1/datasets/community_resources"
39
39
  DISCUSSION_URL = "/api/1/discussions"
40
40
 
41
41
 
42
- DEFAULT_FIXTURE_FILE_TAG: str = "v4.0.0"
42
+ DEFAULT_FIXTURE_FILE_TAG: str = "v3.0.0"
43
43
  DEFAULT_FIXTURE_FILE: str = f"https://raw.githubusercontent.com/opendatateam/udata-fixtures/{DEFAULT_FIXTURE_FILE_TAG}/results.json" # noqa
44
44
 
45
45
  DEFAULT_FIXTURES_RESULTS_FILENAME: str = "results.json"
@@ -180,9 +180,7 @@ def get_or_create_user(data):
180
180
  def import_fixtures(source):
181
181
  """Build sample fixture data (users, datasets, reuses, dataservices) from local or remote file."""
182
182
  if source.startswith("http"):
183
- response = requests.get(source)
184
- response.raise_for_status()
185
- json_fixtures = response.json()
183
+ json_fixtures = requests.get(source).json()
186
184
  else:
187
185
  with open(source) as f:
188
186
  json_fixtures = json.load(f)
@@ -7,10 +7,7 @@ from udata.core.dataset.models import Dataset, License
7
7
  from udata.core.dataset.rdf import dataset_to_graph_id, sanitize_html
8
8
  from udata.rdf import (
9
9
  DCAT,
10
- DCATAP,
11
10
  DCT,
12
- HVD_LEGISLATION,
13
- TAG_TO_EU_HVD_CATEGORIES,
14
11
  contact_point_from_rdf,
15
12
  contact_point_to_rdf,
16
13
  namespace_manager,
@@ -141,29 +138,8 @@ def dataservice_to_rdf(dataservice: Dataservice, graph=None):
141
138
  if dataservice.endpoint_description_url:
142
139
  d.set(DCAT.endpointDescription, URIRef(dataservice.endpoint_description_url))
143
140
 
144
- # Add DCAT-AP HVD properties if the dataservice is tagged hvd.
145
- # See https://semiceu.github.io/DCAT-AP/releases/2.2.0-hvd/
146
- is_hvd = current_app.config["HVD_SUPPORT"] and "hvd" in dataservice.tags
147
- if is_hvd:
148
- d.add(DCATAP.applicableLegislation, URIRef(HVD_LEGISLATION))
149
-
150
- hvd_category_tags = set()
151
141
  for tag in dataservice.tags:
152
142
  d.add(DCAT.keyword, Literal(tag))
153
- # Add HVD category if this dataservice is tagged HVD
154
- if is_hvd and tag in TAG_TO_EU_HVD_CATEGORIES:
155
- hvd_category_tags.add(tag)
156
-
157
- if is_hvd:
158
- # We also want to automatically add any HVD category tags of the dataservice's datasets.
159
- for dataset in dataservice.datasets:
160
- if "hvd" not in dataset.tags: # Only check HVD datasets for their categories.
161
- continue
162
- for tag in dataset.tags:
163
- if tag in TAG_TO_EU_HVD_CATEGORIES:
164
- hvd_category_tags.add(tag)
165
- for tag in hvd_category_tags:
166
- d.add(DCATAP.hvdCategory, URIRef(TAG_TO_EU_HVD_CATEGORIES[tag]))
167
143
 
168
144
  # `dataset_to_graph_id(dataset)` URIRef may not exist in the current page
169
145
  # but should exists in the catalog somewhere. Maybe we should create a Node
@@ -72,8 +72,6 @@ RESOURCE_FILETYPES = OrderedDict(
72
72
  ]
73
73
  )
74
74
 
75
- OGC_SERVICE_FORMATS = ["ogc:wms", "ogc:wfs", "wms", "wfs"]
76
-
77
75
  CHECKSUM_TYPES = ("sha1", "sha2", "sha256", "md5", "crc")
78
76
  DEFAULT_CHECKSUM_TYPE = "sha1"
79
77
 
@@ -21,7 +21,6 @@ from udata.core import storages
21
21
  from udata.core.owned import Owned, OwnedQuerySet
22
22
  from udata.frontend.markdown import mdstrip
23
23
  from udata.i18n import lazy_gettext as _
24
- from udata.mail import get_mail_campaign_dict
25
24
  from udata.models import Badge, BadgeMixin, BadgesList, SpatialCoverage, WithMetrics, db
26
25
  from udata.mongo.errors import FieldValidationError
27
26
  from udata.uris import ValidationError, endpoint_for
@@ -690,11 +689,6 @@ class Dataset(WithMetrics, DatasetBadgeMixin, Owned, db.Document):
690
689
  def external_url(self):
691
690
  return self.url_for(_external=True)
692
691
 
693
- @property
694
- def external_url_with_campaign(self):
695
- extras = get_mail_campaign_dict()
696
- return self.url_for(_external=True, **extras)
697
-
698
692
  @property
699
693
  def image_url(self):
700
694
  if self.organization:
udata/core/dataset/rdf.py CHANGED
@@ -49,7 +49,7 @@ from udata.rdf import (
49
49
  from udata.uris import endpoint_for
50
50
  from udata.utils import get_by, safe_unicode
51
51
 
52
- from .constants import OGC_SERVICE_FORMATS, UPDATE_FREQUENCIES
52
+ from .constants import UPDATE_FREQUENCIES
53
53
  from .models import Checksum, Dataset, License, Resource
54
54
 
55
55
  log = logging.getLogger(__name__)
@@ -126,44 +126,6 @@ def owner_to_rdf(dataset, graph=None):
126
126
  return
127
127
 
128
128
 
129
- def ogc_service_to_rdf(dataset, resource, graph=None, is_hvd=False):
130
- """
131
- Build a dataservice on the fly for OGC services distributions
132
- Inspired from https://github.com/SEMICeu/iso-19139-to-dcat-ap/blob/f61b2921dd398b90b2dd2db14085e75687f7616b/iso-19139-to-dcat-ap.xsl#L1419
133
- """
134
- graph = graph or Graph(namespace_manager=namespace_manager)
135
- service = graph.resource(BNode())
136
- service.set(RDF.type, DCAT.DataService)
137
- service.set(DCT.title, Literal(resource.title))
138
- service.set(DCAT.endpointURL, URIRef(resource.url.split("?")[0]))
139
- if "request=getcapabilities" in resource.url.lower():
140
- service.set(DCAT.endpointDescription, URIRef(resource.url))
141
- service.set(
142
- DCT.conformsTo,
143
- URIRef("http://www.opengeospatial.org/standards/" + resource.format.split(":")[-1]),
144
- )
145
-
146
- if dataset and dataset.license:
147
- service.add(DCT.rights, Literal(dataset.license.title))
148
- if dataset.license.url:
149
- service.add(DCT.license, URIRef(dataset.license.url))
150
-
151
- if dataset and dataset.contact_point:
152
- contact_point = contact_point_to_rdf(dataset.contact_point, graph)
153
- if contact_point:
154
- service.set(DCAT.contactPoint, contact_point)
155
-
156
- if is_hvd:
157
- # DCAT-AP HVD applicable legislation is also expected at the distribution > accessService level
158
- service.add(DCATAP.applicableLegislation, URIRef(HVD_LEGISLATION))
159
- for tag in dataset.tags:
160
- # Add HVD category if this dataset is tagged HVD
161
- if tag in TAG_TO_EU_HVD_CATEGORIES:
162
- service.add(DCATAP.hvdCategory, URIRef(TAG_TO_EU_HVD_CATEGORIES[tag]))
163
-
164
- return service
165
-
166
-
167
129
  def resource_to_rdf(resource, dataset=None, graph=None, is_hvd=False):
168
130
  """
169
131
  Map a Resource domain model to a DCAT/RDF graph
@@ -213,11 +175,6 @@ def resource_to_rdf(resource, dataset=None, graph=None, is_hvd=False):
213
175
  if is_hvd:
214
176
  # DCAT-AP HVD applicable legislation is also expected at the distribution level
215
177
  r.add(DCATAP.applicableLegislation, URIRef(HVD_LEGISLATION))
216
-
217
- # Add access service for known OGC service formats
218
- if resource.format in OGC_SERVICE_FORMATS:
219
- r.add(DCAT.accessService, ogc_service_to_rdf(dataset, resource, graph, is_hvd))
220
-
221
178
  return r
222
179
 
223
180
 
@@ -4,7 +4,6 @@ from datetime import datetime
4
4
  from flask_login import current_user
5
5
 
6
6
  from udata.core.spam.models import SpamMixin, spam_protected
7
- from udata.mail import get_mail_campaign_dict
8
7
  from udata.mongo import db
9
8
 
10
9
  from .signals import on_discussion_closed, on_new_discussion, on_new_discussion_comment
@@ -95,13 +94,6 @@ class Discussion(SpamMixin, db.Document):
95
94
  def external_url(self):
96
95
  return self.subject.url_for(_anchor="discussion-{id}".format(id=self.id), _external=True)
97
96
 
98
- @property
99
- def external_url_with_campaign(self):
100
- extras = get_mail_campaign_dict()
101
- return self.subject.url_for(
102
- _anchor="discussion-{id}".format(id=self.id), _external=True, **extras
103
- )
104
-
105
97
  def spam_report_message(self, breadcrumb):
106
98
  message = f"Spam potentiel sur la discussion « [{self.title}]({self.external_url}) »"
107
99
  if self.user:
@@ -11,7 +11,6 @@ from udata.core.metrics.models import WithMetrics
11
11
  from udata.core.storages import avatars, default_image_basename
12
12
  from udata.frontend.markdown import mdstrip
13
13
  from udata.i18n import lazy_gettext as _
14
- from udata.mail import get_mail_campaign_dict
15
14
  from udata.mongo import db
16
15
  from udata.uris import endpoint_for
17
16
 
@@ -189,11 +188,6 @@ class Organization(WithMetrics, OrganizationBadgeMixin, db.Datetimed, db.Documen
189
188
  def external_url(self):
190
189
  return self.url_for(_external=True)
191
190
 
192
- @property
193
- def external_url_with_campaign(self):
194
- extras = get_mail_campaign_dict()
195
- return self.url_for(_external=True, **extras)
196
-
197
191
  @property
198
192
  def pending_requests(self):
199
193
  return [r for r in self.requests if r.status == "pending"]
udata/core/post/models.py CHANGED
@@ -2,7 +2,6 @@ from flask import url_for
2
2
 
3
3
  from udata.core.storages import default_image_basename, images
4
4
  from udata.i18n import lazy_gettext as _
5
- from udata.mail import get_mail_campaign_dict
6
5
  from udata.mongo import db
7
6
 
8
7
  from .constants import BODY_TYPES, IMAGE_SIZES
@@ -62,11 +61,6 @@ class Post(db.Datetimed, db.Document):
62
61
  def external_url(self):
63
62
  return self.url_for(_external=True)
64
63
 
65
- @property
66
- def external_url_with_campaign(self):
67
- extras = get_mail_campaign_dict()
68
- return self.url_for(_external=True, **extras)
69
-
70
64
  def count_discussions(self):
71
65
  # There are no metrics on Post to store discussions count
72
66
  pass
@@ -9,7 +9,6 @@ from udata.core.reuse.api_fields import BIGGEST_IMAGE_SIZE
9
9
  from udata.core.storages import default_image_basename, images
10
10
  from udata.frontend.markdown import mdstrip
11
11
  from udata.i18n import lazy_gettext as _
12
- from udata.mail import get_mail_campaign_dict
13
12
  from udata.models import Badge, BadgeMixin, BadgesList, WithMetrics, db
14
13
  from udata.mongo.errors import FieldValidationError
15
14
  from udata.uris import endpoint_for
@@ -219,11 +218,6 @@ class Reuse(db.Datetimed, WithMetrics, ReuseBadgeMixin, Owned, db.Document):
219
218
  def external_url(self):
220
219
  return self.url_for(_external=True)
221
220
 
222
- @property
223
- def external_url_with_campaign(self):
224
- extras = get_mail_campaign_dict()
225
- return self.url_for(_external=True, **extras)
226
-
227
221
  @property
228
222
  def type_label(self):
229
223
  return REUSE_TYPES[self.type]
@@ -5,7 +5,6 @@ from werkzeug.utils import cached_property
5
5
  from udata.app import cache
6
6
  from udata.core.metrics.models import WithMetrics
7
7
  from udata.i18n import _, get_locale, language
8
- from udata.mail import get_mail_campaign_dict
9
8
  from udata.mongo import db
10
9
  from udata.uris import endpoint_for
11
10
 
@@ -98,11 +97,6 @@ class GeoZone(WithMetrics, db.Document):
98
97
  def external_url(self):
99
98
  return endpoint_for("territories.territory", territory=self, _external=True)
100
99
 
101
- @property
102
- def external_url_with_campaign(self):
103
- extras = get_mail_campaign_dict()
104
- return endpoint_for("territories.territory", territory=self, _external=True, **extras)
105
-
106
100
  def count_datasets(self):
107
101
  from udata.models import Dataset
108
102
 
udata/core/user/models.py CHANGED
@@ -17,7 +17,6 @@ from udata.core.discussions.models import Discussion
17
17
  from udata.core.storages import avatars, default_image_basename
18
18
  from udata.frontend.markdown import mdstrip
19
19
  from udata.i18n import lazy_gettext as _
20
- from udata.mail import get_mail_campaign_dict
21
20
  from udata.models import Follow, WithMetrics, db
22
21
  from udata.uris import endpoint_for
23
22
 
@@ -129,11 +128,6 @@ class User(WithMetrics, UserMixin, db.Document):
129
128
  def external_url(self):
130
129
  return self.url_for(_external=True)
131
130
 
132
- @property
133
- def external_url_with_campaign(self):
134
- extras = get_mail_campaign_dict()
135
- return self.url_for(_external=True, **extras)
136
-
137
131
  @property
138
132
  def visible(self):
139
133
  count = self.metrics.get("datasets", 0) + self.metrics.get("reuses", 0)
@@ -1,6 +1,5 @@
1
1
  from flask import url_for
2
2
 
3
- from udata.mail import get_mail_campaign_dict
4
3
  from udata.models import License, Organization
5
4
 
6
5
  __all__ = ("TerritoryDataset", "ResourceBasedTerritoryDataset", "TERRITORY_DATASETS")
@@ -60,8 +59,3 @@ class ResourceBasedTerritoryDataset(TerritoryDataset):
60
59
  @property
61
60
  def external_url(self):
62
61
  return self.url_for(external=True)
63
-
64
- @property
65
- def external_url_with_campaign(self):
66
- extras = get_mail_campaign_dict()
67
- return self.url_for(_external=True, **extras)
@@ -54,9 +54,6 @@ URIS_TO_REPLACE = {
54
54
  }
55
55
 
56
56
 
57
- SAFE_PARSER = ET.XMLParser(resolve_entities=False)
58
-
59
-
60
57
  def extract_graph(source, target, node, specs):
61
58
  for p, o in source.predicate_objects(node):
62
59
  target.add((node, p, o))
@@ -253,7 +250,7 @@ class CswDcatBackend(DcatBackend):
253
250
  )
254
251
  response.raise_for_status()
255
252
  content = response.content
256
- tree = ET.fromstring(content, parser=SAFE_PARSER)
253
+ tree = ET.fromstring(content)
257
254
  if tree.tag == "{" + OWS_NAMESPACE + "}ExceptionReport":
258
255
  raise ValueError(f"Failed to query CSW:\n{content}")
259
256
  while tree is not None:
@@ -279,8 +276,7 @@ class CswDcatBackend(DcatBackend):
279
276
  tree = ET.fromstring(
280
277
  self.post(
281
278
  url, data=body.format(start=start, schema=self.DCAT_SCHEMA), headers=headers
282
- ).content,
283
- parser=SAFE_PARSER,
279
+ ).content
284
280
  )
285
281
 
286
282
 
@@ -313,7 +309,7 @@ class CswIso19139DcatBackend(DcatBackend):
313
309
  See https://github.com/SEMICeu/iso-19139-to-dcat-ap for more information on the XSLT.
314
310
  """
315
311
  # Load XSLT
316
- xsl = ET.fromstring(self.get(self.XSL_URL).content, parser=SAFE_PARSER)
312
+ xsl = ET.fromstring(self.get(self.XSL_URL).content)
317
313
  transform = ET.XSLT(xsl)
318
314
 
319
315
  # Start querying and parsing graph
@@ -355,7 +351,7 @@ class CswIso19139DcatBackend(DcatBackend):
355
351
  )
356
352
  response.raise_for_status()
357
353
 
358
- tree_before_transform = ET.fromstring(response.content, parser=SAFE_PARSER)
354
+ tree_before_transform = ET.fromstring(response.content)
359
355
  # Disabling CoupledResourceLookUp to prevent failure on xlink:href
360
356
  # https://github.com/SEMICeu/iso-19139-to-dcat-ap/blob/master/documentation/HowTo.md#parameter-coupledresourcelookup
361
357
  tree = transform(tree_before_transform, CoupledResourceLookUp="'disabled'")
@@ -390,5 +386,5 @@ class CswIso19139DcatBackend(DcatBackend):
390
386
  )
391
387
  response.raise_for_status()
392
388
 
393
- tree_before_transform = ET.fromstring(response.content, parser=SAFE_PARSER)
389
+ tree_before_transform = ET.fromstring(response.content)
394
390
  tree = transform(tree_before_transform, CoupledResourceLookUp="'disabled'")
udata/mail.py CHANGED
@@ -50,7 +50,6 @@ def send(subject, recipients, template_base, **kwargs):
50
50
  debug = current_app.config.get("DEBUG", False)
51
51
  send_mail = current_app.config.get("SEND_MAIL", not debug)
52
52
  connection = send_mail and mail.connect or dummyconnection
53
- extras = get_mail_campaign_dict()
54
53
 
55
54
  with connection() as conn:
56
55
  for recipient in recipients:
@@ -59,31 +58,16 @@ def send(subject, recipients, template_base, **kwargs):
59
58
  log.debug('Sending mail "%s" to recipient "%s"', subject, recipient)
60
59
  msg = Message(subject, sender=sender, recipients=[recipient.email])
61
60
  msg.body = render_template(
62
- f"{tpl_path}.txt",
63
- subject=subject,
64
- sender=sender,
65
- recipient=recipient,
66
- extras=extras,
67
- **kwargs,
61
+ f"{tpl_path}.txt", subject=subject, sender=sender, recipient=recipient, **kwargs
68
62
  )
69
63
  msg.html = render_template(
70
64
  f"{tpl_path}.html",
71
65
  subject=subject,
72
66
  sender=sender,
73
67
  recipient=recipient,
74
- extras=extras,
75
68
  **kwargs,
76
69
  )
77
70
  try:
78
71
  conn.send(msg)
79
72
  except SMTPException as e:
80
73
  log.error(f"Error sending mail {e}")
81
-
82
-
83
- def get_mail_campaign_dict() -> dict:
84
- """Return a dict with the `mtm_campaign` key set if there is a `MAIL_CAMPAIGN` configured in udata.cfg."""
85
- extras = {}
86
- mail_campaign = current_app.config.get("MAIL_CAMPAIGN")
87
- if mail_campaign:
88
- extras["mtm_campaign"] = mail_campaign
89
- return extras