diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 84a0b6c..cf21609 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -1,9 +1,10 @@ site_name: Jane repo_url: https://github.com/krischer/jane/ use_directory_urls: false -theme: cosmo +theme: + name: mkdocs copyright: Jane Developers, 2014-2016 -pages: +nav: - 'Home': 'index.md' - 'Introduction': 'introduction.md' - 'Details': diff --git a/src/jane/documents/admin.py b/src/jane/documents/admin.py index d819a87..ae7ffa6 100644 --- a/src/jane/documents/admin.py +++ b/src/jane/documents/admin.py @@ -4,8 +4,8 @@ from django.conf.urls import url from django.contrib.gis import admin -from django.core.urlresolvers import reverse from django.http import HttpResponse +from django.urls import reverse from jane.documents import models diff --git a/src/jane/documents/migrations/0001_initial.py b/src/jane/documents/migrations/0001_initial.py index 912d093..68a4c20 100644 --- a/src/jane/documents/migrations/0001_initial.py +++ b/src/jane/documents/migrations/0001_initial.py @@ -3,8 +3,8 @@ from django.conf import settings import django.contrib.gis.db.models.fields -from django.contrib.postgres.fields import jsonb from django.db import models, migrations +from django.db.models import JSONField import djangoplugins.fields @@ -27,7 +27,7 @@ class Migration(migrations.Migration): ('sha1', models.CharField(unique=True, db_index=True, max_length=40, editable=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('modified_at', models.DateTimeField(auto_now=True)), - ('created_by', models.ForeignKey(related_name='documents_created', to=settings.AUTH_USER_MODEL)), + ('created_by', models.ForeignKey(related_name='documents_created', on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'Document', @@ -39,9 +39,9 @@ class Migration(migrations.Migration): name='DocumentIndex', fields=[ ('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), - ('json', jsonb.JSONField(verbose_name='JSON')), + ('json', JSONField(verbose_name='JSON')), ('geometry', django.contrib.gis.db.models.fields.GeometryCollectionField(srid=4326, geography=True, blank=True, null=True)), - ('document', models.ForeignKey(related_name='indices', to='documents.Document')), + ('document', models.ForeignKey(related_name='indices', to='documents.Document', on_delete=models.CASCADE)), ], options={ 'verbose_name': 'Index', @@ -58,9 +58,9 @@ class Migration(migrations.Migration): ('data', models.BinaryField()), ('created_at', models.DateTimeField(auto_now_add=True)), ('modified_at', models.DateTimeField(auto_now=True)), - ('created_by', models.ForeignKey(related_name='attachments_created', to=settings.AUTH_USER_MODEL)), - ('index', models.ForeignKey(related_name='attachments', to='documents.DocumentIndex')), - ('modified_by', models.ForeignKey(related_name='attachments_modified', to=settings.AUTH_USER_MODEL)), + ('created_by', models.ForeignKey(related_name='attachments_created', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), + ('index', models.ForeignKey(related_name='attachments', to='documents.DocumentIndex', on_delete=models.CASCADE)), + ('modified_by', models.ForeignKey(related_name='attachments_modified', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), ], options={ 'verbose_name': 'Attachment', @@ -87,12 +87,12 @@ class Migration(migrations.Migration): migrations.AddField( model_name='document', name='document_type', - field=models.ForeignKey(related_name='documents', to='documents.DocumentType'), + field=models.ForeignKey(related_name='documents', to='documents.DocumentType', on_delete=models.CASCADE), ), migrations.AddField( model_name='document', name='modified_by', - field=models.ForeignKey(related_name='documents_modified', to=settings.AUTH_USER_MODEL), + field=models.ForeignKey(related_name='documents_modified', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE), ), migrations.AlterUniqueTogether( name='document', diff --git a/src/jane/documents/migrations/0003_auto_20241025_1136.py b/src/jane/documents/migrations/0003_auto_20241025_1136.py new file mode 100644 index 0000000..a7404f6 --- /dev/null +++ b/src/jane/documents/migrations/0003_auto_20241025_1136.py @@ -0,0 +1,41 @@ +# Generated by Django 3.2.19 on 2024-10-25 11:36 + +from django.db import migrations +import django.db.models.deletion +import djangoplugins.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('djangoplugins', '0002_add_id_to_plugins_uniq'), + ('documents', '0002_auto_20161018_0646'), + ] + + operations = [ + migrations.AlterField( + model_name='documenttype', + name='definition', + field=djangoplugins.fields.PluginField(limit_choices_to={'point__pythonpath': 'jane.documents.plugins.DocumentPluginPoint'}, on_delete=django.db.models.deletion.CASCADE, related_name='definition', to='djangoplugins.plugin'), + ), + migrations.AlterField( + model_name='documenttype', + name='indexer', + field=djangoplugins.fields.PluginField(limit_choices_to={'point__pythonpath': 'jane.documents.plugins.IndexerPluginPoint'}, on_delete=django.db.models.deletion.CASCADE, related_name='indexer', to='djangoplugins.plugin'), + ), + migrations.AlterField( + model_name='documenttype', + name='retrieve_permissions', + field=djangoplugins.fields.ManyPluginField(blank=True, limit_choices_to={'point__pythonpath': 'jane.documents.plugins.RetrievePermissionPluginPoint'}, related_name='retrieve_permissions', to='djangoplugins.Plugin'), + ), + migrations.AlterField( + model_name='documenttype', + name='upload_permissions', + field=djangoplugins.fields.ManyPluginField(blank=True, limit_choices_to={'point__pythonpath': 'jane.documents.plugins.UploadPermissionPluginPoint'}, related_name='upload_permissions', to='djangoplugins.Plugin'), + ), + migrations.AlterField( + model_name='documenttype', + name='validators', + field=djangoplugins.fields.ManyPluginField(blank=True, limit_choices_to={'point__pythonpath': 'jane.documents.plugins.ValidatorPluginPoint'}, related_name='validators', to='djangoplugins.Plugin'), + ), + ] diff --git a/src/jane/documents/models.py b/src/jane/documents/models.py index 42c2fd7..82e9f62 100644 --- a/src/jane/documents/models.py +++ b/src/jane/documents/models.py @@ -21,14 +21,14 @@ from django.contrib.auth.models import AnonymousUser from django.contrib.gis.db import models from django.contrib.gis.measure import Distance -from django.contrib.postgres.fields import jsonb -from django.core.urlresolvers import reverse from django.db import connection +from django.db.models import JSONField from django.db.models.aggregates import Count from django.db.models.expressions import OrderBy, RawSQL from django.http import Http404 from django.shortcuts import get_object_or_404 from django.template.defaultfilters import filesizeformat +from django.urls import reverse from djangoplugins.fields import PluginField, ManyPluginField from obspy.core.utcdatetime import UTCDateTime from rest_framework import status @@ -171,7 +171,8 @@ class Document(models.Model): any type that is described by indices. """ # The type of the document. Depends on the available Jane plug-ins. - document_type = models.ForeignKey(DocumentType, related_name='documents') + document_type = models.ForeignKey(DocumentType, related_name='documents', + on_delete=models.CASCADE) # The name of that particular document. Oftentimes the filename. Unique # together with the document type to enable a nice REST API. name = models.CharField(max_length=255, db_index=True) @@ -189,9 +190,11 @@ class Document(models.Model): modified_at = models.DateTimeField(auto_now=True, editable=False) # Users responsible for the aforementioned actions. created_by = models.ForeignKey(settings.AUTH_USER_MODEL, - related_name='documents_created') + related_name='documents_created', + on_delete=models.CASCADE) modified_by = models.ForeignKey(settings.AUTH_USER_MODEL, - related_name='documents_modified') + related_name='documents_modified', + on_delete=models.CASCADE) objects = DocumentManager() class Meta: @@ -228,7 +231,7 @@ def save(self, *args, **kwargs): signals.index_document(sender=None, instance=self, created=None) -class DocumentIndexManager(models.GeoManager): +class DocumentIndexManager(models.Manager): """ Custom queryset manager for the document indices. """ @@ -504,8 +507,9 @@ class DocumentIndex(models.Model): """ Indexed values for a specific document. """ - document = models.ForeignKey(Document, related_name='indices') - json = jsonb.JSONField(verbose_name="JSON") + document = models.ForeignKey(Document, related_name='indices', + on_delete=models.CASCADE) + json = JSONField(verbose_name="JSON") geometry = models.GeometryCollectionField(blank=True, null=True, geography=True) @@ -653,7 +657,8 @@ class DocumentIndexAttachment(models.Model): """ Attachments for one Document. """ - index = models.ForeignKey(DocumentIndex, related_name='attachments') + index = models.ForeignKey(DocumentIndex, related_name='attachments', + on_delete=models.CASCADE) category = models.CharField(max_length=50, db_index=True) content_type = models.CharField(max_length=255) data = models.BinaryField() @@ -663,9 +668,11 @@ class DocumentIndexAttachment(models.Model): modified_at = models.DateTimeField(auto_now=True, editable=False) # Users responsible for the aforementioned actions. created_by = models.ForeignKey(settings.AUTH_USER_MODEL, - related_name='attachments_created') + related_name='attachments_created', + on_delete=models.CASCADE) modified_by = models.ForeignKey(settings.AUTH_USER_MODEL, - related_name='attachments_modified') + related_name='attachments_modified', + on_delete=models.CASCADE) objects = DocumentIndexAttachmentManager() class Meta: diff --git a/src/jane/documents/plugins.py b/src/jane/documents/plugins.py index ce3d582..529d076 100644 --- a/src/jane/documents/plugins.py +++ b/src/jane/documents/plugins.py @@ -171,9 +171,9 @@ def initialize_plugins(): indexer=indexer) resource_type.save() - resource_type.validators = validators - resource_type.retrieve_permissions = retrieve_permissions - resource_type.upload_permissions = upload_permissions + resource_type.validators.set(validators) + resource_type.retrieve_permissions.set(retrieve_permissions) + resource_type.upload_permissions.set(upload_permissions) resource_type.save() # Permissions. diff --git a/src/jane/documents/urls.py b/src/jane/documents/urls.py index b1e6c70..4092119 100644 --- a/src/jane/documents/urls.py +++ b/src/jane/documents/urls.py @@ -37,15 +37,15 @@ router = OptionalTrailingSlashSimpleRouter(trailing_slash=False) router.register(prefix='documents/(?P[a-zA-Z0-9]+)', viewset=views.DocumentsView, - base_name="rest_documents") + basename="rest_documents") router.register(prefix='document_indices/(?P[a-zA-Z0-9]+)', viewset=views.DocumentIndicesView, - base_name="rest_document_indices") + basename="rest_document_indices") router.register( prefix=('document_indices/(?P[a-zA-Z0-9]+)/(?P[0-9]+)' '/attachments'), viewset=views.DocumentIndexAttachmentsView, - base_name="rest_document_index_attachments") + basename="rest_document_index_attachments") urlpatterns.append(url(r'^rest/', include(router.urls))) diff --git a/src/jane/fdsnws/views/dataselect_1.py b/src/jane/fdsnws/views/dataselect_1.py index 1ffcb48..fe4524c 100644 --- a/src/jane/fdsnws/views/dataselect_1.py +++ b/src/jane/fdsnws/views/dataselect_1.py @@ -156,7 +156,7 @@ def query(request): return _error(request, msg) longestonly = bool(longestonly) # user - if request.user.is_authenticated(): + if request.user.is_authenticated: user = request.user else: user = None diff --git a/src/jane/fdsnws/views/event_1.py b/src/jane/fdsnws/views/event_1.py index 1b8b6a2..7af6d1a 100644 --- a/src/jane/fdsnws/views/event_1.py +++ b/src/jane/fdsnws/views/event_1.py @@ -263,7 +263,7 @@ def contributors(request): # @UnusedVariable xml = E.Contributors( E.total(str(len(values))), - *[E.Contributor(_i) for _i in values] + *[E.Contributor(str(_i)) for _i in values] ) with io.BytesIO() as fh: diff --git a/src/jane/fdsnws/views/station_1.py b/src/jane/fdsnws/views/station_1.py index 995c340..67371a6 100644 --- a/src/jane/fdsnws/views/station_1.py +++ b/src/jane/fdsnws/views/station_1.py @@ -250,7 +250,7 @@ def query(request): url = request.build_absolute_uri(request.get_full_path()) # user - if request.user.is_authenticated(): + if request.user.is_authenticated: user = request.user else: user = None diff --git a/src/jane/jane/decorators.py b/src/jane/jane/decorators.py index 1549547..77432d5 100644 --- a/src/jane/jane/decorators.py +++ b/src/jane/jane/decorators.py @@ -81,7 +81,7 @@ def your_view: def view_decorator(func): def wrapper(request, *args, **kwargs): return view_or_basicauth(func, request, - lambda u: u.is_authenticated(), + lambda u: u.is_authenticated, realm, *args, **kwargs) return wrapper return view_decorator diff --git a/src/jane/jane/middleware.py b/src/jane/jane/middleware.py index 2c91e89..5c47acf 100644 --- a/src/jane/jane/middleware.py +++ b/src/jane/jane/middleware.py @@ -6,27 +6,34 @@ class AutoLogoutMiddleware(object): - def process_request(self, request): - # can't log out if not logged in - if not request.user.is_authenticated(): - return + def __init__(self, get_response): + self.get_response = get_response - # check if auto logout is activated - try: - if not settings.AUTO_LOGOUT_MINUTES: - return - except: - return + def __call__(self, request): + set_last_touch = True - try: - delta = time.time() - request.session['last_touch'] - except (KeyError, TypeError): - pass + # can't log out if not logged in + if not request.user.is_authenticated: + # do nothing + set_last_touch = False + # check if auto logout is activated + elif not settings.AUTO_LOGOUT_MINUTES: + # do nothing + set_last_touch = False else: - seconds = settings.AUTO_LOGOUT_MINUTES * 60 - if delta > seconds: - del request.session['last_touch'] - auth.logout(request) - return + try: + delta = time.time() - request.session['last_touch'] + except (KeyError, TypeError): + pass + else: + seconds = settings.AUTO_LOGOUT_MINUTES * 60 + if delta > seconds: + del request.session['last_touch'] + auth.logout(request) + set_last_touch = False + + if set_last_touch: + request.session['last_touch'] = time.time() - request.session['last_touch'] = time.time() + response = self.get_response(request) + return response diff --git a/src/jane/jane/templates/jane/base.html b/src/jane/jane/templates/jane/base.html index a6845df..539ee80 100644 --- a/src/jane/jane/templates/jane/base.html +++ b/src/jane/jane/templates/jane/base.html @@ -1,4 +1,4 @@ -{% load staticfiles %} +{% load static %} diff --git a/src/jane/local_settings.py.example b/src/jane/local_settings.py.example index aa0d0ee..9bc3b94 100644 --- a/src/jane/local_settings.py.example +++ b/src/jane/local_settings.py.example @@ -33,6 +33,12 @@ DEFAULT_FROM_EMAIL = 'noreply@localhost' AUTO_LOGOUT_MINUTES = 60 +# size of http request body is limited to 2.5MB by django by default +# if large files need to be uploaded (e.g. station metadata grouped in one +# file) this needs to be set higher here or upload will fail. +#DATA_UPLOAD_MAX_MEMORY_SIZE = 94371840 # 90 MB + + # see https://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache CACHE = { 'default': { @@ -93,6 +99,8 @@ JANE_ACCENT_COLOR = "#D9230F" JANE_FDSN_STATIONXML_SENDER = "Jane" JANE_FDSN_STATIONXML_SOURCE = "Jane" +# optionally set a custom logfile destination, overriding the default value from settings.py +#LOGFILE = '/home/sysop/logs/jane-rotational.log' # Change the settings for the test database here! # for pytest-django, this did not work for me: diff --git a/src/jane/quakeml/plugins.py b/src/jane/quakeml/plugins.py index 2180780..f18b98b 100644 --- a/src/jane/quakeml/plugins.py +++ b/src/jane/quakeml/plugins.py @@ -217,7 +217,7 @@ def index(self, document): (horizontal_uncertainty_min, horizontal_uncertainty_max_azimuth + 90)): azimuth = azimuth % 180 - distance = geopy.distance.VincentyDistance( + distance = geopy.distance.geodesic( kilometers=distance / 1e3) end1 = distance.destination( point=start, bearing=azimuth) diff --git a/src/jane/settings.py b/src/jane/settings.py index e5b9d13..b13fd01 100644 --- a/src/jane/settings.py +++ b/src/jane/settings.py @@ -19,6 +19,15 @@ PROJECT_DIR = os.path.abspath(os.path.dirname(__file__)) +# new in django 3.2 (?), creates warnings if not set anywhere +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field +# this is old behavior of having int32 as automatic primary key fields. Other +# option could be "BigAutoField" which is int64 but that would need a migration +# (at least if changed on an existing project) +# also see https://dev.to/weplayinternet/upgrading-to-django-3-2-and-fixing-defaultautofield-warnings-518n +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' + + # Hosts/domain names that are valid for this site; required if DEBUG is False # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts ALLOWED_HOSTS = ['*'] @@ -77,7 +86,7 @@ }] -MIDDLEWARE_CLASSES = [ +MIDDLEWARE = [ 'django.middleware.gzip.GZipMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -135,6 +144,12 @@ 'class': 'logging.StreamHandler', 'formatter': 'simple', }, + 'file': { + 'level': 'DEBUG', + 'class': 'logging.FileHandler', + 'filename': '/tmp/jane.log', + 'formatter': 'verbose', + }, 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], @@ -143,18 +158,23 @@ }, }, 'loggers': { + 'jane': { + 'handlers': ['file'], + 'propagate': True, + 'level': 'DEBUG', + }, 'django': { - 'handlers': ['console'], + 'handlers': ['console', 'file'], 'propagate': True, 'level': 'WARN', }, 'django.db.backends': { - 'handers': ['console'], + 'handers': ['console', 'file'], 'level': 'WARN', 'propagate': True, }, 'django.request': { - 'handlers': ['mail_admins'], + 'handlers': ['mail_admins', 'file'], 'level': 'ERROR', 'propagate': False, }, @@ -287,6 +307,11 @@ def show_toolbar(request): "local_settings.py and edit its content before running this " "service.") exit() +else: + try: + LOGGING['handlers']['file']['filename'] = LOGFILE + except: + pass # speed up tests diff --git a/src/jane/static/web_gis/index.html b/src/jane/static/web_gis/index.html index 7f63b37..9a4b7e4 100644 --- a/src/jane/static/web_gis/index.html +++ b/src/jane/static/web_gis/index.html @@ -92,7 +92,6 @@

