udata 10.1.3.dev34195__py2.py3-none-any.whl → 10.1.3.dev34219__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 (27) hide show
  1. udata/core/dataset/api.py +18 -3
  2. udata/core/dataset/forms.py +8 -4
  3. udata/core/dataset/models.py +6 -0
  4. udata/static/chunks/{10.471164b2a9fe15614797.js → 10.8ca60413647062717b1e.js} +3 -3
  5. udata/static/chunks/{10.471164b2a9fe15614797.js.map → 10.8ca60413647062717b1e.js.map} +1 -1
  6. udata/static/chunks/{11.55ab79044cda0271b595.js → 11.b6f741fcc366abfad9c4.js} +3 -3
  7. udata/static/chunks/{11.55ab79044cda0271b595.js.map → 11.b6f741fcc366abfad9c4.js.map} +1 -1
  8. udata/static/chunks/{13.f29411b06be1883356a3.js → 13.2d06442dd9a05d9777b5.js} +2 -2
  9. udata/static/chunks/{13.f29411b06be1883356a3.js.map → 13.2d06442dd9a05d9777b5.js.map} +1 -1
  10. udata/static/chunks/{17.3bd0340930d4a314ce9c.js → 17.e8e4caaad5cb0cc0bacc.js} +2 -2
  11. udata/static/chunks/{17.3bd0340930d4a314ce9c.js.map → 17.e8e4caaad5cb0cc0bacc.js.map} +1 -1
  12. udata/static/chunks/{19.3e0e8651d948e04b8cf2.js → 19.f03a102365af4315f9db.js} +3 -3
  13. udata/static/chunks/{19.3e0e8651d948e04b8cf2.js.map → 19.f03a102365af4315f9db.js.map} +1 -1
  14. udata/static/chunks/{8.494b003a94383b142c18.js → 8.778091d55cd8ea39af6b.js} +2 -2
  15. udata/static/chunks/{8.494b003a94383b142c18.js.map → 8.778091d55cd8ea39af6b.js.map} +1 -1
  16. udata/static/chunks/{9.07515e5187f475bce828.js → 9.033d7e190ca9e226a5d0.js} +3 -3
  17. udata/static/chunks/{9.07515e5187f475bce828.js.map → 9.033d7e190ca9e226a5d0.js.map} +1 -1
  18. udata/static/common.js +1 -1
  19. udata/static/common.js.map +1 -1
  20. udata/tests/api/test_datasets_api.py +58 -0
  21. udata/tests/dataset/test_dataset_model.py +14 -0
  22. {udata-10.1.3.dev34195.dist-info → udata-10.1.3.dev34219.dist-info}/METADATA +3 -1
  23. {udata-10.1.3.dev34195.dist-info → udata-10.1.3.dev34219.dist-info}/RECORD +27 -27
  24. {udata-10.1.3.dev34195.dist-info → udata-10.1.3.dev34219.dist-info}/LICENSE +0 -0
  25. {udata-10.1.3.dev34195.dist-info → udata-10.1.3.dev34219.dist-info}/WHEEL +0 -0
  26. {udata-10.1.3.dev34195.dist-info → udata-10.1.3.dev34219.dist-info}/entry_points.txt +0 -0
  27. {udata-10.1.3.dev34195.dist-info → udata-10.1.3.dev34219.dist-info}/top_level.txt +0 -0
udata/core/dataset/api.py CHANGED
@@ -62,7 +62,12 @@ from .exceptions import (
62
62
  SchemasCacheUnavailableException,
63
63
  SchemasCatalogNotFoundException,
64
64
  )
