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
@@ -0,0 +1,1028 @@
1
+ if (typeof slm === 'undefined' || slm === null) { var slm = {}; }
2
+
3
+ $(document).ready(function() {
4
+ $(".collapse .nav-link").click(function () {
5
+ $(".collapse .nav-link").removeClass("active");
6
+ $(this).addClass("active");
7
+ });
8
+
9
+ $('[data-bs-toggle="tooltip"]').tooltip();
10
+ $('[data-bs-toggle="popover"]').popover();
11
+
12
+ $('.slm-form').each(function() {
13
+ slm.initForm($(this));
14
+ });
15
+ });
16
+
17
+ /*slm.popover = new bootstrap.Popover(
18
+ document.querySelector('.popover-dismiss'),
19
+ {
20
+ trigger: 'focus',
21
+ container: 'body'
22
+ }
23
+ );*/
24
+
25
+ class ErrorBadgeUpdater {
26
+
27
+ constructor(form) {
28
+ this.form = form;
29
+ this.delta = null;
30
+ }
31
+
32
+ visit(node) {
33
+ if (this.delta === null) {
34
+ this.delta = Object.keys(this.form.data('slmErrorFlags')).length -
35
+ (node.data('slmFlags') || 0);
36
+ }
37
+ let badge = node.find('span.slm-error-badge');
38
+ let newNum = (node.data('slmFlags') || 0) + this.delta;
39
+ newNum = newNum < 0 ? 0 : newNum;
40
+ node.data('slmFlags', newNum);
41
+ if (newNum <= 0) {
42
+ badge.hide();
43
+ badge.html(0);
44
+ } else {
45
+ badge.show();
46
+ badge.html(newNum);
47
+ }
48
+ }
49
+ }
50
+
51
+ class StatusUpdater {
52
+
53
+ constructor(form, status) {
54
+ this.form = form;
55
+ if (!status instanceof SiteLogStatus) {
56
+ this.status = slm.SiteLogStatus.get(status);
57
+ } else {
58
+ this.status = status;
59
+ }
60
+ }
61
+
62
+ visit(node) {
63
+ /* update navigation button status classes and data */
64
+ let currentStatus = slm.SiteLogStatus.get(
65
+ node.data('slmStatus')
66
+ );
67
+ if (currentStatus !== null) {
68
+ this.status = currentStatus.set(this.status);
69
+ node.removeClass(currentStatus.css);
70
+ }
71
+ node.addClass(this.status.css);
72
+ node.data('slmStatus', this.status.value);
73
+ slm.getNavSiblings(node).each(function(idx, sibling) {
74
+ this.status = this.status.merge(
75
+ slm.SiteLogStatus.get(
76
+ $(sibling).data('slmStatus')
77
+ )
78
+ )
79
+ }.bind(this));
80
+ }
81
+ }
82
+
83
+ slm.isModerator = !slm.hasOwnProperty('isModerator') ? false : slm.isModerator;
84
+ slm.canPublish = !slm.hasOwnProperty('canPublish') ? false : slm.canPublish;
85
+
86
+ slm.handlePostSuccess = function(form, response, status, jqXHR) {
87
+ form.find('button').blur();
88
+ const data = response && response.hasOwnProperty('results') ? response.results : response;
89
+ if (jqXHR.status === 204) {
90
+ form.data('slmErrorFlags', {});
91
+ slm.visitEditNavTree(form, new ErrorBadgeUpdater(form));
92
+ slm.visitEditNavTree(
93
+ form,
94
+ new StatusUpdater(
95
+ form,
96
+ SiteLogStatus.EMPTY
97
+ )
98
+ );
99
+ form.closest('.accordion-item').remove();
100
+ return;
101
+ }
102
+ if (jqXHR.status === 205) {
103
+ return window.location.reload();
104
+ }
105
+ form.data('slmId', data.id);
106
+ form.find('input[name="id"]').val(data.id);
107
+ if (data.hasOwnProperty('subsection')) {
108
+ form.find('input[name="subsection"]').val(data.subsection);
109
+ }
110
+ if (data.is_deleted) {
111
+ form.addClass('slm-section-deleted');
112
+ form.closest('.accordion-item').find(
113
+ 'button.accordion-button'
114
+ ).addClass('slm-section-deleted').removeClass(
115
+ 'slm-status-published'
116
+ ).addClass('slm-status-updated');
117
+ form.find('.alert.slm-form-deleted').show();
118
+ form.find('.form-control:visible').attr('disabled', '');
119
+ form.find('input.form-check-input:visible').attr('disabled', '');
120
+ form.find('.slm-flag').hide();
121
+ form.find('div[contenteditable]').removeAttr('contenteditable');
122
+ } else {
123
+ if (slm.isModerator) {
124
+ form.find('.slm-flag').show();
125
+ } else {
126
+ form.find('.slm-flag').hide();
127
+ }
128
+ form.removeClass('slm-section-deleted');
129
+ form.closest('.accordion-item').find(
130
+ 'button.accordion-button'
131
+ ).removeClass('slm-section-deleted');
132
+ form.find('.alert.slm-form-deleted').hide();
133
+ form.find('.form-control:visible').removeAttr('disabled');
134
+ form.find('input.form-check-input:visible').removeAttr('disabled', '');
135
+ form.find('.slm-flag').show();
136
+ form.find('div[contenteditable]').attr('contenteditable', true);
137
+ }
138
+
139
+ if (data.hasOwnProperty('_diff') && Object.keys(data._diff).length) {
140
+ if (!data.is_deleted) {
141
+ form.find('.alert.slm-form-unpublished').show();
142
+ }
143
+ for (const [field, diff] of Object.entries(data._diff)) {
144
+ const formField = form.find(`#id_${field}-${form.attr('id').replace('site-', '')}`);
145
+ formField.addClass('is-invalid');
146
+ if (data.hasOwnProperty('_flags') && !data._flags.hasOwnProperty(field)) {
147
+ formField.addClass('slm-form-unpublished');
148
+ }
149
+ formField.after(
150
+ `<div class="invalid-feedback slm-form-unpublished">The published value is ${diff.pub}</div>`
151
+ );
152
+ }
153
+ }
154
+ let headingButton = form.closest('.accordion-item').find('button.accordion-button');
155
+ headingButton.find('.slm-heading').html(data.heading);
156
+ headingButton.find('.slm-effective').html(data.effective);
157
+ if (data.hasOwnProperty('_flags')) {
158
+ form.data('slmErrorFlags', data._flags);
159
+ slm.setFormFlagUI(form);
160
+ }
161
+ if (
162
+ (data.hasOwnProperty('published') && !data.published) ||
163
+ (data.hasOwnProperty('is_deleted') && data.is_deleted) &&
164
+ data.can_publish
165
+ ) {
166
+ form.find('button[name="publish"]').show();
167
+ if (form.data('hasPublished')) {
168
+ form.find('button[name="revert"]').show();
169
+ }
170
+ }
171
+ if (data.hasOwnProperty('is_deleted') && data.is_deleted) {
172
+ form.find('button[name="delete"]').hide();
173
+ form.find('button[name="save"]').hide();
174
+ } else if (data.hasOwnProperty('is_deleted')) {
175
+ form.find('button[name="delete"]').show();
176
+ }
177
+
178
+ slm.visitEditNavTree(form, new ErrorBadgeUpdater(form));
179
+ slm.visitEditNavTree(
180
+ form,
181
+ new StatusUpdater(
182
+ form,
183
+ data.published ? SiteLogStatus.PUBLISHED : SiteLogStatus.UPDATED
184
+ )
185
+ );
186
+ }
187
+
188
+ slm.handlePostErrors = function(form, jqXHR, status, text) {
189
+ if (jqXHR.hasOwnProperty('responseJSON')) {
190
+ const data = jqXHR.responseJSON;
191
+ if (Array.isArray(data)) {
192
+ for (const error of data) {
193
+ form.prepend(`<div class="alert alert-danger slm-form-fail"><strong>${error}</strong></div>`);
194
+ }
195
+ } else {
196
+ for (const [key, value] of Object.entries(data)) {
197
+ let errorElem = form.find(`#id_${key}-${form.attr('id').replace('site-', '')}`);
198
+ errorElem.addClass('is-invalid');
199
+ errorElem.after(`<div class="invalid-feedback">${value}</div>`);
200
+ }
201
+ }
202
+ } else if (jqXHR.hasOwnProperty('responseText')) {
203
+ form.prepend(`<div class="alert alert-danger slm-form-fail"><strong>${jqXHR.responseText}</strong></div>`);
204
+ } else {
205
+ alert('Unknown error!');
206
+ }
207
+ }
208
+
209
+ slm.resetFormErrorsAndWarnings = function(form) {
210
+ form.find('.is-invalid.slm-form-unpublished').removeClass('.slm-form-unpublished');
211
+ form.find('.is-invalid').removeClass('is-invalid');
212
+ form.find('.invalid-feedback').remove();
213
+ form.find('.slm-form-fail').remove();
214
+ form.find('.alert.slm-form-unpublished').hide();
215
+ form.find('.alert.slm-form-error').hide();
216
+ //form.find('button[name="publish"]').hide();
217
+ }
218
+
219
+ slm.initForm = function(form_id, initial=null, transform= function(data){ return data; }) {
220
+ const form = typeof form_id === 'string' || form_id instanceof String ? $(form_id) : form_id;
221
+ const form_api = form.data('slmApi');
222
+ const form_url = form.data('slmUrl');
223
+ if (form.data('slmFlags')) {
224
+ form.data(
225
+ 'slmErrorFlags',
226
+ JSON.parse(document.getElementById(form.data('slmFlags')).textContent)
227
+ );
228
+ } else {
229
+ form.data('slmErrorFlags', {});
230
+ }
231
+ if (initial) {
232
+ slm.setFormFields(form, initial);
233
+ }
234
+ const handleSubmit = function(action, btn) {
235
+ slm.resetFormErrorsAndWarnings(form);
236
+ let data = slm.formToObject(form);
237
+ const csrf = data.csrfmiddlewaretoken;
238
+ delete data.csrfmiddlewaretoken;
239
+ let request = null;
240
+ const dataId = data.id || form.data('slmId');
241
+ let finished = function() {};
242
+ let formBtn = form.closest('.accordion-item');
243
+ if (action === 'delete') {
244
+ formBtn.prevAll().find('span.section-number').each(
245
+ function(){
246
+ $(this).text(slm.incrSectionNumber($(this).text(), -1));
247
+ }
248
+ );
249
+ formBtn.find('span.section-number').remove();
250
+ if (!dataId) {
251
+ formBtn.remove();
252
+ return;
253
+ }
254
+ if (btn) {
255
+ finished = slm.processing(btn);
256
+ }
257
+ request = $.ajax({
258
+ url: form_url ? form_url : slm.urls.reverse(`${form_api}-detail`, {kwargs: {'pk': dataId}}),
259
+ method: 'DELETE',
260
+ headers: {'X-CSRFToken': csrf}
261
+ })
262
+ } else if (action === 'publish' || action === 'revert') {
263
+ let toPost = transform(data);
264
+ toPost[action] = true;
265
+ let options = {};
266
+ let endpoint = `${form_api}-list`;
267
+ let method = 'POST';
268
+ if (dataId) {
269
+ endpoint = `${form_api}-detail`;
270
+ options['pk'] = dataId;
271
+ method = 'PATCH';
272
+ }
273
+ if (btn) {
274
+ let btnFinished = slm.processing(btn);
275
+ finished = function() {
276
+ btn.hide();
277
+ btnFinished();
278
+ }
279
+ }
280
+ request = $.ajax({
281
+ url: form_url ? form_url : slm.urls.reverse(endpoint, {kwargs: options}),
282
+ method: method,
283
+ headers: {'X-CSRFToken': csrf},
284
+ data: toPost
285
+ });
286
+ } else {
287
+ if (btn) {
288
+ finished = slm.processing(btn);
289
+ }
290
+ request = $.ajax({
291
+ url: form_url ? form_url : slm.urls.reverse(`${form_api}-list`),
292
+ method: form.attr('data-slm-method') ? form.attr('data-slm-method') : 'POST',
293
+ headers: {'X-CSRFToken': csrf}, // todo still necessary?
294
+ data: JSON.stringify(transform(data)),
295
+ contentType: 'application/json; charset=utf-8',
296
+ dataType: 'json',
297
+ });
298
+ }
299
+
300
+ request.done(
301
+ function(data, status, jqXHR) {
302
+ if (action === 'revert') {
303
+ window.location.reload();
304
+ }
305
+ finished();
306
+ if (data) {
307
+ $.ajax({
308
+ url: slm.urls.reverse(
309
+ 'slm_edit_api:stations-detail',
310
+ {kwargs: {pk: data.site}}
311
+ )
312
+ }).done(function (site, status, jqXHR) {
313
+ slm.updateAlertBell(site);
314
+ });
315
+ }
316
+ if (action === 'publish') {
317
+ form.data('hasPublished', true);
318
+ }
319
+ slm.handlePostSuccess(form, data, status, jqXHR);
320
+ }
321
+ ).fail(
322
+ function(jqXHR, status, text) {
323
+ finished();
324
+ slm.handlePostErrors(form, jqXHR, status, text);
325
+ }
326
+ );
327
+ };
328
+ form.on('click', 'button[name="save"]', function() { handleSubmit('save', $(this)); });
329
+ form.on('click', 'button[name="delete"]', function() { handleSubmit('delete', $(this)); });
330
+ form.on('click', 'button[name="publish"]', function() { handleSubmit('publish', $(this)); });
331
+ form.on('click', 'button[name="revert"]', function() { handleSubmit('revert', $(this)); });
332
+ form.submit(function(event){ event.preventDefault(); handleSubmit(false);});
333
+
334
+ form.on('click', '.slm-flag-error', function() {
335
+ let field = $(this).closest('.slm-form-fieldset');
336
+ let inpt = field.find('.slm-flag-input');
337
+ let fieldInpt = field.find(`.slm-form-field[name="${$(field).data('slmField')}"]`);
338
+ if (inpt.is(":visible")) {
339
+ $(this).html('<i class="bi bi-flag"></i><i class="bi bi-flag-fill"></i>');
340
+ inpt.val('');
341
+ if (slm.isUnpublished(field)) {
342
+ fieldInpt.addClass('is-invalid');
343
+ fieldInpt.addClass('slm-form-unpublished');
344
+ } else {
345
+ fieldInpt.removeClass('is-invalid');
346
+ fieldInpt.removeClass('slm-form-unpublished');
347
+ }
348
+ inpt.hide();
349
+ slm.flagsUpdated(form);
350
+ } else {
351
+ $(this).html('<i class="bi bi-x-circle"></i><i class="bi bi-x-circle-fill"></i>');
352
+ fieldInpt.addClass('is-invalid');
353
+ fieldInpt.addClass('is-invalid');
354
+ fieldInpt.removeClass('slm-form-unpublished');
355
+ inpt.show();
356
+ inpt.focus();
357
+ }
358
+ });
359
+ form.find('.slm-flag-input').keypress(function(event) {
360
+ // de-focus on enter triggering update
361
+ if ((event.keyCode ? event.keyCode : event.which) === 13 ) {
362
+ $(this).blur();
363
+ }
364
+ });
365
+ form.on('blur', '.slm-flag-input', function() {
366
+ if (!$(this).val()) {
367
+ $(this).closest('.slm-form-field').find('.slm-flag-error').trigger('click');
368
+ } else {
369
+ slm.flagsUpdated(form);
370
+ }
371
+ });
372
+ slm.time24Init(form.find('fieldset.time-24hr'));
373
+ }
374
+
375
+ slm.extractFlags = function(form) {
376
+ const flags = {};
377
+ form.find('input.slm-flag-input').each(function() {
378
+ if ($(this).val()) {
379
+ flags[$(this).attr('data-slm-field')] = $(this).val();
380
+ }
381
+ });
382
+ return flags;
383
+ }
384
+
385
+ slm.setFormFlagUI = function(form) {
386
+ form.find('fieldset:visible').each(
387
+ function() {
388
+ let fieldInpt = $(this).find(`.slm-form-field[name="${$(this).data('slmField')}"]`);
389
+ if (form.data('slmErrorFlags').hasOwnProperty($(this).data('slmField'))) {
390
+ let flag = form.data('slmErrorFlags')[$(this).data('slmField')];
391
+ $(this).find('.slm-flag-error').html(
392
+ '<i class="bi bi-x-circle"></i><i class="bi bi-x-circle-fill"></i>'
393
+ );
394
+ let inpt = $(this).find('input.slm-flag-input');
395
+ inpt.val(flag);
396
+ inpt.show();
397
+ let err = $(this).find('div.slm-form-error');
398
+ err.html(flag);
399
+ err.show();
400
+ fieldInpt.addClass('is-invalid');
401
+ fieldInpt.removeClass('slm-form-unpublished');
402
+ } else {
403
+ $(this).find('.slm-flag-error').html(
404
+ '<i class="bi bi-flag"></i><i class="bi bi-flag-fill"></i>'
405
+ );
406
+ let inpt = $(this).find('input.slm-flag-input');
407
+ inpt.val('');
408
+ inpt.hide();
409
+ let err = $(this).find('div.slm-form-error');
410
+ err.html('');
411
+ err.hide();
412
+ if (slm.isUnpublished($(this))) {
413
+ fieldInpt.addClass('is-invalid');
414
+ fieldInpt.addClass('slm-form-unpublished');
415
+ } else {
416
+ fieldInpt.removeClass('is-invalid');
417
+ fieldInpt.removeClass('slm-form-unpublished');
418
+ }
419
+ }
420
+ }
421
+ );
422
+ slm.visitEditNavTree(form, new ErrorBadgeUpdater(form));
423
+ }
424
+
425
+ slm.visitEditNavTree = function(form, visitor) {
426
+ /* visit navigation ancestor buttons from the top up */
427
+ let node = $(form).closest('.accordion-item').find('button.slm-subsection');
428
+ if (!node.length) {
429
+ node = $(`button[data-slm-section="${form.data('slmSection')}"]`);
430
+ }
431
+ while (node.data('slmParent')) {
432
+ visitor.visit(node);
433
+ node = $(`button#${node.data('slmParent')}`);
434
+ }
435
+ visitor.visit(node);
436
+ }
437
+
438
+ slm.getNavSiblings = function(editNavButton) {
439
+ return $(`button[data-slm-parent="${editNavButton.data('slmParent')}"`);
440
+ }
441
+
442
+ slm.isUnpublished = function(fieldset) {
443
+ return fieldset.find('div.slm-form-unpublished').text().length > 0;
444
+ }
445
+
446
+ slm.flagsUpdated = function(form) {
447
+ let doUpdate = function() {
448
+ form.data('slmErrorFlags', newFlags);
449
+ const data = Object.fromEntries(new FormData(form.get(0)).entries());
450
+ const form_api = form.attr('data-slm-api');
451
+ const form_url = form.attr('data-slm-url');
452
+ const csrf = data.csrfmiddlewaretoken;
453
+ delete data.csrfmiddlewaretoken;
454
+ $.ajax({
455
+ url: form_url ? form_url : slm.urls.reverse(`${form_api}-detail`, {kwargs: {'pk': data.id}}),
456
+ method: 'PATCH',
457
+ headers: {'X-CSRFToken': csrf},
458
+ data: JSON.stringify({'_flags': form.data('slmErrorFlags')}),
459
+ contentType: "application/json"
460
+ }).fail(
461
+ function( jqXHR, status, errorTxt ) {
462
+ console.log(jqXHR);
463
+ alert(`Error setting flags: ${errorTxt}`);
464
+ }
465
+ ).done(function() { slm.setFormFlagUI(form); });
466
+ }
467
+ const newFlags = slm.extractFlags(form);
468
+ if (
469
+ Object.keys(newFlags).length !== Object.keys(form.data('slmErrorFlags')).length
470
+ ) {
471
+ doUpdate();
472
+ } else {
473
+ for (const [flag, val] of Object.entries(newFlags)) {
474
+ if (!form.data('slmErrorFlags').hasOwnProperty(flag) || form.data('slmErrorFlags')[flag] !== val) {
475
+ doUpdate();
476
+ }
477
+ }
478
+ }
479
+ }
480
+
481
+ slm.flipIcons = function(container) {
482
+ container.append(container.children('i').get().reverse());
483
+ }
484
+
485
+ slm.getName = function(user) {
486
+ if (user) {
487
+ if (user.first_name || user.last_name) {
488
+ return `${user.first_name} ${user.last_name}`;
489
+ }
490
+ return `${user.email}`;
491
+ }
492
+ return '';
493
+ }
494
+
495
+ slm.mailToUser = function(user) {
496
+ if (user) {
497
+ return `<a href="mailto:${user.email}">${slm.getName(user)}</a>`;
498
+ }
499
+ return '';
500
+ }
501
+
502
+ slm.initInfiniteScroll = function(div, scrollDiv, loader, api, kwargs, query, draw, cache=false) {
503
+ div = $(div);
504
+ scrollDiv = scrollDiv === null ? $(window) : scrollDiv;
505
+ const atBottom = $.isWindow(scrollDiv.get(0)) ? slm.windowAtBottom : slm.scrollAtBottom;
506
+ const position = div.find('> div').last();
507
+ if (loader === null) {
508
+ loader = position;
509
+ }
510
+ const drawPage = function(data) {
511
+ loader.hide();
512
+ if (data.next) {
513
+ scrollDiv.scroll(function() {
514
+ if (atBottom(scrollDiv.get(0))) {
515
+ fetchPage();
516
+ }
517
+ });
518
+ }
519
+ draw(
520
+ position,
521
+ data.hasOwnProperty('results') ?
522
+ data.results : data.hasOwnProperty('data') ?
523
+ data.data : data,
524
+ data.hasOwnProperty('recordsFiltered') ? data.recordsFiltered : null,
525
+ data.hasOwnProperty('recordsTotal') ? data.recordsTotal : null
526
+ );
527
+ div.data('slmPage', div.data('slmPage') + query.length);
528
+ };
529
+ const fetchPage = function() {
530
+ loader.show();
531
+ scrollDiv.off( 'scroll' );
532
+ query = Object.assign(
533
+ query,
534
+ Object.assign(
535
+ div.data('slmQuery') || {},
536
+ {
537
+ start: div.data('slmPage'),
538
+ length: div.data('slmPageSize')
539
+ }
540
+ )
541
+ );
542
+ const queryUrl = slm.urls.reverse(api, {kwargs: kwargs, query: query});
543
+ const cached = sessionStorage.getItem(queryUrl);
544
+ if (cached) {
545
+ drawPage(JSON.parse(cached));
546
+ } else {
547
+ $.ajax({url: queryUrl}).done(
548
+ (data) => {
549
+ if (cache) {
550
+ sessionStorage.setItem(queryUrl, JSON.stringify(data));
551
+ }
552
+ drawPage(data);
553
+ }
554
+ ).fail((jqXHR) => {
555
+ console.log(jqXHR);
556
+ });
557
+ }
558
+ }
559
+ fetchPage();
560
+ }
561
+
562
+ slm.scrollAtBottom = function(div) {
563
+ return div.offsetHeight + div.scrollTop >= div.scrollHeight;
564
+ }
565
+
566
+ slm.windowAtBottom = function() {
567
+ return (window.innerHeight + window.scrollY) >= document.body.scrollHeight
568
+ }
569
+
570
+ slm.initStationList = function(listId, station, searchId, stationTmpl) {
571
+ const stationList = $(listId);
572
+ const searchInput = $(searchId);
573
+ if (station) {
574
+ stationList.scrollTop(
575
+ document.getElementById(`select-${ station }`).offsetTop - stationList.before().position().top
576
+ );
577
+ }
578
+ slm.stationListOrig = null;
579
+ let keyupTimeoutID = 0;
580
+ searchInput.on('input', function() {
581
+ clearTimeout(keyupTimeoutID);
582
+ keyupTimeoutID = setTimeout(function() {
583
+ if (slm.stationListOrig === null) {
584
+ slm.stationListOrig = $('#station-list > button').detach();
585
+ }
586
+ if (searchInput.val()) {
587
+ $.ajax({
588
+ url: slm.urls.reverse('slm_edit_api:stations-list'),
589
+ method: 'GET',
590
+ data: {
591
+ name__icontains: searchInput.val()
592
+ }
593
+ }).done(
594
+ function (response) {
595
+ const stations = response.hasOwnProperty('results') ? response.results : response;
596
+ stationList.empty();
597
+ for (const station of stations) {
598
+ stationList.append(stationTmpl(station.name));
599
+ }
600
+ // TODO FIX THIS disgusting kludge to fix some css problems - nav pills are stretched,
601
+ // as if in justify-content stretch mode even though they arent, so we just add some hidden
602
+ // elements to make the spacing look right
603
+ let neededFiller = 100 - stations.length;
604
+ if (neededFiller > 0) {
605
+ for (var i = 0; i < neededFiller; i++) {
606
+ stationList.append('<button style="visibility: hidden">FILLER</button>');
607
+ }
608
+ }
609
+ }
610
+ )
611
+ } else {
612
+ stationList.empty();
613
+ stationList.append(slm.stationListOrig);
614
+ }
615
+ }, 500);
616
+ });
617
+ }
618
+
619
+
620
+ slm.showDiff = function(head, ancestor, display, mode='char') {
621
+ let dmp = new diff_match_patch();
622
+ dmp.Diff_EditCost = 4;
623
+ let lineArray = null;
624
+ if (mode !== 'char') {
625
+ let a = null;
626
+ if (mode === 'line') {
627
+ a = dmp.diff_linesToChars_(ancestor, head);
628
+ } else {
629
+ a = dmp.diff_linesToWords_(ancestor, head);
630
+ }
631
+ ancestor = a.chars1;
632
+ head = a.chars2;
633
+ lineArray = a.lineArray;
634
+ }
635
+ let diffs = dmp.diff_main(ancestor, head, mode === 'char');
636
+ dmp.diff_cleanupSemantic(diffs);
637
+ if (mode !== 'char') {
638
+ dmp.diff_charsToLines_(diffs, lineArray);
639
+ }
640
+ //dmp.diff_cleanupEfficiency(0);
641
+ //display.html(dmp.diff_prettyHtml(diffs));
642
+ display.html(`<div class="slm-diff-header"></div><span class="slm-review-lineno"> </span><span class="slm-review-line"></span><br/>${slm.prettyHtml(diffs)}<div class="slm-diff-footer"></div>`);
643
+ }
644
+
645
+ slm.setDateTimeWidget = function(widget, datetime, attr=null, length=16) {
646
+ let val = null;
647
+ if (datetime) {
648
+ datetime = new Date(datetime.getTime());
649
+ datetime.setMinutes(datetime.getMinutes() - datetime.getTimezoneOffset());
650
+ val = datetime.toISOString().slice(0, length);
651
+ }
652
+ if (attr !== null) {
653
+ widget.attr(attr, val);
654
+ } else {
655
+ widget.val(val);
656
+ }
657
+ }
658
+
659
+ slm.prettyHtml = function(diffs) {
660
+ let html = [];
661
+ let pattern_amp = /&/g;
662
+ let pattern_lt = /</g;
663
+ let pattern_gt = />/g;
664
+ let pattern_crlf = /\r/g;
665
+ let lineno = 0;
666
+ for (let x = 0; x < diffs.length; x++) {
667
+ let start = lineno;
668
+ let op = diffs[x][0]; // Operation (insert, delete, equal)
669
+ let data = diffs[x][1]; // Text of change.
670
+ let text = data.replace(pattern_amp, '&amp;').replace(pattern_lt, '&lt;').replace(pattern_gt, '&gt;').replace(pattern_crlf, '');
671
+ let lines = [];
672
+ for (const line of text.slice(0,text.length-1).split('\n')) {
673
+ lineno++;
674
+ lines.push(`<span class="slm-review-lineno">${lineno}</span><span class="slm-review-line">${line}</span>`);
675
+ }
676
+ text = lines.join('\n');
677
+ switch (op) {
678
+ case DIFF_INSERT:
679
+ html[x] = `<ins style="background:#e6ffe6;">${text}</ins><br/>`;
680
+ break;
681
+ case DIFF_DELETE:
682
+ html[x] = `<del style="background:#ffe6e6;">${text}</del><br/>`;
683
+ lineno = start;
684
+ break;
685
+ case DIFF_EQUAL:
686
+ html[x] = `<span class="slm-diff-equal">${text}</span><br/>`;
687
+ break;
688
+ }
689
+ }
690
+ return html.join('');
691
+ };
692
+
693
+
694
+ slm.addColumnFiltering = function( table) {
695
+ /**
696
+ * Add column filtering to our table's sub header row. The filtering selections are redone each time new data
697
+ * is fetched from ajax so the available values can be redone based on the other active filters. See filterableCols
698
+ * on the api data.
699
+ */
700
+ const value_map = { };
701
+ let api = table.api;
702
+ let id = table.id;
703
+
704
+ // do this each time we receive new data via ajax
705
+ table.api.on( 'xhr', function ( ) {
706
+ let data = api.ajax.json( ) ;
707
+ // add filtering drop downs - the strategy is to copy the header row and walk through the columns adding a drop
708
+ // down wherever a column is found in the filterableCols attribute on the data received from the server
709
+ let hdr_row = $( '#' + id + ' thead tr.filter_row' );
710
+ hdr_row.remove( );
711
+ if ( data.filterableCols ) {
712
+ $( '#' + id + ' thead tr' ).clone( true ).appendTo( '#' + id + ' thead' ).addClass( 'filter_row' );
713
+ $( '#' + id + ' thead tr:eq(1) th' ).each( function ( i ) {
714
+ let centered = $( this ).hasClass( 'dt-center' );
715
+ let col_name = $( this ).html( );
716
+ $( this ).html( '' );
717
+ $( this ).removeAttr( 'aria-controls' ).removeAttr( 'tabindex' ).removeAttr( 'class' );
718
+ $( this ).off( 'click' );
719
+ if ( col_name in data.filterableCols ) {
720
+ if ( centered ) {
721
+ $( this ).addClass( 'dt-center' );
722
+ }
723
+ $( this ).addClass( 'filter-column' );
724
+ let idx = data.filterableCols[col_name][0];
725
+ let selected = '';
726
+ if ( api.ajax.params( ).hasOwnProperty( idx ) ) {
727
+ selected = api.ajax.params( )[idx];
728
+ }
729
+ var title = $( this ).text( );
730
+ let html = '<select id=' + id + '__filter_col_' + idx + ' name=' + idx + ' placeholder="Filter ' + title + '">';
731
+ html += '<option ' + (selected === '' ? 'selected' : '') + ' value></option>';
732
+ if ( selected === 'false' ) {
733
+ selected = false;
734
+ }
735
+ else if ( selected === 'true' ) {
736
+ selected = true;
737
+ }
738
+ else if ( selected === 'null' ) {
739
+ selected = null;
740
+ }
741
+ data.filterableCols[col_name][1].forEach(function(value) {
742
+ let strValue = value;
743
+ if ( value !== null && Number.isFinite(value) ) strValue = value.toString( );
744
+ html += '<option ' + ( selected === strValue ? 'selected' : '' ) + ' value="' + value + '">' + (col_name in value_map ? value_map[col_name](value) : value) + '</option>'
745
+ });
746
+ html += '</select>'
747
+
748
+ $( this ).html(html);
749
+ $( 'select', this ).on( 'change', function ( ) {
750
+ api.ajax.reload( );
751
+ });
752
+ }
753
+ });
754
+
755
+ hdr_row.on( 'click', 'thead th', function ( e ) {
756
+ // make it so we dont trigger a reorder when we select dropdown
757
+ e.preventDefault( );
758
+ });
759
+ }
760
+ });
761
+ };
762
+
763
+
764
+ slm.dataTablesAdaptor = function( data, select=null ) {
765
+ /**
766
+ * Massage our datatables ajax query parameters into names understood by the server. See The base view class for
767
+ * any datatables enabled web api view.
768
+ */
769
+ select['draw'] = data.draw;
770
+ select['length'] = data.length;
771
+ select['order[0][column]'] = data.order[0]['column'];
772
+ select['order[0][dir]'] = data.order[0]['dir'];
773
+ select['search[value]'] = data.search['value'];
774
+ select['start'] = data.start;
775
+
776
+ let filter_row = $('#' + this.id + ' thead tr:eq(1) th');
777
+ if ( $(filter_row).length > 0 ) {
778
+ filter_row.each( function ( i ) {
779
+ if ($(this).hasClass('filter-column')) {
780
+ let val = $('select :selected', this).val();
781
+ if (val !== '') {
782
+ select[$('select', this).attr('name')] = val;
783
+ }
784
+ }
785
+ });
786
+ }
787
+ else if ( this.hasOwnProperty('colFilters') )
788
+ {
789
+ // if we dont have a dropdown row yet, we're at the pre first load stage - check to see
790
+ // if we have any column filters specified in the link and if so apply those so they're included
791
+ // in the initial data fetch
792
+ for ( const idx of Object.keys( this.colFilters ) ) {
793
+ if ( this.colFilters.hasOwnProperty( idx ) ) {
794
+ select[idx] = this.colFilters[idx];
795
+ }
796
+ }
797
+ }
798
+ }
799
+
800
+ slm.requestReview = function(siteId, detail='') {
801
+ return $.ajax({
802
+ url: slm.urls.reverse(
803
+ 'slm_edit_api:request_review-detail',
804
+ {kwargs: {pk: siteId}}
805
+ ),
806
+ method: 'PUT',
807
+ data: {detail: detail}
808
+ });
809
+ }
810
+
811
+ slm.rejectReview = function(siteId, detail='') {
812
+ return $.ajax({
813
+ url: slm.urls.reverse(
814
+ 'slm_edit_api:reject_updates-detail',
815
+ {kwargs: {pk: siteId}}
816
+ ),
817
+ method: 'PUT',
818
+ data: {detail: detail}
819
+ });
820
+ }
821
+
822
+ slm.publish = function(siteId) {
823
+ return $.ajax({
824
+ url: slm.urls.reverse('slm_edit_api:stations-detail', {kwargs: {'pk': siteId}}),
825
+ data: {'publish': true},
826
+ method: 'PATCH'
827
+ });
828
+ }
829
+
830
+ slm.revert = function(siteId) {
831
+ return $.ajax({
832
+ url: slm.urls.reverse('slm_edit_api:stations-detail', {kwargs: {'pk': siteId}}),
833
+ data: {'revert': true},
834
+ method: 'PATCH'
835
+ });
836
+ }
837
+
838
+ slm.rotateImage = function(degrees, fileId) {
839
+ return $.ajax({
840
+ url: slm.urls.reverse(
841
+ 'slm_edit_api:image-detail',
842
+ {kwargs: {'pk': fileId}, query: {'rotate': degrees}})
843
+ });
844
+ }
845
+
846
+ slm.deleteFile = function(station, fileId) {
847
+ return $.ajax({
848
+ url: slm.urls.reverse(
849
+ 'slm_edit_api:files-detail',
850
+ {kwargs: {'site': station, 'pk': fileId}}
851
+ ),
852
+ method: 'DELETE'
853
+ });
854
+ }
855
+
856
+ slm.publishFile = function(station, fileId, publish) {
857
+ return $.ajax({
858
+ url: slm.urls.reverse(
859
+ 'slm_edit_api:files-detail',
860
+ {kwargs: {'site': station, 'pk': fileId}}
861
+ ),
862
+ method: 'PATCH',
863
+ data: {
864
+ 'status': publish ?
865
+ slm.SiteFileUploadStatus.PUBLISHED.value :
866
+ slm.SiteFileUploadStatus.UNPUBLISHED.value
867
+ }
868
+ });
869
+ }
870
+
871
+ slm.updateFileBadges = function(delta) {
872
+ let filesBadge = $('span.slm-files-badge');
873
+ filesBadge.data(
874
+ 'slmFiles',
875
+ Math.max(0, filesBadge.data('slmFiles') + delta)
876
+ );
877
+ filesBadge.html(filesBadge.data('slmFiles'));
878
+ if (filesBadge.data('slmFiles') === 0) {
879
+ filesBadge.hide();
880
+ } else {
881
+ filesBadge.show();
882
+ }
883
+ }
884
+
885
+ slm.setFormFields = function(form, data) {
886
+ // todo swap this with Form class - its much more robust.
887
+ const toBool = function(value) {
888
+ if (value === 'off' || !value) {
889
+ return false;
890
+ }
891
+ return true;
892
+ }
893
+ for (const [field, value] of Object.entries(data)) {
894
+ const select = form.find(`select[name="${field}"]`);
895
+ select.find('option').prop('selected', false);
896
+ const multiCheck = form.find(`input:checkbox[name="${field}"]`);
897
+ if (select.length > 0) {
898
+ for (const val of Array.isArray(value) ? value : [value]) {
899
+ select.find(`option[value="${val}"]`).prop('selected', true);
900
+ }
901
+ } else if (multiCheck.length > 1) {
902
+ for (const val of Array.isArray(value) ? value : [value]) {
903
+ form.find(`input:checkbox[name="${field}"][value="${val}"]`).prop('checked', true);
904
+ }
905
+ } else {
906
+ form.find(`input[name="${field}"], textarea[name="${field}"]`).val(value);
907
+ form.find(`input:checkbox[name="${field}"]`).prop('checked', toBool(value));
908
+ }
909
+ }
910
+ }
911
+
912
+ slm.formToObject = function(form, fields=null) {
913
+ /**
914
+ * Why is it so hard to turn form data into json? FormData is very awkward
915
+ * to work with fields with multiple selections.
916
+ */
917
+ let formData = new FormData(form.get(0));
918
+ let data = {};
919
+ let multiples = new Set();
920
+ formData.forEach(function(value, key) {
921
+ if (fields && !fields.includes(key)) {
922
+ return;
923
+ }
924
+ let element = form.find(
925
+ `input[name="${key}"], textarea[name="${key}"], select[name="${key}"]`
926
+ );
927
+ if (element.length > 1 || element.get(0).hasAttribute( 'multiple' )) {
928
+ // special case for split date/times
929
+ if (element.length === 2 && element.get(0).getAttribute('type') === 'date') {
930
+ if (element.get(0).value) {
931
+ data[key] = `${element.get(0).value}T${element.get(1).value || "00:00"}Z`
932
+ }
933
+ } else {
934
+ data[key] = formData.getAll(key);
935
+ }
936
+ } else {
937
+ data[key] = value;
938
+ }
939
+ });
940
+ const checkboxes = new Set();
941
+ form.find('input:checkbox').each(function(idx, element) {
942
+ const name = element.getAttribute('name');
943
+ if (checkboxes.has(name)) {
944
+ multiples.add(name);
945
+ }
946
+ checkboxes.add(name);
947
+ });
948
+ let notMult = '';
949
+ for (const mult of multiples) {
950
+ notMult += `[name!="${mult}"]`;
951
+ }
952
+ form.find(`${notMult}:checkbox`).each(function(idx, element) {
953
+ data[element.getAttribute('name')] = $(element).prop('checked')
954
+ });
955
+ return data;
956
+ }
957
+
958
+ slm.stationFilterCallbacks = [];
959
+
960
+ slm.stationFilterChanged = function(filterParams) {
961
+ for (const callback of slm.stationFilterCallbacks) {
962
+ callback(filterParams);
963
+ }
964
+ }
965
+
966
+ slm.hasParameters = function(query, ignored=[]) {
967
+ for (const [key, value] of Object.entries(query)) {
968
+ if (
969
+ key === 'start' || key === 'length' || key === 'id' || ignored.includes(key)
970
+ ) { continue; }
971
+ if (Array.isArray(value)) {
972
+ if (value.length > 0) { return true; }
973
+ } else if (
974
+ value !== null &&
975
+ value !== '' &&
976
+ typeof value !== 'undefined'
977
+ ) { return true; }
978
+ }
979
+ return false;
980
+ }
981
+
982
+ slm.updateAlertBell = function(site) {
983
+ let level = site.max_alert ? AlertLevel.get(site.max_alert) : null;
984
+ let navBtn = $(`#select-${site.name}`);
985
+ let bells = $(
986
+ `#select-${site.name} .slm-alert-bell, #slm-station-nav .slm-alert-bell`
987
+ );
988
+ let current = AlertLevel.get(navBtn.data('slmAlert'));
989
+ bells.removeClass('bi-bell-fill');
990
+ bells.addClass('bi-bell');
991
+ navBtn.data('slmAlert', null);
992
+ if (current) {
993
+ bells.removeClass(`${current.css}`);
994
+ }
995
+ if (level) {
996
+ navBtn.data('slmAlert', level.value);
997
+ bells.addClass(`${level.css}`);
998
+ bells.removeClass('bi-bell');
999
+ bells.addClass('bi-bell-fill');
1000
+ bells.show();
1001
+ } else {
1002
+ $(`#select-${site.name} .slm-alert-bell`).hide();
1003
+ }
1004
+ }
1005
+
1006
+ slm.processing = function(btn) {
1007
+ btn.find('span.spinner-border').remove();
1008
+ $('body').css('cursor', 'progress');
1009
+ btn.append('<span class="ms-2 spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>');
1010
+ return function() {
1011
+ $('body').css('cursor', 'default');
1012
+ btn.find('span.spinner-border').remove();
1013
+ }
1014
+ }
1015
+
1016
+ slm.isIterable = function(input) {
1017
+ if (input === null || input === undefined) { return false; }
1018
+ return typeof input[Symbol.iterator] === 'function';
1019
+ }
1020
+
1021
+ slm.incrSectionNumber = function(versionString, incr=1) {
1022
+ if (versionString !== null && versionString !== '') {
1023
+ let numbers = versionString.split('.').map(Number);
1024
+ numbers[numbers.length - 1] += incr;
1025
+ return numbers.join('.');
1026
+ }
1027
+ return '';
1028
+ }