igs-slm 0.1.0b0__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.
Files changed (447) hide show
  1. igs_slm-0.1.0b0.dist-info/LICENSE +21 -0
  2. igs_slm-0.1.0b0.dist-info/METADATA +151 -0
  3. igs_slm-0.1.0b0.dist-info/RECORD +447 -0
  4. igs_slm-0.1.0b0.dist-info/WHEEL +4 -0
  5. igs_slm-0.1.0b0.dist-info/entry_points.txt +3 -0
  6. igs_tools/__init__.py +0 -0
  7. igs_tools/connection.py +88 -0
  8. igs_tools/defines/__init__.py +8 -0
  9. igs_tools/defines/constellation.py +21 -0
  10. igs_tools/defines/data_center.py +75 -0
  11. igs_tools/defines/rinex.py +49 -0
  12. igs_tools/directory.py +247 -0
  13. igs_tools/utils.py +66 -0
  14. slm/__init__.py +21 -0
  15. slm/admin.py +674 -0
  16. slm/api/edit/__init__.py +0 -0
  17. slm/api/edit/serializers.py +316 -0
  18. slm/api/edit/views.py +1632 -0
  19. slm/api/fields.py +89 -0
  20. slm/api/filter.py +504 -0
  21. slm/api/pagination.py +55 -0
  22. slm/api/permissions.py +65 -0
  23. slm/api/public/__init__.py +0 -0
  24. slm/api/public/serializers.py +249 -0
  25. slm/api/public/views.py +606 -0
  26. slm/api/serializers.py +132 -0
  27. slm/api/views.py +148 -0
  28. slm/apps.py +323 -0
  29. slm/authentication.py +198 -0
  30. slm/bin/__init__.py +0 -0
  31. slm/bin/startproject.py +262 -0
  32. slm/bin/templates/{{ project_dir }}/pyproject.toml +35 -0
  33. slm/bin/templates/{{ project_dir }}/sites/__init__.py +0 -0
  34. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/__init__.py +0 -0
  35. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/base.py +15 -0
  36. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/develop/__init__.py +56 -0
  37. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/develop/local.py +4 -0
  38. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/develop/wsgi.py +16 -0
  39. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/manage.py +34 -0
  40. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/production/__init__.py +61 -0
  41. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/production/wsgi.py +16 -0
  42. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/urls.py +7 -0
  43. slm/bin/templates/{{ project_dir }}/sites/{{ site }}/validation.py +11 -0
  44. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/__init__.py +0 -0
  45. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/admin.py +5 -0
  46. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/apps.py +14 -0
  47. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/management/__init__.py +0 -0
  48. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/management/commands/__init__.py +0 -0
  49. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/management/commands/import_archive.py +64 -0
  50. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/migrations/__init__.py +0 -0
  51. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/models.py +6 -0
  52. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/templates/slm/base.html +8 -0
  53. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/urls.py +10 -0
  54. slm/bin/templates/{{ project_dir }}/{{ extension_app }}/views.py +5 -0
  55. slm/defines/AlertLevel.py +24 -0
  56. slm/defines/AntennaCalibration.py +25 -0
  57. slm/defines/AntennaFeatures.py +27 -0
  58. slm/defines/AntennaReferencePoint.py +22 -0
  59. slm/defines/Aspiration.py +13 -0
  60. slm/defines/CardinalDirection.py +19 -0
  61. slm/defines/CollocationStatus.py +12 -0
  62. slm/defines/EquipmentState.py +22 -0
  63. slm/defines/FlagSeverity.py +14 -0
  64. slm/defines/FractureSpacing.py +15 -0
  65. slm/defines/FrequencyStandardType.py +15 -0
  66. slm/defines/GeodesyMLVersion.py +48 -0
  67. slm/defines/ISOCountry.py +1194 -0
  68. slm/defines/Instrumentation.py +19 -0
  69. slm/defines/LogEntryType.py +30 -0
  70. slm/defines/SLMFileType.py +18 -0
  71. slm/defines/SiteFileUploadStatus.py +61 -0
  72. slm/defines/SiteLogFormat.py +49 -0
  73. slm/defines/SiteLogStatus.py +78 -0
  74. slm/defines/TectonicPlates.py +28 -0
  75. slm/defines/__init__.py +46 -0
  76. slm/forms.py +1126 -0
  77. slm/jinja2/slm/sitelog/ascii_9char.log +346 -0
  78. slm/jinja2/slm/sitelog/legacy.log +346 -0
  79. slm/jinja2/slm/sitelog/xsd/0.4/collocationInformation.xml +12 -0
  80. slm/jinja2/slm/sitelog/xsd/0.4/condition.xml +12 -0
  81. slm/jinja2/slm/sitelog/xsd/0.4/contact.xml +52 -0
  82. slm/jinja2/slm/sitelog/xsd/0.4/formInformation.xml +5 -0
  83. slm/jinja2/slm/sitelog/xsd/0.4/frequencyStandard.xml +12 -0
  84. slm/jinja2/slm/sitelog/xsd/0.4/gnssAntenna.xml +16 -0
  85. slm/jinja2/slm/sitelog/xsd/0.4/gnssReceiver.xml +11 -0
  86. slm/jinja2/slm/sitelog/xsd/0.4/humiditySensor.xml +13 -0
  87. slm/jinja2/slm/sitelog/xsd/0.4/localEpisodicEffect.xml +10 -0
  88. slm/jinja2/slm/sitelog/xsd/0.4/moreInformation.xml +22 -0
  89. slm/jinja2/slm/sitelog/xsd/0.4/multipathSource.xml +10 -0
  90. slm/jinja2/slm/sitelog/xsd/0.4/otherInstrumentation.xml +5 -0
  91. slm/jinja2/slm/sitelog/xsd/0.4/pressureSensor.xml +12 -0
  92. slm/jinja2/slm/sitelog/xsd/0.4/radioInterference.xml +11 -0
  93. slm/jinja2/slm/sitelog/xsd/0.4/sensor.xml +16 -0
  94. slm/jinja2/slm/sitelog/xsd/0.4/signalObstruction.xml +10 -0
  95. slm/jinja2/slm/sitelog/xsd/0.4/siteIdentification.xml +22 -0
  96. slm/jinja2/slm/sitelog/xsd/0.4/siteLocation.xml +21 -0
  97. slm/jinja2/slm/sitelog/xsd/0.4/surveyedLocalTie.xml +20 -0
  98. slm/jinja2/slm/sitelog/xsd/0.4/temperatureSensor.xml +13 -0
  99. slm/jinja2/slm/sitelog/xsd/0.4/waterVaporSensor.xml +11 -0
  100. slm/jinja2/slm/sitelog/xsd/0.5/document.xml +10 -0
  101. slm/jinja2/slm/sitelog/xsd/geodesyml_0.4.xml +99 -0
  102. slm/jinja2/slm/sitelog/xsd/geodesyml_0.5.xml +112 -0
  103. slm/management/__init__.py +0 -0
  104. slm/management/commands/__init__.py +53 -0
  105. slm/management/commands/build_index.py +96 -0
  106. slm/management/commands/generate_sinex.py +675 -0
  107. slm/management/commands/head_from_index.py +541 -0
  108. slm/management/commands/import_archive.py +908 -0
  109. slm/management/commands/import_equipment.py +351 -0
  110. slm/management/commands/set_site.py +56 -0
  111. slm/management/commands/sitelog.py +144 -0
  112. slm/management/commands/synchronize.py +60 -0
  113. slm/management/commands/update_data_availability.py +167 -0
  114. slm/management/commands/validate_db.py +186 -0
  115. slm/management/commands/validate_gml.py +73 -0
  116. slm/map/__init__.py +1 -0
  117. slm/map/admin.py +5 -0
  118. slm/map/api/__init__.py +0 -0
  119. slm/map/api/edit/__init__.py +0 -0
  120. slm/map/api/edit/serializers.py +28 -0
  121. slm/map/api/edit/views.py +46 -0
  122. slm/map/api/public/__init__.py +0 -0
  123. slm/map/api/public/serializers.py +29 -0
  124. slm/map/api/public/views.py +64 -0
  125. slm/map/apps.py +7 -0
  126. slm/map/defines.py +53 -0
  127. slm/map/migrations/0001_initial.py +115 -0
  128. slm/map/migrations/__init__.py +0 -0
  129. slm/map/models.py +63 -0
  130. slm/map/static/slm/css/map.css +86 -0
  131. slm/map/static/slm/js/map.js +159 -0
  132. slm/map/templates/slm/map.html +374 -0
  133. slm/map/templates/slm/station/base.html +11 -0
  134. slm/map/templates/slm/station/edit.html +10 -0
  135. slm/map/templates/slm/top_nav.html +17 -0
  136. slm/map/templatetags/__init__.py +0 -0
  137. slm/map/templatetags/slm_map.py +18 -0
  138. slm/map/urls.py +25 -0
  139. slm/map/views.py +36 -0
  140. slm/middleware.py +29 -0
  141. slm/migrations/0001_alter_siteantenna_marker_enu_alter_sitelocation_llh_and_more.py +47 -0
  142. slm/migrations/0001_initial.py +4826 -0
  143. slm/migrations/0002_alter_dataavailability_site.py +22 -0
  144. slm/migrations/0003_remove_logentry_slm_logentr_site_lo_7a2af7_idx_and_more.py +80 -0
  145. slm/migrations/0004_alter_logentry_timestamp_and_more.py +25 -0
  146. slm/migrations/0005_alter_logentry_options_alter_logentry_section_and_more.py +46 -0
  147. slm/migrations/0006_alter_logentry_options_alter_logentry_index_together.py +24 -0
  148. slm/migrations/0007_alter_dataavailability_rate.py +23 -0
  149. slm/migrations/0008_alter_archiveindex_options_and_more.py +64 -0
  150. slm/migrations/0009_alter_archiveindex_end.py +21 -0
  151. slm/migrations/0010_alter_dataavailability_rinex_version_and_more.py +844 -0
  152. slm/migrations/0011_alter_siteidentification_fracture_spacing.py +33 -0
  153. slm/migrations/0012_alter_logentry_type.py +36 -0
  154. slm/migrations/0013_unpublishedfilesalert.py +48 -0
  155. slm/migrations/0014_sitelogpublished.py +48 -0
  156. slm/migrations/0015_alter_siteantenna_options_and_more.py +181 -0
  157. slm/migrations/0016_alter_antenna_description_alter_radome_description_and_more.py +42 -0
  158. slm/migrations/0017_alter_logentry_unique_together_and_more.py +54 -0
  159. slm/migrations/0018_afix_deleted.py +34 -0
  160. slm/migrations/0018_alter_siteantenna_options_and_more.py +244 -0
  161. slm/migrations/0019_remove_siteantenna_marker_enu_siteantenna_marker_une_and_more.py +101 -0
  162. slm/migrations/0020_alter_manufacturer_options.py +16 -0
  163. slm/migrations/0021_alter_siteform_report_type.py +23 -0
  164. slm/migrations/0022_rename_antcal_antenna_radome_slm_antcal_antenna_20827a_idx_and_more.py +297 -0
  165. slm/migrations/0023_archivedsitelog_gml_version_and_more.py +55 -0
  166. slm/migrations/0024_alter_agency_name_alter_agency_shortname.py +24 -0
  167. slm/migrations/0025_alter_archivedsitelog_log_format_and_more.py +61 -0
  168. slm/migrations/0026_alter_archivedsitelog_log_format_and_more.py +61 -0
  169. slm/migrations/0027_importalert_file_contents_importalert_findings_and_more.py +41 -0
  170. slm/migrations/0028_antenna_replaced_manufacturer_url_radome_replaced_and_more.py +46 -0
  171. slm/migrations/0029_manufacturer_full_name.py +17 -0
  172. slm/migrations/0030_alter_antenna_state_alter_radome_state_and_more.py +43 -0
  173. slm/migrations/__init__.py +0 -0
  174. slm/migrations/load_satellitesystems.py +27 -0
  175. slm/models/__init__.py +118 -0
  176. slm/models/about.py +14 -0
  177. slm/models/alerts.py +1204 -0
  178. slm/models/data.py +58 -0
  179. slm/models/equipment.py +229 -0
  180. slm/models/help.py +14 -0
  181. slm/models/index.py +428 -0
  182. slm/models/sitelog.py +4279 -0
  183. slm/models/system.py +723 -0
  184. slm/models/user.py +304 -0
  185. slm/parsing/__init__.py +786 -0
  186. slm/parsing/legacy/__init__.py +4 -0
  187. slm/parsing/legacy/binding.py +817 -0
  188. slm/parsing/legacy/parser.py +377 -0
  189. slm/parsing/xsd/__init__.py +34 -0
  190. slm/parsing/xsd/binding.py +86 -0
  191. slm/parsing/xsd/geodesyml/0.4/commonTypes.xsd +133 -0
  192. slm/parsing/xsd/geodesyml/0.4/contact.xsd +29 -0
  193. slm/parsing/xsd/geodesyml/0.4/dataStreams.xsd +129 -0
  194. slm/parsing/xsd/geodesyml/0.4/document.xsd +64 -0
  195. slm/parsing/xsd/geodesyml/0.4/equipment.xsd +427 -0
  196. slm/parsing/xsd/geodesyml/0.4/fieldMeasurement.xsd +170 -0
  197. slm/parsing/xsd/geodesyml/0.4/geodesyML.xsd +71 -0
  198. slm/parsing/xsd/geodesyml/0.4/geodeticEquipment.xsd +343 -0
  199. slm/parsing/xsd/geodesyml/0.4/geodeticMonument.xsd +147 -0
  200. slm/parsing/xsd/geodesyml/0.4/lineage.xsd +614 -0
  201. slm/parsing/xsd/geodesyml/0.4/localInterferences.xsd +131 -0
  202. slm/parsing/xsd/geodesyml/0.4/measurement.xsd +473 -0
  203. slm/parsing/xsd/geodesyml/0.4/monumentInfo.xsd +251 -0
  204. slm/parsing/xsd/geodesyml/0.4/observationSystem.xsd +429 -0
  205. slm/parsing/xsd/geodesyml/0.4/project.xsd +38 -0
  206. slm/parsing/xsd/geodesyml/0.4/quality.xsd +176 -0
  207. slm/parsing/xsd/geodesyml/0.4/referenceFrame.xsd +194 -0
  208. slm/parsing/xsd/geodesyml/0.4/siteLog.xsd +71 -0
  209. slm/parsing/xsd/geodesyml/0.5/commonTypes.xsd +133 -0
  210. slm/parsing/xsd/geodesyml/0.5/contact.xsd +29 -0
  211. slm/parsing/xsd/geodesyml/0.5/dataStreams.xsd +129 -0
  212. slm/parsing/xsd/geodesyml/0.5/document.xsd +64 -0
  213. slm/parsing/xsd/geodesyml/0.5/equipment.xsd +427 -0
  214. slm/parsing/xsd/geodesyml/0.5/fieldMeasurement.xsd +170 -0
  215. slm/parsing/xsd/geodesyml/0.5/geodesyML.xsd +71 -0
  216. slm/parsing/xsd/geodesyml/0.5/geodeticEquipment.xsd +343 -0
  217. slm/parsing/xsd/geodesyml/0.5/geodeticMonument.xsd +147 -0
  218. slm/parsing/xsd/geodesyml/0.5/lineage.xsd +614 -0
  219. slm/parsing/xsd/geodesyml/0.5/localInterferences.xsd +131 -0
  220. slm/parsing/xsd/geodesyml/0.5/measurement.xsd +473 -0
  221. slm/parsing/xsd/geodesyml/0.5/monumentInfo.xsd +306 -0
  222. slm/parsing/xsd/geodesyml/0.5/observationSystem.xsd +429 -0
  223. slm/parsing/xsd/geodesyml/0.5/project.xsd +38 -0
  224. slm/parsing/xsd/geodesyml/0.5/quality.xsd +176 -0
  225. slm/parsing/xsd/geodesyml/0.5/referenceFrame.xsd +194 -0
  226. slm/parsing/xsd/geodesyml/0.5/siteLog.xsd +73 -0
  227. slm/parsing/xsd/parser.py +116 -0
  228. slm/parsing/xsd/resolver.py +28 -0
  229. slm/receivers/__init__.py +11 -0
  230. slm/receivers/alerts.py +87 -0
  231. slm/receivers/cleanup.py +41 -0
  232. slm/receivers/event_loggers.py +175 -0
  233. slm/receivers/index.py +67 -0
  234. slm/settings/__init__.py +55 -0
  235. slm/settings/auth.py +15 -0
  236. slm/settings/ckeditor.py +14 -0
  237. slm/settings/debug.py +47 -0
  238. slm/settings/internationalization.py +12 -0
  239. slm/settings/logging.py +113 -0
  240. slm/settings/platform/__init__.py +0 -0
  241. slm/settings/platform/darwin.py +10 -0
  242. slm/settings/rest.py +21 -0
  243. slm/settings/root.py +152 -0
  244. slm/settings/routines.py +43 -0
  245. slm/settings/secrets.py +37 -0
  246. slm/settings/security.py +5 -0
  247. slm/settings/slm.py +188 -0
  248. slm/settings/static_templates.py +53 -0
  249. slm/settings/templates.py +29 -0
  250. slm/settings/uploads.py +8 -0
  251. slm/settings/urls.py +126 -0
  252. slm/settings/validation.py +196 -0
  253. slm/signals.py +250 -0
  254. slm/singleton.py +49 -0
  255. slm/static/rest_framework/css/bootstrap-tweaks.css +204 -0
  256. slm/static/rest_framework/css/bootstrap.min.css +7 -0
  257. slm/static/rest_framework/css/bootstrap.min.css.map +1 -0
  258. slm/static/rest_framework/css/default.css +82 -0
  259. slm/static/rest_framework/css/prettify.css +30 -0
  260. slm/static/rest_framework/docs/css/base.css +344 -0
  261. slm/static/rest_framework/docs/css/highlight.css +125 -0
  262. slm/static/rest_framework/docs/css/jquery.json-view.min.css +11 -0
  263. slm/static/rest_framework/docs/img/favicon.ico +0 -0
  264. slm/static/rest_framework/docs/img/grid.png +0 -0
  265. slm/static/rest_framework/docs/js/api.js +321 -0
  266. slm/static/rest_framework/docs/js/highlight.pack.js +2 -0
  267. slm/static/rest_framework/docs/js/jquery.json-view.min.js +7 -0
  268. slm/static/rest_framework/img/grid.png +0 -0
  269. slm/static/rest_framework/js/ajax-form.js +127 -0
  270. slm/static/rest_framework/js/bootstrap.bundle.min.js +7 -0
  271. slm/static/rest_framework/js/bootstrap.bundle.min.js.map +1 -0
  272. slm/static/rest_framework/js/bootstrap.min.js.map +1 -0
  273. slm/static/rest_framework/js/coreapi-0.1.1.js +2043 -0
  274. slm/static/rest_framework/js/csrf.js +52 -0
  275. slm/static/rest_framework/js/default.js +47 -0
  276. slm/static/rest_framework/js/jquery-3.5.1.min.js +2 -0
  277. slm/static/rest_framework/js/prettify-min.js +28 -0
  278. slm/static/slm/css/admin.css +3 -0
  279. slm/static/slm/css/defines.css +82 -0
  280. slm/static/slm/css/forms.css +1 -0
  281. slm/static/slm/css/style.css +1004 -0
  282. slm/static/slm/img/email-branding.png +0 -0
  283. slm/static/slm/img/favicon.ico +0 -0
  284. slm/static/slm/img/login-bg.jpg +0 -0
  285. slm/static/slm/img/slm-logo.svg +4 -0
  286. slm/static/slm/js/autocomplete.js +341 -0
  287. slm/static/slm/js/enums.js +322 -0
  288. slm/static/slm/js/fileIcons.js +30 -0
  289. slm/static/slm/js/form.js +404 -0
  290. slm/static/slm/js/formWidget.js +23 -0
  291. slm/static/slm/js/persistable.js +33 -0
  292. slm/static/slm/js/slm.js +1028 -0
  293. slm/static/slm/js/time24.js +212 -0
  294. slm/static_templates/slm/css/defines.css +26 -0
  295. slm/static_templates/slm/js/enums.js +28 -0
  296. slm/static_templates/slm/js/fileIcons.js +16 -0
  297. slm/static_templates/slm/js/urls.js +5 -0
  298. slm/templates/account/base.html +20 -0
  299. slm/templates/account/email/base.html +43 -0
  300. slm/templates/account/email/base_message.txt +7 -0
  301. slm/templates/account/email/email_confirmation_message.html +16 -0
  302. slm/templates/account/email/email_confirmation_message.txt +7 -0
  303. slm/templates/account/email/email_confirmation_signup_message.html +1 -0
  304. slm/templates/account/email/email_confirmation_signup_message.txt +1 -0
  305. slm/templates/account/email/email_confirmation_signup_subject.txt +1 -0
  306. slm/templates/account/email/email_confirmation_subject.txt +4 -0
  307. slm/templates/account/email/password_reset_key_message.html +28 -0
  308. slm/templates/account/email/password_reset_key_message.txt +9 -0
  309. slm/templates/account/email/password_reset_key_subject.txt +4 -0
  310. slm/templates/account/email/unknown_account_message.html +25 -0
  311. slm/templates/account/email/unknown_account_message.txt +12 -0
  312. slm/templates/account/email/unknown_account_subject.txt +4 -0
  313. slm/templates/account/login.html +67 -0
  314. slm/templates/account/logout.html +38 -0
  315. slm/templates/account/password_change.html +48 -0
  316. slm/templates/account/password_reset.html +51 -0
  317. slm/templates/account/password_reset_done.html +20 -0
  318. slm/templates/account/password_reset_from_key.html +52 -0
  319. slm/templates/account/password_reset_from_key_done.html +17 -0
  320. slm/templates/admin/base.html +7 -0
  321. slm/templates/messages.html +8 -0
  322. slm/templates/rest_framework/README +16 -0
  323. slm/templates/rest_framework/admin/detail.html +10 -0
  324. slm/templates/rest_framework/admin/dict_value.html +11 -0
  325. slm/templates/rest_framework/admin/list.html +32 -0
  326. slm/templates/rest_framework/admin/list_value.html +11 -0
  327. slm/templates/rest_framework/admin/simple_list_value.html +2 -0
  328. slm/templates/rest_framework/admin.html +282 -0
  329. slm/templates/rest_framework/api.html +3 -0
  330. slm/templates/rest_framework/base.html +334 -0
  331. slm/templates/rest_framework/docs/auth/basic.html +42 -0
  332. slm/templates/rest_framework/docs/auth/session.html +40 -0
  333. slm/templates/rest_framework/docs/auth/token.html +41 -0
  334. slm/templates/rest_framework/docs/document.html +37 -0
  335. slm/templates/rest_framework/docs/error.html +71 -0
  336. slm/templates/rest_framework/docs/index.html +55 -0
  337. slm/templates/rest_framework/docs/interact.html +57 -0
  338. slm/templates/rest_framework/docs/langs/javascript-intro.html +5 -0
  339. slm/templates/rest_framework/docs/langs/javascript.html +15 -0
  340. slm/templates/rest_framework/docs/langs/python-intro.html +3 -0
  341. slm/templates/rest_framework/docs/langs/python.html +13 -0
  342. slm/templates/rest_framework/docs/langs/shell-intro.html +3 -0
  343. slm/templates/rest_framework/docs/langs/shell.html +6 -0
  344. slm/templates/rest_framework/docs/link.html +113 -0
  345. slm/templates/rest_framework/docs/sidebar.html +78 -0
  346. slm/templates/rest_framework/filters/base.html +16 -0
  347. slm/templates/rest_framework/filters/ordering.html +17 -0
  348. slm/templates/rest_framework/filters/search.html +13 -0
  349. slm/templates/rest_framework/horizontal/checkbox.html +23 -0
  350. slm/templates/rest_framework/horizontal/checkbox_multiple.html +32 -0
  351. slm/templates/rest_framework/horizontal/dict_field.html +11 -0
  352. slm/templates/rest_framework/horizontal/fieldset.html +16 -0
  353. slm/templates/rest_framework/horizontal/form.html +6 -0
  354. slm/templates/rest_framework/horizontal/input.html +21 -0
  355. slm/templates/rest_framework/horizontal/list_field.html +11 -0
  356. slm/templates/rest_framework/horizontal/list_fieldset.html +13 -0
  357. slm/templates/rest_framework/horizontal/radio.html +42 -0
  358. slm/templates/rest_framework/horizontal/select.html +36 -0
  359. slm/templates/rest_framework/horizontal/select_multiple.html +38 -0
  360. slm/templates/rest_framework/horizontal/textarea.html +21 -0
  361. slm/templates/rest_framework/inline/checkbox.html +8 -0
  362. slm/templates/rest_framework/inline/checkbox_multiple.html +14 -0
  363. slm/templates/rest_framework/inline/dict_field.html +9 -0
  364. slm/templates/rest_framework/inline/fieldset.html +6 -0
  365. slm/templates/rest_framework/inline/form.html +8 -0
  366. slm/templates/rest_framework/inline/input.html +9 -0
  367. slm/templates/rest_framework/inline/list_field.html +9 -0
  368. slm/templates/rest_framework/inline/list_fieldset.html +3 -0
  369. slm/templates/rest_framework/inline/radio.html +25 -0
  370. slm/templates/rest_framework/inline/select.html +24 -0
  371. slm/templates/rest_framework/inline/select_multiple.html +25 -0
  372. slm/templates/rest_framework/inline/textarea.html +9 -0
  373. slm/templates/rest_framework/login.html +3 -0
  374. slm/templates/rest_framework/login_base.html +65 -0
  375. slm/templates/rest_framework/pagination/numbers.html +47 -0
  376. slm/templates/rest_framework/pagination/previous_and_next.html +21 -0
  377. slm/templates/rest_framework/raw_data_form.html +11 -0
  378. slm/templates/rest_framework/schema.js +3 -0
  379. slm/templates/rest_framework/vertical/checkbox.html +16 -0
  380. slm/templates/rest_framework/vertical/checkbox_multiple.html +30 -0
  381. slm/templates/rest_framework/vertical/dict_field.html +7 -0
  382. slm/templates/rest_framework/vertical/fieldset.html +13 -0
  383. slm/templates/rest_framework/vertical/form.html +6 -0
  384. slm/templates/rest_framework/vertical/input.html +17 -0
  385. slm/templates/rest_framework/vertical/list_field.html +7 -0
  386. slm/templates/rest_framework/vertical/list_fieldset.html +7 -0
  387. slm/templates/rest_framework/vertical/radio.html +40 -0
  388. slm/templates/rest_framework/vertical/select.html +34 -0
  389. slm/templates/rest_framework/vertical/select_multiple.html +31 -0
  390. slm/templates/rest_framework/vertical/textarea.html +17 -0
  391. slm/templates/slm/about.html +21 -0
  392. slm/templates/slm/alerts/alert.html +15 -0
  393. slm/templates/slm/alerts/geodesymlinvalid.html +8 -0
  394. slm/templates/slm/alerts/importalert.html +10 -0
  395. slm/templates/slm/alerts.html +18 -0
  396. slm/templates/slm/auth_menu.html +41 -0
  397. slm/templates/slm/base.html +195 -0
  398. slm/templates/slm/emails/alert_issued.html +31 -0
  399. slm/templates/slm/emails/alert_issued.txt +9 -0
  400. slm/templates/slm/emails/base.html +6 -0
  401. slm/templates/slm/emails/changes_rejected.txt +7 -0
  402. slm/templates/slm/emails/review_requested.txt +7 -0
  403. slm/templates/slm/forms/widgets/auto_complete.html +21 -0
  404. slm/templates/slm/forms/widgets/auto_complete_multiple.html +18 -0
  405. slm/templates/slm/forms/widgets/checkbox_multiple.html +6 -0
  406. slm/templates/slm/forms/widgets/inline_multi.html +1 -0
  407. slm/templates/slm/forms/widgets/splitdatetime.html +14 -0
  408. slm/templates/slm/forms/widgets/time24.html +37 -0
  409. slm/templates/slm/help.html +54 -0
  410. slm/templates/slm/messages.html +13 -0
  411. slm/templates/slm/new_site.html +88 -0
  412. slm/templates/slm/profile.html +57 -0
  413. slm/templates/slm/register.html +40 -0
  414. slm/templates/slm/reports/file_log.html +43 -0
  415. slm/templates/slm/reports/head_log.html +23 -0
  416. slm/templates/slm/reports/head_report.html +55 -0
  417. slm/templates/slm/reports/index_log.html +23 -0
  418. slm/templates/slm/reports/index_report.html +71 -0
  419. slm/templates/slm/station/alert.html +8 -0
  420. slm/templates/slm/station/alerts.html +19 -0
  421. slm/templates/slm/station/base.html +104 -0
  422. slm/templates/slm/station/download.html +87 -0
  423. slm/templates/slm/station/edit.html +283 -0
  424. slm/templates/slm/station/form.html +110 -0
  425. slm/templates/slm/station/log.html +18 -0
  426. slm/templates/slm/station/review.html +461 -0
  427. slm/templates/slm/station/upload.html +295 -0
  428. slm/templates/slm/station/uploads/attachment.html +20 -0
  429. slm/templates/slm/station/uploads/geodesyml.html +1 -0
  430. slm/templates/slm/station/uploads/image.html +27 -0
  431. slm/templates/slm/station/uploads/json.html +0 -0
  432. slm/templates/slm/station/uploads/legacy.html +77 -0
  433. slm/templates/slm/top_nav.html +14 -0
  434. slm/templates/slm/user_activity.html +16 -0
  435. slm/templates/slm/widgets/alert_scroll.html +135 -0
  436. slm/templates/slm/widgets/filelist.html +258 -0
  437. slm/templates/slm/widgets/legend.html +12 -0
  438. slm/templates/slm/widgets/log_scroll.html +88 -0
  439. slm/templates/slm/widgets/stationlist.html +233 -0
  440. slm/templatetags/__init__.py +0 -0
  441. slm/templatetags/jinja2.py +9 -0
  442. slm/templatetags/slm.py +459 -0
  443. slm/urls.py +148 -0
  444. slm/utils.py +299 -0
  445. slm/validators.py +297 -0
  446. slm/views.py +654 -0
  447. slm/widgets.py +134 -0
