simo 2.0.42__py3-none-any.whl → 2.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of simo might be problematic. Click here for more details.

Files changed (124) hide show
  1. simo/__pycache__/asgi.cpython-38.pyc +0 -0
  2. simo/__pycache__/settings.cpython-38.pyc +0 -0
  3. simo/__pycache__/wsgi.cpython-38.pyc +0 -0
  4. simo/asgi.py +1 -1
  5. simo/core/__init__.py +1 -0
  6. simo/core/__pycache__/__init__.cpython-38.pyc +0 -0
  7. simo/core/__pycache__/admin.cpython-38.pyc +0 -0
  8. simo/core/__pycache__/api.cpython-38.pyc +0 -0
  9. simo/core/__pycache__/api_meta.cpython-38.pyc +0 -0
  10. simo/core/__pycache__/app_widgets.cpython-38.pyc +0 -0
  11. simo/core/__pycache__/apps.cpython-38.pyc +0 -0
  12. simo/core/__pycache__/auto_urls.cpython-38.pyc +0 -0
  13. simo/core/__pycache__/base_types.cpython-38.pyc +0 -0
  14. simo/core/__pycache__/controllers.cpython-38.pyc +0 -0
  15. simo/core/__pycache__/dynamic_settings.cpython-38.pyc +0 -0
  16. simo/core/__pycache__/form_fields.cpython-38.pyc +0 -0
  17. simo/core/__pycache__/forms.cpython-38.pyc +0 -0
  18. simo/core/__pycache__/gateways.cpython-38.pyc +0 -0
  19. simo/core/__pycache__/managers.cpython-38.pyc +0 -0
  20. simo/core/__pycache__/models.cpython-38.pyc +0 -0
  21. simo/core/__pycache__/permissions.cpython-38.pyc +0 -0
  22. simo/core/__pycache__/serializers.cpython-38.pyc +0 -0
  23. simo/core/__pycache__/signal_receivers.cpython-38.pyc +0 -0
  24. simo/core/__pycache__/tasks.cpython-38.pyc +0 -0
  25. simo/core/__pycache__/views.cpython-38.pyc +0 -0
  26. simo/core/admin.py +26 -26
  27. simo/core/api.py +22 -2
  28. simo/core/api_meta.py +23 -13
  29. simo/core/app_widgets.py +6 -0
  30. simo/core/apps.py +13 -0
  31. simo/core/auto_urls.py +2 -3
  32. simo/core/base_types.py +1 -0
  33. simo/core/controllers.py +57 -0
  34. simo/core/dynamic_settings.py +0 -8
  35. simo/core/form_fields.py +93 -0
  36. simo/core/forms.py +16 -101
  37. simo/core/gateways.py +1 -1
  38. simo/core/managers.py +14 -1
  39. simo/core/migrations/0037_auto_20240606_1057.py +33 -0
  40. simo/core/migrations/0038_remove_instance_cover_image_and_more.py +30 -0
  41. simo/core/migrations/__pycache__/0037_auto_20240606_1057.cpython-38.pyc +0 -0
  42. simo/core/migrations/__pycache__/0038_remove_instance_cover_image_and_more.cpython-38.pyc +0 -0
  43. simo/core/models.py +30 -16
  44. simo/core/permissions.py +6 -3
  45. simo/core/serializers.py +77 -5
  46. simo/core/signal_receivers.py +25 -0
  47. simo/core/static/admin/css/simo.css +14 -0
  48. simo/core/tasks.py +82 -49
  49. simo/core/templates/admin/controller_widgets/button.html +8 -0
  50. simo/core/templates/admin/core/component_change_form.html +97 -0
  51. simo/core/templates/admin/formset_widget.html +88 -118
  52. simo/core/templates/admin/formset_widget_old.html +122 -0
  53. simo/core/templates/admin/user_tools.html +0 -3
  54. simo/core/templates/admin/wizard/wizard_add.html +16 -9
  55. simo/core/utils/__pycache__/admin.cpython-38.pyc +0 -0
  56. simo/core/utils/__pycache__/cache.cpython-38.pyc +0 -0
  57. simo/core/utils/__pycache__/formsets.cpython-38.pyc +0 -0
  58. simo/core/utils/admin.py +11 -0
  59. simo/core/utils/cache.py +15 -0
  60. simo/core/utils/formsets.py +11 -18
  61. simo/core/views.py +2 -85
  62. simo/fleet/__pycache__/auto_urls.cpython-38.pyc +0 -0
  63. simo/fleet/__pycache__/controllers.cpython-38.pyc +0 -0
  64. simo/fleet/__pycache__/forms.cpython-38.pyc +0 -0
  65. simo/fleet/__pycache__/gateways.cpython-38.pyc +0 -0
  66. simo/fleet/__pycache__/models.cpython-38.pyc +0 -0
  67. simo/fleet/__pycache__/socket_consumers.cpython-38.pyc +0 -0
  68. simo/fleet/__pycache__/utils.cpython-38.pyc +0 -0
  69. simo/fleet/__pycache__/views.cpython-38.pyc +0 -0
  70. simo/fleet/auto_urls.py +7 -1
  71. simo/fleet/controllers.py +194 -31
  72. simo/fleet/forms.py +223 -87
  73. simo/fleet/gateways.py +53 -2
  74. simo/fleet/migrations/0036_auto_20240605_0702.py +68 -0
  75. simo/fleet/migrations/0037_alter_colonelpin_options_alter_colonelpin_no_and_more.py +27 -0
  76. simo/fleet/migrations/__pycache__/0036_auto_20240605_0702.cpython-38.pyc +0 -0
  77. simo/fleet/migrations/__pycache__/0037_alter_colonelpin_options_alter_colonelpin_no_and_more.cpython-38.pyc +0 -0
  78. simo/fleet/models.py +35 -6
  79. simo/fleet/socket_consumers.py +1 -1
  80. simo/fleet/templates/fleet/controllers_info/button.md +16 -0
  81. simo/fleet/utils.py +31 -1
  82. simo/fleet/views.py +45 -0
  83. simo/generic/__pycache__/controllers.cpython-38.pyc +0 -0
  84. simo/generic/__pycache__/forms.cpython-38.pyc +0 -0
  85. simo/generic/__pycache__/gateways.cpython-38.pyc +0 -0
  86. simo/generic/controllers.py +61 -16
  87. simo/generic/forms.py +0 -3
  88. simo/generic/gateways.py +2 -0
  89. simo/generic/templates/admin/controller_widgets/blinds.html +2 -1
  90. simo/generic/templates/admin/controller_widgets/weather_forecast.html +1 -1
  91. simo/generic/templates/generic/controllers_info/dummy.md +3 -0
  92. simo/generic/templates/generic/controllers_info/stateselect.md +2 -0
  93. simo/management/__init__.py +0 -0
  94. simo/management/__pycache__/__init__.cpython-38.pyc +0 -0
  95. simo/management/__pycache__/on_http_start.cpython-38.pyc +0 -0
  96. simo/{_hub_template → management/_hub_template}/hub/nginx.conf +2 -2
  97. simo/{auto_update.py → management/auto_update.py} +3 -0
  98. simo/{cli.py → management/copy_template.py} +3 -16
  99. simo/management/install.py +258 -0
  100. simo/{on_http_start.py → management/on_http_start.py} +22 -2
  101. simo/settings.py +20 -4
  102. simo/users/__init__.py +1 -0
  103. simo/users/__pycache__/__init__.cpython-38.pyc +0 -0
  104. simo/users/__pycache__/admin.cpython-38.pyc +0 -0
  105. simo/users/__pycache__/apps.cpython-38.pyc +0 -0
  106. simo/users/__pycache__/models.cpython-38.pyc +0 -0
  107. simo/users/apps.py +9 -0
  108. simo/users/migrations/__pycache__/0029_alter_instanceuser_options_instanceuser_order.cpython-38.pyc +0 -0
  109. simo/users/migrations/__pycache__/0030_alter_instanceuser_options_remove_instanceuser_order.cpython-38.pyc +0 -0
  110. simo/users/models.py +16 -3
  111. {simo-2.0.42.dist-info → simo-2.1.2.dist-info}/METADATA +5 -3
  112. {simo-2.0.42.dist-info → simo-2.1.2.dist-info}/RECORD +122 -95
  113. simo-2.1.2.dist-info/entry_points.txt +2 -0
  114. simo/__pycache__/on_http_start.cpython-38.pyc +0 -0
  115. simo/wsgi.py +0 -7
  116. /simo/{_hub_template → management/_hub_template}/hub/asgi.py +0 -0
  117. /simo/{_hub_template → management/_hub_template}/hub/celeryc.py +0 -0
  118. /simo/{_hub_template → management/_hub_template}/hub/manage.py +0 -0
  119. /simo/{_hub_template → management/_hub_template}/hub/settings.py +0 -0
  120. /simo/{_hub_template → management/_hub_template}/hub/supervisor.conf +0 -0
  121. /simo/{_hub_template → management/_hub_template}/hub/urls.py +0 -0
  122. {simo-2.0.42.dist-info → simo-2.1.2.dist-info}/LICENSE.md +0 -0
  123. {simo-2.0.42.dist-info → simo-2.1.2.dist-info}/WHEEL +0 -0
  124. {simo-2.0.42.dist-info → simo-2.1.2.dist-info}/top_level.txt +0 -0
