simo 1.6.2__py3-none-any.whl → 1.6.4__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/api.py CHANGED
@@ -3,7 +3,6 @@ from calendar import monthrange
3
3
  import pytz
4
4
  import logging
5
5
  from django.db.models import Q, Prefetch
6
- from django.urls import get_script_prefix
7
6
  from django.utils.translation import gettext_lazy as _
8
7
  from django.utils import timezone
9
8
  from django.shortcuts import get_object_or_404
simo/core/apps.py CHANGED
@@ -19,6 +19,6 @@ class CoreAppConfig(AppConfig):
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)
22
- auto_update_cron = f'*/10 * * * * {executable_path} \n'
22
+ auto_update_cron = f'0 * * * * {executable_path} \n'
23
23
  cron_out = subprocess.Popen(['crontab', '-'], stdin=subprocess.PIPE)
24
24
  cron_out.communicate(input=str.encode(auto_update_cron))
@@ -1,5 +1,4 @@
1
1
  from dal import autocomplete
2
- from django.urls import get_script_prefix
3
2
  from django.db.models import Q
4
3
  from django.template.loader import render_to_string
5
4
  from simo.core.utils.helpers import search_queryset
@@ -24,7 +23,7 @@ class IconModelAutocomplete(autocomplete.Select2QuerySetView):
24
23
  def get_result_label(self, item):
25
24
  return render_to_string(
26
25
  'core/icon_acutocomplete_select_item.html', {
27
- 'icon': item, 'prefix': get_script_prefix()[:-1]
26
+ 'icon': item,
28
27
  }
29
28
  )
30
29
 
@@ -70,7 +69,7 @@ class CategoryAutocomplete(autocomplete.Select2QuerySetView):
70
69
  def get_result_label(self, item):
71
70
  return render_to_string(
72
71
  'core/object_acutocomplete_select_item.html', {
73
- 'object': item, 'prefix': get_script_prefix()[:-1]
72
+ 'object': item
74
73
  }
75
74
  )
76
75
 
@@ -96,7 +95,7 @@ class ZoneAutocomplete(autocomplete.Select2QuerySetView):
96
95
  def get_result_label(self, item):
97
96
  return render_to_string(
98
97
  'core/object_acutocomplete_select_item.html', {
99
- 'object': item, 'prefix': get_script_prefix()[:-1]
98
+ 'object': item
100
99
  }
101
100
  )
102
101
 
@@ -133,7 +132,7 @@ class ComponentAutocomplete(autocomplete.Select2QuerySetView):
133
132
  def get_result_label(self, item):
134
133
  return render_to_string(
135
134
  'core/object_acutocomplete_select_item.html', {
136
- 'object': item, 'prefix': get_script_prefix()[:-1]
135
+ 'object': item
137
136
  }
138
137
  )
139
138
 
simo/core/events.py CHANGED
@@ -2,9 +2,14 @@ import json
2
2
  import time
3
3
  import logging
4
4
  import threading
5
+ import sys
6
+ import json
7
+ import traceback
8
+ import pytz
5
9
  from django.contrib.contenttypes.models import ContentType
6
10
  from django.conf import settings
7
11
  import paho.mqtt.client as mqtt
12
+ from django.utils import timezone
8
13
  from django.utils.translation import gettext_lazy as _
9
14
  import paho.mqtt.publish as mqtt_publish
10
15
 
@@ -130,3 +135,54 @@ class EventsStream:
130
135
  def on_tick(self):
131
136
  """Override me to do something every second"""
132
137
  pass
138
+
139
+
140
+ class OnChangeMixin:
141
+
142
+ on_change_fields = ('value', )
143
+
144
+ def get_instance(self):
145
+ # default for component
146
+ return self.zone.instance.timezone
147
+
148
+ def on_mqtt_connect(self, mqtt_client, userdata, flags, rc):
149
+ mqtt_client.subscribe(ObjectManagementEvent.TOPIC)
150
+
151
+ def on_mqtt_message(self, client, userdata, msg):
152
+ payload = json.loads(msg.payload)
153
+ if not self._on_change_function:
154
+ return
155
+ if payload['obj_pk'] != self.id:
156
+ return
157
+ if payload['obj_ct_pk'] != self._obj_ct_id:
158
+ return
159
+ if payload['event'] != 'changed':
160
+ return
161
+ if 'value' not in payload.get('dirty_fields', {}):
162
+ return
163
+
164
+ tz = pytz.timezone(self.gget_instance().timezone)
165
+ timezone.activate(tz)
166
+
167
+ self.refresh_from_db()
168
+
169
+ try:
170
+ self._on_change_function(self)
171
+ except Exception:
172
+ print(traceback.format_exc(), file=sys.stderr)
173
+
174
+ def on_change(self, function):
175
+ if function:
176
+ self._mqtt_client = mqtt.Client()
177
+ self._mqtt_client.on_connect = self.on_mqtt_connect
178
+ self._mqtt_client.on_message = self.on_mqtt_message
179
+ self._mqtt_client.connect(host=settings.MQTT_HOST,
180
+ port=settings.MQTT_PORT)
181
+ self._mqtt_client.loop_start()
182
+ self._on_change_function = function
183
+ self._obj_ct_id = ContentType.objects.get_for_model(self).pk
184
+ elif self._mqtt_client:
185
+ self._mqtt_client.disconnect()
186
+ self._mqtt_client.loop_stop()
187
+ self._mqtt_client = None
188
+ self._on_change_function = None
simo/core/middleware.py CHANGED
@@ -1,14 +1,9 @@
1
1
  import pytz
2
2
  import threading