Jane WebGIS

margin-top: -2px; margin-left: 50px"> -
diff --git a/src/jane/static/web_gis/src/baynetapp.js b/src/jane/static/web_gis/src/baynetapp.js index 55ef142..c361a33 100644 --- a/src/jane/static/web_gis/src/baynetapp.js +++ b/src/jane/static/web_gis/src/baynetapp.js @@ -82,7 +82,7 @@ module.factory('events', function($http, $log, jane_server) { "coordinates": [j.longitude, j.latitude]}, { "type": "MultiLineString", - "coordinates": i.geometry.coordinates[1]} + "coordinates": i.geometry.geometries[1].coordinates} ]} }; return geojson; @@ -213,7 +213,7 @@ module.controller("BayNetController", function($scope, $log, stations, station_c }; $scope.rotation = 0; - $scope.base_layer_opacity = 100.0; + $scope.base_layer_opacity = 60.0; $scope.show_bavaria_outline = false; diff --git a/src/jane/static/web_gis/src/directives/map.js b/src/jane/static/web_gis/src/directives/map.js index db71ea2..86a6094 100644 --- a/src/jane/static/web_gis/src/directives/map.js +++ b/src/jane/static/web_gis/src/directives/map.js @@ -43,26 +43,26 @@ app.directive('openlayers3', function($q, $log, bing_key, $modal) { crossOrigin: null }) }), - "Stamen Toner-Lite": new ol.layer.Tile({ - visible: false, - source: new ol.source.Stamen({layer: 'toner-lite'}) - }), - "Stamen Toner": new ol.layer.Tile({ - visible: false, - source: new ol.source.Stamen({layer: 'toner'}) - }), - "Stamen Watercolor": new ol.layer.Tile({ - visible: false, - source: new ol.source.Stamen({layer: 'watercolor'}) - }), - "MapQuest (Street)": new ol.layer.Tile({ - visible: false, - source: new ol.source.MapQuest({layer: 'osm'}) - }), - "MapQuest (Satellite)": new ol.layer.Tile({ - visible: false, - source: new ol.source.MapQuest({layer: 'sat'}) - }), + //"Stamen Toner-Lite": new ol.layer.Tile({ + // visible: false, + // source: new ol.source.Stamen({layer: 'toner-lite'}) + //}), + //"Stamen Toner": new ol.layer.Tile({ + // visible: false, + // source: new ol.source.Stamen({layer: 'toner'}) + //}), + //"Stamen Watercolor": new ol.layer.Tile({ + // visible: false, + // source: new ol.source.Stamen({layer: 'watercolor'}) + //}), + //"MapQuest (Street)": new ol.layer.Tile({ + // visible: false, + // source: new ol.source.MapQuest({layer: 'osm'}) + //}), + //"MapQuest (Satellite)": new ol.layer.Tile({ + // visible: false, + // source: new ol.source.MapQuest({layer: 'sat'}) + //}), "Open Street Map": new ol.layer.Tile({ visible: false, source: new ol.source.OSM() @@ -73,35 +73,35 @@ app.directive('openlayers3', function($q, $log, bing_key, $modal) { url: '//{a-c}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', crossOrigin: null }) - }), - "OSM EU TOPO (4umaps.eu)": new ol.layer.Tile({ - visible: false, - source: new ol.source.OSM({ - url: '//4umaps.eu/{z}/{x}/{y}.png', - crossOrigin: null - }) - }), - "Bing (Road)": new ol.layer.Tile({ - visible: false, - source: new ol.source.BingMaps({ - key: bing_key, - imagerySet: 'Road' - }) - }), - "Bing (Aerial)": new ol.layer.Tile({ - visible: false, - source: new ol.source.BingMaps({ - key: bing_key, - imagerySet: 'Aerial' - }) - }), - "Bing (Aerial with Labels)": new ol.layer.Tile({ - visible: false, - source: new ol.source.BingMaps({ - key: bing_key, - imagerySet: 'AerialWithLabels' - }) }) + //"OSM EU TOPO (4umaps.eu)": new ol.layer.Tile({ + // visible: false, + // source: new ol.source.OSM({ + // url: '//4umaps.eu/{z}/{x}/{y}.png', + // crossOrigin: null + // }) + //}), + //"Bing (Road)": new ol.layer.Tile({ + // visible: false, + // source: new ol.source.BingMaps({ + // key: bing_key, + // imagerySet: 'Road' + // }) + //}), + //"Bing (Aerial)": new ol.layer.Tile({ + // visible: false, + // source: new ol.source.BingMaps({ + // key: bing_key, + // imagerySet: 'Aerial' + // }) + //}), + //"Bing (Aerial with Labels)": new ol.layer.Tile({ + // visible: false, + // source: new ol.source.BingMaps({ + // key: bing_key, + // imagerySet: 'AerialWithLabels' + // }) + //}) }; $scope.change_base_layer = function(layer_name) { diff --git a/src/jane/urls.py b/src/jane/urls.py index 591c27c..1823439 100644 --- a/src/jane/urls.py +++ b/src/jane/urls.py @@ -10,7 +10,8 @@ urlpatterns = [ - url(r'^admin/', include(admin.site.urls)), + url(r'^admin/', + include(admin.site.urls[:2], namespace=admin.site.urls[2])), url(r'', include('jane.waveforms.urls')), url(r'', include('jane.documents.urls')), url(r'', include('jane.jane.urls')), diff --git a/src/jane/waveforms/migrations/0001_initial.py b/src/jane/waveforms/migrations/0001_initial.py index 172bb34..fc37a6d 100644 --- a/src/jane/waveforms/migrations/0001_initial.py +++ b/src/jane/waveforms/migrations/0001_initial.py @@ -6,6 +6,8 @@ import django.contrib.postgres.fields from django.conf import settings +from jane.waveforms.models import validate_name + class Migration(migrations.Migration): @@ -69,8 +71,8 @@ class Migration(migrations.Migration): ('file_regex', models.CharField(max_length=255, blank=True)), ('created_at', models.DateTimeField(auto_now_add=True)), ('modified_at', models.DateTimeField(auto_now=True)), - ('created_by', models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, editable=False, related_name='mappings_created')), - ('modified_by', models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, editable=False, related_name='mappings_modified')), + ('created_by', models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, editable=False, related_name='mappings_created')), + ('modified_by', models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, editable=False, related_name='mappings_modified')), ], options={ 'ordering': ['-timerange'], @@ -79,7 +81,7 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Path', fields=[ - ('name', models.CharField(max_length=255, validators=['validate_name'], serialize=False, primary_key=True)), + ('name', models.CharField(max_length=255, validators=[validate_name], serialize=False, primary_key=True)), ('ctime', models.DateTimeField()), ('mtime', models.DateTimeField()), ('created_at', models.DateTimeField(auto_now_add=True)), @@ -97,20 +99,20 @@ class Migration(migrations.Migration): ('comment', models.TextField(null=True, blank=True)), ('created_at', models.DateTimeField(auto_now_add=True)), ('modified_at', models.DateTimeField(auto_now=True)), - ('created_by', models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, editable=False, related_name='restrictions_created')), - ('modified_by', models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, editable=False, related_name='restrictions_modified')), + ('created_by', models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, editable=False, related_name='restrictions_created')), + ('modified_by', models.ForeignKey(null=True, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE, editable=False, related_name='restrictions_modified')), ('users', models.ManyToManyField(db_index=True, to=settings.AUTH_USER_MODEL)), ], ), migrations.AddField( model_name='file', name='path', - field=models.ForeignKey(related_name='files', to='waveforms.Path'), + field=models.ForeignKey(related_name='files', to='waveforms.Path', on_delete=models.CASCADE), ), migrations.AddField( model_name='continuoustrace', name='file', - field=models.ForeignKey(related_name='traces', to='waveforms.File'), + field=models.ForeignKey(related_name='traces', to='waveforms.File', on_delete=models.CASCADE), ), migrations.AlterUniqueTogether( name='file', diff --git a/src/jane/waveforms/models.py b/src/jane/waveforms/models.py index 7fedcfa..faf003a 100644 --- a/src/jane/waveforms/models.py +++ b/src/jane/waveforms/models.py @@ -13,9 +13,16 @@ User = settings.AUTH_USER_MODEL +def validate_name(value): + if not os.path.isdir(value): + raise ValidationError(u'%s is not a valid path' % value) + if not os.path.isabs(value): + raise ValidationError(u'%s is not a absolute path' % value) + + class Path(models.Model): name = models.CharField(max_length=255, primary_key=True, - validators=['validate_name']) + validators=[validate_name]) ctime = models.DateTimeField() mtime = models.DateTimeField() created_at = models.DateTimeField(auto_now_add=True, editable=False) @@ -26,12 +33,6 @@ def __str__(self): class Meta: ordering = ['name'] - def validate_name(self, value): - if not os.path.isdir(value): - raise ValidationError(u'%s is not a valid path' % value) - if not os.path.isabs(value): - raise ValidationError(u'%s is not a absolute path' % value) - def save(self, *args, **kwargs): stats = os.stat(self.name) self.mtime = to_datetime(stats.st_mtime) @@ -40,7 +41,8 @@ def save(self, *args, **kwargs): class File(models.Model): - path = models.ForeignKey(Path, related_name='files') + path = models.ForeignKey( + Path, related_name='files', on_delete=models.CASCADE) name = models.CharField(max_length=255, db_index=True) size = models.IntegerField() gaps = models.IntegerField(default=0, db_index=True) @@ -71,7 +73,8 @@ def save(self, *args, **kwargs): class ContinuousTrace(models.Model): - file = models.ForeignKey(File, related_name='traces') + file = models.ForeignKey( + File, related_name='traces', on_delete=models.CASCADE) pos = models.IntegerField(default=0) network = models.CharField(max_length=2, db_index=True, blank=True) station = models.CharField(max_length=5, db_index=True, blank=True) @@ -198,10 +201,12 @@ class Mapping(models.Model): max_length=255, blank=False, default=r"^.*$") created_at = models.DateTimeField(auto_now_add=True, editable=False) created_by = models.ForeignKey(User, null=True, editable=False, - related_name='mappings_created') + related_name='mappings_created', + on_delete=models.CASCADE) modified_at = models.DateTimeField(auto_now=True, editable=False) modified_by = models.ForeignKey(User, null=True, editable=False, - related_name='mappings_modified') + related_name='mappings_modified', + on_delete=models.CASCADE) def __str__(self): return "%s.%s.%s.%s | %s ==> %s.%s.%s.%s" % ( @@ -241,10 +246,12 @@ class Restriction(models.Model): comment = models.TextField(blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True, editable=False) created_by = models.ForeignKey(User, null=True, editable=False, - related_name='restrictions_created') + related_name='restrictions_created', + on_delete=models.CASCADE) modified_at = models.DateTimeField(auto_now=True, editable=False) modified_by = models.ForeignKey(User, null=True, editable=False, - related_name='restrictions_modified') + related_name='restrictions_modified', + on_delete=models.CASCADE) def save(self, *args, **kwargs): # ensure uppercase and no whitespaces around network/station ids diff --git a/src/jane/waveforms/urls.py b/src/jane/waveforms/urls.py index fe8c256..01ddcbb 100644 --- a/src/jane/waveforms/urls.py +++ b/src/jane/waveforms/urls.py @@ -6,7 +6,7 @@ router = OptionalTrailingSlashSimpleRouter(trailing_slash=False) -router.register(r'waveforms', views.WaveformView, base_name='rest_waveforms') +router.register(r'waveforms', views.WaveformView, basename='rest_waveforms') urlpatterns = [ url(r'^rest/', include(router.urls)), diff --git a/src/jane/waveforms/views.py b/src/jane/waveforms/views.py index 0fcf174..804be1a 100644 --- a/src/jane/waveforms/views.py +++ b/src/jane/waveforms/views.py @@ -3,7 +3,7 @@ from rest_framework import viewsets, renderers, filters from rest_framework.response import Response -from rest_framework.decorators import detail_route +from rest_framework.decorators import action from jane.waveforms import models, serializer @@ -48,12 +48,12 @@ def get_queryset(self): filter_backends = (filters.OrderingFilter,) ordering_fields = '__all__' - @detail_route(renderer_classes=[PNGRenderer]) + @action(detail=True, renderer_classes=[PNGRenderer]) def plot(self, request, *args, **kwargs): obj = self.get_object() return Response(obj.preview_image) - @detail_route(renderer_classes=[BinaryRenderer]) + @action(detail=True, renderer_classes=[BinaryRenderer]) def file(self, request, *args, **kwargs): file_obj = self.get_object().file filename = os.path.join(file_obj.path.name, file_obj.name)