commit 8ec69c5d16665930d88fe48c5e0f68ad55f710d6 Author: The unwasted guests Date: Tue Jan 28 21:43:26 2025 +1000 back-end 1.0 diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/__pycache__/__init__.cpython-312.pyc b/backend/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..db1e5a6 Binary files /dev/null and b/backend/__pycache__/__init__.cpython-312.pyc differ diff --git a/backend/__pycache__/settings.cpython-312.pyc b/backend/__pycache__/settings.cpython-312.pyc new file mode 100644 index 0000000..ed25646 Binary files /dev/null and b/backend/__pycache__/settings.cpython-312.pyc differ diff --git a/backend/__pycache__/urls.cpython-312.pyc b/backend/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000..f59f21f Binary files /dev/null and b/backend/__pycache__/urls.cpython-312.pyc differ diff --git a/backend/__pycache__/wsgi.cpython-312.pyc b/backend/__pycache__/wsgi.cpython-312.pyc new file mode 100644 index 0000000..8e96749 Binary files /dev/null and b/backend/__pycache__/wsgi.cpython-312.pyc differ diff --git a/backend/asgi.py b/backend/asgi.py new file mode 100644 index 0000000..ed01e6a --- /dev/null +++ b/backend/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for backend 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', 'backend.settings') + +application = get_asgi_application() diff --git a/backend/settings.py b/backend/settings.py new file mode 100644 index 0000000..64c0af3 --- /dev/null +++ b/backend/settings.py @@ -0,0 +1,145 @@ +""" +Django settings for backend project. + +Generated by 'django-admin startproject' using Django 5.1.5. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-z8m_e(v=^%)1f-=hgcl1d7a2%rg_#w$r$ig%x%l8ua_cj(ts)w' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', # Django Rest Framework + 'orthanc', # Наше приложение +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'backend.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'backend.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'xray', + 'USER': 'postgres', + 'PASSWORD': '1240069630Bk!', + 'HOST': 'localhost', + 'PORT': '5432', + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/5.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.1/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ), + 'DEFAULT_PERMISSION_CLASSES': ( + 'rest_framework.permissions.IsAuthenticated', + ), +} + +# Настройки токенов +from datetime import timedelta +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30), # Срок действия токена + 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), + 'AUTH_HEADER_TYPES': ('Bearer',), +} \ No newline at end of file diff --git a/backend/urls.py b/backend/urls.py new file mode 100644 index 0000000..fb36519 --- /dev/null +++ b/backend/urls.py @@ -0,0 +1,25 @@ +""" +URL configuration for backend project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path('admin/', admin.site.urls), + # path('patients/', include('orthanc.urls')), + path('auth/', include('orthanc.urls')), +] + diff --git a/backend/wsgi.py b/backend/wsgi.py new file mode 100644 index 0000000..07bda9d --- /dev/null +++ b/backend/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for backend project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..eb6431e --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/orthanc/__init__.py b/orthanc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/orthanc/__pycache__/__init__.cpython-312.pyc b/orthanc/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..53b16fb Binary files /dev/null and b/orthanc/__pycache__/__init__.cpython-312.pyc differ diff --git a/orthanc/__pycache__/admin.cpython-312.pyc b/orthanc/__pycache__/admin.cpython-312.pyc new file mode 100644 index 0000000..d276763 Binary files /dev/null and b/orthanc/__pycache__/admin.cpython-312.pyc differ diff --git a/orthanc/__pycache__/apps.cpython-312.pyc b/orthanc/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000..bb621c0 Binary files /dev/null and b/orthanc/__pycache__/apps.cpython-312.pyc differ diff --git a/orthanc/__pycache__/models.cpython-312.pyc b/orthanc/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000..3848d22 Binary files /dev/null and b/orthanc/__pycache__/models.cpython-312.pyc differ diff --git a/orthanc/__pycache__/serializers.cpython-312.pyc b/orthanc/__pycache__/serializers.cpython-312.pyc new file mode 100644 index 0000000..7fb4293 Binary files /dev/null and b/orthanc/__pycache__/serializers.cpython-312.pyc differ diff --git a/orthanc/__pycache__/tasks.cpython-312.pyc b/orthanc/__pycache__/tasks.cpython-312.pyc new file mode 100644 index 0000000..4a633f3 Binary files /dev/null and b/orthanc/__pycache__/tasks.cpython-312.pyc differ diff --git a/orthanc/__pycache__/urls.cpython-312.pyc b/orthanc/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000..b9b8307 Binary files /dev/null and b/orthanc/__pycache__/urls.cpython-312.pyc differ diff --git a/orthanc/__pycache__/views.cpython-312.pyc b/orthanc/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000..5bc8537 Binary files /dev/null and b/orthanc/__pycache__/views.cpython-312.pyc differ diff --git a/orthanc/admin.py b/orthanc/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/orthanc/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/orthanc/apps.py b/orthanc/apps.py new file mode 100644 index 0000000..d66b5d8 --- /dev/null +++ b/orthanc/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class OrthancConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'orthanc' diff --git a/orthanc/migrations/0001_initial.py b/orthanc/migrations/0001_initial.py new file mode 100644 index 0000000..c4a206c --- /dev/null +++ b/orthanc/migrations/0001_initial.py @@ -0,0 +1,27 @@ +# Generated by Django 5.1.5 on 2025-01-26 03:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Patient', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('orthanc_id', models.CharField(max_length=255, unique=True)), + ('patient_id', models.CharField(blank=True, max_length=255, null=True)), + ('patient_name', models.CharField(blank=True, max_length=255, null=True)), + ('patient_sex', models.CharField(blank=True, max_length=10, null=True)), + ('patient_birth_date', models.CharField(blank=True, max_length=20, null=True)), + ('studies', models.JSONField(blank=True, null=True)), + ('patient_metadata', models.JSONField(blank=True, null=True)), + ], + ), + ] diff --git a/orthanc/migrations/0002_series_instance.py b/orthanc/migrations/0002_series_instance.py new file mode 100644 index 0000000..ccecfef --- /dev/null +++ b/orthanc/migrations/0002_series_instance.py @@ -0,0 +1,39 @@ +# Generated by Django 5.1.5 on 2025-01-26 08:47 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('orthanc', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Series', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('orthanc_id', models.CharField(max_length=255, unique=True)), + ('parent_study', models.CharField(max_length=255)), + ('main_dicom_tags', models.JSONField(blank=True, null=True)), + ('status', models.CharField(blank=True, max_length=50, null=True)), + ('is_stable', models.BooleanField(default=False)), + ('last_update', models.CharField(blank=True, max_length=50, null=True)), + ('patient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='series', to='orthanc.patient')), + ], + ), + migrations.CreateModel( + name='Instance', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('orthanc_id', models.CharField(max_length=255, unique=True)), + ('file_size', models.IntegerField(blank=True, null=True)), + ('file_uuid', models.CharField(blank=True, max_length=255, null=True)), + ('main_dicom_tags', models.JSONField(blank=True, null=True)), + ('index_in_series', models.IntegerField(blank=True, null=True)), + ('parent_series', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='instances', to='orthanc.series')), + ], + ), + ] diff --git a/orthanc/migrations/__init__.py b/orthanc/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/orthanc/migrations/__pycache__/0001_initial.cpython-312.pyc b/orthanc/migrations/__pycache__/0001_initial.cpython-312.pyc new file mode 100644 index 0000000..f65ddcd Binary files /dev/null and b/orthanc/migrations/__pycache__/0001_initial.cpython-312.pyc differ diff --git a/orthanc/migrations/__pycache__/0002_series_instance.cpython-312.pyc b/orthanc/migrations/__pycache__/0002_series_instance.cpython-312.pyc new file mode 100644 index 0000000..ad49ff3 Binary files /dev/null and b/orthanc/migrations/__pycache__/0002_series_instance.cpython-312.pyc differ diff --git a/orthanc/migrations/__pycache__/__init__.cpython-312.pyc b/orthanc/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..b99fe09 Binary files /dev/null and b/orthanc/migrations/__pycache__/__init__.cpython-312.pyc differ diff --git a/orthanc/models.py b/orthanc/models.py new file mode 100644 index 0000000..f711c0d --- /dev/null +++ b/orthanc/models.py @@ -0,0 +1,36 @@ +from django.db import models + +class Patient(models.Model): + orthanc_id = models.CharField(max_length=255, unique=True) + patient_id = models.CharField(max_length=255, null=True, blank=True) + patient_name = models.CharField(max_length=255, null=True, blank=True) + patient_sex = models.CharField(max_length=10, null=True, blank=True) + patient_birth_date = models.CharField(max_length=20, null=True, blank=True) + studies = models.JSONField(null=True, blank=True) # Массив ID исследований + patient_metadata = models.JSONField(null=True, blank=True) + + def __str__(self): + return self.patient_name or "Unknown Patient" + +class Series(models.Model): + orthanc_id = models.CharField(max_length=255, unique=True) + parent_study = models.CharField(max_length=255) + patient = models.ForeignKey(Patient, related_name="series", on_delete=models.CASCADE) + main_dicom_tags = models.JSONField(null=True, blank=True) + status = models.CharField(max_length=50, null=True, blank=True) + is_stable = models.BooleanField(default=False) + last_update = models.CharField(max_length=50, null=True, blank=True) + + def __str__(self): + return self.main_dicom_tags.get("SeriesDescription", "Unknown Series") + +class Instance(models.Model): + orthanc_id = models.CharField(max_length=255, unique=True) + parent_series = models.ForeignKey(Series, related_name="instances", on_delete=models.CASCADE) + file_size = models.IntegerField(null=True, blank=True) + file_uuid = models.CharField(max_length=255, null=True, blank=True) + main_dicom_tags = models.JSONField(null=True, blank=True) + index_in_series = models.IntegerField(null=True, blank=True) + + def __str__(self): + return self.main_dicom_tags.get("SOPInstanceUID", "Unknown Instance") diff --git a/orthanc/serializers.py b/orthanc/serializers.py new file mode 100644 index 0000000..018e792 --- /dev/null +++ b/orthanc/serializers.py @@ -0,0 +1,7 @@ +from rest_framework import serializers +from .models import Patient + +class PatientSerializer(serializers.ModelSerializer): + class Meta: + model = Patient + fields = "__all__" diff --git a/orthanc/tasks.py b/orthanc/tasks.py new file mode 100644 index 0000000..6f82b16 --- /dev/null +++ b/orthanc/tasks.py @@ -0,0 +1,108 @@ +import requests +from urllib3.exceptions import InsecureRequestWarning + +from .models import Patient, Series, Instance + +# Отключение предупреждений о небезопасном соединении +requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + +ORTHANC_BASE_URL = "http://192.168.2.60:8042" +ORTHANC_USERNAME = "writehost" +ORTHANC_PASSWORD = "writehost" + +# 1. Получение всех пациентов +def fetch_patients(): + url = f"{ORTHANC_BASE_URL}/patients" + response = requests.get(url, auth=(ORTHANC_USERNAME, ORTHANC_PASSWORD)) + response.raise_for_status() + return response.json() + +# 2. Получение информации о конкретном пациенте +def fetch_patient_details(orthanc_id): + url = f"{ORTHANC_BASE_URL}/patients/{orthanc_id}" + response = requests.get(url, auth=(ORTHANC_USERNAME, ORTHANC_PASSWORD)) + response.raise_for_status() + return response.json() + +# 3. Получение данных об исследовании +def fetch_study_details(study_id): + url = f"{ORTHANC_BASE_URL}/studies/{study_id}" + response = requests.get(url, auth=(ORTHANC_USERNAME, ORTHANC_PASSWORD)) + response.raise_for_status() + return response.json() + +# 4. Получение данных о серии +def fetch_series_details(series_id): + url = f"{ORTHANC_BASE_URL}/series/{series_id}" + response = requests.get(url, auth=(ORTHANC_USERNAME, ORTHANC_PASSWORD)) + response.raise_for_status() + return response.json() + +# 5. Получение данных об изображении (инстансе) +def fetch_instance_details(instance_id): + url = f"{ORTHANC_BASE_URL}/instances/{instance_id}" + response = requests.get(url, auth=(ORTHANC_USERNAME, ORTHANC_PASSWORD)) + response.raise_for_status() + return response.json() + +# Основная синхронизация +def sync_patients(): + patient_ids = fetch_patients() + for patient_id in patient_ids: + patient_data = fetch_patient_details(patient_id) + + # Синхронизация пациента + patient, created = Patient.objects.update_or_create( + orthanc_id=patient_id, + defaults={ + "patient_id": patient_data["MainDicomTags"].get("PatientID"), + "patient_name": patient_data["MainDicomTags"].get("PatientName"), + "patient_sex": patient_data["MainDicomTags"].get("PatientSex"), + "patient_birth_date": patient_data["MainDicomTags"].get("PatientBirthDate"), + "studies": patient_data.get("Studies", []), + "patient_metadata": patient_data.get("Labels", []), + }, + ) + + # Синхронизация исследований (Studies) + for study_id in patient_data.get("Studies", []): + sync_study(study_id, patient) + +# Синхронизация исследования +def sync_study(study_id, patient): + study_data = fetch_study_details(study_id) + for series_id in study_data.get("Series", []): + sync_series(series_id, patient) + +# Синхронизация серии +def sync_series(series_id, patient): + series_data = fetch_series_details(series_id) + series, created = Series.objects.update_or_create( + orthanc_id=series_id, + defaults={ + "parent_study": series_data["ParentStudy"], + "patient": patient, + "main_dicom_tags": series_data.get("MainDicomTags", {}), + "status": series_data.get("Status"), + "is_stable": series_data.get("IsStable", False), + "last_update": series_data.get("LastUpdate"), + }, + ) + + # Синхронизация снимков (Instances) + for instance_id in series_data.get("Instances", []): + sync_instance(instance_id, series) + +# Синхронизация снимка +def sync_instance(instance_id, series): + instance_data = fetch_instance_details(instance_id) + Instance.objects.update_or_create( + orthanc_id=instance_id, + defaults={ + "parent_series": series, + "file_size": instance_data.get("FileSize"), + "file_uuid": instance_data.get("FileUuid"), + "main_dicom_tags": instance_data.get("MainDicomTags", {}), + "index_in_series": instance_data.get("IndexInSeries"), + }, + ) diff --git a/orthanc/tests.py b/orthanc/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/orthanc/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/orthanc/urls.py b/orthanc/urls.py new file mode 100644 index 0000000..2ce2c15 --- /dev/null +++ b/orthanc/urls.py @@ -0,0 +1,12 @@ +from django.urls import path +from .views import PatientListView, SyncPatientsView, ProtectedView +from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView + +urlpatterns = [ + path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # Получение токена + path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # Обновление токена + path('', PatientListView.as_view(), name='patient-list'), + path('sync/', SyncPatientsView.as_view(), name='sync-patients'), + path('protected/', ProtectedView.as_view(), name='protected'), + +] diff --git a/orthanc/views.py b/orthanc/views.py new file mode 100644 index 0000000..abedb1a --- /dev/null +++ b/orthanc/views.py @@ -0,0 +1,76 @@ +# from rest_framework.views import APIView +# from rest_framework.response import Response +# from rest_framework import status +# from .models import Patient +# from .serializers import PatientSerializer +# from .tasks import fetch_patients, fetch_patient_details, sync_patients +# +# +# class PatientListView(APIView): +# def get(self, request): +# patients = Patient.objects.all() +# serializer = PatientSerializer(patients, many=True) +# return Response(serializer.data) +# +# class SyncPatientsView(APIView): +# def post(self, request): +# try: +# patient_ids = fetch_patients() +# for orthanc_id in patient_ids: +# patient_data = fetch_patient_details(orthanc_id) +# patient, created = Patient.objects.update_or_create( +# orthanc_id=orthanc_id, +# defaults={ +# "patient_id": patient_data["MainDicomTags"].get("PatientID"), +# "patient_name": patient_data["MainDicomTags"].get("PatientName"), +# "patient_sex": patient_data["MainDicomTags"].get("PatientSex"), +# "patient_birth_date": patient_data["MainDicomTags"].get("PatientBirthDate"), +# "studies": patient_data.get("Studies", []), +# "patient_metadata": patient_data, +# }, +# ) +# return Response({"message": "Synchronization completed successfully"}) +# except Exception as e: +# return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) +# +# class SyncPatientsView(APIView): +# def post(self, request): +# try: +# sync_patients() +# return Response({"detail": "Synchronization completed successfully."}, status=status.HTTP_200_OK) +# except Exception as e: +# return Response({"detail": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + + +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status +from .models import Patient +from .serializers import PatientSerializer +from .tasks import fetch_patients, fetch_patient_details, sync_patients +from rest_framework.permissions import IsAuthenticated + + + +class ProtectedView(APIView): + permission_classes = [IsAuthenticated] + + def get(self, request): + return Response({"message": f"Привет, {request.user.username}! Вы авторизованы."}) + +# Эндпоинт для получения списка пациентов +class PatientListView(APIView): + def get(self, request): + patients = Patient.objects.all() + serializer = PatientSerializer(patients, many=True) + return Response(serializer.data) + +# Эндпоинт для синхронизации данных с Orthanc +class SyncPatientsView(APIView): + def post(self, request): + try: + sync_patients() + return Response({"detail": "Synchronization completed successfully."}, status=status.HTTP_200_OK) + except Exception as e: + return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)