mirror of
https://github.com/leaders-of-digital-9-task/backend.git
synced 2024-11-25 10:43:46 +03:00
added auth, dicom crud
This commit is contained in:
parent
8d9d0697da
commit
4f15a29b07
|
@ -3,4 +3,5 @@
|
||||||
<component name="JavaScriptSettings">
|
<component name="JavaScriptSettings">
|
||||||
<option name="languageLevel" value="ES6" />
|
<option name="languageLevel" value="ES6" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (lct_backend)" project-jdk-type="Python SDK" />
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,15 +1,30 @@
|
||||||
from django.conf import settings
|
from dicom.api.views import ListCreateDicomApi, RetrieveUpdateDeleteDicomApi
|
||||||
from rest_framework.routers import DefaultRouter, SimpleRouter
|
from django.urls import include, path
|
||||||
|
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
|
||||||
|
from users.api.views import RegisterView
|
||||||
|
|
||||||
from image_markuper.users.api.views import UserViewSet
|
urlpatterns = [
|
||||||
|
path(
|
||||||
if settings.DEBUG:
|
"auth/",
|
||||||
router = DefaultRouter()
|
include(
|
||||||
else:
|
[
|
||||||
router = SimpleRouter()
|
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
|
||||||
|
path("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
|
||||||
router.register("users", UserViewSet)
|
path("register/", RegisterView.as_view(), name="user_register"),
|
||||||
|
]
|
||||||
|
),
|
||||||
app_name = "api"
|
),
|
||||||
urlpatterns = router.urls
|
path(
|
||||||
|
"dicom/",
|
||||||
|
include(
|
||||||
|
[
|
||||||
|
path("", ListCreateDicomApi.as_view(), name="list_create_dicom"),
|
||||||
|
path(
|
||||||
|
"<str:slug>",
|
||||||
|
RetrieveUpdateDeleteDicomApi.as_view(),
|
||||||
|
name="get_update_delete_dicom",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
|
@ -10,7 +10,7 @@ ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
|
||||||
APPS_DIR = ROOT_DIR / "image_markuper"
|
APPS_DIR = ROOT_DIR / "image_markuper"
|
||||||
env = environ.Env()
|
env = environ.Env()
|
||||||
|
|
||||||
READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=False)
|
READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=True)
|
||||||
if READ_DOT_ENV_FILE:
|
if READ_DOT_ENV_FILE:
|
||||||
# OS environment variables take precedence over variables from .env
|
# OS environment variables take precedence over variables from .env
|
||||||
env.read_env(str(ROOT_DIR / ".env"))
|
env.read_env(str(ROOT_DIR / ".env"))
|
||||||
|
@ -80,6 +80,7 @@ THIRD_PARTY_APPS = [
|
||||||
|
|
||||||
LOCAL_APPS = [
|
LOCAL_APPS = [
|
||||||
"image_markuper.users",
|
"image_markuper.users",
|
||||||
|
"image_markuper.dicom"
|
||||||
# Your stuff: custom apps go here
|
# Your stuff: custom apps go here
|
||||||
]
|
]
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||||
|
@ -302,8 +303,7 @@ SOCIALACCOUNT_FORMS = {"signup": "image_markuper.users.forms.UserSocialSignupFor
|
||||||
# django-rest-framework - https://www.django-rest-framework.org/api-guide/settings/
|
# django-rest-framework - https://www.django-rest-framework.org/api-guide/settings/
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||||
"rest_framework.authentication.SessionAuthentication",
|
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||||
"rest_framework.authentication.TokenAuthentication",
|
|
||||||
),
|
),
|
||||||
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
|
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
|
||||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||||
|
@ -311,18 +311,19 @@ REST_FRAMEWORK = {
|
||||||
|
|
||||||
# django-cors-headers - https://github.com/adamchainz/django-cors-headers#setup
|
# django-cors-headers - https://github.com/adamchainz/django-cors-headers#setup
|
||||||
CORS_URLS_REGEX = r"^/api/.*$"
|
CORS_URLS_REGEX = r"^/api/.*$"
|
||||||
|
|
||||||
# By Default swagger ui is available only to admin user(s). You can change permission classes to change that
|
# By Default swagger ui is available only to admin user(s). You can change permission classes to change that
|
||||||
# See more configuration options at https://drf-spectacular.readthedocs.io/en/latest/settings.html#settings
|
# See more configuration options at https://drf-spectacular.readthedocs.io/en/latest/settings.html#settings
|
||||||
SPECTACULAR_SETTINGS = {
|
SPECTACULAR_SETTINGS = {
|
||||||
"TITLE": "Image markuper API",
|
"TITLE": "Image markuper API",
|
||||||
"DESCRIPTION": "Documentation of API endpoints of Image markuper",
|
"DESCRIPTION": "Documentation of API endpoints of Image markuper",
|
||||||
"VERSION": "1.0.0",
|
"VERSION": "1.0.0",
|
||||||
"SERVE_PERMISSIONS": ["rest_framework.permissions.IsAdminUser"],
|
"SCHEMA_PATH_PREFIX": r"/api/",
|
||||||
|
"SERVE_INCLUDE_SCHEMA": False,
|
||||||
|
"SERVE_PERMISSIONS": ["rest_framework.permissions.AllowAny"],
|
||||||
"SERVERS": [
|
"SERVERS": [
|
||||||
{"url": "http://127.0.0.1:8000", "description": "Local Development server"},
|
{"url": "https://dev.akarpov.ru", "description": "Development server"},
|
||||||
{"url": "https://akarpov.ru", "description": "Production server"},
|
{"url": "https//127.0.0.1:8000", "description": "Development server"},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
# Your stuff...
|
|
||||||
# ------------------------------------------------------------------------------
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from .base import * # noqa
|
from .base import * # noqa
|
||||||
from .base import env
|
from .base import env
|
||||||
|
|
||||||
|
@ -11,7 +13,7 @@ SECRET_KEY = env(
|
||||||
default="XgO9NMQfMY5CNeVNh98WrKRXiQZnvtPzHJrF9ROPhAFLVEG1FvDD2ZRKTdJKVu8p",
|
default="XgO9NMQfMY5CNeVNh98WrKRXiQZnvtPzHJrF9ROPhAFLVEG1FvDD2ZRKTdJKVu8p",
|
||||||
)
|
)
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
|
||||||
ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1"]
|
ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1", "dev.akarpov.ru"]
|
||||||
|
|
||||||
# CACHES
|
# CACHES
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -64,5 +66,9 @@ INSTALLED_APPS += ["django_extensions"] # noqa F405
|
||||||
|
|
||||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#task-eager-propagates
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#task-eager-propagates
|
||||||
CELERY_TASK_EAGER_PROPAGATES = True
|
CELERY_TASK_EAGER_PROPAGATES = True
|
||||||
# Your stuff...
|
|
||||||
# ------------------------------------------------------------------------------
|
SIMPLE_JWT = {
|
||||||
|
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=10000),
|
||||||
|
}
|
||||||
|
|
||||||
|
CORS_ALLOW_ALL_ORIGINS = True
|
||||||
|
|
|
@ -2,21 +2,14 @@ from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from django.views import defaults as default_views
|
from drf_spectacular.views import (
|
||||||
from django.views.generic import TemplateView
|
SpectacularAPIView,
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
SpectacularRedocView,
|
||||||
from rest_framework.authtoken.views import obtain_auth_token
|
SpectacularSwaggerView,
|
||||||
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", TemplateView.as_view(template_name="pages/home.html"), name="home"),
|
path(settings.ADMIN_URL, admin.site.urls)
|
||||||
path(
|
|
||||||
"about/", TemplateView.as_view(template_name="pages/about.html"), name="about"
|
|
||||||
),
|
|
||||||
# Django Admin, use {% url 'admin:index' %}
|
|
||||||
path(settings.ADMIN_URL, admin.site.urls),
|
|
||||||
# User management
|
|
||||||
path("users/", include("image_markuper.users.urls", namespace="users")),
|
|
||||||
path("accounts/", include("allauth.urls")),
|
|
||||||
# Your stuff: custom urls includes go here
|
# Your stuff: custom urls includes go here
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
@ -24,37 +17,23 @@ urlpatterns = [
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
# API base url
|
# API base url
|
||||||
path("api/", include("config.api_router")),
|
path("api/", include("config.api_router")),
|
||||||
# DRF auth token
|
path("api_schema/", SpectacularAPIView.as_view(), name="api-schema"),
|
||||||
path("auth-token/", obtain_auth_token),
|
path("api_rschema/", SpectacularAPIView.as_view(), name="api-redoc-schema"),
|
||||||
path("api/schema/", SpectacularAPIView.as_view(), name="api-schema"),
|
|
||||||
path(
|
path(
|
||||||
"api/docs/",
|
"api/docs/",
|
||||||
SpectacularSwaggerView.as_view(url_name="api-schema"),
|
SpectacularSwaggerView.as_view(url_name="api-schema"),
|
||||||
name="api-docs",
|
name="home",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"api/redoc/",
|
||||||
|
SpectacularRedocView.as_view(url_name="api-redoc-schema"),
|
||||||
|
name="home",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
# This allows the error pages to be debugged during development, just visit
|
# This allows the error pages to be debugged during development, just visit
|
||||||
# these url in browser to see how these error pages look like.
|
# these url in browser to see how these error pages look like.
|
||||||
urlpatterns += [
|
|
||||||
path(
|
|
||||||
"400/",
|
|
||||||
default_views.bad_request,
|
|
||||||
kwargs={"exception": Exception("Bad Request!")},
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
"403/",
|
|
||||||
default_views.permission_denied,
|
|
||||||
kwargs={"exception": Exception("Permission Denied")},
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
"404/",
|
|
||||||
default_views.page_not_found,
|
|
||||||
kwargs={"exception": Exception("Page not Found")},
|
|
||||||
),
|
|
||||||
path("500/", default_views.server_error),
|
|
||||||
]
|
|
||||||
if "debug_toolbar" in settings.INSTALLED_APPS:
|
if "debug_toolbar" in settings.INSTALLED_APPS:
|
||||||
import debug_toolbar
|
import debug_toolbar
|
||||||
|
|
||||||
|
|
0
image_markuper/dicom/__init__.py
Normal file
0
image_markuper/dicom/__init__.py
Normal file
0
image_markuper/dicom/admin.py
Normal file
0
image_markuper/dicom/admin.py
Normal file
0
image_markuper/dicom/api/__init__.py
Normal file
0
image_markuper/dicom/api/__init__.py
Normal file
24
image_markuper/dicom/api/serializers.py
Normal file
24
image_markuper/dicom/api/serializers.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
from dicom.models import Dicom
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class ListDicomSerializer(serializers.ModelSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(
|
||||||
|
view_name="get_update_delete_dicom", lookup_field="slug"
|
||||||
|
)
|
||||||
|
file = serializers.FileField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Dicom
|
||||||
|
fields = ["file", "uploaded", "url"]
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
return Dicom.objects.create(**validated_data, user=self.context["request"].user)
|
||||||
|
|
||||||
|
|
||||||
|
class DicomSerializer(serializers.ModelSerializer):
|
||||||
|
file = serializers.FileField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Dicom
|
||||||
|
fields = ["file", "uploaded"]
|
36
image_markuper/dicom/api/views.py
Normal file
36
image_markuper/dicom/api/views.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
from drf_spectacular.utils import extend_schema
|
||||||
|
from rest_framework import generics
|
||||||
|
from rest_framework.parsers import FormParser, MultiPartParser
|
||||||
|
|
||||||
|
from ..models import Dicom
|
||||||
|
from .serializers import DicomSerializer, ListDicomSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ListCreateDicomApi(generics.ListCreateAPIView):
|
||||||
|
serializer_class = ListDicomSerializer
|
||||||
|
parser_classes = [MultiPartParser, FormParser]
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Dicom.objects.filter(user=self.request.user)
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
operation_id="upload_file",
|
||||||
|
request={
|
||||||
|
"multipart/form-data": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {"file": {"type": "string", "format": "binary"}},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
return self.create(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class RetrieveUpdateDeleteDicomApi(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
def get_queryset(self):
|
||||||
|
return Dicom.objects.filter(user=self.request.user)
|
||||||
|
|
||||||
|
serializer_class = DicomSerializer
|
||||||
|
parser_classes = [MultiPartParser, FormParser]
|
||||||
|
|
||||||
|
lookup_field = "slug"
|
12
image_markuper/dicom/apps.py
Normal file
12
image_markuper/dicom/apps.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class DicomConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "dicom"
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
try:
|
||||||
|
import image_markuper.dicom.signals # noqa F401
|
||||||
|
except ImportError:
|
||||||
|
pass
|
28
image_markuper/dicom/migrations/0001_initial.py
Normal file
28
image_markuper/dicom/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 4.0.8 on 2022-10-26 15:01
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import utils.files
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Dicom',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('slug', models.SlugField()),
|
||||||
|
('file', models.FileField(upload_to=utils.files.media_upload_path)),
|
||||||
|
('uploaded', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
0
image_markuper/dicom/migrations/__init__.py
Normal file
0
image_markuper/dicom/migrations/__init__.py
Normal file
16
image_markuper/dicom/models.py
Normal file
16
image_markuper/dicom/models.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.db import models
|
||||||
|
from utils.files import media_upload_path
|
||||||
|
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
class Dicom(models.Model):
|
||||||
|
user = models.ForeignKey(User, related_name="files", on_delete=models.CASCADE)
|
||||||
|
slug = models.SlugField()
|
||||||
|
|
||||||
|
file = models.FileField(upload_to=media_upload_path)
|
||||||
|
uploaded = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.file.name
|
12
image_markuper/dicom/signals.py
Normal file
12
image_markuper/dicom/signals.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
from dicom.models import Dicom
|
||||||
|
from django.db.models.signals import pre_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from utils.generators import generate_charset
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(pre_save, sender=Dicom)
|
||||||
|
def create_dicom(sender, instance: Dicom, **kwargs):
|
||||||
|
slug = generate_charset(5)
|
||||||
|
while Dicom.objects.filter(slug=slug):
|
||||||
|
slug = generate_charset(5)
|
||||||
|
instance.slug = slug
|
|
@ -15,7 +15,6 @@ class UserAdmin(auth_admin.UserAdmin):
|
||||||
add_form = UserAdminCreationForm
|
add_form = UserAdminCreationForm
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {"fields": ("username", "password")}),
|
(None, {"fields": ("username", "password")}),
|
||||||
(_("Personal info"), {"fields": ("name", "email")}),
|
|
||||||
(
|
(
|
||||||
_("Permissions"),
|
_("Permissions"),
|
||||||
{
|
{
|
||||||
|
@ -30,5 +29,5 @@ class UserAdmin(auth_admin.UserAdmin):
|
||||||
),
|
),
|
||||||
(_("Important dates"), {"fields": ("last_login", "date_joined")}),
|
(_("Important dates"), {"fields": ("last_login", "date_joined")}),
|
||||||
)
|
)
|
||||||
list_display = ["username", "name", "is_superuser"]
|
list_display = ["username", "is_superuser"]
|
||||||
search_fields = ["name"]
|
search_fields = ["username"]
|
||||||
|
|
|
@ -7,8 +7,28 @@ User = get_user_model()
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ["username", "name", "url"]
|
fields = ["username", "url"]
|
||||||
|
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
"url": {"view_name": "api:user-detail", "lookup_field": "username"}
|
"url": {"view_name": "api:user-detail", "lookup_field": "username"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RegisterSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = (
|
||||||
|
"username",
|
||||||
|
"password",
|
||||||
|
)
|
||||||
|
extra_kwargs = {"password": {"write_only": True}}
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
user = User.objects.create(
|
||||||
|
username=validated_data["username"],
|
||||||
|
)
|
||||||
|
|
||||||
|
user.set_password(validated_data["password"])
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from rest_framework import status
|
from rest_framework import generics, status
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin
|
||||||
|
from rest_framework.permissions import AllowAny
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import GenericViewSet
|
from rest_framework.viewsets import GenericViewSet
|
||||||
|
|
||||||
from .serializers import UserSerializer
|
from .serializers import RegisterSerializer, UserSerializer
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
@ -16,10 +17,15 @@ class UserViewSet(RetrieveModelMixin, ListModelMixin, UpdateModelMixin, GenericV
|
||||||
lookup_field = "username"
|
lookup_field = "username"
|
||||||
|
|
||||||
def get_queryset(self, *args, **kwargs):
|
def get_queryset(self, *args, **kwargs):
|
||||||
assert isinstance(self.request.user.id, int)
|
|
||||||
return self.queryset.filter(id=self.request.user.id)
|
return self.queryset.filter(id=self.request.user.id)
|
||||||
|
|
||||||
@action(detail=False)
|
@action(detail=False)
|
||||||
def me(self, request):
|
def me(self, request):
|
||||||
serializer = UserSerializer(request.user, context={"request": request})
|
serializer = UserSerializer(request.user, context={"request": request})
|
||||||
return Response(status=status.HTTP_200_OK, data=serializer.data)
|
return Response(status=status.HTTP_200_OK, data=serializer.data)
|
||||||
|
|
||||||
|
|
||||||
|
class RegisterView(generics.CreateAPIView):
|
||||||
|
queryset = User.objects.all()
|
||||||
|
permission_classes = (AllowAny,)
|
||||||
|
serializer_class = RegisterSerializer
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db.models import CharField
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
|
@ -11,10 +9,9 @@ class User(AbstractUser):
|
||||||
check forms.SignupForm and forms.SocialSignupForms accordingly.
|
check forms.SignupForm and forms.SocialSignupForms accordingly.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#: First and last name do not cover name patterns around the globe
|
|
||||||
name = CharField(_("Name of User"), blank=True, max_length=255)
|
|
||||||
first_name = None # type: ignore
|
first_name = None # type: ignore
|
||||||
last_name = None # type: ignore
|
last_name = None # type: ignore
|
||||||
|
email = None # type: ignore
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Get url for user's detail view.
|
"""Get url for user's detail view.
|
||||||
|
|
|
@ -25,9 +25,6 @@ class UserUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
success_message = _("Information successfully updated")
|
success_message = _("Information successfully updated")
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
assert (
|
|
||||||
self.request.user.is_authenticated
|
|
||||||
) # for mypy to know that the user is authenticated
|
|
||||||
return self.request.user.get_absolute_url()
|
return self.request.user.get_absolute_url()
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
|
|
7
image_markuper/utils/files.py
Normal file
7
image_markuper/utils/files.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from utils.generators import generate_charset
|
||||||
|
|
||||||
|
|
||||||
|
def media_upload_path(instance, filename):
|
||||||
|
return os.path.join(f"uploads/dicom/{generate_charset(7)}/", filename)
|
7
image_markuper/utils/generators.py
Normal file
7
image_markuper/utils/generators.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
|
||||||
|
def generate_charset(length: int) -> str:
|
||||||
|
"""Generate a random string of characters of a given length."""
|
||||||
|
return "".join(random.choice(string.ascii_letters) for _ in range(length))
|
|
@ -1,67 +0,0 @@
|
||||||
import os
|
|
||||||
from collections.abc import Sequence
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
ROOT_DIR_PATH = Path(__file__).parent.resolve()
|
|
||||||
PRODUCTION_DOTENVS_DIR_PATH = ROOT_DIR_PATH / ".envs" / ".production"
|
|
||||||
PRODUCTION_DOTENV_FILE_PATHS = [
|
|
||||||
PRODUCTION_DOTENVS_DIR_PATH / ".django",
|
|
||||||
PRODUCTION_DOTENVS_DIR_PATH / ".postgres",
|
|
||||||
]
|
|
||||||
DOTENV_FILE_PATH = ROOT_DIR_PATH / ".env"
|
|
||||||
|
|
||||||
|
|
||||||
def merge(
|
|
||||||
output_file_path: str, merged_file_paths: Sequence[str], append_linesep: bool = True
|
|
||||||
) -> None:
|
|
||||||
with open(output_file_path, "w") as output_file:
|
|
||||||
for merged_file_path in merged_file_paths:
|
|
||||||
with open(merged_file_path) as merged_file:
|
|
||||||
merged_file_content = merged_file.read()
|
|
||||||
output_file.write(merged_file_content)
|
|
||||||
if append_linesep:
|
|
||||||
output_file.write(os.linesep)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
merge(DOTENV_FILE_PATH, PRODUCTION_DOTENV_FILE_PATHS)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("merged_file_count", range(3))
|
|
||||||
@pytest.mark.parametrize("append_linesep", [True, False])
|
|
||||||
def test_merge(tmpdir_factory, merged_file_count: int, append_linesep: bool):
|
|
||||||
tmp_dir_path = Path(str(tmpdir_factory.getbasetemp()))
|
|
||||||
|
|
||||||
output_file_path = tmp_dir_path / ".env"
|
|
||||||
|
|
||||||
expected_output_file_content = ""
|
|
||||||
merged_file_paths = []
|
|
||||||
for i in range(merged_file_count):
|
|
||||||
merged_file_ord = i + 1
|
|
||||||
|
|
||||||
merged_filename = f".service{merged_file_ord}"
|
|
||||||
merged_file_path = tmp_dir_path / merged_filename
|
|
||||||
|
|
||||||
merged_file_content = merged_filename * merged_file_ord
|
|
||||||
|
|
||||||
with open(merged_file_path, "w+") as file:
|
|
||||||
file.write(merged_file_content)
|
|
||||||
|
|
||||||
expected_output_file_content += merged_file_content
|
|
||||||
if append_linesep:
|
|
||||||
expected_output_file_content += os.linesep
|
|
||||||
|
|
||||||
merged_file_paths.append(merged_file_path)
|
|
||||||
|
|
||||||
merge(output_file_path, merged_file_paths, append_linesep)
|
|
||||||
|
|
||||||
with open(output_file_path) as output_file:
|
|
||||||
actual_output_file_content = output_file.read()
|
|
||||||
|
|
||||||
assert actual_output_file_content == expected_output_file_content
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -21,5 +21,6 @@ django-redis==5.2.0 # https://github.com/jazzband/django-redis
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
djangorestframework==3.14.0 # https://github.com/encode/django-rest-framework
|
djangorestframework==3.14.0 # https://github.com/encode/django-rest-framework
|
||||||
django-cors-headers==3.13.0 # https://github.com/adamchainz/django-cors-headers
|
django-cors-headers==3.13.0 # https://github.com/adamchainz/django-cors-headers
|
||||||
|
djangorestframework-simplejwt==5.2.2
|
||||||
# DRF-spectacular for api documentation
|
# DRF-spectacular for api documentation
|
||||||
drf-spectacular==0.24.2 # https://github.com/tfranzel/drf-spectacular
|
drf-spectacular==0.24.2 # https://github.com/tfranzel/drf-spectacular
|
||||||
|
|
Loading…
Reference in New Issue
Block a user