simo 2.5.4__py3-none-any.whl → 2.5.6__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/core/__pycache__/middleware.cpython-38.pyc +0 -0
- simo/core/__pycache__/models.cpython-38.pyc +0 -0
- simo/core/__pycache__/signal_receivers.cpython-38.pyc +0 -0
- simo/core/management/commands/__pycache__/gateways_manager.cpython-38.pyc +0 -0
- simo/core/middleware.py +14 -7
- simo/core/models.py +9 -4
- simo/core/signal_receivers.py +63 -2
- simo/core/templates/core/auto_night_day_script.py +66 -0
- simo/core/templates/core/auto_state_script.py +78 -0
- simo/fleet/__pycache__/models.cpython-38.pyc +0 -0
- simo/fleet/models.py +3 -2
- simo/generic/__pycache__/gateways.cpython-38.pyc +0 -0
- simo/generic/__pycache__/models.cpython-38.pyc +0 -0
- simo/generic/gateways.py +5 -2
- simo/generic/models.py +1 -0
- simo/generic/scripting/__pycache__/helpers.cpython-38.pyc +0 -0
- simo/generic/scripting/example.py +0 -67
- simo/notifications/__pycache__/admin.cpython-38.pyc +0 -0
- simo/notifications/__pycache__/models.cpython-38.pyc +0 -0
- simo/notifications/__pycache__/utils.cpython-38.pyc +0 -0
- simo/notifications/admin.py +14 -3
- simo/notifications/models.py +3 -1
- simo/users/__pycache__/api.cpython-38.pyc +0 -0
- simo/users/__pycache__/models.cpython-38.pyc +0 -0
- simo/users/api.py +16 -7
- simo/users/models.py +2 -2
- {simo-2.5.4.dist-info → simo-2.5.6.dist-info}/METADATA +1 -1
- {simo-2.5.4.dist-info → simo-2.5.6.dist-info}/RECORD +32 -30
- {simo-2.5.4.dist-info → simo-2.5.6.dist-info}/LICENSE.md +0 -0
- {simo-2.5.4.dist-info → simo-2.5.6.dist-info}/WHEEL +0 -0
- {simo-2.5.4.dist-info → simo-2.5.6.dist-info}/entry_points.txt +0 -0
- {simo-2.5.4.dist-info → simo-2.5.6.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
simo/core/middleware.py
CHANGED
|
@@ -37,11 +37,13 @@ def get_current_instance(request=None):
|
|
|
37
37
|
|
|
38
38
|
instance = getattr(_thread_locals, 'instance', None)
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
# NEVER FORCE THIS! IT's A very BAD IDEA!
|
|
41
|
+
# For example gateways run on an instance neutral environment!
|
|
42
|
+
# if not instance:
|
|
43
|
+
# from .models import Instance
|
|
44
|
+
# instance = Instance.objects.filter(is_active=True).first()
|
|
45
|
+
# if instance:
|
|
46
|
+
# introduce_instance(instance)
|
|
45
47
|
return instance
|
|
46
48
|
|
|
47
49
|
|
|
@@ -92,8 +94,13 @@ def instance_middleware(get_response):
|
|
|
92
94
|
|
|
93
95
|
if instance:
|
|
94
96
|
introduce_instance(instance, request)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
try:
|
|
98
|
+
# should never, but just in case
|
|
99
|
+
tz = pytz.timezone(instance.timezone)
|
|
100
|
+
timezone.activate(tz)
|
|
101
|
+
except:
|
|
102
|
+
tz = pytz.timezone('UTC')
|
|
103
|
+
timezone.activate(tz)
|
|
97
104
|
|
|
98
105
|
response = get_response(request)
|
|
99
106
|
|
simo/core/models.py
CHANGED
|
@@ -61,7 +61,7 @@ def post_icon_delete(sender, instance, *args, **kwargs):
|
|
|
61
61
|
pass
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
class Instance(models.Model, SimoAdminMixin):
|
|
64
|
+
class Instance(DirtyFieldsMixin, models.Model, SimoAdminMixin):
|
|
65
65
|
# Multiple home instances can be had on a single hub computer!
|
|
66
66
|
# For example separate hotel apartments
|
|
67
67
|
# or something of that kind.
|
|
@@ -101,7 +101,7 @@ class Instance(models.Model, SimoAdminMixin):
|
|
|
101
101
|
User, null=True, blank=True, on_delete=models.SET_NULL
|
|
102
102
|
)
|
|
103
103
|
|
|
104
|
-
objects = InstanceManager()
|
|
104
|
+
#objects = InstanceManager()
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
def __str__(self):
|
|
@@ -118,7 +118,10 @@ class Instance(models.Model, SimoAdminMixin):
|
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
class Zone(DirtyFieldsMixin, models.Model, SimoAdminMixin):
|
|
121
|
-
instance = models.ForeignKey(
|
|
121
|
+
instance = models.ForeignKey(
|
|
122
|
+
Instance, on_delete=models.CASCADE, related_name='zones',
|
|
123
|
+
limit_choices_to={'is_active': True}
|
|
124
|
+
)
|
|
122
125
|
name = models.CharField(_('name'), max_length=40)
|
|
123
126
|
order = models.PositiveIntegerField(
|
|
124
127
|
default=0, blank=False, null=False, db_index=True
|
|
@@ -137,7 +140,9 @@ class Zone(DirtyFieldsMixin, models.Model, SimoAdminMixin):
|
|
|
137
140
|
|
|
138
141
|
|
|
139
142
|
class Category(DirtyFieldsMixin, models.Model, SimoAdminMixin):
|
|
140
|
-
instance = models.ForeignKey(
|
|
143
|
+
instance = models.ForeignKey(
|
|
144
|
+
Instance, on_delete=models.CASCADE, limit_choices_to={'is_active': True}
|
|
145
|
+
)
|
|
141
146
|
name = models.CharField(_('name'), max_length=40)
|
|
142
147
|
icon = models.ForeignKey(Icon, on_delete=models.SET_NULL, null=True)
|
|
143
148
|
header_image = models.ImageField(
|
simo/core/signal_receivers.py
CHANGED
|
@@ -5,6 +5,7 @@ from django.db.models.signals import post_save, post_delete
|
|
|
5
5
|
from django.dispatch import receiver
|
|
6
6
|
from django.utils import timezone
|
|
7
7
|
from django.conf import settings
|
|
8
|
+
from django.template.loader import render_to_string
|
|
8
9
|
from actstream import action
|
|
9
10
|
from simo.users.models import PermissionsRole
|
|
10
11
|
from .models import Instance, Gateway, Component, Icon, Zone, Category
|
|
@@ -43,6 +44,7 @@ def create_instance_defaults(sender, instance, created, **kwargs):
|
|
|
43
44
|
|
|
44
45
|
# Create default categories
|
|
45
46
|
climate_category = None
|
|
47
|
+
other_category = None
|
|
46
48
|
for i, data in enumerate([
|
|
47
49
|
("All", 'star'), ("Climate", 'temperature-half'),
|
|
48
50
|
("Lights", 'lightbulb'), ("Security", 'eye'),
|
|
@@ -63,17 +65,17 @@ def create_instance_defaults(sender, instance, created, **kwargs):
|
|
|
63
65
|
)
|
|
64
66
|
if cat.name == 'Climate':
|
|
65
67
|
climate_category = cat
|
|
68
|
+
if cat.name == 'Other':
|
|
69
|
+
other_category = cat
|
|
66
70
|
|
|
67
71
|
# Create generic gateway and components
|
|
68
72
|
|
|
69
73
|
generic, new = Gateway.objects.get_or_create(
|
|
70
74
|
type='simo.generic.gateways.GenericGatewayHandler'
|
|
71
75
|
)
|
|
72
|
-
generic.start()
|
|
73
76
|
dummy, new = Gateway.objects.get_or_create(
|
|
74
77
|
type='simo.generic.gateways.DummyGatewayHandler'
|
|
75
78
|
)
|
|
76
|
-
dummy.start()
|
|
77
79
|
weather_icon = Icon.objects.get(slug='cloud-bolt-sun')
|
|
78
80
|
|
|
79
81
|
Component.objects.create(
|
|
@@ -85,6 +87,63 @@ def create_instance_defaults(sender, instance, created, **kwargs):
|
|
|
85
87
|
config={'is_main': True}
|
|
86
88
|
)
|
|
87
89
|
|
|
90
|
+
state_comp = Component.objects.create(
|
|
91
|
+
name='State', icon=Icon.objects.get(slug='home'),
|
|
92
|
+
zone=other_zone,
|
|
93
|
+
category=other_category,
|
|
94
|
+
gateway=generic, base_type='state-select',
|
|
95
|
+
controller_uid='simo.generic.controllers.StateSelect',
|
|
96
|
+
value='day',
|
|
97
|
+
config={"states": [
|
|
98
|
+
{"icon": "house-day", "name": "Day", "slug": "day"},
|
|
99
|
+
{"icon": "house-night", "name": "Evening", "slug": "evening"},
|
|
100
|
+
{"icon": "moon-cloud", "name": "Night", "slug": "night"},
|
|
101
|
+
{"icon": "house-person-leave", "name": "Away", "slug": "away"},
|
|
102
|
+
{"icon": "island-tropical", "name": "Vacation", "slug": "vacation"}
|
|
103
|
+
], "is_main": True}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
auto_state_code = render_to_string(
|
|
108
|
+
'core/auto_state_script.py', {'state_comp_id': state_comp.id}
|
|
109
|
+
)
|
|
110
|
+
Component.objects.create(
|
|
111
|
+
name='Auto state', icon=Icon.objects.get(slug='bolt'),
|
|
112
|
+
zone=other_zone,
|
|
113
|
+
category=other_category,
|
|
114
|
+
gateway=generic, base_type='script',
|
|
115
|
+
controller_uid='simo.generic.controllers.Script',
|
|
116
|
+
config={
|
|
117
|
+
"code": auto_state_code, 'autostart': True, 'keep_alive': True,
|
|
118
|
+
"notes": f"""
|
|
119
|
+
The script automatically controls the states of the "State" component (ID:{state_comp.id}) — 'day,' 'evening,' 'night,' 'away.'
|
|
120
|
+
The 'day' state is activated on weekdays from 10 a.m., and on weekends from 11 a.m. When the sun sets, the 'evening' state is activated, and at midnight, the 'night' state is activated.
|
|
121
|
+
If no one is home, the 'away' state is activated.
|
|
122
|
+
If a different state, such as 'vacation,' is selected, the script stops running and waits until the State is switched back to one of the controlled states.
|
|
123
|
+
If one of the controlled states is manually selected, the script waits until that state is reached automatically and, once aligned with the manually set state, resumes its operation in normal mode.
|
|
124
|
+
"""
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
code = render_to_string(
|
|
129
|
+
'core/auto_night_day_script.py', {'state_comp_id': state_comp.id}
|
|
130
|
+
)
|
|
131
|
+
Component.objects.create(
|
|
132
|
+
name='Auto night/day by owner phones on charge',
|
|
133
|
+
icon=Icon.objects.get(slug='bolt'), zone=other_zone,
|
|
134
|
+
category=other_category, show_in_app=False,
|
|
135
|
+
gateway=generic, base_type='script',
|
|
136
|
+
controller_uid='simo.generic.controllers.Script',
|
|
137
|
+
config={
|
|
138
|
+
"code": code, 'autostart': True, 'keep_alive': True,
|
|
139
|
+
"notes": f"""
|
|
140
|
+
Automatically sets State component (ID: {state_comp.id}) to "night" if it is later than 10pm and all home owners phones who are at home are put on charge.
|
|
141
|
+
Sets State component to "day" state as soon as none of the home owners phones are on charge and it is 6am or later.
|
|
142
|
+
|
|
143
|
+
"""
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
|
|
88
147
|
# Create default User permission roles
|
|
89
148
|
|
|
90
149
|
PermissionsRole.objects.create(
|
|
@@ -96,6 +155,8 @@ def create_instance_defaults(sender, instance, created, **kwargs):
|
|
|
96
155
|
PermissionsRole.objects.create(
|
|
97
156
|
instance=instance, name="Guest", is_owner=True
|
|
98
157
|
)
|
|
158
|
+
generic.start()
|
|
159
|
+
dummy.start()
|
|
99
160
|
|
|
100
161
|
|
|
101
162
|
@receiver(post_save, sender=Zone)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import random
|
|
3
|
+
from django.utils import timezone
|
|
4
|
+
from simo.core.middleware import get_current_instance
|
|
5
|
+
from simo.core.models import Component
|
|
6
|
+
from simo.users.models import InstanceUser
|
|
7
|
+
from simo.generic.scripting.helpers import LocalSun
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Automation:
|
|
11
|
+
STATE_COMPONENT_ID = {{ state_comp_id }}
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self.instance = get_current_instance()
|
|
15
|
+
self.state = Component.objects.get(id=self.STATE_COMPONENT_ID)
|
|
16
|
+
self.sun = LocalSun(self.instance.location)
|
|
17
|
+
self.night_is_on = False
|
|
18
|
+
|
|
19
|
+
def check_owner_phones(self, state, instance_users, datetime):
|
|
20
|
+
if not self.night_is_on:
|
|
21
|
+
if not (datetime.hour >= 22 or datetime.hour < 6):
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
for iuser in instance_users:
|
|
25
|
+
# skipping users that are not at home
|
|
26
|
+
if not iuser.at_home:
|
|
27
|
+
continue
|
|
28
|
+
if not iuser.phone_on_charge:
|
|
29
|
+
# at least one user's phone is not yet on charge
|
|
30
|
+
return
|
|
31
|
+
self.night_is_on = True
|
|
32
|
+
print("Night!")
|
|
33
|
+
return 'night'
|
|
34
|
+
else:
|
|
35
|
+
if datetime.hour >= 22 or datetime.hour < 6:
|
|
36
|
+
return
|
|
37
|
+
# return new_state diena only if there are still users
|
|
38
|
+
# at home, none of them have their phones on charge
|
|
39
|
+
# and current state is still night
|
|
40
|
+
for iuser in instance_users:
|
|
41
|
+
# skipping users that are not at home
|
|
42
|
+
if not iuser.at_home:
|
|
43
|
+
continue
|
|
44
|
+
if iuser.phone_on_charge:
|
|
45
|
+
# at least one user's phone is still on charge
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
self.night_is_on = False
|
|
49
|
+
if not self.night_is_on and state.value == 'night':
|
|
50
|
+
print("Day has come!")
|
|
51
|
+
return 'day'
|
|
52
|
+
|
|
53
|
+
def run(self):
|
|
54
|
+
while True:
|
|
55
|
+
instance_users = InstanceUser.objects.filter(
|
|
56
|
+
is_active=True, role__is_owner=True
|
|
57
|
+
)
|
|
58
|
+
self.state.refresh_from_db()
|
|
59
|
+
new_state = self.check_owner_phones(
|
|
60
|
+
self.state, instance_users, timezone.localtime()
|
|
61
|
+
)
|
|
62
|
+
if new_state:
|
|
63
|
+
self.state.send(new_state)
|
|
64
|
+
|
|
65
|
+
# randomize script load
|
|
66
|
+
time.sleep(random.randint(20, 40))
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from django.utils import timezone
|
|
3
|
+
from simo.core.middleware import get_current_instance
|
|
4
|
+
from simo.core.models import Component
|
|
5
|
+
from simo.users.models import InstanceUser
|
|
6
|
+
from simo.generic.scripting.helpers import LocalSun
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Automation:
|
|
10
|
+
STATE_COMPONENT_ID = {{ state_comp_id }}
|
|
11
|
+
last_state = None
|
|
12
|
+
weekdays_morning_hour = 10
|
|
13
|
+
weekends_morning_hour = 11
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.instance = get_current_instance()
|
|
17
|
+
self.state = Component.objects.get(id=self.STATE_COMPONENT_ID)
|
|
18
|
+
self.sun = LocalSun(self.instance.location)
|
|
19
|
+
|
|
20
|
+
def check_at_home(self):
|
|
21
|
+
return bool(InstanceUser.objects.filter(
|
|
22
|
+
is_active=True, at_home=True
|
|
23
|
+
).count())
|
|
24
|
+
|
|
25
|
+
def calculate_appropriate_state(self, localtime, at_home):
|
|
26
|
+
if not at_home:
|
|
27
|
+
return 'away'
|
|
28
|
+
if self.sun.is_night(localtime) \
|
|
29
|
+
and self.sun.get_sunset_time(localtime) < localtime:
|
|
30
|
+
return 'evening'
|
|
31
|
+
|
|
32
|
+
if localtime.weekday() < 5 \
|
|
33
|
+
and localtime.hour < self.weekdays_morning_hour:
|
|
34
|
+
return 'night'
|
|
35
|
+
|
|
36
|
+
if localtime.weekday() >= 5 \
|
|
37
|
+
and localtime.hour < self.weekends_morning_hour:
|
|
38
|
+
return 'night'
|
|
39
|
+
|
|
40
|
+
return 'day'
|
|
41
|
+
|
|
42
|
+
def get_new_state(self, state, localtime, at_home):
|
|
43
|
+
# If state component on vacation or in some other state
|
|
44
|
+
# we do not interfere!
|
|
45
|
+
if state.value not in ('day', 'night', 'evening', 'away'):
|
|
46
|
+
return
|
|
47
|
+
should_be = self.calculate_appropriate_state(
|
|
48
|
+
localtime, at_home
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if self.last_state != state.value:
|
|
52
|
+
# user changed something manually
|
|
53
|
+
# we must first wait for appropriate state to get in to
|
|
54
|
+
# manually selected one, only then we will transition to forward.
|
|
55
|
+
if should_be == state.value:
|
|
56
|
+
print("Consensus with system users reached!")
|
|
57
|
+
self.last_state = should_be
|
|
58
|
+
elif self.last_state != should_be:
|
|
59
|
+
print("New state: ", should_be)
|
|
60
|
+
self.last_state = should_be
|
|
61
|
+
return should_be
|
|
62
|
+
|
|
63
|
+
def run(self):
|
|
64
|
+
# do not interfere on script start,
|
|
65
|
+
# only later when we absolutely must
|
|
66
|
+
self.last_state = self.get_new_state(
|
|
67
|
+
self.state, timezone.localtime(),
|
|
68
|
+
self.check_at_home()
|
|
69
|
+
)
|
|
70
|
+
while True:
|
|
71
|
+
self.state.refresh_from_db()
|
|
72
|
+
new_state_value = self.get_new_state(
|
|
73
|
+
self.state, timezone.localtime(),
|
|
74
|
+
self.check_at_home()
|
|
75
|
+
)
|
|
76
|
+
if new_state_value:
|
|
77
|
+
self.state.send(new_state_value)
|
|
78
|
+
time.sleep(10)
|
|
Binary file
|
simo/fleet/models.py
CHANGED
|
@@ -33,7 +33,8 @@ def get_new_secret():
|
|
|
33
33
|
|
|
34
34
|
class InstanceOptions(models.Model):
|
|
35
35
|
instance = models.OneToOneField(
|
|
36
|
-
Instance, on_delete=models.CASCADE, related_name='fleet_options'
|
|
36
|
+
Instance, on_delete=models.CASCADE, related_name='fleet_options',
|
|
37
|
+
limit_choices_to={'is_active': True}
|
|
37
38
|
)
|
|
38
39
|
secret_key = models.CharField(max_length=20, default=get_new_secret)
|
|
39
40
|
|
|
@@ -46,7 +47,7 @@ def create_instance_options(sender, instance, *args, **kwargs):
|
|
|
46
47
|
class Colonel(DirtyFieldsMixin, models.Model):
|
|
47
48
|
instance = models.ForeignKey(
|
|
48
49
|
'core.Instance', on_delete=models.CASCADE, related_name='colonels',
|
|
49
|
-
|
|
50
|
+
limit_choices_to={'is_active': True}
|
|
50
51
|
)
|
|
51
52
|
uid = models.CharField(
|
|
52
53
|
max_length=100, db_index=True, editable=False, unique=True,
|
|
Binary file
|
|
Binary file
|
simo/generic/gateways.py
CHANGED
|
@@ -74,7 +74,10 @@ class ScriptRunHandler(multiprocessing.Process):
|
|
|
74
74
|
def run(self):
|
|
75
75
|
db_connection.connect()
|
|
76
76
|
self.component = Component.objects.get(id=self.component_id)
|
|
77
|
-
|
|
77
|
+
try:
|
|
78
|
+
tz = pytz.timezone(self.component.zone.instance.timezone)
|
|
79
|
+
except:
|
|
80
|
+
tz = pytz.timezone('UTC')
|
|
78
81
|
timezone.activate(tz)
|
|
79
82
|
introduce_instance(self.component.zone.instance)
|
|
80
83
|
self.logger = get_component_logger(self.component)
|
|
@@ -151,7 +154,7 @@ class GenericGatewayHandler(BaseObjectCommandsGatewayHandler):
|
|
|
151
154
|
for id, process in self.running_scripts.items():
|
|
152
155
|
if process.is_alive():
|
|
153
156
|
if not Component.objects.filter(id=id).count():
|
|
154
|
-
# script is deleted
|
|
157
|
+
# script is deleted, or instance deactivated
|
|
155
158
|
process.terminate()
|
|
156
159
|
continue
|
|
157
160
|
component = Component.objects.filter(id=id).exclude(
|
simo/generic/models.py
CHANGED
|
Binary file
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import random
|
|
3
|
-
import pytz
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
from django.utils import timezone
|
|
6
|
-
from simo.core.middleware import get_current_instance
|
|
7
|
-
from simo.core.models import Component
|
|
8
|
-
from simo.users.models import InstanceUser
|
|
9
|
-
from simo.generic.scripting.helpers import LocalSun
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class Automation:
|
|
13
|
-
REZIMAS_COMPONENT_ID = 130
|
|
14
|
-
|
|
15
|
-
def __init__(self):
|
|
16
|
-
self.instance = get_current_instance()
|
|
17
|
-
self.rezimas = Component.objects.get(id=self.REZIMAS_COMPONENT_ID)
|
|
18
|
-
self.sun = LocalSun(self.instance.location)
|
|
19
|
-
self.night_is_on = False
|
|
20
|
-
|
|
21
|
-
def check_owner_phones(self, rezimas, instance_users, datetime):
|
|
22
|
-
if not self.night_is_on:
|
|
23
|
-
if not (datetime.hour >= 22 or datetime.hour < 6):
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
for iuser in instance_users:
|
|
27
|
-
# skipping users that are not at home
|
|
28
|
-
if not iuser.at_home:
|
|
29
|
-
continue
|
|
30
|
-
if not iuser.phone_on_charge:
|
|
31
|
-
# at least one user's phone is not yet on charge
|
|
32
|
-
return
|
|
33
|
-
self.night_is_on = True
|
|
34
|
-
return 'night'
|
|
35
|
-
else:
|
|
36
|
-
# return new_rezimas diena only if there are still users
|
|
37
|
-
# at home, none of them have their phones on charge
|
|
38
|
-
# and current rezimas is still night
|
|
39
|
-
for iuser in instance_users:
|
|
40
|
-
# skipping users that are not at home
|
|
41
|
-
if not iuser.at_home:
|
|
42
|
-
continue
|
|
43
|
-
if iuser.phone_on_charge:
|
|
44
|
-
# at least one user's phone is still on charge
|
|
45
|
-
return
|
|
46
|
-
else:
|
|
47
|
-
self.night_is_on = False
|
|
48
|
-
if not self.night_is_on and rezimas.value == 'night':
|
|
49
|
-
return 'day'
|
|
50
|
-
|
|
51
|
-
def run(self):
|
|
52
|
-
while True:
|
|
53
|
-
instance_users = InstanceUser.objects.filter(
|
|
54
|
-
is_active=True, role__is_owner=True
|
|
55
|
-
)
|
|
56
|
-
self.rezimas.refresh_from_db()
|
|
57
|
-
new_rezimas = self.check_owner_phones(
|
|
58
|
-
self.rezimas, instance_users, timezone.localtime()
|
|
59
|
-
)
|
|
60
|
-
if new_rezimas:
|
|
61
|
-
self.rezimas.send(new_rezimas)
|
|
62
|
-
|
|
63
|
-
# randomize script load
|
|
64
|
-
time.sleep(random.randint(20, 40))
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def test(self):
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
simo/notifications/admin.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from django.contrib import admin
|
|
2
|
+
from simo.core.middleware import get_current_instance
|
|
2
3
|
from .models import Notification, UserNotification
|
|
3
4
|
|
|
4
5
|
|
|
@@ -14,10 +15,20 @@ class NotificationAdmin(admin.ModelAdmin):
|
|
|
14
15
|
inlines = UserNotificationInline,
|
|
15
16
|
actions = 'dispatch',
|
|
16
17
|
|
|
18
|
+
readonly_fields = 'instance',
|
|
19
|
+
|
|
20
|
+
def save_model(self, request, obj, form, change):
|
|
21
|
+
if not obj.id:
|
|
22
|
+
obj.instance = get_current_instance()
|
|
23
|
+
return super().save_model(request, obj, form, change)
|
|
24
|
+
|
|
17
25
|
def get_queryset(self, request):
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
qs = super().get_queryset(request)
|
|
27
|
+
instance = get_current_instance()
|
|
28
|
+
if instance:
|
|
29
|
+
qs = qs.filter(instance=instance)
|
|
30
|
+
return qs.prefetch_related('to_users')
|
|
31
|
+
|
|
21
32
|
|
|
22
33
|
def to(self, obj):
|
|
23
34
|
return ', '.join([str(u) for u in obj.to_users.all()])
|
simo/notifications/models.py
CHANGED
|
@@ -14,7 +14,9 @@ class Notification(models.Model):
|
|
|
14
14
|
Notification get's sent to_users as soon as it's created.
|
|
15
15
|
If new users are added, notification gets sent to those users as well.
|
|
16
16
|
'''
|
|
17
|
-
instance = models.ForeignKey(
|
|
17
|
+
instance = models.ForeignKey(
|
|
18
|
+
Instance, on_delete=models.CASCADE, limit_choices_to={'is_active': True}
|
|
19
|
+
)
|
|
18
20
|
datetime = models.DateTimeField(auto_now_add=True)
|
|
19
21
|
to_users = models.ManyToManyField(
|
|
20
22
|
User, through='notifications.UserNotification'
|
|
Binary file
|
|
Binary file
|
simo/users/api.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import sys
|
|
2
|
+
import datetime
|
|
2
3
|
from django.db.models import Q
|
|
3
4
|
from rest_framework import viewsets, mixins, status
|
|
4
5
|
from rest_framework.serializers import Serializer
|
|
@@ -211,12 +212,6 @@ class UserDeviceReport(InstanceMixin, viewsets.GenericViewSet):
|
|
|
211
212
|
[str(i) for i in location]
|
|
212
213
|
) if location else None
|
|
213
214
|
|
|
214
|
-
speed_mps = float(request.data.get('speed', 0))
|
|
215
|
-
if speed_mps < 0:
|
|
216
|
-
speed_mps = 0
|
|
217
|
-
speed_kmh = speed_mps * 3.6
|
|
218
|
-
|
|
219
|
-
|
|
220
215
|
if request.data.get('app_open', False):
|
|
221
216
|
user_device.is_primary = True
|
|
222
217
|
UserDevice.objects.filter(
|
|
@@ -231,7 +226,21 @@ class UserDeviceReport(InstanceMixin, viewsets.GenericViewSet):
|
|
|
231
226
|
) < dynamic_settings['users__at_home_radius']
|
|
232
227
|
elif not relay:
|
|
233
228
|
iu.at_home = True
|
|
234
|
-
|
|
229
|
+
speed_kmh = 0
|
|
230
|
+
if user_device.last_seen_location and iu.last_seen_location \
|
|
231
|
+
and iu.last_seen > timezone.now() - datetime.timedelta(seconds=30):
|
|
232
|
+
if user_device.last_seen_location == iu.last_seen_location:
|
|
233
|
+
speed_kmh = iu.last_seen_speed_kmh
|
|
234
|
+
else:
|
|
235
|
+
seconds_passed = (timezone.now() - user_device.last_seen).seconds
|
|
236
|
+
if not seconds_passed:
|
|
237
|
+
speed_kmh = 0
|
|
238
|
+
else:
|
|
239
|
+
moved_distance = haversine_distance(
|
|
240
|
+
iu.last_seen_location, user_device.last_seen_location
|
|
241
|
+
)
|
|
242
|
+
speed_mps = moved_distance / seconds_passed
|
|
243
|
+
speed_kmh = speed_mps * 3.6
|
|
235
244
|
iu.last_seen = user_device.last_seen
|
|
236
245
|
iu.last_seen_location = user_device.last_seen_location
|
|
237
246
|
iu.last_seen_speed_kmh = speed_kmh
|
simo/users/models.py
CHANGED
|
@@ -289,13 +289,13 @@ class User(AbstractBaseUser, SimoAdminMixin):
|
|
|
289
289
|
instances = cache.get(cache_key, 'expired')
|
|
290
290
|
if instances == 'expired':
|
|
291
291
|
if self.is_master:
|
|
292
|
-
instances = Instance.objects.
|
|
292
|
+
instances = Instance.objects.filter(is_active=True)
|
|
293
293
|
else:
|
|
294
294
|
instances = Instance.objects.filter(id__in=[
|
|
295
295
|
r.instance.id for r in self.instance_roles.filter(
|
|
296
296
|
is_active=True, instance__isnull=False
|
|
297
297
|
)
|
|
298
|
-
])
|
|
298
|
+
], is_active=True)
|
|
299
299
|
cache.set(cache_key, instances, 10)
|
|
300
300
|
return instances
|
|
301
301
|
|
|
@@ -51,12 +51,12 @@ simo/core/forms.py,sha256=nL_trDNs7RLic11zLSen4EobtywGx8igUMYe7Ojuv1k,21988
|
|
|
51
51
|
simo/core/gateways.py,sha256=m0eS3XjVe34Dge6xtoCq16kFWCKJcdQrT0JW0REqoq8,3715
|
|
52
52
|
simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
|
|
53
53
|
simo/core/managers.py,sha256=n-b3I4uXzfHKTeB1VMjSaMsDUxp8FegFJwnbV1IsWQ4,3019
|
|
54
|
-
simo/core/middleware.py,sha256=
|
|
55
|
-
simo/core/models.py,sha256=
|
|
54
|
+
simo/core/middleware.py,sha256=hExD7Vmw7eitk0vAjOwKzkwrtuw8YxpflF92j_CA2YY,3193
|
|
55
|
+
simo/core/models.py,sha256=dqwnGUc-BKefkWx4SfGDhiytP7vxAGFcKOlEXz2VhHA,22594
|
|
56
56
|
simo/core/permissions.py,sha256=v0iJM4LOeYoEfMiw3OLPYio272G1aUEAg_z9Wd1q5m0,2993
|
|
57
57
|
simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
|
|
58
58
|
simo/core/serializers.py,sha256=Pa2lhJ6VgNalbH4awbKdGJCYAPNsu5WQWfo6Tz6LbOQ,20782
|
|
59
|
-
simo/core/signal_receivers.py,sha256=
|
|
59
|
+
simo/core/signal_receivers.py,sha256=qCpzEUv5Bl9--K8fe08GVDmE6EBOj292YBia1TYDdSE,9267
|
|
60
60
|
simo/core/socket_consumers.py,sha256=trRZvBGTJ7xIbfdmVvn7zoiWp_qssSkMZykDrI5YQyE,9783
|
|
61
61
|
simo/core/storage.py,sha256=_5igjaoWZAiExGWFEJMElxUw55DzJG1jqFty33xe8BE,342
|
|
62
62
|
simo/core/tasks.py,sha256=dLutVjQdAhZVFldQpWilQEYfPcTFqkAoyGao0MTuKJ0,14583
|
|
@@ -84,12 +84,12 @@ simo/core/__pycache__/forms.cpython-38.pyc,sha256=O_mCWAQHAJhiqcKLUina7tIFbw5uXw
|
|
|
84
84
|
simo/core/__pycache__/gateways.cpython-38.pyc,sha256=D1ooHL-iSpQrxnD8uAl4xWFJmm-QWZfbkLiLlFOMtdU,4553
|
|
85
85
|
simo/core/__pycache__/loggers.cpython-38.pyc,sha256=Z-cdQnC6XlIonPV4Sl4E52tP4NMEdPAiHK0cFaIL7I8,1623
|
|
86
86
|
simo/core/__pycache__/managers.cpython-38.pyc,sha256=6RTIxyjOgpQGtAqcUyE2vFPS09w1V5Wmd_vOV7rHRRI,3370
|
|
87
|
-
simo/core/__pycache__/middleware.cpython-38.pyc,sha256=
|
|
88
|
-
simo/core/__pycache__/models.cpython-38.pyc,sha256=
|
|
87
|
+
simo/core/__pycache__/middleware.cpython-38.pyc,sha256=iOSTXSQl3sEsa-9kx_6w5zbEByRtfzJHT6XkUIYMGdE,2469
|
|
88
|
+
simo/core/__pycache__/models.cpython-38.pyc,sha256=lNpWQXIobV40Pxnq3p5PO8vSE6vX-nFrKARsWlk-76E,18508
|
|
89
89
|
simo/core/__pycache__/permissions.cpython-38.pyc,sha256=fH4iyqd9DdzRLEu2b621-FeM-napR0M7hzBUTHo9Q3g,2972
|
|
90
90
|
simo/core/__pycache__/routing.cpython-38.pyc,sha256=3T3FPJ8Cn99xZCGvMyg2xjl7al-Shm9CelbSpkJtNP8,599
|
|
91
91
|
simo/core/__pycache__/serializers.cpython-38.pyc,sha256=qIHxrurPk555mHc9P8Udg9eGv-ODw1FTmBS_jXrPuws,19220
|
|
92
|
-
simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=
|
|
92
|
+
simo/core/__pycache__/signal_receivers.cpython-38.pyc,sha256=lBVca6zNPVn3Ev98ekjPGzBR1MJk4xI19CyMcm4lf6A,7056
|
|
93
93
|
simo/core/__pycache__/socket_consumers.cpython-38.pyc,sha256=KqbO1cOewodVPcy0-htVefyUjCuELKV0o7fOfYqfgPc,8490
|
|
94
94
|
simo/core/__pycache__/storage.cpython-38.pyc,sha256=9R1Xu0FJDflfRXUPsqEgt0SpwiP7FGk7HaR8s8XRyI8,721
|
|
95
95
|
simo/core/__pycache__/tasks.cpython-38.pyc,sha256=qQZ1wP3ksyh6c6kmqMtkYxGs-MTTDhaqQDlYfK7vQ7c,10003
|
|
@@ -161,7 +161,7 @@ simo/core/management/commands/gateways_manager.py,sha256=oHzgC-eV4w_KHkiz6eCAlt3
|
|
|
161
161
|
simo/core/management/commands/on_http_start.py,sha256=A2V40pyGY7AfONhtnxiGATOkqd0i9FUvRRxkwyAJF9k,2252
|
|
162
162
|
simo/core/management/commands/run_gateway.py,sha256=bp0FQQoBeOSoxjHCCMicDL1fxPZZGyLgnq2QKht3bJo,645
|
|
163
163
|
simo/core/management/commands/__pycache__/__init__.cpython-38.pyc,sha256=WKpfZZpAB9D7U4X6oWQIrU_H-6rUmq8Gl9fj9XaY2fw,178
|
|
164
|
-
simo/core/management/commands/__pycache__/gateways_manager.cpython-38.pyc,sha256=
|
|
164
|
+
simo/core/management/commands/__pycache__/gateways_manager.cpython-38.pyc,sha256=g5xhLz6AgU7cGZ5EmoiBZIZuZbs9AN01ZRZEOCEFqeE,6031
|
|
165
165
|
simo/core/management/commands/__pycache__/on_http_start.cpython-38.pyc,sha256=LQeFW3oYYRrEPEcGghyeahFE114-4VbnKH4XaVGcQcg,3235
|
|
166
166
|
simo/core/migrations/0001_initial.py,sha256=0Uy7IqJxQQYlurs8Mw_RJy7NaWS7BU0VFmZBBz8YkQI,9220
|
|
167
167
|
simo/core/migrations/0002_load_icons.py,sha256=s9TtGo5NWEyWV3BspfbDNAlWqmQWxmDj7GjEaJXruFk,2044
|
|
@@ -10166,6 +10166,8 @@ simo/core/templates/admin/users/qr_code.html,sha256=kE4WNSVsPUvNUFnSUAY8jiD9JCvc
|
|
|
10166
10166
|
simo/core/templates/admin/wizard/discovery.html,sha256=xpAiXgKneT0d53c7h1MyAjoOFdXc_lDaH9TdelrggVU,6608
|
|
10167
10167
|
simo/core/templates/admin/wizard/field.html,sha256=ZbgzAUMs6RdJDH44yQ3-rmAkPmBdsIvBTk1RAQaENAs,413
|
|
10168
10168
|
simo/core/templates/admin/wizard/wizard_add.html,sha256=RPkwKXctu_yxJxjJqcvVEzG4YtK9-CJK801RPxleWRE,4127
|
|
10169
|
+
simo/core/templates/core/auto_night_day_script.py,sha256=6dnoU4UsjgdiEaD3hIPMovBRhI4p1aCAKL8ca_D-3zQ,2349
|
|
10170
|
+
simo/core/templates/core/auto_state_script.py,sha256=_UhSTpeCnv1oOzRzdOI9EXGdaSYevBolWChCKfPPZ6w,2666
|
|
10169
10171
|
simo/core/templates/core/icon_acutocomplete_select_item.html,sha256=D7aWefAJjrDqyMcwt4vtuwkruklJ1aSjCTi99HLrQUY,768
|
|
10170
10172
|
simo/core/templates/core/object_acutocomplete_select_item.html,sha256=pS8APlv1IdhfttONh3npzQNfrOhj63YC7837tnOfSHk,465
|
|
10171
10173
|
simo/core/templates/core/openvpn_client.conf,sha256=z1838G8v8vmIiQKyfE8URCCMpLsges5jbX3hDJkztF4,249
|
|
@@ -10223,7 +10225,7 @@ simo/fleet/controllers.py,sha256=fjri1GtCnflkkDpNqhTwy6i9CK6RDEB0Q_BtADzcG8E,291
|
|
|
10223
10225
|
simo/fleet/forms.py,sha256=XTkQUxce-6VPr7-HRONJnIzWZizeIUeA6DGqqTACInQ,62980
|
|
10224
10226
|
simo/fleet/gateways.py,sha256=lKEJW0MgaOEiNnijH50DNSVChvaUT3TA3UurcI57P8k,5677
|
|
10225
10227
|
simo/fleet/managers.py,sha256=XOpDOA9L-f_550TNSyXnJbun2EmtGz1TenVTMlUSb8E,807
|
|
10226
|
-
simo/fleet/models.py,sha256=
|
|
10228
|
+
simo/fleet/models.py,sha256=4ZHiT2yoUv3xnDzsMbPi0Z3DOvYzEfwYZw-jxFlqG30,16884
|
|
10227
10229
|
simo/fleet/routing.py,sha256=cofGsVWXMfPDwsJ6HM88xxtRxHwERhJ48Xyxc8mxg5o,149
|
|
10228
10230
|
simo/fleet/serializers.py,sha256=-16BjY_bp9VbDOYuD0V54h7r_RHpuLNkJX0SydWL9aU,2247
|
|
10229
10231
|
simo/fleet/socket_consumers.py,sha256=8RLEmKQ0Q7nVgJJ6IrU4ioocsWBJrgBVH_AUpVas1no,18095
|
|
@@ -10240,7 +10242,7 @@ simo/fleet/__pycache__/controllers.cpython-38.pyc,sha256=jtFHr_uyjCCeuidL-o-hGaf
|
|
|
10240
10242
|
simo/fleet/__pycache__/forms.cpython-38.pyc,sha256=8ARAilbCnSUjwluL0mmknFcNvBRn8oZ7b2-z8Yer6ns,42498
|
|
10241
10243
|
simo/fleet/__pycache__/gateways.cpython-38.pyc,sha256=0RKVn0ndreVKhsrukqeLPSdMnRrsQ_W7yeVeBkRLfIk,5058
|
|
10242
10244
|
simo/fleet/__pycache__/managers.cpython-38.pyc,sha256=8uz-xpUiqbGDgXIZ_XRZtFb-Tju6NGxflGg-Ee4Yo6k,1310
|
|
10243
|
-
simo/fleet/__pycache__/models.cpython-38.pyc,sha256=
|
|
10245
|
+
simo/fleet/__pycache__/models.cpython-38.pyc,sha256=ePD11IHU9AoiufsuwcgaXukCGkNE0dco-JPajXB96c0,13935
|
|
10244
10246
|
simo/fleet/__pycache__/routing.cpython-38.pyc,sha256=aPrCmxFKVyB8R8ZbJDwdPdFfvT7CvobovvZeq_mqRgY,314
|
|
10245
10247
|
simo/fleet/__pycache__/serializers.cpython-38.pyc,sha256=9ljhwoHkolcVrJwOVbYCbGPAUKgALRwor_M3W_K0adE,3173
|
|
10246
10248
|
simo/fleet/__pycache__/socket_consumers.cpython-38.pyc,sha256=cNLhA0PTF2BgXXcw4b4va1zIw-gBrghoRrSr8iZluE0,13893
|
|
@@ -10336,8 +10338,8 @@ simo/generic/app_widgets.py,sha256=vwYYVRKzKZ9XTvWTfEbaH4zpoHiDIHP6qFTNgZI-xvY,9
|
|
|
10336
10338
|
simo/generic/base_types.py,sha256=Bvf3lv6PXx_SwtwBH7qpkwysWuloNcKNRh3LiuZf-Dc,359
|
|
10337
10339
|
simo/generic/controllers.py,sha256=Xo0ZYQZfhDAwLq9H3uTrHWLj-HeLlxdXJ71dUESd41Y,49263
|
|
10338
10340
|
simo/generic/forms.py,sha256=nDrvNGbWTE_MSZmSXrKj1bSn-Ylo4w7Y1z-SZRKRYW8,30840
|
|
10339
|
-
simo/generic/gateways.py,sha256=
|
|
10340
|
-
simo/generic/models.py,sha256=
|
|
10341
|
+
simo/generic/gateways.py,sha256=dUzRBxVDdsx70mrCvxSQwhJr0ydQ5NtoLHoYeVLJmtA,15224
|
|
10342
|
+
simo/generic/models.py,sha256=Adq7ipWK-renxJlNW-SZnAq2oGEOwKx8EdUWaKnfcVQ,7597
|
|
10341
10343
|
simo/generic/routing.py,sha256=elQVZmgnPiieEuti4sJ7zITk1hlRxpgbotcutJJgC60,228
|
|
10342
10344
|
simo/generic/socket_consumers.py,sha256=K2OjphIhKJH48BvfFfoCOyCQZ1NmXb_phs6y1IP-qaQ,1757
|
|
10343
10345
|
simo/generic/__pycache__/__init__.cpython-38.pyc,sha256=mLu54WS9KIl-pHwVCBKpsDFIlOqml--JsOVzAUHg6cU,161
|
|
@@ -10345,16 +10347,16 @@ simo/generic/__pycache__/app_widgets.cpython-38.pyc,sha256=dt7fSf38eDA5hVUvVfpyt
|
|
|
10345
10347
|
simo/generic/__pycache__/base_types.cpython-38.pyc,sha256=8YDxrsRFGqaeBfSF3Y1WmIGDRHGH1Ww7dSBkxRxkKyc,511
|
|
10346
10348
|
simo/generic/__pycache__/controllers.cpython-38.pyc,sha256=HBZDEFhJAwd6YFWul_sX4OoA1r1m0DK1MLxJk9u70rk,32674
|
|
10347
10349
|
simo/generic/__pycache__/forms.cpython-38.pyc,sha256=JM1UN13391udDpBvNsbZURX5onDhLrOLIun-kISmGac,22078
|
|
10348
|
-
simo/generic/__pycache__/gateways.cpython-38.pyc,sha256=
|
|
10349
|
-
simo/generic/__pycache__/models.cpython-38.pyc,sha256=
|
|
10350
|
+
simo/generic/__pycache__/gateways.cpython-38.pyc,sha256=IazhRBe-YZ9t7_wq1fULoyLnxn3frR967lAN9D7MbKY,11583
|
|
10351
|
+
simo/generic/__pycache__/models.cpython-38.pyc,sha256=MZpum7syAFxuulf47K7gtUlJJ7xRD-IBUBAwUM1ZRnw,5825
|
|
10350
10352
|
simo/generic/__pycache__/routing.cpython-38.pyc,sha256=xtxTUTBTdivzFyA5Wh7k-hUj1WDO_FiRq6HYXdbr9Ks,382
|
|
10351
10353
|
simo/generic/__pycache__/socket_consumers.cpython-38.pyc,sha256=qJO5kvQLWhsQDOr1AtAtsAybuRWioxSkQei3Pc7rdP0,1737
|
|
10352
10354
|
simo/generic/scripting/__init__.py,sha256=aZZvNBae7unnux_zGHCIWCV2z47hVJc-DIL72Hqfkeo,600
|
|
10353
|
-
simo/generic/scripting/example.py,sha256=
|
|
10355
|
+
simo/generic/scripting/example.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10354
10356
|
simo/generic/scripting/helpers.py,sha256=Zt8Mx5AXIggzYk0e7jn-xQNR_NOqzolAReLkrmDJzVQ,3042
|
|
10355
10357
|
simo/generic/scripting/serializers.py,sha256=PjyFrjdPK1mBsgbNhyqMi9SWzcymqTa742ipy0LhAN4,1996
|
|
10356
10358
|
simo/generic/scripting/__pycache__/__init__.cpython-38.pyc,sha256=eHncoNpv5dy35IO1_htWd8CK0sHFBnU_WJ0hl5TKOHQ,794
|
|
10357
|
-
simo/generic/scripting/__pycache__/helpers.cpython-38.pyc,sha256=
|
|
10359
|
+
simo/generic/scripting/__pycache__/helpers.cpython-38.pyc,sha256=34sa3L2cK1Aw636PCaoCYIWUBIE1h6XmbgDIto9cLeo,2757
|
|
10358
10360
|
simo/generic/scripting/__pycache__/serializers.cpython-38.pyc,sha256=JD9KCNO27H18mkFaeSMdybTMdTvodqcZSLNbC3pheHU,3412
|
|
10359
10361
|
simo/generic/static/weather_icons/01d@2x.png,sha256=TZfWi6Rfddb2P-oldWWcjUiuCHiU9Yrc5hyrQAhF26I,948
|
|
10360
10362
|
simo/generic/static/weather_icons/01n@2x.png,sha256=e9RleTa0T7To9Wi2wJ-9waeTbfHOsUB_xGwkx-89eEg,945
|
|
@@ -10412,17 +10414,17 @@ simo/multimedia/migrations/__pycache__/0003_alter_sound_length.cpython-38.pyc,sh
|
|
|
10412
10414
|
simo/multimedia/migrations/__pycache__/0004_auto_20231023_1055.cpython-38.pyc,sha256=tX6x1gNeVcUHcCFvisP9Z2jPBE029TJG632fvtvUjV8,892
|
|
10413
10415
|
simo/multimedia/migrations/__pycache__/__init__.cpython-38.pyc,sha256=mCgSiQBphL85imdWyTi9-4zBDYF6HfXbhB0ycSPVVuA,175
|
|
10414
10416
|
simo/notifications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10415
|
-
simo/notifications/admin.py,sha256=
|
|
10417
|
+
simo/notifications/admin.py,sha256=WQbN_bd2KRxVjbOajeworNrV9QlDNSadQT58La0Nn2M,1174
|
|
10416
10418
|
simo/notifications/api.py,sha256=GXQpq68ULBaJpU8w3SJKaCKuxYGWYehKnGeocGB1RVc,1783
|
|
10417
|
-
simo/notifications/models.py,sha256=
|
|
10419
|
+
simo/notifications/models.py,sha256=gJW0ahHvSyFrb7BzrJXa3Nk2FFDvX361ZgLcf1k7ff8,2558
|
|
10418
10420
|
simo/notifications/serializers.py,sha256=altDEAPWwOhxRcEzE9-34jL8EFpyf3vPoEdAPoVLfGc,523
|
|
10419
10421
|
simo/notifications/utils.py,sha256=uBl-Y7WGu00iaGM5rrdogcq0OMRVtyVfJF39-mdB3_k,1853
|
|
10420
10422
|
simo/notifications/__pycache__/__init__.cpython-38.pyc,sha256=YvucUfu98XFvEEg1LYFMlOZJpo_jSGxTVrM-ylAFLOg,167
|
|
10421
|
-
simo/notifications/__pycache__/admin.cpython-38.pyc,sha256=
|
|
10423
|
+
simo/notifications/__pycache__/admin.cpython-38.pyc,sha256=MScNrtVM1wavefsPfxy0A7LVyXKcbvEkLH9GJkgNOl8,1945
|
|
10422
10424
|
simo/notifications/__pycache__/api.cpython-38.pyc,sha256=ys6E4AFghX6bq-rQ0gtA9s0Y2Hh-ypsWH8-Yz4edMrc,2073
|
|
10423
|
-
simo/notifications/__pycache__/models.cpython-38.pyc,sha256=
|
|
10425
|
+
simo/notifications/__pycache__/models.cpython-38.pyc,sha256=iOBlXejQrYV-M_SaPIGt6WbIV2YF5y5a3eXgnG5ZaJg,2604
|
|
10424
10426
|
simo/notifications/__pycache__/serializers.cpython-38.pyc,sha256=7-eRGKYuQ4g1SpKOMpz17SIiu1HmaMoYv-cJbaO9QGA,1028
|
|
10425
|
-
simo/notifications/__pycache__/utils.cpython-38.pyc,sha256=
|
|
10427
|
+
simo/notifications/__pycache__/utils.cpython-38.pyc,sha256=6Tq7VkW-pZLzWzcxPtBU9MDFZLO7iLY8-ygyefoJ5OQ,1529
|
|
10426
10428
|
simo/notifications/migrations/0001_initial.py,sha256=Zh69AQ-EKlQKfqfnMDVRcxvo1MxRY-TFLCdnNcgqi6g,2003
|
|
10427
10429
|
simo/notifications/migrations/0002_notification_instance.py,sha256=B3msbMeKvsuq-V7gvRADRjj5PFLayhi3pQvHZjqzO5g,563
|
|
10428
10430
|
simo/notifications/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -10431,14 +10433,14 @@ simo/notifications/migrations/__pycache__/0002_notification_instance.cpython-38.
|
|
|
10431
10433
|
simo/notifications/migrations/__pycache__/__init__.cpython-38.pyc,sha256=YMBRHVon2nWDtIUbghckjnC12sIg_ykPWhV5aM0tto4,178
|
|
10432
10434
|
simo/users/__init__.py,sha256=6a7uBpCWB_DR7p54rbHusc0xvi1qfT1ZCCQGb6TiBh8,52
|
|
10433
10435
|
simo/users/admin.py,sha256=Xr7faGeupUKkpo1QLRm84OS63u-5Rf2ir_nVEaAPBZw,6839
|
|
10434
|
-
simo/users/api.py,sha256=
|
|
10436
|
+
simo/users/api.py,sha256=JIjSCg_VOkYRYoKJrc9svJ1NpTuQjONX_sGnZ-am1sQ,12825
|
|
10435
10437
|
simo/users/apps.py,sha256=cq0A8-U1HALEwev0TicgFhr4CAu7Icz8rwq0HfOaL4E,207
|
|
10436
10438
|
simo/users/auth_backends.py,sha256=bBSNXQJ88TRXaQxyh1aETfmOIfiDr08Jnj8rSY9sHDk,4074
|
|
10437
10439
|
simo/users/auto_urls.py,sha256=lcJvteBsbHQMJieZpDz-63tDYejLApqsW3CUnDakd7k,272
|
|
10438
10440
|
simo/users/dynamic_settings.py,sha256=sEIsi4yJw3kH46Jq_aOkSuK7QTfQACGUE-lkyBogCaM,570
|
|
10439
10441
|
simo/users/managers.py,sha256=Fajwpm3wdMES73iPqoa_66J8g13bvUhjUtrexLKIcIU,312
|
|
10440
10442
|
simo/users/middleware.py,sha256=GMCrnWSc_2qCleyQIkfQGdL-pU-UTEcSg1wPvIKZ9uk,1210
|
|
10441
|
-
simo/users/models.py,sha256=
|
|
10443
|
+
simo/users/models.py,sha256=jq0045_J846w7aiTA6jqb0jliX_gHZaUuBZYsSUXa9o,19218
|
|
10442
10444
|
simo/users/permissions.py,sha256=IwtYS8yQdupWbYKR9VimSRDV3qCJ2jXP57Lyjpb2EQM,242
|
|
10443
10445
|
simo/users/serializers.py,sha256=zzw1KONTnaTNBaU0r4rNVxJ827KzD6Z5LuQt27ZsQ98,2516
|
|
10444
10446
|
simo/users/sso_urls.py,sha256=gQOaPvGMYFD0NCVSwyoWO-mTEHe5j9sbzV_RK7kdvp0,251
|
|
@@ -10448,14 +10450,14 @@ simo/users/utils.py,sha256=1HGSZyHRqQvdJ4RtAiZDg1juvgG8aOlrGXR7CcvsyQc,1886
|
|
|
10448
10450
|
simo/users/views.py,sha256=dOQVvmlHG7ihWKJLFUBcqKOA0UDctlMKR0pTc36JZqg,3487
|
|
10449
10451
|
simo/users/__pycache__/__init__.cpython-38.pyc,sha256=VFoDJE_SKKaPqqYaaBYd1Ndb1hjakkTo_u0EG_XJ1GM,211
|
|
10450
10452
|
simo/users/__pycache__/admin.cpython-38.pyc,sha256=tL8b3f181AjcN2dSsDUPkqjpZziEOtVzI535SbnbDzc,7793
|
|
10451
|
-
simo/users/__pycache__/api.cpython-38.pyc,sha256=
|
|
10453
|
+
simo/users/__pycache__/api.cpython-38.pyc,sha256=M49GlN1f-IMXKpokLJVxcfVmXYxPneXQ9z9v0RFysQk,10411
|
|
10452
10454
|
simo/users/__pycache__/apps.cpython-38.pyc,sha256=dgbWL8CxzzISJQTmq_4IztPJ2UzykNVdqA2Ae1PmeGk,605
|
|
10453
10455
|
simo/users/__pycache__/auth_backends.cpython-38.pyc,sha256=n5nx2QSXNj2idzRcGE6bAagMN-8qxoCs580H1EFZXls,3105
|
|
10454
10456
|
simo/users/__pycache__/auto_urls.cpython-38.pyc,sha256=K-3sz2h-cEitoflSmZk1t0eUg5mQMMGLNZFREVwG7_o,430
|
|
10455
10457
|
simo/users/__pycache__/dynamic_settings.cpython-38.pyc,sha256=6F8JBjZkHykySnmZjNEzjS0ijbmPdcp9yUAZ5kqq_Fo,864
|
|
10456
10458
|
simo/users/__pycache__/managers.cpython-38.pyc,sha256=8NvEXbI795f-BXs6CvE_Kp0PpWfYmEJIZ8Bh8H6S2PQ,705
|
|
10457
10459
|
simo/users/__pycache__/middleware.cpython-38.pyc,sha256=Tj4nVEAvxEW3xA63fBRiJWRJpz_M848ZOqbHioc_IPE,1149
|
|
10458
|
-
simo/users/__pycache__/models.cpython-38.pyc,sha256=
|
|
10460
|
+
simo/users/__pycache__/models.cpython-38.pyc,sha256=bEyKyFodxErPeXSPvGHroYl4BKjDgLQY_4Pr_YTwLow,17859
|
|
10459
10461
|
simo/users/__pycache__/permissions.cpython-38.pyc,sha256=ez5NxoL_JUeeH6GsKhvFreuA3FCBgGf9floSypdXUtM,633
|
|
10460
10462
|
simo/users/__pycache__/serializers.cpython-38.pyc,sha256=Dy8RAcwNkNSXoJHvLp8fozURyHCtucqpSPyqZtbnMZc,3732
|
|
10461
10463
|
simo/users/__pycache__/sso_urls.cpython-38.pyc,sha256=uAwDozpOmrhUald-8tOHANILXkH7-TI8fNYXOtPkSY8,402
|
|
@@ -10549,9 +10551,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
|
|
|
10549
10551
|
simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10550
10552
|
simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10551
10553
|
simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10552
|
-
simo-2.5.
|
|
10553
|
-
simo-2.5.
|
|
10554
|
-
simo-2.5.
|
|
10555
|
-
simo-2.5.
|
|
10556
|
-
simo-2.5.
|
|
10557
|
-
simo-2.5.
|
|
10554
|
+
simo-2.5.6.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
|
|
10555
|
+
simo-2.5.6.dist-info/METADATA,sha256=Q8JlXRCVfWvw15jO8jXZp65dGIWYlLNfz4u8gNIA5NI,1923
|
|
10556
|
+
simo-2.5.6.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
10557
|
+
simo-2.5.6.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
|
|
10558
|
+
simo-2.5.6.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
|
|
10559
|
+
simo-2.5.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|