diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 290e740..95a78b0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,7 +63,7 @@ jobs: pip install -r requirements.txt - name: Run tests - run: pytest --log-cli-level=DEBUG --cov=project --splits 4 --group ${{ matrix.group }} + run: pytest --cov=project --splits 4 --group ${{ matrix.group }} env: TEST_DATABASE_URL: postgresql://postgres:postgres@localhost/eventcally_tests TEST_REDIS_URL: redis://localhost:6379 diff --git a/cypress/e2e/event.cy.js b/cypress/e2e/event.cy.js index 479d485..792759d 100644 --- a/cypress/e2e/event.cy.js +++ b/cypress/e2e/event.cy.js @@ -1,6 +1,6 @@ describe("Event", () => { [{ recurrence: false }, { recurrence: true }].forEach(function (test) { - it("creates event with recurrence=" + test.recurrence, () => { + it.only("creates event with recurrence=" + test.recurrence, () => { cy.login(); cy.createAdminUnit().then(function (adminUnitId) { cy.visit("/admin_unit/" + adminUnitId + "/events/create"); @@ -48,7 +48,7 @@ describe("Event", () => { }); }); - it("saves draft", () => { + it.only("saves draft", () => { cy.login(); cy.createAdminUnit().then(function (adminUnitId) { cy.visit("/admin_unit/" + adminUnitId + "/events/create"); diff --git a/project/api/event/schemas.py b/project/api/event/schemas.py index e7908b0..3163254 100644 --- a/project/api/event/schemas.py +++ b/project/api/event/schemas.py @@ -88,11 +88,11 @@ class EventBaseSchemaMixin(TrackableSchemaMixin): } ) kid_friendly = marshmallow.auto_field( - missing=False, + load_default=False, metadata={"description": "If the event is particularly suitable for children."}, ) accessible_for_free = marshmallow.auto_field( - missing=False, + load_default=False, metadata={"description": "If the event is accessible for free."}, ) age_from = marshmallow.auto_field( @@ -103,19 +103,19 @@ class EventBaseSchemaMixin(TrackableSchemaMixin): ) target_group_origin = EnumField( EventTargetGroupOrigin, - missing=EventTargetGroupOrigin.both, + load_default=EventTargetGroupOrigin.both, metadata={ "description": "Whether the event is particularly suitable for tourists or residents." }, ) attendance_mode = EnumField( EventAttendanceMode, - missing=EventAttendanceMode.offline, + load_default=EventAttendanceMode.offline, metadata={"description": "Choose how people can attend the event."}, ) status = EnumField( EventStatus, - missing=EventStatus.scheduled, + load_default=EventStatus.scheduled, metadata={"description": "Select the status of the event."}, ) previous_start_date = CustomDateTimeField( @@ -124,13 +124,13 @@ class EventBaseSchemaMixin(TrackableSchemaMixin): }, ) registration_required = marshmallow.auto_field( - missing=False, + load_default=False, metadata={ "description": "If the participants needs to register for the event." }, ) booked_up = marshmallow.auto_field( - missing=False, + load_default=False, metadata={"description": "If the event is booked up or sold out."}, ) expected_participants = marshmallow.auto_field( @@ -143,7 +143,7 @@ class EventBaseSchemaMixin(TrackableSchemaMixin): ) public_status = EnumField( PublicStatus, - missing=PublicStatus.published, + load_default=PublicStatus.published, metadata={"description": "Public status of the event."}, ) @@ -296,8 +296,8 @@ class EventWriteSchemaMixin(object): metadata={"description": "Categories that fit the event."}, ) rating = marshmallow.auto_field( - missing=50, - default=50, + load_default=50, + dump_default=50, validate=validate.OneOf([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]), metadata={ "description": "How relevant the event is to your organization. 0 (Little relevant), 50 (Default), 100 (Highlight)." @@ -322,7 +322,7 @@ class EventPostRequestSchema( date_definitions = fields.List( fields.Nested(EventDateDefinitionPostRequestSchema), - default=None, + dump_default=None, required=True, validate=[validate.Length(min=1)], metadata={"description": "At least one date definition."}, @@ -339,7 +339,7 @@ class EventPatchRequestSchema( date_definitions = fields.List( fields.Nested(EventDateDefinitionPatchRequestSchema), - default=None, + dump_default=None, required=True, validate=[validate.Length(min=1)], metadata={"description": "At least one date definition."}, @@ -370,6 +370,6 @@ class EventImportRequestSchema(marshmallow.Schema): ) public_status = EnumField( PublicStatus, - missing=PublicStatus.published, + load_default=PublicStatus.published, metadata={"description": "Public status of the event."}, ) diff --git a/project/api/event_date_definition/schemas.py b/project/api/event_date_definition/schemas.py index babf320..4bb5da5 100644 --- a/project/api/event_date_definition/schemas.py +++ b/project/api/event_date_definition/schemas.py @@ -36,7 +36,7 @@ class EventDateDefinitionBaseSchemaMixin(object): }, ) allday = fields.Bool( - missing=False, + load_default=False, metadata={"description": "If the event is an all-day event."}, ) recurrence_rule = fields.Str( diff --git a/project/api/schemas.py b/project/api/schemas.py index 042860a..49ddaf3 100644 --- a/project/api/schemas.py +++ b/project/api/schemas.py @@ -25,7 +25,7 @@ class SQLAlchemyBaseSchema(marshmallow.SQLAlchemySchema): class IdSchemaMixin(object): - id = marshmallow.auto_field(dump_only=True, default=missing) + id = marshmallow.auto_field(dump_only=True, dump_default=missing) class WriteIdSchemaMixin(object): @@ -60,13 +60,13 @@ class UnprocessableEntityResponseSchema(ErrorResponseSchema): class PaginationRequestSchema(marshmallow.Schema): page = fields.Integer( required=False, - default=1, + dump_default=1, validate=validate.Range(min=1), metadata={"description": "The page number (1 indexed)."}, ) per_page = fields.Integer( required=False, - default=20, + dump_default=20, validate=validate.Range(min=1, max=50), metadata={"description": "Items per page"}, ) diff --git a/project/cli/test.py b/project/cli/test.py index efb3f42..8fe5e0b 100644 --- a/project/cli/test.py +++ b/project/cli/test.py @@ -4,7 +4,7 @@ import click from flask.cli import AppGroup from flask_migrate import stamp from flask_security.confirmable import confirm_user -from sqlalchemy import MetaData +from sqlalchemy import MetaData, text from project import app, db from project.api import scope_list @@ -75,14 +75,15 @@ def _create_user( @test_cli.command("reset") @click.option("--seed/--no-seed", default=False) def reset(seed): - meta = MetaData(bind=db.engine, reflect=True) + meta = MetaData() + meta.reflect(db.engine) con = db.engine.connect() trans = con.begin() for table in meta.sorted_tables: - con.execute(f'ALTER TABLE "{table.name}" DISABLE TRIGGER ALL;') + con.execute(text(f'ALTER TABLE "{table.name}" DISABLE TRIGGER ALL;')) con.execute(table.delete()) - con.execute(f'ALTER TABLE "{table.name}" ENABLE TRIGGER ALL;') + con.execute(text(f'ALTER TABLE "{table.name}" ENABLE TRIGGER ALL;')) trans.commit() diff --git a/project/forms/security.py b/project/forms/security.py index 7e99da0..eb16e3c 100644 --- a/project/forms/security.py +++ b/project/forms/security.py @@ -35,6 +35,10 @@ class ExtendedConfirmRegisterForm(ConfirmRegisterForm): class ExtendedLoginForm(LoginForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._fields["email"].flags.required = True + def validate(self, **kwargs): result = super().validate(**kwargs) diff --git a/project/forms/widgets.py b/project/forms/widgets.py index a82a439..4f7cb14 100644 --- a/project/forms/widgets.py +++ b/project/forms/widgets.py @@ -26,13 +26,14 @@ class CustomDateTimeWidget: time = date_value.strftime("%H:%M") kwargs_class = kwargs.pop("class", "") + required = True if field.flags.required else False date_class = kwargs_class + " datepicker" date_params = html_params( name=field.name, id=id, value=date, - required=field.flags.required, + required=required, class_=date_class, **kwargs ) @@ -42,7 +43,7 @@ class CustomDateTimeWidget: name=field.name, id=id + "-time", value=time, - required=field.flags.required, + required=required, class_=time_class, **kwargs ) diff --git a/project/imageutils.py b/project/imageutils.py index 182ccda..af98d8b 100644 --- a/project/imageutils.py +++ b/project/imageutils.py @@ -54,14 +54,14 @@ def resize_image_to_min(image: PIL.Image) -> PIL.Image: width = int(math.ceil(image.width * ratio)) height = int(math.ceil(image.height * ratio)) format = image.format - result = image.resize((width, height), PIL.Image.LANCZOS) + result = image.resize((width, height), PIL.Image.Resampling.LANCZOS) result.format = format return result def resize_image_to_max(image: PIL.Image): if image.width > max_image_size or image.height > max_image_size: - image.thumbnail((max_image_size, max_image_size), PIL.Image.ANTIALIAS) + image.thumbnail((max_image_size, max_image_size), PIL.Image.Resampling.LANCZOS) def validate_image(image: PIL.Image):