3
- from django.urls import set_script_prefix, get_script_prefix
4
- from django.shortcuts import redirect, render
3
+ from django.urls import set_script_prefix
5
4
  from django.utils import timezone
6
- from django.conf import settings
7
- from simo.users.models import User
8
5
  from simo.conf import dynamic_settings
9
6
 
10
-
11
-
12
7
  _thread_locals = threading.local()
13
8
 
14
9
 
@@ -25,7 +20,6 @@ def simo_router_middleware(get_response):
25
20
  _thread_locals.request = request
26
21
 
27
22
  request.relay = None
28
- router_prefix = '/'
29
23
 
30
24
  if request.META.get('HTTP_HOST', '').endswith('.simo.io'):
31
25
  router_prefix = dynamic_settings['core__remote_http']
@@ -0,0 +1,23 @@
1
+ # Generated by Django 3.2.9 on 2023-12-21 07:35
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('core', '0021_auto_20231020_1041'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='gateway',
15
+ name='type',
16
+ field=models.CharField(choices=[('simo.generic.gateways.DummyGatewayHandler', 'Dummy'), ('simo_esphome.gateways.ESPHomeGatewayHandler', 'ESPHome'), ('simo.generic.gateways.GenericGatewayHandler', 'Generic'), ('NukiDevices', 'Nuki'), ('simo_fleet.gateways.FleetGatewayHandler', 'SIMO.io Fleet'), ('simo_sonos.gateways.SONOSGatewayHandler', 'SONOS'), ('simo_zwave.gateways.ZwaveGatewayHandler', 'Zwave')], db_index=True, max_length=200, unique=True),
17
+ ),
18
+ migrations.AlterField(
19
+ model_name='instance',
20
+ name='timezone',
21
+ field=models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Asmera', 'Africa/Asmera'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Timbuktu', 'Africa/Timbuktu'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/ComodRivadavia', 'America/Argentina/ComodRivadavia'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Atka', 'America/Atka'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Buenos_Aires', 'America/Buenos_Aires'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Catamarca', 'America/Catamarca'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Ciudad_Juarez', 'America/Ciudad_Juarez'), ('America/Coral_Harbour', 'America/Coral_Harbour'), ('America/Cordoba', 'America/Cordoba'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Ensenada', 'America/Ensenada'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fort_Wayne', 'America/Fort_Wayne'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Indianapolis', 'America/Indianapolis'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Jujuy', 'America/Jujuy'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Knox_IN', 'America/Knox_IN'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Louisville', 'America/Louisville'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Mendoza', 'America/Mendoza'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montreal', 'America/Montreal'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Nuuk', 'America/Nuuk'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Acre', 'America/Porto_Acre'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Rosario', 'America/Rosario'), ('America/Santa_Isabel', 'America/Santa_Isabel'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Shiprock', 'America/Shiprock'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Virgin', 'America/Virgin'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/South_Pole', 'Antarctica/South_Pole'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Ashkhabad', 'Asia/Ashkhabad'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Calcutta', 'Asia/Calcutta'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Chongqing', 'Asia/Chongqing'), ('Asia/Chungking', 'Asia/Chungking'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Dacca', 'Asia/Dacca'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Harbin', 'Asia/Harbin'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Istanbul', 'Asia/Istanbul'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kashgar', 'Asia/Kashgar'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Katmandu', 'Asia/Katmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macao', 'Asia/Macao'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Rangoon', 'Asia/Rangoon'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Saigon', 'Asia/Saigon'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Tel_Aviv', 'Asia/Tel_Aviv'), ('Asia/Thimbu', 'Asia/Thimbu'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ujung_Pandang', 'Asia/Ujung_Pandang'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Ulan_Bator', 'Asia/Ulan_Bator'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faeroe', 'Atlantic/Faeroe'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Jan_Mayen', 'Atlantic/Jan_Mayen'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/ACT', 'Australia/ACT'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Canberra', 'Australia/Canberra'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/LHI', 'Australia/LHI'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/NSW', 'Australia/NSW'), ('Australia/North', 'Australia/North'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Queensland', 'Australia/Queensland'), ('Australia/South', 'Australia/South'), ('Australia/Sydney', 'Australia/Sydney'), ('Australia/Tasmania', 'Australia/Tasmania'), ('Australia/Victoria', 'Australia/Victoria'), ('Australia/West', 'Australia/West'), ('Australia/Yancowinna', 'Australia/Yancowinna'), ('Brazil/Acre', 'Brazil/Acre'), ('Brazil/DeNoronha', 'Brazil/DeNoronha'), ('Brazil/East', 'Brazil/East'), ('Brazil/West', 'Brazil/West'), ('CET', 'CET'), ('CST6CDT', 'CST6CDT'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Canada/Saskatchewan', 'Canada/Saskatchewan'), ('Canada/Yukon', 'Canada/Yukon'), ('Chile/Continental', 'Chile/Continental'), ('Chile/EasterIsland', 'Chile/EasterIsland'), ('Cuba', 'Cuba'), ('EET', 'EET'), ('EST', 'EST'), ('EST5EDT', 'EST5EDT'), ('Egypt', 'Egypt'), ('Eire', 'Eire'), ('Etc/GMT', 'Etc/GMT'), ('Etc/GMT+0', 'Etc/GMT+0'), ('Etc/GMT+1', 'Etc/GMT+1'), ('Etc/GMT+10', 'Etc/GMT+10'), ('Etc/GMT+11', 'Etc/GMT+11'), ('Etc/GMT+12', 'Etc/GMT+12'), ('Etc/GMT+2', 'Etc/GMT+2'), ('Etc/GMT+3', 'Etc/GMT+3'), ('Etc/GMT+4', 'Etc/GMT+4'), ('Etc/GMT+5', 'Etc/GMT+5'), ('Etc/GMT+6', 'Etc/GMT+6'), ('Etc/GMT+7', 'Etc/GMT+7'), ('Etc/GMT+8', 'Etc/GMT+8'), ('Etc/GMT+9', 'Etc/GMT+9'), ('Etc/GMT-0', 'Etc/GMT-0'), ('Etc/GMT-1', 'Etc/GMT-1'), ('Etc/GMT-10', 'Etc/GMT-10'), ('Etc/GMT-11', 'Etc/GMT-11'), ('Etc/GMT-12', 'Etc/GMT-12'), ('Etc/GMT-13', 'Etc/GMT-13'), ('Etc/GMT-14', 'Etc/GMT-14'), ('Etc/GMT-2', 'Etc/GMT-2'), ('Etc/GMT-3', 'Etc/GMT-3'), ('Etc/GMT-4', 'Etc/GMT-4'), ('Etc/GMT-5', 'Etc/GMT-5'), ('Etc/GMT-6', 'Etc/GMT-6'), ('Etc/GMT-7', 'Etc/GMT-7'), ('Etc/GMT-8', 'Etc/GMT-8'), ('Etc/GMT-9', 'Etc/GMT-9'), ('Etc/GMT0', 'Etc/GMT0'), ('Etc/Greenwich', 'Etc/Greenwich'), ('Etc/UCT', 'Etc/UCT'), ('Etc/UTC', 'Etc/UTC'), ('Etc/Universal', 'Etc/Universal'), ('Etc/Zulu', 'Etc/Zulu'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belfast', 'Europe/Belfast'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Kyiv', 'Europe/Kyiv'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Nicosia', 'Europe/Nicosia'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Tiraspol', 'Europe/Tiraspol'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GB', 'GB'), ('GB-Eire', 'GB-Eire'), ('GMT', 'GMT'), ('GMT+0', 'GMT+0'), ('GMT-0', 'GMT-0'), ('GMT0', 'GMT0'), ('Greenwich', 'Greenwich'), ('HST', 'HST'), ('Hongkong', 'Hongkong'), ('Iceland', 'Iceland'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Iran', 'Iran'), ('Israel', 'Israel'), ('Jamaica', 'Jamaica'), ('Japan', 'Japan'), ('Kwajalein', 'Kwajalein'), ('Libya', 'Libya'), ('MET', 'MET'), ('MST', 'MST'), ('MST7MDT', 'MST7MDT'), ('Mexico/BajaNorte', 'Mexico/BajaNorte'), ('Mexico/BajaSur', 'Mexico/BajaSur'), ('Mexico/General', 'Mexico/General'), ('NZ', 'NZ'), ('NZ-CHAT', 'NZ-CHAT'), ('Navajo', 'Navajo'), ('PRC', 'PRC'), ('PST8PDT', 'PST8PDT'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Johnston', 'Pacific/Johnston'), ('Pacific/Kanton', 'Pacific/Kanton'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Ponape', 'Pacific/Ponape'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Samoa', 'Pacific/Samoa'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Truk', 'Pacific/Truk'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('Pacific/Yap', 'Pacific/Yap'), ('Poland', 'Poland'), ('Portugal', 'Portugal'), ('ROC', 'ROC'), ('ROK', 'ROK'), ('Singapore', 'Singapore'), ('Turkey', 'Turkey'), ('UCT', 'UCT'), ('US/Alaska', 'US/Alaska'), ('US/Aleutian', 'US/Aleutian'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/East-Indiana', 'US/East-Indiana'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Indiana-Starke', 'US/Indiana-Starke'), ('US/Michigan', 'US/Michigan'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('US/Samoa', 'US/Samoa'), ('UTC', 'UTC'), ('Universal', 'Universal'), ('W-SU', 'W-SU'), ('WET', 'WET'), ('Zulu', 'Zulu')], db_index=True, max_length=50),
22
+ ),
23
+ ]
simo/core/models.py CHANGED
@@ -1,9 +1,7 @@
1
1
  import os
