simo 1.7.5__py3-none-any.whl → 1.7.7__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.

Files changed (47) hide show
  1. simo/__pycache__/settings.cpython-38.pyc +0 -0
  2. simo/core/__pycache__/api.cpython-38.pyc +0 -0
  3. simo/core/__pycache__/api_auth.cpython-38.pyc +0 -0
  4. simo/core/__pycache__/apps.cpython-38.pyc +0 -0
  5. simo/core/__pycache__/controllers.cpython-38.pyc +0 -0
  6. simo/core/__pycache__/dynamic_settings.cpython-38.pyc +0 -0
  7. simo/core/__pycache__/middleware.cpython-38.pyc +0 -0
  8. simo/core/__pycache__/models.cpython-38.pyc +0 -0
  9. simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
  10. simo/core/__pycache__/socket_consumers.cpython-38.pyc +0 -0
  11. simo/core/__pycache__/storage.cpython-38.pyc +0 -0
  12. simo/core/api.py +0 -1
  13. simo/core/api_auth.py +6 -3
  14. simo/core/apps.py +1 -1
  15. simo/core/middleware.py +0 -6
  16. simo/core/migrations/0024_alter_instance_device_report_history_days.py +18 -0
  17. simo/core/migrations/__pycache__/0024_alter_instance_device_report_history_days.cpython-38.pyc +0 -0
  18. simo/core/serializers.py +1 -1
  19. simo/core/socket_consumers.py +0 -4
  20. simo/core/storage.py +2 -14
  21. simo/core/utils/__pycache__/api.cpython-38.pyc +0 -0
  22. simo/core/utils/api.py +35 -0
  23. simo/fleet/__pycache__/routing.cpython-38.pyc +0 -0
  24. simo/fleet/__pycache__/socket_consumers.cpython-38.pyc +0 -0
  25. simo/notifications/utils.py +4 -1
  26. simo/settings.py +1 -2
  27. simo/users/__pycache__/admin.cpython-38.pyc +0 -0
  28. simo/users/__pycache__/api.cpython-38.pyc +0 -0
  29. simo/users/__pycache__/auth_backends.cpython-38.pyc +0 -0
  30. simo/users/__pycache__/middleware.cpython-38.pyc +0 -0
  31. simo/users/__pycache__/models.cpython-38.pyc +0 -0
  32. simo/users/__pycache__/serializers.cpython-38.pyc +0 -0
  33. simo/users/__pycache__/utils.cpython-38.pyc +0 -0
  34. simo/users/admin.py +11 -4
  35. simo/users/api.py +32 -34
  36. simo/users/auth_backends.py +44 -2
  37. simo/users/middleware.py +1 -2
  38. simo/users/migrations/0023_auto_20240105_0719.py +27 -0
  39. simo/users/migrations/__pycache__/0023_auto_20240105_0719.cpython-38.pyc +0 -0
  40. simo/users/models.py +29 -13
  41. simo/users/serializers.py +14 -5
  42. simo/users/utils.py +5 -4
  43. {simo-1.7.5.dist-info → simo-1.7.7.dist-info}/METADATA +1 -1
  44. {simo-1.7.5.dist-info → simo-1.7.7.dist-info}/RECORD +47 -39
  45. {simo-1.7.5.dist-info → simo-1.7.7.dist-info}/LICENSE.md +0 -0
  46. {simo-1.7.5.dist-info → simo-1.7.7.dist-info}/WHEEL +0 -0
  47. {simo-1.7.5.dist-info → simo-1.7.7.dist-info}/top_level.txt +0 -0
Binary file
Binary file
Binary file
Binary file
simo/core/api.py CHANGED
@@ -222,7 +222,6 @@ class ComponentHistoryViewSet(InstanceMixin, viewsets.ReadOnlyModelViewSet):
222
222
  def get_queryset(self):
223
223
  qs = ComponentHistory.objects.filter(
224
224
  component__zone__instance=self.instance,
225
- component__show_in_app=True
226
225
  )
227
226
  if self.request.user.is_superuser:
228
227
  return qs
simo/core/api_auth.py CHANGED
@@ -10,10 +10,13 @@ class SecretKeyAuth(BasicAuthentication):
10
10
  secret_key = request.META.get('HTTP_SECRET')
11
11
  if secret_key:
12
12
  user = User.objects.filter(
13
- secret_key=secret_key, is_active=True
13
+ secret_key=secret_key
14
14
  ).first()
15
- if user:
16
- return (user, None)
15
+
16
+ if not user or not user.is_active:
17
+ return
18
+
19
+ return (user, None)
17
20
 
18
21
  def authenticate_header(self, request):
19
22
  return "None"
simo/core/apps.py CHANGED
@@ -15,7 +15,7 @@ class CoreAppConfig(AppConfig):
15
15
  os.chmod(auto_update_file_path, st.st_mode | 0o111)
16
16
 
17
17
  executable_path = '/usr/local/bin/simo-auto-update'
18
- if os.geteuid() == 0 and not os.path.exists(executable_path):
18
+ if os.geteuid() == 0 and not os.path.islink(executable_path):
19
19
  # We are running as root and there is no symbolic link yet made
20
20
  # for auto updates.
21
21
  os.symlink(auto_update_file_path, executable_path)
simo/core/middleware.py CHANGED
@@ -21,12 +21,6 @@ def simo_router_middleware(get_response):
21
21
 
22
22
  request.relay = None
23
23
 
24
- if request.META.get('HTTP_HOST', '').endswith('.simo.io'):
25
- router_prefix = dynamic_settings['core__remote_http']
26
- router_prefix = router_prefix[router_prefix.find('simo.io') + 7:]
27
- set_script_prefix(router_prefix)
28
- request.path = router_prefix + request.path
29
-
30
24
  response = get_response(request)
31
25
 
32
26
  return response
@@ -0,0 +1,18 @@
1
+ # Generated by Django 3.2.9 on 2024-01-05 07:19
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('core', '0023_auto_20231229_1352'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='instance',
15
+ name='device_report_history_days',
16
+ field=models.PositiveIntegerField(default=0, help_text='How many days of user device reports log do we keep? Use 0 if you do not want to keep these logs at all.'),
17
+ ),
18
+ ]
simo/core/serializers.py CHANGED
@@ -109,7 +109,7 @@ class ZoneSerializer(serializers.ModelSerializer):
109
109
  fields = ['id', 'name', 'components']
110
110
 
111
111
  def get_components_qs(self, obj):
112
- qs = obj.components.filter(show_in_app=True)
112
+ qs = obj.components.all()
113
113
  if self.context['request'].user.is_superuser:
114
114
  return qs
115
115
  user = self.context.get('request').user
@@ -34,10 +34,6 @@ class SIMOWebsocketConsumer(WebsocketConsumer):
34
34
  self.headers = {
35
35
  key.decode(): val.decode() for key, val in self.scope['headers']
36
36
  }
37
- if self.headers.get('host').endswith('simo.io'):
38
- router_prefix = dynamic_settings['core__remote_http']
39
- router_prefix = router_prefix[router_prefix.find('simo.io') + 7:]
40
- set_script_prefix(router_prefix)
41
37
 
42
38
 
43
39
  class LogConsumer(AsyncWebsocketConsumer):
simo/core/storage.py CHANGED
@@ -2,25 +2,13 @@ import os
2
2
  from django.contrib.staticfiles.storage import StaticFilesStorage as OrgStaticFilesStorage
3
3
  from django.core.files.storage import FileSystemStorage as OrgFileSystemStorage
4
4
  from django.conf import settings
5
- from simo.core.middleware import get_current_request
6
- from simo.conf import dynamic_settings
7
5
 
8
6
 
9
- class SIMOProxyMixin():
10
-
11
- def url(self, name):
12
- url = super().url(name)
13
- request = get_current_request()
14
- if request and request.META.get('HTTP_HOST', '').endswith('.simo.io'):
15
- return dynamic_settings['core__remote_http'] + url
16
- return url
17
-
18
-
19
- class ProxyingStaticFilesStorage(SIMOProxyMixin, OrgStaticFilesStorage):
7
+ class ProxyingStaticFilesStorage(OrgStaticFilesStorage):
20
8
  pass
