From 481dd78bf98de4bdd5f1da1ce7725338c942503b Mon Sep 17 00:00:00 2001 From: Bryan Larson Date: Mon, 27 Mar 2023 09:18:29 -0600 Subject: [PATCH 1/5] HYP-280 - Implemented initial API --- app/api/__init__.py | 0 app/api/admin.py | 3 + app/api/api.py | 119 ++++++++++++++++++++++++++++ app/api/apps.py | 6 ++ app/api/auth.py | 45 +++++++++++ app/api/migrations/__init__.py | 0 app/api/models.py | 3 + app/api/scheme.py | 17 ++++ app/api/serializers.py | 43 ++++++++++ app/api/tests.py | 3 + app/api/urls.py | 21 +++++ app/api/views.py | 3 + app/hypatio/auth0authenticate.py | 16 ++-- app/hypatio/settings.py | 27 +++++++ app/hypatio/urls.py | 1 + requirements.in | 3 + requirements.txt | 130 +++++++++++++++++++++++-------- 17 files changed, 402 insertions(+), 38 deletions(-) create mode 100644 app/api/__init__.py create mode 100644 app/api/admin.py create mode 100644 app/api/api.py create mode 100644 app/api/apps.py create mode 100644 app/api/auth.py create mode 100644 app/api/migrations/__init__.py create mode 100644 app/api/models.py create mode 100644 app/api/scheme.py create mode 100644 app/api/serializers.py create mode 100644 app/api/tests.py create mode 100644 app/api/urls.py create mode 100644 app/api/views.py diff --git a/app/api/__init__.py b/app/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/api/admin.py b/app/api/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/app/api/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/api/api.py b/app/api/api.py new file mode 100644 index 00000000..95c34e83 --- /dev/null +++ b/app/api/api.py @@ -0,0 +1,119 @@ +from django.http import Http404 +from django.contrib.auth.models import User +from django.db.models import Q +from django.shortcuts import get_object_or_404 + +from datetime import datetime, timedelta +from rest_framework.generics import ListAPIView, RetrieveAPIView +from rest_framework.views import APIView +from rest_framework import viewsets +from rest_framework.response import Response +from rest_framework import authentication, permissions +from rest_framework import exceptions +from rest_framework.decorators import action +from dbmi_client import authz +from dbmi_client.authn import DBMIModelUser +from django_filters.rest_framework import DjangoFilterBackend +from drf_spectacular.utils import extend_schema, OpenApiParameter, extend_schema_view + +from api.scheme import JWTScheme +from projects.models import DataProject, HostedFile +from api.serializers import ( + DataProjectSerializer, + HostedFileSerializer, + HostedFileDownloadSerializer, +) +from hypatio.file_services import get_download_url + + +class HostedFilePermission(permissions.BasePermission): + """ + This BasePermission subclass ensures the requesting user has adequate + permissions on the DataProject to which the HostedFile belongs. + """ + + READ_PERMISSIONS = ["VIEW", "MANAGE"] + WRITE_PERMISSIONS = ["MANAGE"] + + def has_permission(self, request, view): + if not request.user.is_authenticated: + return False + + # Check Participant objects first + if request.user.participant_set.filter( + project=view.project, + permission__in=self.READ_PERMISSIONS): + return True + + if authz.has_a_permission( + request=request, + email=request.user.email, + item=f"Hypatio.{view.project.project_key}", + permissions=self.READ_PERMISSIONS, + check_parents=True): + return True + + +class DataProjectViewSet(viewsets.ReadOnlyModelViewSet): + """ + A view for listing or retrieving projects. + """ + authentication_classes = [DBMIModelUser] + permission_classes = [permissions.IsAuthenticated] + filter_backends = [DjangoFilterBackend] + queryset = DataProject.objects.filter(visible=True) + serializer_class = DataProjectSerializer + lookup_field = "id" + + +# Define parameters schema for detail views +detail_parameters = [ + OpenApiParameter( + "project_id", + type=int, + description="The unique ID of the project containing the file(s).", + location=OpenApiParameter.PATH, + required=True, + ), +] + +@extend_schema_view( + list=extend_schema( + parameters=detail_parameters, + ), + retrieve=extend_schema( + parameters=detail_parameters, + ), + download=extend_schema( + description="A view for downloading a project's files.", + parameters=detail_parameters, + responses=HostedFileDownloadSerializer, + ), +) +class HostedFileViewSet(viewsets.ReadOnlyModelViewSet): + """ + A view for listing or retrieving a projects's files. + """ + authentication_classes = [DBMIModelUser] + permission_classes = [permissions.IsAuthenticated, HostedFilePermission] + filter_backends = [DjangoFilterBackend] + queryset = HostedFile.objects.filter(enabled=True) + serializer_class = HostedFileSerializer + lookup_field = "id" + project_lookup = "project_id" + + def get_queryset(self): + return HostedFile.objects.filter( + project=self.kwargs[self.project_lookup], + enabled=True, + ) + + def initial(self, request, *args, **kwargs): + print(kwargs) + self.project = get_object_or_404(DataProject.objects.all(), pk=kwargs[self.project_lookup]) + return super(HostedFileViewSet, self).initial(request, args, kwargs) + + @action(detail=True, methods=['get']) + def download(self, request, project_id, id): + serializer = HostedFileDownloadSerializer(self.get_object()) + return Response(serializer.data) diff --git a/app/api/apps.py b/app/api/apps.py new file mode 100644 index 00000000..a6eb4edd --- /dev/null +++ b/app/api/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ApiConfig(AppConfig): + name = 'api' + default_auto_field = 'django.db.models.BigAutoField' diff --git a/app/api/auth.py b/app/api/auth.py new file mode 100644 index 00000000..4a199586 --- /dev/null +++ b/app/api/auth.py @@ -0,0 +1,45 @@ +from rest_framework import permissions +from django.core.exceptions import ObjectDoesNotExist + +from projects.models import DataProject +from projects.models import Participant + +import logging +logger = logging.getLogger(__name__) + + +class DataProjectPermission(permissions.BasePermission): + message = 'Access to data project is prohibited.' + + def has_object_permission(self, request, view, obj): + + # Ensure user has permission on the given project. + + # Get the project + try: + project = DataProject.objects.get(project_key=obj) + except ObjectDoesNotExist: + logger.debug(f"No project found for key: {obj}") + return False + + # If the project doesn't require authorization, grant access + if not project.requires_authorization: + logger.debug(f"No auth for project, access granted for: {obj}{request.user.email}") + return True + + # Get their permission for this project + try: + participant = Participant.objects.get(user=request.user, project=project) + + # Check permission + if participant.permission == "VIEW": + logger.debug(f"Access granted for: {obj}{request.user.email}") + return True + + except ObjectDoesNotExist: + logger.debug(f"Participant does not exist for: {obj}/{request.user.email}", extra={ + "request": request, "project": obj, "user": request.user, + }) + + logger.debug(f"Access denied for: {obj}{request.user.email}") + return False diff --git a/app/api/migrations/__init__.py b/app/api/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/api/models.py b/app/api/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/app/api/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/app/api/scheme.py b/app/api/scheme.py new file mode 100644 index 00000000..bd90a228 --- /dev/null +++ b/app/api/scheme.py @@ -0,0 +1,17 @@ +from django.utils.translation import gettext_lazy as _ +from drf_spectacular.extensions import OpenApiAuthenticationExtension + + +class JWTScheme(OpenApiAuthenticationExtension): + target_class = 'dbmi_client.authn.DBMIModelUser' + name = 'JWT Authentication' + + def get_security_definition(self, auto_schema): + return { + 'type': 'apiKey', + 'in': 'header', + 'name': 'Authorization', + 'description': _( + 'Token-based authentication with required prefix "%s" (JWT can be viewed when logged in at https://authentication.dbmi.hms.harvard.edu/)' + ) % "JWT" + } diff --git a/app/api/serializers.py b/app/api/serializers.py new file mode 100644 index 00000000..10f00929 --- /dev/null +++ b/app/api/serializers.py @@ -0,0 +1,43 @@ +from rest_framework import serializers +from datetime import datetime, timedelta + +from drf_spectacular.utils import extend_schema_field +from drf_spectacular.types import OpenApiTypes + +from projects.models import DataProject +from projects.models import HostedFile +from hypatio.file_services import get_download_url + + +class DataProjectSerializer(serializers.ModelSerializer): + class Meta: + model = DataProject + fields = [ + 'id', 'name', 'project_key', 'description', + 'short_description', 'created', 'modified', #TODO: 'group', + ] + +class HostedFileSerializer(serializers.ModelSerializer): + class Meta: + model = HostedFile + fields = [ + 'id', 'project', 'uuid', 'long_name', 'description', + 'file_name', 'file_location', 'created', 'modified' + ] + + +class HostedFileDownloadSerializer(serializers.ModelSerializer): + url = serializers.SerializerMethodField() + expires = serializers.SerializerMethodField() + + class Meta: + model = HostedFile + fields = ['url', 'expires'] + + @extend_schema_field(OpenApiTypes.URI) + def get_url(self, obj): + return get_download_url(obj.file_location + "/" + obj.file_name) + + @extend_schema_field(OpenApiTypes.DATETIME) + def get_expires(self, obj): + return datetime.now() + timedelta(hours=1) diff --git a/app/api/tests.py b/app/api/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/app/api/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/api/urls.py b/app/api/urls.py new file mode 100644 index 00000000..b1238358 --- /dev/null +++ b/app/api/urls.py @@ -0,0 +1,21 @@ +from django.urls import include, re_path +from django.http import HttpResponse +from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView, SpectacularRedocView +from rest_framework_nested import routers +from api.api import DataProjectViewSet, HostedFileViewSet + +router = routers.SimpleRouter() +router.register(r'projects', DataProjectViewSet) + +projects_router = routers.NestedSimpleRouter(router, r'projects', lookup='project') +projects_router.register(r'files', HostedFileViewSet, basename='project-files') + +app_name = 'api' +urlpatterns = [ + re_path(r'^schema/?$', SpectacularAPIView.as_view(), name='schema'), + re_path(r'^schema/redoc/', SpectacularRedocView.as_view(url_name='api:schema'), name='redoc'), + re_path(r'^schema/swagger/?$', SpectacularSwaggerView.as_view(url_name='api:schema'), name='swagger'), + re_path(r'^v1/', include(router.urls)), + re_path(r'^v1/', include(projects_router.urls)), + re_path(r'^', lambda request: HttpResponse(status=404)), +] diff --git a/app/api/views.py b/app/api/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/app/api/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/app/hypatio/auth0authenticate.py b/app/hypatio/auth0authenticate.py index 8e65a49c..2fcd60aa 100644 --- a/app/hypatio/auth0authenticate.py +++ b/app/hypatio/auth0authenticate.py @@ -14,7 +14,7 @@ from django.core.exceptions import PermissionDenied from dbmi_client.settings import dbmi_settings from dbmi_client.settings import dbmi_settings -from dbmi_client.authn import validate_request, login_redirect_url +from dbmi_client.authn import validate_request, login_redirect_url, get_jwt_payload, get_jwt logger = logging.getLogger(__name__) @@ -259,14 +259,20 @@ def logout_redirect(request): class Auth0Authentication(object): def authenticate(self, request, **token_dictionary): - logger.debug("Authenticate User: {}/{}".format(token_dictionary.get('sub'), token_dictionary.get('email'))) + + # Get the JWT payload + payload = get_jwt_payload(request, verify=True) + if not payload: + return None + + logger.debug("Authenticate User: {}/{}".format(payload.get('sub'), payload.get('email'))) try: - user = User.objects.get(username=token_dictionary["email"]) + user = User.objects.get(username=payload["email"]) except User.DoesNotExist: - logger.debug("User not found, creating: {}".format(token_dictionary.get('email'))) + logger.debug("User not found, creating: {}".format(payload.get('email'))) - user = User(username=token_dictionary["email"], email=token_dictionary["email"]) + user = User(username=payload["email"], email=payload["email"]) user.save() return user diff --git a/app/hypatio/settings.py b/app/hypatio/settings.py index fdd870c4..2c699678 100644 --- a/app/hypatio/settings.py +++ b/app/hypatio/settings.py @@ -57,6 +57,9 @@ 'storages', 'django_jsonfield_backport', 'django_q', + 'rest_framework', + 'drf_spectacular', + 'django_filters', ] MIDDLEWARE = [ @@ -279,6 +282,30 @@ ##################################################################################### +##################################################################################### +# Django Rest Framework settings +##################################################################################### + +REST_FRAMEWORK = { + 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', +} + +##################################################################################### +# API Schema settings +##################################################################################### + +SPECTACULAR_SETTINGS = { + 'TITLE': 'HMS DBMI Portal API', + 'DESCRIPTION': 'API for Portal projects and data sets', + 'VERSION': '1.0.0', + 'SERVE_INCLUDE_SCHEMA': False, + 'SERVE_AUTHENTICATION': [], + # OTHER SETTINGS +} + +##################################################################################### + LOGGING = { 'version': 1, 'disable_existing_loggers': False, diff --git a/app/hypatio/urls.py b/app/hypatio/urls.py index 28b9ffef..f97fb4cc 100644 --- a/app/hypatio/urls.py +++ b/app/hypatio/urls.py @@ -14,6 +14,7 @@ re_path(r'^manage/', include('manage.urls', namespace='manage')), re_path(r'^projects/', include('projects.urls', namespace='projects')), re_path(r'^profile/', include('profile.urls', namespace='profile')), + re_path(r'^api/', include('api.urls', namespace='api')), re_path(r'^data-sets/$', list_data_projects, name='data-sets'), re_path(r'^data-challenges/$', list_data_challenges, name='data-challenges'), re_path(r'^software-projects/$', list_software_projects, name='software-projects'), diff --git a/requirements.in b/requirements.in index 56a0cfa1..7d06a046 100644 --- a/requirements.in +++ b/requirements.in @@ -6,6 +6,7 @@ django-bootstrap3<23.0 django-bootstrap-datepicker-plus<6.0 django-countries<8.0 django-dbmi-client<2.0 +django-filter<24.0 django-health-check<4.0 django-jquery<4.0 django-jsonfield-backport<2.0 @@ -15,6 +16,8 @@ django-stronghold<=1.0 djangorestframework<4.0 django-smtp-ssl<2.0 django-q<2.0 +drf-nested-routers<=1.0 +drf-spectacular<=1.0 furl<3.0 mysqlclient<3.0 python-dateutil<3.0 diff --git a/requirements.txt b/requirements.txt index d8b1fb1e..ae20477e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,21 +14,25 @@ asgiref==3.6.0 \ # via # django # django-countries -awscli==1.27.98 \ - --hash=sha256:7d4165a1d0f16d36d08a2aef8d13f9f5de6cc3d9ebd02c045270269de9582c84 \ - --hash=sha256:f6edc2509644d79246287c066f52db00b8f29f4e3e5ee886b3c986cdd9248b5d +attrs==22.2.0 \ + --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \ + --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99 + # via jsonschema +awscli==1.27.99 \ + --hash=sha256:5abaf226dc45cd31df1171617071bf0067995cb7febc13c6d908c0952a8685f1 \ + --hash=sha256:c6961a9aaf56b671b30ab0f835fc7ff1bd5122f8e0cb7a52cd48bd3ad0f8d41d # via -r requirements.in blessed==1.20.0 \ --hash=sha256:0c542922586a265e699188e52d5f5ac5ec0dd517e5a1041d90d2bbf23f906058 \ --hash=sha256:2cdd67f8746e048f00df47a2880f4d6acbcdb399031b604e34ba8f71d5787680 # via django-q -boto3==1.26.98 \ - --hash=sha256:983ec9e539431c29b5265e435b91af7c0d77a75809e173427798edb4ede1d69c \ - --hash=sha256:f35a42c6d0130a75e58485efa94383256d9b8c72c3a31ad872807873a8800363 +boto3==1.26.99 \ + --hash=sha256:536d9e7a074f4f16cc87b426f91b3079edd5c6927541a04f7e3fa28c53293532 \ + --hash=sha256:d9fd57d6e98fd919cdbd613428f685e05b48c71477fda1aa7fbf51867262c7d1 # via -r requirements.in -botocore==1.29.98 \ - --hash=sha256:ae906c1feb56063a38ffd2280232fa44d634057825470d3beed274925088cb42 \ - --hash=sha256:b74283ff71eb4e57edfa5cf6dc36d959b1eec618a2b1e5e781643184857dd1c4 +botocore==1.29.99 \ + --hash=sha256:15c205e4578253da1e8cc247b9d4755042f5f873f68ac6e5fed48f4bd6f008c6 \ + --hash=sha256:d1770b4fe5531870af7a81e9897b2092d2f89e4ba8cb7abbbaf3ab952f6b8a6f # via # awscli # boto3 @@ -184,26 +188,26 @@ colorama==0.4.4 \ --hash=sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b \ --hash=sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2 # via awscli -cryptography==40.0.0 \ - --hash=sha256:14da8c26755ffa5c7863ffa5e8b87cb9596a21b6c34852cb19e0f48c226c64fb \ - --hash=sha256:168ded448fb5d82dfa911156ab8b13b1716de65bd50ff977f4657643f998fa05 \ - --hash=sha256:22e63fb48e2615cfab5a9c4bb457d35e7ae03ea8593996bfbe257e78244d12d0 \ - --hash=sha256:23c42c59c2b5b9ddc6a85b5c46b8fabc4d63a1714f4dbea4bf20d25690bf2365 \ - --hash=sha256:34f502619964210939bb7ee7cd5df53178534eb08d3526f941695a8f7aa0efe4 \ - --hash=sha256:43089be365c0ca4235c6e4e781f3bc125bc1fff576c9dd22cdfb585309b9bb9d \ - --hash=sha256:6b36e2864e04c82634879c7e7aad48824b1847fdb06b64cd410d2ec5e51d1b31 \ - --hash=sha256:7162ae4530958114ca2eee30a56eca46527def33493f622f059dc2e825fd0913 \ - --hash=sha256:71cb346b9dd1537102e7466a2d629385b01847f8d96cd7405f0e717d91cebc8e \ - --hash=sha256:722cfddae79684166840be2cbbae154f44a455519e644b60bf274a50ccb834db \ - --hash=sha256:754dc5ab648113dc54197f242db43234a04e4d61193fb5d3ebb42bd569dca571 \ - --hash=sha256:7cc9fc3ffcb766c313ed0515d77d0deabb4f36bdcff3a9f115c43e5ec611b82a \ - --hash=sha256:b05c9f25a1ea42e427085230815bbdebe15a53bb6163c4c06022e5630645046b \ - --hash=sha256:e5855a80c77565fe2464e88e0095764e25d8ddb2d24df2b1d31773e80be94435 \ - --hash=sha256:e917a07094217edeefe8f6ea960b45d7aab650b982e4209da078332cc9d3ac3a \ - --hash=sha256:f2c4134d29cdce0735c16abf48fa8435f001a7b0031e68dd9a9ee1c80a29374a \ - --hash=sha256:f421f6777592eb199ca8abac7c20b9ecef27c50ad63546e6c614b29771b46d0d \ - --hash=sha256:fafa997b9e6818db333ded4b379f5b7679b48bd88ac878428cea2a1aa6e79fd8 \ - --hash=sha256:fba36ec552794a06a07ac8bdc5ad83a587f6959d98547f373d401975d55c7c9e +cryptography==40.0.1 \ + --hash=sha256:0a4e3406cfed6b1f6d6e87ed243363652b2586b2d917b0609ca4f97072994405 \ + --hash=sha256:1e0af458515d5e4028aad75f3bb3fe7a31e46ad920648cd59b64d3da842e4356 \ + --hash=sha256:2803f2f8b1e95f614419926c7e6f55d828afc614ca5ed61543877ae668cc3472 \ + --hash=sha256:28d63d75bf7ae4045b10de5413fb1d6338616e79015999ad9cf6fc538f772d41 \ + --hash=sha256:32057d3d0ab7d4453778367ca43e99ddb711770477c4f072a51b3ca69602780a \ + --hash=sha256:3a4805a4ca729d65570a1b7cac84eac1e431085d40387b7d3bbaa47e39890b88 \ + --hash=sha256:63dac2d25c47f12a7b8aa60e528bfb3c51c5a6c5a9f7c86987909c6c79765554 \ + --hash=sha256:650883cc064297ef3676b1db1b7b1df6081794c4ada96fa457253c4cc40f97db \ + --hash=sha256:6f2bbd72f717ce33100e6467572abaedc61f1acb87b8d546001328d7f466b778 \ + --hash=sha256:7c872413353c70e0263a9368c4993710070e70ab3e5318d85510cc91cce77e7c \ + --hash=sha256:918cb89086c7d98b1b86b9fdb70c712e5a9325ba6f7d7cfb509e784e0cfc6917 \ + --hash=sha256:9618a87212cb5200500e304e43691111570e1f10ec3f35569fdfcd17e28fd797 \ + --hash=sha256:a805a7bce4a77d51696410005b3e85ae2839bad9aa38894afc0aa99d8e0c3160 \ + --hash=sha256:cc3a621076d824d75ab1e1e530e66e7e8564e357dd723f2533225d40fe35c60c \ + --hash=sha256:cd033d74067d8928ef00a6b1327c8ea0452523967ca4463666eeba65ca350d4c \ + --hash=sha256:cf91e428c51ef692b82ce786583e214f58392399cf65c341bc7301d096fa3ba2 \ + --hash=sha256:d36bbeb99704aabefdca5aee4eba04455d7a27ceabd16f3b3ba9bdcc31da86c4 \ + --hash=sha256:d8aa3609d337ad85e4eb9bb0f8bcf6e4409bfb86e706efa9a027912169e89122 \ + --hash=sha256:f5d7b79fa56bc29580faafc2ff736ce05ba31feaa9d4735048b0de7d9ceb2b94 # via django-dbmi-client django==4.1.7 \ --hash=sha256:44f714b81c5f190d9d2ddad01a532fe502fa01c4cb8faf1d081f4264ed15dcd8 \ @@ -213,6 +217,7 @@ django==4.1.7 \ # django-bootstrap-datepicker-plus # django-bootstrap3 # django-dbmi-client + # django-filter # django-health-check # django-jquery # django-jsonfield-backport @@ -220,6 +225,8 @@ django==4.1.7 \ # django-q # django-storages # djangorestframework + # drf-nested-routers + # drf-spectacular django-autocomplete-light==3.9.4 \ --hash=sha256:0f6da75c1c7186698b867a467a8cdb359f0513fdd8e09288a0c2fb018ae3d94e # via -r requirements.in @@ -241,6 +248,10 @@ django-dbmi-client==1.0.3 \ --hash=sha256:0900bbc4c29125b15d62f1ed4c12eebb26f3d0542575bb4349182c33d08100c5 \ --hash=sha256:ccd8a19b2f4cc82555311e54d00ea7edc4526744772acaeefacd21f01dfa2891 # via -r requirements.in +django-filter==23.1 \ + --hash=sha256:dee5dcf2cea4d7f767e271b6d01f767fce7500676d5e5dc58dac8154000b87df \ + --hash=sha256:e3c52ad83c32fb5882125105efb5fea2a1d6a85e7dc64b04ef52edbf14451b6c + # via -r requirements.in django-health-check==3.17.0 \ --hash=sha256:20dc5ccb516a4e7163593fd4026f0a7531e3027b47d23ebe3bd9dbc99ac4354c \ --hash=sha256:d1b8671e79d1de6e3dd1a9c69566222b0bfcfacca8b90511a4407b2d0d3d2778 @@ -279,10 +290,20 @@ djangorestframework==3.14.0 \ # via # -r requirements.in # django-dbmi-client + # drf-nested-routers + # drf-spectacular docutils==0.16 \ --hash=sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af \ --hash=sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc # via awscli +drf-nested-routers==0.93.4 \ + --hash=sha256:01aa556b8c08608bb74fb34f6ca065a5183f2cda4dc0478192cc17a2581d71b0 \ + --hash=sha256:996b77f3f4dfaf64569e7b8f04e3919945f90f95366838ca5b8bed9dd709d6c5 + # via -r requirements.in +drf-spectacular==0.26.1 \ + --hash=sha256:1599a204bf9cc6be7ef3e509859885a38d4f871fe287a1f191479868afd9e234 \ + --hash=sha256:6df86ff6c2dc663792e5ff618643bf41d2ac9dc6fb5d1b0f273e2778bab951e5 + # via -r requirements.in furl==2.1.3 \ --hash=sha256:5a6188fe2666c484a12159c18be97a1977a71d632ef5bb867ef15f54af39cc4e \ --hash=sha256:9ab425062c4217f9802508e45feb4a83e54324273ac4b202f1850363309666c0 @@ -293,12 +314,20 @@ idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via requests +inflection==0.5.1 \ + --hash=sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417 \ + --hash=sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2 + # via drf-spectacular jmespath==1.0.1 \ --hash=sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980 \ --hash=sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe # via # boto3 # botocore +jsonschema==4.17.3 \ + --hash=sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d \ + --hash=sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6 + # via drf-spectacular mysqlclient==2.1.1 \ --hash=sha256:0d1cd3a5a4d28c222fa199002810e8146cffd821410b67851af4cc80aeccd97c \ --hash=sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782 \ @@ -362,6 +391,35 @@ pyjwt==2.6.0 \ --hash=sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd \ --hash=sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14 # via django-dbmi-client +pyrsistent==0.19.3 \ + --hash=sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8 \ + --hash=sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440 \ + --hash=sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a \ + --hash=sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c \ + --hash=sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3 \ + --hash=sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393 \ + --hash=sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9 \ + --hash=sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da \ + --hash=sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf \ + --hash=sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64 \ + --hash=sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a \ + --hash=sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3 \ + --hash=sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98 \ + --hash=sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2 \ + --hash=sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8 \ + --hash=sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf \ + --hash=sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc \ + --hash=sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7 \ + --hash=sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28 \ + --hash=sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2 \ + --hash=sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b \ + --hash=sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a \ + --hash=sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64 \ + --hash=sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19 \ + --hash=sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1 \ + --hash=sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9 \ + --hash=sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c + # via jsonschema python-dateutil==2.8.2 \ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 @@ -373,9 +431,9 @@ python-magic==0.4.27 \ --hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b \ --hash=sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3 # via -r requirements.in -pytz==2022.7.1 \ - --hash=sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0 \ - --hash=sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a +pytz==2023.2 \ + --hash=sha256:8a8baaf1e237175b02f5c751eea67168043a749c843989e2b3015aa1ad9db68b \ + --hash=sha256:a27dcf612c05d2ebde626f7d506555f10dfc815b3eddccfaadfc7d99b11c9a07 # via djangorestframework pyyaml==5.4.1 \ --hash=sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf \ @@ -407,7 +465,9 @@ pyyaml==5.4.1 \ --hash=sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247 \ --hash=sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6 \ --hash=sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0 - # via awscli + # via + # awscli + # drf-spectacular raven==6.10.0 \ --hash=sha256:3fa6de6efa2493a7c827472e984ce9b020797d0da16f1db67197bcc23c8fae54 \ --hash=sha256:44a13f87670836e153951af9a3c80405d36b43097db869a36e92809673692ce4 @@ -454,6 +514,10 @@ typing-extensions==4.5.0 \ # django-bootstrap-datepicker-plus # django-countries # pydantic +uritemplate==4.1.1 \ + --hash=sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0 \ + --hash=sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e + # via drf-spectacular urllib3==1.26.15 \ --hash=sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305 \ --hash=sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42 From d89fef6753cb0a7969a4128b2ab79a4f5dbf7ed5 Mon Sep 17 00:00:00 2001 From: Bryan Larson Date: Tue, 4 Apr 2023 18:01:56 -0600 Subject: [PATCH 2/5] HYP-280 - Refactored Permission classes --- app/api/api.py | 45 ++++------------------- app/api/auth.py | 79 ++++++++++++++++++++++++++++++----------- app/hypatio/settings.py | 16 ++++++++- 3 files changed, 79 insertions(+), 61 deletions(-) diff --git a/app/api/api.py b/app/api/api.py index 95c34e83..55a32430 100644 --- a/app/api/api.py +++ b/app/api/api.py @@ -1,57 +1,24 @@ -from django.http import Http404 -from django.contrib.auth.models import User -from django.db.models import Q from django.shortcuts import get_object_or_404 - -from datetime import datetime, timedelta -from rest_framework.generics import ListAPIView, RetrieveAPIView -from rest_framework.views import APIView from rest_framework import viewsets +from rest_framework import mixins from rest_framework.response import Response -from rest_framework import authentication, permissions -from rest_framework import exceptions +from rest_framework import authentication +from rest_framework import permissions from rest_framework.decorators import action -from dbmi_client import authz from dbmi_client.authn import DBMIModelUser from django_filters.rest_framework import DjangoFilterBackend from drf_spectacular.utils import extend_schema, OpenApiParameter, extend_schema_view -from api.scheme import JWTScheme from projects.models import DataProject, HostedFile from api.serializers import ( DataProjectSerializer, HostedFileSerializer, HostedFileDownloadSerializer, ) -from hypatio.file_services import get_download_url - - -class HostedFilePermission(permissions.BasePermission): - """ - This BasePermission subclass ensures the requesting user has adequate - permissions on the DataProject to which the HostedFile belongs. - """ - - READ_PERMISSIONS = ["VIEW", "MANAGE"] - WRITE_PERMISSIONS = ["MANAGE"] - - def has_permission(self, request, view): - if not request.user.is_authenticated: - return False - - # Check Participant objects first - if request.user.participant_set.filter( - project=view.project, - permission__in=self.READ_PERMISSIONS): - return True +from api.auth import HostedFilePermission - if authz.has_a_permission( - request=request, - email=request.user.email, - item=f"Hypatio.{view.project.project_key}", - permissions=self.READ_PERMISSIONS, - check_parents=True): - return True +import logging +logger = logging.getLogger(__name__) class DataProjectViewSet(viewsets.ReadOnlyModelViewSet): diff --git a/app/api/auth.py b/app/api/auth.py index 4a199586..6e1c14b6 100644 --- a/app/api/auth.py +++ b/app/api/auth.py @@ -1,8 +1,7 @@ from rest_framework import permissions -from django.core.exceptions import ObjectDoesNotExist +from dbmi_client import authz from projects.models import DataProject -from projects.models import Participant import logging logger = logging.getLogger(__name__) @@ -11,35 +10,73 @@ class DataProjectPermission(permissions.BasePermission): message = 'Access to data project is prohibited.' + # Permission strings for the Data Portal + READ_PERMISSIONS = ["VIEW", "MANAGE"] + WRITE_PERMISSIONS = ["MANAGE"] + + def has_read_permission(self, request, project): + """ + Returns whether the requesting user has a read permission on the passed + project or not. + + :param request: The current request + :type request: HttpRequest + :param project: The DataProject the requestor is attempting to read + :type project: DataProject + """ + # Check Participant objects first + if request.user.participant_set.filter( + project=project, + permission__in=self.READ_PERMISSIONS): + return True + + if authz.has_a_permission( + request=request, + email=request.user.email, + item=f"Hypatio.{project.project_key}", + permissions=self.READ_PERMISSIONS, + check_parents=True): + return True + + return False + + def has_permission(self, request, view): + if not request.user.is_authenticated: + return False + def has_object_permission(self, request, view, obj): # Ensure user has permission on the given project. # Get the project try: - project = DataProject.objects.get(project_key=obj) - except ObjectDoesNotExist: - logger.debug(f"No project found for key: {obj}") + project = DataProject.objects.get(pk=obj) + except DataProject.DoesNotExist: + logger.error(f"DataProject does not exist for PK: '{obj}'") return False - # If the project doesn't require authorization, grant access - if not project.requires_authorization: - logger.debug(f"No auth for project, access granted for: {obj}{request.user.email}") + # Check Participant objects first + if self.has_read_permission(request, project): return True - # Get their permission for this project - try: - participant = Participant.objects.get(user=request.user, project=project) + logger.debug(f"Access denied on '{obj}' for: {request.user.email}") + return False - # Check permission - if participant.permission == "VIEW": - logger.debug(f"Access granted for: {obj}{request.user.email}") - return True - except ObjectDoesNotExist: - logger.debug(f"Participant does not exist for: {obj}/{request.user.email}", extra={ - "request": request, "project": obj, "user": request.user, - }) +class HostedFilePermission(DataProjectPermission): + """ + This BasePermission subclass ensures the requesting user has adequate + permissions on the DataProject to which the HostedFile belongs. + """ + message = 'Access to file is prohibited.' - logger.debug(f"Access denied for: {obj}{request.user.email}") - return False + def has_permission(self, request, view): + if not request.user.is_authenticated: + return False + + # Check Participant objects first + if self.has_read_permission(request, view.project): + return True + + def has_object_permission(self, request, view, obj): + return True diff --git a/app/hypatio/settings.py b/app/hypatio/settings.py index 2c699678..04c5ed8a 100644 --- a/app/hypatio/settings.py +++ b/app/hypatio/settings.py @@ -287,7 +287,21 @@ ##################################################################################### REST_FRAMEWORK = { - 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'dbmi_client.authn.DBMIModelUser', + ], + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', + ], + 'DEFAULT_RENDERER_CLASSES': [ + 'rest_framework.renderers.JSONRenderer', + ], + 'DEFAULT_PARSER_CLASSES': [ + 'rest_framework.parsers.JSONParser', + ], + 'DEFAULT_FILTER_BACKENDS': [ + 'django_filters.rest_framework.DjangoFilterBackend' + ], 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', } From 502ce5971bfc2fd5a1b9a82197e3b6d6f7998706 Mon Sep 17 00:00:00 2001 From: Bryan Larson Date: Wed, 5 Apr 2023 09:07:58 -0600 Subject: [PATCH 3/5] HYP-280 - Fixed bug where authenticate wasn't including request object --- app/hypatio/auth0authenticate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/hypatio/auth0authenticate.py b/app/hypatio/auth0authenticate.py index 2fcd60aa..57250f92 100644 --- a/app/hypatio/auth0authenticate.py +++ b/app/hypatio/auth0authenticate.py @@ -219,7 +219,7 @@ def jwt_login(request, jwt_payload): request.session['profile'] = jwt_payload - user = django_auth.authenticate(**jwt_payload) + user = django_auth.authenticate(request, **jwt_payload) if user: login(request, user) From a67fa56e26970f9ebb1fa8d9b5f540f69136ec93 Mon Sep 17 00:00:00 2001 From: Bryan Larson Date: Wed, 13 Sep 2023 09:51:55 -0600 Subject: [PATCH 4/5] HYP-280 - Finished merge with 'development' branch --- app/hypatio/settings.py | 3 - requirements.txt | 442 ++++++++++++++++++++++++---------------- 2 files changed, 270 insertions(+), 175 deletions(-) diff --git a/app/hypatio/settings.py b/app/hypatio/settings.py index 55535c4b..2506c999 100644 --- a/app/hypatio/settings.py +++ b/app/hypatio/settings.py @@ -57,13 +57,10 @@ 'storages', 'django_jsonfield_backport', 'django_q', -<<<<<<< HEAD 'rest_framework', 'drf_spectacular', 'django_filters', -======= 'django_ses', ->>>>>>> development ] MIDDLEWARE = [ diff --git a/requirements.txt b/requirements.txt index 23f50bf0..b272ed7e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,27 +18,29 @@ asgiref==3.7.2 \ # via # django # django-countries -attrs==22.2.0 \ - --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \ - --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99 - # via jsonschema -awscli==1.29.32 \ - --hash=sha256:4aecd37baf1f316f305e3701efac368ffdd8ec0ab9c55e9e5609f068b02aa6c8 \ - --hash=sha256:54228ade9963b55d36f7a8e618a26f6a68a46c9fce8dd678bd68fed366b4caf5 +attrs==23.1.0 \ + --hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \ + --hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015 + # via + # jsonschema + # referencing +awscli==1.29.46 \ + --hash=sha256:4e2e681789bd8ec47f08a6d1df0193cb24b6488438f05399dfcdaea6be78a924 \ + --hash=sha256:ad5ff776d1d0a4f3383f35d128a1f78c7240ef464d86efce97e632233b206579 # via -r requirements.in blessed==1.20.0 \ --hash=sha256:0c542922586a265e699188e52d5f5ac5ec0dd517e5a1041d90d2bbf23f906058 \ --hash=sha256:2cdd67f8746e048f00df47a2880f4d6acbcdb399031b604e34ba8f71d5787680 # via django-q -boto3==1.28.32 \ - --hash=sha256:b505faa126db84e226f6f8d242a798fae30a725f0cac8a76c6aca9ace4e8eb28 \ - --hash=sha256:ed787f250ce2562c7744395bdf32b5a7bc9184126ef50a75e97bcb66043dccf3 +boto3==1.28.46 \ + --hash=sha256:04445d70127c25fad69e2cab7e3f5cb219c8d6e60463af3657f20e29ac517957 \ + --hash=sha256:2ca2852f7b7c1bc2e56f10f968d4c8483c8228b935ecd89a444ae8292ad0dc24 # via # -r requirements.in # django-ses -botocore==1.31.32 \ - --hash=sha256:7a07d8dc8cc47bf23af39409ada81f388eb78233e1bb2cde0c415756da753664 \ - --hash=sha256:8992ac186988c4b4cc168e8e479e9472da1442b193c1bf7c9dcd1877ec62d23c +botocore==1.31.46 \ + --hash=sha256:6c30be3371624a80d6a881d9c7771a80e0eb82697ee374aaf522cd59b76e14dd \ + --hash=sha256:ac0c1258b1782cde42950bd00138fdce6bd7d04855296af8c326d5844a426473 # via # awscli # boto3 @@ -219,9 +221,9 @@ cryptography==41.0.3 \ --hash=sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e \ --hash=sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de # via django-dbmi-client -django==4.2.4 \ - --hash=sha256:7e4225ec065e0f354ccf7349a22d209de09cc1c074832be9eb84c51c1799c432 \ - --hash=sha256:860ae6a138a238fc4f22c99b52f3ead982bb4b1aad8c0122bcd8c8a3a02e409d +django==4.2.5 \ + --hash=sha256:5e5c1c9548ffb7796b4a8a4782e9a2e5a3df3615259fc1bfd3ebc73b646146c1 \ + --hash=sha256:b6b2b5cae821077f137dc4dade696a1c2aa292f892eca28fa8d7bfdf2608ddd4 # via # -r requirements.in # django-autocomplete-light @@ -237,6 +239,8 @@ django==4.2.4 \ # django-ses # django-storages # djangorestframework + # drf-nested-routers + # drf-spectacular django-autocomplete-light==3.9.7 \ --hash=sha256:a34f192ac438c4df056dbfd399550799ddc631c4661960134ded924648770373 # via -r requirements.in @@ -258,9 +262,9 @@ django-dbmi-client==1.0.7 \ --hash=sha256:1332527e263536a0958847b9d0cddbd276df507db3f4aede6180aeef375e5f9b \ --hash=sha256:f9e683724fddc16f965301927a1808dda59e53bcb0014410b051ea448538ba41 # via -r requirements.in -django-filter==23.1 \ - --hash=sha256:dee5dcf2cea4d7f767e271b6d01f767fce7500676d5e5dc58dac8154000b87df \ - --hash=sha256:e3c52ad83c32fb5882125105efb5fea2a1d6a85e7dc64b04ef52edbf14451b6c +django-filter==23.2 \ + --hash=sha256:2fe15f78108475eda525692813205fa6f9e8c1caf1ae65daa5862d403c6dbf00 \ + --hash=sha256:d12d8e0fc6d3eb26641e553e5d53b191eb8cec611427d4bdce0becb1f7c172b5 # via -r requirements.in django-health-check==3.17.0 \ --hash=sha256:20dc5ccb516a4e7163593fd4026f0a7531e3027b47d23ebe3bd9dbc99ac4354c \ @@ -291,9 +295,9 @@ django-ses==3.5.0 \ django-smtp-ssl==1.0 \ --hash=sha256:282863d5905e03686b6555ac788aa732842695d6f9cf1dcfa66d898abb7565d0 # via -r requirements.in -django-storages==1.13.2 \ - --hash=sha256:31dc5a992520be571908c4c40d55d292660ece3a55b8141462b4e719aa38eab3 \ - --hash=sha256:cbadd15c909ceb7247d4ffc503f12a9bec36999df8d0bef7c31e57177d512688 +django-storages==1.14 \ + --hash=sha256:11280a883b13812df548f3cfe9c10280afc0d4727c8babdee369a75e71158f16 \ + --hash=sha256:6c97e5faad829c923a1262206281742c484d76d43b332a196ddcc242b909c551 # via -r requirements.in django-stronghold==0.4.0 \ --hash=sha256:4127d5f9c11f6582a1c03e7758256b1fe5c872f64f212980e5ad5c67f5eeaa3d @@ -314,9 +318,9 @@ drf-nested-routers==0.93.4 \ --hash=sha256:01aa556b8c08608bb74fb34f6ca065a5183f2cda4dc0478192cc17a2581d71b0 \ --hash=sha256:996b77f3f4dfaf64569e7b8f04e3919945f90f95366838ca5b8bed9dd709d6c5 # via -r requirements.in -drf-spectacular==0.26.1 \ - --hash=sha256:1599a204bf9cc6be7ef3e509859885a38d4f871fe287a1f191479868afd9e234 \ - --hash=sha256:6df86ff6c2dc663792e5ff618643bf41d2ac9dc6fb5d1b0f273e2778bab951e5 +drf-spectacular==0.26.4 \ + --hash=sha256:8f5a8f87353d1bb8dcb3f3909b7109b2dcbe1d91f3e069409cf322963e140bd6 \ + --hash=sha256:afeccc6533dcdb4e78afbfcc49f3c5e9c369aeb62f965e4d1a43b165449c147a # via -r requirements.in furl==2.1.3 \ --hash=sha256:5a6188fe2666c484a12159c18be97a1977a71d632ef5bb867ef15f54af39cc4e \ @@ -338,10 +342,14 @@ jmespath==1.0.1 \ # via # boto3 # botocore -jsonschema==4.17.3 \ - --hash=sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d \ - --hash=sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6 +jsonschema==4.19.0 \ + --hash=sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb \ + --hash=sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f # via drf-spectacular +jsonschema-specifications==2023.7.1 \ + --hash=sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1 \ + --hash=sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb + # via jsonschema mysqlclient==2.2.0 \ --hash=sha256:004fe1d30d2c2ff8072f8ea513bcec235fd9b896f70dad369461d0ad7e570e98 \ --hash=sha256:04368445f9c487d8abb7a878e3d23e923e6072c04a6c320f9e0dc8a82efba14e \ @@ -363,151 +371,122 @@ pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via cffi -pydantic==2.2.1 \ - --hash=sha256:0c88bd2b63ed7a5109c75ab180d55f58f80a4b559682406812d0684d3f4b9192 \ - --hash=sha256:31b5cada74b2320999fb2577e6df80332a200ff92e7775a52448b6b036fce24a +pydantic==2.3.0 \ + --hash=sha256:1607cc106602284cd4a00882986570472f193fde9cb1259bceeaedb26aa79a6d \ + --hash=sha256:45b5e446c6dfaad9444819a293b921a40e1db1aa61ea08aede0522529ce90e81 # via django-bootstrap-datepicker-plus -pydantic-core==2.6.1 \ - --hash=sha256:043212f21c75cb6ee3a92fffbc747410e32b08e1a419ce16a9da98a16d660a7c \ - --hash=sha256:09e4ebd11a0b333b1fca75c1004c76dc9719f3aaf83ae38c42358754d8a76148 \ - --hash=sha256:1281c940f47e5c89b594ef7580045647df1f9ad687edd503bcc0485be94576f4 \ - --hash=sha256:136de286abf53f326b90389aaaca8a8050c2570adfc74afe06ab1c35d5d242bf \ - --hash=sha256:153a5dd24c09ab7544beda967366afbaae8350b327a4ebd5807ed45ec791baa0 \ - --hash=sha256:17ab25bb24e98b61d120b7248c2b49ea56ce754a050d6b348be42015fcb7aa25 \ - --hash=sha256:1f4327fa6a1ac3da62b27d43bb0f27657ed4e601b141ecbfcf8523814b6c33b6 \ - --hash=sha256:200704f6824f8014bdccb1ce57cbd328666e6de4ecd77f0b8ab472cdea9c49ce \ - --hash=sha256:2034d9b83a59b3b74b9dbf97ddb99de86c08863c1c33aabf80bc95791c7d50c3 \ - --hash=sha256:20e850f3242d7836a5e15453f798d8569b9754350c8e184ba32d102c515dd507 \ - --hash=sha256:26b81017aeae0d96f776fbce34a3a763d26ac575d8ad3f1202bdfdd2b935954b \ - --hash=sha256:27ba58bbfd1b2b9da45bfe524e680e2bc747a1ca9738ee5aa18d8cbdcc08e5e6 \ - --hash=sha256:2b8ccec2189d8a8b83929f79e5bc00c0656f6c2ba4345125c0c82d1b77e15a26 \ - --hash=sha256:2d41701c88d8b678c16c10562949f2d28aceacd767cbe51dac9c8c41e6e609fb \ - --hash=sha256:2da1d21a4f2675d5b8a749674993a65c0537e2066e7ab7b1a4a54ef0b3ac8efd \ - --hash=sha256:2effc71653247e76c5b95d15c58d4ca3f591f42f714eb3b32df9d6ec613794a5 \ - --hash=sha256:3210eb73707e3487c16ef25cfd1663660f4e7d647a181d6c2fb18bc6167985fb \ - --hash=sha256:33b9343aa464d60c31937b361abde08d3af9943f3eb09d3216211b6236bd40c4 \ - --hash=sha256:34734d486d059f0f6f5bfa9ba4a41449f666e2abbde002e9fa8b050bc50e3347 \ - --hash=sha256:364c13ef48c9e2f8c2ea8ee0da5ea23db5e218f99e796cbf360a2a7cab511439 \ - --hash=sha256:3679b9a1f41eb1b699e9556f91281d78c416cdc59ae90d5733fbe2017f1effe9 \ - --hash=sha256:382d40843ae759d43ef65b67dec713390f9417135c1dd730afbf03cf2f450f45 \ - --hash=sha256:3bdf293b6304bc451678b7016c2505b7d97aa85ff13dac4420027b1b69e15d3d \ - --hash=sha256:3c8f3aebaf92f088b1dafd7101d1ccca0459ae0f5b26017411b9969667d289a9 \ - --hash=sha256:3d14ae98a8d251402ef8ed017039d2fc3e29fb155f909cd3816ba259fd30fb48 \ - --hash=sha256:420a76a62dd20a6ef08445abf7cf04dcd8a845a5bb15932c2e88a8e518c70d43 \ - --hash=sha256:4223e8bdad41d846a84cda400cd538e1cdc63d98eb4d41951396bfdb88fd8ce9 \ - --hash=sha256:4525b8498d362e4e324e3e175239b364768f52bd3563ac4ef9750160f5789de8 \ - --hash=sha256:45d248c3c5c5c23a8d048cfdebc8151ae7b32a6dc6d68fbca995521e54692207 \ - --hash=sha256:4902300e763a2fcc49ae14366493ef1fdbd3c7128b9acf37aef505f671aa681f \ - --hash=sha256:494b211b12b8fedd184dbba609f6ed582e23561db57c1996fd6773989dbaef9b \ - --hash=sha256:4a3c20808d3ced90e29439f72a563eadf21d29560935cc818b2dab80b92c114a \ - --hash=sha256:51ffa985b874ca7d0dc199bb75c67b77907379291c91532a9e2d981f7b681527 \ - --hash=sha256:5482d692ae37857695feccb179022728b275b7bfcc1c85bcdf7b556e76bffcd8 \ - --hash=sha256:55701608e60418a423db2486b5c64d790f86eb78a11b9077efb6302c50e62564 \ - --hash=sha256:55aac69d7339a63e37164f0a629c3034becc6746d68d126118a3ee4493514bed \ - --hash=sha256:56672429f8a89d2a0f4402d912f0dad68c2d05f7c278d3152c6fb4a76c2a429a \ - --hash=sha256:56e4953cd911293d6d755e2a97c651826aca76201db8f1ee298939e703721390 \ - --hash=sha256:588a5ffd8bbf1b2230611ed1b45221adcf05b981037b2f853b5f20465849b5c1 \ - --hash=sha256:5a12520a6d502a25f6e47319874e47056b290f1b3c2ed9391444ce81c8cc5b83 \ - --hash=sha256:5b4efa68bcfa6f2b93624c6660b6cf4b7b4336d4225afb314254a0ed9c9f4153 \ - --hash=sha256:5f253d20314e53ba0fb2b95541b6ed23f44fbcd927fe7674de341545c3327c3d \ - --hash=sha256:60a238bb4ab09a81a6b25c9a0bb12756cfab2d9f3a7a471f857a179f83da0df6 \ - --hash=sha256:6221c97d6d58f2370650cfe3d81408901a1951c99960e1df9f6f9f8482d73d08 \ - --hash=sha256:64ff7a4b7ee2a56735af28da76c5dacbba6995801080f739d14610f4aa3de35d \ - --hash=sha256:66eda8ac48ac33e9e5c6541c8e30c702924b70a6f2e9732b74230d9b2dd35fb6 \ - --hash=sha256:6916b27072c957947919fb32551f08486562bb8616f2e3db9e4e9c1d83d36886 \ - --hash=sha256:6a839c95d5cc91eed053d8dafde4e200c4bc82f56fb1cf7bbfaeb03e2d907929 \ - --hash=sha256:6dd6c9f47e26779bf1f7da4d6ccd60f66973e63b0a143438f1e20bae296c3fde \ - --hash=sha256:6ea8dd2854fe6cee5ea0d60304ee7877dffe487cf118f221e85029269dd1235d \ - --hash=sha256:707e3005e8c129bdac117285b71717c13b9ed81a81eae0b1642f4ddc60028e63 \ - --hash=sha256:7188359b95a2b1aef5744a2ee6af2d9cfc733dd823f8840f4c896129477a172b \ - --hash=sha256:734864605d722a6f8db3b9c96371710f7cb591fbfca40cfeaedf5b67df282438 \ - --hash=sha256:760f8a0aeb43ceeff1e536859e071a72e91075d4d37d51470812c4f49e682702 \ - --hash=sha256:775098e3629a959dfec8444667a53e0916839e9fbf6b55e07d6e2aadde006400 \ - --hash=sha256:7888b3ee7566865cff3e9edab5d6cdf2e7cf793df17fe53d5e7be3e57eae45ec \ - --hash=sha256:78eadd8d7d5cd8c3616e363c394d721437c339feaa4c28404e2eda79add69781 \ - --hash=sha256:7c3a2b4d1636446dc71da1e949d2cf9ac1ee691ca63a640b77fce0360b4b75be \ - --hash=sha256:7ddaa2c3c66682f0ff4ebc8c85ef2d8305f32deba79416464c47c93d94ca3740 \ - --hash=sha256:7ef56a05bb60336d5e795bf166d6712b2362e6478522c77e8336cb0da8909913 \ - --hash=sha256:7f03541c25a77fb5445055e070b69d292c9818a9195ffbfd3962c0ad0da983e8 \ - --hash=sha256:81424dc05c4342a19fb64323bb9d4468e7407b745c00377ccc4d3dd96d5e02fe \ - --hash=sha256:8714e958d01342d08e520ffec6c1acf66cdec83ce51302f9a1a6efb2f784d0b6 \ - --hash=sha256:92321582e59da185b76b2eca4488ea95e41800672e57107509d32ebf8ad550f8 \ - --hash=sha256:9b623e09239ed333d14c02c9fcd1a7bb350b95eca8383f6e9b0d8e373d5a14b5 \ - --hash=sha256:9bf3ba6b4878ee692f6e24230801f682807fd97356bc2064f630fc0a2ad2ead6 \ - --hash=sha256:a1ad48e77935d7dbbc2d75aeb638abbfbd0df0cfacf774dbe98d52271468f00c \ - --hash=sha256:a32ed5a794918a61bf77b967c197eb78f31ad4e3145860193dc381bde040717e \ - --hash=sha256:a4536d132a8bbd05bf368fb802a264cb9828f6c85e4029a6a3670bc98ba97323 \ - --hash=sha256:a5127b811c6a26deb85f5b17a06c26c28ce204e51e0a963b75bdf8612b22546d \ - --hash=sha256:a809498dceb0cd1cd1e57a2bfdc70ea82f424776e0196f4d63c4b6fcdaeb5aab \ - --hash=sha256:aadc84f5bd7b1421b5a6b389ceff46062dd4a58c44cfb75990e9ca2d9d8270df \ - --hash=sha256:b1a01dce87507b9a8f1b71933ade85c573a22c9bd4649590e28d8a497afb68bd \ - --hash=sha256:b1aed20778092f8334c8eaf91550fa2805221d5e9b40ebdd1f46ee7efc159a48 \ - --hash=sha256:b974d65692333931b4c7f730e7a3135ff854a1e5384bc260de3327ea364c835a \ - --hash=sha256:bb6273068e9450c5c91f58dd277fbd406b896ffa30f0ef312edc5519d07f16ae \ - --hash=sha256:c07cdb2e02733e5f26b9b004a1a8b99814d175f8953fa9f59e4293de2b8e9787 \ - --hash=sha256:c1e44b77442fb5b1b6fccea30e3359b14d0a2e5896801243defe54482a591500 \ - --hash=sha256:c22e4fbfb5823d0fcb2c20ed164b39c3588554f9635f70765e8c9cff0fef67ad \ - --hash=sha256:c5be947ad41a7602f941dc834d03e64dd1c7fae65fa85cb4f1004a95c5d50df1 \ - --hash=sha256:c7b89b2875b967ad5c3c980bf72773851554f80c2529796e815a10c99295d872 \ - --hash=sha256:c82fb25f965f6777032fc2f2856c86149f7709c8f7fd0c020a8631b8211f2bab \ - --hash=sha256:ca5606bd82e255b1d704a4334e5ebf05ae966b69686fae02dcd31c057bdcb113 \ - --hash=sha256:cb5131d75d69b0547ef9a8f46f7b94857411c9badcdd5092de61a3b4943f08c7 \ - --hash=sha256:cc7fc3e81b4ea6bce7e0e1d9797f496e957c5e66adf483f89afdce2d81d19986 \ - --hash=sha256:cd163109047ab41ef1ea34258b35beb3ccac90af2012927ee8ab6ff122fef671 \ - --hash=sha256:cd6f05f3e237ed6b3949464e7679e55843645fe0fe8d3b33277c321386836f6a \ - --hash=sha256:cd9f14454b4bc89c705ce17951f9c783db82efd2b44a424487c593e2269eef61 \ - --hash=sha256:d0bf1c2545ab253732229c7fe8294d98eb08f99aa25a388267e1bc4d2d7e0a34 \ - --hash=sha256:d1141f18414aee8865c7917ae1432e419c1983272f53625152493692ff3d6783 \ - --hash=sha256:d6971131de66d1a37293f2e032206b6984b0dec44f568b453dfe89a84a2de0cc \ - --hash=sha256:da240bbd8191edc6009e7793d5d4d67c55f56225c4788f068d6286c20e5a2038 \ - --hash=sha256:db0c12f1e9d3bf658634621f3423486803d749fef77a64cfb4252f9d619e1817 \ - --hash=sha256:de1a3e56e34264d5216c67d2a48185216ada8f5f35a7f4c96a3971847c0de897 \ - --hash=sha256:dfc8f534a21b60b00f87e5a4fc36b8b8945160a6cc9e7b6e67db541c766c9597 \ - --hash=sha256:dfdb1617af455a551be4cc0471f0bf3bfb1e882db71afad0e587c821326bb749 \ - --hash=sha256:e1c69334bb843c9bff98f52a1fa6c06420081a561fcecb03c6b9376960bd7de2 \ - --hash=sha256:e2d8faedb138c704957642fdf154c94f1b3d2a15cbd2472e45665f80463e85ee \ - --hash=sha256:e3ff36f945342086ee917d4219dd0e59660a2dfcdb86a07696c2791f5d59c07d \ - --hash=sha256:e55514a022c768cccf07a675d20d07b847980dcd9250f6b516a86bab5612fc01 \ - --hash=sha256:e84812b1ca989b2e9f4913d7b75ae0eece2a90154de35b4c5411ad640bfd387c \ - --hash=sha256:f2fed4ad60ccf2698bd04e95dfc3bd84149ced9605a29fd27d624701e1da300c \ - --hash=sha256:f34f26d8a5f1a45366189ec30a57f43b21e2172d0d3b62822638dd885cc8eaab \ - --hash=sha256:f55001a689111a297c0006c46c0589cfd559261baaa9a37bc35eff05b8cae1a6 \ - --hash=sha256:f5b51ec04743c94288c46e3759769611ab7c5ce0f941113363da96d20d345fb6 \ - --hash=sha256:f7ec4c6edafa3f0eb1aa461e31ea263736cc541b2459dddfbda7085b30844801 +pydantic-core==2.6.3 \ + --hash=sha256:002d0ea50e17ed982c2d65b480bd975fc41086a5a2f9c924ef8fc54419d1dea3 \ + --hash=sha256:02e1c385095efbd997311d85c6021d32369675c09bcbfff3b69d84e59dc103f6 \ + --hash=sha256:046af9cfb5384f3684eeb3f58a48698ddab8dd870b4b3f67f825353a14441418 \ + --hash=sha256:04fe5c0a43dec39aedba0ec9579001061d4653a9b53a1366b113aca4a3c05ca7 \ + --hash=sha256:07a1aec07333bf5adebd8264047d3dc518563d92aca6f2f5b36f505132399efc \ + --hash=sha256:1480fa4682e8202b560dcdc9eeec1005f62a15742b813c88cdc01d44e85308e5 \ + --hash=sha256:1508f37ba9e3ddc0189e6ff4e2228bd2d3c3a4641cbe8c07177162f76ed696c7 \ + --hash=sha256:171a4718860790f66d6c2eda1d95dd1edf64f864d2e9f9115840840cf5b5713f \ + --hash=sha256:19e20f8baedd7d987bd3f8005c146e6bcbda7cdeefc36fad50c66adb2dd2da48 \ + --hash=sha256:1a0ddaa723c48af27d19f27f1c73bdc615c73686d763388c8683fe34ae777bad \ + --hash=sha256:1aa712ba150d5105814e53cb141412217146fedc22621e9acff9236d77d2a5ef \ + --hash=sha256:1ac1750df1b4339b543531ce793b8fd5c16660a95d13aecaab26b44ce11775e9 \ + --hash=sha256:1c721bfc575d57305dd922e6a40a8fe3f762905851d694245807a351ad255c58 \ + --hash=sha256:1ce8c84051fa292a5dc54018a40e2a1926fd17980a9422c973e3ebea017aa8da \ + --hash=sha256:1fa1f6312fb84e8c281f32b39affe81984ccd484da6e9d65b3d18c202c666149 \ + --hash=sha256:22134a4453bd59b7d1e895c455fe277af9d9d9fbbcb9dc3f4a97b8693e7e2c9b \ + --hash=sha256:23470a23614c701b37252618e7851e595060a96a23016f9a084f3f92f5ed5881 \ + --hash=sha256:240a015102a0c0cc8114f1cba6444499a8a4d0333e178bc504a5c2196defd456 \ + --hash=sha256:252851b38bad3bfda47b104ffd077d4f9604a10cb06fe09d020016a25107bf98 \ + --hash=sha256:2a20c533cb80466c1d42a43a4521669ccad7cf2967830ac62c2c2f9cece63e7e \ + --hash=sha256:2dd50d6a1aef0426a1d0199190c6c43ec89812b1f409e7fe44cb0fbf6dfa733c \ + --hash=sha256:340e96c08de1069f3d022a85c2a8c63529fd88709468373b418f4cf2c949fb0e \ + --hash=sha256:3796a6152c545339d3b1652183e786df648ecdf7c4f9347e1d30e6750907f5bb \ + --hash=sha256:37a822f630712817b6ecc09ccc378192ef5ff12e2c9bae97eb5968a6cdf3b862 \ + --hash=sha256:3a750a83b2728299ca12e003d73d1264ad0440f60f4fc9cee54acc489249b728 \ + --hash=sha256:3c8945a105f1589ce8a693753b908815e0748f6279959a4530f6742e1994dcb6 \ + --hash=sha256:3ccc13afee44b9006a73d2046068d4df96dc5b333bf3509d9a06d1b42db6d8bf \ + --hash=sha256:3f90e5e3afb11268628c89f378f7a1ea3f2fe502a28af4192e30a6cdea1e7d5e \ + --hash=sha256:4292ca56751aebbe63a84bbfc3b5717abb09b14d4b4442cc43fd7c49a1529efd \ + --hash=sha256:430ddd965ffd068dd70ef4e4d74f2c489c3a313adc28e829dd7262cc0d2dd1e8 \ + --hash=sha256:439a0de139556745ae53f9cc9668c6c2053444af940d3ef3ecad95b079bc9987 \ + --hash=sha256:44b4f937b992394a2e81a5c5ce716f3dcc1237281e81b80c748b2da6dd5cf29a \ + --hash=sha256:48c1ed8b02ffea4d5c9c220eda27af02b8149fe58526359b3c07eb391cb353a2 \ + --hash=sha256:4ef724a059396751aef71e847178d66ad7fc3fc969a1a40c29f5aac1aa5f8784 \ + --hash=sha256:50555ba3cb58f9861b7a48c493636b996a617db1a72c18da4d7f16d7b1b9952b \ + --hash=sha256:522a9c4a4d1924facce7270c84b5134c5cabcb01513213662a2e89cf28c1d309 \ + --hash=sha256:5493a7027bfc6b108e17c3383959485087d5942e87eb62bbac69829eae9bc1f7 \ + --hash=sha256:56ea80269077003eaa59723bac1d8bacd2cd15ae30456f2890811efc1e3d4413 \ + --hash=sha256:5a2a3c9ef904dcdadb550eedf3291ec3f229431b0084666e2c2aa8ff99a103a2 \ + --hash=sha256:5cfde4fab34dd1e3a3f7f3db38182ab6c95e4ea91cf322242ee0be5c2f7e3d2f \ + --hash=sha256:5e4a2cf8c4543f37f5dc881de6c190de08096c53986381daebb56a355be5dfe6 \ + --hash=sha256:5e9c068f36b9f396399d43bfb6defd4cc99c36215f6ff33ac8b9c14ba15bdf6b \ + --hash=sha256:5ed7ceca6aba5331ece96c0e328cd52f0dcf942b8895a1ed2642de50800b79d3 \ + --hash=sha256:5fa159b902d22b283b680ef52b532b29554ea2a7fc39bf354064751369e9dbd7 \ + --hash=sha256:615a31b1629e12445c0e9fc8339b41aaa6cc60bd53bf802d5fe3d2c0cda2ae8d \ + --hash=sha256:621afe25cc2b3c4ba05fff53525156d5100eb35c6e5a7cf31d66cc9e1963e378 \ + --hash=sha256:6656a0ae383d8cd7cc94e91de4e526407b3726049ce8d7939049cbfa426518c8 \ + --hash=sha256:672174480a85386dd2e681cadd7d951471ad0bb028ed744c895f11f9d51b9ebe \ + --hash=sha256:692b4ff5c4e828a38716cfa92667661a39886e71136c97b7dac26edef18767f7 \ + --hash=sha256:6bcc1ad776fffe25ea5c187a028991c031a00ff92d012ca1cc4714087e575973 \ + --hash=sha256:6bf7d610ac8f0065a286002a23bcce241ea8248c71988bda538edcc90e0c39ad \ + --hash=sha256:75c0ebbebae71ed1e385f7dfd9b74c1cff09fed24a6df43d326dd7f12339ec34 \ + --hash=sha256:788be9844a6e5c4612b74512a76b2153f1877cd845410d756841f6c3420230eb \ + --hash=sha256:7dc2ce039c7290b4ef64334ec7e6ca6494de6eecc81e21cb4f73b9b39991408c \ + --hash=sha256:813aab5bfb19c98ae370952b6f7190f1e28e565909bfc219a0909db168783465 \ + --hash=sha256:8421cf496e746cf8d6b677502ed9a0d1e4e956586cd8b221e1312e0841c002d5 \ + --hash=sha256:84e87c16f582f5c753b7f39a71bd6647255512191be2d2dbf49458c4ef024588 \ + --hash=sha256:84f8bb34fe76c68c9d96b77c60cef093f5e660ef8e43a6cbfcd991017d375950 \ + --hash=sha256:85cc4d105747d2aa3c5cf3e37dac50141bff779545ba59a095f4a96b0a460e70 \ + --hash=sha256:883daa467865e5766931e07eb20f3e8152324f0adf52658f4d302242c12e2c32 \ + --hash=sha256:8b2b1bfed698fa410ab81982f681f5b1996d3d994ae8073286515ac4d165c2e7 \ + --hash=sha256:8ecbac050856eb6c3046dea655b39216597e373aa8e50e134c0e202f9c47efec \ + --hash=sha256:930bfe73e665ebce3f0da2c6d64455098aaa67e1a00323c74dc752627879fc67 \ + --hash=sha256:9616567800bdc83ce136e5847d41008a1d602213d024207b0ff6cab6753fe645 \ + --hash=sha256:9680dd23055dd874173a3a63a44e7f5a13885a4cfd7e84814be71be24fba83db \ + --hash=sha256:99faba727727b2e59129c59542284efebbddade4f0ae6a29c8b8d3e1f437beb7 \ + --hash=sha256:9a718d56c4d55efcfc63f680f207c9f19c8376e5a8a67773535e6f7e80e93170 \ + --hash=sha256:9b33bf9658cb29ac1a517c11e865112316d09687d767d7a0e4a63d5c640d1b17 \ + --hash=sha256:9e8b374ef41ad5c461efb7a140ce4730661aadf85958b5c6a3e9cf4e040ff4bb \ + --hash=sha256:9e9b65a55bbabda7fccd3500192a79f6e474d8d36e78d1685496aad5f9dbd92c \ + --hash=sha256:a0b7486d85293f7f0bbc39b34e1d8aa26210b450bbd3d245ec3d732864009819 \ + --hash=sha256:a53e3195f134bde03620d87a7e2b2f2046e0e5a8195e66d0f244d6d5b2f6d31b \ + --hash=sha256:a87c54e72aa2ef30189dc74427421e074ab4561cf2bf314589f6af5b37f45e6d \ + --hash=sha256:a892b5b1871b301ce20d40b037ffbe33d1407a39639c2b05356acfef5536d26a \ + --hash=sha256:a8acc9dedd304da161eb071cc7ff1326aa5b66aadec9622b2574ad3ffe225525 \ + --hash=sha256:aaafc776e5edc72b3cad1ccedb5fd869cc5c9a591f1213aa9eba31a781be9ac1 \ + --hash=sha256:acafc4368b289a9f291e204d2c4c75908557d4f36bd3ae937914d4529bf62a76 \ + --hash=sha256:b0a5d7edb76c1c57b95df719af703e796fc8e796447a1da939f97bfa8a918d60 \ + --hash=sha256:b25afe9d5c4f60dcbbe2b277a79be114e2e65a16598db8abee2a2dcde24f162b \ + --hash=sha256:b44c42edc07a50a081672e25dfe6022554b47f91e793066a7b601ca290f71e42 \ + --hash=sha256:b594b64e8568cf09ee5c9501ede37066b9fc41d83d58f55b9952e32141256acd \ + --hash=sha256:b962700962f6e7a6bd77e5f37320cabac24b4c0f76afeac05e9f93cf0c620014 \ + --hash=sha256:bb128c30cf1df0ab78166ded1ecf876620fb9aac84d2413e8ea1594b588c735d \ + --hash=sha256:bf9d42a71a4d7a7c1f14f629e5c30eac451a6fc81827d2beefd57d014c006c4a \ + --hash=sha256:c6595b0d8c8711e8e1dc389d52648b923b809f68ac1c6f0baa525c6440aa0daa \ + --hash=sha256:c8c6660089a25d45333cb9db56bb9e347241a6d7509838dbbd1931d0e19dbc7f \ + --hash=sha256:c9d469204abcca28926cbc28ce98f28e50e488767b084fb3fbdf21af11d3de26 \ + --hash=sha256:d38bbcef58220f9c81e42c255ef0bf99735d8f11edef69ab0b499da77105158a \ + --hash=sha256:d4eb77df2964b64ba190eee00b2312a1fd7a862af8918ec70fc2d6308f76ac64 \ + --hash=sha256:d63b7545d489422d417a0cae6f9898618669608750fc5e62156957e609e728a5 \ + --hash=sha256:d7050899026e708fb185e174c63ebc2c4ee7a0c17b0a96ebc50e1f76a231c057 \ + --hash=sha256:d79f1f2f7ebdb9b741296b69049ff44aedd95976bfee38eb4848820628a99b50 \ + --hash=sha256:d85463560c67fc65cd86153a4975d0b720b6d7725cf7ee0b2d291288433fc21b \ + --hash=sha256:d9140ded382a5b04a1c030b593ed9bf3088243a0a8b7fa9f071a5736498c5483 \ + --hash=sha256:d9b4916b21931b08096efed090327f8fe78e09ae8f5ad44e07f5c72a7eedb51b \ + --hash=sha256:df14f6332834444b4a37685810216cc8fe1fe91f447332cd56294c984ecbff1c \ + --hash=sha256:e49ce7dc9f925e1fb010fc3d555250139df61fa6e5a0a95ce356329602c11ea9 \ + --hash=sha256:e61eae9b31799c32c5f9b7be906be3380e699e74b2db26c227c50a5fc7988698 \ + --hash=sha256:ea053cefa008fda40f92aab937fb9f183cf8752e41dbc7bc68917884454c6362 \ + --hash=sha256:f06e21ad0b504658a3a9edd3d8530e8cea5723f6ea5d280e8db8efc625b47e49 \ + --hash=sha256:f14546403c2a1d11a130b537dda28f07eb6c1805a43dae4617448074fd49c282 \ + --hash=sha256:f1a5d8f18877474c80b7711d870db0eeef9442691fcdb00adabfc97e183ee0b0 \ + --hash=sha256:f2969e8f72c6236c51f91fbb79c33821d12a811e2a94b7aa59c65f8dbdfad34a \ + --hash=sha256:f468d520f47807d1eb5d27648393519655eadc578d5dd862d06873cce04c4d1b \ + --hash=sha256:f70dc00a91311a1aea124e5f64569ea44c011b58433981313202c46bccbec0e1 \ + --hash=sha256:f93255b3e4d64785554e544c1c76cd32f4a354fa79e2eeca5d16ac2e7fdd57aa # via pydantic pyjwt==2.8.0 \ --hash=sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de \ --hash=sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320 # via django-dbmi-client -pyrsistent==0.19.3 \ - --hash=sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8 \ - --hash=sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440 \ - --hash=sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a \ - --hash=sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c \ - --hash=sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3 \ - --hash=sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393 \ - --hash=sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9 \ - --hash=sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da \ - --hash=sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf \ - --hash=sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64 \ - --hash=sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a \ - --hash=sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3 \ - --hash=sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98 \ - --hash=sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2 \ - --hash=sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8 \ - --hash=sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf \ - --hash=sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc \ - --hash=sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7 \ - --hash=sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28 \ - --hash=sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2 \ - --hash=sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b \ - --hash=sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a \ - --hash=sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64 \ - --hash=sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19 \ - --hash=sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1 \ - --hash=sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9 \ - --hash=sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c - # via jsonschema python-dateutil==2.8.2 \ --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 @@ -519,14 +498,16 @@ python-magic==0.4.27 \ --hash=sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b \ --hash=sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3 # via -r requirements.in -pytz==2023.3 \ - --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \ - --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb +pytz==2023.3.post1 \ + --hash=sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b \ + --hash=sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7 # via # django-ses # djangorestframework pyyaml==6.0.1 \ + --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ + --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \ --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ @@ -534,7 +515,10 @@ pyyaml==6.0.1 \ --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ + --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \ + --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \ --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ + --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \ --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ @@ -542,9 +526,12 @@ pyyaml==6.0.1 \ --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ + --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \ --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ + --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \ + --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \ --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ @@ -559,14 +546,18 @@ pyyaml==6.0.1 \ --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ + --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \ --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ + --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \ --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f - # via awscli + # via + # awscli + # drf-spectacular raven==6.10.0 \ --hash=sha256:3fa6de6efa2493a7c827472e984ce9b020797d0da16f1db67197bcc23c8fae54 \ --hash=sha256:44a13f87670836e153951af9a3c80405d36b43097db869a36e92809673692ce4 @@ -577,12 +568,119 @@ redis==3.5.3 \ --hash=sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2 \ --hash=sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24 # via django-q +referencing==0.30.2 \ + --hash=sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf \ + --hash=sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0 + # via + # jsonschema + # jsonschema-specifications requests==2.31.0 \ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 # via # -r requirements.in # django-dbmi-client +rpds-py==0.10.3 \ + --hash=sha256:015de2ce2af1586ff5dc873e804434185199a15f7d96920ce67e50604592cae9 \ + --hash=sha256:061c3ff1f51ecec256e916cf71cc01f9975af8fb3af9b94d3c0cc8702cfea637 \ + --hash=sha256:08a80cf4884920863623a9ee9a285ee04cef57ebedc1cc87b3e3e0f24c8acfe5 \ + --hash=sha256:09362f86ec201288d5687d1dc476b07bf39c08478cde837cb710b302864e7ec9 \ + --hash=sha256:0bb4f48bd0dd18eebe826395e6a48b7331291078a879295bae4e5d053be50d4c \ + --hash=sha256:106af1653007cc569d5fbb5f08c6648a49fe4de74c2df814e234e282ebc06957 \ + --hash=sha256:11fdd1192240dda8d6c5d18a06146e9045cb7e3ba7c06de6973000ff035df7c6 \ + --hash=sha256:16a472300bc6c83fe4c2072cc22b3972f90d718d56f241adabc7ae509f53f154 \ + --hash=sha256:176287bb998fd1e9846a9b666e240e58f8d3373e3bf87e7642f15af5405187b8 \ + --hash=sha256:177914f81f66c86c012311f8c7f46887ec375cfcfd2a2f28233a3053ac93a569 \ + --hash=sha256:177c9dd834cdf4dc39c27436ade6fdf9fe81484758885f2d616d5d03c0a83bd2 \ + --hash=sha256:187700668c018a7e76e89424b7c1042f317c8df9161f00c0c903c82b0a8cac5c \ + --hash=sha256:1d9b5ee46dcb498fa3e46d4dfabcb531e1f2e76b477e0d99ef114f17bbd38453 \ + --hash=sha256:22da15b902f9f8e267020d1c8bcfc4831ca646fecb60254f7bc71763569f56b1 \ + --hash=sha256:24cd91a03543a0f8d09cb18d1cb27df80a84b5553d2bd94cba5979ef6af5c6e7 \ + --hash=sha256:255f1a10ae39b52122cce26ce0781f7a616f502feecce9e616976f6a87992d6b \ + --hash=sha256:271c360fdc464fe6a75f13ea0c08ddf71a321f4c55fc20a3fe62ea3ef09df7d9 \ + --hash=sha256:2ed83d53a8c5902ec48b90b2ac045e28e1698c0bea9441af9409fc844dc79496 \ + --hash=sha256:2f3e1867dd574014253b4b8f01ba443b9c914e61d45f3674e452a915d6e929a3 \ + --hash=sha256:35fbd23c1c8732cde7a94abe7fb071ec173c2f58c0bd0d7e5b669fdfc80a2c7b \ + --hash=sha256:37d0c59548ae56fae01c14998918d04ee0d5d3277363c10208eef8c4e2b68ed6 \ + --hash=sha256:39d05e65f23a0fe897b6ac395f2a8d48c56ac0f583f5d663e0afec1da89b95da \ + --hash=sha256:3ad59efe24a4d54c2742929001f2d02803aafc15d6d781c21379e3f7f66ec842 \ + --hash=sha256:3aed39db2f0ace76faa94f465d4234aac72e2f32b009f15da6492a561b3bbebd \ + --hash=sha256:3bbac1953c17252f9cc675bb19372444aadf0179b5df575ac4b56faaec9f6294 \ + --hash=sha256:40bc802a696887b14c002edd43c18082cb7b6f9ee8b838239b03b56574d97f71 \ + --hash=sha256:42f712b4668831c0cd85e0a5b5a308700fe068e37dcd24c0062904c4e372b093 \ + --hash=sha256:448a66b8266de0b581246ca7cd6a73b8d98d15100fb7165974535fa3b577340e \ + --hash=sha256:485301ee56ce87a51ccb182a4b180d852c5cb2b3cb3a82f7d4714b4141119d8c \ + --hash=sha256:485747ee62da83366a44fbba963c5fe017860ad408ccd6cd99aa66ea80d32b2e \ + --hash=sha256:4cf0855a842c5b5c391dd32ca273b09e86abf8367572073bd1edfc52bc44446b \ + --hash=sha256:4eca20917a06d2fca7628ef3c8b94a8c358f6b43f1a621c9815243462dcccf97 \ + --hash=sha256:4ed172d0c79f156c1b954e99c03bc2e3033c17efce8dd1a7c781bc4d5793dfac \ + --hash=sha256:5267cfda873ad62591b9332fd9472d2409f7cf02a34a9c9cb367e2c0255994bf \ + --hash=sha256:52b5cbc0469328e58180021138207e6ec91d7ca2e037d3549cc9e34e2187330a \ + --hash=sha256:53d7a3cd46cdc1689296348cb05ffd4f4280035770aee0c8ead3bbd4d6529acc \ + --hash=sha256:563646d74a4b4456d0cf3b714ca522e725243c603e8254ad85c3b59b7c0c4bf0 \ + --hash=sha256:570cc326e78ff23dec7f41487aa9c3dffd02e5ee9ab43a8f6ccc3df8f9327623 \ + --hash=sha256:5aca759ada6b1967fcfd4336dcf460d02a8a23e6abe06e90ea7881e5c22c4de6 \ + --hash=sha256:5de11c041486681ce854c814844f4ce3282b6ea1656faae19208ebe09d31c5b8 \ + --hash=sha256:5e271dd97c7bb8eefda5cca38cd0b0373a1fea50f71e8071376b46968582af9b \ + --hash=sha256:642ed0a209ced4be3a46f8cb094f2d76f1f479e2a1ceca6de6346a096cd3409d \ + --hash=sha256:6446002739ca29249f0beaaf067fcbc2b5aab4bc7ee8fb941bd194947ce19aff \ + --hash=sha256:691d50c99a937709ac4c4cd570d959a006bd6a6d970a484c84cc99543d4a5bbb \ + --hash=sha256:69b857a7d8bd4f5d6e0db4086da8c46309a26e8cefdfc778c0c5cc17d4b11e08 \ + --hash=sha256:6ac3fefb0d168c7c6cab24fdfc80ec62cd2b4dfd9e65b84bdceb1cb01d385c33 \ + --hash=sha256:6c9141af27a4e5819d74d67d227d5047a20fa3c7d4d9df43037a955b4c748ec5 \ + --hash=sha256:7170cbde4070dc3c77dec82abf86f3b210633d4f89550fa0ad2d4b549a05572a \ + --hash=sha256:763ad59e105fca09705d9f9b29ecffb95ecdc3b0363be3bb56081b2c6de7977a \ + --hash=sha256:77076bdc8776a2b029e1e6ffbe6d7056e35f56f5e80d9dc0bad26ad4a024a762 \ + --hash=sha256:7cd020b1fb41e3ab7716d4d2c3972d4588fdfbab9bfbbb64acc7078eccef8860 \ + --hash=sha256:821392559d37759caa67d622d0d2994c7a3f2fb29274948ac799d496d92bca73 \ + --hash=sha256:829e91f3a8574888b73e7a3feb3b1af698e717513597e23136ff4eba0bc8387a \ + --hash=sha256:850c272e0e0d1a5c5d73b1b7871b0a7c2446b304cec55ccdb3eaac0d792bb065 \ + --hash=sha256:87d9b206b1bd7a0523375dc2020a6ce88bca5330682ae2fe25e86fd5d45cea9c \ + --hash=sha256:8bd01ff4032abaed03f2db702fa9a61078bee37add0bd884a6190b05e63b028c \ + --hash=sha256:8d54bbdf5d56e2c8cf81a1857250f3ea132de77af543d0ba5dce667183b61fec \ + --hash=sha256:8efaeb08ede95066da3a3e3c420fcc0a21693fcd0c4396d0585b019613d28515 \ + --hash=sha256:8f94fdd756ba1f79f988855d948ae0bad9ddf44df296770d9a58c774cfbcca72 \ + --hash=sha256:95cde244e7195b2c07ec9b73fa4c5026d4a27233451485caa1cd0c1b55f26dbd \ + --hash=sha256:975382d9aa90dc59253d6a83a5ca72e07f4ada3ae3d6c0575ced513db322b8ec \ + --hash=sha256:9dd9d9d9e898b9d30683bdd2b6c1849449158647d1049a125879cb397ee9cd12 \ + --hash=sha256:a019a344312d0b1f429c00d49c3be62fa273d4a1094e1b224f403716b6d03be1 \ + --hash=sha256:a4d9bfda3f84fc563868fe25ca160c8ff0e69bc4443c5647f960d59400ce6557 \ + --hash=sha256:a657250807b6efd19b28f5922520ae002a54cb43c2401e6f3d0230c352564d25 \ + --hash=sha256:a771417c9c06c56c9d53d11a5b084d1de75de82978e23c544270ab25e7c066ff \ + --hash=sha256:aad6ed9e70ddfb34d849b761fb243be58c735be6a9265b9060d6ddb77751e3e8 \ + --hash=sha256:ae87137951bb3dc08c7d8bfb8988d8c119f3230731b08a71146e84aaa919a7a9 \ + --hash=sha256:af247fd4f12cca4129c1b82090244ea5a9d5bb089e9a82feb5a2f7c6a9fe181d \ + --hash=sha256:b5d4bdd697195f3876d134101c40c7d06d46c6ab25159ed5cbd44105c715278a \ + --hash=sha256:b9255e7165083de7c1d605e818025e8860636348f34a79d84ec533546064f07e \ + --hash=sha256:c22211c165166de6683de8136229721f3d5c8606cc2c3d1562da9a3a5058049c \ + --hash=sha256:c55f9821f88e8bee4b7a72c82cfb5ecd22b6aad04033334f33c329b29bfa4da0 \ + --hash=sha256:c7aed97f2e676561416c927b063802c8a6285e9b55e1b83213dfd99a8f4f9e48 \ + --hash=sha256:cd2163f42868865597d89399a01aa33b7594ce8e2c4a28503127c81a2f17784e \ + --hash=sha256:ce5e7504db95b76fc89055c7f41e367eaadef5b1d059e27e1d6eabf2b55ca314 \ + --hash=sha256:cff7351c251c7546407827b6a37bcef6416304fc54d12d44dbfecbb717064717 \ + --hash=sha256:d27aa6bbc1f33be920bb7adbb95581452cdf23005d5611b29a12bb6a3468cc95 \ + --hash=sha256:d3b52a67ac66a3a64a7e710ba629f62d1e26ca0504c29ee8cbd99b97df7079a8 \ + --hash=sha256:de61e424062173b4f70eec07e12469edde7e17fa180019a2a0d75c13a5c5dc57 \ + --hash=sha256:e10e6a1ed2b8661201e79dff5531f8ad4cdd83548a0f81c95cf79b3184b20c33 \ + --hash=sha256:e1a0ffc39f51aa5f5c22114a8f1906b3c17eba68c5babb86c5f77d8b1bba14d1 \ + --hash=sha256:e22491d25f97199fc3581ad8dd8ce198d8c8fdb8dae80dea3512e1ce6d5fa99f \ + --hash=sha256:e626b864725680cd3904414d72e7b0bd81c0e5b2b53a5b30b4273034253bb41f \ + --hash=sha256:e8c71ea77536149e36c4c784f6d420ffd20bea041e3ba21ed021cb40ce58e2c9 \ + --hash=sha256:e8d0f0eca087630d58b8c662085529781fd5dc80f0a54eda42d5c9029f812599 \ + --hash=sha256:ea65b59882d5fa8c74a23f8960db579e5e341534934f43f3b18ec1839b893e41 \ + --hash=sha256:ea93163472db26ac6043e8f7f93a05d9b59e0505c760da2a3cd22c7dd7111391 \ + --hash=sha256:eab75a8569a095f2ad470b342f2751d9902f7944704f0571c8af46bede438475 \ + --hash=sha256:ed8313809571a5463fd7db43aaca68ecb43ca7a58f5b23b6e6c6c5d02bdc7882 \ + --hash=sha256:ef5fddfb264e89c435be4adb3953cef5d2936fdeb4463b4161a6ba2f22e7b740 \ + --hash=sha256:ef750a20de1b65657a1425f77c525b0183eac63fe7b8f5ac0dd16f3668d3e64f \ + --hash=sha256:efb9ece97e696bb56e31166a9dd7919f8f0c6b31967b454718c6509f29ef6fee \ + --hash=sha256:f4c179a7aeae10ddf44c6bac87938134c1379c49c884529f090f9bf05566c836 \ + --hash=sha256:f602881d80ee4228a2355c68da6b296a296cd22bbb91e5418d54577bbf17fa7c \ + --hash=sha256:fc2200e79d75b5238c8d69f6a30f8284290c777039d331e7340b6c17cad24a5a \ + --hash=sha256:fcc1ebb7561a3e24a6588f7c6ded15d80aec22c66a070c757559b57b17ffd1cb + # via + # jsonschema + # referencing rsa==4.7.2 \ --hash=sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2 \ --hash=sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9 @@ -614,6 +712,7 @@ typing-extensions==4.7.1 \ # django-bootstrap-datepicker-plus # django-countries # pydantic + # pydantic-core uritemplate==4.1.1 \ --hash=sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0 \ --hash=sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e @@ -624,7 +723,6 @@ urllib3==1.26.16 \ # via # botocore # requests - # pydantic-core wcwidth==0.2.6 \ --hash=sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e \ --hash=sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0 From 6a96c1927a2775e9844773230715aeec2fdd896f Mon Sep 17 00:00:00 2001 From: Bryan Larson Date: Wed, 13 Sep 2023 09:54:26 -0600 Subject: [PATCH 5/5] HYP-280 - Make user's token available for templates --- .gitignore | 1 + app/hypatio/views.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 719aca1e..29849fc4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ app/db.sqlite3 app/hypatio/local_settings.py .vscode/settings.json backup +infrastructure diff --git a/app/hypatio/views.py b/app/hypatio/views.py index bd1c0295..a8e534ad 100644 --- a/app/hypatio/views.py +++ b/app/hypatio/views.py @@ -1,6 +1,7 @@ import os from django.shortcuts import render from django.utils.functional import SimpleLazyObject +from dbmi_client.authn import get_jwt from hypatio.auth0authenticate import public_user_auth_and_jwt from projects.models import Group, DataProject @@ -43,6 +44,14 @@ def group_context(): "active_group": active_group, } + def user_context(): + + # Check for signed in user + return { + "jwt": get_jwt(request), + } + return { - "navigation": SimpleLazyObject(group_context) + "navigation": SimpleLazyObject(group_context), + "dbmiuser": SimpleLazyObject(user_context), }