2
2
  import sys
3
3
  import inspect
4
- import json
5
- import traceback
6
- import pytz
4
+
7
5
  from django.utils.text import slugify
8
6
  from django.core.cache import cache
9
7
  from django.urls import reverse_lazy
@@ -25,10 +23,7 @@ from django.contrib.contenttypes.models import ContentType
25
23
  from simo.core.utils.mixins import SimoAdminMixin
26
24
  from simo.core.storage import OverwriteStorage
27
25
  from simo.core.utils.validators import validate_svg
28
- from .events import ObjectCommand, ObjectManagementEvent
29
-
30
-
31
-
26
+ from .events import ObjectCommand, ObjectManagementEvent, OnChangeMixin
32
27
 
33
28
 
34
29
  User = get_user_model()
@@ -239,7 +234,7 @@ class Gateway(DirtyFieldsMixin, models.Model, SimoAdminMixin):
239
234
  )
240
235
 
241
236
 
242
- class Component(DirtyFieldsMixin, models.Model, SimoAdminMixin):
237
+ class Component(DirtyFieldsMixin, models.Model, SimoAdminMixin, OnChangeMixin):
243
238
  name = models.CharField(
244
239
  _('name'), max_length=100, db_index=True
245
240
  )
@@ -403,47 +398,6 @@ def translate_before_set(self, value):
403
398
  return '%s | %s' % (self.zone.name, self.name)
404
399
  return self.name
