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.
- igs_slm-0.1.0b0.dist-info/LICENSE +21 -0
- igs_slm-0.1.0b0.dist-info/METADATA +151 -0
- igs_slm-0.1.0b0.dist-info/RECORD +447 -0
- igs_slm-0.1.0b0.dist-info/WHEEL +4 -0
- igs_slm-0.1.0b0.dist-info/entry_points.txt +3 -0
- igs_tools/__init__.py +0 -0
- igs_tools/connection.py +88 -0
- igs_tools/defines/__init__.py +8 -0
- igs_tools/defines/constellation.py +21 -0
- igs_tools/defines/data_center.py +75 -0
- igs_tools/defines/rinex.py +49 -0
- igs_tools/directory.py +247 -0
- igs_tools/utils.py +66 -0
- slm/__init__.py +21 -0
- slm/admin.py +674 -0
- slm/api/edit/__init__.py +0 -0
- slm/api/edit/serializers.py +316 -0
- slm/api/edit/views.py +1632 -0
- slm/api/fields.py +89 -0
- slm/api/filter.py +504 -0
- slm/api/pagination.py +55 -0
- slm/api/permissions.py +65 -0
- slm/api/public/__init__.py +0 -0
- slm/api/public/serializers.py +249 -0
- slm/api/public/views.py +606 -0
- slm/api/serializers.py +132 -0
- slm/api/views.py +148 -0
- slm/apps.py +323 -0
- slm/authentication.py +198 -0
- slm/bin/__init__.py +0 -0
- slm/bin/startproject.py +262 -0
- slm/bin/templates/{{ project_dir }}/pyproject.toml +35 -0
- slm/bin/templates/{{ project_dir }}/sites/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/base.py +15 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/develop/__init__.py +56 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/develop/local.py +4 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/develop/wsgi.py +16 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/manage.py +34 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/production/__init__.py +61 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/production/wsgi.py +16 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/urls.py +7 -0
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/validation.py +11 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/admin.py +5 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/apps.py +14 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/management/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/management/commands/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/management/commands/import_archive.py +64 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/migrations/__init__.py +0 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/models.py +6 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/templates/slm/base.html +8 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/urls.py +10 -0
- slm/bin/templates/{{ project_dir }}/{{ extension_app }}/views.py +5 -0
- slm/defines/AlertLevel.py +24 -0
- slm/defines/AntennaCalibration.py +25 -0
- slm/defines/AntennaFeatures.py +27 -0
- slm/defines/AntennaReferencePoint.py +22 -0
- slm/defines/Aspiration.py +13 -0
- slm/defines/CardinalDirection.py +19 -0
- slm/defines/CollocationStatus.py +12 -0
- slm/defines/EquipmentState.py +22 -0
- slm/defines/FlagSeverity.py +14 -0
- slm/defines/FractureSpacing.py +15 -0
- slm/defines/FrequencyStandardType.py +15 -0
- slm/defines/GeodesyMLVersion.py +48 -0
- slm/defines/ISOCountry.py +1194 -0
- slm/defines/Instrumentation.py +19 -0
- slm/defines/LogEntryType.py +30 -0
- slm/defines/SLMFileType.py +18 -0
- slm/defines/SiteFileUploadStatus.py +61 -0
- slm/defines/SiteLogFormat.py +49 -0
- slm/defines/SiteLogStatus.py +78 -0
- slm/defines/TectonicPlates.py +28 -0
- slm/defines/__init__.py +46 -0
- slm/forms.py +1126 -0
- slm/jinja2/slm/sitelog/ascii_9char.log +346 -0
- slm/jinja2/slm/sitelog/legacy.log +346 -0
- slm/jinja2/slm/sitelog/xsd/0.4/collocationInformation.xml +12 -0
- slm/jinja2/slm/sitelog/xsd/0.4/condition.xml +12 -0
- slm/jinja2/slm/sitelog/xsd/0.4/contact.xml +52 -0
- slm/jinja2/slm/sitelog/xsd/0.4/formInformation.xml +5 -0
- slm/jinja2/slm/sitelog/xsd/0.4/frequencyStandard.xml +12 -0
- slm/jinja2/slm/sitelog/xsd/0.4/gnssAntenna.xml +16 -0
- slm/jinja2/slm/sitelog/xsd/0.4/gnssReceiver.xml +11 -0
- slm/jinja2/slm/sitelog/xsd/0.4/humiditySensor.xml +13 -0
- slm/jinja2/slm/sitelog/xsd/0.4/localEpisodicEffect.xml +10 -0
- slm/jinja2/slm/sitelog/xsd/0.4/moreInformation.xml +22 -0
- slm/jinja2/slm/sitelog/xsd/0.4/multipathSource.xml +10 -0
- slm/jinja2/slm/sitelog/xsd/0.4/otherInstrumentation.xml +5 -0
- slm/jinja2/slm/sitelog/xsd/0.4/pressureSensor.xml +12 -0
- slm/jinja2/slm/sitelog/xsd/0.4/radioInterference.xml +11 -0
- slm/jinja2/slm/sitelog/xsd/0.4/sensor.xml +16 -0
- slm/jinja2/slm/sitelog/xsd/0.4/signalObstruction.xml +10 -0
- slm/jinja2/slm/sitelog/xsd/0.4/siteIdentification.xml +22 -0
- slm/jinja2/slm/sitelog/xsd/0.4/siteLocation.xml +21 -0
- slm/jinja2/slm/sitelog/xsd/0.4/surveyedLocalTie.xml +20 -0
- slm/jinja2/slm/sitelog/xsd/0.4/temperatureSensor.xml +13 -0
- slm/jinja2/slm/sitelog/xsd/0.4/waterVaporSensor.xml +11 -0
- slm/jinja2/slm/sitelog/xsd/0.5/document.xml +10 -0
- slm/jinja2/slm/sitelog/xsd/geodesyml_0.4.xml +99 -0
- slm/jinja2/slm/sitelog/xsd/geodesyml_0.5.xml +112 -0
- slm/management/__init__.py +0 -0
- slm/management/commands/__init__.py +53 -0
- slm/management/commands/build_index.py +96 -0
- slm/management/commands/generate_sinex.py +675 -0
- slm/management/commands/head_from_index.py +541 -0
- slm/management/commands/import_archive.py +908 -0
- slm/management/commands/import_equipment.py +351 -0
- slm/management/commands/set_site.py +56 -0
- slm/management/commands/sitelog.py +144 -0
- slm/management/commands/synchronize.py +60 -0
- slm/management/commands/update_data_availability.py +167 -0
- slm/management/commands/validate_db.py +186 -0
- slm/management/commands/validate_gml.py +73 -0
- slm/map/__init__.py +1 -0
- slm/map/admin.py +5 -0
- slm/map/api/__init__.py +0 -0
- slm/map/api/edit/__init__.py +0 -0
- slm/map/api/edit/serializers.py +28 -0
- slm/map/api/edit/views.py +46 -0
- slm/map/api/public/__init__.py +0 -0
- slm/map/api/public/serializers.py +29 -0
- slm/map/api/public/views.py +64 -0
- slm/map/apps.py +7 -0
- slm/map/defines.py +53 -0
- slm/map/migrations/0001_initial.py +115 -0
- slm/map/migrations/__init__.py +0 -0
- slm/map/models.py +63 -0
- slm/map/static/slm/css/map.css +86 -0
- slm/map/static/slm/js/map.js +159 -0
- slm/map/templates/slm/map.html +374 -0
- slm/map/templates/slm/station/base.html +11 -0
- slm/map/templates/slm/station/edit.html +10 -0
- slm/map/templates/slm/top_nav.html +17 -0
- slm/map/templatetags/__init__.py +0 -0
- slm/map/templatetags/slm_map.py +18 -0
- slm/map/urls.py +25 -0
- slm/map/views.py +36 -0
- slm/middleware.py +29 -0
- slm/migrations/0001_alter_siteantenna_marker_enu_alter_sitelocation_llh_and_more.py +47 -0
- slm/migrations/0001_initial.py +4826 -0
- slm/migrations/0002_alter_dataavailability_site.py +22 -0
- slm/migrations/0003_remove_logentry_slm_logentr_site_lo_7a2af7_idx_and_more.py +80 -0
- slm/migrations/0004_alter_logentry_timestamp_and_more.py +25 -0
- slm/migrations/0005_alter_logentry_options_alter_logentry_section_and_more.py +46 -0
- slm/migrations/0006_alter_logentry_options_alter_logentry_index_together.py +24 -0
- slm/migrations/0007_alter_dataavailability_rate.py +23 -0
- slm/migrations/0008_alter_archiveindex_options_and_more.py +64 -0
- slm/migrations/0009_alter_archiveindex_end.py +21 -0
- slm/migrations/0010_alter_dataavailability_rinex_version_and_more.py +844 -0
- slm/migrations/0011_alter_siteidentification_fracture_spacing.py +33 -0
- slm/migrations/0012_alter_logentry_type.py +36 -0
- slm/migrations/0013_unpublishedfilesalert.py +48 -0
- slm/migrations/0014_sitelogpublished.py +48 -0
- slm/migrations/0015_alter_siteantenna_options_and_more.py +181 -0
- slm/migrations/0016_alter_antenna_description_alter_radome_description_and_more.py +42 -0
- slm/migrations/0017_alter_logentry_unique_together_and_more.py +54 -0
- slm/migrations/0018_afix_deleted.py +34 -0
- slm/migrations/0018_alter_siteantenna_options_and_more.py +244 -0
- slm/migrations/0019_remove_siteantenna_marker_enu_siteantenna_marker_une_and_more.py +101 -0
- slm/migrations/0020_alter_manufacturer_options.py +16 -0
- slm/migrations/0021_alter_siteform_report_type.py +23 -0
- slm/migrations/0022_rename_antcal_antenna_radome_slm_antcal_antenna_20827a_idx_and_more.py +297 -0
- slm/migrations/0023_archivedsitelog_gml_version_and_more.py +55 -0
- slm/migrations/0024_alter_agency_name_alter_agency_shortname.py +24 -0
- slm/migrations/0025_alter_archivedsitelog_log_format_and_more.py +61 -0
- slm/migrations/0026_alter_archivedsitelog_log_format_and_more.py +61 -0
- slm/migrations/0027_importalert_file_contents_importalert_findings_and_more.py +41 -0
- slm/migrations/0028_antenna_replaced_manufacturer_url_radome_replaced_and_more.py +46 -0
- slm/migrations/0029_manufacturer_full_name.py +17 -0
- slm/migrations/0030_alter_antenna_state_alter_radome_state_and_more.py +43 -0
- slm/migrations/__init__.py +0 -0
- slm/migrations/load_satellitesystems.py +27 -0
- slm/models/__init__.py +118 -0
- slm/models/about.py +14 -0
- slm/models/alerts.py +1204 -0
- slm/models/data.py +58 -0
- slm/models/equipment.py +229 -0
- slm/models/help.py +14 -0
- slm/models/index.py +428 -0
- slm/models/sitelog.py +4279 -0
- slm/models/system.py +723 -0
- slm/models/user.py +304 -0
- slm/parsing/__init__.py +786 -0
- slm/parsing/legacy/__init__.py +4 -0
- slm/parsing/legacy/binding.py +817 -0
- slm/parsing/legacy/parser.py +377 -0
- slm/parsing/xsd/__init__.py +34 -0
- slm/parsing/xsd/binding.py +86 -0
- slm/parsing/xsd/geodesyml/0.4/commonTypes.xsd +133 -0
- slm/parsing/xsd/geodesyml/0.4/contact.xsd +29 -0
- slm/parsing/xsd/geodesyml/0.4/dataStreams.xsd +129 -0
- slm/parsing/xsd/geodesyml/0.4/document.xsd +64 -0
- slm/parsing/xsd/geodesyml/0.4/equipment.xsd +427 -0
- slm/parsing/xsd/geodesyml/0.4/fieldMeasurement.xsd +170 -0
- slm/parsing/xsd/geodesyml/0.4/geodesyML.xsd +71 -0
- slm/parsing/xsd/geodesyml/0.4/geodeticEquipment.xsd +343 -0
- slm/parsing/xsd/geodesyml/0.4/geodeticMonument.xsd +147 -0
- slm/parsing/xsd/geodesyml/0.4/lineage.xsd +614 -0
- slm/parsing/xsd/geodesyml/0.4/localInterferences.xsd +131 -0
- slm/parsing/xsd/geodesyml/0.4/measurement.xsd +473 -0
- slm/parsing/xsd/geodesyml/0.4/monumentInfo.xsd +251 -0
- slm/parsing/xsd/geodesyml/0.4/observationSystem.xsd +429 -0
- slm/parsing/xsd/geodesyml/0.4/project.xsd +38 -0
- slm/parsing/xsd/geodesyml/0.4/quality.xsd +176 -0
- slm/parsing/xsd/geodesyml/0.4/referenceFrame.xsd +194 -0
- slm/parsing/xsd/geodesyml/0.4/siteLog.xsd +71 -0
- slm/parsing/xsd/geodesyml/0.5/commonTypes.xsd +133 -0
- slm/parsing/xsd/geodesyml/0.5/contact.xsd +29 -0
- slm/parsing/xsd/geodesyml/0.5/dataStreams.xsd +129 -0
- slm/parsing/xsd/geodesyml/0.5/document.xsd +64 -0
- slm/parsing/xsd/geodesyml/0.5/equipment.xsd +427 -0
- slm/parsing/xsd/geodesyml/0.5/fieldMeasurement.xsd +170 -0
- slm/parsing/xsd/geodesyml/0.5/geodesyML.xsd +71 -0
- slm/parsing/xsd/geodesyml/0.5/geodeticEquipment.xsd +343 -0
- slm/parsing/xsd/geodesyml/0.5/geodeticMonument.xsd +147 -0
- slm/parsing/xsd/geodesyml/0.5/lineage.xsd +614 -0
- slm/parsing/xsd/geodesyml/0.5/localInterferences.xsd +131 -0
- slm/parsing/xsd/geodesyml/0.5/measurement.xsd +473 -0
- slm/parsing/xsd/geodesyml/0.5/monumentInfo.xsd +306 -0
- slm/parsing/xsd/geodesyml/0.5/observationSystem.xsd +429 -0
- slm/parsing/xsd/geodesyml/0.5/project.xsd +38 -0
- slm/parsing/xsd/geodesyml/0.5/quality.xsd +176 -0
- slm/parsing/xsd/geodesyml/0.5/referenceFrame.xsd +194 -0
- slm/parsing/xsd/geodesyml/0.5/siteLog.xsd +73 -0
- slm/parsing/xsd/parser.py +116 -0
- slm/parsing/xsd/resolver.py +28 -0
- slm/receivers/__init__.py +11 -0
- slm/receivers/alerts.py +87 -0
- slm/receivers/cleanup.py +41 -0
- slm/receivers/event_loggers.py +175 -0
- slm/receivers/index.py +67 -0
- slm/settings/__init__.py +55 -0
- slm/settings/auth.py +15 -0
- slm/settings/ckeditor.py +14 -0
- slm/settings/debug.py +47 -0
- slm/settings/internationalization.py +12 -0
- slm/settings/logging.py +113 -0
- slm/settings/platform/__init__.py +0 -0
- slm/settings/platform/darwin.py +10 -0
- slm/settings/rest.py +21 -0
- slm/settings/root.py +152 -0
- slm/settings/routines.py +43 -0
- slm/settings/secrets.py +37 -0
- slm/settings/security.py +5 -0
- slm/settings/slm.py +188 -0
- slm/settings/static_templates.py +53 -0
- slm/settings/templates.py +29 -0
- slm/settings/uploads.py +8 -0
- slm/settings/urls.py +126 -0
- slm/settings/validation.py +196 -0
- slm/signals.py +250 -0
- slm/singleton.py +49 -0
- slm/static/rest_framework/css/bootstrap-tweaks.css +204 -0
- slm/static/rest_framework/css/bootstrap.min.css +7 -0
- slm/static/rest_framework/css/bootstrap.min.css.map +1 -0
- slm/static/rest_framework/css/default.css +82 -0
- slm/static/rest_framework/css/prettify.css +30 -0
- slm/static/rest_framework/docs/css/base.css +344 -0
- slm/static/rest_framework/docs/css/highlight.css +125 -0
- slm/static/rest_framework/docs/css/jquery.json-view.min.css +11 -0
- slm/static/rest_framework/docs/img/favicon.ico +0 -0
- slm/static/rest_framework/docs/img/grid.png +0 -0
- slm/static/rest_framework/docs/js/api.js +321 -0
- slm/static/rest_framework/docs/js/highlight.pack.js +2 -0
- slm/static/rest_framework/docs/js/jquery.json-view.min.js +7 -0
- slm/static/rest_framework/img/grid.png +0 -0
- slm/static/rest_framework/js/ajax-form.js +127 -0
- slm/static/rest_framework/js/bootstrap.bundle.min.js +7 -0
- slm/static/rest_framework/js/bootstrap.bundle.min.js.map +1 -0
- slm/static/rest_framework/js/bootstrap.min.js.map +1 -0
- slm/static/rest_framework/js/coreapi-0.1.1.js +2043 -0
- slm/static/rest_framework/js/csrf.js +52 -0
- slm/static/rest_framework/js/default.js +47 -0
- slm/static/rest_framework/js/jquery-3.5.1.min.js +2 -0
- slm/static/rest_framework/js/prettify-min.js +28 -0
- slm/static/slm/css/admin.css +3 -0
- slm/static/slm/css/defines.css +82 -0
- slm/static/slm/css/forms.css +1 -0
- slm/static/slm/css/style.css +1004 -0
- slm/static/slm/img/email-branding.png +0 -0
- slm/static/slm/img/favicon.ico +0 -0
- slm/static/slm/img/login-bg.jpg +0 -0
- slm/static/slm/img/slm-logo.svg +4 -0
- slm/static/slm/js/autocomplete.js +341 -0
- slm/static/slm/js/enums.js +322 -0
- slm/static/slm/js/fileIcons.js +30 -0
- slm/static/slm/js/form.js +404 -0
- slm/static/slm/js/formWidget.js +23 -0
- slm/static/slm/js/persistable.js +33 -0
- slm/static/slm/js/slm.js +1028 -0
- slm/static/slm/js/time24.js +212 -0
- slm/static_templates/slm/css/defines.css +26 -0
- slm/static_templates/slm/js/enums.js +28 -0
- slm/static_templates/slm/js/fileIcons.js +16 -0
- slm/static_templates/slm/js/urls.js +5 -0
- slm/templates/account/base.html +20 -0
- slm/templates/account/email/base.html +43 -0
- slm/templates/account/email/base_message.txt +7 -0
- slm/templates/account/email/email_confirmation_message.html +16 -0
- slm/templates/account/email/email_confirmation_message.txt +7 -0
- slm/templates/account/email/email_confirmation_signup_message.html +1 -0
- slm/templates/account/email/email_confirmation_signup_message.txt +1 -0
- slm/templates/account/email/email_confirmation_signup_subject.txt +1 -0
- slm/templates/account/email/email_confirmation_subject.txt +4 -0
- slm/templates/account/email/password_reset_key_message.html +28 -0
- slm/templates/account/email/password_reset_key_message.txt +9 -0
- slm/templates/account/email/password_reset_key_subject.txt +4 -0
- slm/templates/account/email/unknown_account_message.html +25 -0
- slm/templates/account/email/unknown_account_message.txt +12 -0
- slm/templates/account/email/unknown_account_subject.txt +4 -0
- slm/templates/account/login.html +67 -0
- slm/templates/account/logout.html +38 -0
- slm/templates/account/password_change.html +48 -0
- slm/templates/account/password_reset.html +51 -0
- slm/templates/account/password_reset_done.html +20 -0
- slm/templates/account/password_reset_from_key.html +52 -0
- slm/templates/account/password_reset_from_key_done.html +17 -0
- slm/templates/admin/base.html +7 -0
- slm/templates/messages.html +8 -0
- slm/templates/rest_framework/README +16 -0
- slm/templates/rest_framework/admin/detail.html +10 -0
- slm/templates/rest_framework/admin/dict_value.html +11 -0
- slm/templates/rest_framework/admin/list.html +32 -0
- slm/templates/rest_framework/admin/list_value.html +11 -0
- slm/templates/rest_framework/admin/simple_list_value.html +2 -0
- slm/templates/rest_framework/admin.html +282 -0
- slm/templates/rest_framework/api.html +3 -0
- slm/templates/rest_framework/base.html +334 -0
- slm/templates/rest_framework/docs/auth/basic.html +42 -0
- slm/templates/rest_framework/docs/auth/session.html +40 -0
- slm/templates/rest_framework/docs/auth/token.html +41 -0
- slm/templates/rest_framework/docs/document.html +37 -0
- slm/templates/rest_framework/docs/error.html +71 -0
- slm/templates/rest_framework/docs/index.html +55 -0
- slm/templates/rest_framework/docs/interact.html +57 -0
- slm/templates/rest_framework/docs/langs/javascript-intro.html +5 -0
- slm/templates/rest_framework/docs/langs/javascript.html +15 -0
- slm/templates/rest_framework/docs/langs/python-intro.html +3 -0
- slm/templates/rest_framework/docs/langs/python.html +13 -0
- slm/templates/rest_framework/docs/langs/shell-intro.html +3 -0
- slm/templates/rest_framework/docs/langs/shell.html +6 -0
- slm/templates/rest_framework/docs/link.html +113 -0
- slm/templates/rest_framework/docs/sidebar.html +78 -0
- slm/templates/rest_framework/filters/base.html +16 -0
- slm/templates/rest_framework/filters/ordering.html +17 -0
- slm/templates/rest_framework/filters/search.html +13 -0
- slm/templates/rest_framework/horizontal/checkbox.html +23 -0
- slm/templates/rest_framework/horizontal/checkbox_multiple.html +32 -0
- slm/templates/rest_framework/horizontal/dict_field.html +11 -0
- slm/templates/rest_framework/horizontal/fieldset.html +16 -0
- slm/templates/rest_framework/horizontal/form.html +6 -0
- slm/templates/rest_framework/horizontal/input.html +21 -0
- slm/templates/rest_framework/horizontal/list_field.html +11 -0
- slm/templates/rest_framework/horizontal/list_fieldset.html +13 -0
- slm/templates/rest_framework/horizontal/radio.html +42 -0
- slm/templates/rest_framework/horizontal/select.html +36 -0
- slm/templates/rest_framework/horizontal/select_multiple.html +38 -0
- slm/templates/rest_framework/horizontal/textarea.html +21 -0
- slm/templates/rest_framework/inline/checkbox.html +8 -0
- slm/templates/rest_framework/inline/checkbox_multiple.html +14 -0
- slm/templates/rest_framework/inline/dict_field.html +9 -0
- slm/templates/rest_framework/inline/fieldset.html +6 -0
- slm/templates/rest_framework/inline/form.html +8 -0
- slm/templates/rest_framework/inline/input.html +9 -0
- slm/templates/rest_framework/inline/list_field.html +9 -0
- slm/templates/rest_framework/inline/list_fieldset.html +3 -0
- slm/templates/rest_framework/inline/radio.html +25 -0
- slm/templates/rest_framework/inline/select.html +24 -0
- slm/templates/rest_framework/inline/select_multiple.html +25 -0
- slm/templates/rest_framework/inline/textarea.html +9 -0
- slm/templates/rest_framework/login.html +3 -0
- slm/templates/rest_framework/login_base.html +65 -0
- slm/templates/rest_framework/pagination/numbers.html +47 -0
- slm/templates/rest_framework/pagination/previous_and_next.html +21 -0
- slm/templates/rest_framework/raw_data_form.html +11 -0
- slm/templates/rest_framework/schema.js +3 -0
- slm/templates/rest_framework/vertical/checkbox.html +16 -0
- slm/templates/rest_framework/vertical/checkbox_multiple.html +30 -0
- slm/templates/rest_framework/vertical/dict_field.html +7 -0
- slm/templates/rest_framework/vertical/fieldset.html +13 -0
- slm/templates/rest_framework/vertical/form.html +6 -0
- slm/templates/rest_framework/vertical/input.html +17 -0
- slm/templates/rest_framework/vertical/list_field.html +7 -0
- slm/templates/rest_framework/vertical/list_fieldset.html +7 -0
- slm/templates/rest_framework/vertical/radio.html +40 -0
- slm/templates/rest_framework/vertical/select.html +34 -0
- slm/templates/rest_framework/vertical/select_multiple.html +31 -0
- slm/templates/rest_framework/vertical/textarea.html +17 -0
- slm/templates/slm/about.html +21 -0
- slm/templates/slm/alerts/alert.html +15 -0
- slm/templates/slm/alerts/geodesymlinvalid.html +8 -0
- slm/templates/slm/alerts/importalert.html +10 -0
- slm/templates/slm/alerts.html +18 -0
- slm/templates/slm/auth_menu.html +41 -0
- slm/templates/slm/base.html +195 -0
- slm/templates/slm/emails/alert_issued.html +31 -0
- slm/templates/slm/emails/alert_issued.txt +9 -0
- slm/templates/slm/emails/base.html +6 -0
- slm/templates/slm/emails/changes_rejected.txt +7 -0
- slm/templates/slm/emails/review_requested.txt +7 -0
- slm/templates/slm/forms/widgets/auto_complete.html +21 -0
- slm/templates/slm/forms/widgets/auto_complete_multiple.html +18 -0
- slm/templates/slm/forms/widgets/checkbox_multiple.html +6 -0
- slm/templates/slm/forms/widgets/inline_multi.html +1 -0
- slm/templates/slm/forms/widgets/splitdatetime.html +14 -0
- slm/templates/slm/forms/widgets/time24.html +37 -0
- slm/templates/slm/help.html +54 -0
- slm/templates/slm/messages.html +13 -0
- slm/templates/slm/new_site.html +88 -0
- slm/templates/slm/profile.html +57 -0
- slm/templates/slm/register.html +40 -0
- slm/templates/slm/reports/file_log.html +43 -0
- slm/templates/slm/reports/head_log.html +23 -0
- slm/templates/slm/reports/head_report.html +55 -0
- slm/templates/slm/reports/index_log.html +23 -0
- slm/templates/slm/reports/index_report.html +71 -0
- slm/templates/slm/station/alert.html +8 -0
- slm/templates/slm/station/alerts.html +19 -0
- slm/templates/slm/station/base.html +104 -0
- slm/templates/slm/station/download.html +87 -0
- slm/templates/slm/station/edit.html +283 -0
- slm/templates/slm/station/form.html +110 -0
- slm/templates/slm/station/log.html +18 -0
- slm/templates/slm/station/review.html +461 -0
- slm/templates/slm/station/upload.html +295 -0
- slm/templates/slm/station/uploads/attachment.html +20 -0
- slm/templates/slm/station/uploads/geodesyml.html +1 -0
- slm/templates/slm/station/uploads/image.html +27 -0
- slm/templates/slm/station/uploads/json.html +0 -0
- slm/templates/slm/station/uploads/legacy.html +77 -0
- slm/templates/slm/top_nav.html +14 -0
- slm/templates/slm/user_activity.html +16 -0
- slm/templates/slm/widgets/alert_scroll.html +135 -0
- slm/templates/slm/widgets/filelist.html +258 -0
- slm/templates/slm/widgets/legend.html +12 -0
- slm/templates/slm/widgets/log_scroll.html +88 -0
- slm/templates/slm/widgets/stationlist.html +233 -0
- slm/templatetags/__init__.py +0 -0
- slm/templatetags/jinja2.py +9 -0
- slm/templatetags/slm.py +459 -0
- slm/urls.py +148 -0
- slm/utils.py +299 -0
- slm/validators.py +297 -0
- slm/views.py +654 -0
- slm/widgets.py +134 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Station equipment including Antennas, Radomes and Receivers are coded by IGS and
|
|
3
|
+
those standard codes are used to uniquely identify equipment in site log files.
|
|
4
|
+
|
|
5
|
+
The full IGS changelog for equipment codes is recorded in rcvr_ant.tab_.
|
|
6
|
+
|
|
7
|
+
The SLM stores these codes in database tables, so it is possible to instantiate an
|
|
8
|
+
SLM with a different set of equipment codes. This command can be used to load codes
|
|
9
|
+
from another SLM or from the IGS by default:
|
|
10
|
+
|
|
11
|
+
* **antennas**: https://network.igs.org/api/public/antenna/
|
|
12
|
+
* **receivers**: https://network.igs.org/api/public/receiver/
|
|
13
|
+
* **radomes**: https://network.igs.org/api/public/radome/
|
|
14
|
+
* **manufacturers**: https://network.igs.org/api/public/manufacturer/
|
|
15
|
+
|
|
16
|
+
.. tip::
|
|
17
|
+
|
|
18
|
+
**import_equipment** can be run routinely to synchronize with upstream equipment
|
|
19
|
+
sources. No equipment will be removed if any site logs reference it in the database.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import typing as t
|
|
23
|
+
|
|
24
|
+
import requests
|
|
25
|
+
from django.db.models import Q
|
|
26
|
+
from django.utils.translation import gettext as _
|
|
27
|
+
from django_typer.completers import these_strings
|
|
28
|
+
from django_typer.management import TyperCommand, command, initialize
|
|
29
|
+
from typer import Context, Option
|
|
30
|
+
from typing_extensions import Annotated
|
|
31
|
+
|
|
32
|
+
from slm.defines import EquipmentState
|
|
33
|
+
from slm.models.equipment import Antenna, Manufacturer, Radome, Receiver
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Command(TyperCommand, rich_markup_mode="markdown", chain=True):
|
|
37
|
+
help = _(
|
|
38
|
+
"Import equipment (Antennas, Receivers and Radomes). Imports are made from "
|
|
39
|
+
"the IGS public network API by default. You may periodically run this to "
|
|
40
|
+
"synchronize with external equipment sources. These codings are used to "
|
|
41
|
+
"standardize references to equipment in site logs. For a full change log of "
|
|
42
|
+
"equipment encodings used by IGS, see: "
|
|
43
|
+
"https://files.igs.org/pub/station/general/rcvr_ant.tab"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
suppressed_base_arguments = {
|
|
47
|
+
*TyperCommand.suppressed_base_arguments,
|
|
48
|
+
"version",
|
|
49
|
+
"pythonpath",
|
|
50
|
+
"settings"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
remove: bool = False
|
|
54
|
+
synchronize: bool = True
|
|
55
|
+
slm: t.Optional[str] = None
|
|
56
|
+
states: t.List[t.Union[str, EquipmentState]] = [EquipmentState.ACTIVE.name]
|
|
57
|
+
|
|
58
|
+
manufacturers: t.Set[Manufacturer]
|
|
59
|
+
manufacturers_added: t.Set[Manufacturer]
|
|
60
|
+
|
|
61
|
+
antennas: t.Set[Antenna]
|
|
62
|
+
antennas_added: t.Set[Antenna]
|
|
63
|
+
|
|
64
|
+
receivers: t.Set[Receiver]
|
|
65
|
+
receivers_added: t.Set[Receiver]
|
|
66
|
+
|
|
67
|
+
radomes: t.Set[Radome]
|
|
68
|
+
radomes_added: t.Set[Radome]
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def params(self):
|
|
72
|
+
"""Global equipment request params"""
|
|
73
|
+
return {"state": [st.value for st in self.states]}
|
|
74
|
+
|
|
75
|
+
@initialize(invoke_without_command=True)
|
|
76
|
+
def init(
|
|
77
|
+
self,
|
|
78
|
+
ctx: Context,
|
|
79
|
+
remove: Annotated[
|
|
80
|
+
bool,
|
|
81
|
+
Option(
|
|
82
|
+
"--remove",
|
|
83
|
+
help=_(
|
|
84
|
+
"Remove any equipment from the database not present in sources."
|
|
85
|
+
),
|
|
86
|
+
),
|
|
87
|
+
] = remove,
|
|
88
|
+
no_synchronize: Annotated[
|
|
89
|
+
bool,
|
|
90
|
+
Option(
|
|
91
|
+
"--no-synchronize",
|
|
92
|
+
help=_(
|
|
93
|
+
"Do not synchronize ancillary equipment meta data with source(s)."
|
|
94
|
+
),
|
|
95
|
+
),
|
|
96
|
+
] = synchronize,
|
|
97
|
+
slm: Annotated[
|
|
98
|
+
str,
|
|
99
|
+
Option(
|
|
100
|
+
help=_(
|
|
101
|
+
"The url to the SLM to pull equipment data from (if different than source defaults)."
|
|
102
|
+
)
|
|
103
|
+
),
|
|
104
|
+
] = "https://network.igs.org",
|
|
105
|
+
states: Annotated[
|
|
106
|
+
t.List[
|
|
107
|
+
str
|
|
108
|
+
], # list of SiteLogFormat's does not work for some upstream reason
|
|
109
|
+
Option(
|
|
110
|
+
"--state",
|
|
111
|
+
metavar="STATE",
|
|
112
|
+
help=_("Only import equipment from these specified state(s)."),
|
|
113
|
+
shell_complete=these_strings([st.name for st in EquipmentState]),
|
|
114
|
+
),
|
|
115
|
+
] = states,
|
|
116
|
+
):
|
|
117
|
+
self.remove = remove
|
|
118
|
+
self.synchronize = not no_synchronize
|
|
119
|
+
self.slm = slm
|
|
120
|
+
self.states = [EquipmentState(st) for st in states]
|
|
121
|
+
self.manufacturers = set()
|
|
122
|
+
self.manufacturers_added = set()
|
|
123
|
+
self.antennas = set()
|
|
124
|
+
self.antennas_added = set()
|
|
125
|
+
self.receivers = set()
|
|
126
|
+
self.receivers_added = set()
|
|
127
|
+
self.radomes = set()
|
|
128
|
+
self.radomes_added = set()
|
|
129
|
+
|
|
130
|
+
if not ctx.invoked_subcommand:
|
|
131
|
+
for cmd in [cmd for cmd in self.get_subcommand().children.values()]:
|
|
132
|
+
cmd()
|
|
133
|
+
|
|
134
|
+
def get_manufacturer(self, item):
|
|
135
|
+
manufacturer, created = Manufacturer.objects.get_or_create(
|
|
136
|
+
name=item.get("manufacturer", item)
|
|
137
|
+
)
|
|
138
|
+
self.manufacturers.add(manufacturer)
|
|
139
|
+
if created:
|
|
140
|
+
self.manufacturers_added.add(manufacturer)
|
|
141
|
+
return manufacturer
|
|
142
|
+
|
|
143
|
+
@command(help=_("Import manufacturers."))
|
|
144
|
+
def manufacturers(
|
|
145
|
+
self,
|
|
146
|
+
sources: Annotated[
|
|
147
|
+
t.List[str],
|
|
148
|
+
Option(
|
|
149
|
+
"--source", "-s", help=_("The source(s) to import manufacturers from.")
|
|
150
|
+
),
|
|
151
|
+
] = ["{slm}/api/public/manufacturer/"],
|
|
152
|
+
):
|
|
153
|
+
sources = [src.format(slm=self.slm) for src in sources]
|
|
154
|
+
for src in sources:
|
|
155
|
+
manufacturers = requests.get(src, json=True).json()
|
|
156
|
+
for entry in manufacturers:
|
|
157
|
+
manufacturer, created = (
|
|
158
|
+
Manufacturer.objects.update_or_create
|
|
159
|
+
if self.synchronize
|
|
160
|
+
else Manufacturer.objects.get_or_create
|
|
161
|
+
)(
|
|
162
|
+
name=entry["name"],
|
|
163
|
+
defaults={
|
|
164
|
+
"full_name": entry.get("full_name", ""),
|
|
165
|
+
"url": entry.get("url", None),
|
|
166
|
+
},
|
|
167
|
+
)
|
|
168
|
+
self.manufacturers.add(manufacturer)
|
|
169
|
+
if created:
|
|
170
|
+
self.manufacturers_added.add(manufacturer)
|
|
171
|
+
|
|
172
|
+
self.secho(_(
|
|
173
|
+
"Added {added} manufacturers from {sources}."
|
|
174
|
+
).format(
|
|
175
|
+
added=len(self.manufacturers_added),
|
|
176
|
+
sources=sources[0] if len(sources) == 1 else sources
|
|
177
|
+
), fg="green")
|
|
178
|
+
|
|
179
|
+
if self.remove:
|
|
180
|
+
to_delete = Manufacturer.objects.filter(
|
|
181
|
+
~Q(id__in=[mf.id for mf in self.manufacturers])
|
|
182
|
+
)
|
|
183
|
+
num_to_delete = to_delete.count()
|
|
184
|
+
if num_to_delete:
|
|
185
|
+
to_delete.delete()
|
|
186
|
+
self.secho(f"Removed {num_to_delete} manufacturers.", fg="red")
|
|
187
|
+
|
|
188
|
+
@command(help=_("Import antennas."))
|
|
189
|
+
def antennas(
|
|
190
|
+
self,
|
|
191
|
+
sources: Annotated[
|
|
192
|
+
t.List[str],
|
|
193
|
+
Option("--source", "-s", help=_("The source(s) to import antennas from.")),
|
|
194
|
+
] = ["{slm}/api/public/antenna/"],
|
|
195
|
+
):
|
|
196
|
+
replacements = {}
|
|
197
|
+
sources = [src.format(slm=self.slm) for src in sources]
|
|
198
|
+
for src in sources:
|
|
199
|
+
antennas = requests.get(src, params=self.params).json()
|
|
200
|
+
for entry in antennas:
|
|
201
|
+
antenna, created = (
|
|
202
|
+
Antenna.objects.update_or_create
|
|
203
|
+
if self.synchronize
|
|
204
|
+
else Antenna.objects.get_or_create
|
|
205
|
+
)(
|
|
206
|
+
model=entry["model"],
|
|
207
|
+
defaults={
|
|
208
|
+
"description": entry.get("description", ""),
|
|
209
|
+
"state": EquipmentState(
|
|
210
|
+
entry.get("state", EquipmentState.ACTIVE)
|
|
211
|
+
),
|
|
212
|
+
"features": entry.get("features", None),
|
|
213
|
+
"reference_point": entry.get("reference_point", None),
|
|
214
|
+
"graphic": entry.get("graphic", ""),
|
|
215
|
+
},
|
|
216
|
+
)
|
|
217
|
+
replaced = entry.get("replaced", [])
|
|
218
|
+
if replaced:
|
|
219
|
+
replacements[antenna] = replaced
|
|
220
|
+
self.antennas.add(antenna)
|
|
221
|
+
if created:
|
|
222
|
+
self.antennas_added.add(antenna)
|
|
223
|
+
|
|
224
|
+
self.secho(_(
|
|
225
|
+
"Added {added} antennas from {sources}."
|
|
226
|
+
).format(
|
|
227
|
+
added=len(self.antennas_added),
|
|
228
|
+
sources=sources[0] if len(sources) == 1 else sources
|
|
229
|
+
), fg="green")
|
|
230
|
+
|
|
231
|
+
for ant, replaced in replacements.items():
|
|
232
|
+
ant.replaced.set(Antenna.objects.filter(model__in=replaced))
|
|
233
|
+
|
|
234
|
+
if self.remove:
|
|
235
|
+
to_delete = Antenna.objects.filter(
|
|
236
|
+
~Q(id__in=[ant.id for ant in self.antennas])
|
|
237
|
+
)
|
|
238
|
+
num_to_delete = to_delete.count()
|
|
239
|
+
if num_to_delete:
|
|
240
|
+
to_delete.delete()
|
|
241
|
+
self.secho(f"Removed {num_to_delete} antennas.", fg="red")
|
|
242
|
+
|
|
243
|
+
@command(help=_("Import receivers."))
|
|
244
|
+
def receivers(
|
|
245
|
+
self,
|
|
246
|
+
sources: Annotated[
|
|
247
|
+
t.List[str],
|
|
248
|
+
Option("--source", "-s", help=_("The source(s) to import receivers from.")),
|
|
249
|
+
] = ["{slm}/api/public/receiver/"],
|
|
250
|
+
):
|
|
251
|
+
replacements = {}
|
|
252
|
+
sources = [src.format(slm=self.slm) for src in sources]
|
|
253
|
+
for source in sources:
|
|
254
|
+
source = source.format(slm=self.slm)
|
|
255
|
+
receivers = requests.get(source, params=self.params).json()
|
|
256
|
+
for entry in receivers:
|
|
257
|
+
receiver, created = (
|
|
258
|
+
Receiver.objects.update_or_create
|
|
259
|
+
if self.synchronize
|
|
260
|
+
else Receiver.objects.get_or_create
|
|
261
|
+
)(
|
|
262
|
+
model=entry["model"],
|
|
263
|
+
defaults={
|
|
264
|
+
"description": entry.get("description", ""),
|
|
265
|
+
"state": EquipmentState(
|
|
266
|
+
entry.get("state", EquipmentState.ACTIVE)
|
|
267
|
+
),
|
|
268
|
+
},
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
replaced = entry.get("replaced", [])
|
|
272
|
+
if replaced:
|
|
273
|
+
replacements[receiver] = replaced
|
|
274
|
+
|
|
275
|
+
self.receivers.add(receiver)
|
|
276
|
+
if created:
|
|
277
|
+
self.receivers_added.add(receiver)
|
|
278
|
+
|
|
279
|
+
self.secho(_(
|
|
280
|
+
"Added {added} receivers from {sources}."
|
|
281
|
+
).format(
|
|
282
|
+
added=len(self.receivers_added),
|
|
283
|
+
sources=sources[0] if len(sources) == 1 else sources
|
|
284
|
+
), fg="green")
|
|
285
|
+
|
|
286
|
+
for ant, replaced in replacements.items():
|
|
287
|
+
ant.replaced.set(Receiver.objects.filter(model__in=replaced))
|
|
288
|
+
|
|
289
|
+
if self.remove:
|
|
290
|
+
to_delete = Receiver.objects.filter(
|
|
291
|
+
~Q(id__in=[rec.id for rec in self.receivers])
|
|
292
|
+
)
|
|
293
|
+
num_to_delete = to_delete.count()
|
|
294
|
+
if num_to_delete:
|
|
295
|
+
to_delete.delete()
|
|
296
|
+
self.secho(f"Removed {num_to_delete} receivers.", fg="red")
|
|
297
|
+
|
|
298
|
+
@command(help=_("Import radomes."))
|
|
299
|
+
def radomes(
|
|
300
|
+
self,
|
|
301
|
+
sources: Annotated[
|
|
302
|
+
t.List[str],
|
|
303
|
+
Option("--source", "-s", help=_("The source(s) to import radomes from.")),
|
|
304
|
+
] = ["{slm}/api/public/radome/"],
|
|
305
|
+
):
|
|
306
|
+
replacements = {}
|
|
307
|
+
sources = [src.format(slm=self.slm) for src in sources]
|
|
308
|
+
for source in sources:
|
|
309
|
+
source = source.format(slm=self.slm)
|
|
310
|
+
radomes = requests.get(source, params=self.params).json()
|
|
311
|
+
for entry in radomes:
|
|
312
|
+
radome, created = (
|
|
313
|
+
Radome.objects.update_or_create
|
|
314
|
+
if self.synchronize
|
|
315
|
+
else Radome.objects.get_or_create
|
|
316
|
+
)(
|
|
317
|
+
model=entry["model"],
|
|
318
|
+
defaults={
|
|
319
|
+
"description": entry.get("description", ""),
|
|
320
|
+
"state": EquipmentState(
|
|
321
|
+
entry.get("state", EquipmentState.ACTIVE)
|
|
322
|
+
),
|
|
323
|
+
},
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
replaced = entry.get("replaced", [])
|
|
327
|
+
if replaced:
|
|
328
|
+
replacements[radome] = replaced
|
|
329
|
+
|
|
330
|
+
self.radomes.add(radome)
|
|
331
|
+
if created:
|
|
332
|
+
self.radomes_added.add(radome)
|
|
333
|
+
|
|
334
|
+
self.secho(_(
|
|
335
|
+
"Added {added} radomes from {sources}."
|
|
336
|
+
).format(
|
|
337
|
+
added=len(self.radomes_added),
|
|
338
|
+
sources=sources[0] if len(sources) == 1 else sources
|
|
339
|
+
), fg="green")
|
|
340
|
+
|
|
341
|
+
for ant, replaced in replacements.items():
|
|
342
|
+
ant.replaced.set(Radome.objects.filter(model__in=replaced))
|
|
343
|
+
|
|
344
|
+
if self.remove:
|
|
345
|
+
to_delete = Radome.objects.filter(
|
|
346
|
+
~Q(id__in=[rad.id for rad in self.radomes])
|
|
347
|
+
)
|
|
348
|
+
num_to_delete = to_delete.count()
|
|
349
|
+
if num_to_delete:
|
|
350
|
+
to_delete.delete()
|
|
351
|
+
self.secho(f"Removed {num_to_delete} radomes.", fg="red")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The `Django Sites framework <https://docs.djangoproject.com/en/stable/ref/contrib/sites/>`_
|
|
3
|
+
is used by the SLM and SLM extensions to store information about the organization name and
|
|
4
|
+
domain name being served by the current instance. This command populates that information
|
|
5
|
+
from SLM specific settings:
|
|
6
|
+
|
|
7
|
+
* SLM_SITE_NAME
|
|
8
|
+
* SLM_ORG_NAME
|
|
9
|
+
|
|
10
|
+
.. note::
|
|
11
|
+
|
|
12
|
+
The sites framework is typically used to support serving multiple domains off the same
|
|
13
|
+
software stack. In our experience it is usually preferable to serve separate domains
|
|
14
|
+
off customized software stacks because their requirements may differ substantially.
|
|
15
|
+
For example network.igs.org and slm.igs.org are both instances of the SLM with
|
|
16
|
+
different configurations.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from django.conf import settings
|
|
20
|
+
from django.contrib.sites.models import Site
|
|
21
|
+
from django.core.management import CommandError
|
|
22
|
+
from django.utils.translation import gettext as _
|
|
23
|
+
from django_typer.management import TyperCommand
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Command(TyperCommand):
|
|
27
|
+
help = _(
|
|
28
|
+
"Set the Django Site database object to reflect SLM_SITE_NAME and "
|
|
29
|
+
"SLM_ORG_NAME in settings."
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
suppressed_base_arguments = {
|
|
33
|
+
*TyperCommand.suppressed_base_arguments,
|
|
34
|
+
"version",
|
|
35
|
+
"pythonpath",
|
|
36
|
+
"settings",
|
|
37
|
+
"skip-checks",
|
|
38
|
+
}
|
|
39
|
+
requires_migrations_checks = False
|
|
40
|
+
requires_system_checks = []
|
|
41
|
+
|
|
42
|
+
def handle(self):
|
|
43
|
+
domain = getattr(settings, "SLM_SITE_NAME", None)
|
|
44
|
+
org = getattr(settings, "SLM_ORG_NAME", None)
|
|
45
|
+
if domain and org:
|
|
46
|
+
site = Site.objects.get_current()
|
|
47
|
+
site.domain = domain
|
|
48
|
+
site.name = org
|
|
49
|
+
site.save()
|
|
50
|
+
else:
|
|
51
|
+
raise CommandError(
|
|
52
|
+
_(
|
|
53
|
+
"To set the default Site object, both SLM_SITE_NAME and "
|
|
54
|
+
"SLM_ORG_NAME must be defined in settings."
|
|
55
|
+
)
|
|
56
|
+
)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generate a serialized site log of the given format for a station's published or
|
|
3
|
+
unpublished head state. Optionally the file will be pulled from the index of archived
|
|
4
|
+
site log files.
|
|
5
|
+
|
|
6
|
+
It is usually more convenient to go through the web interface if you just want to view
|
|
7
|
+
a sitelog, but this command can be useful for entering into the debugger to troubleshoot
|
|
8
|
+
parts of this pipeline.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import typing as t
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from django.core.management import CommandError
|
|
16
|
+
from django.db.models import Q
|
|
17
|
+
from django.utils.translation import gettext as _
|
|
18
|
+
from django_typer.management import (
|
|
19
|
+
TyperCommand,
|
|
20
|
+
command,
|
|
21
|
+
initialize,
|
|
22
|
+
model_parser_completer,
|
|
23
|
+
)
|
|
24
|
+
from typer import Argument, Option
|
|
25
|
+
from typing_extensions import Annotated
|
|
26
|
+
|
|
27
|
+
from slm.api.serializers import SiteLogSerializer
|
|
28
|
+
from slm.defines import GeodesyMLVersion, SiteLogFormat
|
|
29
|
+
from slm.management.commands import EnumParser
|
|
30
|
+
from slm.models import ArchiveIndex, Site
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Command(TyperCommand):
|
|
34
|
+
help = _(
|
|
35
|
+
"Generate a site log in the specified format for the specified site "
|
|
36
|
+
"and print it to stdout. Optionally pull the log from the archive or "
|
|
37
|
+
"regenerate it based on given parameters."
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
suppressed_base_arguments = {
|
|
41
|
+
*TyperCommand.suppressed_base_arguments,
|
|
42
|
+
"version",
|
|
43
|
+
"pythonpath",
|
|
44
|
+
"settings",
|
|
45
|
+
"skip-checks",
|
|
46
|
+
}
|
|
47
|
+
requires_migrations_checks = False
|
|
48
|
+
requires_system_checks = []
|
|
49
|
+
|
|
50
|
+
site: Site
|
|
51
|
+
head: bool
|
|
52
|
+
archive: bool
|
|
53
|
+
|
|
54
|
+
@initialize()
|
|
55
|
+
def set_site(
|
|
56
|
+
self,
|
|
57
|
+
site: Annotated[
|
|
58
|
+
Site,
|
|
59
|
+
Argument(
|
|
60
|
+
**model_parser_completer(
|
|
61
|
+
Site, lookup_field="name", case_insensitive=True
|
|
62
|
+
),
|
|
63
|
+
help=_("The name of the site."),
|
|
64
|
+
),
|
|
65
|
+
],
|
|
66
|
+
head: Annotated[
|
|
67
|
+
bool,
|
|
68
|
+
Option(
|
|
69
|
+
"--head", help=_("Generate the log from the head edits (unpublished).")
|
|
70
|
+
),
|
|
71
|
+
] = False,
|
|
72
|
+
archive: Annotated[ # todo, should be mutually exclusive with head
|
|
73
|
+
t.Optional[datetime],
|
|
74
|
+
Option(help=_("Pull from archive rather than generating.")),
|
|
75
|
+
] = None,
|
|
76
|
+
):
|
|
77
|
+
self.site = site
|
|
78
|
+
if head and archive:
|
|
79
|
+
raise CommandError("Cannot specify both --head and --archive.")
|
|
80
|
+
self.head = head
|
|
81
|
+
self.archive = archive
|
|
82
|
+
|
|
83
|
+
@command()
|
|
84
|
+
def legacy(self):
|
|
85
|
+
if self.archive:
|
|
86
|
+
index = ArchiveIndex.objects.filter(site=self.site).first()
|
|
87
|
+
log_file = index.files.filter(log_format=SiteLogFormat.LEGACY).first()
|
|
88
|
+
if not log_file:
|
|
89
|
+
raise CommandError(
|
|
90
|
+
_("Latest index of {site} does not have a legacy log file.").format(
|
|
91
|
+
site=self.site.name
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
self.stdout.write(Path(log_file.file.path).read_text())
|
|
96
|
+
else:
|
|
97
|
+
self.stdout.write(
|
|
98
|
+
SiteLogSerializer(
|
|
99
|
+
instance=self.site, published=None if self.head else True
|
|
100
|
+
).format(SiteLogFormat.LEGACY)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
@command()
|
|
104
|
+
def xml(
|
|
105
|
+
self,
|
|
106
|
+
gml_version: Annotated[
|
|
107
|
+
t.Optional[GeodesyMLVersion],
|
|
108
|
+
Option(
|
|
109
|
+
"--version",
|
|
110
|
+
metavar="VERSION",
|
|
111
|
+
parser=EnumParser(GeodesyMLVersion, "version"),
|
|
112
|
+
help=_("The Geodesy ML version. ({versions})").format(
|
|
113
|
+
versions=", ".join([str(gml.version) for gml in GeodesyMLVersion])
|
|
114
|
+
),
|
|
115
|
+
),
|
|
116
|
+
] = None,
|
|
117
|
+
):
|
|
118
|
+
if self.archive:
|
|
119
|
+
index = ArchiveIndex.objects.filter(site=self.site).first()
|
|
120
|
+
qry = Q(log_format=SiteLogFormat.GEODESY_ML)
|
|
121
|
+
qry &= Q(index__begin__lte=self.archive) & (
|
|
122
|
+
Q(index__end__gt=self.archive) | Q(index__end__isnull=True)
|
|
123
|
+
)
|
|
124
|
+
if gml_version:
|
|
125
|
+
qry &= Q(gml_version=gml_version)
|
|
126
|
+
log_file = index.files.filter(qry).first()
|
|
127
|
+
if not log_file:
|
|
128
|
+
raise CommandError(
|
|
129
|
+
_(
|
|
130
|
+
"Archive of {site} @ {archive} does not have a {version} log file."
|
|
131
|
+
).format(
|
|
132
|
+
site=self.site.name,
|
|
133
|
+
archive=self.archive,
|
|
134
|
+
version=str(gml_version) or "GeodesyML",
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
self.stdout.write(Path(log_file.file.path).read_text())
|
|
139
|
+
else:
|
|
140
|
+
self.stdout.write(
|
|
141
|
+
SiteLogSerializer(
|
|
142
|
+
instance=self.site, published=None if self.head else True
|
|
143
|
+
).format(SiteLogFormat.GEODESY_ML, version=gml_version)
|
|
144
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
To keep the SLM APIs performant some database state is
|
|
3
|
+
`denormalized <https://en.wikipedia.org/wiki/Denormalization>`_. In normal
|
|
4
|
+
operations this state is synchronized when it needs to be, but if for
|
|
5
|
+
whatever reason the denormalized state becomes unsynchronized, this command
|
|
6
|
+
can be manually invoked to force synchronization.
|
|
7
|
+
|
|
8
|
+
Some examples of denormalized state in the SLM include:
|
|
9
|
+
|
|
10
|
+
* Counts of validation flags
|
|
11
|
+
* Maximum alert levels for stations
|
|
12
|
+
* Sitelog status indicators (PUBLISHED/UNPUBLISHED) for stations.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import typing as t
|
|
16
|
+
|
|
17
|
+
from django.db import transaction
|
|
18
|
+
from django.db.models import Q
|
|
19
|
+
from django.utils.translation import gettext as _
|
|
20
|
+
from django_typer.management import TyperCommand, model_parser_completer
|
|
21
|
+
from typer import Argument
|
|
22
|
+
from typing_extensions import Annotated
|
|
23
|
+
|
|
24
|
+
from slm.models import Site
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Command(TyperCommand):
|
|
28
|
+
help = _(
|
|
29
|
+
"Synchronize all denormalized data - that is data that is cached for "
|
|
30
|
+
"performance reasons that may become out of sync if updates are "
|
|
31
|
+
"performed outside of normal request/response cycles."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
suppressed_base_arguments = {
|
|
35
|
+
*TyperCommand.suppressed_base_arguments,
|
|
36
|
+
"version",
|
|
37
|
+
"pythonpath",
|
|
38
|
+
"settings",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
def handle(
|
|
42
|
+
self,
|
|
43
|
+
sites: Annotated[
|
|
44
|
+
t.Optional[t.List[Site]],
|
|
45
|
+
Argument(
|
|
46
|
+
**model_parser_completer(
|
|
47
|
+
Site, lookup_field="name", case_insensitive=True
|
|
48
|
+
),
|
|
49
|
+
help=_(
|
|
50
|
+
"The station(s) to synchronize, if unspecified, synchronize all "
|
|
51
|
+
"of them."
|
|
52
|
+
),
|
|
53
|
+
),
|
|
54
|
+
] = None,
|
|
55
|
+
):
|
|
56
|
+
with transaction.atomic():
|
|
57
|
+
qry = Q()
|
|
58
|
+
if sites:
|
|
59
|
+
qry = Q(pk__in=[site.id for site in sites])
|
|
60
|
+
Site.objects.filter(qry).synchronize_denormalized_state()
|