Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sasview database #106

Draft
wants to merge 17 commits into
base: refactor_24
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
**/build
/dist
.mplconfig
**/db.sqlite3

# doc build
/docs/sphinx-docs/build
Expand Down
Empty file.
4 changes: 4 additions & 0 deletions sasdata/fair_database/data/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from django.contrib import admin
from .models import Data

admin.site.register(Data)
6 changes: 6 additions & 0 deletions sasdata/fair_database/data/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class DataConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'data'
8 changes: 8 additions & 0 deletions sasdata/fair_database/data/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django import forms
from .models import Data

# Create the form class.
class DataForm(forms.ModelForm):
class Meta:
model = Data
fields = ["file", "is_public"]
28 changes: 28 additions & 0 deletions sasdata/fair_database/data/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 5.1.5 on 2025-01-23 18:41

import django.core.files.storage
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='Data',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('file_name', models.CharField(blank=True, default=None, help_text='File name', max_length=200, null=True)),
('file', models.FileField(default=None, help_text='This is a file', storage=django.core.files.storage.FileSystemStorage(), upload_to='uploaded_files')),
('is_public', models.BooleanField(default=False, help_text='opt in to submit your data into example pool')),
('current_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]
Empty file.
22 changes: 22 additions & 0 deletions sasdata/fair_database/data/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from django.db import models
from django.contrib.auth.models import User
from django.core.files.storage import FileSystemStorage

# Create your models here.
class Data(models.Model):
#username
current_user = models.ForeignKey(User, blank=True,
null=True, on_delete=models.CASCADE)

#file name
file_name = models.CharField(max_length=200, default=None,
blank=True, null=True, help_text="File name")

#imported data
#user can either import a file path or actual file
file = models.FileField(blank=False, default=None, help_text="This is a file",
upload_to="uploaded_files", storage=FileSystemStorage())

#is the data public?
is_public = models.BooleanField(default=False,
help_text= "opt in to submit your data into example pool")
8 changes: 8 additions & 0 deletions sasdata/fair_database/data/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from rest_framework import serializers

from .models import Data

class DataSerializer(serializers.ModelSerializer):
class Meta:
model = Data
fields = "__all__"
97 changes: 97 additions & 0 deletions sasdata/fair_database/data/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import os
import shutil

from django.conf import settings
from django.test import TestCase
from django.contrib.auth.models import User
from rest_framework.test import APIClient, APITestCase
from rest_framework import status

from .models import Data

def find(filename):
return os.path.join(os.path.dirname(__file__), "../../example_data/1d_data", filename)

class TestLists(TestCase):
def setUp(self):
public_test_data = Data.objects.create(id = 1, file_name = "cyl_400_40.txt", is_public = True)
public_test_data.file.save("cyl_400_40.txt", open(find("cyl_400_40.txt"), 'rb'))
self.user = User.objects.create_user(username="testUser", password="secret", id = 2)
private_test_data = Data.objects.create(id = 3, current_user = self.user, file_name = "cyl_400_20.txt", is_public = False)
private_test_data.file.save("cyl_400_20.txt", open(find("cyl_400_20.txt"), 'rb'))
self.client = APIClient()
self.client.force_authenticate(user=self.user)

#working
def test_does_list_public(self):
request = self.client.get('/v1/data/list/')
self.assertEqual(request.data, {"public_data_ids":{1:"cyl_400_40.txt"}})

def test_does_list_user(self):
request = self.client.get('/v1/data/list/testUser/', user = self.user)
self.assertEqual(request.data, {"user_data_ids":{3:"cyl_400_20.txt"}})

def test_does_load_data_info_public(self):
request = self.client.get('/v1/data/load/1/')
print(request.data)
self.assertEqual(request.status_code, status.HTTP_200_OK)

def test_does_load_data_info_private(self):
request = self.client.get('/v1/data/load/3/')
print(request.data)
self.assertEqual(request.status_code, status.HTTP_200_OK)

def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT)

class TestingDatabase(APITestCase):
def setUp(self):
self.user = User.objects.create_user(username="testUser", password="secret", id = 1)
self.data = Data.objects.create(id = 2, current_user = self.user, file_name = "cyl_400_20.txt", is_public = False)
self.data.file.save("cyl_400_20.txt", open(find("cyl_400_20.txt"), 'rb'))
self.client = APIClient()
self.client.force_authenticate(user=self.user)
self.client2 = APIClient()

def test_is_data_being_created(self):
file = open(find("cyl_400_40.txt"), 'rb')
data = {
"is_public":False,
"file":file
}
request = self.client.post('/v1/data/upload/', data=data)
self.assertEqual(request.status_code, status.HTTP_200_OK)
self.assertEqual(request.data, {"current_user":'testUser', "authenticated" : True, "file_id" : 3, "file_alternative_name":"cyl_400_40.txt","is_public" : False})
Data.objects.get(id = 3).delete()

def test_is_data_being_created_no_user(self):
file = open(find("cyl_400_40.txt"), 'rb')
data = {
"is_public":False,
"file":file
}
request = self.client2.post('/v1/data/upload/', data=data)
self.assertEqual(request.status_code, status.HTTP_200_OK)
self.assertEqual(request.data, {"current_user":'', "authenticated" : False, "file_id" : 3, "file_alternative_name":"cyl_400_40.txt","is_public" : False})
Data.objects.get(id = 3).delete()

