kinto 18.1.0__py3-none-any.whl → 20.4.0__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 kinto might be problematic. Click here for more details.
- kinto/__init__.py +1 -0
- kinto/__main__.py +1 -19
- kinto/config/kinto.tpl +5 -15
- kinto/contribute.json +27 -0
- kinto/core/__init__.py +21 -8
- kinto/core/cornice/__init__.py +93 -0
- kinto/core/cornice/cors.py +144 -0
- kinto/core/cornice/errors.py +40 -0
- kinto/core/cornice/pyramidhook.py +373 -0
- kinto/core/cornice/renderer.py +89 -0
- kinto/core/cornice/resource.py +205 -0
- kinto/core/cornice/service.py +641 -0
- kinto/core/cornice/util.py +138 -0
- kinto/core/cornice/validators/__init__.py +94 -0
- kinto/core/cornice/validators/_colander.py +142 -0
- kinto/core/cornice/validators/_marshmallow.py +182 -0
- kinto/core/cornice_swagger/__init__.py +92 -0
- kinto/core/cornice_swagger/converters/__init__.py +21 -0
- kinto/core/cornice_swagger/converters/exceptions.py +6 -0
- kinto/core/cornice_swagger/converters/parameters.py +90 -0
- kinto/core/cornice_swagger/converters/schema.py +249 -0
- kinto/core/cornice_swagger/swagger.py +725 -0
- kinto/core/cornice_swagger/templates/index.html +73 -0
- kinto/core/cornice_swagger/templates/index_script_template.html +21 -0
- kinto/core/cornice_swagger/util.py +42 -0
- kinto/core/cornice_swagger/views.py +78 -0
- kinto/core/errors.py +6 -4
- kinto/core/initialization.py +129 -59
- kinto/core/metrics.py +93 -0
- kinto/core/openapi.py +2 -3
- kinto/core/permission/memory.py +3 -2
- kinto/core/permission/postgresql/__init__.py +9 -9
- kinto/core/permission/testing.py +6 -0
- kinto/core/resource/__init__.py +9 -4
- kinto/core/resource/schema.py +1 -2
- kinto/core/resource/viewset.py +1 -1
- kinto/core/statsd.py +1 -63
- kinto/core/storage/__init__.py +15 -0
- kinto/core/storage/memory.py +20 -3
- kinto/core/storage/postgresql/__init__.py +31 -1
- kinto/core/storage/postgresql/client.py +2 -2
- kinto/core/storage/postgresql/migrations/migration_022_023.sql +5 -0
- kinto/core/storage/postgresql/pool.py +1 -1
- kinto/core/storage/postgresql/schema.sql +3 -2
- kinto/core/storage/testing.py +41 -1
- kinto/core/testing.py +6 -2
- kinto/core/utils.py +14 -4
- kinto/core/views/batch.py +1 -1
- kinto/core/views/errors.py +4 -3
- kinto/core/views/openapi.py +1 -1
- kinto/plugins/accounts/__init__.py +3 -21
- kinto/plugins/accounts/authentication.py +8 -54
- kinto/plugins/accounts/utils.py +0 -133
- kinto/plugins/accounts/{views/__init__.py → views.py} +7 -62
- kinto/plugins/admin/VERSION +1 -1
- kinto/plugins/admin/build/VERSION +1 -0
- kinto/plugins/admin/build/assets/asn1-EdZsLKOL.js +1 -0
- kinto/plugins/admin/build/assets/clojure-BMjYHr_A.js +1 -0
- kinto/plugins/admin/build/assets/css-BnMrqG3P.js +1 -0
- kinto/plugins/admin/build/assets/index-Cs7JVwIg.css +6 -0
- kinto/plugins/admin/build/assets/index-CylsivYB.js +165 -0
- kinto/plugins/admin/build/assets/javascript-qCveANmP.js +1 -0
- kinto/plugins/admin/build/assets/logo-VBRiKSPX.png +0 -0
- kinto/plugins/admin/build/assets/mllike-CXdrOF99.js +1 -0
- kinto/plugins/admin/build/assets/python-BuPzkPfP.js +1 -0
- kinto/plugins/admin/build/assets/rpm-CTu-6PCP.js +1 -0
- kinto/plugins/admin/build/assets/sql-D0XecflT.js +1 -0
- kinto/plugins/admin/build/assets/ttcn-cfg-B9xdYoR4.js +1 -0
- kinto/plugins/admin/build/index.html +18 -0
- kinto/plugins/default_bucket/__init__.py +1 -2
- kinto/plugins/flush.py +2 -2
- kinto/plugins/history/__init__.py +15 -6
- kinto/plugins/history/listener.py +68 -5
- kinto/plugins/openid/views.py +1 -1
- kinto/plugins/prometheus.py +203 -0
- kinto/plugins/statsd.py +78 -0
- kinto/views/contribute.py +14 -13
- {kinto-18.1.0.dist-info → kinto-20.4.0.dist-info}/METADATA +31 -32
- kinto-20.4.0.dist-info/RECORD +149 -0
- {kinto-18.1.0.dist-info → kinto-20.4.0.dist-info}/WHEEL +1 -1
- kinto/plugins/accounts/mails.py +0 -96
- kinto/plugins/accounts/views/validation.py +0 -136
- kinto/plugins/quotas/__init__.py +0 -22
- kinto/plugins/quotas/listener.py +0 -226
- kinto/plugins/quotas/scripts.py +0 -80
- kinto/plugins/quotas/utils.py +0 -7
- kinto/scripts.py +0 -41
- kinto-18.1.0.dist-info/RECORD +0 -116
- {kinto-18.1.0.dist-info → kinto-20.4.0.dist-info}/entry_points.txt +0 -0
- {kinto-18.1.0.dist-info → kinto-20.4.0.dist-info/licenses}/LICENSE +0 -0
- {kinto-18.1.0.dist-info → kinto-20.4.0.dist-info}/top_level.txt +0 -0
kinto/plugins/statsd.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from urllib.parse import urlparse
|
|
3
|
+
|
|
4
|
+
from pyramid.exceptions import ConfigurationError
|
|
5
|
+
from zope.interface import implementer
|
|
6
|
+
|
|
7
|
+
from kinto.core import metrics
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
import statsd as statsd_module
|
|
12
|
+
except ImportError: # pragma: no cover
|
|
13
|
+
statsd_module = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def sanitize(value):
|
|
17
|
+
"""
|
|
18
|
+
Telegraf does not support ':' in values.
|
|
19
|
+
See https://github.com/influxdata/telegraf/issues/4495
|
|
20
|
+
"""
|
|
21
|
+
return value.replace(":", "") if isinstance(value, str) else value
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@implementer(metrics.IMetricsService)
|
|
25
|
+
class StatsDService:
|
|
26
|
+
def __init__(self, host, port, prefix):
|
|
27
|
+
self._client = statsd_module.StatsClient(host, port, prefix=prefix)
|
|
28
|
+
|
|
29
|
+
def timer(self, key):
|
|
30
|
+
return self._client.timer(key)
|
|
31
|
+
|
|
32
|
+
def observe(self, key, value, labels=[]):
|
|
33
|
+
return self._client.gauge(key, sanitize(value))
|
|
34
|
+
|
|
35
|
+
def count(self, key, count=1, unique=None):
|
|
36
|
+
if unique is None:
|
|
37
|
+
return self._client.incr(key, count=count)
|
|
38
|
+
if isinstance(unique, list):
|
|
39
|
+
# [("method", "get")] -> "method.get"
|
|
40
|
+
# [("endpoint", "/"), ("method", "get")] -> "endpoint./.method.get"
|
|
41
|
+
unique = ".".join(f"{label[0]}.{sanitize(label[1])}" for label in unique)
|
|
42
|
+
else:
|
|
43
|
+
warnings.warn(
|
|
44
|
+
"`unique` parameter should be of type ``list[tuple[str, str]]``",
|
|
45
|
+
DeprecationWarning,
|
|
46
|
+
)
|
|
47
|
+
return self._client.set(key, unique)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def load_from_config(config):
|
|
51
|
+
# If this is called, it means that a ``statsd_url`` was specified in settings.
|
|
52
|
+
# (see ``kinto.core.initialization``)
|
|
53
|
+
# Raise a proper error if the ``statsd`` module is not installed.
|
|
54
|
+
if statsd_module is None:
|
|
55
|
+
error_msg = "Please install Kinto with monitoring dependencies (e.g. statsd package)"
|
|
56
|
+
raise ConfigurationError(error_msg)
|
|
57
|
+
|
|
58
|
+
settings = config.get_settings()
|
|
59
|
+
uri = settings["statsd_url"]
|
|
60
|
+
uri = urlparse(uri)
|
|
61
|
+
|
|
62
|
+
if settings["project_name"] != "":
|
|
63
|
+
prefix = settings["project_name"]
|
|
64
|
+
else:
|
|
65
|
+
prefix = settings["statsd_prefix"]
|
|
66
|
+
|
|
67
|
+
return StatsDService(uri.hostname, uri.port, prefix)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def includeme(config):
|
|
71
|
+
settings = config.get_settings()
|
|
72
|
+
|
|
73
|
+
# TODO: this backend abstraction may not be required anymore.
|
|
74
|
+
statsd_mod = settings["statsd_backend"]
|
|
75
|
+
statsd_mod = config.maybe_dotted(statsd_mod)
|
|
76
|
+
client = statsd_mod.load_from_config(config)
|
|
77
|
+
|
|
78
|
+
config.registry.registerUtility(client, metrics.IMetricsService)
|
kinto/views/contribute.py
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
1
4
|
import colander
|
|
2
|
-
from cornice import Service
|
|
3
5
|
from pyramid.security import NO_PERMISSION_REQUIRED
|
|
4
6
|
|
|
7
|
+
from kinto.core import Service
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
HERE = os.path.dirname(__file__)
|
|
11
|
+
ORIGIN = os.path.dirname(HERE) # package root.
|
|
12
|
+
_CONTRIBUTE_INFO = None
|
|
5
13
|
|
|
6
14
|
contribute = Service(
|
|
7
15
|
name="contribute.json", description="Open-source information", path="/contribute.json"
|
|
@@ -24,15 +32,8 @@ contribute_responses = {
|
|
|
24
32
|
response_schemas=contribute_responses,
|
|
25
33
|
)
|
|
26
34
|
def contribute_get(request):
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"docs": "https://kinto.readthedocs.io/",
|
|
33
|
-
"mailing-list": "kinto@mozilla.org",
|
|
34
|
-
"irc": "irc://irc.freenode.net/#kinto",
|
|
35
|
-
},
|
|
36
|
-
"keywords": ["JSON", "Python", "Offline", "Sync", "Storage"],
|
|
37
|
-
"urls": {"dev": "https://demo.kinto-storage.org/v1/"},
|
|
38
|
-
}
|
|
35
|
+
global _CONTRIBUTE_INFO
|
|
36
|
+
if _CONTRIBUTE_INFO is None:
|
|
37
|
+
with open(os.path.join(ORIGIN, "contribute.json")) as f:
|
|
38
|
+
_CONTRIBUTE_INFO = json.load(f)
|
|
39
|
+
return _CONTRIBUTE_INFO
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: kinto
|
|
3
|
-
Version:
|
|
3
|
+
Version: 20.4.0
|
|
4
4
|
Summary: Kinto Web Service - Store, Sync, Share, and Self-Host.
|
|
5
5
|
Author-email: Mozilla Services <developers@kinto-storage.org>
|
|
6
6
|
License: Copyright 2012 - Mozilla Foundation
|
|
@@ -21,10 +21,10 @@ Project-URL: Repository, https://github.com/Kinto/kinto
|
|
|
21
21
|
Keywords: web,sync,json,storage,services
|
|
22
22
|
Classifier: Programming Language :: Python
|
|
23
23
|
Classifier: Programming Language :: Python :: 3
|
|
24
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
25
24
|
Classifier: Programming Language :: Python :: 3.9
|
|
26
25
|
Classifier: Programming Language :: Python :: 3.10
|
|
27
26
|
Classifier: Programming Language :: Python :: 3.11
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
28
28
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
29
29
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
30
30
|
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
|
|
@@ -33,45 +33,44 @@ Description-Content-Type: text/x-rst
|
|
|
33
33
|
License-File: LICENSE
|
|
34
34
|
Requires-Dist: bcrypt
|
|
35
35
|
Requires-Dist: colander
|
|
36
|
-
Requires-Dist: cornice
|
|
37
|
-
Requires-Dist: cornice-swagger
|
|
38
36
|
Requires-Dist: dockerflow
|
|
39
37
|
Requires-Dist: jsonschema
|
|
40
38
|
Requires-Dist: jsonpatch
|
|
41
39
|
Requires-Dist: logging-color-formatter
|
|
42
40
|
Requires-Dist: python-dateutil
|
|
43
41
|
Requires-Dist: pyramid
|
|
44
|
-
Requires-Dist:
|
|
45
|
-
Requires-Dist: pyramid-multiauth
|
|
42
|
+
Requires-Dist: pyramid_multiauth
|
|
46
43
|
Requires-Dist: transaction
|
|
47
|
-
Requires-Dist:
|
|
44
|
+
Requires-Dist: pyramid_tm
|
|
48
45
|
Requires-Dist: requests
|
|
49
46
|
Requires-Dist: waitress
|
|
50
47
|
Requires-Dist: python-rapidjson
|
|
51
|
-
Provides-Extra:
|
|
52
|
-
Requires-Dist:
|
|
53
|
-
Requires-Dist: ruff ; extra == 'dev'
|
|
54
|
-
Requires-Dist: twine ; extra == 'dev'
|
|
48
|
+
Provides-Extra: redis
|
|
49
|
+
Requires-Dist: kinto_redis; extra == "redis"
|
|
55
50
|
Provides-Extra: memcached
|
|
56
|
-
Requires-Dist: python-memcached
|
|
57
|
-
Provides-Extra: monitoring
|
|
58
|
-
Requires-Dist: newrelic ; extra == 'monitoring'
|
|
59
|
-
Requires-Dist: sentry-sdk[sqlalchemy] ; extra == 'monitoring'
|
|
60
|
-
Requires-Dist: statsd ; extra == 'monitoring'
|
|
61
|
-
Requires-Dist: werkzeug ; extra == 'monitoring'
|
|
51
|
+
Requires-Dist: python-memcached; extra == "memcached"
|
|
62
52
|
Provides-Extra: postgresql
|
|
63
|
-
Requires-Dist: SQLAlchemy
|
|
64
|
-
Requires-Dist: psycopg2
|
|
65
|
-
Requires-Dist: zope.sqlalchemy
|
|
66
|
-
Provides-Extra:
|
|
67
|
-
Requires-Dist:
|
|
53
|
+
Requires-Dist: SQLAlchemy<3; extra == "postgresql"
|
|
54
|
+
Requires-Dist: psycopg2-binary; extra == "postgresql"
|
|
55
|
+
Requires-Dist: zope.sqlalchemy; extra == "postgresql"
|
|
56
|
+
Provides-Extra: monitoring
|
|
57
|
+
Requires-Dist: newrelic; extra == "monitoring"
|
|
58
|
+
Requires-Dist: sentry-sdk[sqlalchemy]; extra == "monitoring"
|
|
59
|
+
Requires-Dist: statsd; extra == "monitoring"
|
|
60
|
+
Requires-Dist: werkzeug; extra == "monitoring"
|
|
61
|
+
Requires-Dist: prometheus-client; extra == "monitoring"
|
|
68
62
|
Provides-Extra: test
|
|
69
|
-
Requires-Dist: bravado
|
|
70
|
-
Requires-Dist: pytest
|
|
71
|
-
Requires-Dist: pytest-cache
|
|
72
|
-
Requires-Dist: pytest-cov
|
|
73
|
-
Requires-Dist: playwright
|
|
74
|
-
Requires-Dist: webtest
|
|
63
|
+
Requires-Dist: bravado; extra == "test"
|
|
64
|
+
Requires-Dist: pytest; extra == "test"
|
|
65
|
+
Requires-Dist: pytest-cache; extra == "test"
|
|
66
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
67
|
+
Requires-Dist: playwright; extra == "test"
|
|
68
|
+
Requires-Dist: webtest; extra == "test"
|
|
69
|
+
Provides-Extra: dev
|
|
70
|
+
Requires-Dist: build; extra == "dev"
|
|
71
|
+
Requires-Dist: ruff; extra == "dev"
|
|
72
|
+
Requires-Dist: twine; extra == "dev"
|
|
73
|
+
Dynamic: license-file
|
|
75
74
|
|
|
76
75
|
Kinto
|
|
77
76
|
=====
|
|
@@ -79,7 +78,7 @@ Kinto
|
|
|
79
78
|
|coc| |gitter| |readthedocs| |pypi| |ci| |main-coverage|
|
|
80
79
|
|
|
81
80
|
.. |coc| image:: https://img.shields.io/badge/%E2%9D%A4-code%20of%20conduct-blue.svg
|
|
82
|
-
:target: https://github.com/Kinto/kinto/blob/main/CODE_OF_CONDUCT.md
|
|
81
|
+
:target: https://github.com/Kinto/kinto/blob/main/.github/CODE_OF_CONDUCT.md
|
|
83
82
|
:alt: Code of conduct
|
|
84
83
|
|
|
85
84
|
.. |gitter| image:: https://badges.gitter.im/Kinto/kinto.svg
|
|
@@ -107,13 +106,12 @@ Kinto is a minimalist JSON storage service with synchronisation and sharing abil
|
|
|
107
106
|
* `Tutorial <https://kinto.readthedocs.io/en/latest/tutorials/first-steps.html>`_
|
|
108
107
|
* `Issue tracker <https://github.com/Kinto/kinto/issues>`_
|
|
109
108
|
* `Contributing <https://kinto.readthedocs.io/en/latest/community.html#how-to-contribute>`_
|
|
110
|
-
* `Try our daily flushed instance at: https://demo.kinto-storage.org/v1/ <https://demo.kinto-storage.org/v1/>`_
|
|
111
109
|
* `Docker Hub <https://hub.docker.com/r/kinto/kinto-server>`_
|
|
112
110
|
|
|
113
111
|
Requirements
|
|
114
112
|
------------
|
|
115
113
|
|
|
116
|
-
* **Python**: 3.
|
|
114
|
+
* **Python**: 3.9+
|
|
117
115
|
* **Backends**: In-memory (development), PostgreSQL 9.5+ (production)
|
|
118
116
|
|
|
119
117
|
Contributors
|
|
@@ -135,6 +133,7 @@ Contributors
|
|
|
135
133
|
* Balthazar Rouberol <br@imap.cc>
|
|
136
134
|
* Boris Feld <lothiraldan@gmail.com>
|
|
137
135
|
* Brady Dufresne <dufresnebrady@gmail.com>
|
|
136
|
+
* Can Berk Güder <cbguder@mozilla.com>
|
|
138
137
|
* Castro
|
|
139
138
|
* Chirag B. Jadwani <chirag.jadwani@gmail.com>
|
|
140
139
|
* Christophe Gragnic <cgragnic@protonmail.com>
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
kinto/__init__.py,sha256=XG7cOyHN0ipQeOSPMW-XFax7uFgAjnCd3Slq0jSFGC4,3299
|
|
2
|
+
kinto/__main__.py,sha256=0vBSUT2pAMg78HyRpfGbk3R6Z_fpg12pcGi3pi1XJ1c,7181
|
|
3
|
+
kinto/authorization.py,sha256=i3ttdPTFGzE9CqUQmfC4rR_6dDZJu0jWJMLGl_jFzIE,4919
|
|
4
|
+
kinto/contribute.json,sha256=HT9QVB8rA8jWIREQoqWfMibfJXMAzbRsixW8F6O6cQY,792
|
|
5
|
+
kinto/events.py,sha256=NMPvKUdbi25aYHhu9svzQsrEZMa9nyO4mtuMZC5871Q,85
|
|
6
|
+
kinto/schema_validation.py,sha256=mtAmnl5HwiUsjS2gU8MKH4lkZ1380A5wZht-w9s5X7M,5306
|
|
7
|
+
kinto/config/__init__.py,sha256=av8W0utmjheueFqrjTYEDk_vbpm3XYdHcqv5lppNR4k,2131
|
|
8
|
+
kinto/config/kinto.tpl,sha256=Pm9p_oRsBlVoEXPVA2X6Wvv49jMOVv-27jw4rahVlwE,8201
|
|
9
|
+
kinto/core/__init__.py,sha256=s7PshdeKmpiqI5sW-zdC7p3Ig-e60w4kiUwlKi-impY,8655
|
|
10
|
+
kinto/core/authentication.py,sha256=HLA0kREC3GMEsrIsHsQYjVNztYfAF01kb8-pLboByFs,1527
|
|
11
|
+
kinto/core/authorization.py,sha256=GywY25KEzuSSAI709dFHDfdLnKxy3SLEYGwW5FkQ7Qc,13212
|
|
12
|
+
kinto/core/decorators.py,sha256=3SAPWXlyPNUSICZ9mz04bcN-UdbnDuFOtU0bQHHzLis,2178
|
|
13
|
+
kinto/core/errors.py,sha256=JXZjkPYjjC0I6x02d2VJRGeaQ2yZYS2zm5o7_ljfyes,8946
|
|
14
|
+
kinto/core/events.py,sha256=SYpXgKMtVjiD9fwYJA2Omdom9yA3nBqi9btdvU1I_nc,10345
|
|
15
|
+
kinto/core/initialization.py,sha256=ZjmCKc8MYZXv63W2mv--fY8rXSLAnJa7RtCYdfK4jsg,26225
|
|
16
|
+
kinto/core/metrics.py,sha256=Y6Mt4PUzy2-oudeGr_oCmtX8nIR4SZkzUlPxr58jr-g,2619
|
|
17
|
+
kinto/core/openapi.py,sha256=92sZviff4NCxN0jMnu5lPUnF5iQbrKMGy7Cegf-VAME,3876
|
|
18
|
+
kinto/core/schema.py,sha256=d5L5TQynRYJPkZ8Mu2X7F72xEh6SKDbrHK1CNTdOf2E,3646
|
|
19
|
+
kinto/core/scripts.py,sha256=5HSq5QAuin7HuU6icNYkPisny-4JpcdBvjf8X4JImrE,978
|
|
20
|
+
kinto/core/statsd.py,sha256=2f4s2opiHVdrA02ZlBa5pxIHaEjPuG8tdVLsmdII27s,64
|
|
21
|
+
kinto/core/testing.py,sha256=kZ-75EiiZwTNDBpHZyKBBHute6jEmUwXd7nRMK9kwr4,5908
|
|
22
|
+
kinto/core/utils.py,sha256=EDlZfHsgcaUvxg-AG_dn9IcQCq7j7RxpBjnFrx8b11E,17069
|
|
23
|
+
kinto/core/cache/__init__.py,sha256=NJT_39WFTuUd-OHuVqgoQTQUYv5zS9PIc3W_Kq9tabc,2726
|
|
24
|
+
kinto/core/cache/memcached.py,sha256=WuYyq6-QykRNryLA_bKdeGAY_Hvwq0c1ejS_8G94cY4,2914
|
|
25
|
+
kinto/core/cache/memory.py,sha256=603vuyV5nKxsmUlkVxZFZWKPAbxMSTQKqkpqK4ttFas,2748
|
|
26
|
+
kinto/core/cache/testing.py,sha256=KVNz1tVYv_A33HF66SObM1WTgOx1UY47MuwPsaaQRag,6980
|
|
27
|
+
kinto/core/cache/postgresql/__init__.py,sha256=04OetGaxI89XAHUhtrNtRyipsZTe0bn_ZjoUQms_3VA,6026
|
|
28
|
+
kinto/core/cache/postgresql/schema.sql,sha256=a-6lbhqzlNMcig7DCGQ_ULP-Z5nzhNWrZWCpaHTiJPw,503
|
|
29
|
+
kinto/core/cornice/__init__.py,sha256=P07QaR_5qIXuFxAXciJZYlUlQSH5bYD2LNsv5v9E_tY,3685
|
|
30
|
+
kinto/core/cornice/cors.py,sha256=nA61VsAamFovkpk5aYVoSWASLnXWVl6XJdMw17IDIKA,5159
|
|
31
|
+
kinto/core/cornice/errors.py,sha256=_8Jxhm7ic2obRSMkEKqRtJEK2tg9Fp75DhJ0kJ5OxLI,1433
|
|
32
|
+
kinto/core/cornice/pyramidhook.py,sha256=iy5I8nFTg29aIjPKrwmak5_hy_GjGK1nLwPkmvB7mYM,13936
|
|
33
|
+
kinto/core/cornice/renderer.py,sha256=Rk1BNrPnpFxIZVE1jdQmgqcpsOVf37378Ge1Fm4gidc,3341
|
|
34
|
+
kinto/core/cornice/resource.py,sha256=jpjZdvOfJNe9XMDvetBhVIcoJsQot5D6K3gcrH2DQGE,6181
|
|
35
|
+
kinto/core/cornice/service.py,sha256=3qZteBmR9aVjL9ZQDylnWCZeac51IE9iBtUVnFqv3so,23261
|
|
36
|
+
kinto/core/cornice/util.py,sha256=N6KbypHKkz5YmCARilY_xatGUePwreH3ThhiafrgCh8,4106
|
|
37
|
+
kinto/core/cornice/validators/__init__.py,sha256=tJAewtgSYL2Fpye0pQ-jsbA3vLJ3A6d3hhm9yXUO2Yc,3325
|
|
38
|
+
kinto/core/cornice/validators/_colander.py,sha256=qlh1jR3xEOkRvMgS-F-CxtyKohzJFPjaaOYPi5Lb2Ns,4752
|
|
39
|
+
kinto/core/cornice/validators/_marshmallow.py,sha256=auiqi9chYk2H1y47Xd0UDi5FMO-umis20pNqOTx9-oU,6278
|
|
40
|
+
kinto/core/cornice_swagger/__init__.py,sha256=ls4uB23VcamRxoBo2IDVA4cadBlzbp5x99jbTY_pmK4,2815
|
|
41
|
+
kinto/core/cornice_swagger/swagger.py,sha256=a4QProdgZ7XUDFNUWsC0zLwmroxwtWbALm0Jjd00stQ,26001
|
|
42
|
+
kinto/core/cornice_swagger/util.py,sha256=xNKQ9kY8gkIJdVoWIDqEzrK0v8o-vfdAxxKvbXMeTwE,1210
|
|
43
|
+
kinto/core/cornice_swagger/views.py,sha256=h3Ehwidak0CeCr3oTy5Eh4_rLTDEAYm2Ubxb_opqaUc,2572
|
|
44
|
+
kinto/core/cornice_swagger/converters/__init__.py,sha256=DaSaL-e2TKtqrhWk91dZolPOk_e-oPbzgctjZNXjnj0,640
|
|
45
|
+
kinto/core/cornice_swagger/converters/exceptions.py,sha256=YDtm7yDay_PRxCZWOKgdWZc549JTMCi_n8Z5-PtKvCA,94
|
|
46
|
+
kinto/core/cornice_swagger/converters/parameters.py,sha256=VWx3NzKqaC12U2BrflYCuLJHt0W3_UJqcXiTNfeQ414,2757
|
|
47
|
+
kinto/core/cornice_swagger/converters/schema.py,sha256=Ga9qJMso90U0a43JHFyQ1NVKjnAGOYd0jRWmCgFqbCA,6922
|
|
48
|
+
kinto/core/cornice_swagger/templates/index.html,sha256=rgDT8vx6Pu4amI2vym2BC0utGPbDM8kJ2KCQWJwtgBY,2957
|
|
49
|
+
kinto/core/cornice_swagger/templates/index_script_template.html,sha256=vq92R0oZE5kSJ0c0NuvUq_RCSC1_325ht_cu7aCrD2s,518
|
|
50
|
+
kinto/core/listeners/__init__.py,sha256=mBBo0LxNOjL8h8IqRweG1sY_G142FAakhimzKcgQBDQ,203
|
|
51
|
+
kinto/core/permission/__init__.py,sha256=RoI8UJYl3X8ZmuUfVGC8QH1g4EGNrRknUao97D3jKRE,7331
|
|
52
|
+
kinto/core/permission/memory.py,sha256=ymageLrGfgYxa0j8erOvVq2WPDBgtTo75R0wcL3Wx3Y,6171
|
|
53
|
+
kinto/core/permission/testing.py,sha256=o94YzVhrokh9xHO7s9hxkeoxIjKP_HSRFNj1K2dGaVU,22348
|
|
54
|
+
kinto/core/permission/postgresql/__init__.py,sha256=LRKo4yhrfn9tRm3cLaAVK4ALAn-8Gxb0hI2-QoUevBg,18251
|
|
55
|
+
kinto/core/permission/postgresql/schema.sql,sha256=BlKJNC-omDVF9REaWCTsfKgXupFrmCBX8ZvN4sqTWUU,1344
|
|
56
|
+
kinto/core/permission/postgresql/migrations/migration_001_002.sql,sha256=ey5rDVQfStVStWpyTJn2fmQP5WSA34HhO99PapcgH1k,681
|
|
57
|
+
kinto/core/resource/__init__.py,sha256=B-1X3nPzIZOiN8Dc_tSersAP-Wn4jXf3GcrctN2Ck1k,50746
|
|
58
|
+
kinto/core/resource/model.py,sha256=xjZ6shnhelXCdWvgw6yeOWXodxiKMm9iyDqLTk0i8Bs,15626
|
|
59
|
+
kinto/core/resource/schema.py,sha256=EhPKDMlBjx60hXztMvywfo4IrRfwaZ3V-7sY_sl-BYk,16126
|
|
60
|
+
kinto/core/resource/viewset.py,sha256=Wo7mQwmI08IGnSetaqGF66fCqYPB1pDUdZa3U92NIic,7613
|
|
61
|
+
kinto/core/storage/__init__.py,sha256=Bo9q5PCDQ7KkBuBAHt7UoZFr5WfVWwEbFJjGsuq4Oo4,13704
|
|
62
|
+
kinto/core/storage/exceptions.py,sha256=o10f7LohwyCHOTlR-dOdnB4us_MdCGOJUxZO8HZ3Akc,1304
|
|
63
|
+
kinto/core/storage/generators.py,sha256=rxWN9hOfOsB-PLeryhPGO-aE670sivr3LFRIExImpxc,1829
|
|
64
|
+
kinto/core/storage/memory.py,sha256=DR6gpqSYh4oGPBX9x4-dGLNITZi33T0VODsNWsPtgho,19875
|
|
65
|
+
kinto/core/storage/testing.py,sha256=4hGR6xc54M6H81IQb8XP7NP_iBP-X8m8PqKqixDs5nU,78411
|
|
66
|
+
kinto/core/storage/utils.py,sha256=BHpohIKVOCtURjRbUT7O5AEhIKfSEFv-pfgRzq8Q5zs,1082
|
|
67
|
+
kinto/core/storage/postgresql/__init__.py,sha256=HMlUfTBsnsUQkLEhuhItU-9fgSOf9wTH6J09-1HW1fA,40157
|
|
68
|
+
kinto/core/storage/postgresql/client.py,sha256=JTRxHK-8ipTXgs0E4PyiFiun-32yuzqFGsWTi-OuFfA,4270
|
|
69
|
+
kinto/core/storage/postgresql/migrator.py,sha256=MQ_5aSrDi9-s2wlyyFyfhYP6HreCXjtlJzBI4b85u1I,3524
|
|
70
|
+
kinto/core/storage/postgresql/pool.py,sha256=lOtclVagFqzzWbVxrGoWeKylpHlKdFgGz3Ef6cgGNJU,2219
|
|
71
|
+
kinto/core/storage/postgresql/schema.sql,sha256=qRmx8NSwqedwozOi-Nn-pnipubxUWLCcYTRDMkt2B80,4216
|
|
72
|
+
kinto/core/storage/postgresql/migrations/migration_001_002.sql,sha256=GVJIs8MGmZEyp1i0KjsmGKv1pLlBRckn0EWX6Kl6uQE,428
|
|
73
|
+
kinto/core/storage/postgresql/migrations/migration_002_003.sql,sha256=zlSZpG_2L-wd8KXh3szmbYtoGjAOOwy2gH7RFMUd61w,1203
|
|
74
|
+
kinto/core/storage/postgresql/migrations/migration_003_004.sql,sha256=OZSbH6Yt1PA2zba8iQWIguaTsnn3v7bFF-rbg2_teXY,530
|
|
75
|
+
kinto/core/storage/postgresql/migrations/migration_004_005.sql,sha256=3VzFzj5y7quywYN-j6OE8xwYvB84O33YeeTF7QYXFOA,603
|
|
76
|
+
kinto/core/storage/postgresql/migrations/migration_005_006.sql,sha256=NE1fdI1grEqnXZOiO714vME-TQo2UKVuxeUvplEKCUg,354
|
|
77
|
+
kinto/core/storage/postgresql/migrations/migration_006_007.sql,sha256=anpEkjSCJ6uXaDr_krei1ZY_1TIbxBW9iF5JsPDT4sw,2352
|
|
78
|
+
kinto/core/storage/postgresql/migrations/migration_007_008.sql,sha256=7SQpJRjD-44tuBYbXL0mGg3ugUhh7tlRpQiv98JeY-k,2011
|
|
79
|
+
kinto/core/storage/postgresql/migrations/migration_008_009.sql,sha256=UnMmGLf3mYNmfYMfStzWS4oeHWRTCEpqvMD9a60aHTg,1224
|
|
80
|
+
kinto/core/storage/postgresql/migrations/migration_009_010.sql,sha256=Wzczz3J2sjPUfcG7iP2nEuASU9Qrx97IYHiCfrTvYeA,2843
|
|
81
|
+
kinto/core/storage/postgresql/migrations/migration_010_011.sql,sha256=zQS3GMgZNJEmHtaW1uH8hVP5IVQ9lU9Gpk6tzfYb_cs,484
|
|
82
|
+
kinto/core/storage/postgresql/migrations/migration_011_012.sql,sha256=YcpZcO68d4wPF3b5e-PWljV3F9LACe1o2uEKmDOnxHo,304
|
|
83
|
+
kinto/core/storage/postgresql/migrations/migration_012_013.sql,sha256=MOnGjfQVIucs3A3eOBRZ0mdgS9NY-KZDdQ8Eu2FjPdI,2389
|
|
84
|
+
kinto/core/storage/postgresql/migrations/migration_013_014.sql,sha256=cyDg2EpAwvbfaOXJbuxiJz_ofwl2pN6lix8Yrd3pbys,482
|
|
85
|
+
kinto/core/storage/postgresql/migrations/migration_014_015.sql,sha256=U2LtXV-oo8aozeeUIm2D62ujPHj29KuQ0JSYbJ3t1Iw,2992
|
|
86
|
+
kinto/core/storage/postgresql/migrations/migration_015_016.sql,sha256=gacFTc1zpmbkkbSCqpn12lySeMyYT-4_g4L6bSqHOFw,176
|
|
87
|
+
kinto/core/storage/postgresql/migrations/migration_016_017.sql,sha256=B0QFDuvcp8hKXY5xjOVy58vl0OO9LLnZdJQxBuyrLus,2476
|
|
88
|
+
kinto/core/storage/postgresql/migrations/migration_017_018.sql,sha256=n_BGQ-btSoTjmznHd0yypxoGcSJ7wWkORrLqlhUuVPI,993
|
|
89
|
+
kinto/core/storage/postgresql/migrations/migration_018_019.sql,sha256=XK6ex2jwQQLXgxjhy5bXF4H2Zt9nV_K4dehmvePd30k,346
|
|
90
|
+
kinto/core/storage/postgresql/migrations/migration_019_020.sql,sha256=yDQDdzU65cgctKIeo1YqMrFi7aU2VGdBhVUpVQAQOgM,306
|
|
91
|
+
kinto/core/storage/postgresql/migrations/migration_020_021.sql,sha256=cEgfGNDLH3RyLswxy9YZazZtOvidxNsi57z7SGR8VsQ,2369
|
|
92
|
+
kinto/core/storage/postgresql/migrations/migration_021_022.sql,sha256=MUIAfgbBDQLy8JfklEs6ekK93nr1buVRtmBAHaaMXug,1993
|
|
93
|
+
kinto/core/storage/postgresql/migrations/migration_022_023.sql,sha256=c1Fw10sxtaDqYJpxk1P9eZCtXP3uSmBY7-3IjZZLwjU,231
|
|
94
|
+
kinto/core/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
95
|
+
kinto/core/views/batch.py,sha256=sWNn67YqfTbiqwpbwbm1QyumcVGi8aNhlT5AtLToElI,5657
|
|
96
|
+
kinto/core/views/errors.py,sha256=2uTy85UBQL1EDIMotzFBhVl14RmWwb3rupbsB0mycbs,6099
|
|
97
|
+
kinto/core/views/heartbeat.py,sha256=qidZ7fTvuPoJMo7miDnclAm_WsbgqubzsARrv9aCo5U,3336
|
|
98
|
+
kinto/core/views/hello.py,sha256=tTjJ2PHKPnmLL41cwF6e0AzPhm4WmojIc0VWHcZNOgI,1961
|
|
99
|
+
kinto/core/views/openapi.py,sha256=PgxplQX1D0zqzlvRxBvd5SzrNMJmsaLfDta_fh-Pr-A,958
|
|
100
|
+
kinto/core/views/version.py,sha256=-m5G_o0oHTpCgrtfFrHFve6Zqw_gs_szT0Bd8jnNmD4,1419
|
|
101
|
+
kinto/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
102
|
+
kinto/plugins/flush.py,sha256=poiBOLGXjml0xXHjqDMRdbXJSd6N3SL0mfeGK2vxeHY,812
|
|
103
|
+
kinto/plugins/prometheus.py,sha256=oGpm1H4-CTVK4kd_GWDyn4nKBCSVq1fypdBoewDMRPk,6209
|
|
104
|
+
kinto/plugins/statsd.py,sha256=-VasJZM1xkhTfFa6_0GgWwfPqKnYS2722bSMDLzZ3pI,2469
|
|
105
|
+
kinto/plugins/accounts/__init__.py,sha256=2DeIaXJmMqRca3xVHeJ6xBWmeXAfrCdyg3EvK5jzIak,3670
|
|
106
|
+
kinto/plugins/accounts/authentication.py,sha256=pCb269FquKGFd6DH8AVTjFnBFlfxcDEYVyxhQp5Y08o,2117
|
|
107
|
+
kinto/plugins/accounts/scripts.py,sha256=_LNkSpFprOMGHFKkRmmOqK31uoQW28yttPQztmfUt5Q,2001
|
|
108
|
+
kinto/plugins/accounts/utils.py,sha256=xGtWwBPKVEwkbJbtJ_SUFgTJpwQzreoJG9XY86HPj7M,358
|
|
109
|
+
kinto/plugins/accounts/views.py,sha256=NO2nZCS1v0dN390Hxhe55Bsi4IM-NH9jEStkiKH2AEU,5221
|
|
110
|
+
kinto/plugins/admin/README.md,sha256=3a9inoO2IHH5aST3xZp_km3ddupHZqadWrQjOQifBRk,105
|
|
111
|
+
kinto/plugins/admin/VERSION,sha256=Tpnn6sIcK3GpcTnKzKaV2YyT-9fdJlBfBPUnGAmsS5Q,6
|
|
112
|
+
kinto/plugins/admin/__init__.py,sha256=057R3q_S4CFiUuqwMIFkyu4prMBnUVc1eo8OUAPeJBs,1327
|
|
113
|
+
kinto/plugins/admin/views.py,sha256=NHQncNB-32ytP03o-ZqisbYEoK7L2QcaK7RBuh0akwg,1338
|
|
114
|
+
kinto/plugins/admin/build/VERSION,sha256=Tpnn6sIcK3GpcTnKzKaV2YyT-9fdJlBfBPUnGAmsS5Q,6
|
|
115
|
+
kinto/plugins/admin/build/index.html,sha256=cfQ_QjlmMyviojnRWQFxC6J5nWbyo8WIFvWtmcyzbeo,467
|
|
116
|
+
kinto/plugins/admin/build/assets/asn1-EdZsLKOL.js,sha256=rgO6M_APbSRME0yY3rddue8niU7UJmG2uWz4l1YeG6s,3981
|
|
117
|
+
kinto/plugins/admin/build/assets/clojure-BMjYHr_A.js,sha256=SYpgEG0C5dkSQgMtAejALIQFzA3S0InWn1XquOeNGiA,10815
|
|
118
|
+
kinto/plugins/admin/build/assets/css-BnMrqG3P.js,sha256=qj5HvX1-byua7Xs0K31qoFn_bncMhtZMsOr5e0A-yYo,27132
|
|
119
|
+
kinto/plugins/admin/build/assets/index-Cs7JVwIg.css,sha256=dtEppIrcuaKwSBl-bfgIKrBnbrr7qFL7PST9yLyPfc0,171774
|
|
120
|
+
kinto/plugins/admin/build/assets/index-CylsivYB.js,sha256=4GW6MPa0FgDsBjUF2bjYB-8jjU5hjUXykaQMxjChFsM,2754443
|
|
121
|
+
kinto/plugins/admin/build/assets/javascript-qCveANmP.js,sha256=ol336oG7yGQxC9YIvojoE-dqx7wd3lLp0Ikn2rV4F5g,17080
|
|
122
|
+
kinto/plugins/admin/build/assets/logo-VBRiKSPX.png,sha256=4LXIgVZbcdbMun8bTlCFgnBik7uIkIRILVPFYrTUGgg,5578
|
|
123
|
+
kinto/plugins/admin/build/assets/mllike-CXdrOF99.js,sha256=C_YMaIP-ED2BN1nxtpuqRq-LXcC1AqrkksJHg4pdh4Q,4788
|
|
124
|
+
kinto/plugins/admin/build/assets/python-BuPzkPfP.js,sha256=rDHPcNHr9ezekY0ihOc2YV-rU0QsKzwjC_qD-F-AbXg,6475
|
|
125
|
+
kinto/plugins/admin/build/assets/rpm-CTu-6PCP.js,sha256=YPjyUyP0eZbB5aKZ-H9C3kK9bBOlhHM8T-PXHsSLplo,1622
|
|
126
|
+
kinto/plugins/admin/build/assets/sql-D0XecflT.js,sha256=3hecsZJ0WlDxeFA_1lrl_ySI80tNQh3oWWGhIHkwoSU,37052
|
|
127
|
+
kinto/plugins/admin/build/assets/ttcn-cfg-B9xdYoR4.js,sha256=jTZ_XHKOChJZEt-FzJbGHhvSYW42F1NccHg0lOY2FlM,4050
|
|
128
|
+
kinto/plugins/admin/public/help.html,sha256=1hol7z5Sv0Xn3mYyEfPQWFOsrR24htlKhmnGA3rH8fs,958
|
|
129
|
+
kinto/plugins/default_bucket/__init__.py,sha256=7TmBzFgW0gmYsetXr6Kqt9317XZ3PiB9gyCr-IBfmGg,7276
|
|
130
|
+
kinto/plugins/history/__init__.py,sha256=ZuGoj9giDEefv2BNuaakgGEV87e85wvrkNgsmVAotIU,1443
|
|
131
|
+
kinto/plugins/history/listener.py,sha256=ABPRduTnkwH6oMzRyrQlF3AZoVt7brqwKVpA8ynY0Sw,7962
|
|
132
|
+
kinto/plugins/history/views.py,sha256=NoBP-S7epeH5TLZZbIqfBmwMA2KaWmxP7lqPAS11BTU,2293
|
|
133
|
+
kinto/plugins/openid/__init__.py,sha256=1Iv5SCa6vwEvoJkmGd45-TYm_mxz2okFj6u2VTNuVrk,4863
|
|
134
|
+
kinto/plugins/openid/utils.py,sha256=n3KGS-ogXR2sg6j4QtdPe_DtEsqD7AGVT2K7vhl8yE8,273
|
|
135
|
+
kinto/plugins/openid/views.py,sha256=RRLBH6uipqafPSyQG5bi8nQOGGO6kT4fGLW4H3blU3E,6519
|
|
136
|
+
kinto/views/__init__.py,sha256=mItMqadROvEieXtxm0AoDReH3PwxOlM4rzECPCQfK_s,1187
|
|
137
|
+
kinto/views/admin.py,sha256=m4JKApzUUQNmmbHOfoc2n0CK01OrNiho21nYW_f5zlo,7439
|
|
138
|
+
kinto/views/buckets.py,sha256=3dc5cURZEP4vPKfk3f9W3BDbloG3QZ2lefhIoo-BiSQ,1868
|
|
139
|
+
kinto/views/collections.py,sha256=KrqJuje88er1VS2mtspMnXU6eYeZQTqUw0zB1ova9Bo,2206
|
|
140
|
+
kinto/views/contribute.py,sha256=PJoIMLj9_IszSjgZkaCd_TUjekDgNqjpmVTmRN9ztaA,983
|
|
141
|
+
kinto/views/groups.py,sha256=jOq5fX0-4lwZE8k1q5HME2tU7x9052rtBPF7YqcJ-Qg,3181
|
|
142
|
+
kinto/views/permissions.py,sha256=F0_eKx201WyLonXJ5vLdGKa9RcFKjvAihrEEhU1JuLw,9069
|
|
143
|
+
kinto/views/records.py,sha256=lYfACW2L8qcQoyYBD5IX-fTPjFWmGp7GjHq_U4InlyE,5037
|
|
144
|
+
kinto-20.4.0.dist-info/licenses/LICENSE,sha256=oNEIMTuTJzppR5ZEyi86yvvtSagveMYXTYFn56zF0Uk,561
|
|
145
|
+
kinto-20.4.0.dist-info/METADATA,sha256=FJkC9Vuz90F7WOrCHXR68mhO8z59xIu5bkLBCe1Os2k,8731
|
|
146
|
+
kinto-20.4.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
147
|
+
kinto-20.4.0.dist-info/entry_points.txt,sha256=3KlqBWPKY81mrCe_oX0I5s1cRO7Q53nCLbnVr5P9LH4,85
|
|
148
|
+
kinto-20.4.0.dist-info/top_level.txt,sha256=EG_YmbZL6FAug9VwopG7JtF9SvH_r0DEnFp-3twPPys,6
|
|
149
|
+
kinto-20.4.0.dist-info/RECORD,,
|
kinto/plugins/accounts/mails.py
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import string
|
|
2
|
-
|
|
3
|
-
from pyramid_mailer import get_mailer
|
|
4
|
-
from pyramid_mailer.message import Message
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
DEFAULT_EMAIL_SENDER = "admin@example.com"
|
|
8
|
-
DEFAULT_SUBJECT_TEMPLATE = "activate your account"
|
|
9
|
-
DEFAULT_BODY_TEMPLATE = "{activation-key}"
|
|
10
|
-
DEFAULT_CONFIRMATION_SUBJECT_TEMPLATE = "Account active"
|
|
11
|
-
DEFAULT_CONFIRMATION_BODY_TEMPLATE = "The account {id} is now active"
|
|
12
|
-
DEFAULT_RESET_SUBJECT_TEMPLATE = "Reset password"
|
|
13
|
-
DEFAULT_RESET_BODY_TEMPLATE = "{reset-password}"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class EmailFormatter(string.Formatter):
|
|
17
|
-
"""Formatter class that will not fail if there's a missing key."""
|
|
18
|
-
|
|
19
|
-
def __init__(self, default="{{{0}}}"):
|
|
20
|
-
self.default = default
|
|
21
|
-
|
|
22
|
-
def get_value(self, key, args, kwargs):
|
|
23
|
-
return kwargs.get(key, self.default.format(key))
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class Emailer:
|
|
27
|
-
def __init__(self, request, user):
|
|
28
|
-
self.request = request
|
|
29
|
-
self.settings = request.registry.settings
|
|
30
|
-
self.user = user
|
|
31
|
-
self.user_email = user["id"]
|
|
32
|
-
self.email_sender = self.settings.get(
|
|
33
|
-
"account_validation.email_sender", DEFAULT_EMAIL_SENDER
|
|
34
|
-
)
|
|
35
|
-
self.mailer = get_mailer(request)
|
|
36
|
-
|
|
37
|
-
def send_mail(self, subject_template, body_template, extra_data=None):
|
|
38
|
-
formatter = EmailFormatter()
|
|
39
|
-
if extra_data is None:
|
|
40
|
-
extra_data = {}
|
|
41
|
-
user_email_context = self.user.get("email-context", {})
|
|
42
|
-
# We might have some previous email context.
|
|
43
|
-
try:
|
|
44
|
-
data = self.request.json.get("data", {})
|
|
45
|
-
email_context = data.get("email-context", user_email_context)
|
|
46
|
-
except ValueError:
|
|
47
|
-
email_context = user_email_context
|
|
48
|
-
|
|
49
|
-
formatted_subject = formatter.format(
|
|
50
|
-
subject_template, **self.user, **extra_data, **email_context
|
|
51
|
-
)
|
|
52
|
-
formatted_body = formatter.format(
|
|
53
|
-
body_template, **self.user, **extra_data, **email_context
|
|
54
|
-
)
|
|
55
|
-
message = Message(
|
|
56
|
-
subject=formatted_subject,
|
|
57
|
-
sender=self.email_sender,
|
|
58
|
-
recipients=[self.user_email],
|
|
59
|
-
body=formatted_body,
|
|
60
|
-
)
|
|
61
|
-
self.mailer.send(message)
|
|
62
|
-
|
|
63
|
-
def send_activation(self, activation_key):
|
|
64
|
-
extra_data = {"activation-key": activation_key}
|
|
65
|
-
|
|
66
|
-
subject_template = self.settings.get(
|
|
67
|
-
"account_validation.email_subject_template", DEFAULT_SUBJECT_TEMPLATE
|
|
68
|
-
)
|
|
69
|
-
body_template = self.settings.get(
|
|
70
|
-
"account_validation.email_body_template", DEFAULT_BODY_TEMPLATE
|
|
71
|
-
)
|
|
72
|
-
self.send_mail(subject_template, body_template, extra_data)
|
|
73
|
-
|
|
74
|
-
def send_confirmation(self):
|
|
75
|
-
subject_template = self.settings.get(
|
|
76
|
-
"account_validation.email_confirmation_subject_template",
|
|
77
|
-
DEFAULT_CONFIRMATION_SUBJECT_TEMPLATE,
|
|
78
|
-
)
|
|
79
|
-
body_template = self.settings.get(
|
|
80
|
-
"account_validation.email_confirmation_body_template",
|
|
81
|
-
DEFAULT_CONFIRMATION_BODY_TEMPLATE,
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
self.send_mail(subject_template, body_template)
|
|
85
|
-
|
|
86
|
-
def send_temporary_reset_password(self, reset_password):
|
|
87
|
-
extra_data = {"reset-password": reset_password}
|
|
88
|
-
subject_template = self.settings.get(
|
|
89
|
-
"account_validation.email_reset_password_subject_template",
|
|
90
|
-
DEFAULT_RESET_SUBJECT_TEMPLATE,
|
|
91
|
-
)
|
|
92
|
-
body_template = self.settings.get(
|
|
93
|
-
"account_validation.email_reset_password_body_template", DEFAULT_RESET_BODY_TEMPLATE
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
self.send_mail(subject_template, body_template, extra_data)
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import uuid
|
|
3
|
-
|
|
4
|
-
from pyramid import httpexceptions
|
|
5
|
-
from pyramid.events import subscriber
|
|
6
|
-
|
|
7
|
-
from kinto.core import Service
|
|
8
|
-
from kinto.core.errors import http_error, raise_invalid
|
|
9
|
-
from kinto.core.events import ACTIONS, ResourceChanged
|
|
10
|
-
from kinto.core.storage import exceptions as storage_exceptions
|
|
11
|
-
|
|
12
|
-
from ..mails import Emailer
|
|
13
|
-
from ..utils import (
|
|
14
|
-
cache_reset_password,
|
|
15
|
-
delete_cached_validation_key,
|
|
16
|
-
get_cached_validation_key,
|
|
17
|
-
hash_password,
|
|
18
|
-
)
|
|
19
|
-
from . import DEFAULT_EMAIL_REGEXP
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
# Account validation (enable in the settings).
|
|
23
|
-
validation = Service(
|
|
24
|
-
name="account-validation",
|
|
25
|
-
path="/accounts/{user_id}/validate/{activation_key}",
|
|
26
|
-
description="Validate an account",
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def check_validation_key(activation_key, username, registry):
|
|
31
|
-
"""Given a username, compare the activation-key provided with the one from the cache."""
|
|
32
|
-
cache_result = get_cached_validation_key(username, registry)
|
|
33
|
-
|
|
34
|
-
if cache_result == activation_key:
|
|
35
|
-
delete_cached_validation_key(username, registry) # We're done with the activation key.
|
|
36
|
-
return True
|
|
37
|
-
return False
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@validation.post()
|
|
41
|
-
def post_validation(request):
|
|
42
|
-
user_id = request.matchdict["user_id"]
|
|
43
|
-
activation_key = request.matchdict["activation_key"]
|
|
44
|
-
|
|
45
|
-
parent_id = user_id
|
|
46
|
-
try:
|
|
47
|
-
user = request.registry.storage.get(
|
|
48
|
-
parent_id=parent_id, resource_name="account", object_id=user_id
|
|
49
|
-
)
|
|
50
|
-
except storage_exceptions.ObjectNotFoundError:
|
|
51
|
-
# Don't give information on the existence of a user id: return a generic error message.
|
|
52
|
-
error_details = {"message": "Account ID and activation key do not match"}
|
|
53
|
-
raise http_error(httpexceptions.HTTPForbidden(), **error_details)
|
|
54
|
-
|
|
55
|
-
if not check_validation_key(activation_key, user_id, request.registry):
|
|
56
|
-
error_details = {"message": "Account ID and activation key do not match"}
|
|
57
|
-
raise http_error(httpexceptions.HTTPForbidden(), **error_details)
|
|
58
|
-
|
|
59
|
-
# User is now validated.
|
|
60
|
-
new = user.copy()
|
|
61
|
-
new["validated"] = True
|
|
62
|
-
|
|
63
|
-
result = request.registry.storage.update(
|
|
64
|
-
parent_id=parent_id, resource_name="account", object_id=user_id, obj=new
|
|
65
|
-
)
|
|
66
|
-
request.notify_resource_event(
|
|
67
|
-
parent_id=parent_id,
|
|
68
|
-
timestamp=result["last_modified"],
|
|
69
|
-
data=result,
|
|
70
|
-
action=ACTIONS.UPDATE,
|
|
71
|
-
old=user,
|
|
72
|
-
resource_name="account",
|
|
73
|
-
)
|
|
74
|
-
return new
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# Password reset.
|
|
78
|
-
reset_password = Service(
|
|
79
|
-
name="reset-password",
|
|
80
|
-
path="/accounts/{user_id}/reset-password",
|
|
81
|
-
description="Send a temporary reset password by mail for an account",
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
@reset_password.post()
|
|
86
|
-
def post_reset_password(request):
|
|
87
|
-
user_id = request.matchdict["user_id"]
|
|
88
|
-
|
|
89
|
-
parent_id = user_id
|
|
90
|
-
try:
|
|
91
|
-
user = request.registry.storage.get(
|
|
92
|
-
parent_id=parent_id, resource_name="account", object_id=user_id
|
|
93
|
-
)
|
|
94
|
-
except storage_exceptions.ObjectNotFoundError:
|
|
95
|
-
# Don't give information on the existence of a user id: return a generic message.
|
|
96
|
-
return {"message": "A temporary reset password has been sent by mail"}
|
|
97
|
-
|
|
98
|
-
settings = request.registry.settings
|
|
99
|
-
|
|
100
|
-
user_email = user["id"]
|
|
101
|
-
email_regexp = settings.get("account_validation.email_regexp", DEFAULT_EMAIL_REGEXP)
|
|
102
|
-
compiled_email_regexp = re.compile(email_regexp)
|
|
103
|
-
if not compiled_email_regexp.match(user_email):
|
|
104
|
-
error_details = {
|
|
105
|
-
"name": "data.id",
|
|
106
|
-
"description": f"The user id should match {email_regexp}.",
|
|
107
|
-
}
|
|
108
|
-
raise_invalid(request, **error_details)
|
|
109
|
-
|
|
110
|
-
reset_password = str(uuid.uuid4())
|
|
111
|
-
hashed_reset_password = hash_password(reset_password)
|
|
112
|
-
cache_reset_password(hashed_reset_password, user_id, request.registry)
|
|
113
|
-
|
|
114
|
-
# Send a temporary reset password by mail.
|
|
115
|
-
Emailer(request, user).send_temporary_reset_password(reset_password)
|
|
116
|
-
|
|
117
|
-
return {"message": "A temporary reset password has been sent by mail"}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
# Send confirmation email on account activation if account validation is enabled.
|
|
121
|
-
@subscriber(ResourceChanged, for_resources=("account",), for_actions=(ACTIONS.UPDATE,))
|
|
122
|
-
def on_account_activated(event):
|
|
123
|
-
request = event.request
|
|
124
|
-
settings = request.registry.settings
|
|
125
|
-
if not settings.get("account_validation", False):
|
|
126
|
-
return
|
|
127
|
-
|
|
128
|
-
for impacted_object in event.impacted_objects:
|
|
129
|
-
old_account = impacted_object["old"]
|
|
130
|
-
account = impacted_object["new"]
|
|
131
|
-
if old_account.get("validated", True) or not account.get("validated", False):
|
|
132
|
-
# It's not an account activation, bail.
|
|
133
|
-
continue
|
|
134
|
-
|
|
135
|
-
# Send a confirmation email.
|
|
136
|
-
Emailer(request, account).send_confirmation()
|
kinto/plugins/quotas/__init__.py
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
from kinto.core.events import ResourceChanged
|
|
2
|
-
|
|
3
|
-
from .listener import on_resource_changed
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def includeme(config):
|
|
7
|
-
config.add_api_capability(
|
|
8
|
-
"quotas",
|
|
9
|
-
description="Quotas Management on buckets " "and collections.",
|
|
10
|
-
url="https://kinto.readthedocs.io",
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
# If StatsD is enabled, monitor execution time of listener.
|
|
14
|
-
listener = on_resource_changed
|
|
15
|
-
if config.registry.statsd:
|
|
16
|
-
key = "plugins.quotas"
|
|
17
|
-
listener = config.registry.statsd.timer(key)(on_resource_changed)
|
|
18
|
-
|
|
19
|
-
# Listen to every resources (except history)
|
|
20
|
-
config.add_subscriber(
|
|
21
|
-
listener, ResourceChanged, for_resources=("bucket", "group", "collection", "record")
|
|
22
|
-
)
|