slm/api/serializers.py ADDED
@@ -0,0 +1,132 @@
1
+ import json
2
+
3
+ from django.template.loader import get_template
4
+ from django.utils.functional import cached_property
5
+ from lxml import etree
6
+ from rest_framework import serializers
7
+
8
+ from slm.defines import GeodesyMLVersion, SiteLogFormat, SiteLogStatus
9
+ from slm.models import Site
10
+
11
+
12
+ class _Heading:
13
+ pass
14
+
15
+
16
+ _heading = _Heading()
17
+
18
+
19
+ class SiteLogSerializer(serializers.BaseSerializer):
20
+ site = None
21
+ epoch = None
22
+ epoch_param = None
23
+ published_param = True
24
+ is_published = None
25
+ graphic = ""
26
+
27
+ text_tmpl = get_template("slm/sitelog/legacy.log")
28
+ text_9char_tmpl = get_template("slm/sitelog/ascii_9char.log")
29
+
30
+ xml_parser = etree.XMLParser(remove_blank_text=True)
31
+
32
+ def __init__(self, *args, instance, epoch=None, published=True, **kwargs):
33
+ self.site = instance
34
+ self.epoch_param = epoch
35
+ self.epoch = epoch
36
+ self.published_param = (bool(epoch) or published) or None
37
+ self.is_published = self.published_param or (
38
+ self.site.status not in SiteLogStatus.unpublished_states()
39
+ )
40
+ if self.epoch is None:
41
+ self.epoch = (
42
+ self.site.last_publish
43
+ if self.published_param
44
+ else self.site.last_update or self.site.created
45
+ )
46
+ super().__init__(*args, instance=instance, **kwargs)
47
+
48
+ def xml(self, version):
49
+ return etree.tostring(
50
+ etree.fromstring(
51
+ version.template.render(
52
+ {
53
+ **self.context,
54
+ "identifier": self.site.get_filename(
55
+ log_format=SiteLogFormat.GEODESY_ML, epoch=self.epoch_param
56
+ ).split(".")[0],
57
+ "files": self.site.sitefileuploads.public().order_by(
58
+ "timestamp"
59
+ ),
60
+ }
61
+ ).encode(),
62
+ parser=self.xml_parser,
63
+ ),
64
+ pretty_print=True,
65
+ ).decode()
66
+
67
+ @cached_property
68
+ def json(self):
69
+ # todo
70
+ return json.dumps({})
71
+
72
+ def format(self, log_format, version=None):
73
+ if log_format == SiteLogFormat.LEGACY:
74
+ return self.text
75
+ elif log_format == SiteLogFormat.ASCII_9CHAR:
76
+ return self.text_9char
77
+ elif log_format == SiteLogFormat.GEODESY_ML:
78
+ return self.xml(version=(version or GeodesyMLVersion.latest()))
79
+ raise NotImplementedError(
80
+ f"Serialization for format {log_format} is not yet implemented."
81
+ )
82
+
83
+ def section_name(self, name):
84
+ if name.startswith("site"):
85
+ return name[4:]
86
+ return name
87
+
88
+ @cached_property
89
+ def context(self):
90
+ def sort(subsections):
91
+ if subsections:
92
+ return subsections.sort()
93
+ return subsections
94
+
95
+ # todo put this logic on the site model?
96
+ graphic = ""
97
+ if self.published_param:
98
+ ant = self.site.siteantenna_set.published(epoch=self.epoch_param).last()
99
+ graphic = ant.graphic if ant else ""
100
+ else:
101
+ antennas = self.site.siteantenna_set.head(
102
+ epoch=self.epoch_param, include_deleted=False
103
+ ).sort(reverse=True)
104
+ if antennas:
105
+ graphic = antennas[0].graphic
106
+
107
+ return {
108
+ "site": self.site,
109
+ **{
110
+ self.section_name(section.field): (
111
+ getattr(self.site, section.accessor).published(
112
+ epoch=self.epoch_param
113
+ )
114
+ if self.published_param
115
+ else sort(
116
+ getattr(self.site, section.accessor).head(
117
+ epoch=self.epoch_param, include_deleted=False
118
+ )
119
+ )
120
+ )
121
+ for section in Site.sections()
122
+ },
123
+ "graphic": graphic,
124
+ }
125
+
126
+ @cached_property
127
+ def text(self):
128
+ return self.text_tmpl.render({**self.context, "include_templates": True})
129
+
130
+ @cached_property
131
+ def text_9char(self):
132
+ return self.text_9char_tmpl.render({**self.context, "include_templates": True})
slm/api/views.py ADDED
@@ -0,0 +1,148 @@
1
+ from datetime import datetime
2
+
3
+ from django.db.models import Q
4
+ from django.http import FileResponse
5
+ from django.utils.translation import gettext as _
6
+ from django_filters import filters
7
+ from django_filters.rest_framework import DjangoFilterBackend
8
+ from rest_framework import mixins, renderers, viewsets
9
+
10
+ from slm.api.filter import InitialValueFilterSet, SLMDateTimeFilter
11
+ from slm.defines import SiteLogFormat
12
+ from slm.models import ArchivedSiteLog, ArchiveIndex
13
+
14
+
15
+ class LegacyRenderer(renderers.BaseRenderer):
16
+ """
17
+ Renderer which serializes to legacy format.
18
+ """
19
+
20
+ media_type = SiteLogFormat.LEGACY.mimetype
21
+ format = SiteLogFormat.LEGACY
22
+
23
+ def render(self, data, accepted_media_type=None, renderer_context=None):
24
+ return b""
25
+
26
+
27
+ class ASCIIRenderer(renderers.BaseRenderer):
28
+ """
29
+ Renderer which serializes to legacy format.
30
+ """
31
+
32
+ media_type = SiteLogFormat.ASCII_9CHAR.mimetype
33
+ format = SiteLogFormat.ASCII_9CHAR
34
+
35
+ def render(self, data, accepted_media_type=None, renderer_context=None):
36
+ return b""
37
+
38
+
39
+ class GeodesyMLRenderer(renderers.BaseRenderer):
40
+ """
41
+ Renderer which serializes to GeodesyML format.
42
+ """
43
+
44
+ media_type = SiteLogFormat.GEODESY_ML.mimetype
45
+ format = SiteLogFormat.GEODESY_ML
46
+
47
+ def render(self, data, accepted_media_type=None, renderer_context=None):
48
+ return b""
49
+
50
+
51
+ class JSONRenderer(renderers.BaseRenderer):
52
+ """
53
+ Renderer which serializes to GeodesyML format.
54
+ """
55
+
56
+ media_type = SiteLogFormat.JSON.mimetype
57
+ format = SiteLogFormat.JSON
58
+
59
+ def render(self, data, accepted_media_type=None, renderer_context=None):
60
+ return b""
61
+
62
+
63
+ class BaseSiteLogDownloadViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
64
+ renderer_classes = [ASCIIRenderer, LegacyRenderer, GeodesyMLRenderer]
65
+
66
+ site = None
67
+
68
+ lookup_field = "site__name__istartswith"
69
+ lookup_url_kwarg = "site"
70
+
71
+ queryset = ArchiveIndex.objects.all()
72
+
73
+ class ArchiveIndexFilter(InitialValueFilterSet):
74
+ epoch = SLMDateTimeFilter(
75
+ method="at_epoch",
76
+ initial=lambda: datetime.now(),
77
+ help_text=_("Get the log that was active at this given date or datetime."),
78
+ )
79
+
80
+ name_len = filters.NumberFilter(
81
+ method="noop",
82
+ help_text=_(
83
+ "The number of characters to include in the filename from the "
84
+ "start of the 9 character site name."
85
+ ),
86
+ )
87
+
88
+ lower_case = filters.BooleanFilter(
89
+ method="noop", help_text=_("If true filename will be lowercase.")
90
+ )
91
+
92
+ def at_epoch(self, queryset, name, value):
93
+ return queryset.filter(
94
+ Q(begin__lte=value) & (Q(end__isnull=True) | Q(end__gt=value))
95
+ )
96
+
97
+ def noop(self, queryset, _1, _2):
98
+ return queryset
99
+
100
+ class Meta:
101
+ model = ArchiveIndex
102
+ fields = ["name_len", "epoch", "lower_case"]
103
+
104
+ filter_backends = (DjangoFilterBackend,)
105
+ filterset_class = ArchiveIndexFilter
106
+
107
+ def get_format_suffix(self, **kwargs):
108
+ requested_format = super().get_format_suffix(**kwargs)
109
+
110
+ # if the site name is a 4-id return the old 4char log format
111
+ if "site" in kwargs and len(kwargs["site"]) == 4 and requested_format == "log":
112
+ return SiteLogFormat.LEGACY
113
+
114
+ # match suffix first
115
+ for fmt in reversed(SiteLogFormat):
116
+ if fmt.ext == requested_format:
117
+ return fmt
118
+
119
+ # if that fails accept alts by priority
120
+ return SiteLogFormat(requested_format)
121
+
122
+ def retrieve(self, request, *args, **kwargs):
123
+ """
124
+ Download the site log rendered in the specified format - preferencing
125
+ the HTTP_ACCEPTS header over the format parameter. In most cases
126
+ from_site will fetch the archived log from disk, but if a format that
127
+ was not previously rendered is requested from_site might first create
128
+ a new ArchivedSiteLog. If no index is found and allow_unpublished is
129
+ true a new site log will be rendered from the current HEAD state.
130
+
131
+ :param request:
132
+ :param args:
133
+ :param kwargs:
134
+ :return:
135
+ """
136
+ index = self.get_object()
137
+ archived = ArchivedSiteLog.objects.from_index(
138
+ index=index, log_format=request.accepted_renderer.format
139
+ )
140
+ return FileResponse(
141
+ archived.file,
142
+ filename=index.site.get_filename(
143
+ log_format=archived.log_format,
144
+ epoch=index.begin,
145
+ name_len=request.GET.get("name_len", None),
146
+ lower_case=request.GET.get("lower_case", False),
147
+ ),
148
+ )
slm/apps.py ADDED
@@ -0,0 +1,323 @@
1
+ import sys
2
+ from pprint import pformat
3
+
4
+ from django.apps import AppConfig, apps
5
+ from django.conf import settings
6
+ from django.core.checks import Error, Tags, Warning, register
7
+ from django.db.models.signals import (
8
+ post_delete,
9
+ post_init,
10
+ post_migrate,
11
+ post_save,
12
+ pre_delete,
13
+ )
14
+ from django.dispatch import Signal
15
+ from django.utils.module_loading import import_string
16
+ from django.utils.translation import gettext as _
17
+
18
+ from slm.defines import GeodesyMLVersion
19
+ from slm.signals import signal_name
20
+ from slm.utils import clear_caches
21
+
22
+
23
+ @register("slm", Tags.security)
24
+ def check_permission_groups_setting(**kwargs):
25
+ error_id = "slm.E002"
26
+ header = _("settings.SLM_DEFAULT_PERMISSION_GROUPS is invalid")
27
+ group_setting = getattr(settings, "SLM_DEFAULT_PERMISSION_GROUPS", {})
28
+ errors = []
29
+ if group_setting:
30
+ for group_name, permissions in group_setting.items():
31
+ if not isinstance(group_name, str):
32
+ errors.append(
33
+ Error(
34
+ header,
35
+ hint=_("{} is not a group name string.").format(
36
+ str(group_name)
37
+ ),
38
+ id=error_id,
39
+ )
40
+ )
41
+ continue
42
+
43
+ try:
44
+ for perm in permissions:
45
+ if not isinstance(perm, str):
46
+ errors.append(
47
+ Error(
48
+ header,
49
+ hint=_(
50
+ "SLM_DEFAULT_PERMISSION_GROUPS[{}][{}] is not "
51
+ "a permission codename string."
52
+ "instead of {}."
53
+ ).format(group_name, str(perm)),
54
+ id=error_id,
55
+ )
56
+ )
57
+
58
+ except TypeError:
59
+ errors.append(
60
+ Error(
61
+ header,
62
+ hint=_(
63
+ "{} must be an iterable list of permission code names "
64
+ "instead of {}."
65
+ ).format(group_name, type(permissions)),
66
+ id=error_id,
67
+ )
68
+ )
69
+ return errors
70
+
71
+
72
+ @register("slm", Tags.security)
73
+ def check_permissions_setting(**kwargs):
74
+ warning_id = "slm.W001"
75
+ permissions = getattr(settings, "SLM_PERMISSIONS", None)
76
+ if permissions:
77
+ try:
78
+ from django.utils.module_loading import import_string
79
+
80
+ import_string(permissions)
81
+ except ImportError:
82
+ return [
83
+ Warning(
84
+ _(
85
+ f"Was unable to load SLM_PERMISSIONS callable: "
86
+ f"{permissions}"
87
+ ),
88
+ hint=_(
89
+ "Set SLM_PERMISSIONS to the import string for a "
90
+ "callable that returns a queryset of valid system"
91
+ "permissions."
92
+ ),
93
+ id=warning_id,
94
+ )
95
+ ]
96
+ return []
97
+
98
+
99
+ @register("slm", Tags.signals)
100
+ def check_automated_alerts(**kwargs):
101
+ error_id = "slm.E001"
102
+
103
+ def alert_conf_error(hint):
104
+ return Error(_("settings.SLM_AUTOMATED_ALERTS is incorrect."), hint, error_id)
105
+
106
+ alerts = getattr(settings, "SLM_AUTOMATED_ALERTS", {})
107
+ if not isinstance(alerts, dict):
108
+ return [
109
+ alert_conf_error(
110
+ _(
111
+ "SLM_AUTOMATED_ALERTS is a {} but it must be a dictionary"
112
+ "keyed on Alert model labels, the values are dictionaries "
113
+ "containing the signals configured to issue the alert and/or"
114
+ "rescind the alert and any default Alert model parameter "
115
+ "overrides."
116
+ ).format(type(alerts))
117
+ )
118
+ ]
119
+ errors = []
120
+ for alert, config in alerts.items():
121
+ try:
122
+ AlertModel = apps.get_model(*alert.split(".", 1))
123
+ except LookupError:
124
+ errors.append(
125
+ alert_conf_error(
126
+ _(
127
+ "SLM_AUTOMATED_ALERTS[{}] is not a registered model label."
128
+ ).format(alert)
129
+ )
130
+ )
131
+ continue
132
+ if not AlertModel.automated:
133
+ errors.append(
134
+ alert_conf_error(
135
+ _("SLM_AUTOMATED_ALERTS[{}] is a non-automated alert type.").format(
136
+ alert
137
+ )
138
+ )
139
+ )
140
+ continue
141
+
142
+ if not isinstance(AlertModel.objects.SUPPORTED_SIGNALS, dict):
143
+ errors.append(
144
+ alert_conf_error(
145
+ _(
146
+ "{}.objects.SUPPORTED_SIGNALS must be a dictionary keyed "
147
+ "with `issue` and `rescind` signal lists that are supported."
148
+ ).format(AlertModel.__name__)
149
+ )
150
+ )
151
+ continue
152
+
153
+ def check_signals(signal_type):
154
+ for signal in config.get(signal_type, []):
155
+ try:
156
+ signal = import_string(signal)
157
+ if not isinstance(signal, Signal):
158
+ errors.append(
159
+ alert_conf_error(
160
+ _(
161
+ "SLM_AUTOMATED_ALERTS[{}][{}][{}] is not a "
162
+ "Signal"
163
+ ).format(alert, signal_type, signal_name(signal)),
164
+ )
165
+ )
166
+ except ImportError:
167
+ errors.append(
168
+ alert_conf_error(
169
+ _(
170
+ "SLM_AUTOMATED_ALERTS[{}][{}] contains a non "
171
+ "existent trigger signal ({})."
172
+ ).format(alert, signal_type, signal_name(signal))
173
+ )
174
+ )
175
+ continue
176
+
177
+ if signal not in AlertModel.objects.SUPPORTED_SIGNALS.get(
178
+ signal_type, []
179
+ ):
180
+ errors.append(
181
+ alert_conf_error(
182
+ _(
183
+ "SLM_AUTOMATED_ALERTS[{}][{}] contains an "
184
+ "unsupported signal ({}) for alerts of type "
185
+ "{}. Must be one of:\n{}"
186
+ ).format(
187
+ alert,
188
+ signal_type,
189
+ signal_name(signal),
190
+ AlertModel,
191
+ pformat(
192
+ [
193
+ signal_name(sig)
194
+ for sig in AlertModel.objects.SUPPORTED_SIGNALS[
195
+ signal_type
196
+ ]
197
+ ]
198
+ ),
199
+ )
200
+ )
201
+ )
202
+
203
+ check_signals("issue")
204
+ check_signals("rescind")
205
+ return errors
206
+
207
+
208
+ def alert_save(sender, instance, created, raw, using, update_fields, **kwargs):
209
+ from slm.signals import alert_issued
210
+
211
+ if created:
212
+ alert_issued.send(sender=sender, alert=instance)
213
+
214
+
215
+ def cache_realalert(sender, instance, using, **kwargs):
216
+ """
217
+ Cache real alert instance onto the model because we wont be able
218
+ to get it in post because it no longer exists.
219
+ """
220
+ #
221
+ instance._slm_real_alert = instance.get_real_instance()
222
+
223
+
224
+ def alert_delete(sender, instance, using, **kwargs):
225
+ from slm.signals import alert_cleared
226
+
227
+ alert_cleared.send(
228
+ sender=sender, alert=getattr(instance, "_slm_real_alert", instance)
229
+ )
230
+
231
+
232
+ def site_init(sender, instance, **kwargs):
233
+ # publishing may be tracked through a status update or if the
234
+ # last_publish timestamp changes
235
+
236
+ # an infinite recursion loop is triggered if you access a deferred
237
+ # field in a model's init(). We guard against that case here, which
238
+ # can happen when related fields are deleted. Such cases should
239
+ # not involve a status update
240
+ deferred = instance.get_deferred_fields()
241
+ if "status" not in deferred and "last_publish" not in deferred:
242
+ instance._slm_pre_status = instance.status
243
+ instance._slm_last_publish = instance.last_publish
244
+ if instance.pk is None:
245
+ instance._slm_pre_status = None
246
+ instance._slm_last_publish = None
247
+
248
+
249
+ def site_save(sender, instance, created, raw, using, update_fields, **kwargs):
250
+ from slm.models import Site
251
+ from slm.signals import site_status_changed
252
+
253
+ if (
254
+ hasattr(instance, "_slm_pre_status")
255
+ and instance._slm_pre_status != instance.status
256
+ ) or ( # todo why this second clause?
257
+ hasattr(instance, "_slm_last_publish")
258
+ and instance._slm_last_publish != instance.last_publish
259
+ ):
260
+ site_status_changed.send(
261
+ sender=Site,
262
+ site=instance,
263
+ previous_status=instance._slm_pre_status,
264
+ new_status=instance.status,
265
+ )
266
+
267
+
268
+ def user_save(sender, instance, created, raw, using, update_fields, **kwargs):
269
+ """Clear any relevant caches whenever a user is saved."""
270
+ clear_caches()
271
+
272
+
273
+ def populate_groups(**kwargs):
274
+ from django.contrib.auth.models import Group, Permission
275
+
276
+ for group_name, permissions in getattr(
277
+ settings, "SLM_DEFAULT_PERMISSION_GROUPS", {}
278
+ ).items():
279
+ group, created = Group.objects.get_or_create(name=group_name)
280
+ if created:
281
+ group.permissions.set(Permission.objects.filter(codename__in=permissions))
282
+ group.save()
283
+
284
+
285
+ class SLMConfig(AppConfig):
286
+ name = "slm"
287
+
288
+ # space is used as a workaround to alphabetically push SLM to the
289
+ # top of the admin
290
+ verbose_name = " SLM"
291
+
292
+ def ready(self):
293
+ from django.contrib.auth import get_user_model
294
+
295
+ from slm.models import Alert, Site
296
+ from slm.receivers import register as register_receivers
297
+
298
+ register_receivers()
299
+
300
+ post_init.connect(site_init, sender=Site)
301
+ post_save.connect(site_save, sender=Site)
302
+ post_save.connect(user_save, sender=get_user_model())
303
+ post_migrate.connect(populate_groups)
304
+
305
+ for alert in Alert.objects.classes():
306
+ post_save.connect(alert_save, sender=alert)
307
+ pre_delete.connect(cache_realalert, sender=Alert)
308
+ post_delete.connect(alert_delete, sender=Alert)
309
+
310
+ # load schemas into memory - this can take a few moments and requires
311
+ # a live internet connection
312
+ xsd_preload = getattr(
313
+ settings, "SLM_PRELOAD_SCHEMAS", [geo for geo in GeodesyMLVersion]
314
+ )
315
+
316
+ if (
317
+ xsd_preload
318
+ and not getattr(settings, "SLM_MANAGEMENT_MODE", False)
319
+ and not (len(sys.argv) >= 2 and sys.argv[1] == "runserver")
320
+ ):
321
+ from slm.parsing.xsd import load_schemas
322
+
323
+ load_schemas()