21
9
 
22
10
 
23
- class ProxyingFileSystemStorage(SIMOProxyMixin, OrgFileSystemStorage):
11
+ class ProxyingFileSystemStorage(OrgFileSystemStorage):
24
12
  pass
25
13
 
26
14
 
simo/core/utils/api.py ADDED
@@ -0,0 +1,35 @@
1
+ from rest_framework import serializers
2
+
3
+
4
+ class ReadWriteSerializerMethodField(serializers.Field):
5
+ def __init__(self, method_name=None, **kwargs):
6
+ self.method_name = method_name
7
+ kwargs['source'] = '*'
8
+ #kwargs['read_only'] = True
9
+ super(ReadWriteSerializerMethodField, self).__init__(**kwargs)
10
+
11
+ def bind(self, field_name, parent):
12
+ self.field_name = field_name
13
+ # In order to enforce a consistent style, we error if a redundant
14
+ # 'method_name' argument has been used. For example:
15
+ # my_field = serializer.SerializerMethodField(method_name='get_my_field')
16
+ default_method_name = 'get_{field_name}'.format(field_name=field_name)
17
+ assert self.method_name != default_method_name, (
18
+ "It is redundant to specify `%s` on SerializerMethodField '%s' in "
19
+ "serializer '%s', because it is the same as the default method name. "
20
+ "Remove the `method_name` argument." %
21
+ (self.method_name, field_name, parent.__class__.__name__)
22
+ )
23
+
24
+ # The method name should default to `get_{field_name}`.
25
+ if self.method_name is None:
26
+ self.method_name = default_method_name
27
+
28
+ super(ReadWriteSerializerMethodField, self).bind(field_name, parent)
29
+
30
+ def to_representation(self, value):
31
+ method = getattr(self.parent, self.method_name)
32
+ return method(value)
33
+
34
+ def to_internal_value(self, data):
35
+ return {self.field_name: data}
@@ -13,7 +13,10 @@ def notify_users(instance, severity, title, body=None, component=None, users=Non
13
13
  component=component
14
14
  )
15
15
  if not users:
16
- users = User.objects.filter(roles__instnace=instance, is_active=True)
16
+ users = User.objects.filter(
17
+ instance_roles__instnace=instance,
18
+ instance_roles__is_active=True
19
+ )
17
20
  for user in users:
18
21
  if instance not in user.instances:
19
22
  continue
simo/settings.py CHANGED
@@ -144,7 +144,7 @@ AUTH_PASSWORD_VALIDATORS = [
144
144
  ]
145
145
 
146
146
  AUTHENTICATION_BACKENDS = [
147
- 'django.contrib.auth.backends.ModelBackend',
147
+ 'simo.users.auth_backends.SIMOUserBackend',
148
148
  'simo.users.auth_backends.SSOBackend'
149
149
  ]
150
150
 
@@ -269,7 +269,6 @@ LOCATION_FIELD = {
269
269
  'map.provider': 'openstreetmap',
270
270
  'map.zoom': 13,
271
271
  'search.provider': 'nominatim',
272
- 'resources.root_path': '/static/location_field',
273
272
  }
274
273
 
275
274
 
Binary file
Binary file
Binary file
simo/users/admin.py CHANGED
@@ -78,7 +78,7 @@ class UserAdmin(OrgUserAdmin):
78
78
  list_display = (
79
79
  'name_display', 'email', 'roles_display', 'is_master', 'is_active'
80
80
  )
81
- list_filter = ('is_master', 'is_active', )
81
+ list_filter = ('is_master', )
82
82
  search_fields = ('name', 'email')
83
83
  ordering = ('name', 'email')
84
84
  filter_horizontal = ()
@@ -90,7 +90,7 @@ class UserAdmin(OrgUserAdmin):
90
90
  )
91
91
  readonly_fields = (
92
92
  'name', 'email', 'avatar',
93
- 'last_action', 'ssh_key',
93
+ 'last_action', 'ssh_key', 'is_active'
94
94
  )
95
95
  inlines = UserDeviceInline, InstanceUserInline
96
96
 
@@ -134,14 +134,21 @@ admin.site.unregister(Group)
134
134
  @admin.register(UserDeviceReportLog)
135
135
  class UserDeviceLogInline(admin.ModelAdmin):
136
136
  model = UserDeviceReportLog
137
- readonly_fields = 'datetime', 'app_open', 'location', 'relay'
138
- list_display = 'datetime', 'app_open', 'location', 'relay'
137
+ readonly_fields = 'datetime', 'app_open', 'location', 'relay', 'user'
138
+ list_display = 'datetime', 'app_open', 'location', 'relay', 'user'
139
139
  fields = readonly_fields
140
140
  list_filter = 'user_device__user',
141
141
 
142
142
  def has_add_permission(self, request, obj=None):
143
143
  return False
144
144
 
145
+ def user(self, obj):
146
+ return mark_safe(
147
+ f'<a href="{obj.user_device.user.get_admin_url()}">'
148
+ f'{obj.user_device.user}'
149
+ f'</a>'
150
+ )
151
+
145
152
  def get_queryset(self, request):
146
153
  qs = super().get_queryset(request)
147
154
  if request.user.is_master:
simo/users/api.py CHANGED
@@ -1,3 +1,4 @@
1
+ import sys
1
2
  from rest_framework import viewsets, mixins, status
2
3
  from rest_framework.serializers import Serializer
3
4
  from rest_framework.decorators import action
@@ -8,6 +9,7 @@ from django.utils import timezone
8
9
  from simo.core.api import InstanceMixin
9
10
  from .models import (
10
11
  User, UserDevice, UserDeviceReportLog, PermissionsRole, InstanceInvitation,
12
+ InstanceUser
11
13
  )
