kinto 23.2.1__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.
Files changed (142) hide show
  1. kinto/__init__.py +92 -0
  2. kinto/__main__.py +249 -0
  3. kinto/authorization.py +134 -0
  4. kinto/config/__init__.py +94 -0
  5. kinto/config/kinto.tpl +270 -0
  6. kinto/contribute.json +27 -0
  7. kinto/core/__init__.py +246 -0
  8. kinto/core/authentication.py +48 -0
  9. kinto/core/authorization.py +311 -0
  10. kinto/core/cache/__init__.py +131 -0
  11. kinto/core/cache/memcached.py +112 -0
  12. kinto/core/cache/memory.py +104 -0
  13. kinto/core/cache/postgresql/__init__.py +178 -0
  14. kinto/core/cache/postgresql/schema.sql +23 -0
  15. kinto/core/cache/testing.py +208 -0
  16. kinto/core/cornice/__init__.py +93 -0
  17. kinto/core/cornice/cors.py +144 -0
  18. kinto/core/cornice/errors.py +40 -0
  19. kinto/core/cornice/pyramidhook.py +373 -0
  20. kinto/core/cornice/renderer.py +89 -0
  21. kinto/core/cornice/resource.py +205 -0
  22. kinto/core/cornice/service.py +641 -0
  23. kinto/core/cornice/util.py +138 -0
  24. kinto/core/cornice/validators/__init__.py +94 -0
  25. kinto/core/cornice/validators/_colander.py +142 -0
  26. kinto/core/cornice/validators/_marshmallow.py +182 -0
  27. kinto/core/cornice_swagger/__init__.py +92 -0
  28. kinto/core/cornice_swagger/converters/__init__.py +21 -0
  29. kinto/core/cornice_swagger/converters/exceptions.py +6 -0
  30. kinto/core/cornice_swagger/converters/parameters.py +90 -0
  31. kinto/core/cornice_swagger/converters/schema.py +249 -0
  32. kinto/core/cornice_swagger/swagger.py +725 -0
  33. kinto/core/cornice_swagger/templates/index.html +73 -0
  34. kinto/core/cornice_swagger/templates/index_script_template.html +21 -0
  35. kinto/core/cornice_swagger/util.py +42 -0
  36. kinto/core/cornice_swagger/views.py +78 -0
  37. kinto/core/decorators.py +74 -0
  38. kinto/core/errors.py +216 -0
  39. kinto/core/events.py +301 -0
  40. kinto/core/initialization.py +738 -0
  41. kinto/core/listeners/__init__.py +9 -0
  42. kinto/core/metrics.py +94 -0
  43. kinto/core/openapi.py +115 -0
  44. kinto/core/permission/__init__.py +202 -0
  45. kinto/core/permission/memory.py +167 -0
  46. kinto/core/permission/postgresql/__init__.py +489 -0
  47. kinto/core/permission/postgresql/migrations/migration_001_002.sql +18 -0
  48. kinto/core/permission/postgresql/schema.sql +41 -0
  49. kinto/core/permission/testing.py +487 -0
  50. kinto/core/resource/__init__.py +1311 -0
  51. kinto/core/resource/model.py +412 -0
  52. kinto/core/resource/schema.py +502 -0
  53. kinto/core/resource/viewset.py +230 -0
  54. kinto/core/schema.py +119 -0
  55. kinto/core/scripts.py +50 -0
  56. kinto/core/statsd.py +1 -0
  57. kinto/core/storage/__init__.py +436 -0
  58. kinto/core/storage/exceptions.py +53 -0
  59. kinto/core/storage/generators.py +58 -0
  60. kinto/core/storage/memory.py +651 -0
  61. kinto/core/storage/postgresql/__init__.py +1131 -0
  62. kinto/core/storage/postgresql/client.py +120 -0
  63. kinto/core/storage/postgresql/migrations/migration_001_002.sql +10 -0
  64. kinto/core/storage/postgresql/migrations/migration_002_003.sql +33 -0
  65. kinto/core/storage/postgresql/migrations/migration_003_004.sql +18 -0
  66. kinto/core/storage/postgresql/migrations/migration_004_005.sql +20 -0
  67. kinto/core/storage/postgresql/migrations/migration_005_006.sql +11 -0
  68. kinto/core/storage/postgresql/migrations/migration_006_007.sql +74 -0
  69. kinto/core/storage/postgresql/migrations/migration_007_008.sql +66 -0
  70. kinto/core/storage/postgresql/migrations/migration_008_009.sql +41 -0
  71. kinto/core/storage/postgresql/migrations/migration_009_010.sql +98 -0
  72. kinto/core/storage/postgresql/migrations/migration_010_011.sql +14 -0
  73. kinto/core/storage/postgresql/migrations/migration_011_012.sql +9 -0
  74. kinto/core/storage/postgresql/migrations/migration_012_013.sql +71 -0
  75. kinto/core/storage/postgresql/migrations/migration_013_014.sql +14 -0
  76. kinto/core/storage/postgresql/migrations/migration_014_015.sql +95 -0
  77. kinto/core/storage/postgresql/migrations/migration_015_016.sql +4 -0
  78. kinto/core/storage/postgresql/migrations/migration_016_017.sql +81 -0
  79. kinto/core/storage/postgresql/migrations/migration_017_018.sql +25 -0
  80. kinto/core/storage/postgresql/migrations/migration_018_019.sql +8 -0
  81. kinto/core/storage/postgresql/migrations/migration_019_020.sql +7 -0
  82. kinto/core/storage/postgresql/migrations/migration_020_021.sql +68 -0
  83. kinto/core/storage/postgresql/migrations/migration_021_022.sql +62 -0
  84. kinto/core/storage/postgresql/migrations/migration_022_023.sql +5 -0
  85. kinto/core/storage/postgresql/migrations/migration_023_024.sql +6 -0
  86. kinto/core/storage/postgresql/migrations/migration_024_025.sql +6 -0
  87. kinto/core/storage/postgresql/migrator.py +98 -0
  88. kinto/core/storage/postgresql/pool.py +55 -0
  89. kinto/core/storage/postgresql/schema.sql +143 -0
  90. kinto/core/storage/testing.py +1857 -0
  91. kinto/core/storage/utils.py +37 -0
  92. kinto/core/testing.py +182 -0
  93. kinto/core/utils.py +553 -0
  94. kinto/core/views/__init__.py +0 -0
  95. kinto/core/views/batch.py +163 -0
  96. kinto/core/views/errors.py +145 -0
  97. kinto/core/views/heartbeat.py +106 -0
  98. kinto/core/views/hello.py +69 -0
  99. kinto/core/views/openapi.py +35 -0
  100. kinto/core/views/version.py +50 -0
  101. kinto/events.py +3 -0
  102. kinto/plugins/__init__.py +0 -0
  103. kinto/plugins/accounts/__init__.py +94 -0
  104. kinto/plugins/accounts/authentication.py +63 -0
  105. kinto/plugins/accounts/scripts.py +61 -0
  106. kinto/plugins/accounts/utils.py +13 -0
  107. kinto/plugins/accounts/views.py +136 -0
  108. kinto/plugins/admin/README.md +3 -0
  109. kinto/plugins/admin/VERSION +1 -0
  110. kinto/plugins/admin/__init__.py +40 -0
  111. kinto/plugins/admin/build/VERSION +1 -0
  112. kinto/plugins/admin/build/assets/index-CYFwtKtL.css +6 -0
  113. kinto/plugins/admin/build/assets/index-DJ0m93zA.js +149 -0
  114. kinto/plugins/admin/build/assets/logo-VBRiKSPX.png +0 -0
  115. kinto/plugins/admin/build/index.html +18 -0
  116. kinto/plugins/admin/public/help.html +25 -0
  117. kinto/plugins/admin/views.py +42 -0
  118. kinto/plugins/default_bucket/__init__.py +191 -0
  119. kinto/plugins/flush.py +28 -0
  120. kinto/plugins/history/__init__.py +65 -0
  121. kinto/plugins/history/listener.py +181 -0
  122. kinto/plugins/history/views.py +66 -0
  123. kinto/plugins/openid/__init__.py +131 -0
  124. kinto/plugins/openid/utils.py +14 -0
  125. kinto/plugins/openid/views.py +193 -0
  126. kinto/plugins/prometheus.py +300 -0
  127. kinto/plugins/statsd.py +85 -0
  128. kinto/schema_validation.py +135 -0
  129. kinto/views/__init__.py +34 -0
  130. kinto/views/admin.py +195 -0
  131. kinto/views/buckets.py +45 -0
  132. kinto/views/collections.py +58 -0
  133. kinto/views/contribute.py +39 -0
  134. kinto/views/groups.py +90 -0
  135. kinto/views/permissions.py +235 -0
  136. kinto/views/records.py +133 -0
  137. kinto-23.2.1.dist-info/METADATA +232 -0
  138. kinto-23.2.1.dist-info/RECORD +142 -0
  139. kinto-23.2.1.dist-info/WHEEL +5 -0
  140. kinto-23.2.1.dist-info/entry_points.txt +5 -0
  141. kinto-23.2.1.dist-info/licenses/LICENSE +13 -0
  142. kinto-23.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,412 @@
