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/views.py ADDED
@@ -0,0 +1,654 @@
1
+ """
2
+ Handles web requests and responses.
3
+
4
+ NOTES:
5
+ Holds important functions for each page.
6
+ Data processing, validation, etc. lives here.
7
+
8
+ ADD MORE COMMENTS
9
+
10
+ MORE INFO:
11
+ https://docs.djangoproject.com/en/stable/topics/http/views/
12
+ """
13
+
14
+ from enum import Enum
15
+
16
+ from django.conf import settings
17
+ from django.contrib.auth import get_user_model
18
+ from django.contrib.auth.decorators import login_required
19
+ from django.core.exceptions import PermissionDenied
20
+ from django.db.models import Max, Q
21
+ from django.db.models.fields import NOT_PROVIDED
22
+ from django.http import Http404, HttpResponseNotFound
23
+ from django.template.exceptions import TemplateDoesNotExist
24
+ from django.template.loader import get_template
25
+ from django.utils.decorators import method_decorator
26
+ from django.views.generic import TemplateView
27
+
28
+ from slm import defines
29
+ from slm.api.edit.views import StationFilterForm
30
+ from slm.defines import (
31
+ AlertLevel,
32
+ SiteFileUploadStatus,
33
+ SiteLogFormat,
34
+ SiteLogStatus,
35
+ SLMFileType,
36
+ )
37
+ from slm.forms import (
38
+ NewSiteForm,
39
+ RichTextForm,
40
+ SiteAntennaForm,
41
+ SiteCollocationForm,
42
+ SiteFileForm,
43
+ SiteFormForm,
44
+ SiteFrequencyStandardForm,
45
+ SiteHumiditySensorForm,
46
+ SiteIdentificationForm,
47
+ SiteLocalEpisodicEffectsForm,
48
+ SiteLocationForm,
49
+ SiteMoreInformationForm,
50
+ SiteMultiPathSourcesForm,
51
+ SiteOperationalContactForm,
52
+ SiteOtherInstrumentationForm,
53
+ SitePressureSensorForm,
54
+ SiteRadioInterferencesForm,
55
+ SiteReceiverForm,
56
+ SiteResponsibleAgencyForm,
57
+ SiteSignalObstructionsForm,
58
+ SiteSurveyedLocalTiesForm,
59
+ SiteTemperatureSensorForm,
60
+ SiteWaterVaporRadiometerForm,
61
+ UserForm,
62
+ UserProfileForm,
63
+ )
64
+ from slm.models import (
65
+ About,
66
+ Agency,
67
+ Alert,
68
+ ArchivedSiteLog,
69
+ Help,
70
+ Network,
71
+ Site,
72
+ SiteFileUpload,
73
+ SiteLocation,
74
+ SiteSubSection,
75
+ )
76
+ from slm.parsing import Error, Warn
77
+
78
+ User = get_user_model()
79
+
80
+
81
+ @method_decorator(login_required, name="dispatch")
82
+ class SLMView(TemplateView):
83
+ DEFINES = {
84
+ name: define
85
+ for name, define in vars(defines).items()
86
+ if isinstance(define, type) and issubclass(define, Enum)
87
+ }
88
+
89
+ def get_context_data(self, **kwargs):
90
+ context = super().get_context_data(**kwargs)
91
+ context.update(self.DEFINES)
92
+ Alert.objects.all().delete_expired()
93
+ max_alert = Alert.objects.visible_to(self.request.user).aggregate(Max("level"))[
94
+ "level__max"
95
+ ]
96
+ if max_alert is NOT_PROVIDED:
97
+ max_alert = None
98
+
99
+ context["user"] = self.request.user
100
+ context["alert_level"] = AlertLevel(max_alert) if max_alert else None
101
+
102
+ context["SLM_ORG_NAME"] = getattr(settings, "SLM_ORG_NAME", None)
103
+ context["is_moderator"] = (
104
+ self.request.user.is_superuser if self.request.user else None
105
+ )
106
+ context["networks"] = Network.objects.all()
107
+ if self.request.user.is_superuser:
108
+ context["user_agencies"] = Agency.objects.all()
109
+ else:
110
+ context["user_agencies"] = self.request.user.agencies.all()
111
+ return context
112
+
113
+
114
+ class StationContextView(SLMView):
115
+ station = None
116
+ agencies = None
117
+ sites = None
118
+ site = None
119
+
120
+ @method_decorator(login_required)
121
+ def dispatch(self, request, *args, **kwargs):
122
+ return super().dispatch(request, *args, **kwargs)
123
+
124
+ def get_context_data(self, **kwargs):
125
+ context = super().get_context_data(**kwargs)
126
+ self.station = kwargs.get("station", None)
127
+ self.sites = Site.objects.editable_by(self.request.user)
128
+ self.site = (
129
+ Site.objects.filter(name__iexact=self.station)
130
+ .editable_by(self.request.user)
131
+ .first()
132
+ )
133
+ initial = None
134
+ if self.request.GET:
135
+ station_filter = StationFilterForm(data=self.request.GET)
136
+ station_filter.full_clean()
137
+ if station_filter.errors:
138
+ raise Http404(station_filter.errors)
139
+ initial = station_filter.cleaned_data
140
+ filter_form = StationFilterForm(initial=initial)
141
+ if self.site:
142
+ self.agencies = [agency for agency in self.site.agencies.all()]
143
+ location = SiteLocation.objects.filter(site=self.site).head()
144
+ if location and location.llh:
145
+ context["station_position"] = (location.llh[0], location.llh[1])
146
+ context["attn_files"] = (
147
+ self.site.sitefileuploads.available_to(self.request.user)
148
+ .filter(status=SiteFileUploadStatus.UNPUBLISHED)
149
+ .count()
150
+ )
151
+ else:
152
+ self.agencies = filter_form.initial.get("agency", [])
153
+
154
+ max_alert = (
155
+ Alert.objects.visible_to(self.request.user)
156
+ .for_site(self.site)
157
+ .aggregate(Max("level"))["level__max"]
158
+ )
159
+ if max_alert is NOT_PROVIDED:
160
+ max_alert = None
161
+
162
+ context.update(
163
+ {
164
+ "num_sites": self.sites.count(),
165
+ "station": self.station if self.station else None,
166
+ "site": self.site if self.site else None,
167
+ "agencies": self.agencies,
168
+ "is_moderator": (
169
+ self.site.is_moderator(self.request.user) if self.site else None
170
+ ),
171
+ # some non-moderators may be able to publish a some changes
172
+ "can_publish": (
173
+ self.site.can_publish(self.request.user) if self.site else None
174
+ ),
175
+ "is_publishable": self.site.is_publishable() if self.site else None,
176
+ "link_view": (
177
+ "slm:edit"
178
+ if self.request.resolver_match.view_name
179
+ not in {
180
+ "slm:alerts",
181
+ "slm:download",
182
+ "slm:review",
183
+ "slm:log",
184
+ "slm:edit",
185
+ }
186
+ else self.request.resolver_match.view_name
187
+ ),
188
+ "station_alert_level": (AlertLevel(max_alert) if max_alert else None),
189
+ "site_alerts": Alert.objects.site_alerts(),
190
+ "filter_form": filter_form,
191
+ }
192
+ )
193
+
194
+ if self.station:
195
+ try:
196
+ self.station = Site.objects.get(name=context["station"])
197
+ if (
198
+ not self.request.user.is_superuser
199
+ and self.station not in self.sites
200
+ ):
201
+ raise PermissionDenied()
202
+ except Site.DoesNotExist:
203
+ raise Http404(f'Site {context["station"]} was not found!')
204
+ return context
205
+
206
+
207
+ class EditView(StationContextView):
208
+ """
209
+ This is the view that creates and renders a context when a user requests
210
+ to edit a site log. Site log edit forms do not render a giant form for the
211
+ entire site log. The specific section being edited is part of the request
212
+ url. So the job of this view is to compile enough context to render the
213
+ status and error information for all sections as well as all of the
214
+ information required to edit the requested section.
215
+ """
216
+
217
+ template_name = "slm/station/edit.html"
218
+
219
+ FORMS = {
220
+ form.Meta.model.section_slug(): form
221
+ for form in [
222
+ SiteFormForm,
223
+ SiteIdentificationForm,
224
+ SiteLocationForm,
225
+ SiteReceiverForm,
226
+ SiteAntennaForm,
227
+ SiteSurveyedLocalTiesForm,
228
+ SiteFrequencyStandardForm,
229
+ SiteCollocationForm,
230
+ SiteHumiditySensorForm,
231
+ SitePressureSensorForm,
232
+ SiteTemperatureSensorForm,
233
+ SiteWaterVaporRadiometerForm,
234
+ SiteOtherInstrumentationForm,
235
+ SiteRadioInterferencesForm,
236
+ SiteMultiPathSourcesForm,
237
+ SiteSignalObstructionsForm,
238
+ SiteLocalEpisodicEffectsForm,
239
+ SiteOperationalContactForm,
240
+ SiteResponsibleAgencyForm,
241
+ SiteMoreInformationForm,
242
+ ]
243
+ }
244
+
245
+ def get_context_data(self, **kwargs):
246
+ """
247
+ Builds a context that contains the sections and their meta information
248
+ as well as forms bound ot the site log data at head for the section
249
+ being edited. The context dictionary includes all StationContextView
250
+ context as well as:
251
+
252
+ ..code-block::
253
+
254
+ # forms contains the information needed to render the forms in the
255
+ # central edit pane
256
+ 'forms': [...], # bound form instances to section models at head
257
+ # for the section being edited. If the section
258
+ # does not allow subsections it will be a list of
259
+ # length 1, if it does allow subections, it will
260
+ # be a list of bound subsection forms and the
261
+ # first instance in the list will be an unbound
262
+ # form used to add new subsections
263
+
264
+ 'multi': True, # True if the section being edited has subsections
265
+ 'section_id': str, # The identifier of the section being edited
266
+ 'section_name': str, # The display name of the section
267
+
268
+ # dictionary of sections in render-order - keys are section_names
269
+ # this dictionary contains the meta information needed to render
270
+ # the navigation
271
+ 'sections': {
272
+ 'Section Name': {
273
+ 'flags': int, # the cumulative number of error flags on
274
+ # this section
275
+ 'id': str, # section_id
276
+
277
+ # the SiteLogStatus of the section
278
+ 'status': SiteLogStatus
279
+
280
+ 'subsections': {
281
+ 'Subsection Name': {
282
+ 'active': False, # True if subsection is selected
283
+ 'flags': # the number of error flags the subsection
284
+ 'id': str, # section_id
285
+
286
+ # the SiteLogStatus of the section
287
+ 'status': SiteLogStatus
288
+ },
289
+ ...
290
+ },
291
+ },
292
+ ...
293
+ }
294
+
295
+ """
296
+ context = super().get_context_data(**kwargs)
297
+ if not self.site:
298
+ raise Http404(f'Station {kwargs.get("station", "")} does not exist!')
299
+ context.update(
300
+ {
301
+ "section_id": kwargs.get("section", None),
302
+ "sections": {},
303
+ "forms": [],
304
+ "station_images": self.site.sitefileuploads.available_to(
305
+ self.request.user
306
+ ).filter(
307
+ status=SiteFileUploadStatus.PUBLISHED,
308
+ file_type=SLMFileType.SITE_IMAGE,
309
+ ),
310
+ "station_attachments": self.site.sitefileuploads.available_to(
311
+ self.request.user
312
+ ).filter(
313
+ status=SiteFileUploadStatus.PUBLISHED,
314
+ file_type=SLMFileType.ATTACHMENT,
315
+ ),
316
+ }
317
+ )
318
+
319
+ section = self.FORMS.get(kwargs.get("section", None), None)
320
+ if section:
321
+ context["section_name"] = section.section_name()
322
+ context["multi"] = issubclass(section._meta.model, SiteSubSection)
323
+
324
+ # create the context of our form tree - the form/edit templates are
325
+ # responsible for rendering this structure in html
326
+ for section_id, form in self.FORMS.items():
327
+ if hasattr(form, "NAV_HEADING"):
328
+ context["sections"].setdefault(
329
+ form.NAV_HEADING,
330
+ {
331
+ "id": form.group_name(),
332
+ "flags": 0,
333
+ "status": SiteLogStatus.EMPTY,
334
+ "active": False,
335
+ "subsections": {},
336
+ },
337
+ )["subsections"][form.section_name()] = {
338
+ "id": form.section_name().lower().replace(" ", ""),
339
+ "group": form.group_name(), # todo remove
340
+ "parent": form.group_name(),
341
+ "flags": 0,
342
+ "active": False,
343
+ "status": SiteLogStatus.EMPTY,
344
+ }
345
+ if section is form:
346
+ context["parent"] = form.group_name()
347
+
348
+ else:
349
+ context["sections"][form.section_name()] = {
350
+ "id": form.section_name().lower().replace(" ", ""),
351
+ "flags": 0,
352
+ "status": SiteLogStatus.EMPTY,
353
+ }
354
+
355
+ if issubclass(form._meta.model, SiteSubSection):
356
+ # for subsections we need to:
357
+ # 1) set nav heading meta information
358
+ # 2) add sections for all children
359
+ # 3) populate the subsections of the requested edit form
360
+
361
+ heading = context["sections"][
362
+ getattr(form, "NAV_HEADING", form.section_name())
363
+ ]
364
+ subheading = None
365
+ if hasattr(form, "NAV_HEADING"):
366
+ subheading = heading["subsections"][form.section_name()]
367
+
368
+ for inst in (
369
+ form._meta.model.objects.station(self.station)
370
+ .head(include_deleted=True)
371
+ .sort(reverse=True)
372
+ ):
373
+ if section is form:
374
+ # if this is our requested form for editing - populate
375
+ # it with data from head
376
+ context["forms"].append(
377
+ form(
378
+ instance=inst,
379
+ initial={
380
+ field: getattr(inst, field)
381
+ for field in form._meta.fields
382
+ },
383
+ )
384
+ )
385
+
386
+ heading["flags"] += inst.num_flags if inst else 0
387
+ heading["status"] = heading.get("status", inst.mod_status).merge(
388
+ inst.mod_status
389
+ )
390
+ if subheading:
391
+ subheading.setdefault("flags", 0)
392
+ subheading["flags"] += inst.num_flags if inst else 0
393
+ subheading["status"] = subheading.get(
394
+ "status", inst.mod_status
395
+ ).merge(inst.mod_status)
396
+
397
+ if section is form:
398
+ # if this is the edit section we add an empty form as the
399
+ # first form in the context, the template knows to render
400
+ # this form as the 'add' subsection form
401
+ context["forms"].insert(0, form(initial={"site": self.station}))
402
+ context["copy_last_on_add"] = [
403
+ field
404
+ for field in getattr(form, "COPY_LAST_ON_ADD", [])
405
+ if field not in {"id", "subsection"}
406
+ # guard against these ^ fields being included -
407
+ # will break things
408
+ ]
409
+ heading["active"] = heading.get("active", True) | True
410
+ if subheading:
411
+ subheading["active"] = True
412
+
413
+ # add form (sub-sub section) numbers
414
+ number = 1
415
+ for form in reversed(context["forms"]):
416
+ if not getattr(form.instance, "is_deleted", False):
417
+ form.form_number = number
418
+ number += 1
419
+
420
+ else:
421
+ instance = form._meta.model.objects.station(
422
+ self.station
423
+ ).head() # we always edit on head
424
+ if section is form:
425
+ # only one form is requested per edit view request - if
426
+ # this section is that form we need to populate it with
427
+ # data
428
+ context["forms"].append(
429
+ form(
430
+ instance=instance,
431
+ initial=(
432
+ {
433
+ field: getattr(instance, field, None)
434
+ for field in form._meta.fields
435
+ }
436
+ if instance
437
+ else {"site": self.station}
438
+ ),
439
+ )
440
+ )
441
+ context["sections"][form.section_name()]["active"] = True
442
+
443
+ # for all sections we need to set status and number of flags
444
+ context["sections"][form.section_name()]["flags"] = (
445
+ instance.num_flags if instance else 0
446
+ )
447
+ context["sections"][form.section_name()]["status"] = (
448
+ instance.mod_status if instance else SiteLogStatus.EMPTY
449
+ )
450
+
451
+ return context
452
+
453
+
454
+ class StationAlertsView(StationContextView):
455
+ template_name = "slm/station/alerts.html"
456
+
457
+ def get_context_data(self, **kwargs):
458
+ context = super().get_context_data(**kwargs)
459
+ context["exclude_targets"] = True
460
+ return context
461
+
462
+
463
+ class UploadView(StationContextView):
464
+ template_name = "slm/station/upload.html"
465
+
466
+ def get_context_data(self, file=None, **kwargs):
467
+ context = super().get_context_data(**kwargs)
468
+ if file:
469
+ try:
470
+ file = SiteFileUpload.objects.get(pk=file)
471
+ except SiteFileUpload.DoesNotExist:
472
+ raise Http404(f"File {file} does not exist.")
473
+ context["file"] = file
474
+ if file.context:
475
+ context.update(file.context)
476
+ if "findings" in context:
477
+ errors = 0
478
+ warnings = 0
479
+ for lineno, finding in context["findings"].items():
480
+ if finding[0] == Error.level:
481
+ errors += 1
482
+ elif finding[0] == Warn.level:
483
+ warnings += 1
484
+ context["finding_errors"] = errors
485
+ context["finding_warnings"] = warnings
486
+
487
+ if file.file_type in {SLMFileType.SITE_IMAGE, SLMFileType.ATTACHMENT}:
488
+ context["form"] = SiteFileForm(instance=file)
489
+ context["num_files"] = SiteFileUpload.objects.filter(site=self.site).count()
490
+ context["MAX_UPLOAD_MB"] = getattr(settings, "SLM_MAX_UPLOAD_SIZE_MB", 100)
491
+ context["link_view"] = "slm:upload"
492
+ return context
493
+
494
+
495
+ class NewSiteView(StationContextView):
496
+ template_name = "slm/new_site.html"
497
+
498
+ def get_context_data(self, **kwargs):
499
+ context = super().get_context_data(**kwargs)
500
+ context["form"] = NewSiteForm(
501
+ initial=(
502
+ {"agencies": self.request.user.agencies.all()}
503
+ if not self.request.user.is_superuser
504
+ else {}
505
+ )
506
+ )
507
+ if not self.request.user.is_superuser:
508
+ context["form"].fields["agencies"].queryset = self.request.user.agencies
509
+ return context
510
+
511
+
512
+ class IndexView(StationContextView):
513
+ template_name = "slm/station/base.html"
514
+
515
+
516
+ class DownloadView(StationContextView):
517
+ template_name = "slm/station/download.html"
518
+
519
+
520
+ class UserProfileView(SLMView):
521
+ template_name = "slm/profile.html"
522
+
523
+ @method_decorator(login_required)
524
+ def get(self, request, *args, **kwargs):
525
+ return self.render_to_response(
526
+ {
527
+ **self.get_context_data(**kwargs),
528
+ "user_form": UserForm(instance=request.user),
529
+ "profile_form": UserProfileForm(instance=request.user.profile),
530
+ }
531
+ )
532
+
533
+
534
+ class LogView(StationContextView):
535
+ template_name = "slm/station/log.html"
536
+
537
+
538
+ class UserActivityLogView(SLMView):
539
+ template_name = "slm/user_activity.html"
540
+
541
+ def get_context_data(self, log_user=None, **kwargs):
542
+ context = super().get_context_data()
543
+ try:
544
+ if log_user:
545
+ # must be a super user to see other people's log history
546
+ # todo configurable perm for this? like is mod for user's
547
+ # agency?
548
+ if not self.request.user.is_superuser:
549
+ raise PermissionDenied()
550
+
551
+ context["log_user"] = get_user_model().objects.get(pk=log_user)
552
+ else:
553
+ # otherwise we're getting the logged in user's log history
554
+ context["log_user"] = self.request.user
555
+
556
+ except get_user_model().DoesNotExist:
557
+ raise Http404()
558
+
559
+ return context
560
+
561
+
562
+ class StationReviewView(StationContextView):
563
+ template_name = "slm/station/review.html"
564
+
565
+ LOG_FORMATS = {
566
+ fmt
567
+ for fmt in SiteLogFormat
568
+ if fmt not in {SiteLogFormat.JSON, SiteLogFormat.LEGACY}
569
+ }
570
+
571
+ def get_context_data(self, **kwargs):
572
+ ctx = super().get_context_data(**kwargs)
573
+
574
+ # we use legacy log files on the ascii 9 char review stack if no 9 char file is available
575
+ review_stack = {fmt: [] for fmt in self.LOG_FORMATS}
576
+ for fmt in self.LOG_FORMATS:
577
+ fmt_q = Q(log_format=fmt)
578
+ if fmt is SiteLogFormat.ASCII_9CHAR:
579
+ fmt_q |= Q(log_format=SiteLogFormat.LEGACY)
580
+ for archive in (
581
+ ArchivedSiteLog.objects.filter(Q(site=self.site) & fmt_q)
582
+ .order_by("-index__begin", "-log_format")
583
+ .values_list("index__begin", "id")
584
+ .distinct("index__begin")
585
+ ):
586
+ review_stack[fmt].append((archive[0], archive[1]))
587
+ ctx = {
588
+ **ctx,
589
+ "richtextform": RichTextForm(),
590
+ "default_format": SiteLogFormat.ASCII_9CHAR,
591
+ "log_formats": self.LOG_FORMATS,
592
+ "review_stack": review_stack,
593
+ "needs_publish": self.station.needs_publish(),
594
+ }
595
+ if ctx["needs_publish"]:
596
+ for fmt in self.LOG_FORMATS:
597
+ ctx["review_stack"][fmt].insert(0, (None, None))
598
+ return ctx
599
+
600
+
601
+ class AlertsView(SLMView):
602
+ template_name = "slm/alerts.html"
603
+
604
+
605
+ class AlertView(StationContextView):
606
+ template_name = "slm/station/alert.html"
607
+ template_map = {}
608
+ alert = None
609
+
610
+ def get_template(self, alert):
611
+ if alert.__class__ not in self.template_map:
612
+ try:
613
+ self.template_map[alert.__class__] = get_template(
614
+ f"slm/alerts/{alert.__class__.__name__.lower()}.html"
615
+ )
616
+ except TemplateDoesNotExist:
617
+ self.template_map[alert.__class__] = get_template(
618
+ "slm/alerts/alert.html"
619
+ )
620
+ return self.template_map[alert.__class__]
621
+
622
+ def get_context_data(self, **kwargs):
623
+ if hasattr(self.alert, "site") and self.alert.site:
624
+ kwargs["station"] = self.alert.site.name
625
+ context = super().get_context_data(**kwargs)
626
+ context.update(
627
+ {
628
+ **self.alert.context,
629
+ "alert_template": self.get_template(self.alert).origin.template_name,
630
+ "exclude_targets": True,
631
+ }
632
+ )
633
+ return context
634
+
635
+ def get(self, request, *args, **kwargs):
636
+ try:
637
+ self.alert = Alert.objects.get(pk=kwargs.pop("alert", None))
638
+ except Alert.DoesNotExist:
639
+ return HttpResponseNotFound()
640
+ return super().get(request, *args, **kwargs)
641
+
642
+
643
+ class HelpView(SLMView):
644
+ template_name = "slm/help.html"
645
+
646
+ def get_context_data(self, **kwargs):
647
+ return {**super().get_context_data(**kwargs), "help": Help.load()}
648
+
649
+
650
+ class AboutView(SLMView):
651
+ template_name = "slm/about.html"
652
+
653
+ def get_context_data(self, **kwargs):
654
+ return {**super().get_context_data(**kwargs), "about": About.load()}