@@ -26,6 +26,9 @@ def perform_update():
26
26
  if proc.returncode:
27
27
  raise Exception(err.decode())
28
28
 
29
+ from simo.management.install import install_dependencies
30
+ install_dependencies()
31
+
29
32
  proc = subprocess.Popen(
30
33
  [os.path.join(HUB_DIR, 'manage.py'), 'migrate'],
31
34
  cwd=HUB_DIR,
@@ -1,6 +1,5 @@
1
- """Console script for simo."""
1
+ #!/usr/bin/env python
2
2
  import sys
3
- import click
4
3
  import os
5
4
  import shutil
6
5
  import simo
@@ -8,7 +7,7 @@ from django.template import Context, Engine
8
7
  from django.core.management.utils import get_random_secret_key
9
8
 
10
9
 
11
- def copy_default_template(to_directory='/etc/SIMO'):
10
+ def copy_template(to_directory='/etc/SIMO'):
12
11
  template_file_extensions = ['.py', '.conf']
13
12
 
14
13
  context = Context({
@@ -49,18 +48,6 @@ def copy_default_template(to_directory='/etc/SIMO'):
49
48
  os.makedirs(os.path.join(root, dirname), exist_ok=True)
50
49
 
51
50
 
52
- @click.command()
53
- def init():
54
- copy_default_template()
55
-
56
-
57
- @click.group()
58
- def main(args=None):
59
- pass
60
-
61
-
62
- main.add_command(init)
63
-
64
51
 
65
52
  if __name__ == "__main__":
66
- sys.exit(main()) # pragma: no cover
53
+ sys.exit(copy_template())
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env python
2
+
3
+ """
4
+ This should be called after simo has just been installed.
5
+ It prepares and powers up SIMO.io hub.
6
+ However it is not guaranteed to be fully operational.
7
+ """
8
+ import os, sys, json, subprocess, socket, shutil, traceback
9
+ import simo
10
+ from django.template import Context, Engine
11
+ from django.core.management.utils import get_random_secret_key
12
+
13
+
14
+
15
+ def install_dependencies():
16
+
17
+ status = subprocess.call(
18
+ 'apt install postgresql libpq-dev postgresql-client '
19
+ 'postgresql-client-common python3-pip redis-server supervisor '
20
+ 'mosquitto libopenjp2-7 libtiff5 pkg-config libcairo2-dev '
21
+ 'libgirepository1.0-dev libcairo2 libudev-dev gdal-bin net-tools '
22
+ 'timeshift nginx postgis openvpn ffmpeg libsm6 libxext6 ssh keychain -y',
23
+ shell=True
24
+ )
25
+ if status != 0:
26
+ print("Unable install required packages.")
27
+ return
28
+
29
+ return True
30
+
31
+
32
+ def get_ip():
33
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
34
+ try:
35
+ # doesn't even have to be reachable
36
+ s.connect(('10.255.255.255', 1))
37
+ IP = s.getsockname()[0]
38
+ except Exception:
39
+ IP = '127.0.0.1'
40
+ finally:
41
+ s.close()
42
+ return IP
43
+
44
+
45
+ def copy_template(to_directory='/etc/SIMO'):
46
+ template_file_extensions = ['.py', '.conf']
47
+
48
+ context = Context({
49
+ 'secret_key': get_random_secret_key(),
50
+ 'project_dir': to_directory,
51
+ 'base_dir': to_directory
52
+ }, autoescape=False)
53
+ template_dir = os.path.join(
54
+ os.path.dirname(simo.__file__), '_hub_template'
55
+ )
56
+ prefix_length = len(template_dir) + 1
57
+ for root, dirs, files in os.walk(template_dir):
58
+ relative_dir = root[prefix_length:]
59
+ target_dir = os.path.join(to_directory, relative_dir)
60
+ os.makedirs(target_dir, exist_ok=True)
61
+ for filename in files:
62
+ if filename.endswith(('.pyo', '.pyc', '.py.class')):
63
+ # Ignore some files as they cause various breakages.
64
+ continue
65
+ old_path = os.path.join(root, filename)
66
+ new_path = os.path.join(target_dir, filename)
67
+ os.makedirs(target_dir, exist_ok=True)
68
+ fn, file_extension = os.path.splitext(new_path)
69
+ if file_extension in template_file_extensions:
70
+ with open(old_path, encoding='utf-8') as template_file:
71
+ content = template_file.read()
72
+ template = Engine().from_string(content)
73
+ content = template.render(context)
74
+ with open(new_path, 'w', encoding='utf-8') as new_file:
75
+ new_file.write(content)
76
+ else:
77
+ shutil.copyfile(old_path, new_path)
78
+ shutil.copymode(old_path, new_path)
79
+ for dirname in dirs[:]:
80
+ if dirname.startswith('.') or dirname == '__pycache__':
81
+ dirs.remove(dirname)
82
+ else:
83
+ os.makedirs(os.path.join(root, dirname), exist_ok=True)
84
+
85
+
86
+ def install():
87
+ simo_directory = '/etc/SIMO'
88
+ installed_flag_file_path = os.path.join(simo_directory, 'is_installed.json')
89
+
90
+ if os.path.exists(installed_flag_file_path):
91
+ print("SIMO.io hub is already installed. ")
92
+ print(f"Please delete {installed_flag_file_path} file manually if you want to force this.")
93
+ return
94
+
95
+ step = 1
96
+ print(f"{step}.___________Install dependencies__________________")
97
+ status = subprocess.call(
98
+ 'apt-add-repository ppa:mosquitto-dev/mosquitto-ppa -y', shell=True
99
+ )
100
+ if status != 0:
101
+ print("Unable to add mosquitto-dev dependency")
102
+ print("Installation failed!")
103
+ return
104
+
105
+ status = subprocess.call('apt-get update -y', shell=True)
106
+ if status != 0:
107
+ print("Unable to apt-update")
108
+ print("Installation failed!")
109
+ return
110
+ success = install_dependencies()
111
+ if not success:
112
+ print("Installation failed!")
113
+ return
114
+
115
+ step += 1
116
+ print(f"{step}.___________Copy default template__________________")
117
+
118
+ if os.path.exists(simo_directory):
119
+ print("Already exists!")
120
+ else:
121
+ try:
122
+ copy_template(simo_directory)
123
+ except Exception as e:
124
+ print(traceback.format_exc(), file=sys.stderr)
125
+ shutil.rmtree(simo_directory, ignore_errors=True)
126
+ return
127
+
128
+ step += 1
129
+ print(f"{step}.___________Configure supervisor__________________")
130
+
131
+ try:
132
+ os.remove('/etc/supervisor/conf.d/SIMO.conf', ignore_errors=True)
133
+ except:
134
+ pass
135
+ os.symlink(
136
+ f'{simo_directory}/hub/supervisor.conf',
137
+ '/etc/supervisor/conf.d/SIMO.conf'
138
+ )
139
+ status = subprocess.call(['supervisorctl', 'update', 'all'])
140
+ if status != 0:
141
+ sys.exit("INSTALLATION FAILED! Unable to start supervisord")
142
+
143
+
144
+
145
+ step += 1
146
+ print("%d._____________ Configure NGINX _________________________" % step)
147
+
148
+ try:
149
+ os.remove('/etc/nginx/sites-enabled/default')
150
+ except:
151
+ pass
152
+
153
+ os.symlink(
154
+ '/etc/SIMO/hub/nginx.conf', '/etc/nginx/sites-enabled/SIMO'
155
+ )
156
+
157
+ try:
158
+ os.remove('/etc/ssl/private/localhost.key')
159
+ except:
160
+ pass
161
+ try:
162
+ os.remove('/etc/ssl/certs/localhost.crt')
163
+ except:
164
+ pass
165
+
166
+ status = subprocess.call([
167
+ 'openssl', 'req', '-x509', '-nodes', '-days', '36500',
168
+ '-newkey', 'rsa:2048',
169
+ '-subj', '/C=US/ST=Denial/L=Springfield/O=Dis/CN=simo.io',
170
+ '-keyout', '/etc/ssl/private/localhost.key',
171
+ '-out', '/etc/ssl/certs/localhost.crt'
172
+ ])
173
+ if status != 0:
174
+ sys.exit(
175
+ "INSTALLATION FAILED! Unable to prepare self signed certificate.")
176
+
177
+ status = subprocess.call(['service', 'nginx', 'reload'])
178
+ if status != 0:
179
+ sys.exit("INSTALLATION FAILED! Something is wrong witn NGINX conf.")
180
+
181
+ step += 1
182
+ print("%d._____________ Configure SSH and Firewall_____________" % step)
183
+ new_ssh_conf = ''
184
+ with open('/etc/ssh/sshd_config', 'r') as ssh_conf:
185
+ line = ssh_conf.readline()
186
+ while line:
187
+ if 'PasswordAuthentication' in line:
188
+ new_ssh_conf += 'PasswordAuthentication no'
189
+ else:
190
+ new_ssh_conf += line
191
+ line = ssh_conf.readline()
192
+ with open('/etc/ssh/sshd_config', 'w') as ssh_conf:
193
+ ssh_conf.write(new_ssh_conf)
194
+
195
+ status = subprocess.call(['service', 'ssh', 'restart'])
196
+ if status != 0:
197
+ sys.exit("INSTALLATION FAILED! Unable to restart SSH")
198
+
199
+ stats = []
200
+ stats.append(subprocess.call(['ufw', 'allow', 'ssh']))
201
+ stats.append(subprocess.call(['ufw', 'allow', 'http']))
202
+ stats.append(subprocess.call(['ufw', 'allow', 'https']))
203
+ stats.append(subprocess.call(['ufw', 'allow', '1194']))
204
+ stats.append(subprocess.call(['ufw', 'allow', '1883']))
205
+ if any(stats):
206
+ sys.exit("INSTALLATION FAILED! Unable to update UFW rules")
207
+
208
+ status = subprocess.call('echo y | ufw enable', shell=True)
209
+ if status != 0:
210
+ sys.exit("INSTALLATION FAILED! Unable to enable UFW")
211
+
212
+
213
+ step += 1
214
+ print("%d.__________ CONFIGURE TIMESHIFT _____________________" % step)
215
+
216
+ default_timeshift_file_path = '/etc/timeshift/default.json'
217
+ if not os.path.exists(default_timeshift_file_path):
218
+ default_timeshift_file_path = '/etc/timeshift/timeshift.json'
219
+ if not os.path.exists(default_timeshift_file_path):
220
+ default_timeshift_file_path = '/etc/default/timeshift.json'
221
+
222
+ if not os.path.exists(default_timeshift_file_path):
223
+ print("Unable to find default TimeShift config! Skip TimeShift configuration.")
224
+
225
+ else:
226
+
227
+ with open(default_timeshift_file_path, 'r') as conf_f:
228
+ timeshift_conf = json.loads(conf_f.read())
229
+
230
+ timeshift_conf['backup_device_uuid'] = subprocess.check_output(
231
+ "lsblk -no UUID $(df -P /etc/SIMO/hub/settings.py | awk 'END{print $1}')",
232
+ shell=True
233
+ ).decode()[:-1]
234
+ timeshift_conf['schedule_monthly'] = "true"
235
+ timeshift_conf['schedule_weekly'] = "true"
236
+ timeshift_conf['schedule_daily'] = "true"
237
+
238
+ # Must be copied to /etc/timeshift.json to work
239
+ with open('/etc/timeshift.json', 'w') as conf_f:
240
+ conf_f.write(json.dumps(timeshift_conf))
241
+
242
+ status = subprocess.call([
243
+ '/usr/bin/timeshift', '--create',
244
+ '--comments', '"Initial backup"', '--tags', 'M'
245
+ ])
246
+ if status != 0:
247
+ print("Unable to start TimeShift")
248
+
249
+ with open(installed_flag_file_path, 'w') as f:
250
+ f.write(json.dumps(True))
251
+
252
+ print("--------------------------------------------------------------")
253
+ print("DONE!")
254
+ print("Your SIMO.io Hub is Up and running at: https://%s/" % get_ip())
255
+
256
+
257
+ if __name__ == "__main__":
258
+ sys.exit(init())
@@ -2,6 +2,7 @@ import os
2
2
  import pwd
3
3
  import grp
4
4
  import subprocess
5
+ import pkg_resources
5
6
  from django.conf import settings
6
7
  from django.template.loader import render_to_string
7
8
 
@@ -58,7 +59,8 @@ prepare_mosquitto()
58
59
  def update_auto_update():
59
60
  import simo
60
61
  auto_update_file_path = os.path.join(
61
- os.path.dirname(simo.__file__), 'auto_update.py'
62
+ os.path.dirname(simo.__file__), 'management',
63
+ 'auto_update.py'
62
64
  )
63
65
  st = os.stat(auto_update_file_path)
64
66
  os.chmod(auto_update_file_path, st.st_mode | 0o111)
@@ -75,4 +77,22 @@ def update_auto_update():
75
77
  cron_out.communicate(input=str.encode(auto_update_cron))
76
78
 
77
79
 
78
- update_auto_update()
80
+ update_auto_update()
81
+
82
+
83
+ def maybe_update_to_latest_immediately():
84
+ from simo.core.tasks import update_latest_version_available, update
85
+ from simo.core.models import Instance
86
+ from simo.conf import dynamic_settings
87
+ update_latest_version_available()
88
+ if dynamic_settings['core__latest_version_available'] != \
89
+ pkg_resources.get_distribution('simo').version:
90
+ print("There is newer version, we should probably update!")
91
+ if not Instance.objects.all().count():
92
+ print("Yes let's do it asynchronously!")
93
+ return update.s()
94
+ print("Nope, we already have some instances running, "
95
+ "so we leave that for hub owners.")
96
+
97
+
98
+ maybe_update_to_latest_immediately()
simo/settings.py CHANGED
@@ -40,12 +40,14 @@ MEDIA_ROOT = os.path.join(VAR_DIR, 'media')
40
40
  EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
41
41
 
42
42
  INSTALLED_APPS = [
43
- 'channels',
43
+ 'daphne',
44
+ #'channels',
44
45
  'dal',
45
46
  'dal_select2',
46
47
  'django.forms',
47
48
 
48
49
  'django.contrib.auth',
50
+ 'django.contrib.sites',
49
51
  'django.contrib.contenttypes',
50
52
  'django.contrib.sessions',
51
53
  'django.contrib.gis',
@@ -58,9 +60,11 @@ INSTALLED_APPS = [
58
60
  'dynamic_preferences',
59
61
  'easy_thumbnails',
60
62
  'django_filters',
61
- 'adminsortable2',
63
+ 'markdownify.apps.MarkdownifyConfig',
64
+
62
65
  'bootstrap4',
63
66
  'taggit',
67
+ 'actstream',
64
68
 
65
69
  'simo.core',
66
70
  'simo.users',
@@ -70,6 +74,7 @@ INSTALLED_APPS = [
70
74
  'simo.fleet',
71
75
 
72
76
  'django.contrib.admin',
77
+ 'adminsortable2',
73
78
  ]
74
79
 
75
80
 
@@ -90,7 +95,7 @@ MIDDLEWARE = [
90
95
  FILE_UPLOAD_MAX_MEMORY_SIZE = 20971520 # 20Mb
91
96
 
92
97
  ROOT_URLCONF = 'urls'
93
- WSGI_APPLICATION = 'simo.wsgi.application'
98
+ #WSGI_APPLICATION = 'simo.wsgi.application'
94
99
 
95
100
  CHANNELS_URLCONF = 'simo.asgi'
96
101
  ASGI_APPLICATION = "asgi.application"
@@ -223,6 +228,8 @@ DEFAULT_FILE_STORAGE = 'simo.core.storage.ProxyingFileSystemStorage'
223
228
  THUMBNAIL_DEFAULT_STORAGE = DEFAULT_FILE_STORAGE
224
229
 
225
230
 
231
+ SITE_ID = 1
232
+
226
233
  LOGGING = {
227
234
  'version': 1,
228
235
  'disable_existing_loggers': False,
@@ -273,5 +280,14 @@ LOCATION_FIELD = {
273
280
  'search.provider': 'nominatim',
274
281
  }
275
282
 
276
-
277
283
  TAGGIT_CASE_INSENSITIVE = True
284
+
285
+
286
+
287
+ ACTSTREAM_SETTINGS = {
288
+ 'MANAGER': 'simo.core.managers.ActionManager',
289
+ 'FETCH_RELATIONS': True,
290
+ 'USE_PREFETCH': True,
291
+ 'USE_JSONFIELD': True,
292
+ 'GFK_FETCH_DEPTH': 1,
293
+ }
simo/users/__init__.py CHANGED
@@ -0,0 +1 @@
1
+ default_app_config = 'users.apps.SIMOUsersAppConfig'
Binary file
simo/users/apps.py ADDED
@@ -0,0 +1,9 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class SIMOUsersAppConfig(AppConfig):
5
+ name = 'simo.users'
6
+
7
+ def ready(self):
8
+ from actstream import registry
9
+ registry.register(self.get_model('User'))
simo/users/models.py CHANGED
@@ -11,6 +11,7 @@ from django.dispatch import receiver
11
11
  from dirtyfields import DirtyFieldsMixin
12
12
  from django.contrib.gis.geos import Point
13
13
  from geopy.distance import distance
14
+ from actstream import action
14
15
  from django.contrib.auth.models import (
15
16
  AbstractBaseUser, PermissionsMixin, UserManager as DefaultUserManager
16
17
  )
@@ -68,6 +69,10 @@ class PermissionsRole(models.Model):
68
69
 
69
70
  class UserManager(DefaultUserManager):
70
71
 
72
+ def get_queryset(self):
73
+ qs = super().get_queryset()
74
+ return qs.prefetch_related('instance_roles')
75
+
71
76
  def _create_user(self, name, email, password, **extra_fields):
72
77
  if not name:
73
78
  raise ValueError('The given name must be set')
@@ -115,6 +120,15 @@ def post_instance_user_save(sender, instance, created, **kwargs):
115
120
  dirty_fields = instance.get_dirty_fields()
116
121
  if 'at_home' in dirty_fields:
117
122
  def post_update():
123
+ if instance.at_home:
124
+ verb = 'came home'
125
+ else:
126
+ verb = 'left'
127
+ action.send(
128
+ instance.user, verb=verb,
129
+ instance_id=instance.instance.id,
130
+ action_type='user_presence', value=instance.at_home
131
+ )
118
132
  ObjectChangeEvent(
119
133
  instance.instance, instance, dirty_fields=dirty_fields
120
134
  ).publish()
@@ -291,9 +305,8 @@ class User(AbstractBaseUser, SimoAdminMixin):
291
305
  instance=self._instance, is_active=True
292
306
  ).first()
293
307
  )
294
- return bool(
295
- self.instance_roles.filter(is_active=True).first()
296
- )
308
+ return any([ir.is_active for ir in self.instance_roles.all()])
309
+
297
310
 
298
311
  @is_active.setter
299
312
  def is_active(self, val):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simo
3
- Version: 2.0.42
3
+ Version: 2.1.2
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
@@ -17,7 +17,7 @@ Requires-Dist: djangorestframework ==3.14.0
17
17
  Requires-Dist: django-dynamic-preferences ==1.11.0
18
18
  Requires-Dist: django-formtools ==2.3
19
19
  Requires-Dist: easy-thumbnails ==2.8.5
20
- Requires-Dist: channels ==4.0.0
20
+ Requires-Dist: channels ==4.1.0
21
21
  Requires-Dist: asgiref ==3.7.2
22
22
  Requires-Dist: django-filter ==2.4.0
23
23
  Requires-Dist: celery ==5.3.6
@@ -43,6 +43,8 @@ Requires-Dist: ansi2html ==1.7.0
43
43
  Requires-Dist: slugify ==0.0.1
44
44
  Requires-Dist: django-countries ==7.5.1
45
45
  Requires-Dist: librosa ==0.10.1
46
- Requires-Dist: daphne ==4.1.0
46
+ Requires-Dist: daphne ==4.1.2
47
47
  Requires-Dist: Pillow ==9.5.0
48
+ Requires-Dist: django-markdownify ==0.9.5
49
+ Requires-Dist: django-activity-stream ==2.0.0
48
50