405
400
 
406
- def on_mqtt_connect(self, mqtt_client, userdata, flags, rc):
407
- mqtt_client.subscribe(ObjectManagementEvent.TOPIC)
408
-
409
- def on_mqtt_message(self, client, userdata, msg):
410
- payload = json.loads(msg.payload)
411
- if not self._on_change_function:
412
- return
413
- if payload['obj_pk'] != self.id:
414
- return
415
- if payload['obj_ct_pk'] != self._obj_ct_id:
416
- return
417
- if payload['event'] != 'changed':
418
- return
419
- if 'value' not in payload.get('dirty_fields', {}):
420
- return
421
-
422
- tz = pytz.timezone(self.zone.instance.timezone)
423
- timezone.activate(tz)
424
-
425
- self.refresh_from_db()
426
-
427
- try:
428
- self._on_change_function(self)
429
- except Exception:
430
- print(traceback.format_exc(), file=sys.stderr)
431
-
432
- def on_change(self, function):
433
- if function:
434
- self._mqtt_client = mqtt.Client()
435
- self._mqtt_client.on_connect = self.on_mqtt_connect
436
- self._mqtt_client.on_message = self.on_mqtt_message
437
- self._mqtt_client.connect(host=settings.MQTT_HOST,
438
- port=settings.MQTT_PORT)
439
- self._mqtt_client.loop_start()
440
- self._on_change_function = function
441
- self._obj_ct_id = ContentType.objects.get_for_model(self).pk
442
- elif self._mqtt_client:
443
- self._mqtt_client.disconnect()
444
- self._mqtt_client.loop_stop()
445
- self._mqtt_client = None
446
- self._on_change_function = None
447
401
 
448
402
  def get_socket_url(self):
449
403
  return reverse_lazy(
@@ -6,7 +6,7 @@ import os
6
6
  import logging
7
7
  from ansi2html import Ansi2HTMLConverter
8
8
  from asgiref.sync import sync_to_async
9
- from django.urls import set_script_prefix, get_script_prefix
9
+ from django.urls import set_script_prefix
10
10
  from django.core.exceptions import ValidationError
11
11
  from django.template.loader import render_to_string
12
12
  from django.conf import settings
simo/core/widgets.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from django import forms
2
2
  from django.conf import settings
3
+ from django.templatetags.static import static
3
4
  from django.utils.safestring import mark_safe
4
5
  from location_field.widgets import LocationWidget as OrgLocationWidget
5
6
 
@@ -12,6 +13,14 @@ class LocationWidget(OrgLocationWidget):
12
13
  if zoom:
13
14
  self.options['map.zoom'] = zoom
14
15
 
16
+ @property
17
+ def media(self):
18
+ return forms.Media({
19
+ 'js': [
20
+ static('location_field') + '/js/form.js',
21
+ ],
22
+ })
23
+
15
24
 
16
25
  class SVGFileWidget(forms.ClearableFileInput):
17
26
  template_name = 'admin/svg_file_widget.html'
@@ -1123,6 +1123,7 @@ class AlarmClock(ControllerBase):
1123
1123
  week_days.sort()
1124
1124
  week_days = week_days + [d + 7 for d in week_days]
1125
1125
  for wd in week_days:
1126
+ alarm = json.loads(json.dumps(alarm))
1126
1127
  if wd < weekday:
1127
1128
  continue
1128
1129
  days_diff = wd - weekday
simo/users/admin.py CHANGED
@@ -6,7 +6,7 @@ from django.contrib.auth.admin import UserAdmin as OrgUserAdmin
6
6
  from django.contrib import admin
7
7
  from .models import (
8
8
  PermissionsRole, ComponentPermission, User, UserDevice, UserDeviceReportLog,
9
- InstanceInvitation, UserInstanceRole
9
+ InstanceInvitation, InstanceUser
10
10
  )
11
11
 
12
12
 
@@ -67,8 +67,8 @@ class UserDeviceInline(admin.TabularInline):
67
67
  return mark_safe('<a href="%s">more >></a>' % obj.get_admin_url())
68
68
 
69
69
 
70
- class UserInstanceRoleInline(admin.TabularInline):
71
- model = UserInstanceRole
70
+ class InstanceUserInline(admin.TabularInline):
71
+ model = InstanceUser
72
72
  extra = 0
73
73
  readonly_fields = 'instance', 'at_home'
74
74
 
@@ -90,7 +90,7 @@ class UserAdmin(OrgUserAdmin):
90
90
  'name', 'email', 'avatar',
91
91
  'last_action', 'ssh_key',
92
92
  )
93
- inlines = UserDeviceInline, UserInstanceRoleInline
93
+ inlines = UserDeviceInline, InstanceUserInline
94
94
 
95
95
  def name_display(self, obj=None):
96
96
  if not obj:
@@ -132,8 +132,8 @@ admin.site.unregister(Group)
132
132
  @admin.register(UserDeviceReportLog)
133
133
  class UserDeviceLogInline(admin.ModelAdmin):
134
134
  model = UserDeviceReportLog
135
- readonly_fields = 'datetime', 'app_open', 'location', 'relay', 'at_home'
136
- list_display = 'datetime', 'app_open', 'location', 'relay', 'at_home'
135
+ readonly_fields = 'datetime', 'app_open', 'location', 'relay'
136
+ list_display = 'datetime', 'app_open', 'location', 'relay'
137
137
  fields = readonly_fields
138
138
  list_filter = 'user_device__user',
139
139
 
simo/users/api.py CHANGED
@@ -11,7 +11,7 @@ from simo.core.api import InstanceMixin
11
11
  from simo.core.models import Instance
