Skip to content

Commit

Permalink
Mid October Update (#903)
Browse files Browse the repository at this point in the history
* Feat(kontres)/add image to bookable item (#785)

* added optional image to bookable item model

* added update method in serializer to handle new images

* linting

* remove update method for images

* Feat(kontres)/add approved by (#786)

* added approved by field

* endpoint will now set approved by

* serializer will return full user object in approved_by_detail

* created test for approved by

* migration

* remove unnecessary code

* removed write-only field in approved-by context

* Create minutes for Codex (#787)

* init

* format

* Feat(minute)/viewset (#788)

* added richer reponse on post and put

* added to admin panel

* added filter for minute

* Feat(kontres)/add notification (#790)

* created methods for sending notification to admin and user

* endpoint will now send notification if needed

* add migrations for new notification types

* Memberships with fines activated (#791)

init

* Feat(user)/user bio (#758)

* Created model, serializer and view for user-bio

* Created user bio model and made migrations

* Created user bio serializer + viewsets + added new endpoint

* Tested create method + added bio serializer to user serializer

* Format

* Created update method and started testing

* Debugging test failures in user retrieve

* fixed model error

* Created user_bio_factory + started testing put method

* Created fixture for UserBio

* Created custom excpetion for duplicate user bio

* Added permissions and inherited from BaseModel

* Modularized serializer for bio

* Use correct serializers in viewset + added destroy method

* Finished testing bio viewset integration + format

* Changed environent file to .env to avoid pushing up keys

* Fix: Flipped assertion statement in test, since user bio should not be deleted

* skiped buggy test from kontres

* added mark to pytest.skip

* Moved keys to .env file and reverted docker variables

* Skip buggy kontres test

* format

* Added str method to user_bio

* Removed unused imports

* format

* Changed user relation to a OneToOne-field (same affect as ForeignKey(unique=True) + removed check for duplicate bio in serializer

* Migrations + changed assertion status code in duplicate bio test (could try catch in serializer to produce 400 status code)

* format

* format

* Changed limit for description 50 -> 500 + migrations

* Migrate

* added id to serializer

* merged leaf nodes in migrations

* format

---------

Co-authored-by: Ester2109 <[email protected]>
Co-authored-by: Mads Nylund <[email protected]>
Co-authored-by: Mads Nylund <[email protected]>
Co-authored-by: Tam Le <[email protected]>

* Update CHANGELOG.md

* added filter for allowed photos for user (#794)

added filter for allowed photos

* Upped payment time when coming from waiting list (#796)

* fixed paymenttime saved to db (#798)

* fixed bug (#800)

* Disallow users to unregister when payment is done (#802)

added 400 status code for deleting paid registration

* update changelog

* Added serializer for category in  event (#804)

added serializer for category in  event

* Permission middelware (#806)

* added a check for existing user and id on request

* format

* Permission refactor of QR Codes (#807)

* added permissions to qr code and refactored viewset

* format

* removed unused imports

* Permissions for payment orders (#808)

* added read permissions

* added permissions for payment order and tests

* format

* chore(iac): updated docs and force https (#810)

chore: updated docs and force https

* feat(iac): add terraform guardrails so index don't nuke our infra (#811)

feat: add guardrails so index don't fup

* Automatic registration for new users with Feide (#809)

* started on feide registration endpoint

* made endpoint for creating user with Feide

* added test for parse group

* finished

* format

* removes three years if in digtrans

* changelog update

* Feide env variables Terraform (#814)

added feid env variables

* added delete endpoint for file (#815)

* added delete endpoint for file

* Trigger Build

* changed workflow to checkout v4

* changed from docker-compose to docker compose

* Update CHANGELOG.md

* format

* format

* fixed permission for committee leaders for group forms

* updated csv for forms (#818)

* Permission for group forms and news (#820)

added permission for committees to create news, and all leaders of groups to create group forms

* Update reservation_seralizer.py (#822)

* Update reservation_seralizer.py

* Fixed linting

* Put a band aid on it *smack*

* Removed blank line..

* ????

* Group ownership of Minutes (#847)

* Refactor MinuteFactory to include group field, and added validation for checkin group access

* added validation for POST request

* Changed endpoint response (#846)

* Changed endpoint response

* Fixed test

* Update test_reservation_integration.py

---------

Co-authored-by: Mads Nylund <[email protected]>

* updated changelog.md

* finished events now appear in the correct order (newest first) (#849)

* finished events now appear in the correct order (newest first)

* added description of change in changelog

* fixed formatting

* updated method to use Django ORM instead of using python methods

* Implement Swagger (#858)

* started on removing choiceenums

* refactored cheatsheet and membership

* refacotered strike enum

* refactored Groups enum

* removed AppModel choiceenum

* added swagger

* Swagger GitHub Action (#860)

* added github action for checking if Swagger is up

* new action

* try another

* tried implementing check for container

* added curl to docker image

* added check if swagger is up

* test if swagger does not get status code 200

* added ?format=openai to trigger error

* checking that the request is working

* updated CHANGELOG.md

* Add new app (#862)

* added script for adding new app to Lepton

* added command to Makefile

* Upgrade all dependencies to latest (#857)

* Add endpoint to create new group as admin

Signed-off-by: Tmpecho <[email protected]>

* Upgrade all dependencies to latest

Signed-off-by: Tmpecho <[email protected]>

* remove bad exception handling in serializers/group.py

* fix inheritance ordering in views/group.py

* refactored group integration test, added non_public_groups to enums

* fix linting

* reformat files

* remove unused import in groups/views/group.py

* Upgrade dependency "black"

Signed-off-by: Tmpecho <[email protected]>

* Upgrade dependency "sentry-sdk"

Signed-off-by: Tmpecho <[email protected]>

* Upgrade dependency "azure-storage-blob" and remove outdated comment in requirements.txt

Signed-off-by: Tmpecho <[email protected]>

* Upgrade all non-django dependencies

Signed-off-by: Tmpecho <[email protected]>

* Upgrade dependency "Django"

Signed-off-by: Tmpecho <[email protected]>

* Upgrade dependencies and remove ignored version from docker-compose.yml

Signed-off-by: Tmpecho <[email protected]>

---------

Signed-off-by: Tmpecho <[email protected]>
Co-authored-by: 1Cezzo <[email protected]>

* Allow HS members to create a new group (#864)

* Add endpoint to create new group as admin

Signed-off-by: Tmpecho <[email protected]>

* remove bad exception handling in serializers/group.py

* fix inheritance ordering in views/group.py

* refactored group integration test, added non_public_groups to enums

* fix linting

* reformat files

* remove unused import in groups/views/group.py

---------

Signed-off-by: Tmpecho <[email protected]>
Co-authored-by: 1Cezzo <[email protected]>

* App Script Fix (#875)

added serializers dir to script

* Event registration payment orders (#876)

* added list of payment orders for registrations

* update CHANGELOG.md

* chore(deps): update python-dotenv requirement from ~=0.21.1 to ~=1.0.1 (#871)

Updates the requirements on [python-dotenv](https://github.com/theskumar/python-dotenv) to permit the latest version.
- [Release notes](https://github.com/theskumar/python-dotenv/releases)
- [Changelog](https://github.com/theskumar/python-dotenv/blob/main/CHANGELOG.md)
- [Commits](theskumar/python-dotenv@v0.21.1...v1.0.1)

---
updated-dependencies:
- dependency-name: python-dotenv
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mads Nylund <[email protected]>

* Chore(deps): Bump sentry-sdk from 1.14.0 to 2.8.0 (#866)

Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 1.14.0 to 2.8.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](getsentry/sentry-python@1.14.0...2.8.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mads Nylund <[email protected]>

* Codex Course (#852)

* added models for course and registration, and viewset for course and tests

* added validation for date checking for courses

* added viewset for registration for codex courses

* removed unused fields from course model

* removed unused imports

* added API error mixins as mother clas

* fixed error mixin

* refactored to event model

* fixed wrong import

* fixed tests

* format

* skipped broken tests, must be refactored

* updated CHANGELOG.md

* format

* fixed filtering of groups and made tests

* fixed list endpoint for cheatsheets

* trigger

* format

* Endpoint for sending email (#883)

* fix formatting

* created tests for send_email endpoint

* Fix code scanning alert no. 45: Information exposure through an exception

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fixed errors in send_email and in tests

* lint

* added tests for empty lists and for sending mail to multiple users

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* chore(deps): bump black from 24.3.0 to 24.8.0 (#869)

Bumps [black](https://github.com/psf/black) from 24.3.0 to 24.8.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](psf/black@24.3.0...24.8.0)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mads Nylund <[email protected]>

* chore(deps): Bump azure-storage-blob from 12.13.1 to 12.23.1 (#885)

Bumps [azure-storage-blob](https://github.com/Azure/azure-sdk-for-python) from 12.13.1 to 12.23.1.
- [Release notes](https://github.com/Azure/azure-sdk-for-python/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-python/blob/main/doc/esrp_release.md)
- [Commits](Azure/azure-sdk-for-python@azure-storage-blob_12.13.1...azure-storage-blob_12.23.1)

---
updated-dependencies:
- dependency-name: azure-storage-blob
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mads Nylund <[email protected]>

* Added admin.py to root in new app, and added app dir to tests (#892)

added admin.py to root in new app, and added app dir to tests

* Description to forms (#894)

added description to form

* Bug report system (#865)

* Created New App named Index

* created model

* Refactor: Change admin file

* admin

* added serializer and viewsets for list

* fixed typing error for permission_classes

* Started on the create serializer for feedback

* Made tests for create feedback

* Implemented update serializer for feedback

* made destroy method and testing create method as member

* Made destroy method and tests

* Fixed linting

* Fixed linting

---------

Co-authored-by: Tam Le <[email protected]>
Co-authored-by: Josefine Arntsen <[email protected]>
Co-authored-by: Mads Nylund <[email protected]>
Co-authored-by: Mads Nylund <[email protected]>

* Renaming of index app to feedback (#901)

renamed index app to feedback

* chore(deps): bump django from 4.2.16 to 5.1.1 (#889)

Bumps [django](https://github.com/django/django) from 4.2.16 to 5.1.1.
- [Commits](django/django@4.2.16...5.1.1)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mads Nylund <[email protected]>

* Event registration race condition (#902)

* started on fixing race condition

* fixed race condition

* upadted CHANGELOG.md

---------

Signed-off-by: Tmpecho <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: Erik Skjellevik <[email protected]>
Co-authored-by: haruixu <[email protected]>
Co-authored-by: Ester2109 <[email protected]>
Co-authored-by: Tam Le <[email protected]>
Co-authored-by: martcl <[email protected]>
Co-authored-by: Frikk Balder <[email protected]>
Co-authored-by: Emil Johnsen <[email protected]>
Co-authored-by: Johannes Aamot-Skeidsvoll <[email protected]>
Co-authored-by: 1Cezzo <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Josefine Arntsen <[email protected]>
Co-authored-by: Josefine Arntsen <[email protected]>
  • Loading branch information
14 people authored Oct 11, 2024
1 parent 3af9f5e commit 8c8199a
Show file tree
Hide file tree
Showing 45 changed files with 1,028 additions and 6 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@

## Neste versjon

## Versjon 2024.09.25
## Versjon 2024.10.11
-**Tilbakemelding-funksjon**. Man kan nå opprette tilbakemeldinger for bugs og idé.
- 🦟 **Påmelding**. Det vil nå ikke være mulig med flere påmeldinger på et arrangement enn maksgrensen.

## Versjon 2024.09.25
-**Codex arrangementer**. Det kan nå opprettes arrangementer på Codex, som medlemmer av Codex kan melde seg på.
-**Betalingsordre**. Man kan nå se historikk over betalingsordre for en påmelding til et arrangement.
-**Gruppe**. HS kan nå opprette en ny gruppe.
Expand Down
6 changes: 6 additions & 0 deletions app/communication/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ class UserNotificationSettingType(models.TextChoices):
RESERVATION_NEW = "RESERVATION NEW", "Ny reservasjon"
RESERVATION_APPROVED = "RESERVATION APPROVED", "Godkjent reservasjon"
RESERVATION_CANCELLED = "RESERVATION CANCELLED", "Avslått reservasjon"
KONTRES = "KONTRES", "Kontres"
BLITZED = "BLITZED", "Blitzed"

@classmethod
def get_kontres_and_blitzed(cls):
return [cls.KONTRES, cls.BLITZED]
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Generated by Django 4.2.5 on 2024-09-23 18:02

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("communication", "0010_alter_usernotificationsetting_notification_type"),
]

operations = [
migrations.AlterField(
model_name="usernotificationsetting",
name="notification_type",
field=models.CharField(
choices=[
("REGISTRATION", "Påmeldingsoppdateringer"),
("UNREGISTRATION", "Avmeldingsoppdateringer"),
("STRIKE", "Prikkoppdateringer"),
("EVENT_SIGN_UP_START", "Arrangementer - påmeldingsstart"),
("EVENT_SIGN_OFF_DEADLINE", "Arrangementer - avmeldingsfrist"),
("EVENT_EVALUATION", "Arrangementer - evaluering"),
("EVENT_INFO", "Arrangementer - info fra arrangør"),
("FINE", "Grupper - bot"),
("GROUP_MEMBERSHIP", "Grupper - medlemsskap"),
("OTHER", "Andre"),
("RESERVATION NEW", "Ny reservasjon"),
("RESERVATION APPROVED", "Godkjent reservasjon"),
("RESERVATION CANCELLED", "Avslått reservasjon"),
("KONTRES", "Kontres"),
("BLITZED", "Blitzed"),
],
max_length=30,
),
),
]
216 changes: 216 additions & 0 deletions app/communication/tests/test_send_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import os
from unittest.mock import patch

from rest_framework import status

import pytest

from app.communication.enums import UserNotificationSettingType
from app.communication.notifier import Notify
from app.content.factories import UserFactory
from app.util.test_utils import get_api_client

EMAIL_URL = "/send-email/"
EMAIL_API_KEY = os.environ.get("EMAIL_API_KEY")


def _get_email_url():
return f"{EMAIL_URL}"


@pytest.mark.django_db
@patch.object(Notify, "send", return_value=None)
def test_send_email_success(mock_send):
"""
Test that the send_email endpoint sends an email successfully.
"""
test_user = UserFactory()

data = {
"user_id_list": [test_user.user_id],
"notification_type": "KONTRES",
"title": "Test Notification",
"paragraphs": ["This is a test paragraph.", "This is another paragraph."],
}

client = get_api_client(user=test_user)
url = _get_email_url()
headers = {"api_key": EMAIL_API_KEY}
response = client.post(url, data, format="json", **headers)

assert response.status_code == status.HTTP_201_CREATED
mock_send.assert_called_once()


@pytest.mark.django_db
@patch.object(Notify, "send", return_value=None)
def test_send_email_fails_when_field_missing(mock_send):
"""
Test that the send_email endpoint returns 400 when one of the fields is missing.
"""
test_user = UserFactory()

data = {
"user_id_list": [test_user.user_id],
"title": "Test Notification",
"paragraphs": ["This is a test paragraph.", "This is another paragraph."],
}

client = get_api_client(user=test_user)
url = _get_email_url()
headers = {"api_key": EMAIL_API_KEY}
response = client.post(url, data, format="json", **headers)

assert response.status_code == status.HTTP_400_BAD_REQUEST
mock_send.assert_not_called()


@pytest.mark.django_db
@patch.object(Notify, "send", return_value=None)
def test_send_email_fails_when_wrong_api_key(mock_send):
"""
Test that the send_email endpoint returns 403 when the API key is invalid.
"""
test_user = UserFactory()

data = {
"user_id_list": [test_user.user_id],
"notification_type": "KONTRES",
"title": "Test Notification",
"paragraphs": ["This is a test paragraph.", "This is another paragraph."],
}

client = get_api_client(user=test_user)
url = _get_email_url()
headers = {"api_key": "wrong_key"}
response = client.post(url, data, format="json", **headers)

assert response.status_code == status.HTTP_403_FORBIDDEN
mock_send.assert_not_called()


@pytest.mark.django_db
@patch.object(Notify, "send", return_value=None)
def test_send_email_fails_when_user_id_invalid(mock_send):
"""
Test that the send_email endpoint returns 404 when the user id is invalid.
"""
test_user = UserFactory()

data = {
"user_id_list": [999],
"notification_type": "KONTRES",
"title": "Test Notification",
"paragraphs": ["This is a test paragraph.", "This is another paragraph."],
}

client = get_api_client(user=test_user)
url = _get_email_url()
headers = {"api_key": EMAIL_API_KEY}
response = client.post(url, data, format="json", **headers)

assert response.status_code == status.HTTP_404_NOT_FOUND
mock_send.assert_not_called()


@pytest.mark.django_db
@patch.object(Notify, "send", return_value=None)
@pytest.mark.parametrize(
"notification_type", UserNotificationSettingType.get_kontres_and_blitzed()
)
def test_email_success_with_kontres_and_blitzed(mock_send, notification_type):
"""
Tests that the send_email endpoint works with both KONTRES and BLITZED notification types.
"""
test_user = UserFactory()

data = {
"user_id_list": [test_user.user_id],
"notification_type": notification_type,
"title": "Test Notification",
"paragraphs": ["This is a test paragraph.", "This is another paragraph."],
}

client = get_api_client(user=test_user)
url = _get_email_url()
headers = {"api_key": EMAIL_API_KEY}
response = client.post(url, data, format="json", **headers)

assert response.status_code == status.HTTP_201_CREATED
mock_send.assert_called_once()


@pytest.mark.django_db
@patch.object(Notify, "send", return_value=None)
def test_send_email_success_with_user_id_list(mock_send):
"""
Test that the send_email endpoint sends an email successfully to a list of users.
"""
test_user1 = UserFactory()
test_user2 = UserFactory()
test_user3 = UserFactory()

data = {
"user_id_list": [
test_user.user_id for test_user in [test_user1, test_user2, test_user3]
],
"notification_type": "KONTRES",
"title": "Test Notification",
"paragraphs": ["This is a test paragraph.", "This is another paragraph."],
}

client = get_api_client(user=test_user1)
url = _get_email_url()
headers = {"api_key": EMAIL_API_KEY}
response = client.post(url, data, format="json", **headers)

assert response.status_code == status.HTTP_201_CREATED
mock_send.assert_called_once()


@pytest.mark.django_db
@patch.object(Notify, "send", return_value=None)
def test_send_email_fails_when_user_id_list_is_empty(mock_send):
"""
Test that the send_email endpoint returns 400 when the user id list is empty.
"""
test_user = UserFactory()

data = {
"user_id_list": [],
"notification_type": "KONTRES",
"title": "Test Notification",
"paragraphs": ["This is a test paragraph.", "This is another paragraph."],
}

client = get_api_client(user=test_user)
url = _get_email_url()
headers = {"api_key": EMAIL_API_KEY}
response = client.post(url, data, format="json", **headers)

assert response.status_code == status.HTTP_400_BAD_REQUEST
mock_send.assert_not_called()


@pytest.mark.django_db
@patch.object(Notify, "send", return_value=None)
def test_send_email_fails_when_user_paragraph_list_is_empty(mock_send):
"""
Test that the send_email endpoint returns 400 when the paragraph list is empty.
"""
test_user = UserFactory()

data = {
"user_id_list": [test_user.user_id],
"notification_type": "KONTRES",
"title": "Test Notification",
"paragraphs": [],
}

client = get_api_client(user=test_user)
url = _get_email_url()
headers = {"api_key": EMAIL_API_KEY}
response = client.post(url, data, format="json", **headers)

assert response.status_code == status.HTTP_400_BAD_REQUEST
mock_send.assert_not_called()
1 change: 1 addition & 0 deletions app/content/serializers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class Meta:
"user_id",
"first_name",
"last_name",
"image",
)


Expand Down
2 changes: 2 additions & 0 deletions app/content/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
accept_form,
delete,
register_with_feide,
send_email,
upload,
)

Expand Down Expand Up @@ -53,6 +54,7 @@
re_path(r"", include(router.urls)),
path("accept-form/", accept_form),
path("upload/", upload),
path("send-email/", send_email),
path("delete-file/<str:container_name>/<str:blob_name>/", delete),
path("feide/", register_with_feide),
re_path(r"users/(?P<user_id>[^/.]+)/events.ics", UserCalendarEvents()),
Expand Down
1 change: 1 addition & 0 deletions app/content/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
from app.content.views.logentry import LogEntryViewSet
from app.content.views.minute import MinuteViewSet
from app.content.views.feide import register_with_feide
from app.content.views.send_email import send_email
4 changes: 3 additions & 1 deletion app/content/views/registration.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import uuid

from django.db.transaction import atomic
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters, status
Expand Down Expand Up @@ -48,6 +49,7 @@ def _is_own_registration(self):
def _is_not_own_registration(self):
return not self._is_own_registration()

@atomic
def create(self, request, *args, **kwargs):
"""Register the current user for the given event."""

Expand All @@ -68,7 +70,7 @@ def create(self, request, *args, **kwargs):
serializer.is_valid(raise_exception=True)

event_id = self.kwargs.get("event_id", None)
event = Event.objects.get(pk=event_id)
event = Event.objects.select_for_update().get(pk=event_id)

registration = super().perform_create(
serializer, event=event, user=request.user
Expand Down
Loading

0 comments on commit 8c8199a

Please sign in to comment.