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
slm/models/index.py
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from django.core.files.base import ContentFile
|
|
4
|
+
from django.db import models, transaction
|
|
5
|
+
from django.db.models import F, OuterRef, Q, Subquery, Value
|
|
6
|
+
from django.db.models.functions import (
|
|
7
|
+
Cast,
|
|
8
|
+
Concat,
|
|
9
|
+
ExtractDay,
|
|
10
|
+
ExtractMonth,
|
|
11
|
+
ExtractYear,
|
|
12
|
+
Lower,
|
|
13
|
+
LPad,
|
|
14
|
+
Now,
|
|
15
|
+
Substr,
|
|
16
|
+
)
|
|
17
|
+
from django.utils.functional import cached_property
|
|
18
|
+
from django.utils.timezone import now
|
|
19
|
+
from django.utils.translation import gettext_lazy as _
|
|
20
|
+
|
|
21
|
+
from slm.defines import (
|
|
22
|
+
GeodesyMLVersion,
|
|
23
|
+
RinexVersion,
|
|
24
|
+
SiteLogFormat,
|
|
25
|
+
SiteLogStatus,
|
|
26
|
+
SLMFileType,
|
|
27
|
+
)
|
|
28
|
+
from slm.models.data import DataAvailability
|
|
29
|
+
from slm.models.system import SiteFile
|
|
30
|
+
from slm.parsing import BaseBinder
|
|
31
|
+
from slm.parsing import legacy as legacy_parsing
|
|
32
|
+
from slm.parsing import xsd as xsd_parsing
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ArchiveIndexManager(models.Manager):
|
|
36
|
+
def regenerate(self, site, log_format):
|
|
37
|
+
"""
|
|
38
|
+
Regenerate the index file for this index. This will only be done for
|
|
39
|
+
the head index for this file.
|
|
40
|
+
|
|
41
|
+
:param site: The site to regenerate the archived index file for.
|
|
42
|
+
:param log_format: The log format to regenerate.
|
|
43
|
+
"""
|
|
44
|
+
new_file = ArchivedSiteLog.objects.from_index(
|
|
45
|
+
index=self.get_queryset().filter(site=site).order_by("-begin").first(),
|
|
46
|
+
log_format=log_format,
|
|
47
|
+
regenerate=True,
|
|
48
|
+
)
|
|
49
|
+
return new_file
|
|
50
|
+
|
|
51
|
+
def add_index(self, site, formats=list(SiteLogFormat)):
|
|
52
|
+
assert site.last_publish, "last_publish must be set before calling add_index"
|
|
53
|
+
existing = self.filter(site=site, begin=site.last_publish).first()
|
|
54
|
+
if existing:
|
|
55
|
+
return existing
|
|
56
|
+
|
|
57
|
+
self.close_index(site)
|
|
58
|
+
|
|
59
|
+
new_index = self.create(site=site, begin=site.last_publish, end=None)
|
|
60
|
+
|
|
61
|
+
for log_format in formats:
|
|
62
|
+
if log_format in {SiteLogFormat.JSON}:
|
|
63
|
+
continue # todo - remove
|
|
64
|
+
ArchivedSiteLog.objects.from_site(site=site, log_format=log_format)
|
|
65
|
+
|
|
66
|
+
return new_index
|
|
67
|
+
|
|
68
|
+
def close_index(self, site):
|
|
69
|
+
if site.last_publish:
|
|
70
|
+
last = (
|
|
71
|
+
self.filter(site=site)
|
|
72
|
+
.filter(
|
|
73
|
+
Q(begin__lte=site.last_publish) & Q(end__isnull=True)
|
|
74
|
+
| Q(end__gt=site.last_publish)
|
|
75
|
+
)
|
|
76
|
+
.first()
|
|
77
|
+
)
|
|
78
|
+
if last:
|
|
79
|
+
last.end = site.last_publish
|
|
80
|
+
last.save()
|
|
81
|
+
|
|
82
|
+
def create(self, **kwargs):
|
|
83
|
+
return self.insert_index(**kwargs)
|
|
84
|
+
|
|
85
|
+
def get_or_create(self, site, begin, **kwargs):
|
|
86
|
+
self.insert_index(site=site, begin=begin, **kwargs)
|
|
87
|
+
|
|
88
|
+
def insert_index(self, begin, site, **kwargs):
|
|
89
|
+
"""
|
|
90
|
+
Insert a new index into an existing index deck (i.e. between existing
|
|
91
|
+
indexes).
|
|
92
|
+
"""
|
|
93
|
+
existing = self.get_queryset().filter(site=site, begin=begin).first()
|
|
94
|
+
if existing:
|
|
95
|
+
return existing
|
|
96
|
+
next_index = (
|
|
97
|
+
self.get_queryset()
|
|
98
|
+
.filter(site=site, begin__gt=begin)
|
|
99
|
+
.order_by("begin")
|
|
100
|
+
.first()
|
|
101
|
+
)
|
|
102
|
+
prev_index = (
|
|
103
|
+
self.get_queryset()
|
|
104
|
+
.filter(site=site, begin__lt=begin)
|
|
105
|
+
.order_by("-begin")
|
|
106
|
+
.first()
|
|
107
|
+
)
|
|
108
|
+
kwargs.setdefault("end", next_index.begin if next_index else None)
|
|
109
|
+
if prev_index:
|
|
110
|
+
prev_index.end = begin
|
|
111
|
+
prev_index.save()
|
|
112
|
+
return super().create(begin=begin, site=site, **kwargs)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class ArchiveIndexQuerySet(models.QuerySet):
|
|
116
|
+
def delete(self):
|
|
117
|
+
"""
|
|
118
|
+
We can't just delete an archive to remove it - we also have to
|
|
119
|
+
update the end time of the previous archive in the index if there
|
|
120
|
+
is one to reflect the end time of the deleted log
|
|
121
|
+
"""
|
|
122
|
+
from slm.models import Site, SiteForm
|
|
123
|
+
|
|
124
|
+
with transaction.atomic():
|
|
125
|
+
# also, sites where the deleted index is the current index
|
|
126
|
+
# (end=null) that are in the published state should be set to
|
|
127
|
+
# updated
|
|
128
|
+
# we trigger unpublished state by updating the SiteForm
|
|
129
|
+
# prepared date and synchronizing
|
|
130
|
+
published_sites = Site.objects.filter(
|
|
131
|
+
Q(indexes__in=self.filter(end__isnull=True))
|
|
132
|
+
& Q(status=SiteLogStatus.PUBLISHED)
|
|
133
|
+
).distinct()
|
|
134
|
+
|
|
135
|
+
# these are the indexes that remain that must be updated - that
|
|
136
|
+
# includes any non-deleted index immediately preceding a deleted
|
|
137
|
+
# index, indexes immediately following a deleted index do not
|
|
138
|
+
# need to be updated
|
|
139
|
+
after = self.filter(Q(site=OuterRef("site")) & Q(begin=OuterRef("end")))
|
|
140
|
+
before = self.filter(Q(site=OuterRef("site")) & Q(end=OuterRef("begin")))
|
|
141
|
+
new_bookends = (
|
|
142
|
+
ArchiveIndex.objects.annotate(before=Subquery(before.values("pk")[:1]))
|
|
143
|
+
.filter(
|
|
144
|
+
Q(site=OuterRef("site"))
|
|
145
|
+
& Q(begin__gte=OuterRef("end"))
|
|
146
|
+
& ~Q(pk__in=self)
|
|
147
|
+
& Q(before__isnull=False)
|
|
148
|
+
)
|
|
149
|
+
.order_by("end")
|
|
150
|
+
)
|
|
151
|
+
adjacent_indexes = ArchiveIndex.objects.annotate(
|
|
152
|
+
adjacent=Subquery(after.values("pk")[:1]),
|
|
153
|
+
new_end=Subquery(new_bookends.values("begin")[:1]),
|
|
154
|
+
).filter(Q(adjacent__isnull=False) & ~Q(pk__in=self))
|
|
155
|
+
|
|
156
|
+
# we use the new last indexes' old last end date
|
|
157
|
+
forms = []
|
|
158
|
+
for form in SiteForm.objects.filter(site__in=published_sites):
|
|
159
|
+
form.pk = None
|
|
160
|
+
form.published = False
|
|
161
|
+
form.date_prepared = now().date()
|
|
162
|
+
forms.append(form)
|
|
163
|
+
|
|
164
|
+
SiteForm.objects.bulk_create(forms)
|
|
165
|
+
published_sites.synchronize_denormalized_state()
|
|
166
|
+
|
|
167
|
+
adjacent_indexes.update(end=F("new_end"))
|
|
168
|
+
deleted = super().delete()
|
|
169
|
+
return deleted
|
|
170
|
+
|
|
171
|
+
@staticmethod
|
|
172
|
+
def epoch_q(epoch=None):
|
|
173
|
+
if epoch is None:
|
|
174
|
+
epoch = now()
|
|
175
|
+
return Q(begin__lte=epoch) & (Q(end__gt=epoch) | Q(end__isnull=True))
|
|
176
|
+
|
|
177
|
+
def at_epoch(self, epoch=None):
|
|
178
|
+
return self.filter(self.epoch_q(epoch))
|
|
179
|
+
|
|
180
|
+
def public(self):
|
|
181
|
+
return self.filter(site__agencies__public=True)
|
|
182
|
+
|
|
183
|
+
def availability(self):
|
|
184
|
+
last_data_avail = DataAvailability.objects.filter(site=OuterRef("pk")).order_by(
|
|
185
|
+
"-last"
|
|
186
|
+
)
|
|
187
|
+
return self.annotate(
|
|
188
|
+
last_data_time=Subquery(last_data_avail.values("last")[:1]),
|
|
189
|
+
last_data=Now() - F("last_data_time"),
|
|
190
|
+
last_rinex2=Subquery(
|
|
191
|
+
last_data_avail.filter(RinexVersion(2).major_q()).values("last")[:1]
|
|
192
|
+
),
|
|
193
|
+
last_rinex3=Subquery(
|
|
194
|
+
last_data_avail.filter(RinexVersion(3).major_q()).values("last")[:1]
|
|
195
|
+
),
|
|
196
|
+
last_rinex4=Subquery(
|
|
197
|
+
last_data_avail.filter(RinexVersion(4).major_q()).values("last")[:1]
|
|
198
|
+
),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def annotate_filenames(
|
|
202
|
+
self, name_len=None, field_name="filename", lower_case=False, log_format=None
|
|
203
|
+
):
|
|
204
|
+
"""
|
|
205
|
+
Add the log names (w/o) extension as a property called filename to
|
|
206
|
+
each site.
|
|
207
|
+
|
|
208
|
+
:param name_len: If given a number, the filename will start with only
|
|
209
|
+
the first name_len characters of the site name.
|
|
210
|
+
:param field_name: Change the name of the annotated field.
|
|
211
|
+
:param lower_case: Filenames will be lowercase if true.
|
|
212
|
+
:param log_format: If given, add the extension for the given format
|
|
213
|
+
:return: A queryset with the filename annotation added.
|
|
214
|
+
"""
|
|
215
|
+
name_str = F("site__name")
|
|
216
|
+
if name_len:
|
|
217
|
+
name_str = Cast(
|
|
218
|
+
Substr("site__name", 1, length=name_len), models.CharField()
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
if lower_case:
|
|
222
|
+
name_str = Lower(name_str)
|
|
223
|
+
|
|
224
|
+
parts = [
|
|
225
|
+
name_str,
|
|
226
|
+
Value("_"),
|
|
227
|
+
Cast(ExtractYear("begin"), models.CharField()),
|
|
228
|
+
LPad(
|
|
229
|
+
Cast(ExtractMonth("begin"), models.CharField()), 2, fill_text=Value("0")
|
|
230
|
+
),
|
|
231
|
+
LPad(
|
|
232
|
+
Cast(ExtractDay("begin"), models.CharField()), 2, fill_text=Value("0")
|
|
233
|
+
),
|
|
234
|
+
]
|
|
235
|
+
if log_format:
|
|
236
|
+
parts.append(Value(f".{log_format.ext}"))
|
|
237
|
+
|
|
238
|
+
return self.annotate(**{field_name: Concat(*parts)})
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class ArchiveIndex(models.Model):
|
|
242
|
+
site = models.ForeignKey(
|
|
243
|
+
"slm.Site", on_delete=models.CASCADE, null=False, related_name="indexes"
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# the point in time at which this record begins being valid
|
|
247
|
+
begin = models.DateTimeField(
|
|
248
|
+
null=False,
|
|
249
|
+
db_index=True,
|
|
250
|
+
help_text=_("The point in time at which this archive became valid."),
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# the point in time at which this record stops being valid
|
|
254
|
+
end = models.DateTimeField(
|
|
255
|
+
null=True,
|
|
256
|
+
db_index=True,
|
|
257
|
+
help_text=_("The point in time at which this archive stopped being valid."),
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
objects = ArchiveIndexManager.from_queryset(ArchiveIndexQuerySet)()
|
|
261
|
+
|
|
262
|
+
def __str__(self):
|
|
263
|
+
return (
|
|
264
|
+
f"{self.site.name} | {self.begin.date()} - "
|
|
265
|
+
f'{self.end.date() if self.end else "present"}'
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
def delete(self, using=None, keep_parents=False):
|
|
269
|
+
"""
|
|
270
|
+
Deleting an index requires updating the end time of the previous
|
|
271
|
+
indexes - we use the queryset delete method to do this.
|
|
272
|
+
"""
|
|
273
|
+
return ArchiveIndex.objects.filter(pk=self.pk).delete()
|
|
274
|
+
|
|
275
|
+
class Meta:
|
|
276
|
+
ordering = ("-begin",)
|
|
277
|
+
indexes = [
|
|
278
|
+
models.Index(fields=("begin", "end")),
|
|
279
|
+
models.Index(fields=("site", "begin", "end")),
|
|
280
|
+
]
|
|
281
|
+
unique_together = (("site", "begin"),)
|
|
282
|
+
verbose_name = "Archive Index"
|
|
283
|
+
verbose_name_plural = "Archive Index"
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class ArchivedSiteLogManager(models.Manager):
|
|
287
|
+
"""
|
|
288
|
+
This manager is responsible for mediating access to serialized site logs.
|
|
289
|
+
Most frequently it will be fetching logs that match the given criteria from
|
|
290
|
+
disk, but it might also generate a log from the edit stack if an archived
|
|
291
|
+
file does not exist.
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
def from_index(self, index, log_format, regenerate=False):
|
|
295
|
+
from slm.api.serializers import SiteLogSerializer
|
|
296
|
+
|
|
297
|
+
if index:
|
|
298
|
+
file = index.files.filter(log_format=log_format).first()
|
|
299
|
+
if file and not regenerate:
|
|
300
|
+
return file
|
|
301
|
+
elif file:
|
|
302
|
+
file.delete()
|
|
303
|
+
return self.model.objects.create(
|
|
304
|
+
site=index.site,
|
|
305
|
+
log_format=log_format,
|
|
306
|
+
index=index,
|
|
307
|
+
timestamp=index.begin,
|
|
308
|
+
mimetype=log_format.mimetype,
|
|
309
|
+
file_type=SLMFileType.SITE_LOG,
|
|
310
|
+
name=index.site.get_filename(log_format=log_format, epoch=index.begin),
|
|
311
|
+
file=ContentFile(
|
|
312
|
+
SiteLogSerializer(instance=index.site)
|
|
313
|
+
.format(log_format)
|
|
314
|
+
.encode("utf-8"),
|
|
315
|
+
name=index.site.get_filename(
|
|
316
|
+
log_format=log_format, epoch=index.begin
|
|
317
|
+
),
|
|
318
|
+
),
|
|
319
|
+
gml_version=(
|
|
320
|
+
GeodesyMLVersion.latest()
|
|
321
|
+
if log_format is SiteLogFormat.GEODESY_ML
|
|
322
|
+
else None
|
|
323
|
+
),
|
|
324
|
+
)
|
|
325
|
+
return None
|
|
326
|
+
|
|
327
|
+
def from_site(self, site, log_format=SiteLogFormat.LEGACY, epoch=None):
|
|
328
|
+
index = ArchiveIndex.objects.filter(site=site).at_epoch(epoch=epoch).first()
|
|
329
|
+
if index:
|
|
330
|
+
return self.from_index(index, log_format=log_format)
|
|
331
|
+
return None
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
class ArchivedSiteLogQuerySet(models.QuerySet):
|
|
335
|
+
def annotate_filenames(
|
|
336
|
+
self, name_len=None, field_name="filename", lower_case=False, log_format=None
|
|
337
|
+
):
|
|
338
|
+
"""
|
|
339
|
+
Add the log names (w/o) extension as a property called filename to
|
|
340
|
+
each site.
|
|
341
|
+
|
|
342
|
+
:param name_len: If given a number, the filename will start with only
|
|
343
|
+
the first name_len characters of the site name.
|
|
344
|
+
:param field_name: Change the name of the annotated field.
|
|
345
|
+
:param lower_case: Filenames will be lowercase if true.
|
|
346
|
+
:param log_format: If given, add the extension for the given format
|
|
347
|
+
:return: A queryset with the filename annotation added.
|
|
348
|
+
"""
|
|
349
|
+
name_str = F("site__name")
|
|
350
|
+
if name_len:
|
|
351
|
+
name_str = Cast(
|
|
352
|
+
Substr("site__name", 1, length=name_len), models.CharField()
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
if lower_case:
|
|
356
|
+
name_str = Lower(name_str)
|
|
357
|
+
|
|
358
|
+
parts = [
|
|
359
|
+
name_str,
|
|
360
|
+
Value("_"),
|
|
361
|
+
Cast(ExtractYear("index__begin"), models.CharField()),
|
|
362
|
+
LPad(
|
|
363
|
+
Cast(ExtractMonth("index__begin"), models.CharField()),
|
|
364
|
+
2,
|
|
365
|
+
fill_text=Value("0"),
|
|
366
|
+
),
|
|
367
|
+
LPad(
|
|
368
|
+
Cast(ExtractDay("index__begin"), models.CharField()),
|
|
369
|
+
2,
|
|
370
|
+
fill_text=Value("0"),
|
|
371
|
+
),
|
|
372
|
+
]
|
|
373
|
+
if log_format:
|
|
374
|
+
parts.append(Value(f".{log_format.ext}"))
|
|
375
|
+
return self.annotate(**{field_name: Concat(*parts)})
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class ArchivedSiteLog(SiteFile):
|
|
379
|
+
SUB_DIRECTORY = "archive"
|
|
380
|
+
|
|
381
|
+
index = models.ForeignKey(
|
|
382
|
+
ArchiveIndex, on_delete=models.CASCADE, related_name="files"
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
name = models.CharField(max_length=50)
|
|
386
|
+
|
|
387
|
+
objects = ArchivedSiteLogManager.from_queryset(ArchivedSiteLogQuerySet)()
|
|
388
|
+
|
|
389
|
+
def __str__(self):
|
|
390
|
+
if self.name:
|
|
391
|
+
return f"[{self.index}] {self.name}"
|
|
392
|
+
return f"[{self.index}] {os.path.basename(self.file.path)}"
|
|
393
|
+
|
|
394
|
+
def parse(self) -> BaseBinder:
|
|
395
|
+
if self.log_format is SiteLogFormat.GEODESY_ML:
|
|
396
|
+
return xsd_parsing.SiteLogBinder(
|
|
397
|
+
xsd_parsing.SiteLogParser(self.contents, site_name=self.site.name)
|
|
398
|
+
)
|
|
399
|
+
elif self.log_format in [SiteLogFormat.LEGACY, SiteLogFormat.ASCII_9CHAR]:
|
|
400
|
+
return legacy_parsing.SiteLogBinder(
|
|
401
|
+
legacy_parsing.SiteLogParser(self.contents, site_name=self.site.name)
|
|
402
|
+
)
|
|
403
|
+
raise NotImplementedError(
|
|
404
|
+
_("{format} is not currently supported for site log parsing.").format(
|
|
405
|
+
format=self.log_format
|
|
406
|
+
)
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
@cached_property
|
|
410
|
+
def contents(self) -> str:
|
|
411
|
+
"""
|
|
412
|
+
Decode the contents of a log file. The site log format has been around since the
|
|
413
|
+
early 1990s so we may encounter exotic encodings.
|
|
414
|
+
|
|
415
|
+
:param contents: The bytes of the log file contents.
|
|
416
|
+
:return a decoded string of the contents
|
|
417
|
+
"""
|
|
418
|
+
file_bytes = self.file.open("rb").read()
|
|
419
|
+
try:
|
|
420
|
+
return file_bytes.decode("utf-8")
|
|
421
|
+
except UnicodeDecodeError:
|
|
422
|
+
try:
|
|
423
|
+
return file_bytes.decode("ascii")
|
|
424
|
+
except UnicodeDecodeError:
|
|
425
|
+
return file_bytes.decode("latin")
|
|
426
|
+
|
|
427
|
+
class Meta:
|
|
428
|
+
unique_together = ("index", "log_format")
|