igs-slm 0.1.4b0__py3-none-any.whl → 0.1.5b1__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.5b1.dist-info/METADATA +115 -0
- {igs_slm-0.1.4b0.dist-info → igs_slm-0.1.5b1.dist-info}/RECORD +193 -173
- {igs_slm-0.1.4b0.dist-info → igs_slm-0.1.5b1.dist-info}/WHEEL +1 -1
- igs_slm-0.1.5b1.dist-info/entry_points.txt +3 -0
- {igs_slm-0.1.4b0.dist-info → igs_slm-0.1.5b1.dist-info/licenses}/LICENSE +1 -1
- slm/__init__.py +17 -14
- slm/admin.py +32 -5
- slm/api/edit/views.py +22 -9
- slm/api/public/views.py +9 -7
- slm/api/views.py +45 -6
- slm/apps.py +28 -6
- slm/authentication.py +3 -2
- slm/bin/startproject.py +102 -31
- slm/bin/templates/{{ project_dir }}/pyproject.toml +30 -21
- slm/bin/templates/{{ project_dir }}/{sites → src/sites}/{{ site }}/base.py +12 -1
- slm/bin/templates/{{ project_dir }}/{sites → src/sites}/{{ site }}/develop/__init__.py +5 -27
- slm/bin/templates/{{ project_dir }}/{sites → src/sites}/{{ site }}/production/__init__.py +6 -27
- slm/bin/templates/{{ project_dir }}/src/sites/{{ site }}/urls.py +15 -0
- slm/bin/templates/{{ project_dir }}/src/sites/{{ site }}/validation.py +29 -0
- slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/urls.py +1 -0
- slm/context.py +5 -0
- slm/defines/AlertLevel.py +10 -2
- slm/defines/AntennaCalibration.py +6 -4
- slm/defines/AntennaFeatures.py +12 -9
- slm/defines/AntennaReferencePoint.py +12 -10
- slm/defines/Aspiration.py +4 -2
- slm/defines/CardinalDirection.py +6 -4
- slm/defines/CollocationStatus.py +3 -1
- slm/defines/EquipmentState.py +6 -12
- slm/defines/FlagSeverity.py +4 -2
- slm/defines/FractureSpacing.py +7 -5
- slm/defines/FrequencyStandardType.py +6 -4
- slm/defines/GeodesyMLVersion.py +2 -0
- slm/defines/Instrumentation.py +9 -7
- slm/defines/LogEntryType.py +17 -15
- slm/defines/SLMFileType.py +4 -2
- slm/defines/SiteFileUploadStatus.py +7 -24
- slm/defines/SiteLogFormat.py +8 -32
- slm/defines/SiteLogStatus.py +9 -28
- slm/defines/TectonicPlates.py +18 -16
- slm/manage.py +24 -0
- slm/management/commands/check_upgrade.py +142 -0
- slm/management/commands/generate_sinex.py +110 -92
- slm/management/commands/head_from_index.py +11 -8
- slm/management/commands/import_archive.py +27 -18
- slm/management/commands/import_equipment.py +1 -1
- slm/management/commands/sitelog.py +1 -3
- slm/management/commands/synchronize.py +1 -1
- slm/management/commands/validate_db.py +6 -4
- slm/map/defines.py +18 -14
- slm/map/templates/slm/map.html +5 -7
- slm/migrations/0001_remove_archiveindex_no_overlapping_ranges_per_site_and_more.py +26 -0
- slm/migrations/0002_alter_archivedsitelog_file_and_more.py +44 -0
- slm/migrations/0003_alter_archivedsitelog_name_and_more.py +35 -0
- slm/migrations/0004_alter_site_name.py +24 -0
- slm/migrations/0005_slmversion.py +30 -0
- slm/migrations/0017_alter_logentry_unique_together_and_more.py +3 -1
- slm/migrations/0018_afix_deleted.py +3 -1
- slm/migrations/0018_alter_siteantenna_options_and_more.py +87 -56
- slm/migrations/0019_remove_siteantenna_marker_enu_siteantenna_marker_une_and_more.py +1 -1
- slm/migrations/0023_archivedsitelog_gml_version_and_more.py +1 -1
- slm/migrations/0031_alter_antenna_features.py +44 -0
- slm/migrations/0032_archiveindex_valid_range_and_more.py +84 -0
- slm/migrations/add_index_order_index.py +54 -0
- slm/migrations/normalize_index.py +147 -0
- slm/migrations/simplify_index.py +48 -0
- slm/migrations/verify_index.py +67 -0
- slm/models/__init__.py +2 -0
- slm/models/alerts.py +7 -10
- slm/models/data.py +1 -2
- slm/models/equipment.py +1 -1
- slm/models/fields.py +41 -0
- slm/models/index.py +183 -53
- slm/models/sitelog.py +35 -38
- slm/models/system.py +72 -31
- slm/models/user.py +1 -1
- slm/parsing/__init__.py +33 -16
- slm/parsing/legacy/binding.py +65 -34
- slm/parsing/legacy/parser.py +2 -2
- slm/parsing/xsd/binding.py +1 -1
- slm/parsing/xsd/parser.py +1 -2
- slm/receivers/__init__.py +2 -2
- slm/receivers/index.py +2 -1
- slm/receivers/migration.py +21 -0
- slm/settings/__init__.py +192 -4
- slm/settings/assets.py +26 -0
- slm/settings/auth.py +18 -14
- slm/settings/ckeditor.py +12 -6
- slm/settings/debug.py +2 -2
- slm/settings/emails.py +50 -0
- slm/settings/internationalization.py +8 -6
- slm/settings/logging.py +100 -88
- slm/settings/platform/darwin.py +16 -6
- slm/settings/rest.py +20 -15
- slm/settings/root.py +192 -98
- slm/settings/routines.py +5 -1
- slm/settings/secrets.py +20 -31
- slm/settings/security.py +7 -5
- slm/settings/slm.py +35 -23
- slm/settings/static_templates.py +12 -9
- slm/settings/templates.py +31 -25
- slm/settings/uploads.py +33 -5
- slm/settings/urls.py +7 -12
- slm/settings/validation.py +165 -165
- slm/signals.py +3 -2
- slm/static/slm/css/style.css +37 -36
- slm/static/slm/js/autocomplete.js +6 -4
- slm/static/slm/js/enums.js +6 -5
- slm/static/slm/js/file_modal.js +62 -0
- slm/static/slm/js/form.js +3 -3
- slm/static/slm/js/formWidget.js +3 -3
- slm/static/slm/js/persistable.js +5 -1
- slm/templates/admin/base.html +1 -0
- slm/templates/rest_framework/base.html +23 -11
- slm/templates/slm/base.html +27 -22
- slm/templates/slm/forms/widgets/auto_complete.html +12 -11
- slm/templates/slm/forms/widgets/auto_complete_multiple.html +8 -7
- slm/templates/slm/station/download.html +6 -6
- slm/templates/slm/station/edit.html +9 -17
- slm/templates/slm/station/review.html +5 -3
- slm/templates/slm/station/upload.html +4 -1
- slm/templates/slm/station/uploads/legacy.html +1 -1
- slm/templates/slm/widgets/alert_scroll.html +4 -8
- slm/templates/slm/widgets/filelist.html +0 -5
- slm/templates/slm/widgets/log_scroll.html +2 -13
- slm/templates/slm/widgets/stationlist.html +2 -8
- slm/templatetags/slm.py +70 -9
- slm/utils.py +13 -4
- slm/validators.py +14 -14
- slm/views.py +6 -6
- slm/wsgi.py +16 -0
- igs_slm-0.1.4b0.dist-info/METADATA +0 -154
- igs_slm-0.1.4b0.dist-info/entry_points.txt +0 -3
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/urls.py +0 -7
- slm/bin/templates/{{ project_dir }}/sites/{{ site }}/validation.py +0 -11
- /slm/bin/templates/{{ project_dir }}/{sites → src/sites}/__init__.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{sites → src/sites}/{{ site }}/__init__.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{sites → src/sites}/{{ site }}/develop/local.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{sites → src/sites}/{{ site }}/develop/wsgi.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{sites → src/sites}/{{ site }}/manage.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{sites → src/sites}/{{ site }}/production/wsgi.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/__init__.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/admin.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/apps.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/management/__init__.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/management/commands/__init__.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/management/commands/import_archive.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/migrations/__init__.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/models.py +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/templates/slm/base.html +0 -0
- /slm/bin/templates/{{ project_dir }}/{{{ extension_app }} → src/{{ extension_app }}}/views.py +0 -0
|
@@ -22,7 +22,7 @@ from typing_extensions import Annotated
|
|
|
22
22
|
|
|
23
23
|
from slm.defines import ISOCountry
|
|
24
24
|
from slm.models import Network, Site, SiteAntenna, SiteReceiver
|
|
25
|
-
from slm.utils import dddmmss_ss_parts, xyz2llh
|
|
25
|
+
from slm.utils import dddmmss_ss_parts, transliterate, xyz2llh
|
|
26
26
|
|
|
27
27
|
DEFAULT_ANTEX = "https://files.igs.org/pub/station/general/igs20.atx.gz"
|
|
28
28
|
|
|
@@ -35,7 +35,7 @@ def sinex_time(time):
|
|
|
35
35
|
if time is None:
|
|
36
36
|
return "00:000:00000"
|
|
37
37
|
return (
|
|
38
|
-
f
|
|
38
|
+
f"{time.strftime('%y:%j')}:"
|
|
39
39
|
f"{time.hour * 60 * 60 + time.minute * 60 + time.second:05.0f}"
|
|
40
40
|
)
|
|
41
41
|
|
|
@@ -78,6 +78,7 @@ class Command(TyperCommand):
|
|
|
78
78
|
siteAnt: dict
|
|
79
79
|
atx: dict
|
|
80
80
|
sat_phase_center: dict
|
|
81
|
+
utf8: bool = False
|
|
81
82
|
|
|
82
83
|
suppressed_base_arguments = {
|
|
83
84
|
*TyperCommand.suppressed_base_arguments,
|
|
@@ -117,11 +118,18 @@ class Command(TyperCommand):
|
|
|
117
118
|
bool,
|
|
118
119
|
Option("--include-former", help=_("Include former sites in the list.")),
|
|
119
120
|
] = False,
|
|
121
|
+
utf8: Annotated[
|
|
122
|
+
bool,
|
|
123
|
+
Option(
|
|
124
|
+
"--utf8", help=_("Allow multi-byte UTF-8 characters in the output.")
|
|
125
|
+
),
|
|
126
|
+
] = False,
|
|
120
127
|
):
|
|
121
128
|
self.sinex_code = ""
|
|
122
129
|
self.siteAnt = rec_dd()
|
|
123
130
|
self.atx = rec_dd()
|
|
124
131
|
self.sat_phase_center = rec_dd()
|
|
132
|
+
self.utf8 = utf8
|
|
125
133
|
|
|
126
134
|
sites = Site.objects.all().order_by("name")
|
|
127
135
|
sites = sites.public() if include_former else sites.active()
|
|
@@ -144,52 +152,65 @@ class Command(TyperCommand):
|
|
|
144
152
|
|
|
145
153
|
output = self.stdout
|
|
146
154
|
if destination:
|
|
147
|
-
output = open(
|
|
155
|
+
output = open(
|
|
156
|
+
destination, "wt", encoding="ascii" if not self.utf8 else "utf8"
|
|
157
|
+
)
|
|
148
158
|
|
|
149
159
|
# write header
|
|
150
|
-
for line in self.header(antex_file):
|
|
160
|
+
for line in self.transliterate(self.header(antex_file)):
|
|
151
161
|
output.write(f"{line}\n")
|
|
152
162
|
|
|
153
163
|
# write SITE/ID section
|
|
154
|
-
for line in self.site_ids(sites):
|
|
164
|
+
for line in self.transliterate(self.site_ids(sites)):
|
|
155
165
|
output.write(f"{line}\n")
|
|
156
166
|
|
|
157
167
|
# write SITE/RECEIVER section
|
|
158
|
-
for line in self.site_receivers(sites):
|
|
168
|
+
for line in self.transliterate(self.site_receivers(sites)):
|
|
159
169
|
output.write(f"{line}\n")
|
|
160
170
|
|
|
161
171
|
# write SITE/ANTENNA section
|
|
162
|
-
for line in self.site_antennas(sites):
|
|
172
|
+
for line in self.transliterate(self.site_antennas(sites)):
|
|
163
173
|
output.write(f"{line}\n")
|
|
164
174
|
|
|
165
175
|
# write GPS/PHASECENTER section
|
|
166
|
-
for line in self.gps_phase_center():
|
|
176
|
+
for line in self.transliterate(self.gps_phase_center()):
|
|
167
177
|
output.write(f"{line}\n")
|
|
168
178
|
|
|
169
179
|
# write GAL/PHASECENTER section
|
|
170
|
-
for line in self.gal_phase_center():
|
|
180
|
+
for line in self.transliterate(self.gal_phase_center()):
|
|
171
181
|
output.write(f"{line}\n")
|
|
172
182
|
|
|
173
183
|
# write SITE/ECCENTRICITY
|
|
174
|
-
for line in self.site_eccentricity(sites):
|
|
184
|
+
for line in self.transliterate(self.site_eccentricity(sites)):
|
|
175
185
|
output.write(f"{line}\n")
|
|
176
186
|
|
|
177
187
|
# write SATELLITE/ID
|
|
178
|
-
for line in self.satellite_ids():
|
|
188
|
+
for line in self.transliterate(self.satellite_ids()):
|
|
179
189
|
output.write(f"{line}\n")
|
|
180
190
|
|
|
181
191
|
# write +SATELLITE/PHASE_CENTER
|
|
182
|
-
for line in self.satellite_phase_centers():
|
|
192
|
+
for line in self.transliterate(self.satellite_phase_centers()):
|
|
183
193
|
output.write(f"{line}\n")
|
|
184
194
|
|
|
185
195
|
# close out the file
|
|
186
|
-
for line in self.footer():
|
|
196
|
+
for line in self.transliterate(self.footer()):
|
|
187
197
|
output.write(f"{line}\n")
|
|
188
198
|
|
|
189
199
|
if destination:
|
|
190
200
|
output.close()
|
|
191
201
|
|
|
192
|
-
def
|
|
202
|
+
def transliterate(
|
|
203
|
+
self, utf8_str: t.Generator[str, None, None]
|
|
204
|
+
) -> t.Generator[str, None, None]:
|
|
205
|
+
"""
|
|
206
|
+
Transliterate utf8 -> ascii if we were told to.
|
|
207
|
+
"""
|
|
208
|
+
if self.utf8:
|
|
209
|
+
yield from utf8_str
|
|
210
|
+
for ustr in utf8_str:
|
|
211
|
+
yield transliterate(ustr)
|
|
212
|
+
|
|
213
|
+
def header(self, antex_file) -> t.Generator[str, None, None]:
|
|
193
214
|
now = datetime.now()
|
|
194
215
|
now_date = "%04d-%02d-%02dT%02d:%02d:%02d" % (
|
|
195
216
|
now.year,
|
|
@@ -217,19 +238,18 @@ class Command(TyperCommand):
|
|
|
217
238
|
yield " This file is generated daily from all current IGS site logs in"
|
|
218
239
|
yield " https://files.igs.org/pub/station/log/"
|
|
219
240
|
yield (
|
|
220
|
-
" Phase center offsets are a function of antenna type, using as "
|
|
221
|
-
"reference"
|
|
241
|
+
" Phase center offsets are a function of antenna type, using as reference"
|
|
222
242
|
)
|
|
223
|
-
yield f
|
|
243
|
+
yield f" {antex_file.rstrip('.gz')}"
|
|
224
244
|
yield "-FILE/COMMENT"
|
|
225
245
|
yield "+INPUT/ACKNOWLEDGMENTS"
|
|
226
246
|
yield " IGS International GNSS Service"
|
|
227
247
|
yield "-INPUT/ACKNOWLEDGMENTS"
|
|
228
248
|
|
|
229
|
-
def footer(self):
|
|
249
|
+
def footer(self) -> t.Generator[str, None, None]:
|
|
230
250
|
yield "%ENDSNX"
|
|
231
251
|
|
|
232
|
-
def site_ids(self, sites):
|
|
252
|
+
def site_ids(self, sites) -> t.Generator[str, None, None]:
|
|
233
253
|
sites = sites.with_location_fields().with_identification_fields()
|
|
234
254
|
yield "+SITE/ID"
|
|
235
255
|
yield (
|
|
@@ -247,7 +267,7 @@ class Command(TyperCommand):
|
|
|
247
267
|
llh = xyz2llh(site.xyz.coords)
|
|
248
268
|
location = html.unescape(
|
|
249
269
|
f"{site.city or site.state}"
|
|
250
|
-
f'
|
|
270
|
+
f"{',' if site.city or site.state else ''}{ctry}"
|
|
251
271
|
)[:21]
|
|
252
272
|
lat_deg, lat_min, lat_sec = dddmmss_ss_parts(llh[0])
|
|
253
273
|
|
|
@@ -268,7 +288,7 @@ class Command(TyperCommand):
|
|
|
268
288
|
)
|
|
269
289
|
yield "-SITE/ID"
|
|
270
290
|
|
|
271
|
-
def site_receivers(self, sites):
|
|
291
|
+
def site_receivers(self, sites) -> t.Generator[str, None, None]:
|
|
272
292
|
yield "+SITE/RECEIVER"
|
|
273
293
|
yield (
|
|
274
294
|
"*CODE PT SOLN T _DATA START_ __DATA_END__ ___RECEIVER_TYPE____ "
|
|
@@ -293,11 +313,10 @@ class Command(TyperCommand):
|
|
|
293
313
|
)
|
|
294
314
|
yield "-SITE/RECEIVER"
|
|
295
315
|
|
|
296
|
-
def site_antennas(self, sites):
|
|
316
|
+
def site_antennas(self, sites) -> t.Generator[str, None, None]:
|
|
297
317
|
yield "+SITE/ANTENNA"
|
|
298
318
|
yield (
|
|
299
|
-
"*CODE PT SOLN T _DATA START_ __DATA_END__ ____ANTENNA_TYPE____ "
|
|
300
|
-
"_S/N_ _DAZ"
|
|
319
|
+
"*CODE PT SOLN T _DATA START_ __DATA_END__ ____ANTENNA_TYPE____ _S/N_ _DAZ"
|
|
301
320
|
)
|
|
302
321
|
for site in sites.prefetch_related(
|
|
303
322
|
Prefetch(
|
|
@@ -321,7 +340,7 @@ class Command(TyperCommand):
|
|
|
321
340
|
# seems wrong
|
|
322
341
|
yield "-SITE/ANTENNA"
|
|
323
342
|
|
|
324
|
-
def gps_phase_center(self):
|
|
343
|
+
def gps_phase_center(self) -> t.Generator[str, None, None]:
|
|
325
344
|
yield "+SITE/GPS_PHASE_CENTER"
|
|
326
345
|
yield (
|
|
327
346
|
"*ANTENNA_NAME____DOME S_NO_ __UP__ NORTH_ _EAST_ __UP__ NORTH_ "
|
|
@@ -330,23 +349,23 @@ class Command(TyperCommand):
|
|
|
330
349
|
for ant in sorted(self.siteAnt):
|
|
331
350
|
if "G02" in self.siteAnt[ant]:
|
|
332
351
|
yield (
|
|
333
|
-
f
|
|
334
|
-
f
|
|
335
|
-
f
|
|
336
|
-
f
|
|
337
|
-
f
|
|
338
|
-
f
|
|
352
|
+
f" {ant:20} ----- {self.siteAnt[ant]['G01']['up']:6.6} "
|
|
353
|
+
f"{self.siteAnt[ant]['G01']['north']:6.6} "
|
|
354
|
+
f"{self.siteAnt[ant]['G01']['east']:6.6} "
|
|
355
|
+
f"{self.siteAnt[ant]['G02']['up']:6.6} "
|
|
356
|
+
f"{self.siteAnt[ant]['G02']['north']:6.6} "
|
|
357
|
+
f"{self.siteAnt[ant]['G02']['east']:6.6} {self.sinex_code:10.10}"
|
|
339
358
|
)
|
|
340
359
|
else:
|
|
341
360
|
yield (
|
|
342
|
-
f
|
|
343
|
-
f
|
|
344
|
-
f
|
|
361
|
+
f" {ant:20} ----- {self.siteAnt[ant]['G01']['up']:6.6} "
|
|
362
|
+
f"{self.siteAnt[ant]['G01']['north']:6.6} "
|
|
363
|
+
f"{self.siteAnt[ant]['G01']['east']:6.6} ------ ------ ------ "
|
|
345
364
|
f"{self.sinex_code:10.10}"
|
|
346
365
|
)
|
|
347
366
|
yield "-SITE/GPS_PHASE_CENTER"
|
|
348
367
|
|
|
349
|
-
def gal_phase_center(self):
|
|
368
|
+
def gal_phase_center(self) -> t.Generator[str, None, None]:
|
|
350
369
|
yield "+SITE/GAL_PHASE_CENTER"
|
|
351
370
|
yield (
|
|
352
371
|
"*ANTENNA_NAME____DOME S_NO_ __UP__ NORTH_ _EAST_ __UP__ NORTH_ "
|
|
@@ -355,17 +374,17 @@ class Command(TyperCommand):
|
|
|
355
374
|
for ant in sorted(self.siteAnt):
|
|
356
375
|
if "E01" in self.siteAnt[ant]:
|
|
357
376
|
_e01 = (
|
|
358
|
-
f
|
|
359
|
-
f
|
|
360
|
-
f
|
|
377
|
+
f"{self.siteAnt[ant]['E01']['up']:6.6} "
|
|
378
|
+
f"{self.siteAnt[ant]['E01']['north']:6.6} "
|
|
379
|
+
f"{self.siteAnt[ant]['E01']['east']:6.6}"
|
|
361
380
|
)
|
|
362
381
|
else:
|
|
363
382
|
_e01 = "------ ------ ------"
|
|
364
383
|
if "E05" in self.siteAnt[ant]:
|
|
365
384
|
_e05 = (
|
|
366
|
-
f
|
|
367
|
-
f
|
|
368
|
-
f
|
|
385
|
+
f"{self.siteAnt[ant]['E05']['up']:6.6} "
|
|
386
|
+
f"{self.siteAnt[ant]['E05']['north']:6.6} "
|
|
387
|
+
f"{self.siteAnt[ant]['E05']['east']:6.6}"
|
|
369
388
|
)
|
|
370
389
|
else:
|
|
371
390
|
_e05 = "------ ------ ------"
|
|
@@ -373,17 +392,17 @@ class Command(TyperCommand):
|
|
|
373
392
|
|
|
374
393
|
if "E06" in self.siteAnt[ant]:
|
|
375
394
|
_e06 = (
|
|
376
|
-
f
|
|
377
|
-
f
|
|
378
|
-
f
|
|
395
|
+
f"{self.siteAnt[ant]['E06']['up']:6.6} "
|
|
396
|
+
f"{self.siteAnt[ant]['E06']['north']:6.6} "
|
|
397
|
+
f"{self.siteAnt[ant]['E06']['east']:6.6}"
|
|
379
398
|
)
|
|
380
399
|
else:
|
|
381
400
|
_e06 = "------ ------ ------"
|
|
382
401
|
if "E07" in self.siteAnt[ant]:
|
|
383
402
|
_e07 = (
|
|
384
|
-
f
|
|
385
|
-
f
|
|
386
|
-
f
|
|
403
|
+
f"{self.siteAnt[ant]['E07']['up']:6.6} "
|
|
404
|
+
f"{self.siteAnt[ant]['E07']['north']:6.6} "
|
|
405
|
+
f"{self.siteAnt[ant]['E07']['east']:6.6}"
|
|
387
406
|
)
|
|
388
407
|
else:
|
|
389
408
|
_e07 = "------ ------ ------"
|
|
@@ -391,9 +410,9 @@ class Command(TyperCommand):
|
|
|
391
410
|
|
|
392
411
|
if "E08" in self.siteAnt[ant]:
|
|
393
412
|
_e08 = (
|
|
394
|
-
f
|
|
395
|
-
f
|
|
396
|
-
f
|
|
413
|
+
f"{self.siteAnt[ant]['E08']['up']:6.6} "
|
|
414
|
+
f"{self.siteAnt[ant]['E08']['north']:6.6} "
|
|
415
|
+
f"{self.siteAnt[ant]['E08']['east']:6.6}"
|
|
397
416
|
)
|
|
398
417
|
else:
|
|
399
418
|
_e08 = "------ ------ ------"
|
|
@@ -401,11 +420,10 @@ class Command(TyperCommand):
|
|
|
401
420
|
yield f" {ant} ---- {_e08} ------ ------ ------ {self.sinex_code:10s}"
|
|
402
421
|
yield "-SITE/GAL_PHASE_CENTER"
|
|
403
422
|
|
|
404
|
-
def site_eccentricity(self, sites):
|
|
423
|
+
def site_eccentricity(self, sites) -> t.Generator[str, None, None]:
|
|
405
424
|
yield "+SITE/ECCENTRICITY"
|
|
406
425
|
yield (
|
|
407
|
-
"*CODE PT SOLN T _DATA START_ __DATA_END__ REF __DX_U__ __DX_N__ "
|
|
408
|
-
"__DX_E__"
|
|
426
|
+
"*CODE PT SOLN T _DATA START_ __DATA_END__ REF __DX_U__ __DX_N__ __DX_E__"
|
|
409
427
|
)
|
|
410
428
|
for site in sites.prefetch_related(
|
|
411
429
|
Prefetch(
|
|
@@ -424,39 +442,39 @@ class Command(TyperCommand):
|
|
|
424
442
|
)
|
|
425
443
|
yield "-SITE/ECCENTRICITY"
|
|
426
444
|
|
|
427
|
-
def satellite_ids(self):
|
|
445
|
+
def satellite_ids(self) -> t.Generator[str, None, None]:
|
|
428
446
|
yield "+SATELLITE/ID"
|
|
429
|
-
yield ("*CNNN PN COSPARID_ T _START_DATE_ __END_DATE__
|
|
447
|
+
yield ("*CNNN PN COSPARID_ T _START_DATE_ __END_DATE__ ____ANTENNA_TYPE____")
|
|
430
448
|
for sat in sorted(self.atx):
|
|
431
449
|
for startDate in self.atx[sat]:
|
|
432
450
|
yield (
|
|
433
|
-
f
|
|
434
|
-
f
|
|
435
|
-
f
|
|
436
|
-
f
|
|
451
|
+
f" {sat:.4s} {self.atx[sat][startDate]['prn']:.2s} "
|
|
452
|
+
f"{self.atx[sat][startDate]['cospar_id']:.9s} P "
|
|
453
|
+
f"{startDate:.12s} {self.atx[sat][startDate]['endDate']:.12s} "
|
|
454
|
+
f"{self.atx[sat][startDate]['name']:.20s}"
|
|
437
455
|
)
|
|
438
456
|
yield "-SATELLITE/ID"
|
|
439
457
|
|
|
440
|
-
def satellite_phase_centers(self):
|
|
458
|
+
def satellite_phase_centers(self) -> t.Generator[str, None, None]:
|
|
441
459
|
yield "+SATELLITE/PHASE_CENTER"
|
|
442
|
-
yield ("*CNNN F __UP__ NORTH_ _EAST_ F __UP__ NORTH_ _EAST_
|
|
460
|
+
yield ("*CNNN F __UP__ NORTH_ _EAST_ F __UP__ NORTH_ _EAST_ SINEXCODE_ V M")
|
|
443
461
|
for sat in sorted(self.sat_phase_center):
|
|
444
462
|
if sat.startswith("G"):
|
|
445
463
|
yield (
|
|
446
|
-
f
|
|
447
|
-
f
|
|
448
|
-
f
|
|
449
|
-
f
|
|
450
|
-
f
|
|
451
|
-
f
|
|
464
|
+
f" {sat:4.4} 1 {self.sat_phase_center[sat]['G01']['up']:6.6} "
|
|
465
|
+
f"{self.sat_phase_center[sat]['G01']['north']:6.6} "
|
|
466
|
+
f"{self.sat_phase_center[sat]['G01']['east']:6.6} 2 "
|
|
467
|
+
f"{self.sat_phase_center[sat]['G02']['up']:6.6} "
|
|
468
|
+
f"{self.sat_phase_center[sat]['G02']['north']:6.6} "
|
|
469
|
+
f"{self.sat_phase_center[sat]['G02']['east']:6.6} "
|
|
452
470
|
f"{self.sinex_code:10.10} A E"
|
|
453
471
|
)
|
|
454
472
|
try:
|
|
455
473
|
yield (
|
|
456
474
|
f" {sat:4.4} 5 "
|
|
457
|
-
f
|
|
458
|
-
f
|
|
459
|
-
f
|
|
475
|
+
f"{self.sat_phase_center[sat]['G05']['up']:6.6} "
|
|
476
|
+
f"{self.sat_phase_center[sat]['G05']['north']:6.6} "
|
|
477
|
+
f"{self.sat_phase_center[sat]['G05']['east']:6.6} - ------ "
|
|
460
478
|
f"------ ------ {self.sinex_code:10.10} A E"
|
|
461
479
|
)
|
|
462
480
|
except Exception:
|
|
@@ -464,44 +482,44 @@ class Command(TyperCommand):
|
|
|
464
482
|
|
|
465
483
|
if sat.startswith("R"):
|
|
466
484
|
yield (
|
|
467
|
-
f
|
|
468
|
-
f
|
|
469
|
-
f
|
|
470
|
-
f
|
|
471
|
-
f
|
|
472
|
-
f
|
|
485
|
+
f" {sat:4.4} 1 {self.sat_phase_center[sat]['R01']['up']:6.6} "
|
|
486
|
+
f"{self.sat_phase_center[sat]['R01']['north']:6.6} "
|
|
487
|
+
f"{self.sat_phase_center[sat]['R01']['east']:6.6} 2 "
|
|
488
|
+
f"{self.sat_phase_center[sat]['R02']['up']:6.6} "
|
|
489
|
+
f"{self.sat_phase_center[sat]['R02']['north']:6.6} "
|
|
490
|
+
f"{self.sat_phase_center[sat]['R02']['east']:6.6} "
|
|
473
491
|
f"{self.sinex_code:10.10} A E"
|
|
474
492
|
)
|
|
475
493
|
|
|
476
494
|
if sat.startswith("E"):
|
|
477
495
|
yield (
|
|
478
|
-
f
|
|
479
|
-
f
|
|
480
|
-
f
|
|
481
|
-
f
|
|
482
|
-
f
|
|
483
|
-
f
|
|
496
|
+
f" {sat:4.4} 1 {self.sat_phase_center[sat]['E01']['up']:6.6} "
|
|
497
|
+
f"{self.sat_phase_center[sat]['E01']['north']:6.6} "
|
|
498
|
+
f"{self.sat_phase_center[sat]['E01']['east']:6.6} 5 "
|
|
499
|
+
f"{self.sat_phase_center[sat]['E05']['up']:6.6} "
|
|
500
|
+
f"{self.sat_phase_center[sat]['E05']['north']:6.6} "
|
|
501
|
+
f"{self.sat_phase_center[sat]['E05']['east']:6.6} "
|
|
484
502
|
f"{self.sinex_code:10.10} A E"
|
|
485
503
|
)
|
|
486
504
|
yield (
|
|
487
|
-
f
|
|
488
|
-
f
|
|
489
|
-
f
|
|
490
|
-
f
|
|
491
|
-
f
|
|
492
|
-
f
|
|
505
|
+
f" {sat:4.4} 6 {self.sat_phase_center[sat]['E06']['up']:6.6} "
|
|
506
|
+
f"{self.sat_phase_center[sat]['E06']['north']:6.6} "
|
|
507
|
+
f"{self.sat_phase_center[sat]['E06']['east']:6.6} 7 "
|
|
508
|
+
f"{self.sat_phase_center[sat]['E07']['up']:6.6} "
|
|
509
|
+
f"{self.sat_phase_center[sat]['E07']['north']:6.6} "
|
|
510
|
+
f"{self.sat_phase_center[sat]['E07']['east']:6.6} "
|
|
493
511
|
f"{self.sinex_code:10.10} A E"
|
|
494
512
|
)
|
|
495
513
|
yield (
|
|
496
514
|
f" {sat:4.4} 8 "
|
|
497
|
-
f
|
|
498
|
-
f
|
|
499
|
-
f
|
|
515
|
+
f"{self.sat_phase_center[sat]['E08']['up']:6.6} "
|
|
516
|
+
f"{self.sat_phase_center[sat]['E08']['north']:6.6} "
|
|
517
|
+
f"{self.sat_phase_center[sat]['E08']['east']:6.6} - ------ "
|
|
500
518
|
f"------ ------ {self.sinex_code:10.10} A E"
|
|
501
519
|
)
|
|
502
520
|
yield "-SATELLITE/PHASE_CENTER"
|
|
503
521
|
|
|
504
|
-
def build_antex_index(self, antex_file):
|
|
522
|
+
def build_antex_index(self, antex_file: str):
|
|
505
523
|
"""
|
|
506
524
|
Streams the antex file from files.igs.org and builds an index off of
|
|
507
525
|
it.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"""
|
|
2
2
|
If your site log file index is more current than the database state
|
|
3
|
-
(i.e. you've run :
|
|
3
|
+
(i.e. you've run :django-admin:`import_archive`), you may run this command to pull data
|
|
4
4
|
from the most recent indexed files into the database.
|
|
5
5
|
|
|
6
6
|
.. tip::
|
|
7
7
|
|
|
8
8
|
By default, rich HTML logs of the import process will be written to:
|
|
9
9
|
|
|
10
|
-
``settings.
|
|
10
|
+
``settings.SLM_LOG_DIR / head_from_index.TIMESTAMP``
|
|
11
11
|
|
|
12
12
|
ImportAlerts will also be issued for any errors flagged during import. When,
|
|
13
13
|
appropriate validation flags will be attached to site log fields. This allows you
|
|
@@ -85,7 +85,7 @@ class Command(TyperCommand):
|
|
|
85
85
|
sites: t.Sequence[Site]
|
|
86
86
|
clean: bool = True
|
|
87
87
|
prompt: bool = True
|
|
88
|
-
logs: Path = Path("{
|
|
88
|
+
logs: Path = Path("{SLM_LOG_DIR}") / "head_from_index.{TIMESTAMP}"
|
|
89
89
|
verbosity = 1
|
|
90
90
|
|
|
91
91
|
indexes: t.Sequence[ArchiveIndex]
|
|
@@ -184,7 +184,7 @@ class Command(TyperCommand):
|
|
|
184
184
|
|
|
185
185
|
self.logs = Path(
|
|
186
186
|
str(logs).format(
|
|
187
|
-
|
|
187
|
+
SLM_LOG_DIR=getattr(settings, "SLM_LOG_DIR", "./"),
|
|
188
188
|
TIMESTAMP=datetime.now().strftime("%Y-%m-%d_%H-%M-%S"),
|
|
189
189
|
)
|
|
190
190
|
)
|
|
@@ -214,8 +214,10 @@ class Command(TyperCommand):
|
|
|
214
214
|
self.failed_imports = []
|
|
215
215
|
|
|
216
216
|
self.indexes = (
|
|
217
|
-
ArchiveIndex.objects.filter(
|
|
218
|
-
|
|
217
|
+
ArchiveIndex.objects.filter(
|
|
218
|
+
site__in=self.sites, valid_range__upper_inf=True
|
|
219
|
+
)
|
|
220
|
+
.order_by("site", "-valid_range")
|
|
219
221
|
.distinct("site")
|
|
220
222
|
)
|
|
221
223
|
|
|
@@ -465,9 +467,10 @@ class Command(TyperCommand):
|
|
|
465
467
|
setattr(form, field, value)
|
|
466
468
|
form.previous = (
|
|
467
469
|
ArchiveIndex.objects.filter(
|
|
468
|
-
site=index.site,
|
|
470
|
+
site=index.site,
|
|
471
|
+
valid_range__startswith__lte=index.begin,
|
|
469
472
|
)
|
|
470
|
-
.order_by("-
|
|
473
|
+
.order_by("-valid_range")
|
|
471
474
|
.first()
|
|
472
475
|
)
|
|
473
476
|
form.save(skip_update=True, set_previous=False)
|
|
@@ -3,17 +3,17 @@ When transitioning site log management into an SLM you will have to import all o
|
|
|
3
3
|
existing data. There are two primary steps involved in doing this:
|
|
4
4
|
|
|
5
5
|
1. Import the index of existing serialized point in time site logs.
|
|
6
|
-
2. Populate the
|
|
6
|
+
2. Populate the site log fields in the database from the most recent site logs for each
|
|
7
7
|
station.
|
|
8
8
|
|
|
9
|
-
This command will perform #1 and optionally call :
|
|
9
|
+
This command will perform #1 and optionally call :django-admin:`head_from_index` on the
|
|
10
10
|
imported stations to also perform #2.
|
|
11
11
|
|
|
12
12
|
.. tip::
|
|
13
13
|
|
|
14
14
|
Rich HTML logs of the import process will be written to:
|
|
15
15
|
|
|
16
|
-
``settings.
|
|
16
|
+
``settings.SLM_LOG_DIR / import_archive.TIMESTAMP``
|
|
17
17
|
|
|
18
18
|
Logs will be parsed and errors reported, but parsing errors will not prevent logs from
|
|
19
19
|
being indexed.
|
|
@@ -185,7 +185,7 @@ class Command(TyperCommand):
|
|
|
185
185
|
agencies: t.List[Agency] = []
|
|
186
186
|
owner: t.Optional[User] = None
|
|
187
187
|
|
|
188
|
-
logs: Path = Path("{
|
|
188
|
+
logs: Path = Path("{SLM_LOG_DIR}") / "import_archive.{TIMESTAMP}"
|
|
189
189
|
verbosity: int = 1
|
|
190
190
|
traceback: bool = False
|
|
191
191
|
|
|
@@ -194,9 +194,9 @@ class Command(TyperCommand):
|
|
|
194
194
|
|
|
195
195
|
# this matches fourYYMM.log and four_YYYYMMDD.log styles
|
|
196
196
|
FILE_NAME_REGEX = re.compile(
|
|
197
|
-
r"^((?P<four_id>[a-zA-Z\d]{4})(?P<yymm>\d{4})
|
|
198
|
-
r"((?P<site>[a-zA-Z\d]{4,
|
|
199
|
-
r"[.](?P<ext>(log)|(txt)|(xml))$"
|
|
197
|
+
r"^((?P<four_id>[a-zA-Z\d]{4})(?P<yymm>\d{4})?|"
|
|
198
|
+
r"((?P<site>[a-zA-Z\d]{4,})?\D*(?P<date_part>\d{8})?(?P<extra>.*)?))"
|
|
199
|
+
r"[.](?P<ext>(log)|(sitelog)|(txt)|(xml)|(gml)|(json))$"
|
|
200
200
|
)
|
|
201
201
|
|
|
202
202
|
def process_filename(
|
|
@@ -381,7 +381,9 @@ class Command(TyperCommand):
|
|
|
381
381
|
traceback: Traceback = traceback,
|
|
382
382
|
):
|
|
383
383
|
if not archive:
|
|
384
|
-
archive = Path(
|
|
384
|
+
archive = Path(
|
|
385
|
+
input(_("Where is the archive? (directory or tar/zip): ")).strip()
|
|
386
|
+
)
|
|
385
387
|
self.archive = archive.expanduser()
|
|
386
388
|
if not self.archive.exists():
|
|
387
389
|
raise CommandError(
|
|
@@ -394,7 +396,7 @@ class Command(TyperCommand):
|
|
|
394
396
|
self.owner = owner
|
|
395
397
|
self.logs = Path(
|
|
396
398
|
str(logs).format(
|
|
397
|
-
|
|
399
|
+
SLM_LOG_DIR=getattr(settings, "SLM_LOG_DIR", "./"),
|
|
398
400
|
TIMESTAMP=datetime.now().strftime("%Y-%m-%d_%H-%M-%S"),
|
|
399
401
|
)
|
|
400
402
|
)
|
|
@@ -414,10 +416,11 @@ class Command(TyperCommand):
|
|
|
414
416
|
if not self.archive.exists():
|
|
415
417
|
raise CommandError(_("{file} does not exist.").format(file=self.archive))
|
|
416
418
|
|
|
417
|
-
if SiteLogFormat.GEODESY_ML in self.formats:
|
|
418
|
-
|
|
419
|
+
# if SiteLogFormat.GEODESY_ML in self.formats:
|
|
420
|
+
# # TODO - only do this if necessary
|
|
421
|
+
# from slm.parsing.xsd import load_schemas
|
|
419
422
|
|
|
420
|
-
|
|
423
|
+
# load_schemas()
|
|
421
424
|
|
|
422
425
|
if self.archive.is_file() and tarfile.is_tarfile(self.archive):
|
|
423
426
|
with tarfile.open(self.archive, "r") as archive:
|
|
@@ -451,7 +454,7 @@ class Command(TyperCommand):
|
|
|
451
454
|
if self.verbosity > 1:
|
|
452
455
|
self.secho(
|
|
453
456
|
_(
|
|
454
|
-
"Unable to interpret {filename} as a
|
|
457
|
+
"Unable to interpret {filename} as a site log."
|
|
455
458
|
).format(filename=archive_name),
|
|
456
459
|
fg="red",
|
|
457
460
|
)
|
|
@@ -503,7 +506,7 @@ class Command(TyperCommand):
|
|
|
503
506
|
if self.verbosity > 1:
|
|
504
507
|
self.secho(
|
|
505
508
|
_(
|
|
506
|
-
"Unable to interpret {filename} as a
|
|
509
|
+
"Unable to interpret {filename} as a site log."
|
|
507
510
|
).format(filename=file.name),
|
|
508
511
|
fg="red",
|
|
509
512
|
)
|
|
@@ -537,7 +540,7 @@ class Command(TyperCommand):
|
|
|
537
540
|
if not file_meta:
|
|
538
541
|
raise CommandError(
|
|
539
542
|
_(
|
|
540
|
-
"Unable to interpret {file} as either an tar archive or a
|
|
543
|
+
"Unable to interpret {file} as either an tar archive or a site log."
|
|
541
544
|
).format(file=self.archive)
|
|
542
545
|
)
|
|
543
546
|
file_meta.contents = self.archive.read_bytes()
|
|
@@ -582,7 +585,9 @@ class Command(TyperCommand):
|
|
|
582
585
|
_("Updating {site} state.").format(site=site.name), fg="blue"
|
|
583
586
|
)
|
|
584
587
|
save = False
|
|
585
|
-
recent_first = ArchiveIndex.objects.filter(site=site).order_by(
|
|
588
|
+
recent_first = ArchiveIndex.objects.filter(site=site).order_by(
|
|
589
|
+
"-valid_range"
|
|
590
|
+
)
|
|
586
591
|
latest = recent_first.first()
|
|
587
592
|
oldest = recent_first.last()
|
|
588
593
|
if site.last_publish is None or site.last_publish < latest.begin:
|
|
@@ -684,8 +689,12 @@ class Command(TyperCommand):
|
|
|
684
689
|
with open(log, "wt") as log_f:
|
|
685
690
|
log_f.write(log_index)
|
|
686
691
|
|
|
687
|
-
if log
|
|
688
|
-
|
|
692
|
+
if log:
|
|
693
|
+
import webbrowser
|
|
694
|
+
|
|
695
|
+
webbrowser.open(log.resolve().as_uri())
|
|
696
|
+
if self.verbosity > 0:
|
|
697
|
+
return log.absolute()
|
|
689
698
|
|
|
690
699
|
def process_file(self, file_meta: FileMeta):
|
|
691
700
|
with transaction.atomic():
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Station equipment including Antennas, Radomes and Receivers are coded by IGS and
|
|
3
3
|
those standard codes are used to uniquely identify equipment in site log files.
|
|
4
4
|
|
|
5
|
-
The full IGS
|
|
5
|
+
The full IGS change log for equipment codes is recorded in rcvr_ant.tab_.
|
|
6
6
|
|
|
7
7
|
The SLM stores these codes in database tables, so it is possible to instantiate an
|
|
8
8
|
SLM with a different set of equipment codes. This command can be used to load codes
|
|
@@ -118,9 +118,7 @@ class Command(TyperCommand):
|
|
|
118
118
|
if self.archive:
|
|
119
119
|
index = ArchiveIndex.objects.filter(site=self.site).first()
|
|
120
120
|
qry = Q(log_format=SiteLogFormat.GEODESY_ML)
|
|
121
|
-
qry &= Q(
|
|
122
|
-
Q(index__end__gt=self.archive) | Q(index__end__isnull=True)
|
|
123
|
-
)
|
|
121
|
+
qry &= Q(index__valid_range__contains=self.archive)
|
|
124
122
|
if gml_version:
|
|
125
123
|
qry &= Q(gml_version=gml_version)
|
|
126
124
|
log_file = index.files.filter(qry).first()
|
|
@@ -9,7 +9,7 @@ Some examples of denormalized state in the SLM include:
|
|
|
9
9
|
|
|
10
10
|
* Counts of validation flags
|
|
11
11
|
* Maximum alert levels for stations
|
|
12
|
-
*
|
|
12
|
+
* Site log status indicators (PUBLISHED/UNPUBLISHED) for stations.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
import typing as t
|