1
+ import warnings
2
+
3
+
4
+ class Model:
5
+ """A resource stores and manipulate objects in its attached storage.
6
+
7
+ It is not aware of HTTP environment nor HTTP API.
8
+
9
+ Objects are isolated according to the provided `name` and `parent_id`.
10
+
11
+ Those notions have no particular semantic and can represent anything.
12
+ For example, the resource `name` can be the *type* of objects stored, and
13
+ `parent_id` can be the current *user id* or *a group* where the resource
14
+ belongs. If left empty, the resource objects are not isolated.
15
+ """
16
+
17
+ id_field = "id"
18
+ """Name of `id` field in objects"""
19
+
20
+ modified_field = "last_modified"
21
+ """Name of `last modified` field in objects"""
22
+
23
+ deleted_field = "deleted"
24
+ """Name of `deleted` field in deleted objects"""
25
+
26
+ permissions_field = "__permissions__"
27
+ # Permissions field used to annotate data with permissions.
28
+
29
+ def __init__(
30
+ self,
31
+ storage,
32
+ permission,
33
+ id_generator=None,
34
+ resource_name="",
35
+ parent_id="",
36
+ current_principal=None,
37
+ prefixed_principals=None,
38
+ explicit_perm=True,
39
+ ):
40
+ """
41
+ :param storage: an instance of storage
42
+ :type storage: :class:`kinto.core.storage.Storage`
43
+ :param id_generator: an instance of id generator, used by storage
44
+ on object creation.
45
+
46
+ :param str resource_name: the resource name
47
+ :param str parent_id: the default parent id
48
+ :param bool explicit_perm:
49
+ Without explicit permissions, the ACLs on the object will
50
+ fully depend on the inherited permission tree (eg. read/write on parent).
51
+ This basically means that if user loose the permission on the
52
+ parent, they also loose the permission on children.
53
+ See https://github.com/Kinto/kinto/issues/893
54
+ """
55
+ self.storage = storage
56
+ self.permission = permission
57
+ self.id_generator = id_generator
58
+ self.parent_id = parent_id
59
+ self.resource_name = resource_name
60
+ self.current_principal = current_principal
61
+ self.prefixed_principals = prefixed_principals
62
+ self.explicit_perm = explicit_perm
63
+
64
+ # Object permission id.
65
+ self.get_permission_object_id = None
66
+
67
+ def timestamp(self, parent_id=None):
68
+ """Fetch the resource current timestamp.
69
+
70
+ :param str parent_id: optional filter for parent id
71
+ :rtype: int
72
+
73
+ """
74
+ parent_id = parent_id or self.parent_id
75
+ return self.storage.resource_timestamp(
76
+ resource_name=self.resource_name, parent_id=parent_id
77
+ )
78
+
79
+ def _annotate(self, obj, perm_object_id):
80
+ permissions = self.permission.get_object_permissions(perm_object_id)
81
+ # Permissions are not returned if user only has read permission.
82
+ writers = permissions.get("write", [])
83
+ principals = self.prefixed_principals + [self.current_principal]
84
+ if len(set(writers) & set(principals)) == 0:
85
+ permissions = {}
86
+ # Insert the permissions values in the response.
87
+ annotated = {**obj, self.permissions_field: permissions}
88
+ return annotated
89
+
90
+ def _allow_write(self, perm_object_id):
91
+ """Helper to give the ``write`` permission to the current user."""
92
+ if self.explicit_perm:
93
+ self.permission.add_principal_to_ace(perm_object_id, "write", self.current_principal)
94
+
95
+ def get_objects(
96
+ self,
97
+ filters=None,
98
+ sorting=None,
99
+ pagination_rules=None,
100
+ limit=None,
101
+ include_deleted=False,
102
+ parent_id=None,
103
+ ):
104
+ """Fetch the resource objects.
105
+
106
+ Override to post-process objects after feching them from storage.
107
+
108
+ :param filters: Optionally filter the objects by their attribute.
109
+ Each filter in this list is a tuple of a field, a value and a
110
+ comparison (see `kinto.core.utils.COMPARISON`). All filters
111
+ are combined using *AND*.
112
+ :type filters: list of :class:`kinto.core.storage.Filter`
113
+
114
+ :param sorting: Optionally sort the objects by attribute.
115
+ Each sort instruction in this list refers to a field and a
116
+ direction (negative means descending). All sort instructions are
117
+ cumulative.
118
+ :type sorting: list of :class:`kinto.core.storage.Sort`
119
+
120
+ :param pagination_rules: Optionally paginate the list of objects.
121
+ This list of rules aims to reduce the set of objects to the current
122
+ page. A rule is a list of filters (see `filters` parameter),
123
+ and all rules are combined using *OR*.
124
+ :type pagination_rules: list of list of
125
+ :class:`kinto.core.storage.Filter`
126
+
127
+ :param int limit: Optionally limit the number of objects to be
128
+ retrieved.
129
+
130
+ :param bool include_deleted: Optionally include the deleted objects
131
+ that match the filters.
132
+
133
+ :param str parent_id: optional filter for parent id
134
+
135
+ :returns: A list of objects in the current page.
136
+ :rtype: list
137
+ """
138
+ parent_id = parent_id or self.parent_id
139
+ return self.storage.list_all(
140
+ resource_name=self.resource_name,
141
+ parent_id=parent_id,
142
+ filters=filters,
143
+ sorting=sorting,
144
+ pagination_rules=pagination_rules,
145
+ limit=limit,
146
+ include_deleted=include_deleted,
147
+ id_field=self.id_field,
148
+ modified_field=self.modified_field,
149
+ deleted_field=self.deleted_field,
150
+ )
151
+
152
+ def count_objects(self, filters=None, parent_id=None):
153
+ """Fetch the total count of resource objects
154
+
155
+ Override to post-process objects after feching them from storage.
156
+
157
+ :param filters: Optionally filter the objects by their attribute.
158
+ Each filter in this list is a tuple of a field, a value and a
159
+ comparison (see `kinto.core.utils.COMPARISON`). All filters
160
+ are combined using *AND*.
161
+ :type filters: list of :class:`kinto.core.storage.Filter`
162
+
163
+ :param str parent_id: optional filter for parent id
164
+
165
+ :returns: An integer of the total number of objects in the result set.
166
+ :rtype: int
167
+ """
168
+ parent_id = parent_id or self.parent_id
169
+ return self.storage.count_all(
170
+ resource_name=self.resource_name,
171
+ parent_id=parent_id,
172
+ filters=filters,
173
+ id_field=self.id_field,
174
+ modified_field=self.modified_field,
175
+ deleted_field=self.deleted_field,
176
+ )
177
+
178
+ def delete_objects(
179
+ self, filters=None, sorting=None, pagination_rules=None, limit=None, parent_id=None
180
+ ):
181
+ """Delete multiple resource objects.
182
+
183
+ Override to post-process objects after their deletion from storage.
184
+
185
+ :param filters: Optionally filter the objects by their attribute.
186
+ Each filter in this list is a tuple of a field, a value and a
187
+ comparison (see `kinto.core.utils.COMPARISON`). All filters
188
+ are combined using *AND*.
189
+ :type filters: list of :class:`kinto.core.storage.Filter`
190
+
191
+ :param sorting: Optionnally sort the objects by attribute.
192
+ Each sort instruction in this list refers to a field and a
193
+ direction (negative means descending). All sort instructions are
194
+ cumulative.
195
+ :type sorting: list of :class:`kinto.core.storage.Sort`
196
+
197
+ :param pagination_rules: Optionnally paginate the deletion of objects.
198
+ This list of rules aims to reduce the set of objects to the current
199
+ page. A rule is a list of filters (see `filters` parameter),
200
+ and all rules are combined using *OR*.
201
+ :type pagination_rules: list of list of
202
+ :class:`kinto.core.storage.Filter`
203
+
204
+ :param int limit: Optionnally limit the number of objects to be
205
+ deleted.
206
+
207
+ :param str parent_id: optional filter for parent id
208
+
209
+ :returns: The list of deleted objects from storage.
210
+ """
211
+ parent_id = parent_id or self.parent_id
212
+ deleted = self.storage.delete_all(
213
+ resource_name=self.resource_name,
214
+ parent_id=parent_id,
215
+ filters=filters,
216
+ sorting=sorting,
217
+ pagination_rules=pagination_rules,
218
+ limit=limit,
219
+ id_field=self.id_field,
220
+ modified_field=self.modified_field,
221
+ deleted_field=self.deleted_field,
222
+ )
223
+ # Take a huge shortcut in case we want to delete everything.
224
+ if not filters:
225
+ perm_ids = [self.get_permission_object_id(object_id="*")]
226
+ else:
227
+ perm_ids = [self.get_permission_object_id(object_id=r[self.id_field]) for r in deleted]
228
+ self.permission.delete_object_permissions(*perm_ids)
229
+ return deleted
230
+
231
+ def get_object(self, object_id, parent_id=None):
232
+ """Fetch current view related object, and raise 404 if missing.
233
+
234
+ :param str object_id: object identifier
235
+ :param str parent_id: optional filter for parent id
236
+
237
+ :returns: the object from storage
238
+ :rtype: dict
239
+ """
240
+ parent_id = parent_id or self.parent_id
241
+ obj = self.storage.get(
242
+ resource_name=self.resource_name,
243
+ parent_id=parent_id,
244
+ object_id=object_id,
245
+ id_field=self.id_field,
246
+ modified_field=self.modified_field,
247
+ )
248
+ perm_object_id = self.get_permission_object_id(object_id)
249
+ return self._annotate(obj, perm_object_id)
250
+
251
+ def create_object(self, obj, parent_id=None):
252
+ """Create an object in the resource.
253
+
254
+ The current principal is added to the owner (``write`` permission).
255
+
256
+ Override to perform actions or post-process objects after their
257
+ creation in storage.
258
+
259
+ .. code-block:: python
260
+
261
+ def create_object(self, obj):
262
+ obj = super().create_object(obj)
263
+ idx = index.store(obj)
264
+ object['index'] = idx
265
+ return object
266
+
267
+ :param dict obj: object to store
268
+ :param str parent_id: optional filter for parent id
269
+
270
+ :returns: the newly created object.
271
+ :rtype: dict
272
+ """
273
+ parent_id = parent_id or self.parent_id
274
+
275
+ permissions = obj.pop(self.permissions_field, {})
276
+
277
+ created = self.storage.create(
278
+ resource_name=self.resource_name,
279
+ parent_id=parent_id,
280
+ obj=obj,
281
+ id_generator=self.id_generator,
282
+ id_field=self.id_field,
283
+ modified_field=self.modified_field,
284
+ )
285
+
286
+ object_id = created[self.id_field]
287
+ perm_object_id = self.get_permission_object_id(object_id)
288
+ self.permission.replace_object_permissions(perm_object_id, permissions)
289
+ self._allow_write(perm_object_id)
290
+
291
+ return self._annotate(created, perm_object_id)
292
+
293
+ def update_object(self, obj, parent_id=None):
294
+ """Update object and the specified permissions.
295
+
296
+ If no permissions is specified, the current permissions are not
297
+ modified.
298
+
299
+ The current principal is added to the owner (``write`` permission).
300
+
301
+ Override to perform actions or post-process objects after their
302
+ modification in storage.
303
+
304
+ .. code-block:: python
305
+
306
+ def update_object(self, obj, parent_id=None):
307
+ obj = super().update_object(obj, parent_id)
308
+ subject = f'Object {record[self.id_field]} was changed'
309
+ send_email(subject)
310
+ return object
311
+
312
+ :param dict obj: object to store
313
+ :param str parent_id: optional filter for parent id
314
+ :returns: the updated object.
315
+ :rtype: dict
316
+ """
317
+ parent_id = parent_id or self.parent_id
318
+ object_id = obj[self.id_field]
319
+ permissions = obj.pop(self.permissions_field, {})
320
+
321
+ updated = self.storage.update(
322
+ resource_name=self.resource_name,
323
+ parent_id=parent_id,
324
+ object_id=object_id,
325
+ obj=obj,
326
+ id_field=self.id_field,
327
+ modified_field=self.modified_field,
328
+ )
329
+
330
+ perm_object_id = self.get_permission_object_id(object_id)
331
+ self.permission.replace_object_permissions(perm_object_id, permissions)
332
+ self._allow_write(perm_object_id)
333
+
334
+ return self._annotate(updated, perm_object_id)
335
+
336
+ def delete_object(self, obj, parent_id=None, last_modified=None):
337
+ """Delete an object and its associated permissions.
338
+
339
+ Override to perform actions or post-process objects after deletion
340
+ from storage for example:
341
+
342
+ .. code-block:: python
343
+
344
+ def delete_object(self, obj):
345
+ deleted = super().delete_object(obj)
346
+ erase_media(obj)
347
+ deleted['media'] = 0
348
+ return deleted
349
+
350
+ :param dict obj: the object to delete
351
+ :param str parent_id: optional filter for parent id
352
+ :returns: the deleted object.
353
+ :rtype: dict
354
+ """
355
+ parent_id = parent_id or self.parent_id
356
+ object_id = obj[self.id_field]
357
+ perm_object_id = self.get_permission_object_id(object_id)
358
+
359
+ self.permission.delete_object_permissions(perm_object_id)
360
+
361
+ return self.storage.delete(
362
+ resource_name=self.resource_name,
363
+ parent_id=parent_id,
364
+ object_id=object_id,
365
+ id_field=self.id_field,
366
+ modified_field=self.modified_field,
367
+ deleted_field=self.deleted_field,
368
+ last_modified=last_modified,
369
+ )
370
+
371
+ @property
372
+ def collection_id(self):
373
+ message = "`collection_id` is deprecated, use `resource_name` instead."
374
+ warnings.warn(message, DeprecationWarning)
375
+ return self.resource_name
376
+
377
+ def get_records(self, *args, **kwargs):
378
+ message = "`get_records()` is deprecated, use `get_objects()` instead."
379
+ warnings.warn(message, DeprecationWarning)
380
+ return self.get_objects(*args, **kwargs)
381
+
382
+ def delete_records(self, *args, **kwargs):
383
+ message = "`delete_records()` is deprecated, use `delete_objects()` instead."
384
+ warnings.warn(message, DeprecationWarning)
385
+ return self.delete_objects(*args, **kwargs)
386
+
387
+ def get_record(self, record_id, parent_id=None):
388
+ message = "`get_record()` is deprecated, use `get_object()` instead."
389
+ warnings.warn(message, DeprecationWarning)
390
+ return self.get_object(object_id=record_id, parent_id=parent_id)
391
+
392
+ def create_record(self, record, parent_id=None):
393
+ message = "`create_record()` is deprecated, use `create_object()` instead."
394
+ warnings.warn(message, DeprecationWarning)
395
+ return self.create_object(obj=record, parent_id=parent_id)
396
+
397
+ def update_record(self, record, parent_id=None):
398
+ message = "`update_record()` is deprecated, use `update_object()` instead."
399
+ warnings.warn(message, DeprecationWarning)
400
+ return self.update_object(obj=record, parent_id=parent_id)
401
+
402
+ def delete_record(self, record, parent_id=None, last_modified=None):
403
+ message = "`delete_record()` is deprecated, use `delete_object()` instead."
404
+ warnings.warn(message, DeprecationWarning)
405
+ return self.delete_object(obj=record, parent_id=parent_id, last_modified=last_modified)
406
+
407
+
408
+ class ShareableModel(Model):
409
+ def __init__(self, *args, **kwargs):
410
+ message = "`ShareableModel` is deprecated, use `Model` instead."
411
+ warnings.warn(message, DeprecationWarning)
412
+ super().__init__(*args, **kwargs)