12
12
  from .models import (
13
13
  User, UserDevice, UserDeviceReportLog, PermissionsRole, InstanceInvitation,
14
- UserInstanceRole
14
+ InstanceUser
15
15
  )
16
16
  from .serializers import (
17
17
  UserSerializer, PermissionsRoleSerializer, InstanceInvitationSerializer
@@ -169,12 +169,6 @@ class UserDeviceReport(viewsets.GenericViewSet):
169
169
  if request.META.get('HTTP_HOST', '').endswith('.simo.io'):
170
170
  relay = request.META.get('HTTP_HOST')
171
171
 
172
- at_home = False
173
- if not relay:
174
- at_home = True
175
- elif location:
176
- pass
177
-
178
172
 
179
173
  # TODO: fire at home event:
180
174
  # from simo.core.events import Event
@@ -185,9 +179,9 @@ class UserDeviceReport(viewsets.GenericViewSet):
185
179
  # ).publish()
186
180
 
187
181
  if not relay:
188
- UserInstanceRole.objects.filter(
189
- user=request.user
190
- ).update(at_home=True)
182
+ for item in InstanceUser.objects.filter(user=request.user):
183
+ item.at_home = True
184
+ item.save()
191
185
  elif location:
192
186
  for instance in Instance.objects.all():
193
187
  cords = instance.location
@@ -201,19 +195,21 @@ class UserDeviceReport(viewsets.GenericViewSet):
201
195
  else:
202
196
  if distance(instance_location, location).meters < \
203
197
  dynamic_settings['users__at_home_radius']:
204
- UserInstanceRole.objects.filter(
205
- user=request.user, instance=instance
206
- ).update(at_home=True)
198
+ at_home = True
207
199
  else:
208
- UserInstanceRole.objects.filter(
209
- user=request.user, instance=instance
210
- ).update(at_home=False)
200
+ at_home = False
201
+
202
+ for item in InstanceUser.objects.filter(
203
+ user=request.user, instance=instance
204
+ ):
205
+ item.at_home = at_home
206
+ item.save()
211
207
 
212
208
  log_entry = UserDeviceReportLog.objects.create(
213
209
  user_device=user_device,
214
210
  app_open=request.data.get('app_open', False),
215
211
  location=','.join([str(i) for i in location]) if location else None,
216
- relay=relay, at_home=at_home
212
+ relay=relay
217
213
  )
218
214
  # Do not keep more than 1000 entries for every device.
219
215
  for log in UserDeviceReportLog.objects.filter(
@@ -4,7 +4,7 @@ import requests
4
4
  from django.core.files import File
5
5
  from django.contrib.auth.backends import ModelBackend
6
6
  from django.utils import timezone
7
- from .models import User, InstanceInvitation, UserInstanceRole
7
+ from .models import User, InstanceInvitation, InstanceUser
8
8
  from .utils import get_superuser_role
9
9
 
10
10
 
@@ -52,7 +52,7 @@ class SSOBackend(ModelBackend):
52
52
  if invitation:
53
53
  invitation.taken_by = user
54
54
  invitation.save()
55
- UserInstanceRole.objects.create(
55
+ InstanceUser.objects.create(
56
56
  user=user, role=invitation.role,
57
57
  instance=invitation.instance
58
58
  )
@@ -0,0 +1,22 @@
1
+ # Generated by Django 3.2.9 on 2023-12-21 07:35
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('core', '0022_auto_20231221_0735'),
10
+ ('users', '0016_auto_20231005_1050'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.RenameModel(
15
+ old_name='UserInstanceRole',
16
+ new_name='InstanceUser',
17
+ ),
18
+ migrations.RemoveField(
19
+ model_name='userdevicereportlog',
20
+ name='at_home',
21
+ ),
22
+ ]
simo/users/models.py CHANGED
@@ -7,6 +7,8 @@ from django.db.models import Q
7
7
  from django.db import transaction
8
8
  from django.db.models.signals import post_save, post_delete, m2m_changed
9
9
  from django.dispatch import receiver
10
+ from model_utils import FieldTracker
11
+ from dirtyfields import DirtyFieldsMixin
10
12
  from django.core.exceptions import ValidationError
11
13
  from django.contrib.auth.models import (
12
14
  AbstractBaseUser, PermissionsMixin, UserManager as DefaultUserManager
@@ -17,6 +19,7 @@ from location_field.models.plain import PlainLocationField
17
19
  from simo.conf import dynamic_settings
18
20
  from simo.core.utils.mixins import SimoAdminMixin
19
21
  from simo.core.utils.helpers import get_random_string
22
+ from simo.core.events import OnChangeMixin
20
23
  from .middleware import get_current_user
21
24
  from .utils import rebuild_authorized_keys
22
25
 
@@ -69,7 +72,7 @@ class UserManager(DefaultUserManager):
69
72
  return user
70
73
 
71
74
 
72
- class UserInstanceRole(models.Model):
75
+ class InstanceUser(DirtyFieldsMixin, models.Model, OnChangeMixin):
73
76
  user = models.ForeignKey(
74
77
  'User', on_delete=models.CASCADE, related_name='instance_roles'
75
78
  )
@@ -91,6 +94,23 @@ class UserInstanceRole(models.Model):
91
94
  self.instance = self.role.instance
92
95
  return super().save(*args, **kwargs)
93
96
 
97
+ def get_instance(self):
98
+ return self.instance
99
+
100
+
101
+ @receiver(post_save, sender=InstanceUser)
102
+ def post_instance_user_save(sender, instance, created, **kwargs):
103
+ if created:
104
+ return
105
+ from simo.core.events import ObjectManagementEvent
106
+ dirty_fields = instance.get_dirty_fields()
107
+ if 'at_home' in dirty_fields:
108
+ def post_update():
109
+ ObjectManagementEvent(
110
+ instance, 'changed', dirty_fields=dirty_fields
111
+ ).publish()
112
+ transaction.on_commit(post_update)
113
+
94
114
 
95
115
  class User(AbstractBaseUser, SimoAdminMixin):
96
116
  name = models.CharField(_('name'), max_length=150)
@@ -101,7 +121,7 @@ class User(AbstractBaseUser, SimoAdminMixin):
101
121
  )
102
122
  avatar_url = models.URLField(null=True, blank=True)
103
123
  avatar_last_change = models.DateTimeField(auto_now_add=True)
104
- roles = models.ManyToManyField(PermissionsRole, through=UserInstanceRole)
124
+ roles = models.ManyToManyField(PermissionsRole, through=InstanceUser)
105
125
  is_active = models.BooleanField(
106
126
  _('active'),
107
127
  default=True,
@@ -205,7 +225,7 @@ class User(AbstractBaseUser, SimoAdminMixin):
205
225
  if not role:
206
226
  raise ValueError("There is no such a role on this instance")
207
227
 
208
- UserInstanceRole.objects.update_or_create(
228
+ InstanceUser.objects.update_or_create(
209
229
  user=self, instance=self._instance, defaults={
210
230
  'role': role
211
231
  }
@@ -324,7 +344,6 @@ class UserDeviceReportLog(models.Model):
324
344
  help_text="Sent via remote relay if specified, otherwise it's from LAN."
325
345
  )
326
346
  location = PlainLocationField(zoom=7, null=True, blank=True)
327
- at_home = models.BooleanField(default=False)
328
347
 
329
348
  class Meta:
330
349
  ordering = '-datetime',
simo/users/serializers.py CHANGED
@@ -3,7 +3,7 @@ from collections.abc import Iterable
3
3
  from simo.core.middleware import get_current_request
4
4
  from simo.core.serializers import TimestampField
5
5
  from easy_thumbnails.files import get_thumbnailer
6
- from .models import User, PermissionsRole, InstanceInvitation, UserInstanceRole
6
+ from .models import User, PermissionsRole, InstanceInvitation, InstanceUser
7
7
 
8
8
 
9
9
  class UserSerializer(serializers.ModelSerializer):
@@ -42,7 +42,7 @@ class UserSerializer(serializers.ModelSerializer):
42
42
  return None
43
43
 
44
44
  def get_at_home(self, obj):
45
- return UserInstanceRole.objects.filter(
45
+ return InstanceUser.objects.filter(
46
46
  user=obj
47
47
  ).first().at_home
48
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 1.6.2
3
+ Version: 1.6.4
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
@@ -14,34 +14,34 @@ simo/_hub_template/hub/settings.py,sha256=4QhvhbtLRxHvAntwqG_qeAAtpDUqKvN4jzw9u3
14
14
  simo/_hub_template/hub/urls.py,sha256=Ydm-1BkYAzWeEF-MKSDIFf-7aE4qNLPm48-SA51XgJQ,25
15
15
  simo/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  simo/core/admin.py,sha256=4l2XFoI9yUoOuQkyYdpwxt-PGj-VTVcMb-BiA_NHYok,16588
17
- simo/core/api.py,sha256=6X1oJTp28g7Xt1Wcc_C1TyFqXvbQ87vEtDdSbVz0Lgo,19219
17
+ simo/core/api.py,sha256=AZBNVfi75XeoRU-VctlhHr25uIymuAn_cec4fNzUpAU,19177
18
18
  simo/core/api_auth.py,sha256=8Pp6Rcn3aL5hpQpW2Ph5XZ1rWnN1MIFvium8zlbzSwQ,1108
19
19
  simo/core/app_widgets.py,sha256=SP1txwI8_robAapIjalciS1cnJGoPH6udi6-k3fGC-g,1928
20
- simo/core/apps.py,sha256=acSeesKk3NPT4OKRHnz8X5SXu6wEWXBsIPJPrLEZ51k,902
20
+ simo/core/apps.py,sha256=T41TluDrtjzZ8T5LcvA5OnImmn08HB9tXk1SkZ52k3I,899
21
21
  simo/core/auto_urls.py,sha256=YZcvHqmAs4_azA_F_yz3CBsxrHAGijOPHib3SJCAoR0,1089
22
- simo/core/autocomplete_views.py,sha256=gPl0OeBypnPyhHEuRomrGLft8ho_2YnfQbewnTg1iSw,4034
22
+ simo/core/autocomplete_views.py,sha256=ygbVEOfyygWNy2BanB46Ov0NfWxBFAwwKp5CqAkrGMc,3849
23
23
  simo/core/base_types.py,sha256=OkRoAHp8P3r79k3IlUzkhycqlHDkeq7AAhOgsz7qGz8,552
24
24
  simo/core/context.py,sha256=xmGQ5h6HXw9-_XTuJSXyNiWDRHAVauqGCxmSJo0mxjE,1261
25
25
  simo/core/controllers.py,sha256=pP93QRFdCDRdo-yOqZTHD_LBRkbM-LWeGwWpDanS6os,22836
26
26
  simo/core/dynamic_settings.py,sha256=gLAL4IiZ55T-zXPsfwpaIYpw-QPfxkEJVbt-wNIlyrY,2214
27
- simo/core/events.py,sha256=g2jafhZ65EfvRVb24xfkDAcC-1FvX9R_RyrFnWyVMkw,3758
27
+ simo/core/events.py,sha256=0q5Rez-C92JSJLo5PW1B8-lgWWRfF2OBH8XSPbHtN5c,5539
28
28
  simo/core/filters.py,sha256=ghtOZcrwNAkIyF5_G9Sn73NkiI71mXv0NhwCk4IyMIM,411
29
29
  simo/core/forms.py,sha256=s-Cjw--vibCmxk6IQ_4M5IQOMuE3Z8re75NFPPmi4O4,19735
30
30
  simo/core/gateways.py,sha256=pFTOAfiglyGZ-6NCAHZZs1Lhnp0rVb3IhNc1vX7cZmY,2563
31
31
  simo/core/loggers.py,sha256=EBdq23gTQScVfQVH-xeP90-wII2DQFDjoROAW6ggUP4,1645
32
- simo/core/middleware.py,sha256=dHrdJdIWuxkQj9NGcpReVyXb0pA0vN-j6VivVDYbjHA,1728
33
- simo/core/models.py,sha256=ZpmQ4CNnd4ZqgwRwnJ6kGUwb6Rns9gU4kne8XGwzlZg,19405
32
+ simo/core/middleware.py,sha256=2EELD2mMWpPl3ispu2Yl7zeXUZp7s-PAJm-W-3BRsF0,1565
33
+ simo/core/models.py,sha256=m912O5z4fLYRGY58e5t4ZGZvKL06QPG_K5j4OWwLRYc,17862
34
34
  simo/core/permissions.py,sha256=1GI59JZxl_sL9qzSt2uhoOnYnORDmcOJ8Fb37LbrhJE,576
35
35
  simo/core/routing.py,sha256=X1_IHxyA-_Q7hw1udDoviVP4_FSBDl8GYETTC2zWTbY,499
36
36
  simo/core/serializers.py,sha256=IX5Lnhq6v8tYVFysz7w5K7QelK3fVXOjTUMjuomzbBs,4200
37
37
  simo/core/signal_receivers.py,sha256=sTHwSnCnBaZKFwTSEspkkH490GF7Paxar6KxyoWlh1I,3361
38
- simo/core/socket_consumers.py,sha256=u73FDyGpKR05V0WvQOyPe9TWYncAIe5vJSTVw1yJLfc,9658
38
+ simo/core/socket_consumers.py,sha256=gF6QVVr1T60IFSwx4dS8jlkUifRPlFqVrQq2AL4e5UY,9639
39
39
  simo/core/storage.py,sha256=46x-20HXGa-_gHUBFZYYL72FoR3jjOaYt-i7QDHezzM,981
40
40
  simo/core/tasks.py,sha256=jZKctxcEiO3sqVlkWRuDzeYrA77H_9hAc48mfTmOz_w,10225
41
41
  simo/core/todos.py,sha256=eYVXfLGiapkxKK57XuviSNe3WsUYyIWZ0hgQJk7ThKo,665
42
42
  simo/core/types.py,sha256=WJEq48mIbFi_5Alt4wxWMGXxNxUTXqfQU5koH7wqHHI,1108
43
43
  simo/core/views.py,sha256=Vr4eyLLIbxyPld-mOWH-hn0iqFfAbrK2jCHo_7nhvYE,5420
44
- simo/core/widgets.py,sha256=CTOyo6qHV2jUmNxA2t-tecmM8bXqSrUKXPk1MgcMz2Q,2612
44
+ simo/core/widgets.py,sha256=J9e06C6I22F6xKic3VMgG7WeX07glAcl-4bF2Mg180A,2827
45
45
  simo/core/db_backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
46
  simo/core/db_backend/base.py,sha256=IiE1r74oa6z05QhFMDUnn2ET0dYpye_fMaw_ksYHnrA,1303
47
47
  simo/core/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -70,6 +70,7 @@ simo/core/migrations/0018_auto_20231005_0622.py,sha256=NCITPVoBK_QC-oarTvjzvw-0I
70
70
  simo/core/migrations/0019_alter_gateway_type.py,sha256=qy4vwa4Rm2iE1Kez3X-EMrOGyTMfoQum8Qb45KtUaKQ,738
71
71
  simo/core/migrations/0020_component_meta.py,sha256=aO3qKCRZoAkdKIbRBDlN3H0YaOJmAnvFBScRqDSRy3I,397
72
72
  simo/core/migrations/0021_auto_20231020_1041.py,sha256=OmXoVeWfb8HPvGlP0iC1ZYqByj7pI4T6L2-lEsmbfSQ,998
73
+ simo/core/migrations/0022_auto_20231221_0735.py,sha256=vn8eIRzqWetG_6z3m9dOXqaWtUKeNS3oTkv3EbtwWbY,23894
73
74
  simo/core/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
75
  simo/core/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
76
  simo/core/templatetags/components_list.py,sha256=dcwXEgVrP2xuRpGpv1yQ_DHvmitsuF93PhDa9y69F2M,18540
@@ -90,7 +91,7 @@ simo/core/utils/validators.py,sha256=PGqW9E8tA6I68RiZg_38DS_MsZs1ew_6vQY4YRKhBdU
90
91
  simo/generic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
92
  simo/generic/app_widgets.py,sha256=E_pnpA1hxMIhenRCrHoQ5cik06jm2BAHCkl_eo-OudU,1264
92
93
  simo/generic/base_types.py,sha256=djymox_boXTHX1BTTCLXrCH7ED-uAsV_idhaDOc3OLI,409
93
- simo/generic/controllers.py,sha256=HoZ-_qwgr_p2nlZXN-qNdPlJEvmmkHRxm9CiQAsA9zE,51086
94
+ simo/generic/controllers.py,sha256=J8lfRwgfRIS9BS901lKZZO4tuRus7XKXVIG8VRTBQgQ,51144
94
95
  simo/generic/forms.py,sha256=zF-QYfu6C0TZ7sJ5_-VkhUweV0_J8gg0CC07At6RIK8,19829
95
96
  simo/generic/gateways.py,sha256=Pp29L_2AoZ_4nW6rLHmDCbDoac-yK9evJ1ZTcfMOItc,14807
96
97
  simo/generic/models.py,sha256=XG8VnLSpMSiBnbKwvMknF9J9kdbmBolXvJ9L3Giz8pQ,3330
@@ -121,15 +122,15 @@ simo/notifications/migrations/0001_initial.py,sha256=Zh69AQ-EKlQKfqfnMDVRcxvo1Mx
121
122
  simo/notifications/migrations/0002_notification_instance.py,sha256=B3msbMeKvsuq-V7gvRADRjj5PFLayhi3pQvHZjqzO5g,563
122
123
  simo/notifications/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
124
  simo/users/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
124
- simo/users/admin.py,sha256=0OXhdPbcnfXXwWgEQd0p7E_kZcW3HrIqhlizPzop1LQ,6331
125
- simo/users/api.py,sha256=6yTvpsDV9Fhkey6Wa7cvDS9D0jkqnm9wS-MJNZ8zfNs,9204
126
- simo/users/auth_backends.py,sha256=JRlzwd2-MxFo0xJAezI_A4K_-SIlEOm6OFkW0fgbuTs,2495
125
+ simo/users/admin.py,sha256=NJe9t3fh3ETKPTz0RRhmAsAND-lODEv937fOgnf4gcc,6293
126
+ simo/users/api.py,sha256=9DDVAJ-cpWdkcQCKzQK-E_zV1LFP_K_HGwVRD-FM_Ko,9060
127
+ simo/users/auth_backends.py,sha256=RWoDgfFA32mrS-b0DbbW7_Ve8ZMKp-NqX7Ywg5uaLFI,2487
127
128
  simo/users/auto_urls.py,sha256=ee0d6fWABkJY5mQOTC8KhrqDI6d8xZkYZ4ja-gZJ-rw,269
128
129
  simo/users/dynamic_settings.py,sha256=sEIsi4yJw3kH46Jq_aOkSuK7QTfQACGUE-lkyBogCaM,570
129
130
  simo/users/middleware.py,sha256=lwZQ1koxOEWcRI2PD_EXo3AX8exO-z4R5jOFwfTHRw8,739
130
- simo/users/models.py,sha256=TaJ8tpBg8TkgpQqAiA0pUcASHExkbfqbWZnVm_gBWuU,14328
131
+ simo/users/models.py,sha256=bqdY8BXHhFjaElXgSoRFN7vHXmwMY9JcPzoZU1GNoXg,14948
131
132
  simo/users/permissions.py,sha256=IwtYS8yQdupWbYKR9VimSRDV3qCJ2jXP57Lyjpb2EQM,242
132
- simo/users/serializers.py,sha256=121PP1ACykE5Wfev10kjqy4z-N9L-rHWXwufiipORt0,2009
133
+ simo/users/serializers.py,sha256=K0b5snRTn1ZSbG0wWu9P_0GE8MYYxmNxfAzJlwl00HI,2001
133
134
  simo/users/sso_urls.py,sha256=pcb_GhYHRtmairxJhMXE1bdcTma0BcYfKU3nCRtHQMQ,244
134
135
  simo/users/sso_views.py,sha256=-XI67TvQ7SN3goU4OuAHyn84u_1vtusvpn7Pu0K97zo,4648
135
136
  simo/users/tasks.py,sha256=tZPr4w0kgElHImbKuDZn0ixXR3xf_uU-RNpGbdpA5-c,796
@@ -151,9 +152,10 @@ simo/users/migrations/0013_remove_user_roles.py,sha256=UIau3WxXLM8EpFy16s3rO_Qt6
151
152
  simo/users/migrations/0014_user_roles.py,sha256=rxbSd655IEQ6IvXqOUTpJL6XsvrKEqjpL7XmewhrEwI,431
152
153
  simo/users/migrations/0015_remove_user_at_home.py,sha256=rEpLyrmKLL24Mzm2icrdi0A9DzaNENPBmNsZZeMpGw4,317
153
154
  simo/users/migrations/0016_auto_20231005_1050.py,sha256=PlvqGjJFk0oyd7zd1ZL4urbRj0cMBPICkcQtU04O64Y,719
155
+ simo/users/migrations/0017_auto_20231221_0735.py,sha256=u7o6-f4WB_MiMVNayl4ERBo3oQxgGvMMIMtClo7vPQQ,506
154
156
  simo/users/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
155
- simo-1.6.2.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
156
- simo-1.6.2.dist-info/METADATA,sha256=Edj_dVDN1ol2GWJJnmRpFf21agug-MILOMc3TaZCNzM,1748
157
- simo-1.6.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
158
- simo-1.6.2.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
159
- simo-1.6.2.dist-info/RECORD,,
157
+ simo-1.6.4.dist-info/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
158
+ simo-1.6.4.dist-info/METADATA,sha256=YnV8O01KrQ47L3AkjpXVvddzEVkMaBAfaq7tRwyboh4,1748
159
+ simo-1.6.4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
160
+ simo-1.6.4.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
161
+ simo-1.6.4.dist-info/RECORD,,
File without changes