12
14
  from .serializers import (
13
15
  UserSerializer, PermissionsRoleSerializer, InstanceInvitationSerializer
@@ -47,10 +49,9 @@ class UsersViewSet(mixins.RetrieveModelMixin,
47
49
  user_role = request.user.get_role(self.instance)
48
50
  if not request.user.is_superuser:
49
51
  if not user_role or not user_role.can_manage_users:
50
- raise ValidationError(
51
- 'You are not allowed to change this!',
52
- code=403
53
- )
52
+ msg = 'You are not allowed to change this!'
53
+ print(msg, file=sys.stderr)
54
+ raise ValidationError(msg, code=403)
54
55
 
55
56
  serializer = self.get_serializer(
56
57
  user, data=request.data, partial=partial
@@ -58,39 +59,36 @@ class UsersViewSet(mixins.RetrieveModelMixin,
58
59
  try:
59
60
  serializer.is_valid(raise_exception=True)
60
61
  except Exception as e:
62
+ print(e, file=sys.stderr)
61
63
  raise ValidationError(str(e), code=403)
62
64
 
63
-
64
-
65
-
66
65
  try:
67
- set_role_to = PermissionsRole.objects.get(id=request.data.get('role'))
68
- except Exception as e:
69
- raise ValidationError(e, code=403)
70
-
71
- if set_role_to.is_superuser:
72
- if not request.user.is_superuser:
73
- if not user_role or not user_role.is_superuser:
74
- raise ValidationError(
75
- "You are not allowed to grant superuser roles to others "
76
- "if you are not a superuser yourself.",
77
- code=403
78
- )
79
-
80
- if user == request.user \
81
- and user_role and user_role.is_superuser \
82
- and not set_role_to.is_superuser:
83
- # User is trying to downgrade his own role from
84
- # superuser to something lower, we must make sure
85
- # there is at least one user left that has superuser role on this instance.
86
- if not User.objects.filter(
87
- roles__instance=self.instance, roles__is_superuser=True
88
- ).exclude(id=user.id).values('id').first():
89
- raise ValidationError(
90
- "You are the only one superuser on this instance, "
91
- "therefore you are not alowed to downgrade your role.",
92
- code=403
93
- )
66
+ set_role_to = PermissionsRole.objects.get(
67
+ pk=request.data.get('role')
68
+ )
69
+ except:
70
+ pass
71
+ else:
72
+ if set_role_to != user.get_role(self.instance) and set_role_to.is_superuser \
73
+ and not user_role.is_superuser:
74
+ msg = "You are not allowed to grant superuser roles to others " \
75
+ "if you are not a superuser yourself."
76
+ print(msg, file=sys.stderr)
77
+ raise ValidationError(msg, code=403)
78
+
79
+ if user == request.user \
80
+ and user_role and user_role.is_superuser \
81
+ and not set_role_to.is_superuser:
82
+ # User is trying to downgrade his own role from
83
+ # superuser to something lower, we must make sure
84
+ # there is at least one user left that has superuser role on this instance.
85
+ if not User.objects.filter(
86
+ roles__instance=self.instance, roles__is_superuser=True
87
+ ).exclude(id=user.id).values('id').first():
88
+ msg = "You are the only one superuser on this instance, " \
89
+ "therefore you are not alowed to downgrade your role."
90
+ print(msg, file=sys.stderr)
91
+ raise ValidationError(msg, code=403)
94
92
 
95
93
  self.perform_update(serializer)
96
94
 
@@ -1,12 +1,54 @@
1
1
  import os
2
2
  import io
3
3
  import requests
4
- from django.core.files import File
5
- from django.contrib.auth.backends import ModelBackend
6
4
  from django.utils import timezone
5
+ from django.contrib.auth import get_user_model
6
+ from django.contrib.auth.models import Permission
7
+ from django.db.models import Exists, OuterRef, Q
8
+ from django.contrib.auth.backends import ModelBackend
7
9
  from .models import User, InstanceInvitation, InstanceUser
8
10
 
9
11
 
12
+
13
+ class SIMOUserBackend(ModelBackend):
14
+
15
+ def with_perm(self, perm, is_active=True, include_superusers=True, obj=None):
16
+ """
17
+ Return users that have permission "perm". By default, filter out
18
+ inactive users and include superusers.
19
+ """
20
+ if isinstance(perm, str):
21
+ try:
22
+ app_label, codename = perm.split('.')
23
+ except ValueError:
24
+ raise ValueError(
25
+ 'Permission name should be in the form '
26
+ 'app_label.permission_codename.'
27
+ )
28
+ elif not isinstance(perm, Permission):
29
+ raise TypeError(
30
+ 'The `perm` argument must be a string or a permission instance.'
31
+ )
32
+
33
+ UserModel = get_user_model()
34
+ if obj is not None:
35
+ return UserModel._default_manager.none()
36
+
37
+ permission_q = Q(group__user=OuterRef('pk')) | Q(user=OuterRef('pk'))
38
+ if isinstance(perm, Permission):
39
+ permission_q &= Q(pk=perm.pk)
40
+ else:
41
+ permission_q &= Q(codename=codename, content_type__app_label=app_label)
42
+
43
+ user_q = Exists(Permission.objects.filter(permission_q))
44
+ if include_superusers:
45
+ user_q |= Q(is_superuser=True)
46
+ if is_active is not None:
47
+ user_q &= Q(instance_roles__is_active=is_active).distinct()
48
+
49
+ return UserModel._default_manager.filter(user_q)
50
+
51
+
10
52
  # TODO: get explanation when user tries to log in to admin but is unable to, because of lack of permissions on his role
11
53
  # TODO: allow for additional checkups if somebody would like to implement
12
54
 
simo/users/middleware.py CHANGED
@@ -29,5 +29,4 @@ class IntroduceUser:
29
29
  response = self.get_response(request)
30
30
  if request.user.is_authenticated:
31
31
  introduce(request.user)
32
- return response
33
-
32
+ return response
@@ -0,0 +1,27 @@
1
+ # Generated by Django 3.2.9 on 2024-01-05 07:19
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('users', '0022_userdevicereportlog_instance'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.RemoveField(
14
+ model_name='user',
15
+ name='is_active',
16
+ ),
17
+ migrations.AddField(
18
+ model_name='instanceuser',
19
+ name='is_active',
20
+ field=models.BooleanField(db_index=True, default=True),
21
+ ),
22
+ migrations.AlterField(
23
+ model_name='instanceuser',
24
+ name='at_home',
25
+ field=models.BooleanField(db_index=True, default=False),
26
+ ),
27
+ ]
simo/users/models.py CHANGED
@@ -82,7 +82,8 @@ class InstanceUser(DirtyFieldsMixin, models.Model, OnChangeMixin):
82
82
  'core.Instance', on_delete=models.CASCADE, null=True
83
83
  )
84
84
  role = models.ForeignKey(PermissionsRole, on_delete=models.CASCADE)
85
- at_home = models.BooleanField(default=False)
85
+ at_home = models.BooleanField(default=False, db_index=True)
86
+ is_active = models.BooleanField(default=True, db_index=True)
86
87
 
87
88
  class Meta:
88
89
  unique_together = 'user', 'instance'
@@ -124,15 +125,6 @@ class User(AbstractBaseUser, SimoAdminMixin):
124
125
  avatar_url = models.URLField(null=True, blank=True)
125
126
  avatar_last_change = models.DateTimeField(auto_now_add=True)
126
127
  roles = models.ManyToManyField(PermissionsRole, through=InstanceUser)
127
- # TODO: MOVE to InstanceUser object!
128
- is_active = models.BooleanField(
129
- _('active'),
130
- default=True,
131
- help_text=_(
132
- 'Designates whether this user should be treated as active. '
133
- 'Unselect this instead of deleting accounts.'
134
- ),
135
- )
136
128
  is_master = models.BooleanField(
137
129
  default=False,
138
130
  help_text="Has access to everything "
@@ -199,7 +191,7 @@ class User(AbstractBaseUser, SimoAdminMixin):
199
191
  return obj
200
192
 
201
193
  def can_ssh(self):
202
- return self.is_active and self.ssh_key and self.is_superuser
194
+ return self.is_active and self.ssh_key and self.is_master
203
195
 
204
196
  def get_role(self, instance):
205
197
  for role in self.roles.all():
@@ -245,12 +237,14 @@ class User(AbstractBaseUser, SimoAdminMixin):
245
237
  from simo.core.models import Instance
246
238
 
247
239
  self._instances = set()
240
+ if not self.is_active:
241
+ return self._instance
248
242
  if self.is_master:
249
243
  self._instances = set(Instance.objects.all())
250
244
  return self._instances
251
245
 
252
- for role in self.roles.all():
253
- self._instances.add(role.instance)
246
+ for instance_role in self.instance_roles.filter(is_active=True):
247
+ self._instances.add(instance_role.instance)
254
248
  return self._instances
255
249
 
256
250
  @property
@@ -259,6 +253,28 @@ class User(AbstractBaseUser, SimoAdminMixin):
259
253
  role__in=self.roles.all()
260
254
  )
261
255
 
256
+ @property
257
+ def is_active(self):
258
+ if self._instance:
259
+ return bool(
260
+ self.instance_roles.filter(
261
+ instance=self._instance, is_active=True
262
+ ).first()
263
+ )
264
+ return bool(
265
+ self.instance_roles.filter(is_active=True).first()
266
+ )
267
+
268
+ @is_active.setter
269
+ def is_active(self, val):
270
+ if not self._instance:
271
+ return
272
+ self.instance_roles.filter(
273
+ instance=self._instance
274
+ ).update(is_active=bool(val))
275
+ rebuild_authorized_keys()
276
+
277
+
262
278
  @property
263
279
  def is_superuser(self):
264
280
  if self.is_master:
simo/users/serializers.py CHANGED
@@ -1,15 +1,18 @@
1
1
  from rest_framework import serializers
2
2
  from collections.abc import Iterable
3
3
  from simo.core.middleware import get_current_request
4
- from simo.core.serializers import TimestampField
5
- from easy_thumbnails.files import get_thumbnailer
4
+ from simo.core.utils.api import ReadWriteSerializerMethodField
6
5
  from .models import User, PermissionsRole, InstanceInvitation, InstanceUser
7
6
 
8
7
 
8
+
9
+
10
+
9
11
  class UserSerializer(serializers.ModelSerializer):
10
12
  avatar = serializers.SerializerMethodField()
11
13
  role = serializers.IntegerField(source='role_id')
12
14
  at_home = serializers.SerializerMethodField()
15
+ is_active = ReadWriteSerializerMethodField()
13
16
 
14
17
  def __init__(self, *args, **kwargs):
15
18
  super().__init__(*args, **kwargs)
@@ -29,6 +32,9 @@ class UserSerializer(serializers.ModelSerializer):
29
32
  'id', 'email', 'name', 'avatar', 'at_home', 'last_action', 'ssh_key'
30
33
  )
31
34
 
35
+ def get_is_active(self, obj):
36
+ return obj.is_active
37
+
32
38
  def get_avatar(self, obj):
33
39
  if obj.avatar:
34
40
  url = obj.avatar['avatar'].url
@@ -42,9 +48,12 @@ class UserSerializer(serializers.ModelSerializer):
42
48
  return None
43
49
 
44
50
  def get_at_home(self, obj):
45
- return InstanceUser.objects.filter(
46
- user=obj
47
- ).first().at_home
51
+ iu = InstanceUser.objects.filter(
52
+ user=obj, instance=obj._instance
53
+ ).first()
54
+ if iu:
55
+ return iu.at_home
56
+ return False
48
57
 
49
58
 
50
59
 
simo/users/utils.py CHANGED
@@ -1,4 +1,5 @@
1
-
1
+ import sys
2
+ import traceback
2
3
 
3
4
 
4
5
  def get_system_user():
@@ -26,10 +27,10 @@ def rebuild_authorized_keys():
26
27
  try:
27
28
  with open('/root/.ssh/authorized_keys', 'w') as keys_file:
28
29
  for user in User.objects.filter(
29
- ssh_key__isnull=False, is_active=True
30
+ ssh_key__isnull=False
30
31
  ):
31
- if user.is_superuser:
32
+ if user.is_active and user.is_master:
32
33
  keys_file.write(user.ssh_key + '\n')
33
34
  except:
34
- # Simply do not do this if this installation does not have root permissions.
35
+ print(traceback.format_exc(), file=sys.stderr)
35
36
  pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 1.7.5
3
+ Version: 1.7.7
4
4
  Summary: Smart Home on Steroids!
5
5
  Author-email: Simanas Venčkauskas <simanas@simo.io>
6
6
  Project-URL: Homepage, https://simo.io
@@ -5,13 +5,13 @@ simo/celeryc.py,sha256=eab7_e9rw0c__DCeoUFUh_tjAGVlulxVrk75BaJf57Q,1512
5
5
  simo/cli.py,sha256=kB1dhZ30Pnq7mDawWGbX5WnCuoZ6qNMcnWH-c8XxcaU,2233
6
6
  simo/conf.py,sha256=H2BhXAV8MEDVXF8AbkaLSfR4ULd-9_bS4bnhE5sE5fg,112
7
7
  simo/scripting.py,sha256=PVIkGsiMDWj4CNTbOM3rq7pJ6ruavuns-ZMU7VudLa4,923
8
- simo/settings.py,sha256=IdLLN5oS0IkiXVPbulVyh8UNpyHcsB4D8dWvO5fpUtE,6845
8
+ simo/settings.py,sha256=pMT2rdYKNpvXLxBFNWbqnRNkw8eVCW28u6DbI05AibM,6791
9
9
  simo/urls.py,sha256=cmegi8VcNCq22k9v2rUYWDEcr2_ND2YQFUvpzISK7y0,2553
10
10
  simo/__pycache__/__init__.cpython-38.pyc,sha256=j81de0BqHMr6bs0C7cuYrXl7HwtK_vv8hDEtAdSwDJc,153
11
11
  simo/__pycache__/asgi.cpython-38.pyc,sha256=bOdmI-G4socquYp4aZk2H-v5JSPcjKrGgPjEodme7NQ,845
12
12
  simo/__pycache__/celeryc.cpython-38.pyc,sha256=eSRoaKwfYlxVaxAiwqpQ2ndEcx7W-VpZtbxRFSV8UYg,1653
13
13
  simo/__pycache__/conf.cpython-38.pyc,sha256=MYP2yk3ULxiYwZsZR6tCLjKnU-z03A3avzQzIn66y3k,273
14
- simo/__pycache__/settings.cpython-38.pyc,sha256=QowRD442apMvCqMWnwZ9IyJ0KgbZd3xoHJrouAUxVYA,6090
14
+ simo/__pycache__/settings.cpython-38.pyc,sha256=lyN4n0YWf5paUvhBHZwAeg2TB2iqCjSuc5uxSZjxZLM,6040
15
15
  simo/__pycache__/urls.cpython-38.pyc,sha256=_jjBuEJRAf7oXHOqt3MUElK2-uaYRL2jWK7l2StnUhQ,2210
16
16
  simo/_hub_template/hub/asgi.py,sha256=ElN_fdeSkf0Ysa7pS9rJVmZ1HmLhFxb8jFaMLqe1220,126
17
17
  simo/_hub_template/hub/celeryc.py,sha256=3ksDXftIZKJ4Cq9WNKJERdZdQlDEnjTQXycweRFmsSQ,27
@@ -22,10 +22,10 @@ simo/_hub_template/hub/supervisor.conf,sha256=IY3fdK0fDD2eAothB0n54xhjQj8LYoXIR9
22
22
  simo/_hub_template/hub/urls.py,sha256=Ydm-1BkYAzWeEF-MKSDIFf-7aE4qNLPm48-SA51XgJQ,25
23
23
  simo/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  simo/core/admin.py,sha256=4l2XFoI9yUoOuQkyYdpwxt-PGj-VTVcMb-BiA_NHYok,16588
25
- simo/core/api.py,sha256=9ZwomVaScdRFbV3rbPSCam5JZkgHDfMrMTR9P-3VBn4,19140
26
- simo/core/api_auth.py,sha256=8Pp6Rcn3aL5hpQpW2Ph5XZ1rWnN1MIFvium8zlbzSwQ,1108
25
+ simo/core/api.py,sha256=fJ9GcwepOFN_kTLBNQPSfbIht2px7QUS3BUj93PQ2NM,19100
26
+ simo/core/api_auth.py,sha256=2MRmCid_Fy67chKiJEt6_UaJZmb1PDF8KdbBlkA7YgU,1139
27
27
  simo/core/app_widgets.py,sha256=SP1txwI8_robAapIjalciS1cnJGoPH6udi6-k3fGC-g,1928
28
- simo/core/apps.py,sha256=T41TluDrtjzZ8T5LcvA5OnImmn08HB9tXk1SkZ52k3I,899
28
+ simo/core/apps.py,sha256=n9xwxFO5R3VCOvEPCjqfw3C9lJCzG1gXuHvjSPHKWj8,899
29
29
  simo/core/auto_urls.py,sha256=YZcvHqmAs4_azA_F_yz3CBsxrHAGijOPHib3SJCAoR0,1089
30
30
  simo/core/autocomplete_views.py,sha256=ygbVEOfyygWNy2BanB46Ov0NfWxBFAwwKp5CqAkrGMc,3849
31
31
  simo/core/base_types.py,sha256=OkRoAHp8P3r79k3IlUzkhycqlHDkeq7AAhOgsz7qGz8,552
@@ -37,14 +37,14 @@ simo/core/filters.py,sha256=ghtOZcrwNAkIyF5_G9Sn73NkiI71mXv0NhwCk4IyMIM,411
37
37
  simo/core/forms.py,sha256=s-Cjw--vibCmxk6IQ_4M5IQOMuE3Z8re75NFPPmi4O4,19735
38
38
  simo/core/gateways.py,sha256=VkfKixXXEpjdU_cIYvev_sdz4menoMeJMFEElrsp7kE,2659
39
39
  simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
40
- simo/core/middleware.py,sha256=2EELD2mMWpPl3ispu2Yl7zeXUZp7s-PAJm-W-3BRsF0,1565
40
+ simo/core/middleware.py,sha256=VKt9OBYU2o8BUjc5MESjt2vx_HixwprozmCRkAQDwZI,1252
41
41
  simo/core/models.py,sha256=Gbiw6ZrjuriPZmEQ-ijdZ8VWshTGyjSTcek37CuzWWs,18105
42
42
  simo/core/permissions.py,sha256=1GI59JZxl_sL9qzSt2uhoOnYnORDmcOJ8Fb37LbrhJE,576
43
43
  simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
44
- simo/core/serializers.py,sha256=IX5Lnhq6v8tYVFysz7w5K7QelK3fVXOjTUMjuomzbBs,4200
44
+ simo/core/serializers.py,sha256=styX6kt-h4k3GNu31RWEYIJ7I-u6BGRLfC0zhrtYV-U,4181
45
45
  simo/core/signal_receivers.py,sha256=b9tWEag3f5HepWqUJZvZi6ag1fxHQo0gECe_NLT9Z8A,3286
46
- simo/core/socket_consumers.py,sha256=dvYR5QlWt3OP2N7qJa8Uy5WcaGhlYODRZvQKlCdKyzU,9722
47
- simo/core/storage.py,sha256=46x-20HXGa-_gHUBFZYYL72FoR3jjOaYt-i7QDHezzM,981
46
+ simo/core/socket_consumers.py,sha256=BCCTFsS2Btn4vuhcfQrNss4O41jIR74_C0HvWWLmNoU,9476
47
+ simo/core/storage.py,sha256=YlxmdRs-zhShWtFKgpJ0qp2NDBuIkJGYC1OJzqkbttQ,572
48
48
  simo/core/tasks.py,sha256=TSMI2jijUxXqQ9AwamLFc1wGFcR_qLw13kfW4kYf9II,10330
49
49
  simo/core/todos.py,sha256=eYVXfLGiapkxKK57XuviSNe3WsUYyIWZ0hgQJk7ThKo,665
50
50
  simo/core/types.py,sha256=WJEq48mIbFi_5Alt4wxWMGXxNxUTXqfQU5koH7wqHHI,1108
@@ -55,17 +55,17 @@ simo/core/__pycache__/__init__.cpython-38.pyc,sha256=676XXJyBoy6cU0PWeGuTWqayJLA
55
55
  simo/core/__pycache__/admin.cpython-37.pyc,sha256=ASE0cHkHYkC2GL3geCCixJP31r9AqY0XnRFltItcbYM,1694
56
56
  simo/core/__pycache__/admin.cpython-38.pyc,sha256=ZgDx7HuLwuV_9j6xEx090AU1-35jiA-0zHlAmIdpY1Y,13199
57
57
  simo/core/__pycache__/api.cpython-37.pyc,sha256=srtJhR4q9LU9VmVxkTC2YgjBiqFvSWytHmQiX9W897c,1780
58
- simo/core/__pycache__/api.cpython-38.pyc,sha256=t-0t7pplyTWRN1GlIPvQBvh5DY-nCwQw1qi_E8U9afU,14496
59
- simo/core/__pycache__/api_auth.cpython-38.pyc,sha256=mQsSPdBvBw0kCNMtJZ_o9bTleXk-gngEnQ1pWzWlB-I,1612
58
+ simo/core/__pycache__/api.cpython-38.pyc,sha256=9PImByz3e23ERGfvA8qlvDAI5DxSovHYn4RjDYy40XI,14466
59
+ simo/core/__pycache__/api_auth.cpython-38.pyc,sha256=Df2nEIBP9BU4XB3NxlI335eIYOXjG6rjfLWQR-Jki7k,1627
60
60
  simo/core/__pycache__/app_widgets.cpython-38.pyc,sha256=4oI7IrXxPx2esGzEpAGikyJlDYYYtLaQK4yeBQHRqlA,3290
61
- simo/core/__pycache__/apps.cpython-38.pyc,sha256=2szKkN6MYXOIZlo58BoD4HI-aQZDS0hleJR7wiMx0Hk,1024
61
+ simo/core/__pycache__/apps.cpython-38.pyc,sha256=uFHWsWapjKK5b4F3Cipkym0MG3LAUV0xJoOBT26jMFo,1024
62
62
  simo/core/__pycache__/auto_urls.cpython-38.pyc,sha256=LmdNUMSWfwNXzyoxG4Ki82B6tegLSHn1ethfnPSRR5Y,836
63
63
  simo/core/__pycache__/autocomplete_views.cpython-38.pyc,sha256=Rrrx6jwbhYDa9sU1eia9xBuTx-0H4F1aBsMvrK8cIz0,3861
64
64
  simo/core/__pycache__/base_types.cpython-38.pyc,sha256=LyaOjfDh0ZQNUbYNoJwOAyeBOy1qoEyBvdV0aYV8w7E,693
65
65
  simo/core/__pycache__/context.cpython-38.pyc,sha256=Dq_Z-4U7ppQhu8T-7kqu7LjT6DgbRI9bWbQ17rwX-Us,1184
66
66
  simo/core/__pycache__/controllers.cpython-37.pyc,sha256=18C2XXXvrzaipTVWRx_KFDHP5TmeWM-xnTnqVkzy8as,1663
67
- simo/core/__pycache__/controllers.cpython-38.pyc,sha256=eiTXqx3QmLmJFAqBXWVJNcObdLUJCYO1_AdzG1zM0uQ,21094
68
- simo/core/__pycache__/dynamic_settings.cpython-38.pyc,sha256=rp50E_VjAghZCSMIOqVukWPB59GN-SdcW2REoqyiMjg,2762
67
+ simo/core/__pycache__/controllers.cpython-38.pyc,sha256=VCIh1IJHncVUYMoAPy22JJcpCh4-1AgN1S9Ixh_HoFQ,21094
68
+ simo/core/__pycache__/dynamic_settings.cpython-38.pyc,sha256=2m1IfhIWR47mp9zfNtQBnLktN0ZAccxIdfCuTj7SSnI,2544
69
69
  simo/core/__pycache__/events.cpython-37.pyc,sha256=E17-McBIoKrqwv1Qjh0WaVKYvcL-xzGRXvCg70uRUgs,3154
70
70
  simo/core/__pycache__/events.cpython-38.pyc,sha256=GoIg6o5VUR65fCtFw5sw_e3Yls5WErGtufxwAij7wLE,6415
71
71
  simo/core/__pycache__/filters.cpython-38.pyc,sha256=d2yr0vEtbHsi5L4dysiRz4_m3Zz6ZMGV569mJTzB9Ro,713
@@ -74,17 +74,17 @@ simo/core/__pycache__/forms.cpython-38.pyc,sha256=5N-umEqnAyIh5gYYLLLKAT-uWlDRFF
74
74
  simo/core/__pycache__/gateways.cpython-37.pyc,sha256=-0BwLaNeUv5eWJXouios9-746fTajYUoXscti5FnaG0,593
75
75
  simo/core/__pycache__/gateways.cpython-38.pyc,sha256=AO71NeMeeuJyTI0Nt1tuHT1ijQ_NbSJ6IpuLKfpzHpY,3681
76
76
  simo/core/__pycache__/loggers.cpython-38.pyc,sha256=Z-cdQnC6XlIonPV4Sl4E52tP4NMEdPAiHK0cFaIL7I8,1623
77
- simo/core/__pycache__/middleware.cpython-38.pyc,sha256=i2OcsCi2T8IYydgzWPjcWOxTP95iKkJ053EYTqpt_u8,1672
77
+ simo/core/__pycache__/middleware.cpython-38.pyc,sha256=vRjRp2hUrMLNvP2dExBVpP4T7wa6owWPCJbq5jPqY00,1480
78
78
  simo/core/__pycache__/models.cpython-37.pyc,sha256=kJ1wVtRlrDNAD6svKaiDTNRx7d4t5ect_hsDgpgzb0M,4240
79
- simo/core/__pycache__/models.cpython-38.pyc,sha256=JIMCA9OHwNq_0mWFUwmOw_4_P2pG1cjGUafdUHYu8j8,15879
79
+ simo/core/__pycache__/models.cpython-38.pyc,sha256=k4YWXy7UoBD4sPW1pWQVou1PCdgopRb-Qm5se_hlc8I,15936
80
80
  simo/core/__pycache__/permissions.cpython-38.pyc,sha256=BBstKtFelsJz8oTC3b3M2Z2XUi7cYFjnBaTuvcRraoo,850
81
81
  simo/core/__pycache__/routing.cpython-38.pyc,sha256=SnHuviYlYSp1pBON71-14yWa4jg5GDo8ksjfS5n1Gmk,591
82
82
  simo/core/__pycache__/scripts.cpython-37.pyc,sha256=aVttBA4V6xl6hwaFNbhIp45VbP0wId0vIC6iTvvw7iQ,613
83
83
  simo/core/__pycache__/serializers.cpython-37.pyc,sha256=SraS2BK9PTfrSXZGE7IeT6VvnuYDxrONwuDPba2Vcz8,3129
84
- simo/core/__pycache__/serializers.cpython-38.pyc,sha256=_rcAia752qq8wNEjVrmYentCCVrkVLEwqTg5Xd5DDy0,5760
84
+ simo/core/__pycache__/serializers.cpython-38.pyc,sha256=MhbEoC3bxpiqJc2iPmZRKnlclRdVWiwCLn6baoXNfXQ,5762
85
85
  simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=R9CYfFMykVnigiav4MHIdlJX91hoaapwDSEMMm49K84,3240
86
- simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=UBmrkLeTNmI8PqAb673sDeP6w4oggvYbBc8EGtbsGdo,8580
87
- simo/core/__pycache__/storage.cpython-38.pyc,sha256=C2i_kW0hOQCQ5xgiiW8Om5Q3cqQ0EVEHEH1qy8yJxVg,1672
86
+ simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=TlcvM98STpej8CBSM66qGL--d2UHxGtAT5Lrv6WApqA,8432
87
+ simo/core/__pycache__/storage.cpython-38.pyc,sha256=BTkYH8QQyjqI0WOtJC8fHNtgu0YA1vjqZclXjC2vCVI,1116
88
88
  simo/core/__pycache__/tasks.cpython-38.pyc,sha256=gotoqS3HwCkiNaJI5H4yUTcmZy8RMWG_607yzvGSvWo,7678
89
89
  simo/core/__pycache__/todos.cpython-38.pyc,sha256=CkHQ6v8gmynr83KQsJY6VPR3OnLZnHvVCX5R1Dr8J9Q,245
90
90
  simo/core/__pycache__/views.cpython-38.pyc,sha256=I75ChNeoySYr2uXV0PScwpVWsOoPpyzP9cHKkTJfWAc,3825
@@ -126,6 +126,7 @@ simo/core/migrations/0020_component_meta.py,sha256=aO3qKCRZoAkdKIbRBDlN3H0YaOJmA
126
126
  simo/core/migrations/0021_auto_20231020_1041.py,sha256=OmXoVeWfb8HPvGlP0iC1ZYqByj7pI4T6L2-lEsmbfSQ,998
127
127
  simo/core/migrations/0022_auto_20231221_0735.py,sha256=XR4rfCHy6_oZkybvzcba_Oxx8HST-vSCKy8pPVxX8cs,23525
128
128
  simo/core/migrations/0023_auto_20231229_1352.py,sha256=TuCDRtgmFDLW7e1oIs_3Ndxn-ub2rV87VAzZ_1U0bwQ,1267
129
+ simo/core/migrations/0024_alter_instance_device_report_history_days.py,sha256=CqCWl3GQNeFnNMr0hfdlQG9LcXbN9dILqxw0peHVihs,530
129
130
  simo/core/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
131
  simo/core/migrations/__pycache__/0001_initial.cpython-38.pyc,sha256=ftWpf_RgprbqNo_syjYdeblvFH5nIEc87XEpdi1INHo,5373
131
132
  simo/core/migrations/__pycache__/0002_load_icons.cpython-38.pyc,sha256=gYV4sH0cXffvNtVyFgRQQ1A4I5DeIRnZX9eUrTpEhlk,2115
@@ -150,6 +151,7 @@ simo/core/migrations/__pycache__/0020_component_meta.cpython-38.pyc,sha256=haKPo
150
151
  simo/core/migrations/__pycache__/0021_auto_20231020_1041.cpython-38.pyc,sha256=pFAkPZKdwLI20vkA_p-w5913gRgKVCXDYYmYZweor5k,1151
151
152
  simo/core/migrations/__pycache__/0022_auto_20231221_0735.cpython-38.pyc,sha256=RvnYOHFuY8siQ69Fed3oHoXbiF17Vr54YXRYyJFwp-4,16477
152
153
  simo/core/migrations/__pycache__/0023_auto_20231229_1352.cpython-38.pyc,sha256=NYA0kVuQGWjz2epoLH0XG7FgyaC6JXW28J18bjRAqCk,1281
154
+ simo/core/migrations/__pycache__/0024_alter_instance_device_report_history_days.cpython-38.pyc,sha256=ALrhitBQRd-y9Ragwa0_ZuJ9DDkUIgw72A0CZpWznmE,777
153
155
  simo/core/migrations/__pycache__/__init__.cpython-38.pyc,sha256=a0yc0qWaV-D5f64GdcpP54haEDBzwmAWRGyErHeHztU,161
154
156
  simo/core/static/ansi_styles.css,sha256=4ieJGrjZPKyPSago9FdB_gflHoGE1vxCHi8qVn5tY-Y,37352
155
157
  simo/core/static/admin/Img/plus.svg,sha256=2NpSFPWqGIjpAQGFI7LDQHPKagEhYkJiJX95ufCoZaI,741
@@ -10077,6 +10079,7 @@ simo/core/templatetags/__pycache__/__init__.cpython-38.pyc,sha256=EvOF3sr89atapI
10077
10079
  simo/core/templatetags/__pycache__/components_list.cpython-38.pyc,sha256=0xn7FOm_FEk3hKaH-9LfreqUm5MBUJUDlb4YLzh07fw,12326
10078
10080
  simo/core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10079
10081
  simo/core/utils/admin.py,sha256=iDoTSDzkYqyYkzHgRFWnCRwjl-1BCptRgsUWYj0abvk,1707
10082
+ simo/core/utils/api.py,sha256=T75aESEBUX8yf_ZprtgOz_XYcmoIRxV4lt33ZlDQh8Y,1489
10080
10083
  simo/core/utils/config_values.py,sha256=4HCQmv5wQdupd16WOp80oJSyU7EDccjUO6blX--dnoY,5495
10081
10084
  simo/core/utils/easing.py,sha256=N2NwD0CjLh82RGaYJKjyt-VVpVeS9z0mba8fqr8A1t0,1499
10082
10085
  simo/core/utils/form_fields.py,sha256=UOzYdPd71qgCw1H3qH01u85YjrOlETPJAHOJrZKhyD0,627
@@ -10091,6 +10094,7 @@ simo/core/utils/type_constants.py,sha256=y0YnRa7txooMZUVf1IuFUTXPwLaHo_UToKIChJH
10091
10094
  simo/core/utils/validators.py,sha256=PGqW9E8tA6I68RiZg_38DS_MsZs1ew_6vQY4YRKhBdU,772
10092
10095
  simo/core/utils/__pycache__/__init__.cpython-38.pyc,sha256=fm7tTfba3f_RZC2Q7UCRztAw55rK-ZCVYh0QHl8vvj8,149
10093
10096
  simo/core/utils/__pycache__/admin.cpython-38.pyc,sha256=XrQ3EyhyGw27aXBvW0cCypeiy_XZe5pzLaySjX_wcbg,1505
10097
+ simo/core/utils/__pycache__/api.cpython-38.pyc,sha256=CuJq9GKQC8gbeCxmH2wQHZUmkIihVILSEIAoVYCFwH0,1575
10094
10098
  simo/core/utils/__pycache__/config_values.cpython-38.pyc,sha256=fqTVDhkjaWFv14Pr_ZSKgDYrGPxX8GWnEHmvc4NLcZU,6030
10095
10099
  simo/core/utils/__pycache__/easing.cpython-38.pyc,sha256=z4tgyNvEF1jMgiKWFfYGzPfpwsLKpxngazwk-A_IPs4,2129
10096
10100
  simo/core/utils/__pycache__/form_fields.cpython-38.pyc,sha256=J9PgYdjuG2k3oFOrH4paaGQNKZttzlw5PRwA5qkS1y4,1244
@@ -10126,7 +10130,9 @@ simo/fleet/__pycache__/ble.cpython-38.pyc,sha256=Nrof9w7cm4OlpFWHeVnmvvanh2_oF9o
10126
10130
  simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=479T-on9N6dPt1W-JEhy9x7QHeKR8Hqd5Mco8d4YeD8,22363
10127
10131
  simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=hZZlVkARLKo0VwiENJh65hgiuGwJgQTo0eRbOWqEDBY,492
10128
10132
  simo/fleet/__pycache__/models.cpython-38.pyc,sha256=RNzIw4bNTwuEvHVqs2VSLKMWa8xKPfTXD_f6WrwC-1k,8519
10133
+ simo/fleet/__pycache__/routing.cpython-38.pyc,sha256=aPrCmxFKVyB8R8ZbJDwdPdFfvT7CvobovvZeq_mqRgY,314
10129
10134
  simo/fleet/__pycache__/serializers.cpython-38.pyc,sha256=nbkFJzjZP27U0fvMi_yPOhH7Hj1vK0HB44wn5yT6m_Y,869
10135
+ simo/fleet/__pycache__/socket_consumers.cpython-38.pyc,sha256=PALYpTLf9FPk3E34YAMeFqHvUykVtdXXWMLHpW3UvyY,9506
10130
10136
  simo/fleet/__pycache__/utils.cpython-38.pyc,sha256=txFY3LyTkjtEdaGfcjrjgZogMIoq4T1XR5OQCTkwh7w,2815
10131
10137
  simo/fleet/__pycache__/views.cpython-38.pyc,sha256=FAenBel5MTzNDM8Qa-QBr_5gjSYmCMWMyVjWnfz-HYM,1757
10132
10138
  simo/fleet/migrations/0001_initial.py,sha256=lce8nkD8Sz6pYr-XJSpDm4CMDuB6TA__WtnHpIp-eA4,1326
@@ -10260,7 +10266,7 @@ simo/notifications/admin.py,sha256=y_gmHYXbDh98LUUa-lp9DilTIgM6-pIujWPQPLQsJo8,8
10260
10266
  simo/notifications/api.py,sha256=GXQpq68ULBaJpU8w3SJKaCKuxYGWYehKnGeocGB1RVc,1783
10261
10267
  simo/notifications/models.py,sha256=VZcvweii59j89nPKlWeUSJ44Qz3ZLjJ6mXN6uB9F1Sw,2506
10262
10268
  simo/notifications/serializers.py,sha256=altDEAPWwOhxRcEzE9-34jL8EFpyf3vPoEdAPoVLfGc,523
10263
- simo/notifications/utils.py,sha256=zvbrGV9SMmFrNlc_z8yo5ERF6jONtdVAjL8AZkjcTIs,848
10269
+ simo/notifications/utils.py,sha256=M2UFufqAWD64kHw0rUDIr4nJ1ZkHd47sG_TVa4j918s,907
10264
10270
  simo/notifications/__pycache__/__init__.cpython-38.pyc,sha256=EVOjea4WSAX2rAlowBdVvtLPTqZ4rR1tvtFqTLrh_FQ,152
10265
10271
  simo/notifications/__pycache__/admin.cpython-38.pyc,sha256=VpUM9ieVGJa2zu4lrDAt7GiuHLx8HHwgZHBxxHMFRWw,1624
10266
10272
  simo/notifications/__pycache__/api.cpython-38.pyc,sha256=RCSLrlRK52iEM2eKKfTmdrvkAcJrt9DVuDscJEOQXDs,2065
@@ -10274,33 +10280,33 @@ simo/notifications/migrations/__pycache__/0001_initial.cpython-38.pyc,sha256=rbn
10274
10280
  simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-38.pyc,sha256=Hh_Tv5XTMGIPEFM4ZLC_SVmCGEQKsyykO_Uu5wBPVLs,786
10275
10281
  simo/notifications/migrations/__pycache__/__init__.cpython-38.pyc,sha256=wXGUV-iMXaTLV1UNZ8FtuSK85VPF07qIr5wKwlv5yuc,186
10276
10282
  simo/users/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10277
- simo/users/admin.py,sha256=RFSE9rsYf3rOeu4Qx90FeWqMdbkVxhBfITSuYNmbGX4,6360
10278
- simo/users/api.py,sha256=pjOK5RsGXhFI_X0pQe4w1PkZQGEnm9YqpZ_aIZ6v9H0,7666
10279
- simo/users/auth_backends.py,sha256=Kkn1t8WCD8DErJokuOQxphOIkyxlDJAAL6oBFT-DeLY,2458
10283
+ simo/users/admin.py,sha256=XpUrz1zIVLuK3Y9MF7kCJBExHpMEMkU3iNZG1YZdxO0,6560
10284
+ simo/users/api.py,sha256=in_rxvuZWB2jPvy9P-DI5r5_lKbYtpwozerBewDNvdA,7790
10285
+ simo/users/auth_backends.py,sha256=I5pnaTa20-Lxfw_dFG8471xDITb0_fQl1PVhJalp5vU,3992
10280
10286
  simo/users/auto_urls.py,sha256=ee0d6fWABkJY5mQOTC8KhrqDI6d8xZkYZ4ja-gZJ-rw,269
10281
10287
  simo/users/dynamic_settings.py,sha256=sEIsi4yJw3kH46Jq_aOkSuK7QTfQACGUE-lkyBogCaM,570
10282
- simo/users/middleware.py,sha256=lwZQ1koxOEWcRI2PD_EXo3AX8exO-z4R5jOFwfTHRw8,739
10283
- simo/users/models.py,sha256=tPidNP6lFP0-dHkWvmJjAUBjPIeFBRJhLgrFPW3iHzw,16538
10288
+ simo/users/middleware.py,sha256=FhsAwgUVHSq99qbcyjZ6CXtevvZiLYQ11kPPpkI5uk0,737
10289
+ simo/users/models.py,sha256=iaGqXLM94U_lqwtP4T7zesEt3Lu_HIS6wbs41RfrrJQ,17012
10284
10290
  simo/users/permissions.py,sha256=IwtYS8yQdupWbYKR9VimSRDV3qCJ2jXP57Lyjpb2EQM,242
10285
- simo/users/serializers.py,sha256=K0b5snRTn1ZSbG0wWu9P_0GE8MYYxmNxfAzJlwl00HI,2001
10291
+ simo/users/serializers.py,sha256=Mh2pWmsKDp7CNIxK2OTw3CfVkteZHiVoXWNF1fluvX8,2161
10286
10292
  simo/users/sso_urls.py,sha256=pcb_GhYHRtmairxJhMXE1bdcTma0BcYfKU3nCRtHQMQ,244
10287
10293
  simo/users/sso_views.py,sha256=-XI67TvQ7SN3goU4OuAHyn84u_1vtusvpn7Pu0K97zo,4648
10288
10294
  simo/users/tasks.py,sha256=nwU1nB37L4YtjcuwjFgc_VQZTncC3t2tr-Lk-DVFJkM,641
10289
- simo/users/utils.py,sha256=5DMcY8KGJiFPiJFCOgeIM-BiHV5_PamlbMK0ko7PMV8,870
10295
+ simo/users/utils.py,sha256=bbdBVDzXY3xyy8SdB8ERZF6PCmKbR137AnIyrn4HqLQ,867
10290
10296
  simo/users/views.py,sha256=dOQVvmlHG7ihWKJLFUBcqKOA0UDctlMKR0pTc36JZqg,3487
10291
10297
  simo/users/__pycache__/__init__.cpython-38.pyc,sha256=qVNCdQSNCAQRCsXJ__8eDa_UuFbLz4j_twP9f0TrCMk,144
10292
- simo/users/__pycache__/admin.cpython-38.pyc,sha256=3FoBn-O9a1qwx8tLFpvHoQ-60EAqZeeVOj2K8lIm_vI,7070
10293
- simo/users/__pycache__/api.cpython-38.pyc,sha256=enX8cJ9I2Fc3Qn1BlTqpKIdI40d-n1vqKN2KLqx14Vg,6533
10294
- simo/users/__pycache__/auth_backends.cpython-38.pyc,sha256=-UbdpL6Q4URd70ZeRK734YpAhYQc8WhR5aDDdw1JgGI,1701
10298
+ simo/users/__pycache__/admin.cpython-38.pyc,sha256=RAAzAh_7fTAKOnK-VaITHJkieOwmL8zYhDqrajHOHGs,7274
10299
+ simo/users/__pycache__/api.cpython-38.pyc,sha256=bwuezVy5VBdlIut7fE3JxJCzIFGS1aokDCSl5ioo-MQ,6620
10300
+ simo/users/__pycache__/auth_backends.cpython-38.pyc,sha256=BMVsMoWcoYUQevvj-2OSJShHbMhxbzJzP8SwqJ3Kg2E,3007
10295
10301
  simo/users/__pycache__/auto_urls.cpython-38.pyc,sha256=UCgzFKwKi1_W9jTQ2BBFq7GF7Q-wbP8r-d4Jsw8644c,423
10296
10302
  simo/users/__pycache__/dynamic_settings.cpython-38.pyc,sha256=dexiY5hjMsvBrxCb5_ww1rlETHtSihVRLS_j_-dLCSw,856
10297
- simo/users/__pycache__/middleware.cpython-38.pyc,sha256=LmRI_DKMTQNmKmERlx7zCZIo4lxgZhbTCEWU9pWpD3I,1157
10298
- simo/users/__pycache__/models.cpython-38.pyc,sha256=1EnZ6CDafUyOhx6f4EO1BzFPDG8N74sEcc_IGKhLFXA,16197
10303
+ simo/users/__pycache__/middleware.cpython-38.pyc,sha256=L1kh7QWOsrpBd6yfaiG-3MGdsB3hm-HWOzHPMUbtMnU,1165
10304
+ simo/users/__pycache__/models.cpython-38.pyc,sha256=RPd5pi9Of8tRch0fGzVGhuIWfCLWleWVKyUlmJy5Bls,16541
10299
10305
  simo/users/__pycache__/permissions.cpython-38.pyc,sha256=bIV9s6Y4uTX6KisJeWA_MZZ7aaDuIKu0sSYIPMXUCoo,625
10300
- simo/users/__pycache__/serializers.cpython-38.pyc,sha256=Zve_hE9M4hGcDuDq9oxnWJO0NPq0aQ2_xo3-2HUAK88,2708
10306
+ simo/users/__pycache__/serializers.cpython-38.pyc,sha256=XtCwvcq1BT0pVVPrmjF59ME3V9kP2Or-QAzV2ozwiR0,2868
10301
10307
  simo/users/__pycache__/sso_urls.cpython-38.pyc,sha256=DlIv-bsQRFX1LI-sr-COJb8Ah1iuAvaiVIZtY7fD2WI,395
10302
10308
  simo/users/__pycache__/sso_views.cpython-38.pyc,sha256=EtSXO0RXaunRp6HWsBWhMkHA8vmTCE9WTgyoKwsvljA,3961
10303
- simo/users/__pycache__/utils.cpython-38.pyc,sha256=1rsGzAYpyantkNy9a_wkCuKoC5vQg7a39JDJ6_OPqeA,1026
10309
+ simo/users/__pycache__/utils.cpython-38.pyc,sha256=rx3P-AWi_5Y-7luFlqWpOEw0eNyrJSdpy_uG9lFzPtE,1130
10304
10310
  simo/users/__pycache__/views.cpython-38.pyc,sha256=BsgxcY1ZdBEGAeho1KiFWtkcmvTGqpE4JSR9fdxAzqI,2418
10305
10311
  simo/users/migrations/0001_initial.py,sha256=5ojkoyTndS2kW5guKK9G9WntXOqbJMyyT_8s_fcJogc,7072
10306
10312
  simo/users/migrations/0002_componentpermission.py,sha256=rH9pC9HERf_5WWn3LCsNiu03BiHqURTF62pSNfswStI,918
@@ -10324,6 +10330,7 @@ simo/users/migrations/0019_auto_20231221_1155.py,sha256=hZXiVNLBjiOxtGU1QtMC2iab
10324
10330
  simo/users/migrations/0020_rename_is_god_user_is_master.py,sha256=opZkM36xt6sKuJx5XmqywGNS12bvT4hTNlsntMM3TqU,362
10325
10331
  simo/users/migrations/0021_alter_permissionsrole_instance.py,sha256=Taw2fdHy6U1PlThC3QIWaL_ADbx7gchWsJcGxoMMElo,630
10326
10332
  simo/users/migrations/0022_userdevicereportlog_instance.py,sha256=h0ue6uMcIyVs2o58Aj0PyjGLPvCCfS28HfPIiIu_VLc,549
10333
+ simo/users/migrations/0023_auto_20240105_0719.py,sha256=OAkWJusXjzT6dx4EgwjvNvMEgrP_zvcG8zgi774pYG0,700
10327
10334
  simo/users/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10328
10335
  simo/users/migrations/__pycache__/0001_initial.cpython-38.pyc,sha256=w8ccJbE3x73ITPVmcOUVT8qbhjZtZYg9sS2big8WsNw,4261
10329
10336
  simo/users/migrations/__pycache__/0002_componentpermission.cpython-38.pyc,sha256=TsUDv3OJQfX9CoI224AyGWHzseMPWA4eiP1Woec1reE,987
@@ -10347,6 +10354,7 @@ simo/users/migrations/__pycache__/0019_auto_20231221_1155.cpython-38.pyc,sha256=
10347
10354
  simo/users/migrations/__pycache__/0020_rename_is_god_user_is_master.cpython-38.pyc,sha256=pP7o94NjkII7AVe3z8NGiZEiZdFFBwp8FQoaRhj8MrQ,574
10348
10355
  simo/users/migrations/__pycache__/0021_alter_permissionsrole_instance.cpython-38.pyc,sha256=c-x7nYpDecHoQJvpZ_GWhI_O6cUC8dVQlIp9jjxmfo0,863
10349
10356
  simo/users/migrations/__pycache__/0022_userdevicereportlog_instance.cpython-38.pyc,sha256=B3Q9I8ALjkZeMZkkJTgJzI-ZNJQ8iKYud8ghCpfxRuw,785
10357
+ simo/users/migrations/__pycache__/0023_auto_20240105_0719.cpython-38.pyc,sha256=32yZ1vAmoTVrTg8ZU555JK2M08D9xN5YOF0fln_W4q4,739
10350
10358
  simo/users/migrations/__pycache__/__init__.cpython-38.pyc,sha256=Caxyv82VUq1el4Jywa9a3n4OgNglEXPLGiSzpIZJNE4,162
10351
10359
  simo/users/templates/invitations/authenticated_msg.html,sha256=7gH_v6l61jj1XiqqbGkTTMacofcXHiHYum4JCATRQkk,57
10352
10360
  simo/users/templates/invitations/authenticated_suggestion.html,sha256=ek11fAo7a9Rjgq9CPh2BlpWD3YxY42rgKn9iq5BSMus,49
@@ -10354,8 +10362,8 @@ simo/users/templates/invitations/expired_msg.html,sha256=3hTtUm-Cr1axOjlwAIKsSj9
10354
10362
  simo/users/templates/invitations/expired_suggestion.html,sha256=pT67ludJdeohrlF0QIzs4eqy1SI_oH2i6H0ecEIgaCg,100
10355
10363
  simo/users/templates/invitations/taken_msg.html,sha256=Dv1MaxVVmSdL20gri4Ei-K0aZ0OTmIdmO6a3l5MKwCs,445
10356
10364
  simo/users/templates/invitations/taken_suggestion.html,sha256=NCE2XQail0WQGW8v6y3BkQoM3IOWlh02z9XPEws659E,301
10357
- simo-1.7.5.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10358
- simo-1.7.5.dist-info/METADATA,sha256=VBuz74hcg0PoOuwT0n9Jj3v-1bY5rT_mYvaydjAumos,1748
10359
- simo-1.7.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
10360
- simo-1.7.5.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10361
- simo-1.7.5.dist-info/RECORD,,
10365
+ simo-1.7.7.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
10366
+ simo-1.7.7.dist-info/METADATA,sha256=UUEAAD3661jAkzQC1nCF2DFBmLPj4Noo_3xfvtatrPY,1748
10367
+ simo-1.7.7.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
10368
+ simo-1.7.7.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
10369
+ simo-1.7.7.dist-info/RECORD,,
File without changes