def test_does_file_upload_update(self):
file = open(find("cyl_400_40.txt"))
data = {
"file":file,
"is_public":False
}
request = self.client.put('/v1/data/upload/2/', data = data)
request2 = self.client2.put('/v1/data/upload/2/', data = data)
self.assertEqual(request.data, {"current_user":'testUser', "authenticated" : True, "file_id" : 2, "file_alternative_name":"cyl_400_40.txt","is_public" : False})
self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN)
Data.objects.get(id = 2).delete()

#TODO write tests for download
'''
def test_does_download(self):
self.client.get()
'''

def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT)
13 changes: 13 additions & 0 deletions sasdata/fair_database/data/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.urls import path

from . import views

urlpatterns = [
path("list/", views.list_data, name = "list public file_ids"),
path("list/<str:username>/", views.list_data, name = "view users file_ids"),
path("load/<int:db_id>/", views.data_info, name = "views data using file id"),

path("upload/", views.upload, name = "upload data into db"),
path("upload/<data_id>/", views.upload, name = "update file in data"),
path("<int:data_id>/download/", views.download, name = "download data from db"),
]
105 changes: 105 additions & 0 deletions sasdata/fair_database/data/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import os

from django.shortcuts import get_object_or_404
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, Http404, FileResponse
from rest_framework.decorators import api_view
from rest_framework.response import Response

from sasdata.dataloader.loader import Loader
from .serializers import DataSerializer
from .models import Data
from .forms import DataForm

@api_view(['GET'])
def list_data(request, username = None, version = None):
if request.method == 'GET':
if username:
data_list = {"user_data_ids": {}}
if username == request.user.username and request.user.is_authenticated:
private_data = Data.objects.filter(current_user=request.user.id)
for x in private_data:
data_list["user_data_ids"][x.id] = x.file_name
else:
return HttpResponseBadRequest("user is not logged in, or username is not same as current user")
else:
public_data = Data.objects.filter(is_public=True)
data_list = {"public_data_ids": {}}
for x in public_data:
data_list["public_data_ids"][x.id] = x.file_name
return Response(data_list)
return HttpResponseBadRequest("not get method")

@api_view(['GET'])
def data_info(request, db_id, version = None):
if request.method == 'GET':
loader = Loader()
data_db = get_object_or_404(Data, id=db_id)
if data_db.is_public:
data_list = loader.load(data_db.file.path)
contents = [str(data) for data in data_list]
return_data = {data_db.file_name: contents}
# rewrite with "user.is_authenticated"
elif (data_db.current_user == request.user) and request.user.is_authenticated:
data_list = loader.load(data_db.file.path)
contents = [str(data) for data in data_list]
return_data = {data_db.file_name: contents}
else:
return HttpResponseBadRequest("Database is either not public or wrong auth token")
return Response(return_data)
return HttpResponseBadRequest()

@api_view(['POST', 'PUT'])
def upload(request, data_id = None, version = None):
#saves file
if request.method == 'POST':
form = DataForm(request.data, request.FILES)
if form.is_valid():
form.save()
db = Data.objects.get(pk = form.instance.pk)

if request.user.is_authenticated:
serializer = DataSerializer(db, data={"file_name":os.path.basename(form.instance.file.path), "current_user" : request.user.id})
else:
serializer = DataSerializer(db, data={"file_name":os.path.basename(form.instance.file.path)})


#saves or updates file
elif request.method == 'PUT':
#require data_id
if data_id != None and request.user:
if request.user.is_authenticated:
db = get_object_or_404(Data, current_user = request.user.id, id = data_id)
form = DataForm(request.data, request.FILES, instance=db)
if form.is_valid():
form.save()
serializer = DataSerializer(db, data={"file_name":os.path.basename(form.instance.file.path)}, partial = True)
else:
return HttpResponseForbidden("user is not logged in")
else:
return HttpResponseBadRequest()

if serializer.is_valid():
serializer.save()
#TODO get warnings/errors later
return_data = {"current_user":request.user.username, "authenticated" : request.user.is_authenticated, "file_id" : db.id, "file_alternative_name":serializer.data["file_name"],"is_public" : serializer.data["is_public"]}
return Response(return_data)

#downloads a file
def download(request, data_id, version = None):
if request.method == 'GET':
data = get_object_or_404(Data, id=data_id)
if not data.is_public:
# add session key later
if not request.user.is_authenticated:
return HttpResponseBadRequest("data is private, must log in")
if not request.user == data.current_user:
return HttpResponseBadRequest("data is private")
# TODO add issues later
try:
file = open(data.file.path, 'rb')
except Exception as e:
return HttpResponseBadRequest(str(e))
if file is None:
raise Http404("File not found.")
return FileResponse(file, as_attachment=True)
return HttpResponseBadRequest()
Empty file.
16 changes: 16 additions & 0 deletions sasdata/fair_database/fair_database/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for fair_database project.

It exposes the ASGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fair_database.settings')

application = get_asgi_application()
Loading
Loading