simo 2.0.21__py3-none-any.whl → 2.0.23__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 simo might be problematic. Click here for more details.
- simo/__pycache__/settings.cpython-38.pyc +0 -0
- simo/core/__pycache__/admin.cpython-38.pyc +0 -0
- simo/core/__pycache__/api.cpython-38.pyc +0 -0
- simo/core/__pycache__/api_meta.cpython-38.pyc +0 -0
- simo/core/__pycache__/forms.cpython-38.pyc +0 -0
- simo/core/__pycache__/models.cpython-38.pyc +0 -0
- simo/core/__pycache__/permissions.cpython-38.pyc +0 -0
- simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/core/admin.py +1 -1
- simo/core/api.py +10 -30
- simo/core/api_meta.py +3 -1
- simo/core/forms.py +2 -3
- simo/core/migrations/0031_auto_20240429_1231.py +28 -0
- simo/core/migrations/__pycache__/0031_auto_20240429_1231.cpython-38.pyc +0 -0
- simo/core/models.py +9 -2
- simo/core/permissions.py +29 -4
- simo/core/serializers.py +21 -12
- simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/models.cpython-38.pyc +0 -0
- simo/fleet/forms.py +3 -9
- simo/fleet/models.py +14 -4
- simo/settings.py +0 -1
- {simo-2.0.21.dist-info → simo-2.0.23.dist-info}/METADATA +1 -1
- {simo-2.0.21.dist-info → simo-2.0.23.dist-info}/RECORD +27 -25
- {simo-2.0.21.dist-info → simo-2.0.23.dist-info}/LICENSE.md +0 -0
- {simo-2.0.21.dist-info → simo-2.0.23.dist-info}/WHEEL +0 -0
- {simo-2.0.21.dist-info → simo-2.0.23.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
simo/core/admin.py
CHANGED
|
@@ -269,7 +269,7 @@ class ComponentAdmin(admin.ModelAdmin):
|
|
|
269
269
|
'alarm_category', 'arm_status'
|
|
270
270
|
)
|
|
271
271
|
|
|
272
|
-
search_fields = 'name',
|
|
272
|
+
search_fields = 'id', 'name', 'value', 'config', 'meta', 'notes'
|
|
273
273
|
list_per_page = 100
|
|
274
274
|
change_list_template = 'admin/component_change_list.html'
|
|
275
275
|
inlines = ComponentPermissionInline,
|
simo/core/api.py
CHANGED
|
@@ -5,7 +5,7 @@ import time
|
|
|
5
5
|
from django.db.models import Q, Prefetch
|
|
6
6
|
from django.utils.translation import gettext_lazy as _
|
|
7
7
|
from django.utils import timezone
|
|
8
|
-
from django.
|
|
8
|
+
from django.http import HttpResponse, Http404
|
|
9
9
|
from simo.core.utils.helpers import get_self_ip, search_queryset
|
|
10
10
|
from rest_framework.pagination import PageNumberPagination
|
|
11
11
|
from rest_framework import viewsets
|
|
@@ -14,7 +14,6 @@ from rest_framework.decorators import action
|
|
|
14
14
|
from rest_framework.response import Response as RESTResponse
|
|
15
15
|
from rest_framework.exceptions import ValidationError as APIValidationError
|
|
16
16
|
from simo.core.utils.config_values import ConfigException
|
|
17
|
-
from simo.users.middleware import introduce as introduce_user
|
|
18
17
|
from .models import (
|
|
19
18
|
Instance, Category, Zone, Component, Icon, ComponentHistory,
|
|
20
19
|
HistoryAggregate, Gateway
|
|
@@ -23,7 +22,9 @@ from .serializers import (
|
|
|
23
22
|
IconSerializer, CategorySerializer, ZoneSerializer,
|
|
24
23
|
ComponentSerializer, ComponentHistorySerializer
|
|
25
24
|
)
|
|
26
|
-
from .permissions import
|
|
25
|
+
from .permissions import (
|
|
26
|
+
IsInstanceSuperuser, InstanceSuperuserCanEdit, ComponentPermission
|
|
27
|
+
)
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
class InstanceMixin:
|
|
@@ -34,10 +35,10 @@ class InstanceMixin:
|
|
|
34
35
|
slug=self.request.resolver_match.kwargs.get('instance_slug')
|
|
35
36
|
)
|
|
36
37
|
except Instance.DoesNotExist:
|
|
37
|
-
|
|
38
|
+
return HttpResponse(
|
|
38
39
|
f"Instance {self.request.resolver_match.kwargs.get('instance_slug')} "
|
|
39
40
|
"is not found on this SIMO.io hub!",
|
|
40
|
-
|
|
41
|
+
status=400
|
|
41
42
|
)
|
|
42
43
|
return super().dispatch(request, *args, **kwargs)
|
|
43
44
|
|
|
@@ -165,6 +166,7 @@ class ComponentViewSet(InstanceMixin, viewsets.ModelViewSet):
|
|
|
165
166
|
|
|
166
167
|
def get_permissions(self):
|
|
167
168
|
permissions = super().get_permissions()
|
|
169
|
+
permissions.append(ComponentPermission())
|
|
168
170
|
permissions.append(InstanceSuperuserCanEdit())
|
|
169
171
|
return permissions
|
|
170
172
|
|
|
@@ -210,7 +212,6 @@ class ComponentViewSet(InstanceMixin, viewsets.ModelViewSet):
|
|
|
210
212
|
@action(detail=True, methods=['post'])
|
|
211
213
|
def subcomponent(self, request, pk=None, *args, **kwargs):
|
|
212
214
|
component = self.get_object()
|
|
213
|
-
self.check_object_permissions(request, component)
|
|
214
215
|
json_data = request.data
|
|
215
216
|
subcomponent_id = json_data.pop('id', -1)
|
|
216
217
|
try:
|
|
@@ -228,37 +229,16 @@ class ComponentViewSet(InstanceMixin, viewsets.ModelViewSet):
|
|
|
228
229
|
self.check_object_permissions(self.request, subcomponent)
|
|
229
230
|
return self.perform_controller_method(json_data, subcomponent)
|
|
230
231
|
|
|
231
|
-
|
|
232
|
-
def check_object_permissions(self, request, component):
|
|
233
|
-
super().check_object_permissions(request, component)
|
|
234
|
-
|
|
235
|
-
if not component.controller:
|
|
236
|
-
raise APIValidationError(
|
|
237
|
-
_('Component has no controller assigned.'),
|
|
238
|
-
code=400
|
|
239
|
-
)
|
|
240
|
-
if request.user.is_master:
|
|
241
|
-
return
|
|
242
|
-
user_role = request.user.get_role(self.instance)
|
|
243
|
-
if user_role.is_superuser:
|
|
244
|
-
return
|
|
245
|
-
if not user_role.component_permissions.filter(
|
|
246
|
-
write=True, component=component
|
|
247
|
-
).count():
|
|
248
|
-
raise APIValidationError(
|
|
249
|
-
_('You do not have permission to write to this component.'),
|
|
250
|
-
code=403
|
|
251
|
-
)
|
|
252
|
-
|
|
253
232
|
@action(detail=True, methods=['post'])
|
|
254
233
|
def controller(self, request, pk=None, *args, **kwargs):
|
|
255
234
|
component = self.get_object()
|
|
256
|
-
self.check_object_permissions(self.request, component)
|
|
257
235
|
return self.perform_controller_method(request.data, component)
|
|
258
236
|
|
|
259
237
|
@action(detail=False, methods=['post'])
|
|
260
238
|
def control(self, request, *args, **kwargs):
|
|
261
|
-
component =
|
|
239
|
+
component = self.get_queryset().filter(id=request.data.pop('id', 0))
|
|
240
|
+
if not component:
|
|
241
|
+
raise Http404()
|
|
262
242
|
self.check_object_permissions(self.request, component)
|
|
263
243
|
return self.perform_controller_method(request.data, component)
|
|
264
244
|
|
simo/core/api_meta.py
CHANGED
|
@@ -4,7 +4,8 @@ from rest_framework import serializers
|
|
|
4
4
|
from rest_framework.metadata import SimpleMetadata
|
|
5
5
|
from rest_framework.utils.field_mapping import ClassLookupDict
|
|
6
6
|
from .serializers import (
|
|
7
|
-
HiddenSerializerField, ComponentManyToManyRelatedField
|
|
7
|
+
HiddenSerializerField, ComponentManyToManyRelatedField,
|
|
8
|
+
TextAreaSerializerField
|
|
8
9
|
)
|
|
9
10
|
|
|
10
11
|
|
|
@@ -36,6 +37,7 @@ class SIMOAPIMetadata(SimpleMetadata):
|
|
|
36
37
|
serializers.ManyRelatedField: 'many related objects',
|
|
37
38
|
ComponentManyToManyRelatedField: 'many related objects',
|
|
38
39
|
HiddenSerializerField: 'hidden',
|
|
40
|
+
TextAreaSerializerField: 'textarea',
|
|
39
41
|
})
|
|
40
42
|
|
|
41
43
|
def get_field_info(self, field):
|
simo/core/forms.py
CHANGED
|
@@ -34,7 +34,6 @@ class HiddenField(forms.CharField):
|
|
|
34
34
|
super().__init__(widget=forms.HiddenInput())
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
|
|
38
37
|
class HubConfigForm(forms.Form):
|
|
39
38
|
name = forms.CharField(
|
|
40
39
|
label=_("Hub Name"), required=True,
|
|
@@ -300,7 +299,6 @@ class ComponentAdminForm(forms.ModelForm):
|
|
|
300
299
|
'category': autocomplete.ModelSelect2(
|
|
301
300
|
url='autocomplete-category', attrs={'data-html': True}
|
|
302
301
|
),
|
|
303
|
-
#'instance_methods': PythonCode
|
|
304
302
|
}
|
|
305
303
|
|
|
306
304
|
def __init__(self, *args, **kwargs):
|
|
@@ -334,6 +332,7 @@ class ComponentAdminForm(forms.ModelForm):
|
|
|
334
332
|
#'instance_methods',
|
|
335
333
|
'value_units',
|
|
336
334
|
'alarm_category', 'arm_status',
|
|
335
|
+
'notes'
|
|
337
336
|
)
|
|
338
337
|
base_fields = ['id', 'gateway', 'base_type', 'name']
|
|
339
338
|
if cls.has_icon:
|
|
@@ -348,7 +347,7 @@ class ComponentAdminForm(forms.ModelForm):
|
|
|
348
347
|
|
|
349
348
|
base_fields.append('show_in_app')
|
|
350
349
|
base_fields.append('control')
|
|
351
|
-
|
|
350
|
+
base_fields.append('notes')
|
|
352
351
|
|
|
353
352
|
fieldsets = [
|
|
354
353
|
(_("Base settings"), {'fields': base_fields}),
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Generated by Django 3.2.9 on 2024-04-29 12:31
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('core', '0030_alter_instance_timezone'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='component',
|
|
15
|
+
name='notes',
|
|
16
|
+
field=models.TextField(blank=True, null=True),
|
|
17
|
+
),
|
|
18
|
+
migrations.AlterField(
|
|
19
|
+
model_name='category',
|
|
20
|
+
name='header_image',
|
|
21
|
+
field=models.ImageField(blank=True, help_text='Will be cropped down to: 830x430', null=True, upload_to='categories'),
|
|
22
|
+
),
|
|
23
|
+
migrations.AlterField(
|
|
24
|
+
model_name='instance',
|
|
25
|
+
name='cover_image',
|
|
26
|
+
field=models.ImageField(blank=True, null=True, upload_to='hub_covers'),
|
|
27
|
+
),
|
|
28
|
+
]
|
|
Binary file
|
simo/core/models.py
CHANGED
|
@@ -163,7 +163,7 @@ class Category(DirtyFieldsMixin, models.Model, SimoAdminMixin):
|
|
|
163
163
|
help_text=_("All components automatically belongs to this category")
|
|
164
164
|
)
|
|
165
165
|
order = models.PositiveIntegerField(
|
|
166
|
-
|
|
166
|
+
blank=False, null=False, db_index=True
|
|
167
167
|
)
|
|
168
168
|
objects = CategoriesManager()
|
|
169
169
|
|
|
@@ -175,8 +175,13 @@ class Category(DirtyFieldsMixin, models.Model, SimoAdminMixin):
|
|
|
175
175
|
def __str__(self):
|
|
176
176
|
return self.name
|
|
177
177
|
|
|
178
|
-
|
|
179
178
|
def save(self, *args, **kwargs):
|
|
179
|
+
if self.order is None:
|
|
180
|
+
last_cat = Category.objects.filter(instance=self.instance).last()
|
|
181
|
+
if last_cat:
|
|
182
|
+
self.order = last_cat.order + 1
|
|
183
|
+
else:
|
|
184
|
+
self.order = 0
|
|
180
185
|
dirty_fields = self.get_dirty_fields()
|
|
181
186
|
if 'all' in dirty_fields:
|
|
182
187
|
if self.all:
|
|
@@ -361,6 +366,8 @@ class Component(DirtyFieldsMixin, models.Model, SimoAdminMixin, OnChangeMixin):
|
|
|
361
366
|
|
|
362
367
|
show_in_app = models.BooleanField(default=True, db_index=True)
|
|
363
368
|
|
|
369
|
+
notes = models.TextField(null=True, blank=True)
|
|
370
|
+
|
|
364
371
|
# Feature for global superusers.
|
|
365
372
|
# Good candidate for reworking in to something more API oriented
|
|
366
373
|
# instead of injecting the code directly.
|
simo/core/permissions.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
from rest_framework.permissions import BasePermission, SAFE_METHODS
|
|
1
|
+
from rest_framework.permissions import BasePermission, SAFE_METHODS, IsAuthenticated
|
|
2
2
|
from .models import Instance, Category, Zone
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class InstancePermission(BasePermission):
|
|
6
|
-
""
|
|
7
|
-
Allows access only to user instances
|
|
8
|
-
"""
|
|
6
|
+
message = "You have no role in this SIMO.io instance."
|
|
9
7
|
|
|
10
8
|
def has_permission(self, request, view):
|
|
11
9
|
if not request.user.is_active:
|
|
@@ -24,6 +22,7 @@ class InstancePermission(BasePermission):
|
|
|
24
22
|
|
|
25
23
|
|
|
26
24
|
class IsInstanceSuperuser(BasePermission):
|
|
25
|
+
message = "Only superusers are allowed to do this."
|
|
27
26
|
|
|
28
27
|
def has_permission(self, request, view):
|
|
29
28
|
if request.user.is_master:
|
|
@@ -33,6 +32,7 @@ class IsInstanceSuperuser(BasePermission):
|
|
|
33
32
|
|
|
34
33
|
|
|
35
34
|
class InstanceSuperuserCanEdit(BasePermission):
|
|
35
|
+
message = "Only superusers are allowed to perform this action."
|
|
36
36
|
|
|
37
37
|
def has_object_permission(self, request, view, obj):
|
|
38
38
|
|
|
@@ -47,3 +47,28 @@ class InstanceSuperuserCanEdit(BasePermission):
|
|
|
47
47
|
if user_role.is_superuser:
|
|
48
48
|
return True
|
|
49
49
|
return request.method in SAFE_METHODS
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ComponentPermission(BasePermission):
|
|
53
|
+
message = "You do not have permission to do this on this component."
|
|
54
|
+
|
|
55
|
+
# TODO: clean this up once the app is tested and running 100% correctly for at least 6 months.
|
|
56
|
+
def has_object_permission(self, request, view, obj):
|
|
57
|
+
print(f"Check permission of {request.user} on {obj}")
|
|
58
|
+
if request.method in SAFE_METHODS:
|
|
59
|
+
print("THIS IS SAFE METHOD!")
|
|
60
|
+
return True
|
|
61
|
+
if request.user.is_master:
|
|
62
|
+
print("USER IS MASTER!")
|
|
63
|
+
return True
|
|
64
|
+
user_role = request.user.get_role(view.instance)
|
|
65
|
+
if user_role.is_superuser:
|
|
66
|
+
print("USER IS SUPERUSER!")
|
|
67
|
+
return True
|
|
68
|
+
if request.method == 'POST' and user_role.component_permissions.filter(
|
|
69
|
+
write=True, component=obj
|
|
70
|
+
).count():
|
|
71
|
+
print("USER HAS RIGHT TO DO THIS!")
|
|
72
|
+
return True
|
|
73
|
+
print("USER IS NOT ALLOWED TO DO THIS!")
|
|
74
|
+
return False
|
simo/core/serializers.py
CHANGED
|
@@ -93,6 +93,10 @@ class HiddenSerializerField(serializers.CharField):
|
|
|
93
93
|
pass
|
|
94
94
|
|
|
95
95
|
|
|
96
|
+
class TextAreaSerializerField(serializers.CharField):
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
|
|
96
100
|
class ComponentFormsetField(FormSerializer):
|
|
97
101
|
|
|
98
102
|
class Meta:
|
|
@@ -130,6 +134,7 @@ class ComponentFormsetField(FormSerializer):
|
|
|
130
134
|
continue
|
|
131
135
|
|
|
132
136
|
cls_type = form_field.__class__
|
|
137
|
+
|
|
133
138
|
try:
|
|
134
139
|
serializer_field_class = field_mapping[cls_type]
|
|
135
140
|
except KeyError:
|
|
@@ -238,6 +243,7 @@ class ComponentSerializer(FormSerializer):
|
|
|
238
243
|
meta = ObjectSerializerMethodField()
|
|
239
244
|
arm_status = ObjectSerializerMethodField()
|
|
240
245
|
battery_level = ObjectSerializerMethodField()
|
|
246
|
+
controller_methods = serializers.SerializerMethodField()
|
|
241
247
|
|
|
242
248
|
class Meta:
|
|
243
249
|
form = ComponentAdminForm
|
|
@@ -280,22 +286,25 @@ class ComponentSerializer(FormSerializer):
|
|
|
280
286
|
form_field = form[field_name]
|
|
281
287
|
|
|
282
288
|
cls = form_field.field.__class__
|
|
283
|
-
|
|
284
|
-
serializer_field_class =
|
|
285
|
-
|
|
286
|
-
cls = form_field.field.__class__.__bases__[0]
|
|
289
|
+
if field_name == 'notes':
|
|
290
|
+
serializer_field_class = TextAreaSerializerField
|
|
291
|
+
else:
|
|
287
292
|
try:
|
|
288
293
|
serializer_field_class = field_mapping[cls]
|
|
289
294
|
except KeyError:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
serializer
|
|
296
|
-
|
|
295
|
+
cls = form_field.field.__class__.__bases__[0]
|
|
296
|
+
try:
|
|
297
|
+
serializer_field_class = field_mapping[cls]
|
|
298
|
+
except KeyError:
|
|
299
|
+
raise TypeError(
|
|
300
|
+
"{field} is not mapped to a serializer field. "
|
|
301
|
+
"Please add {field} to {serializer}.Meta.field_mapping. "
|
|
302
|
+
"Currently mapped fields: {mapped}".format(
|
|
303
|
+
field=form_field.field.__class__.__name__,
|
|
304
|
+
serializer=self.__class__.__name__,
|
|
305
|
+
mapped=', '.join(sorted([i.__name__ for i in field_mapping.keys()]))
|
|
306
|
+
)
|
|
297
307
|
)
|
|
298
|
-
)
|
|
299
308
|
|
|
300
309
|
ret[field_name] = self._get_field(
|
|
301
310
|
form_field.field, serializer_field_class
|
|
Binary file
|
|
Binary file
|
simo/fleet/forms.py
CHANGED
|
@@ -573,12 +573,6 @@ class ColonelPWMOutputConfigForm(ColonelComponentForm):
|
|
|
573
573
|
]
|
|
574
574
|
)
|
|
575
575
|
)
|
|
576
|
-
frequency = forms.IntegerField(
|
|
577
|
-
min_value=30, max_value=100000, required=True, initial=3000,
|
|
578
|
-
help_text="PWM signal frequency in Hz. Works only with GPIO ports."
|
|
579
|
-
"3000 Hz offers great performance in most use cases."
|
|
580
|
-
|
|
581
|
-
)
|
|
582
576
|
min = forms.FloatField(
|
|
583
577
|
required=True, initial=0,
|
|
584
578
|
help_text="Minimum component value"
|
|
@@ -723,9 +717,9 @@ class ColonelRGBLightConfigForm(ColonelComponentForm):
|
|
|
723
717
|
return custom_timing
|
|
724
718
|
custom_timing = custom_timing.strip().\
|
|
725
719
|
strip('(').strip('[').rstrip(')').rstrip(']').split(',')
|
|
726
|
-
if len(custom_timing
|
|
720
|
+
if len(custom_timing) != 4:
|
|
727
721
|
raise forms.ValidationError("Tuple of 4 integers please.")
|
|
728
|
-
for t in custom_timing
|
|
722
|
+
for t in custom_timing:
|
|
729
723
|
try:
|
|
730
724
|
t = int(t)
|
|
731
725
|
except:
|
|
@@ -734,7 +728,7 @@ class ColonelRGBLightConfigForm(ColonelComponentForm):
|
|
|
734
728
|
raise forms.ValidationError(f"Intervals must be greater than 0.")
|
|
735
729
|
if t > 100000:
|
|
736
730
|
raise forms.ValidationError(f"{t} seems way to much!")
|
|
737
|
-
return f"({custom_timing})"
|
|
731
|
+
return f"({','.join(custom_timing)})"
|
|
738
732
|
|
|
739
733
|
def clean(self):
|
|
740
734
|
super().clean()
|
simo/fleet/models.py
CHANGED
|
@@ -327,10 +327,20 @@ def post_i2c_interface_delete(sender, instance, *args, **kwargs):
|
|
|
327
327
|
pin.occupied_by_content_type = None
|
|
328
328
|
pin.occupied_by_content_id = None
|
|
329
329
|
pin.save()
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
330
|
+
|
|
331
|
+
# In an event of colonel deletion these pin no longer exist
|
|
332
|
+
# at this point, therefore this trhows irrelevant exceptions
|
|
333
|
+
# that we want to fail silenty
|
|
334
|
+
try:
|
|
335
|
+
instance.scl_pin.occupied_by = instance
|
|
336
|
+
instance.scl_pin.save()
|
|
337
|
+
except ColonelPin.DoesNotExist:
|
|
338
|
+
pass
|
|
339
|
+
try:
|
|
340
|
+
instance.sda_pin.occupied_by = instance
|
|
341
|
+
instance.sda_pin.save()
|
|
342
|
+
except ColonelPin.DoesNotExist:
|
|
343
|
+
pass
|
|
334
344
|
|
|
335
345
|
|
|
336
346
|
class Interface(models.Model):
|
simo/settings.py
CHANGED
|
@@ -176,7 +176,6 @@ REST_FRAMEWORK = {
|
|
|
176
176
|
'simo.core.api_auth.IsAuthenticated',
|
|
177
177
|
],
|
|
178
178
|
'DEFAULT_PERMISSION_CLASSES': [
|
|
179
|
-
'rest_framework.permissions.IsAuthenticated',
|
|
180
179
|
'simo.users.permissions.IsActivePermission',
|
|
181
180
|
'simo.core.permissions.InstancePermission'
|
|
182
181
|
],
|
|
@@ -6,7 +6,7 @@ simo/cli.py,sha256=kB1dhZ30Pnq7mDawWGbX5WnCuoZ6qNMcnWH-c8XxcaU,2233
|
|
|
6
6
|
simo/conf.py,sha256=H2BhXAV8MEDVXF8AbkaLSfR4ULd-9_bS4bnhE5sE5fg,112
|
|
7
7
|
simo/on_http_start.py,sha256=PJQlKYeZbtGCxRjDV6zcCqyA5Ns9d5NND30Tb6vIav4,2358
|
|
8
8
|
simo/scripting.py,sha256=PVIkGsiMDWj4CNTbOM3rq7pJ6ruavuns-ZMU7VudLa4,923
|
|
9
|
-
simo/settings.py,sha256=
|
|
9
|
+
simo/settings.py,sha256=yezM7QleJv73IFWMsPyGxqoI_c3JV21R1RsDcgweIfU,6840
|
|
10
10
|
simo/urls.py,sha256=PgKGCZON3SAL3Hh9vVDWVJ9zDQO5ZPsRQLz_s5GWSV0,2328
|
|
11
11
|
simo/wsgi.py,sha256=ci7BK1zCuqTwCUQi29su7xKeGEJHk0N3Oc8jGJRO6EY,165
|
|
12
12
|
simo/__pycache__/__init__.cpython-38.pyc,sha256=j81de0BqHMr6bs0C7cuYrXl7HwtK_vv8hDEtAdSwDJc,153
|
|
@@ -14,7 +14,7 @@ simo/__pycache__/asgi.cpython-38.pyc,sha256=OemZ2InNbZCiJtD3MWSO8IiDSqp-LUyTLFjM
|
|
|
14
14
|
simo/__pycache__/celeryc.cpython-38.pyc,sha256=eSRoaKwfYlxVaxAiwqpQ2ndEcx7W-VpZtbxRFSV8UYg,1653
|
|
15
15
|
simo/__pycache__/conf.cpython-38.pyc,sha256=MYP2yk3ULxiYwZsZR6tCLjKnU-z03A3avzQzIn66y3k,273
|
|
16
16
|
simo/__pycache__/on_http_start.cpython-38.pyc,sha256=cjgntuqsmandjyNtJoqch0LpxA-BNF3UR8vUxufYn9g,2067
|
|
17
|
-
simo/__pycache__/settings.cpython-38.pyc,sha256=
|
|
17
|
+
simo/__pycache__/settings.cpython-38.pyc,sha256=m9O2hfu1sVkYxi9-MzM2D4DzOHL7ea9LOt1AJlV4LdI,6084
|
|
18
18
|
simo/__pycache__/urls.cpython-38.pyc,sha256=sqfstQthcjXtv31Tad0RAlWWI2A0HH6HN0fW0VmmWQw,2050
|
|
19
19
|
simo/__pycache__/wsgi.cpython-38.pyc,sha256=Wt9kKkH2Sg5LRL4NrVQQDYPIoDyTvnXwm6jZjnG3kIc,322
|
|
20
20
|
simo/_hub_template/hub/asgi.py,sha256=ElN_fdeSkf0Ysa7pS9rJVmZ1HmLhFxb8jFaMLqe1220,126
|
|
@@ -25,10 +25,10 @@ simo/_hub_template/hub/settings.py,sha256=4QhvhbtLRxHvAntwqG_qeAAtpDUqKvN4jzw9u3
|
|
|
25
25
|
simo/_hub_template/hub/supervisor.conf,sha256=IY3fdK0fDD2eAothB0n54xhjQj8LYoXIR96-Adda5Z8,1353
|
|
26
26
|
simo/_hub_template/hub/urls.py,sha256=Ydm-1BkYAzWeEF-MKSDIFf-7aE4qNLPm48-SA51XgJQ,25
|
|
27
27
|
simo/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
-
simo/core/admin.py,sha256=
|
|
29
|
-
simo/core/api.py,sha256=
|
|
28
|
+
simo/core/admin.py,sha256=cPOC2x45Gjf0T8MKtmE2wJZk7DAuHMsvvy5Nk3YUIG8,17675
|
|
29
|
+
simo/core/api.py,sha256=bAX-DXG5aJr3VvjqGKGtjVzel0E7Cp3l5tkA3uLhnFw,22969
|
|
30
30
|
simo/core/api_auth.py,sha256=_3hG4e1eLKrcRnSAOB_xTL6cwtOJ2_7JS7GZU_iqTgA,1251
|
|
31
|
-
simo/core/api_meta.py,sha256=
|
|
31
|
+
simo/core/api_meta.py,sha256=ySmmhtVrWatI3yqnYPuP5ipapmJfyfEbl32w-7_W5O4,3551
|
|
32
32
|
simo/core/app_widgets.py,sha256=EEQOto3fGR0syDqpJE38tQrx8DoTTyg26nF5kYzHY38,2018
|
|
33
33
|
simo/core/auto_urls.py,sha256=0gu-IL7PHobrmKW6ksffiOkAYu-aIorykWdxRNtwGYo,1194
|
|
34
34
|
simo/core/autocomplete_views.py,sha256=JT5LA2_Wtr60XYSAIqaXFKFYPjrmkEf6yunXD9y2zco,4022
|
|
@@ -38,15 +38,15 @@ simo/core/controllers.py,sha256=SHqdSRhF7G-hmRtcWEODkUs-b17y6gEHDdZM3V01uVs,2697
|
|
|
38
38
|
simo/core/dynamic_settings.py,sha256=U2WNL96JzVXdZh0EqMPWrxqO6BaRR2Eo5KTDqz7MC4o,1943
|
|
39
39
|
simo/core/events.py,sha256=LvtonJGNyCb6HLozs4EG0WZItnDwNdtnGQ4vTcnKvUs,4438
|
|
40
40
|
simo/core/filters.py,sha256=ghtOZcrwNAkIyF5_G9Sn73NkiI71mXv0NhwCk4IyMIM,411
|
|
41
|
-
simo/core/forms.py,sha256=
|
|
41
|
+
simo/core/forms.py,sha256=FnnK4pHZ8EaMvubN0NQbz2SdTTgMXvGM-heklzN4RZo,22465
|
|
42
42
|
simo/core/gateways.py,sha256=s_c2W0v2_te89i6LS4Nj7F2wn9UwjZXPT7pfy6SToVo,3714
|
|
43
43
|
simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
|
|
44
44
|
simo/core/managers.py,sha256=WoQ4OX3akIvoroSYji-nLVqXBSJzCiC1u_IiWkKbKmA,2413
|
|
45
45
|
simo/core/middleware.py,sha256=64PYjnyRnYf4sgMvPfR0oQqf9UEtxUwnhJe3RV6z_HI,2040
|
|
46
|
-
simo/core/models.py,sha256=
|
|
47
|
-
simo/core/permissions.py,sha256=
|
|
46
|
+
simo/core/models.py,sha256=zqbPDYLHOsavrBzw5uOmUgcWBnBbjGLvezgETX-pD_E,19672
|
|
47
|
+
simo/core/permissions.py,sha256=b2qO_kNaCgWcv2VJbOp6AUXOc_cup7fOT3Up16rn77M,2495
|
|
48
48
|
simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
|
|
49
|
-
simo/core/serializers.py,sha256=
|
|
49
|
+
simo/core/serializers.py,sha256=kmja52o-BUOcUTX2ZsKWixvKRZSXB7lGe866Q1ajlmo,17563
|
|
50
50
|
simo/core/signal_receivers.py,sha256=EZ8NSYZxUgSaLS16YZdK7T__l8dl0joMRllOxx5PUt4,2809
|
|
51
51
|
simo/core/socket_consumers.py,sha256=n7VE2Fvqt4iEAYLTRbTPOcI-7tszMAADu7gimBxB-Fg,9635
|
|
52
52
|
simo/core/storage.py,sha256=YlxmdRs-zhShWtFKgpJ0qp2NDBuIkJGYC1OJzqkbttQ,572
|
|
@@ -56,10 +56,10 @@ simo/core/types.py,sha256=WJEq48mIbFi_5Alt4wxWMGXxNxUTXqfQU5koH7wqHHI,1108
|
|
|
56
56
|
simo/core/views.py,sha256=hlAKpAbCbqI3a-uL5tDp532T2oLFiF0MBzKUJ_SNzo0,5833
|
|
57
57
|
simo/core/widgets.py,sha256=J9e06C6I22F6xKic3VMgG7WeX07glAcl-4bF2Mg180A,2827
|
|
58
58
|
simo/core/__pycache__/__init__.cpython-38.pyc,sha256=y0IW37wBUIGa3Eh_ZG28pRqHKoLiPyTgUX2OnbkEPlc,158
|
|
59
|
-
simo/core/__pycache__/admin.cpython-38.pyc,sha256=
|
|
60
|
-
simo/core/__pycache__/api.cpython-38.pyc,sha256=
|
|
59
|
+
simo/core/__pycache__/admin.cpython-38.pyc,sha256=EqwHQhU8qQrjfSChyCZXN6J-1Eira9alYIqR45-3OnE,13475
|
|
60
|
+
simo/core/__pycache__/api.cpython-38.pyc,sha256=l3BUnLGBsM-FzqdaKi__1R9Z5DJnhgJrkmXQ2XQetT0,18372
|
|
61
61
|
simo/core/__pycache__/api_auth.cpython-38.pyc,sha256=5UTBr3rDMERAfc0OuOVDwGeQkt6Q7GLBtZJAMBse1sg,1712
|
|
62
|
-
simo/core/__pycache__/api_meta.cpython-38.pyc,sha256=
|
|
62
|
+
simo/core/__pycache__/api_meta.cpython-38.pyc,sha256=94T3_rybn2T1_bkaDQnQRyjy21LBaGOnz-mmkJ6T0N8,2840
|
|
63
63
|
simo/core/__pycache__/app_widgets.cpython-38.pyc,sha256=9Es2wZNduzUJv-jZ_HX0-L3vqwpXWBbseEwoC5K6b-w,3465
|
|
64
64
|
simo/core/__pycache__/auto_urls.cpython-38.pyc,sha256=SVl4fF0-yiq7e9gt08jIM6_rL4JYcR0cNHzR9jCEi1M,931
|
|
65
65
|
simo/core/__pycache__/autocomplete_views.cpython-38.pyc,sha256=hJ6JILI1LqrAtpQMvxnLvljGdW1v1gpvBsD79vFkZ58,3972
|
|
@@ -69,15 +69,15 @@ simo/core/__pycache__/controllers.cpython-38.pyc,sha256=vGRcRD7VPUdpP2WMtn2IIrnk
|
|
|
69
69
|
simo/core/__pycache__/dynamic_settings.cpython-38.pyc,sha256=ELu06Hub4DOidja71ybvD3ZM4HdXiyZjNJrZfnXZXNA,2476
|
|
70
70
|
simo/core/__pycache__/events.cpython-38.pyc,sha256=A1Axx-qftd1r7st7wkO3DkvTdt9-RkcJe5KJhpzJVk8,5109
|
|
71
71
|
simo/core/__pycache__/filters.cpython-38.pyc,sha256=VIMADCBiYhziIyRmxAyUDJluZvuZmiC4bNYWTRsGSao,721
|
|
72
|
-
simo/core/__pycache__/forms.cpython-38.pyc,sha256=
|
|
72
|
+
simo/core/__pycache__/forms.cpython-38.pyc,sha256=U5pV_JyfoGwymn3tsws8FR2GrxihjKFa5dmtdzijexA,19071
|
|
73
73
|
simo/core/__pycache__/gateways.cpython-38.pyc,sha256=XBiwMfBkjoQ2re6jvADJOwK0_0Aav-crzie9qtfqT9U,4599
|
|
74
74
|
simo/core/__pycache__/loggers.cpython-38.pyc,sha256=Z-cdQnC6XlIonPV4Sl4E52tP4NMEdPAiHK0cFaIL7I8,1623
|
|
75
75
|
simo/core/__pycache__/managers.cpython-38.pyc,sha256=5vstOMfm997CZBBkaSiaS7EojhLTWZlbeA_EQ8u-yfg,2554
|
|
76
76
|
simo/core/__pycache__/middleware.cpython-38.pyc,sha256=bGOFJNEhJeLbpsZp8LYn1VA3paLF5HULHQ6IFKa7Juc,2022
|
|
77
|
-
simo/core/__pycache__/models.cpython-38.pyc,sha256=
|
|
78
|
-
simo/core/__pycache__/permissions.cpython-38.pyc,sha256=
|
|
77
|
+
simo/core/__pycache__/models.cpython-38.pyc,sha256=meQeK2mVoSDP9cTMSZDW-Ofi53QzwjfHSUlAGlnhyfs,17127
|
|
78
|
+
simo/core/__pycache__/permissions.cpython-38.pyc,sha256=7iz0o_jIEhDM2FQd-P-3Y6sm4GQ0MRy4a5biBNkngOA,2680
|
|
79
79
|
simo/core/__pycache__/routing.cpython-38.pyc,sha256=3T3FPJ8Cn99xZCGvMyg2xjl7al-Shm9CelbSpkJtNP8,599
|
|
80
|
-
simo/core/__pycache__/serializers.cpython-38.pyc,sha256=
|
|
80
|
+
simo/core/__pycache__/serializers.cpython-38.pyc,sha256=x-obnrdPnoYRhriP_51_Jy_0saCsasWdFQSH1kalVqo,16869
|
|
81
81
|
simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=sgjH_wv-1U99auH5uHb3or0qettPeHAlsz8P7B03ajY,2430
|
|
82
82
|
simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=NJUr7nRyHFvmAumxxWpsod5wzVVZM99rCEuJs1utHA4,8432
|
|
83
83
|
simo/core/__pycache__/storage.cpython-38.pyc,sha256=BTkYH8QQyjqI0WOtJC8fHNtgu0YA1vjqZclXjC2vCVI,1116
|
|
@@ -172,6 +172,7 @@ simo/core/migrations/0027_remove_component_tags.py,sha256=V0o_lgKiVU3HfG5V8MTO-j
|
|
|
172
172
|
simo/core/migrations/0028_rename_subcomponents_component_slaves.py,sha256=ioQcfO2_IIfPc_BZzETmSodsYstzygR9U0ULnhET6ac,373
|
|
173
173
|
simo/core/migrations/0029_auto_20240229_1331.py,sha256=BYXPNwjXApAx7mxE5li3QssfksWTsSjDf_VPQ8iGV8c,1140
|
|
174
174
|
simo/core/migrations/0030_alter_instance_timezone.py,sha256=XZuYr2eD9MvE21Jxfdat8RC3sbc7PaGUfNPaqqxBNzE,23248
|
|
175
|
+
simo/core/migrations/0031_auto_20240429_1231.py,sha256=kskD8dylxqg-l-ZQgxl6ZdZd7iNcJ52rOGPJFa9s-wk,829
|
|
175
176
|
simo/core/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
176
177
|
simo/core/migrations/__pycache__/0001_initial.cpython-38.pyc,sha256=w6GiBXVxWj30Bg4Sn_pFVeA041d-pCrkaq8mR3KuF70,5381
|
|
177
178
|
simo/core/migrations/__pycache__/0002_load_icons.cpython-38.pyc,sha256=Nb9RrPjVYo_RpZ5PmzoaEIWGCeVt4kicpmGiKlBrpIw,2123
|
|
@@ -203,6 +204,7 @@ simo/core/migrations/__pycache__/0027_remove_component_tags.cpython-38.pyc,sha25
|
|
|
203
204
|
simo/core/migrations/__pycache__/0028_rename_subcomponents_component_slaves.cpython-38.pyc,sha256=PSiMp1yDzZ36Ei36U2tcIlvyzGgB5RuvGImrJ__7Q5s,593
|
|
204
205
|
simo/core/migrations/__pycache__/0029_auto_20240229_1331.cpython-38.pyc,sha256=nO6lBU-1SxMQv67jQs7cGgNnot722UVL9pj3UE14I1k,1086
|
|
205
206
|
simo/core/migrations/__pycache__/0030_alter_instance_timezone.cpython-38.pyc,sha256=paRgdijg5o8QzluT4GjSEQIMk6UAF7XmSwjqknXPE_4,16333
|
|
207
|
+
simo/core/migrations/__pycache__/0031_auto_20240429_1231.cpython-38.pyc,sha256=Kl76gU1VUyTWMz9RIZUrbnb_xeteWLDSRfs_GtNCVow,863
|
|
206
208
|
simo/core/migrations/__pycache__/__init__.cpython-38.pyc,sha256=VZmDQ57BTcebuM0KMhjiTOabgWZCBxQmSJzWZos9SO8,169
|
|
207
209
|
simo/core/static/ansi_styles.css,sha256=4ieJGrjZPKyPSago9FdB_gflHoGE1vxCHi8qVn5tY-Y,37352
|
|
208
210
|
simo/core/static/admin/Img/plus.svg,sha256=2NpSFPWqGIjpAQGFI7LDQHPKagEhYkJiJX95ufCoZaI,741
|
|
@@ -10169,10 +10171,10 @@ simo/fleet/auto_urls.py,sha256=X04oKJWA48wFW5iXg3PPROY2KDdHn_a99orQSE28QC4,518
|
|
|
10169
10171
|
simo/fleet/base_types.py,sha256=wL9RVkHr0gA7HI1wZq0pruGEIgvQqpfnCL4cC3ywsvw,102
|
|
10170
10172
|
simo/fleet/ble.py,sha256=eHA_9ABjbmH1vUVCv9hiPXQL2GZZSEVwfO0xyI1S0nI,1081
|
|
10171
10173
|
simo/fleet/controllers.py,sha256=rTxRFf-LKWAZxzixrsLZHHm51BmMx9a1PLdgf6inlNM,20533
|
|
10172
|
-
simo/fleet/forms.py,sha256=
|
|
10174
|
+
simo/fleet/forms.py,sha256=SOz0CnaRJ1jOOJLzvL2kOfacuaE7nOVlc6NtScSaR1Y,37965
|
|
10173
10175
|
simo/fleet/gateways.py,sha256=KV5i5fxXIrlK-k6zyEkk83x11GJt-ELQ0npb4Ac83cM,3693
|
|
10174
10176
|
simo/fleet/managers.py,sha256=XOpDOA9L-f_550TNSyXnJbun2EmtGz1TenVTMlUSb8E,807
|
|
10175
|
-
simo/fleet/models.py,sha256=
|
|
10177
|
+
simo/fleet/models.py,sha256=ve-97F1cwGt-AmwfSJK0d-57pP3NyZpeu0XlHu2oK28,14494
|
|
10176
10178
|
simo/fleet/routing.py,sha256=cofGsVWXMfPDwsJ6HM88xxtRxHwERhJ48Xyxc8mxg5o,149
|
|
10177
10179
|
simo/fleet/serializers.py,sha256=LgSTnSI_sUhFXmW9-669keM6gmaSI_teaqMHEab4aL4,1972
|
|
10178
10180
|
simo/fleet/socket_consumers.py,sha256=Z-MooNN2HQccdhkynADJks5slbK9mGsnEpMLuA51H3I,18534
|
|
@@ -10186,10 +10188,10 @@ simo/fleet/__pycache__/auto_urls.cpython-38.pyc,sha256=SqyTuaz_kEBvx-bL46SclsZEE
|
|
|
10186
10188
|
simo/fleet/__pycache__/base_types.cpython-38.pyc,sha256=deyPwjpT6xZiFxBGFnj5b7R-lbdOTh2krgpJhrcGVhc,274
|
|
10187
10189
|
simo/fleet/__pycache__/ble.cpython-38.pyc,sha256=Nrof9w7cm4OlpFWHeVnmvvanh2_oF9oQ3TknJiV93-0,1267
|
|
10188
10190
|
simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=l9bz18Qp33C12TJOKPSn9vIXnlBKnBusODNk7Fg64qA,18103
|
|
10189
|
-
simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=
|
|
10191
|
+
simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=0HmLdm3-2_4Zy_lIjUnGpnjf_gFz_KmmTFS1Vt4SY48,27398
|
|
10190
10192
|
simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=YAcgTOqJbtjGI03lvEcU6keFfrwAHkObVmErYzfRvjk,3569
|
|
10191
10193
|
simo/fleet/__pycache__/managers.cpython-38.pyc,sha256=8uz-xpUiqbGDgXIZ_XRZtFb-Tju6NGxflGg-Ee4Yo6k,1310
|
|
10192
|
-
simo/fleet/__pycache__/models.cpython-38.pyc,sha256=
|
|
10194
|
+
simo/fleet/__pycache__/models.cpython-38.pyc,sha256=pHNRUiPRjH0SLp14pzbSIxHi_-27SpZFgSh_7lzA8Wo,12359
|
|
10193
10195
|
simo/fleet/__pycache__/routing.cpython-38.pyc,sha256=aPrCmxFKVyB8R8ZbJDwdPdFfvT7CvobovvZeq_mqRgY,314
|
|
10194
10196
|
simo/fleet/__pycache__/serializers.cpython-38.pyc,sha256=gwLIoLQJwkFoDCjKC_ikksNCYea3-mF8hVHFeKlOkbc,3098
|
|
10195
10197
|
simo/fleet/__pycache__/socket_consumers.cpython-38.pyc,sha256=RjzPD580096fby0HYLzZorm61zdZNOq5AHXmNAC4Yd8,13764
|
|
@@ -10446,8 +10448,8 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
|
|
|
10446
10448
|
simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10447
10449
|
simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10448
10450
|
simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10449
|
-
simo-2.0.
|
|
10450
|
-
simo-2.0.
|
|
10451
|
-
simo-2.0.
|
|
10452
|
-
simo-2.0.
|
|
10453
|
-
simo-2.0.
|
|
10451
|
+
simo-2.0.23.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
|
|
10452
|
+
simo-2.0.23.dist-info/METADATA,sha256=n65-Fcht6N4VSA8W5igDDeUKN7Hq5YgU8XMTb5pmUcw,1730
|
|
10453
|
+
simo-2.0.23.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
10454
|
+
simo-2.0.23.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
|
|
10455
|
+
simo-2.0.23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|