65
- from .forms import CommunityResourceForm, DatasetForm, ResourceForm, ResourcesListForm
65
+ from .forms import (
66
+ CommunityResourceForm,
67
+ DatasetForm,
68
+ ResourceFormWithoutId,
69
+ ResourcesListForm,
70
+ )
66
71
  from .models import (
67
72
  Checksum,
68
73
  CommunityResource,
@@ -379,8 +384,9 @@ class ResourcesAPI(API):
379
384
  def post(self, dataset):
380
385
  """Create a new resource for a given dataset"""
381
386
  ResourceEditPermission(dataset).test()
382
- form = api.validate(ResourceForm)
387
+ form = api.validate(ResourceFormWithoutId)
383
388
  resource = Resource()
389
+
384
390
  if form._fields.get("filetype").data != "remote":
385
391
  api.abort(400, "This endpoint only supports remote resources")
386
392
  form.populate_obj(resource)
@@ -545,10 +551,19 @@ class ResourceAPI(ResourceMixin, API):
545
551
  """Update a given resource on a given dataset"""
546
552
  ResourceEditPermission(dataset).test()
547
553
  resource = self.get_resource_or_404(dataset, rid)
548
- form = api.validate(ResourceForm, resource)
554
+ form = api.validate(ResourceFormWithoutId, resource)
555
+
556
+ # ensure filetype is not modified after creation
557
+ if (
558
+ form._fields.get("filetype").data
559
+ and form._fields.get("filetype").data != resource.filetype
560
+ ):
561
+ abort(400, "Cannot modify filetype after creation")
562
+
549
563
  # ensure API client does not override url on self-hosted resources
550
564
  if resource.filetype == "file":
551
565
  form._fields.get("url").data = resource.url
566
+
552
567
  # populate_obj populates existing resource object with the content of the form.
553
568
  # update_resource saves the updated resource dict to the database
554
569
  # the additional dataset.save is required as we update the last_modified date.
@@ -72,7 +72,7 @@ class BaseResourceForm(ModelForm):
72
72
  [validators.DataRequired()],
73
73
  choices=list(RESOURCE_FILETYPES.items()),
74
74
  default="file",
75
- description=_("Whether the resource is an uploaded file, " "a remote file or an API"),
75
+ description=_("Whether the resource is an uploaded file, a remote file or an API"),
76
76
  )
77
77
  type = fields.RadioField(
78
78
  _("Type"),
@@ -89,7 +89,7 @@ class BaseResourceForm(ModelForm):
89
89
  checksum = fields.FormField(ChecksumForm)
90
90
  mime = fields.StringField(
91
91
  _("Mime type"),
92
- description=_("The mime type associated to the extension. " "(ex: text/plain)"),
92
+ description=_("The mime type associated to the extension. (ex: text/plain)"),
93
93
  )
94
94
  filesize = fields.IntegerField(
95
95
  _("Size"), [validators.optional()], description=_("The file size in bytes")
@@ -104,6 +104,10 @@ class ResourceForm(BaseResourceForm):
104
104
  id = fields.UUIDField()
105
105
 
106
106
 
107
+ class ResourceFormWithoutId(BaseResourceForm):
108
+ model_class = Resource
109
+
110
+
107
111
  class CommunityResourceForm(BaseResourceForm):
108
112
  model_class = CommunityResource
109
113
 
@@ -145,7 +149,7 @@ class DatasetForm(ModelForm):
145
149
  description = fields.MarkdownField(
146
150
  _("Description"),
147
151
  [validators.DataRequired(), validators.Length(max=DESCRIPTION_SIZE_LIMIT)],
148
- description=_("The details about the dataset " "(collection process, specifics...)."),
152
+ description=_("The details about the dataset (collection process, specifics...)."),
149
153
  )
150
154
  license = fields.ModelSelectField(_("License"), model=License, allow_blank=True)
151
155
  frequency = fields.SelectField(
@@ -168,7 +172,7 @@ class DatasetForm(ModelForm):
168
172
  tags = fields.TagField(_("Tags"), description=_("Some taxonomy keywords"))
169
173
  private = fields.BooleanField(
170
174
  _("Private"),
171
- description=_("Restrict the dataset visibility to you or " "your organization only."),
175
+ description=_("Restrict the dataset visibility to you or your organization only."),
172
176
  )
173
177
 
174
178
  owner = fields.CurrentUserField()
@@ -638,6 +638,9 @@ class Dataset(WithMetrics, DatasetBadgeMixin, Owned, db.Document):
638
638
  if self.frequency in LEGACY_FREQUENCIES:
639
639
  self.frequency = LEGACY_FREQUENCIES[self.frequency]
640
640
 
641
+ if len(set(res.id for res in self.resources)) != len(self.resources):
642
+ raise MongoEngineValidationError(f"Duplicate resource ID in dataset #{self.id}.")
643
+
641
644
  for key, value in self.extras.items():
642
645
  if not key.startswith("custom:"):
643
646
  continue
@@ -897,6 +900,9 @@ class Dataset(WithMetrics, DatasetBadgeMixin, Owned, db.Document):
897
900
  def add_resource(self, resource):
898
901
  """Perform an atomic prepend for a new resource"""
899
902
  resource.validate()
903
+ if resource.id in [r.id for r in self.resources]:
904
+ raise MongoEngineValidationError("Cannot add resource with already existing ID")
905
+
900
906
  self.update(
901
907
  __raw__={"$push": {"resources": {"$each": [resource.to_mongo()], "$position": 0}}}
902
908
  )