simo 2.4.2__py3-none-any.whl → 2.5.2__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/backups/tasks.py +11 -1
- simo/core/__pycache__/admin.cpython-38.pyc +0 -0
- simo/core/__pycache__/api.cpython-38.pyc +0 -0
- simo/core/__pycache__/app_widgets.cpython-38.pyc +0 -0
- simo/core/__pycache__/controllers.cpython-38.pyc +0 -0
- simo/core/__pycache__/events.cpython-38.pyc +0 -0
- simo/core/__pycache__/forms.cpython-38.pyc +0 -0
- simo/core/__pycache__/middleware.cpython-38.pyc +0 -0
- simo/core/__pycache__/models.cpython-38.pyc +0 -0
- simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/core/__pycache__/socket_consumers.cpython-38.pyc +0 -0
- simo/core/__pycache__/tasks.cpython-38.pyc +0 -0
- simo/core/__pycache__/views.cpython-38.pyc +0 -0
- simo/core/admin.py +4 -4
- simo/core/api.py +20 -4
- simo/core/app_widgets.py +5 -0
- simo/core/controllers.py +4 -3
- simo/core/events.py +13 -4
- simo/core/forms.py +2 -0
- simo/core/management/commands/gateways_manager.py +0 -3
- simo/core/middleware.py +12 -6
- simo/core/models.py +26 -6
- simo/core/serializers.py +17 -17
- simo/core/socket_consumers.py +6 -2
- simo/core/static/admin/js/codemirror-init.js +1 -0
- simo/core/tasks.py +10 -7
- simo/fleet/__pycache__/controllers.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/models.cpython-38.pyc +0 -0
- simo/fleet/__pycache__/socket_consumers.cpython-38.pyc +0 -0
- simo/fleet/controllers.py +86 -22
- simo/fleet/forms.py +84 -9
- simo/fleet/migrations/0039_auto_20241016_1047.py +28 -0
- simo/fleet/migrations/0040_alter_colonel_pwm_frequency.py +18 -0
- simo/fleet/migrations/__pycache__/0039_auto_20241016_1047.cpython-38.pyc +0 -0
- simo/fleet/migrations/__pycache__/0040_alter_colonel_pwm_frequency.cpython-38.pyc +0 -0
- simo/fleet/models.py +6 -2
- simo/fleet/socket_consumers.py +13 -5
- simo/generic/__pycache__/controllers.cpython-38.pyc +0 -0
- simo/generic/__pycache__/forms.cpython-38.pyc +0 -0
- simo/generic/__pycache__/gateways.cpython-38.pyc +0 -0
- simo/generic/__pycache__/models.cpython-38.pyc +0 -0
- simo/generic/controllers.py +45 -2
- simo/generic/forms.py +81 -7
- simo/generic/models.py +0 -1
- simo/generic/scripting/__init__.py +16 -0
- simo/generic/scripting/__pycache__/__init__.cpython-38.pyc +0 -0
- simo/generic/scripting/__pycache__/helpers.cpython-38.pyc +0 -0
- simo/generic/scripting/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/generic/scripting/helpers.py +35 -0
- simo/generic/scripting/serializers.py +77 -0
- simo/generic/templates/admin/controller_widgets/weather_forecast.html +2 -2
- simo/notifications/__pycache__/utils.cpython-38.pyc +0 -0
- simo/notifications/utils.py +30 -12
- simo/scripting.py +2 -2
- simo/users/__pycache__/api.cpython-38.pyc +0 -0
- simo/users/__pycache__/managers.cpython-38.pyc +0 -0
- simo/users/__pycache__/models.cpython-38.pyc +0 -0
- simo/users/__pycache__/serializers.cpython-38.pyc +0 -0
- simo/users/__pycache__/utils.cpython-38.pyc +0 -0
- simo/users/api.py +36 -7
- simo/users/managers.py +5 -1
- simo/users/migrations/0034_instanceuser_last_seen_location_and_more.py +24 -0
- simo/users/migrations/__pycache__/0034_instanceuser_last_seen_location_and_more.cpython-38.pyc +0 -0
- simo/users/models.py +37 -32
- simo/users/serializers.py +11 -8
- simo/users/utils.py +14 -3
- {simo-2.4.2.dist-info → simo-2.5.2.dist-info}/METADATA +1 -1
- {simo-2.4.2.dist-info → simo-2.5.2.dist-info}/RECORD +73 -60
- {simo-2.4.2.dist-info → simo-2.5.2.dist-info}/WHEEL +1 -1
- {simo-2.4.2.dist-info → simo-2.5.2.dist-info}/LICENSE.md +0 -0
- {simo-2.4.2.dist-info → simo-2.5.2.dist-info}/entry_points.txt +0 -0
- {simo-2.4.2.dist-info → simo-2.5.2.dist-info}/top_level.txt +0 -0
simo/notifications/utils.py
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
|
-
from simo.
|
|
1
|
+
from simo.core.middleware import get_current_instance
|
|
2
2
|
from .models import Notification, UserNotification
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def notify_users(
|
|
5
|
+
def notify_users(severity, title, body=None, component=None, instance_users=None, instance=None):
|
|
6
|
+
'''
|
|
7
|
+
Sends a notification to specified users with a given severity level and message details.
|
|
8
|
+
:param severity: One of: 'info', 'warning', 'alarm'
|
|
9
|
+
:param title: A short, descriptive title of the event.
|
|
10
|
+
:param body: (Optional) A more detailed description of the event.
|
|
11
|
+
:param component: (Optional) simo.core.Component linked to this event.
|
|
12
|
+
:param instance_users: List of instance users to receive this notification. All active instance users will receive the message if not specified.
|
|
13
|
+
:return:
|
|
14
|
+
'''
|
|
15
|
+
if not instance:
|
|
16
|
+
if component:
|
|
17
|
+
instance = component.zone.instance
|
|
18
|
+
else:
|
|
19
|
+
instance = get_current_instance()
|
|
20
|
+
if not instance:
|
|
21
|
+
return
|
|
22
|
+
if component and component.zone.instance != instance:
|
|
23
|
+
# something is completely wrong!
|
|
24
|
+
return
|
|
6
25
|
assert severity in ('info', 'warning', 'alarm')
|
|
7
26
|
notification = Notification.objects.create(
|
|
8
27
|
instance=instance,
|
|
@@ -10,20 +29,19 @@ def notify_users(instance, severity, title, body=None, component=None, users=Non
|
|
|
10
29
|
severity=severity, body=body,
|
|
11
30
|
component=component
|
|
12
31
|
)
|
|
13
|
-
if not
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
for user in users:
|
|
32
|
+
if not instance_users:
|
|
33
|
+
instance_users = instance.instance_users.filter(
|
|
34
|
+
is_active=True
|
|
35
|
+
).select_related('user')
|
|
36
|
+
for iuser in instance_users:
|
|
19
37
|
# do not send emails to system users
|
|
20
|
-
if user.email.endswith('simo.io'):
|
|
38
|
+
if iuser.user.email.endswith('simo.io'):
|
|
21
39
|
continue
|
|
22
|
-
if instance
|
|
40
|
+
if iuser.instance.id != instance.id:
|
|
23
41
|
continue
|
|
24
|
-
if component and not component.
|
|
42
|
+
if component and not component.can_read(iuser.user):
|
|
25
43
|
continue
|
|
26
44
|
UserNotification.objects.create(
|
|
27
|
-
user=user, notification=notification,
|
|
45
|
+
user=iuser.user, notification=notification,
|
|
28
46
|
)
|
|
29
47
|
notification.dispatch()
|
simo/scripting.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from django.utils import timezone
|
|
2
2
|
from suntime import Sun
|
|
3
|
-
from simo.core.
|
|
3
|
+
from simo.core.middleware import get_current_instance
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class LocalSun(Sun):
|
|
7
7
|
|
|
8
8
|
def __init__(self, instance=None):
|
|
9
9
|
if not instance:
|
|
10
|
-
instance =
|
|
10
|
+
instance = get_current_instance()
|
|
11
11
|
coordinates = instance.location.split(',')
|
|
12
12
|
try:
|
|
13
13
|
lat = float(coordinates[0])
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
simo/users/api.py
CHANGED
|
@@ -4,17 +4,18 @@ from rest_framework import viewsets, mixins, status
|
|
|
4
4
|
from rest_framework.serializers import Serializer
|
|
5
5
|
from rest_framework.decorators import action
|
|
6
6
|
from rest_framework.response import Response as RESTResponse
|
|
7
|
-
from rest_framework.exceptions import ValidationError
|
|
7
|
+
from rest_framework.exceptions import ValidationError, PermissionDenied
|
|
8
8
|
from django.contrib.gis.geos import Point
|
|
9
9
|
from django.utils import timezone
|
|
10
|
+
from django_filters.rest_framework import DjangoFilterBackend
|
|
10
11
|
from simo.core.api import InstanceMixin
|
|
11
12
|
from .models import (
|
|
12
13
|
User, UserDevice, UserDeviceReportLog, PermissionsRole, InstanceInvitation,
|
|
13
|
-
Fingerprint
|
|
14
|
+
Fingerprint, ComponentPermission, InstanceUser
|
|
14
15
|
)
|
|
15
16
|
from .serializers import (
|
|
16
17
|
UserSerializer, PermissionsRoleSerializer, InstanceInvitationSerializer,
|
|
17
|
-
FingerprintSerializer
|
|
18
|
+
FingerprintSerializer, ComponentPermissionSerializer
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
|
|
@@ -63,9 +64,6 @@ class UsersViewSet(mixins.RetrieveModelMixin,
|
|
|
63
64
|
request.data.pop(key)
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
target_user.set_instance(self.instance)
|
|
67
|
-
|
|
68
|
-
|
|
69
67
|
serializer = self.get_serializer(
|
|
70
68
|
target_user, data=request.data, partial=partial
|
|
71
69
|
)
|
|
@@ -135,12 +133,38 @@ class RolesViewsets(InstanceMixin, viewsets.ReadOnlyModelViewSet):
|
|
|
135
133
|
url = 'users/roles'
|
|
136
134
|
basename = 'roles'
|
|
137
135
|
serializer_class = PermissionsRoleSerializer
|
|
138
|
-
queryset = PermissionsRole.objects.all()
|
|
139
136
|
|
|
140
137
|
def get_queryset(self):
|
|
141
138
|
return PermissionsRole.objects.filter(instance=self.instance)
|
|
142
139
|
|
|
143
140
|
|
|
141
|
+
class ComponentPermissionViewsets(
|
|
142
|
+
InstanceMixin,
|
|
143
|
+
mixins.RetrieveModelMixin, mixins.UpdateModelMixin,
|
|
144
|
+
mixins.ListModelMixin, viewsets.GenericViewSet
|
|
145
|
+
):
|
|
146
|
+
url = 'users/componentpermissions'
|
|
147
|
+
basename = 'componentpermissions'
|
|
148
|
+
serializer_class = ComponentPermissionSerializer
|
|
149
|
+
filter_backends = [DjangoFilterBackend]
|
|
150
|
+
filterset_fields = ['component', 'role']
|
|
151
|
+
|
|
152
|
+
def get_queryset(self):
|
|
153
|
+
return ComponentPermission.objects.filter(role__instance=self.instance)
|
|
154
|
+
|
|
155
|
+
def update(self, request, *args, **kwargs):
|
|
156
|
+
if request.user.is_master:
|
|
157
|
+
return super().update(request, *args, **kwargs)
|
|
158
|
+
iuser = InstanceUser.objects.get(
|
|
159
|
+
instance=self.instance, user=request.user
|
|
160
|
+
).select_related('role')
|
|
161
|
+
if not iuser.is_active:
|
|
162
|
+
raise PermissionDenied()
|
|
163
|
+
if iuser.role.is_owner or iuser.role.is_superuser:
|
|
164
|
+
return super().update(request, *args, **kwargs)
|
|
165
|
+
raise PermissionDenied()
|
|
166
|
+
|
|
167
|
+
|
|
144
168
|
class UserDeviceReport(InstanceMixin, viewsets.GenericViewSet):
|
|
145
169
|
url = 'users'
|
|
146
170
|
basename = 'device_report'
|
|
@@ -188,6 +212,11 @@ class UserDeviceReport(InstanceMixin, viewsets.GenericViewSet):
|
|
|
188
212
|
).exclude(id=user_device.id).update(is_primary=False)
|
|
189
213
|
user_device.save()
|
|
190
214
|
|
|
215
|
+
for iu in request.user.instance_roles.filter(is_active=True):
|
|
216
|
+
iu.last_seen_location = user_device.last_seen_location
|
|
217
|
+
iu.last_seen_location_datetime = user_device.last_seen
|
|
218
|
+
iu.save()
|
|
219
|
+
|
|
191
220
|
request.user.last_seen_location = user_device.last_seen_location
|
|
192
221
|
request.user.last_seen_location_datetime = user_device.last_seen
|
|
193
222
|
request.user.save()
|
simo/users/managers.py
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
from django.db import models
|
|
2
|
+
from simo.core.middleware import get_current_instance
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class ActiveInstanceManager(models.Manager):
|
|
5
6
|
|
|
6
7
|
def get_queryset(self):
|
|
7
|
-
|
|
8
|
+
instance = get_current_instance()
|
|
9
|
+
return super().get_queryset().filter(
|
|
10
|
+
instance__is_active=True, instance=instance
|
|
11
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Generated by Django 4.2.10 on 2024-10-18 08:00
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import location_field.models.plain
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('users', '0033_alter_user_ssh_key'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddField(
|
|
15
|
+
model_name='instanceuser',
|
|
16
|
+
name='last_seen_location',
|
|
17
|
+
field=location_field.models.plain.PlainLocationField(blank=True, help_text='Sent by user mobile app', max_length=63, null=True),
|
|
18
|
+
),
|
|
19
|
+
migrations.AddField(
|
|
20
|
+
model_name='instanceuser',
|
|
21
|
+
name='last_seen_location_datetime',
|
|
22
|
+
field=models.DateTimeField(blank=True, null=True),
|
|
23
|
+
),
|
|
24
|
+
]
|
simo/users/migrations/__pycache__/0034_instanceuser_last_seen_location_and_more.cpython-38.pyc
ADDED
|
Binary file
|
simo/users/models.py
CHANGED
|
@@ -22,6 +22,7 @@ from simo.conf import dynamic_settings
|
|
|
22
22
|
from simo.core.utils.mixins import SimoAdminMixin
|
|
23
23
|
from simo.core.utils.helpers import get_random_string
|
|
24
24
|
from simo.core.events import OnChangeMixin
|
|
25
|
+
from simo.core.middleware import get_current_instance
|
|
25
26
|
from .middleware import get_current_user
|
|
26
27
|
from .utils import rebuild_authorized_keys
|
|
27
28
|
from .managers import ActiveInstanceManager
|
|
@@ -98,6 +99,12 @@ class InstanceUser(DirtyFieldsMixin, models.Model, OnChangeMixin):
|
|
|
98
99
|
role = models.ForeignKey(PermissionsRole, on_delete=models.CASCADE)
|
|
99
100
|
at_home = models.BooleanField(default=False, db_index=True)
|
|
100
101
|
is_active = models.BooleanField(default=True, db_index=True)
|
|
102
|
+
last_seen_location = PlainLocationField(
|
|
103
|
+
zoom=7, null=True, blank=True, help_text="Sent by user mobile app"
|
|
104
|
+
)
|
|
105
|
+
last_seen_location_datetime = models.DateTimeField(
|
|
106
|
+
null=True, blank=True,
|
|
107
|
+
)
|
|
101
108
|
|
|
102
109
|
objects = ActiveInstanceManager()
|
|
103
110
|
|
|
@@ -123,17 +130,18 @@ def post_instance_user_save(sender, instance, created, **kwargs):
|
|
|
123
130
|
return
|
|
124
131
|
from simo.core.events import ObjectChangeEvent
|
|
125
132
|
dirty_fields = instance.get_dirty_fields()
|
|
126
|
-
if 'at_home' in dirty_fields:
|
|
133
|
+
if 'at_home' in dirty_fields or 'last_seen_location' in dirty_fields:
|
|
127
134
|
def post_update():
|
|
128
|
-
if
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
if 'at_home' in dirty_fields:
|
|
136
|
+
if instance.at_home:
|
|
137
|
+
verb = 'came home'
|
|
138
|
+
else:
|
|
139
|
+
verb = 'left'
|
|
140
|
+
action.send(
|
|
141
|
+
instance.user, verb=verb,
|
|
142
|
+
instance_id=instance.instance.id,
|
|
143
|
+
action_type='user_presence', value=instance.at_home
|
|
144
|
+
)
|
|
137
145
|
ObjectChangeEvent(
|
|
138
146
|
instance.instance, instance, dirty_fields=dirty_fields
|
|
139
147
|
).publish()
|
|
@@ -182,8 +190,6 @@ class User(AbstractBaseUser, SimoAdminMixin):
|
|
|
182
190
|
USERNAME_FIELD = 'email'
|
|
183
191
|
REQUIRED_FIELDS = ['name']
|
|
184
192
|
|
|
185
|
-
_instance = None
|
|
186
|
-
|
|
187
193
|
class Meta:
|
|
188
194
|
verbose_name = _('user')
|
|
189
195
|
verbose_name_plural = _('users')
|
|
@@ -206,12 +212,10 @@ class User(AbstractBaseUser, SimoAdminMixin):
|
|
|
206
212
|
obj = super().save(*args, **kwargs)
|
|
207
213
|
|
|
208
214
|
if org:
|
|
209
|
-
if org.can_ssh() != self.can_ssh():
|
|
215
|
+
if org.can_ssh() != self.can_ssh() or org.ssh_key != self.ssh_key:
|
|
210
216
|
rebuild_authorized_keys()
|
|
211
217
|
elif self.can_ssh():
|
|
212
218
|
rebuild_authorized_keys()
|
|
213
|
-
elif org and org.ssh_key != self.ssh_key:
|
|
214
|
-
rebuild_authorized_keys()
|
|
215
219
|
|
|
216
220
|
if not org or (org.secret_key != self.secret_key):
|
|
217
221
|
self.update_mqtt_secret()
|
|
@@ -230,7 +234,7 @@ class User(AbstractBaseUser, SimoAdminMixin):
|
|
|
230
234
|
)
|
|
231
235
|
|
|
232
236
|
def can_ssh(self):
|
|
233
|
-
return self.is_active and self.
|
|
237
|
+
return self.is_active and self.is_master
|
|
234
238
|
|
|
235
239
|
def get_role(self, instance):
|
|
236
240
|
cache_key = f'user-{self.id}_instance-{instance.id}_role'
|
|
@@ -244,19 +248,17 @@ class User(AbstractBaseUser, SimoAdminMixin):
|
|
|
244
248
|
cache.set(cache_key, role, 20)
|
|
245
249
|
return role
|
|
246
250
|
|
|
247
|
-
def set_instance(self, instance):
|
|
248
|
-
self._instance = instance
|
|
249
|
-
|
|
250
251
|
@property
|
|
251
252
|
def role_id(self):
|
|
252
253
|
'''Used by API serializer to get users role on a given instance.'''
|
|
253
|
-
|
|
254
|
+
instance = get_current_instance()
|
|
255
|
+
if not instance:
|
|
254
256
|
return None
|
|
255
|
-
cache_key = f'user-{self.id}_instance-{
|
|
257
|
+
cache_key = f'user-{self.id}_instance-{instance.id}-role-id'
|
|
256
258
|
cached_val = cache.get(cache_key, 'expired')
|
|
257
259
|
if cached_val == 'expired':
|
|
258
260
|
for role in self.roles.all().select_related('instance'):
|
|
259
|
-
if role.instance ==
|
|
261
|
+
if role.instance == instance:
|
|
260
262
|
cached_val = role.id
|
|
261
263
|
cache.set(cache_key, role.id, 20)
|
|
262
264
|
return cached_val
|
|
@@ -264,16 +266,17 @@ class User(AbstractBaseUser, SimoAdminMixin):
|
|
|
264
266
|
|
|
265
267
|
@role_id.setter
|
|
266
268
|
def role_id(self, id):
|
|
267
|
-
|
|
269
|
+
instance = get_current_instance()
|
|
270
|
+
if not instance:
|
|
268
271
|
return
|
|
269
272
|
role = PermissionsRole.objects.filter(
|
|
270
|
-
id=id, instance=
|
|
273
|
+
id=id, instance=instance
|
|
271
274
|
).first()
|
|
272
275
|
if not role:
|
|
273
276
|
raise ValueError("There is no such a role on this instance")
|
|
274
277
|
|
|
275
278
|
InstanceUser.objects.update_or_create(
|
|
276
|
-
user=self, instance=
|
|
279
|
+
user=self, instance=instance, defaults={
|
|
277
280
|
'role': role
|
|
278
281
|
}
|
|
279
282
|
)
|
|
@@ -305,20 +308,21 @@ class User(AbstractBaseUser, SimoAdminMixin):
|
|
|
305
308
|
|
|
306
309
|
@property
|
|
307
310
|
def is_active(self):
|
|
308
|
-
|
|
311
|
+
instance = get_current_instance()
|
|
312
|
+
if not instance:
|
|
309
313
|
cache_key = f'user-{self.id}_is_active'
|
|
310
314
|
else:
|
|
311
|
-
cache_key = f'user-{self.id}_is_active_instance-{
|
|
315
|
+
cache_key = f'user-{self.id}_is_active_instance-{instance.id}'
|
|
312
316
|
cached_value = cache.get(cache_key, 'expired')
|
|
313
317
|
if cached_value == 'expired':
|
|
314
318
|
if self.is_master and not self.instance_roles.all():
|
|
315
319
|
# Master who have no roles on any instance are in GOD mode!
|
|
316
320
|
# It can not be disabled by anybody, nor it is seen by anybody. :)
|
|
317
321
|
cached_value = True
|
|
318
|
-
elif
|
|
322
|
+
elif instance:
|
|
319
323
|
cached_value = bool(
|
|
320
324
|
self.instance_roles.filter(
|
|
321
|
-
instance=
|
|
325
|
+
instance=instance, is_active=True
|
|
322
326
|
).first()
|
|
323
327
|
)
|
|
324
328
|
else:
|
|
@@ -331,13 +335,14 @@ class User(AbstractBaseUser, SimoAdminMixin):
|
|
|
331
335
|
|
|
332
336
|
@is_active.setter
|
|
333
337
|
def is_active(self, val):
|
|
334
|
-
|
|
338
|
+
instance = get_current_instance()
|
|
339
|
+
if not instance:
|
|
335
340
|
return
|
|
336
341
|
|
|
337
342
|
self.instance_roles.filter(
|
|
338
|
-
instance=
|
|
343
|
+
instance=instance
|
|
339
344
|
).update(is_active=bool(val))
|
|
340
|
-
cache_key = f'user-{self.id}_is_active_instance-{
|
|
345
|
+
cache_key = f'user-{self.id}_is_active_instance-{instance.id}'
|
|
341
346
|
try:
|
|
342
347
|
cache.delete(cache_key)
|
|
343
348
|
except:
|
simo/users/serializers.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from rest_framework import serializers
|
|
2
2
|
from collections.abc import Iterable
|
|
3
|
-
from simo.core.middleware import get_current_request
|
|
3
|
+
from simo.core.middleware import get_current_request, get_current_instance
|
|
4
4
|
from simo.core.utils.api import ReadWriteSerializerMethodField
|
|
5
5
|
from .models import (
|
|
6
|
-
User, PermissionsRole,
|
|
6
|
+
User, PermissionsRole, ComponentPermission,
|
|
7
|
+
InstanceInvitation, InstanceUser, Fingerprint
|
|
7
8
|
)
|
|
8
9
|
|
|
9
10
|
|
|
@@ -15,11 +16,6 @@ class UserSerializer(serializers.ModelSerializer):
|
|
|
15
16
|
|
|
16
17
|
def __init__(self, *args, **kwargs):
|
|
17
18
|
super().__init__(*args, **kwargs)
|
|
18
|
-
if isinstance(self.instance, Iterable):
|
|
19
|
-
for inst in self.instance:
|
|
20
|
-
inst.set_instance(self.context['instance'])
|
|
21
|
-
elif self.instance:
|
|
22
|
-
self.instance.set_instance(self.context['instance'])
|
|
23
19
|
|
|
24
20
|
class Meta:
|
|
25
21
|
model = User
|
|
@@ -53,7 +49,7 @@ class UserSerializer(serializers.ModelSerializer):
|
|
|
53
49
|
|
|
54
50
|
def get_at_home(self, obj):
|
|
55
51
|
iu = InstanceUser.objects.filter(
|
|
56
|
-
user=obj, instance=
|
|
52
|
+
user=obj, instance=get_current_instance()
|
|
57
53
|
).first()
|
|
58
54
|
if iu:
|
|
59
55
|
return iu.at_home
|
|
@@ -68,6 +64,13 @@ class PermissionsRoleSerializer(serializers.ModelSerializer):
|
|
|
68
64
|
fields = '__all__'
|
|
69
65
|
|
|
70
66
|
|
|
67
|
+
class ComponentPermissionSerializer(serializers.ModelSerializer):
|
|
68
|
+
|
|
69
|
+
class Meta:
|
|
70
|
+
model = ComponentPermission
|
|
71
|
+
fields = '__all__'
|
|
72
|
+
|
|
73
|
+
|
|
71
74
|
class InstanceInvitationSerializer(serializers.ModelSerializer):
|
|
72
75
|
|
|
73
76
|
class Meta:
|
simo/users/utils.py
CHANGED
|
@@ -29,10 +29,21 @@ def rebuild_authorized_keys():
|
|
|
29
29
|
try:
|
|
30
30
|
with open('/root/.ssh/authorized_keys', 'w') as keys_file:
|
|
31
31
|
for user in User.objects.filter(
|
|
32
|
-
ssh_key__isnull=False
|
|
32
|
+
ssh_key__isnull=False, is_master=True
|
|
33
33
|
):
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
has_roles = user.instance_roles.filter(
|
|
35
|
+
instance__is_active=True
|
|
36
|
+
).first()
|
|
37
|
+
has_active_roles = user.instance_roles.filter(
|
|
38
|
+
instance__is_active=True, is_active=True
|
|
39
|
+
).first()
|
|
40
|
+
# if master user has active roles on some instances
|
|
41
|
+
# but no longer has a single active role on an instance
|
|
42
|
+
# he is most probably has been disabled by the property owner
|
|
43
|
+
# therefore he should no longer be able to ssh in to this hub!
|
|
44
|
+
if has_roles and not has_active_roles:
|
|
45
|
+
continue
|
|
46
|
+
keys_file.write(user.ssh_key + '\n')
|
|
36
47
|
except:
|
|
37
48
|
print(traceback.format_exc(), file=sys.stderr)
|
|
38
49
|
pass
|