diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8ad874e2280585a04f9213b366fe4c7063047c1d..392bbabca29e5ddf0fd43cd09714beef9499312c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,11 +1,49 @@ stages: + - test - build - deploy_to_test - deploy_to_production +workflow: + rules: + - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH + variables: + DOCKER_BUILD_IMAGE_TAG: ":stable" + - if: $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH + variables: + DOCKER_BUILD_IMAGE_TAG: ":latest" + + +test-code: + image: python:3.10 + stage: test + services: + - postgres:11.0 + variables: + POSTGRES_DB: ldv-spec-db + POSTGRES_USER: postgres + POSTGRES_PASSWORD: "atdb123" + script: + - cd ldvspec + - pip install -r requirements/dev.txt + - python manage.py migrate --settings ldvspec.settings.ci + - python manage.py test --settings ldvspec.settings.ci + +docker-test-build: + variables: + if: main + # Official docker image. + image: docker$DOCKER_BUILD_IMAGE_TAG + stage: build + services: + - docker:dind + script: + - docker build --pull -t "$CI_REGISTRY_IMAGE" ldvspec + + docker-build-master: # Official docker image. - image: docker:latest + image: docker$DOCKER_BUILD_IMAGE_TAG stage: build services: - docker:dind @@ -20,7 +58,6 @@ docker-build-master: # deploy test/dev version on 'sdc-dev.astron.nl' docker-deploy-main-test: -# image: docker:latest stage: deploy_to_test before_script: - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY @@ -60,7 +97,7 @@ docker-deploy-main-test: - main docker-deploy-main-production: -# image: docker:latest + # image: docker:latest stage: deploy_to_production before_script: - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY diff --git a/ldvspec/Dockerfile b/ldvspec/Dockerfile index f17b53251ad682fa133f4fd84267f5425dfa2a84..c6db5f535ee6b668fcc701da98eebc8a7d8df8c0 100644 --- a/ldvspec/Dockerfile +++ b/ldvspec/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.6.7-alpine +FROM python:3.10-alpine ENV PYTHONUNBUFFERED 1 RUN apk update && apk add bash && apk add nano && apk add mc RUN mkdir /src @@ -7,7 +7,7 @@ COPY . /src/ # install dependencies RUN \ - apk add --no-cache python3 postgresql-libs && \ + apk add --no-cache postgresql-libs && \ apk add --no-cache --virtual .build-deps gcc python3-dev musl-dev postgresql-dev && \ pip install -r requirements/prod.txt && \ apk --purge del .build-deps diff --git a/ldvspec/ldvspec/settings/base.py b/ldvspec/ldvspec/settings/base.py index 6734ff05c266eee3d4adfbcc3d9ffb8068683abd..24b8ce6551cf34df22f3ac1bed4f7c0485cbf939 100644 --- a/ldvspec/ldvspec/settings/base.py +++ b/ldvspec/ldvspec/settings/base.py @@ -131,7 +131,4 @@ REST_FRAMEWORK = { 'PAGE_SIZE': 100 } -try: - ATDB_HOST = os.environ['ATDB_HOST'] -except: - ATDB_HOST = "http://localhost:8000/atdb/" \ No newline at end of file +ATDB_HOST = os.environ.get('ATDB_HOST', 'http://localhost:8000/atdb/') diff --git a/ldvspec/ldvspec/settings/ci.py b/ldvspec/ldvspec/settings/ci.py new file mode 100644 index 0000000000000000000000000000000000000000..ead5103b7942225b19cefb40ee9300dbf27074da --- /dev/null +++ b/ldvspec/ldvspec/settings/ci.py @@ -0,0 +1,24 @@ +from ldvspec.settings.base import * + +# SECURITY WARNING: don't run with debug turned on in production! +DEV = True +DEBUG = True + +ALLOWED_HOSTS = ["*"] +CORS_ORIGIN_ALLOW_ALL = True + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'USER': 'postgres', + 'PASSWORD': 'atdb123', + 'NAME': 'ldv-spec-db', + 'HOST': 'postgres', + 'PORT': '5432', + }, +} + +# Password validation +# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [] diff --git a/ldvspec/lofardata/admin.py b/ldvspec/lofardata/admin.py index cf044d64e6c5d0935980c65f941a89eff47f36d7..e42f80883d51fbabe15e412aaaa66445078aa39a 100644 --- a/ldvspec/lofardata/admin.py +++ b/ldvspec/lofardata/admin.py @@ -1,5 +1,7 @@ from django.contrib import admin # Register your models here. -from .models import LofarData -admin.site.register(LofarData) \ No newline at end of file +from .models import DataProduct, DataProductFilter + +admin.site.register(DataProduct) +admin.site.register(DataProductFilter) diff --git a/ldvspec/lofardata/migrations/0002_defines_dataproduct.py b/ldvspec/lofardata/migrations/0002_defines_dataproduct.py new file mode 100644 index 0000000000000000000000000000000000000000..a2b6832a26c3edaa91cea85a8761d906d78a9f6f --- /dev/null +++ b/ldvspec/lofardata/migrations/0002_defines_dataproduct.py @@ -0,0 +1,49 @@ +# Generated by Django 3.1.4 on 2022-07-21 09:23 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('lofardata', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='DataLocation', + fields=[ + ('name', models.CharField(max_length=50, primary_key=True, serialize=False)), + ('uri', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='DataProduct', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('obs_id', models.CharField(max_length=15, verbose_name='OBS_ID')), + ('oid_source', models.CharField(max_length=15, verbose_name='OBS_ID_SOURCE')), + ('dataproduct_source', models.CharField(max_length=20)), + ('dataproduct_type', models.CharField(max_length=50)), + ('project', models.CharField(max_length=15)), + ('activity', models.CharField(max_length=50)), + ('surl', models.CharField(max_length=200)), + ('filesize', models.PositiveBigIntegerField()), + ('additional_meta', models.JSONField()), + ('location', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='lofardata.datalocation')), + ], + ), + migrations.CreateModel( + name='DataProductFilter', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('field', models.CharField(max_length=20)), + ('name', models.CharField(max_length=20)), + ('lookup_type', models.CharField(max_length=100)), + ], + ), + migrations.DeleteModel( + name='LofarData', + ), + ] diff --git a/ldvspec/lofardata/models.py b/ldvspec/lofardata/models.py index cece29fd462734113c3584f41e2366894fca4edd..882475e59bc4c1f53fe7916b2b76c7630bbb4f75 100644 --- a/ldvspec/lofardata/models.py +++ b/ldvspec/lofardata/models.py @@ -1,7 +1,68 @@ from django.db import models +from django_filters import rest_framework as filters +from urllib.parse import urlsplit -class LofarData(models.Model): - sas_id = models.CharField(verbose_name="SAS_ID",max_length=15, blank=True, null=True) - def __str__(self): - return self.sas_id \ No newline at end of file +class DataLocation(models.Model): + name = models.CharField(max_length=50, primary_key=True) + uri = models.CharField(max_length=200) + + @staticmethod + def insert_location_from_string(location_string): + """ + Insert a datalocation from a srm string (e.g. srm://surm:4321/path.tar) + + :param str location_string: SRM url + :return: DataLocation object + rtype: DataLocations + """ + _, netloc, *_ = urlsplit(location_string) + + dataloc = DataLocation(name=netloc, uri=location_string.rstrip('/')) + dataloc.save() + return dataloc + + +class DataProduct(models.Model): + obs_id = models.CharField(verbose_name="OBS_ID", max_length=15) + oid_source = models.CharField(verbose_name='OBS_ID_SOURCE', max_length=15) + dataproduct_source = models.CharField(max_length=20) + dataproduct_type = models.CharField(max_length=50) + project = models.CharField(max_length=15) + location = models.ForeignKey(DataLocation, on_delete=models.DO_NOTHING) + activity = models.CharField(max_length=50) + surl = models.CharField(max_length=200) + filesize = models.PositiveBigIntegerField() + additional_meta = models.JSONField() + + @staticmethod + def insert_dataproduct(obs_id, + oid_source, + dataproduct_source, + dataproduct_type, + project, + activity, + surl, + filesize, + additional_meta): + scheme, netloc, *_ = urlsplit(surl) + + dp = DataProduct(obs_id=obs_id, + oid_source=oid_source, + dataproduct_source=dataproduct_source, + dataproduct_type=dataproduct_type, + project=project, + location=DataLocation.insert_location_from_string('://'.join((scheme, netloc))), + activity=activity, + filesize=filesize, + additional_meta=additional_meta, + surl=surl + ) + dp.save() + return dp + + +class DataProductFilter(models.Model): + field = models.CharField(max_length=20) + name = models.CharField(max_length=20) + lookup_type = models.CharField(max_length=100) diff --git a/ldvspec/lofardata/serializers.py b/ldvspec/lofardata/serializers.py index aaf9229c414b1b20f901be87a5d9fa53618cd7a9..f685fb619d7b66f46ef00023be19a953accd413a 100644 --- a/ldvspec/lofardata/serializers.py +++ b/ldvspec/lofardata/serializers.py @@ -1,8 +1,25 @@ +from abc import ABC + from rest_framework import serializers -from .models import LofarData +from .models import DataProduct, DataLocation + + +class DataLocationSerializer(serializers.ModelSerializer): + class Meta: + model = DataLocation + fields = '__all__' -class LofarDataSerializer(serializers.ModelSerializer): +class DataProductSerializer(serializers.ModelSerializer): class Meta: - model = LofarData + model = DataProduct fields = "__all__" + + +class DataProductFlatSerializer(serializers.ModelSerializer): + class Meta: + model = DataProduct + exclude = ('location',) + + def create(self, validated_data): + return DataProduct.insert_dataproduct(**validated_data) diff --git a/ldvspec/lofardata/templates/lofardata/base.html b/ldvspec/lofardata/templates/lofardata/base.html index 020485dbd2f2b26f6a02a1d29810b4ed0e731bb7..e5ab1386442bf38a9a3f6bfd4fece547a9658fc5 100644 --- a/ldvspec/lofardata/templates/lofardata/base.html +++ b/ldvspec/lofardata/templates/lofardata/base.html @@ -34,7 +34,7 @@ </li> <li><a class="nav-link" href="{% url 'index' %}">Home</a></li> - <li><a class="nav-link" href="{% url 'lofardata' %}">LOFAR Data</a></li> + <li><a class="nav-link" href="{% url 'dataproduct' %}">LOFAR Data</a></li> {% if user.is_authenticated %} <a class="nav-link" href="{% url 'logout' %}" target="_blank">Logout {{ user.get_username }}</a> diff --git a/ldvspec/lofardata/templates/lofardata/index.html b/ldvspec/lofardata/templates/lofardata/index.html index 76803327bb3eef32421637c330b7029772fa9107..f41e698a5f62e759ff9087f7512d9892bb64452f 100644 --- a/ldvspec/lofardata/templates/lofardata/index.html +++ b/ldvspec/lofardata/templates/lofardata/index.html @@ -9,7 +9,8 @@ <tbody> <tr><td>atdb_host</td><td>{{ atdb_host }}</td></tr> - <tr><td>api</td><td><a href="{% url 'lofardata' %}">{% url 'lofardata' %}</a></td></tr> + <tr><td>api</td><td><a href="{% url 'dataproduct' %}">{% url 'dataproduct' %}</a></td></tr> + <tr><td>api-schema</td><td><a href="{% url 'openapi-schema' %}">{% url 'openapi-schema' %}</a></td></tr> </tbody> </table> diff --git a/ldvspec/lofardata/tests.py b/ldvspec/lofardata/tests.py deleted file mode 100644 index 7ce503c2dd97ba78597f6ff6e4393132753573f6..0000000000000000000000000000000000000000 --- a/ldvspec/lofardata/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/ldvspec/__init__.py b/ldvspec/lofardata/tests/__init__.py similarity index 100% rename from ldvspec/__init__.py rename to ldvspec/lofardata/tests/__init__.py diff --git a/ldvspec/lofardata/tests/test_data_filter.py b/ldvspec/lofardata/tests/test_data_filter.py new file mode 100644 index 0000000000000000000000000000000000000000..d608546d11ac888d98fbfc0ba95a0710c79bd094 --- /dev/null +++ b/ldvspec/lofardata/tests/test_data_filter.py @@ -0,0 +1,55 @@ +import rest_framework.test as rtest +from django.contrib.auth.models import User +from lofardata.models import DataProduct, DataProductFilter + +test_object_values = [dict(obs_id='12345', oid_source='SAS', dataproduct_source='lofar', + dataproduct_type='observation', + project='LT10_10', + activity='observation', + surl='srm://surfsara.nl:4884/...', + filesize=40, + additional_meta={'dysco_compression': True}), + dict(obs_id='12346', oid_source='SAS', dataproduct_source='lofar', + dataproduct_type='observation', + project='LT10_10', + activity='pipeline', + surl='srm://surfsara.nl:4884/...', + filesize=40, + additional_meta={'dysco_compression': True}), + dict(obs_id='12347', oid_source='SAS', dataproduct_source='lofar', + dataproduct_type='observation', + project='LT10_10', + activity='observation', + surl='srm://surfsara.nl:4884/...', + filesize=40, + additional_meta={'dysco_compression': True})] + + +class TestDataFilter(rtest.APITestCase): + def setUp(self): + self.user = User.objects.create_superuser('admin') + self.client.force_authenticate(self.user) + + for test_object in test_object_values: + DataProduct.insert_dataproduct(**test_object) + + def get_current_query_parameters(self): + response = self.client.get('/ldvspec/api/v1/openapi/') + query_parameters = response.data['paths']['/ldvspec/api/v1/data/']['get']['parameters'] + return {parameter['name']: parameter for parameter in query_parameters} + + def test_add_custom_filter(self): + self.assertNotIn('activity', self.get_current_query_parameters(), 'Test is invalid! Update') + + dp_filter = DataProductFilter(field='activity', name='activity_type', lookup_type='exact') + dp_filter.save() + + response = self.client.get('/ldvspec/api/v1/data/?activity_type=pipeline') + self.assertEqual(1, response.data['count']) + self.assertEqual('pipeline', response.data['results'][0]['activity']) + + response = self.client.get('/ldvspec/api/v1/data/?activity_type=observation') + self.assertEqual(2, response.data['count']) + self.assertEqual('observation', response.data['results'][0]['activity']) + + self.assertIn('activity_type', self.get_current_query_parameters()) \ No newline at end of file diff --git a/ldvspec/lofardata/tests/test_dataproduct.py b/ldvspec/lofardata/tests/test_dataproduct.py new file mode 100644 index 0000000000000000000000000000000000000000..138634b3d5811b60ce73dda190f54d1cc32a2a21 --- /dev/null +++ b/ldvspec/lofardata/tests/test_dataproduct.py @@ -0,0 +1,79 @@ +import django.test as dtest +import rest_framework.test as rtest +from django.contrib.auth.models import User +import rest_framework.status as response_status +from lofardata.models import DataProduct, DataLocation + +test_object_value = dict(obs_id='12345', oid_source='SAS', dataproduct_source='lofar', + dataproduct_type='observation', + project='LT10_10', + location='srm://surfsara.nl:4884/', + activity='observation', + surl='srm://surfsara.nl:4884/...', + filesize=40, + additional_meta={'dysco_compression': True}) + + +class TestDatabaseInteraction(dtest.TestCase): + def test_insert(self): + location = DataLocation(name='surfsara', uri='srm://surfsara.nl') + location.save() + test_values = dict(test_object_value) + test_values['location'] = location + dp = DataProduct(**test_values) + dp.save() + self.assertTrue(dp.pk is not None, 'Failed saving object') + dp = DataProduct.objects.get(obs_id='12345') + for field in test_values: + self.assertEqual(getattr(dp, field), test_values.get(field)) + + def test_insert_with_helper_function(self): + test_values = dict(test_object_value) + test_values.pop('location') + + dp = DataProduct.insert_dataproduct(**test_values) + + for field in test_values: + self.assertEqual(test_object_value.get(field), getattr(dp, field), msg=f'Field {field} does not coincide') + + self.assertEqual('surfsara.nl:4884', dp.location.name) + self.assertEqual( 'srm://surfsara.nl:4884', dp.location.uri) + + +class TestRESTAPI(rtest.APITestCase): + def setUp(self): + self.user = User.objects.create_superuser('admin') + self.client.force_authenticate(self.user) + + def test_insert_not_allowed(self): + client = rtest.APIClient() + response = client.post('/ldvspec/api/v1/data/insert/', data={}, format='json') + self.assertEqual(response_status.HTTP_403_FORBIDDEN, response.status_code) + + def test_insert_flat_error(self): + response = self.client.post('/ldvspec/api/v1/data/insert/', data={}, format='json') + self.assertEqual(response_status.HTTP_400_BAD_REQUEST, response.status_code) + + def test_insert_flat_single(self): + test_payload = dict(test_object_value) + test_payload.pop('location') + response = self.client.post('/ldvspec/api/v1/data/insert/', data=test_payload, format='json') + self.assertEqual(response_status.HTTP_201_CREATED, response.status_code) + + def test_insert_flat_multi(self): + test_payload = dict(test_object_value) + test_payload.pop('location') + response = self.client.post('/ldvspec/api/v1/data/insert/', data=[test_payload, test_payload], format='json') + + self.assertEqual(response_status.HTTP_201_CREATED, response.status_code) + self.assertTrue(DataProduct.objects.count() == 2, 'Not all dataproduct have been inserted') + self.assertTrue(DataLocation.objects.count() == 1, 'Not all dataproduct have been inserted') + + def test_insert_flat_multi_insert_single(self): + test_payload = dict(test_object_value) + test_payload.pop('location') + response = self.client.post('/ldvspec/api/v1/data/insert/', data=test_payload, format='json') + + self.assertEqual(response_status.HTTP_201_CREATED, response.status_code) + self.assertTrue(DataProduct.objects.count() == 1, 'Not all dataproduct have been inserted') + self.assertTrue(DataLocation.objects.count() == 1, 'Not all dataproduct have been inserted') \ No newline at end of file diff --git a/ldvspec/lofardata/tests/test_location.py b/ldvspec/lofardata/tests/test_location.py new file mode 100644 index 0000000000000000000000000000000000000000..86d6466c3b45485d547ffcf21c843bdae7bfdd21 --- /dev/null +++ b/ldvspec/lofardata/tests/test_location.py @@ -0,0 +1,55 @@ +import django.test as dtest +import rest_framework.test as rtest +from django.contrib.auth.models import User +import rest_framework.status as response_status +from lofardata.models import DataLocation + + +class TestDataLocation(dtest.TestCase): + + def test_insert(self): + location = DataLocation(name='test', uri='srm://path_to_file/') + location.save() + + self.assertTrue(location.pk is not None, 'Cannot save object') + + def test_double_insert_unique_entry(self): + location = DataLocation(name='test', uri='srm://path_to_file/') + location.save() + + self.assertTrue(location.pk is not None, 'Cannot save object') + location_first_pk = location.pk + + location = DataLocation(name='test', uri='srm://path_to_file/') + location.save() + + self.assertTrue(location.pk is not None, 'Cannot save object') + location_second_pk = location.pk + + self.assertTrue(location_first_pk == location_second_pk, 'Double inserted index do not coincide') + + self.assertTrue(DataLocation.objects.count() == 1) + + def test_insert_from_string(self): + dataloc = DataLocation.insert_location_from_string('srm://test_site:44321/') + + self.assertTrue(dataloc.pk is not None, 'Cannot save object') + self.assertEqual('test_site:44321', dataloc.name) + self.assertEqual('srm://test_site:44321', dataloc.uri) + + +class TestRESTAPI(rtest.APITestCase): + def setUp(self): + self.user = User.objects.create_superuser('admin') + self.client.force_authenticate(self.user) + + def test_create_error(self): + response = self.client.post('/ldvspec/api/v1/data-location/', data=dict(name='testname'), + format='json') + self.assertEqual(response_status.HTTP_400_BAD_REQUEST, response.status_code) + + def test_create(self): + response = self.client.post('/ldvspec/api/v1/data-location/', data=dict(name='testname', uri='srm://myniceuri/'), + format='json') + self.assertEqual(response_status.HTTP_201_CREATED, response.status_code) + self.assertEqual('srm://myniceuri/', DataLocation.objects.get(name='testname').uri) \ No newline at end of file diff --git a/ldvspec/lofardata/urls.py b/ldvspec/lofardata/urls.py index 236c3de9ebcabd2e1765fd0144414e116a281fea..877dee282177eba1850856f5a56b5de9f9e29471 100644 --- a/ldvspec/lofardata/urls.py +++ b/ldvspec/lofardata/urls.py @@ -1,6 +1,6 @@ from django.urls import include, path from django.contrib.auth import views as auth_views -from rest_framework.authtoken import views as rest_auth_views +from rest_framework.schemas import get_schema_view from . import views @@ -13,8 +13,15 @@ urlpatterns = [ path('login/', auth_views.LoginView.as_view(template_name='registration/login.html')), # REST API - path('lofardata/', views.LofarDataView.as_view(), name='lofardata'), + path('api/v1/data/', views.DataProductView.as_view(), name='dataproduct'), + path('api/v1/data/insert/', views.InsertMultiDataproductView.as_view(), name='dataproduct-insert'), + path('api/v1/data-location/', views.DataLocationView.as_view(), name='datalocation'), + path('api/v1/openapi/', get_schema_view( + title="LDV Specification", + description="API description", + version="0.0.1" + ), name='openapi-schema'), # GUI #path('', views.IndexView.as_view(), name='index'), path('', views.index, name='index'), diff --git a/ldvspec/lofardata/views.py b/ldvspec/lofardata/views.py index d058d3cf4311c2ca01159c3ce6ed54dbdd5536c4..1e2b448394c04715c247e651d8d26f2517a9d0fa 100644 --- a/ldvspec/lofardata/views.py +++ b/ldvspec/lofardata/views.py @@ -1,26 +1,46 @@ +import logging -from django.shortcuts import render, redirect, reverse -from django.views.generic import ListView +from django.shortcuts import render from django.conf import settings from rest_framework import generics, pagination from rest_framework.views import APIView -import django_filters +from rest_framework import status +from rest_framework.response import Response from django_filters import rest_framework as filters -from .models import LofarData -from .serializers import LofarDataSerializer +from .models import DataProduct, DataProductFilter, DataLocation +from .serializers import DataProductSerializer, DataProductFlatSerializer, DataLocationSerializer -# --- Filters --- -class LofarDataFilter(filters.FilterSet): + +class DynamicFilterSet(filters.FilterSet): class Meta: - model = LofarData + filter_class = None + + def __init__(self, *args, **kwargs): + self._load_filters() + super().__init__(*args, **kwargs) + + def _load_filters(self): + if self.Meta.filter_class is None: + raise Exception('Define filter_class meta attribute') + for item in self.Meta.filter_class.objects.all(): + field_obj = self.Meta.model._meta.get_field(item.field) + filter_class, *_ = self.filter_for_lookup(field_obj, item.lookup_type) + self.base_filters[item.name] = filter_class(item.field) + +# --- Filters --- +class DataProductFilterSet(DynamicFilterSet): + class Meta: + model = DataProduct + filter_class = DataProductFilter fields = { - 'sas_id': ['exact', 'icontains'], + 'obs_id': ['exact', 'icontains'], } + # ---------- GUI Views ----------- def index(request): @@ -29,13 +49,32 @@ def index(request): # ---------- REST API views ---------- +class DataProductView(generics.ListCreateAPIView): + model = DataProduct + serializer_class = DataProductSerializer -class LofarDataView(generics.ListCreateAPIView): - model = LofarData - serializer_class = LofarDataSerializer - - queryset = LofarData.objects.all().order_by('sas_id') + queryset = DataProduct.objects.all().order_by('obs_id') # using the Django Filter Backend - https://django-filter.readthedocs.io/en/latest/index.html filter_backends = (filters.DjangoFilterBackend,) - filter_class = LofarDataFilter + filter_class = DataProductFilterSet + + +class DataLocationView(generics.ListCreateAPIView): + model = DataLocation + serializer_class = DataLocationSerializer + queryset = DataLocation.objects.all().order_by('name') + + +class InsertMultiDataproductView(generics.CreateAPIView): + """ + Add single DataProduct + """ + queryset = DataProduct.objects.all() + serializer_class = DataProductFlatSerializer + + def get_serializer(self, *args, **kwargs): + """ if an array is passed, set serializer to many """ + if isinstance(kwargs.get('data', {}), list): + kwargs['many'] = True + return super().get_serializer(*args, **kwargs) diff --git a/ldvspec/manage.py b/ldvspec/manage.py index 110f50eed9bb0655751f09aeaca46b10b0507598..b99a0a4bbaf9cacd4d3a770bd1dd73a52b69b170 100644 --- a/ldvspec/manage.py +++ b/ldvspec/manage.py @@ -6,7 +6,7 @@ import sys def main(): """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ldvspec.settings') + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ldvspec.settings.dev') try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/ldvspec/requirements/base.txt b/ldvspec/requirements/base.txt index 4bfeb5bfa8877c6936b47be6f5ccbda66ccd9797..45954f46e55c36134e02bec5a7006d63434827a9 100644 --- a/ldvspec/requirements/base.txt +++ b/ldvspec/requirements/base.txt @@ -9,3 +9,5 @@ pytz==2022.1 whitenoise==5.0.1 six==1.15.0 fontawesome-free==5.15.2 +pyyaml==6.0 +uritemplate==4.1.1 \ No newline at end of file