slthcore 0.1.9__tar.gz → 0.2.3__tar.gz
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 slthcore might be problematic. Click here for more details.
- {slthcore-0.1.9/slthcore.egg-info → slthcore-0.2.3}/PKG-INFO +1 -1
- {slthcore-0.1.9 → slthcore-0.2.3}/setup.py +1 -1
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/__init__.py +59 -8
- slthcore-0.2.3/slth/apps.py +41 -0
- slthcore-0.2.3/slth/cmd/init/__pycache__/__main__.cpython-312.pyc +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/application.yml +9 -4
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/docker-compose.yml +1 -1
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/components.py +2 -2
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/db/models.py +27 -1
- slthcore-0.1.9/slth/endpoints.py → slthcore-0.2.3/slth/endpoints/__init__.py +127 -424
- slthcore-0.2.3/slth/endpoints/auth.py +64 -0
- slthcore-0.2.3/slth/endpoints/deletion.py +21 -0
- slthcore-0.2.3/slth/endpoints/dev.py +18 -0
- slthcore-0.2.3/slth/endpoints/email.py +34 -0
- slthcore-0.2.3/slth/endpoints/job.py +22 -0
- slthcore-0.2.3/slth/endpoints/log.py +7 -0
- slthcore-0.2.3/slth/endpoints/pushsubscription.py +48 -0
- slthcore-0.2.3/slth/endpoints/report.py +16 -0
- slthcore-0.2.3/slth/endpoints/role.py +6 -0
- slthcore-0.2.3/slth/endpoints/task.py +12 -0
- slthcore-0.2.3/slth/endpoints/user.py +59 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/forms.py +5 -3
- slthcore-0.2.3/slth/management/commands/worker.py +19 -0
- slthcore-0.2.3/slth/middleware/timezone.py +25 -0
- slthcore-0.2.3/slth/migrations/0008_alter_deletion_datetime_alter_log_datetime.py +24 -0
- slthcore-0.2.3/slth/migrations/0009_remove_email_from_email_email_action_email_attempt_and_more.py +43 -0
- slthcore-0.2.3/slth/migrations/0010_email_key_alter_email_action_alter_email_attempt_and_more.py +103 -0
- slthcore-0.2.3/slth/migrations/__init__.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/models.py +247 -58
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/pdf/__init__.py +8 -5
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/queryset.py +30 -23
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/selenium/__init__.py +2 -2
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/serializer.py +9 -6
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/static/js/slth.min.js +18 -18
- slthcore-0.2.3/slth/tasks.py +59 -0
- slthcore-0.2.3/slth/templates/email.html +155 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/urls.py +6 -3
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/views.py +8 -3
- {slthcore-0.1.9 → slthcore-0.2.3/slthcore.egg-info}/PKG-INFO +1 -1
- {slthcore-0.1.9 → slthcore-0.2.3}/slthcore.egg-info/SOURCES.txt +22 -3
- slthcore-0.1.9/slth/middleware.py +0 -24
- slthcore-0.1.9/slth/tasks.py +0 -70
- {slthcore-0.1.9 → slthcore-0.2.3}/MANIFEST.in +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/setup.cfg +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/configure/__main__.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/__main__.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/.DS_Store +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/.gitignore +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/api/__init__.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/api/asgi.py +0 -0
- /slthcore-0.1.9/slth/cmd/init/boilerplate/backend/api/endpoints.py → /slthcore-0.2.3/slth/cmd/init/boilerplate/backend/api/endpoints/__init__.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/api/models.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/api/settings.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/api/tests.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/api/urls.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/api/wsgi.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/entrypoint.sh +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/manage.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/backend/requirements.txt +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/base.env +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/frontend/package.json +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/frontend/src/main.jsx +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/frontend/vite.config.js +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/local.env +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/run.sh +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/selenium/run.sh +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/cmd/init/boilerplate/test.sh +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/db/__init__.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/db/generic.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/exceptions.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/factory.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/management/__init__.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/management/commands/__init__.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/management/commands/integration_test.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/management/commands/sync.py +0 -0
- {slthcore-0.1.9/slth/migrations → slthcore-0.2.3/slth/middleware}/__init__.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/migrations/0001_initial.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/migrations/0002_email_role_pushsubscription_error.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/migrations/0003_rename_photo_profile_alter_profile_options.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/migrations/0004_alter_profile_photo.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/migrations/0005_alter_profile_photo.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/migrations/0006_user.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/migrations/0007_deletion_log.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/notifications.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/oauth.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/pdf/tests.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/permissions.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/printer.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/roles.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/selenium/browser.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/static/.DS_Store +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/static/css/.DS_Store +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/static/css/slth.css +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/static/js/index.min.js +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/static/js/react.min.js +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/statistics.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/templates/index.html +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/templates/report.html +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/templates/service-worker.js +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/templates/signature.html +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/tests.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/threadlocal.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slth/utils.py +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slthcore.egg-info/dependency_links.txt +0 -0
- {slthcore-0.1.9 → slthcore-0.2.3}/slthcore.egg-info/top_level.txt +0 -0
|
@@ -5,7 +5,6 @@ import json
|
|
|
5
5
|
import warnings
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from datetime import datetime, date
|
|
8
|
-
from django.apps import apps
|
|
9
8
|
from django.db import models
|
|
10
9
|
from .queryset import QuerySet
|
|
11
10
|
from django.db.models import manager
|
|
@@ -14,10 +13,13 @@ from django.db.models.deletion import Collector
|
|
|
14
13
|
from .factory import FormFactory
|
|
15
14
|
import django.db.models.options as options
|
|
16
15
|
from django.db.models.base import ModelBase
|
|
16
|
+
from django.db.models import Model
|
|
17
17
|
from django.core.exceptions import FieldDoesNotExist
|
|
18
18
|
from django.utils.autoreload import autoreload_started
|
|
19
19
|
from django.core import serializers
|
|
20
|
+
from django.utils import autoreload
|
|
20
21
|
from .threadlocal import tl
|
|
22
|
+
from django.apps import apps as django_apps
|
|
21
23
|
|
|
22
24
|
from decimal import Decimal
|
|
23
25
|
|
|
@@ -26,6 +28,7 @@ warnings.filterwarnings('ignore', module='urllib3')
|
|
|
26
28
|
FILENAME = 'application.yml'
|
|
27
29
|
ENDPOINTS = {}
|
|
28
30
|
PROXIED_MODELS = []
|
|
31
|
+
THREADS = []
|
|
29
32
|
APPLICATON = None
|
|
30
33
|
|
|
31
34
|
if APPLICATON is None and os.path.exists(FILENAME):
|
|
@@ -39,12 +42,47 @@ if APPLICATON is None and os.path.exists(FILENAME):
|
|
|
39
42
|
class JSONEncoder(json.JSONEncoder):
|
|
40
43
|
def default(self, obj):
|
|
41
44
|
if isinstance(obj, Decimal):
|
|
42
|
-
return float(obj)
|
|
43
|
-
|
|
44
|
-
return obj.
|
|
45
|
+
return dict(type='decimal', value=float(obj))
|
|
46
|
+
elif isinstance(obj, datetime):
|
|
47
|
+
return dict(type='datetime', value=obj.isoformat())
|
|
48
|
+
elif isinstance(obj, date):
|
|
49
|
+
return dict(type='date', value=obj.isoformat())
|
|
50
|
+
elif isinstance(obj, QuerySet):
|
|
51
|
+
return dict(type='queryset', value=obj.dump())
|
|
52
|
+
elif isinstance(obj, Model):
|
|
53
|
+
return dict(type='object', model=obj._meta.label.lower(), pk=obj.pk)
|
|
45
54
|
return json.JSONEncoder.default(self, obj)
|
|
46
55
|
|
|
47
56
|
|
|
57
|
+
class JSONDecoder(json.JSONDecoder):
|
|
58
|
+
|
|
59
|
+
def __init__(self, *args, **kwargs):
|
|
60
|
+
super().__init__(object_hook=self.object_hook, *args, **kwargs)
|
|
61
|
+
|
|
62
|
+
def object_hook(self, obj):
|
|
63
|
+
type = obj.get('type')
|
|
64
|
+
if type:
|
|
65
|
+
if type == 'decimal':
|
|
66
|
+
return Decimal(obj['value'])
|
|
67
|
+
elif type == 'datetime':
|
|
68
|
+
return datetime.fromisoformat(obj['value'])
|
|
69
|
+
elif type == 'date':
|
|
70
|
+
return date.fromisoformat(obj['value'])
|
|
71
|
+
elif type == 'queryset':
|
|
72
|
+
return QuerySet.load(obj['value'])
|
|
73
|
+
elif type == 'object':
|
|
74
|
+
return django_apps.get_model(obj['model']).objects.get(pk=obj['pk'])
|
|
75
|
+
return obj
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def dumps(data):
|
|
79
|
+
return json.dumps(data, cls=JSONEncoder)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def loads(data):
|
|
83
|
+
return json.loads(data, cls=JSONDecoder)
|
|
84
|
+
|
|
85
|
+
|
|
48
86
|
class BaseManager(manager.BaseManager):
|
|
49
87
|
def get_queryset(self):
|
|
50
88
|
return super().get_queryset()
|
|
@@ -53,7 +91,7 @@ class BaseManager(manager.BaseManager):
|
|
|
53
91
|
return self.get_queryset().all()
|
|
54
92
|
|
|
55
93
|
def __call__(self, model):
|
|
56
|
-
return
|
|
94
|
+
return django_apps.get_model(model)
|
|
57
95
|
|
|
58
96
|
|
|
59
97
|
class Manager(BaseManager.from_queryset(QuerySet)):
|
|
@@ -90,7 +128,7 @@ class ModelMixin(object):
|
|
|
90
128
|
obj = self
|
|
91
129
|
for attr_name in username_lookup.split('__'):
|
|
92
130
|
obj = getattr(obj, attr_name)
|
|
93
|
-
roles =
|
|
131
|
+
roles = django_apps.get_model('api.role').objects.filter(username=obj)
|
|
94
132
|
setattr(self, '_roles', roles)
|
|
95
133
|
return roles
|
|
96
134
|
|
|
@@ -98,7 +136,7 @@ class ModelMixin(object):
|
|
|
98
136
|
obj = self
|
|
99
137
|
for attr_name in username_lookup.split('__'):
|
|
100
138
|
obj = getattr(obj, attr_name)
|
|
101
|
-
return
|
|
139
|
+
return django_apps.get_model('auth.user').objects.get(username=obj)
|
|
102
140
|
|
|
103
141
|
def serializer(self) -> Serializer:
|
|
104
142
|
return Serializer(self)
|
|
@@ -131,7 +169,7 @@ class ModelMixin(object):
|
|
|
131
169
|
objects.append(instance)
|
|
132
170
|
if instance.__class__.__name__ not in order:
|
|
133
171
|
order.append(instance.__class__.__name__)
|
|
134
|
-
backup =
|
|
172
|
+
backup = dumps(dict(order=order, objects=serializers.serialize("python", objects)))
|
|
135
173
|
instance = '{}.{}:{}'.format(self._meta.app_label, self._meta.model_name, self.pk)
|
|
136
174
|
Deletion.objects.create(username=username, datetime=datetime.now(), instance=instance, backup=backup)
|
|
137
175
|
return self.delete()
|
|
@@ -222,3 +260,16 @@ def meta(verbose_name=None):
|
|
|
222
260
|
function.verbose_name = verbose_name
|
|
223
261
|
return function
|
|
224
262
|
return decorate
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
original_trigger_reload = autoreload.trigger_reload
|
|
266
|
+
|
|
267
|
+
def trigger_reload(filename):
|
|
268
|
+
print('Stoping sloth thread....')
|
|
269
|
+
for thread in THREADS:
|
|
270
|
+
thread.stop()
|
|
271
|
+
thread.join()
|
|
272
|
+
print('Thread stopped!')
|
|
273
|
+
original_trigger_reload(filename)
|
|
274
|
+
|
|
275
|
+
autoreload.trigger_reload = trigger_reload
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.apps import AppConfig
|
|
6
|
+
from django.utils import autoreload
|
|
7
|
+
from django.apps import apps
|
|
8
|
+
import threading
|
|
9
|
+
from . import THREADS
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Thread(threading.Thread):
|
|
15
|
+
def __init__(self):
|
|
16
|
+
super().__init__()
|
|
17
|
+
self._stop_event = threading.Event()
|
|
18
|
+
|
|
19
|
+
def run(self):
|
|
20
|
+
while not self._stop_event.is_set():
|
|
21
|
+
# print('.')
|
|
22
|
+
apps.get_model("slth", "email").objects.send()
|
|
23
|
+
apps.get_model("slth", "pushnotification").objects.execute()
|
|
24
|
+
apps.get_model("slth", "job").objects.execute()
|
|
25
|
+
time.sleep(10)
|
|
26
|
+
|
|
27
|
+
def stop(self):
|
|
28
|
+
print("Stopping e-mail thread...")
|
|
29
|
+
self._stop_event.set()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AppConfig(AppConfig):
|
|
33
|
+
name = 'slth'
|
|
34
|
+
|
|
35
|
+
def ready(self):
|
|
36
|
+
settings.SLOTH = True
|
|
37
|
+
if os.environ.get("RUN_MAIN"):
|
|
38
|
+
print('Starting sloth thread...')
|
|
39
|
+
thread = Thread()
|
|
40
|
+
thread.start()
|
|
41
|
+
THREADS.append(thread)
|
|
Binary file
|
|
@@ -32,9 +32,14 @@ application:
|
|
|
32
32
|
boxes:
|
|
33
33
|
search:
|
|
34
34
|
usermenu:
|
|
35
|
-
- icons
|
|
36
|
-
- users
|
|
37
|
-
-
|
|
35
|
+
- dev.icons
|
|
36
|
+
- user.users
|
|
37
|
+
- log.logs
|
|
38
|
+
- email.emails
|
|
39
|
+
- pushsubscription.pushsubscriptions
|
|
40
|
+
- job.jobs
|
|
41
|
+
- deletion.deletions
|
|
42
|
+
- auth.logout
|
|
38
43
|
adder:
|
|
39
44
|
tools:
|
|
40
45
|
settings:
|
|
@@ -42,7 +47,7 @@ application:
|
|
|
42
47
|
users:Item 1:
|
|
43
48
|
Item 1.1:
|
|
44
49
|
Sair: logout
|
|
45
|
-
Sair: logout
|
|
50
|
+
Sair: auth.logout
|
|
46
51
|
theme:
|
|
47
52
|
colors:
|
|
48
53
|
primary: "#1351b4"
|
|
@@ -210,10 +210,10 @@ class WebConf(dict):
|
|
|
210
210
|
|
|
211
211
|
|
|
212
212
|
class ZoomMeet(dict):
|
|
213
|
-
def __init__(self, token,
|
|
213
|
+
def __init__(self, token, username):
|
|
214
214
|
self["type"] = "zoommeet"
|
|
215
215
|
self["token"] = token
|
|
216
|
-
self["
|
|
216
|
+
self["username"] = username
|
|
217
217
|
|
|
218
218
|
|
|
219
219
|
class Navbar(dict):
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
from uuid import uuid1
|
|
2
|
-
|
|
2
|
+
import pytz
|
|
3
|
+
from datetime import datetime, timedelta
|
|
4
|
+
from django.utils import timezone
|
|
5
|
+
from django.db.models import Model as DjangoModel, fields as DjangoFields
|
|
3
6
|
from django.db.models import *
|
|
4
7
|
from django.utils.translation import gettext_lazy as _
|
|
5
8
|
from . import generic
|
|
6
9
|
from .. import ModelMixin
|
|
10
|
+
from slth import dumps, loads
|
|
7
11
|
|
|
8
12
|
GenericField = generic.GenericField
|
|
9
13
|
|
|
@@ -107,6 +111,28 @@ class TextField(TextField):
|
|
|
107
111
|
self.formatted= kwargs.pop('formatted', False)
|
|
108
112
|
super().__init__(*args, **kwargs)
|
|
109
113
|
|
|
114
|
+
|
|
115
|
+
class DateTimeField(DateTimeField):
|
|
116
|
+
|
|
117
|
+
def get_db_prep_value(self, value, *args, **kwargs):
|
|
118
|
+
return pytz.timezone(timezone.get_current_timezone_name()).localize(value).astimezone(timezone.get_default_timezone()).replace(tzinfo=None) if value else None
|
|
119
|
+
|
|
120
|
+
def from_db_value(self, value, *args, **kwargs):
|
|
121
|
+
return pytz.timezone(timezone.get_default_timezone_name()).localize(value).astimezone(timezone.get_current_timezone()).replace(tzinfo=None) if value else None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class TaskFied(TextField):
|
|
125
|
+
def get_db_prep_value(self, value, *args, **kwargs):
|
|
126
|
+
s = dumps(dict(module=value.__module__, classname=type(value).__name__, args=value.__initializer__[0], kwargs=value.__initializer__[1]))
|
|
127
|
+
return s
|
|
128
|
+
|
|
129
|
+
def from_db_value(self, value, *args, **kwargs):
|
|
130
|
+
data = loads(value)
|
|
131
|
+
module = __import__(data['module'], fromlist=data['module'].split('.'))
|
|
132
|
+
cls = getattr(module, data['classname'])
|
|
133
|
+
return cls(*data['args'], **data['kwargs'])
|
|
134
|
+
|
|
135
|
+
|
|
110
136
|
class FileField(FileField):
|
|
111
137
|
def __init__(self, *args, extensions=('pdf',), max_size=5, **kwargs):
|
|
112
138
|
self.extensions= extensions
|