diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cab568a1..f6babc08 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout Code Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Python 3.9 uses: actions/setup-python@v2 @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout Code Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up .env file run: | @@ -44,35 +44,35 @@ jobs: echo "VIPPS_MERCHANT_SERIAL_NUMBER=${{ secrets.VIPPS_MERCHANT_SERIAL_NUMBER }}" >> .env - name: Build the Stack - run: docker-compose build + run: docker compose build - name: Run the Stack - run: docker-compose up -d + run: docker compose up -d - name: Make DB Migrations - run: docker-compose run --rm web python manage.py migrate + run: docker compose run --rm web python manage.py migrate - name: Run Django Tests - run: docker-compose run --rm web pytest --cov=app + run: docker compose run --rm web pytest --cov=app - name: Tear down the Stack - run: docker-compose down + run: docker compose down check-migrations: runs-on: ubuntu-latest steps: - name: Checkout Code Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Build the Stack - run: docker-compose build + run: docker compose build - name: Run the Stack - run: docker-compose up -d + run: docker compose up -d - name: Check for unstaged migrations - run: docker-compose run --rm web python manage.py makemigrations --check --no-input + run: docker compose run --rm web python manage.py makemigrations --check --no-input - name: Tear down the Stack - run: docker-compose down \ No newline at end of file + run: docker compose down \ No newline at end of file diff --git a/.gitignore b/.gitignore index 05184f48..f1a7cc85 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ celerybeat-schedule .terraform *.tfvars +.terraform.lock.hcl \ No newline at end of file diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl index 3e007d98..59f929fd 100644 --- a/.terraform.lock.hcl +++ b/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/azurerm" { version = "3.76.0" constraints = "> 3.68.0" hashes = [ + "h1:b7wCNsV0HyJalcmjth7Y4nSBuZqEjbA0Phpggoy4bLE=", "h1:eArCWwNEShXmVWS08Ocd3d8ptsjbAaMECifkIBacpyw=", "zh:33c6b1559b012d03befeb8ee9cf5b88c31acd64983dd4f727a49a436008b5577", "zh:36d3cfa7cf2079a102ffce05da2de41ecf263310544990471c19ee01b135ccf3", @@ -24,6 +25,7 @@ provider "registry.terraform.io/hashicorp/azurerm" { provider "registry.terraform.io/hashicorp/random" { version = "3.5.1" hashes = [ + "h1:3hjTP5tQBspPcFAJlfafnWrNrKnr7J4Cp0qB9jbqf30=", "h1:VSnd9ZIPyfKHOObuQCaKfnjIHRtR7qTw19Rz8tJxm+k=", "zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64", "zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d", diff --git a/CHANGELOG.md b/CHANGELOG.md index ee02ac83..07920a4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ ## Versjon 2024.07.30 - ✨ **Feide**. Man kan nå registrere bruker automatisk med Feide. +- ✨ **Fillagring**. Man kan nå slette en fil fra Azure basert på container navn og fil navn. ## Versjon 2024.05.01 - ⚡**Arrangement**. Et arrangement vil nå få kategori sendt som navn på kategori istedenfor kun id. diff --git a/app/common/file_handler.py b/app/common/file_handler.py index 590123d7..3b745075 100644 --- a/app/common/file_handler.py +++ b/app/common/file_handler.py @@ -21,7 +21,7 @@ def getContainerNameFromBlob(self): return ( "".join(e for e in self.blob.content_type if e.isalnum()) if self.blob.content_type - else None + else "default" ) def checkBlobSize(self): diff --git a/app/content/serializers/user.py b/app/content/serializers/user.py index 86842860..44a20712 100644 --- a/app/content/serializers/user.py +++ b/app/content/serializers/user.py @@ -5,22 +5,22 @@ from dry_rest_permissions.generics import DRYGlobalPermissionsField -from app.communication.notifier import Notify -from app.communication.enums import UserNotificationSettingType -from app.common.enums import GroupType, Groups +from app.common.enums import Groups, GroupType from app.common.serializers import BaseModelSerializer +from app.communication.enums import UserNotificationSettingType +from app.communication.notifier import Notify +from app.content.exceptions import FeideUserExistsError from app.content.models import User from app.content.serializers.user_bio import UserBioSerializer -from app.group.models import Group, Membership from app.content.util.feide_utils import ( + generate_random_password, get_feide_tokens, get_feide_user_groups, - parse_feide_groups, - generate_random_password, - get_study_year, get_feide_user_info_from_jwt, + get_study_year, + parse_feide_groups, ) -from app.content.exceptions import FeideUserExistsError +from app.group.models import Group, Membership class DefaultUserSerializer(BaseModelSerializer): @@ -168,9 +168,7 @@ def add_user_to_study(self, user, slug): study = Group.objects.filter(type=GroupType.STUDY, slug=slug).first() study_year = get_study_year(slug) class_ = Group.objects.get_or_create( - name=study_year, - type=GroupType.STUDYYEAR, - slug=study_year + name=study_year, type=GroupType.STUDYYEAR, slug=study_year ) if not study or not class_: diff --git a/app/content/urls.py b/app/content/urls.py index b7d6d0bc..c5a48239 100644 --- a/app/content/urls.py +++ b/app/content/urls.py @@ -18,8 +18,9 @@ UserCalendarEvents, UserViewSet, accept_form, - upload, + delete, register_with_feide, + upload, ) router = routers.DefaultRouter() @@ -52,6 +53,7 @@ re_path(r"", include(router.urls)), path("accept-form/", accept_form), path("upload/", upload), + path("delete-file///", delete), path("feide/", register_with_feide), re_path(r"users/(?P[^/.]+)/events.ics", UserCalendarEvents()), ] diff --git a/app/content/util/feide_utils.py b/app/content/util/feide_utils.py index 8c0b82e6..bc38cc96 100644 --- a/app/content/util/feide_utils.py +++ b/app/content/util/feide_utils.py @@ -1,11 +1,21 @@ -import jwt -import requests import secrets import string +from datetime import datetime +import jwt +import requests from requests.auth import HTTPBasicAuth -from datetime import datetime +from app.content.exceptions import ( + FeideGetTokenError, + FeideGetUserGroupsError, + FeideParseGroupsError, + FeideTokenNotFoundError, + FeideUsedUserCode, + FeideUserGroupsNotFoundError, + FeideUserInfoNotFoundError, + FeideUsernameNotFoundError, +) from app.settings import ( FEIDE_CLIENT_ID, FEIDE_CLIENT_SECRET, @@ -14,17 +24,6 @@ FEIDE_USER_GROUPS_INFO_URL, ) -from app.content.exceptions import ( - FeideTokenNotFoundError, - FeideGetTokenError, - FeideUserInfoNotFoundError, - FeideUsernameNotFoundError, - FeideUserGroupsNotFoundError, - FeideParseGroupsError, - FeideGetUserGroupsError, - FeideUsedUserCode, -) - def get_feide_tokens(code: str) -> tuple[str, str]: """Get access and JWT tokens for signed in Feide user""" diff --git a/app/content/views/__init__.py b/app/content/views/__init__.py index 50ff70ba..3392d438 100644 --- a/app/content/views/__init__.py +++ b/app/content/views/__init__.py @@ -8,7 +8,7 @@ from app.content.views.news import NewsViewSet from app.content.views.page import PageViewSet from app.content.views.short_link import ShortLinkViewSet -from app.content.views.upload import upload +from app.content.views.upload import upload, delete from app.content.views.strike import StrikeViewSet from app.content.views.toddel import ToddelViewSet from app.content.views.qr_code import QRCodeViewSet diff --git a/app/content/views/feide.py b/app/content/views/feide.py index 57febec1..f09917b0 100644 --- a/app/content/views/feide.py +++ b/app/content/views/feide.py @@ -1,9 +1,12 @@ -from rest_framework.decorators import api_view from rest_framework import status +from rest_framework.decorators import api_view from rest_framework.response import Response -from app.content.serializers import FeideUserCreateSerializer, DefaultUserSerializer from app.content.exceptions import FeideError +from app.content.serializers import ( + DefaultUserSerializer, + FeideUserCreateSerializer, +) @api_view(["POST"]) diff --git a/app/content/views/upload.py b/app/content/views/upload.py index b4e54a3b..e203c0f7 100644 --- a/app/content/views/upload.py +++ b/app/content/views/upload.py @@ -38,3 +38,25 @@ def upload(request): {"detail": str(value_error)}, status=status.HTTP_400_BAD_REQUEST, ) + + +@api_view(["DELETE"]) +@permission_classes([IsMember]) +def delete(request, container_name, blob_name): + """Method for deleting files from Azure Blob Storage, only allowed for members""" + try: + handler = AzureFileHandler() + handler.blobName = blob_name + handler.containerName = container_name + + handler.deleteBlob() + return Response( + {"detail": "Filen ble slettet"}, + status=status.HTTP_200_OK, + ) + + except ValueError as value_error: + return Response( + {"detail": str(value_error)}, + status=status.HTTP_400_BAD_REQUEST, + ) diff --git a/infrastructure/containers.tf b/infrastructure/containers.tf index 856f795c..65fb201f 100644 --- a/infrastructure/containers.tf +++ b/infrastructure/containers.tf @@ -164,6 +164,26 @@ resource "azurerm_container_app" "lepton-api" { name = "VIPPS_ORDER_URL" value = var.vipps_order_url } + env { + name = "FEIDE_CLIENT_ID" + value = var.feide_client_id + } + env { + name = "FEIDE_CLIENT_SECRET" + value = var.feide_client_secret + } + env { + name = "FEIDE_TOKEN_URL" + value = var.feide_token_url + } + env { + name = "FEIDE_USER_GROUPS_INFO_URL" + value = var.feide_user_groups_info_url + } + env { + name = "FEIDE_REDIRECT_URL" + value = var.feide_redirect_url + } env { name = var.enviroment == "pro" ? "PROD" : "DEV" value = "true" @@ -337,6 +357,26 @@ resource "azurerm_container_app" "celery" { name = "VIPPS_ORDER_URL" value = var.vipps_order_url } + env { + name = "FEIDE_CLIENT_ID" + value = var.feide_client_id + } + env { + name = "FEIDE_CLIENT_SECRET" + value = var.feide_client_secret + } + env { + name = "FEIDE_TOKEN_URL" + value = var.feide_token_url + } + env { + name = "FEIDE_USER_GROUPS_INFO_URL" + value = var.feide_user_groups_info_url + } + env { + name = "FEIDE_REDIRECT_URL" + value = var.feide_redirect_url + } } } diff --git a/infrastructure/inputs.tf b/infrastructure/inputs.tf index c95871b3..55b271be 100644 --- a/infrastructure/inputs.tf +++ b/infrastructure/inputs.tf @@ -64,6 +64,30 @@ variable "lepton_api_max_replicas" { default = 1 } +variable "feide_client_id" { + type = string + sensitive = true +} + +variable "feide_client_secret" { + type = string + sensitive = true +} + +variable "feide_token_url" { + type = string + default = "https://auth.dataporten.no/oauth/token" +} + +variable "feide_user_groups_info_url" { + type = string + default = "https://groups-api.dataporten.no/groups/me/groups" +} + +variable "feide_redirect_url" { + type = string +} + variable "enviroment" { type = string description = "value is either dev or pro" diff --git a/main.tf b/main.tf index 10b49d13..50ad565b 100644 --- a/main.tf +++ b/main.tf @@ -39,4 +39,10 @@ module "infrastructure" { lepton_api_min_replicas = var.lepton_api_min_replicas lepton_api_max_replicas = var.lepton_api_max_replicas + + feide_client_id = var.feide_client_id + feide_client_secret = var.feide_client_secret + feide_token_url = var.feide_token_url + feide_user_groups_info_url = var.feide_user_groups_info_url + feide_redirect_url = var.feide_redirect_url }