2021-02-12 15:43:40 +01:00

278 lines
9.1 KiB
Python

from dateutil.rrule import rrulestr
from marshmallow import ValidationError, fields, validate
from marshmallow_enum import EnumField
from project.api import marshmallow
from project.api.event_category.schemas import (
EventCategoryIdSchema,
EventCategoryRefSchema,
EventCategoryWriteIdSchema,
)
from project.api.fields import CustomDateTimeField
from project.api.image.schemas import ImageSchema
from project.api.organization.schemas import OrganizationRefSchema
from project.api.organizer.schemas import OrganizerRefSchema, OrganizerWriteIdSchema
from project.api.place.schemas import (
PlaceRefSchema,
PlaceSearchItemSchema,
PlaceWriteIdSchema,
)
from project.api.schemas import (
IdSchemaMixin,
PaginationRequestSchema,
PaginationResponseSchema,
SQLAlchemyBaseSchema,
TrackableSchemaMixin,
)
from project.models import (
Event,
EventAttendanceMode,
EventStatus,
EventTargetGroupOrigin,
)
class EventModelSchema(SQLAlchemyBaseSchema):
class Meta:
model = Event
load_instance = True
class EventIdSchema(EventModelSchema, IdSchemaMixin):
pass
def validate_recurrence_rule(recurrence_rule):
try:
rrulestr(recurrence_rule, forceset=True)
except Exception as e:
raise ValidationError(str(e))
class EventBaseSchemaMixin(TrackableSchemaMixin):
name = marshmallow.auto_field(
required=True,
validate=validate.Length(min=3, max=255),
metadata={"description": "A short, meaningful name for the event."},
)
description = marshmallow.auto_field(
metadata={"description": "Description of the event"},
)
external_link = marshmallow.auto_field(
validate=[validate.URL(), validate.Length(max=255)],
metadata={
"description": "A link to an external website containing more information about the event."
},
)
ticket_link = marshmallow.auto_field(
validate=[validate.URL(), validate.Length(max=255)],
metadata={"description": "A link where tickets can be purchased."},
)
tags = marshmallow.auto_field(
metadata={
"description": "Comma separated keywords with which the event should be found. Words do not need to be entered if they are already in the name or description."
}
)
kid_friendly = marshmallow.auto_field(
missing=False,
metadata={"description": "If the event is particularly suitable for children."},
)
accessible_for_free = marshmallow.auto_field(
missing=False,
metadata={"description": "If the event is accessible for free."},
)
age_from = marshmallow.auto_field(
metadata={"description": "The minimum age that participants should be."},
)
age_to = marshmallow.auto_field(
metadata={"description": "The maximum age that participants should be."},
)
target_group_origin = EnumField(
EventTargetGroupOrigin,
missing=EventTargetGroupOrigin.both,
metadata={
"description": "Whether the event is particularly suitable for tourists or residents."
},
)
attendance_mode = EnumField(
EventAttendanceMode,
missing=EventAttendanceMode.offline,
metadata={"description": "Choose how people can attend the event."},
)
status = EnumField(
EventStatus,
missing=EventStatus.scheduled,
metadata={"description": "Select the status of the event."},
)
previous_start_date = CustomDateTimeField(
metadata={
"description": "When the event should have taken place before it was postponed."
},
)
registration_required = marshmallow.auto_field(
missing=False,
metadata={
"description": "If the participants needs to register for the event."
},
)
booked_up = marshmallow.auto_field(
missing=False,
metadata={"description": "If the event is booked up or sold out."},
)
expected_participants = marshmallow.auto_field(
metadata={"description": "The estimated expected attendance."},
)
price_info = marshmallow.auto_field(
metadata={
"description": "Price information in textual form. E.g., different prices for adults and children."
},
)
recurrence_rule = marshmallow.auto_field(
validate=validate_recurrence_rule,
metadata={
"description": "If the event takes place regularly. Format: RFC 5545."
},
)
start = CustomDateTimeField(
required=True,
metadata={
"description": "When the event will take place. If the event takes place regularly, enter when the first date will begin."
},
)
end = CustomDateTimeField(
metadata={
"description": "When the event will end. An event can last a maximum of 24 hours. If the event takes place regularly, enter when the first date will end."
},
)
class EventSchema(EventIdSchema, EventBaseSchemaMixin):
organization = fields.Nested(OrganizationRefSchema, attribute="admin_unit")
organizer = fields.Nested(OrganizerRefSchema)
place = fields.Nested(PlaceRefSchema, attribute="event_place")
photo = fields.Nested(ImageSchema)
categories = fields.List(fields.Nested(EventCategoryRefSchema))
class EventDumpSchema(EventIdSchema, EventBaseSchemaMixin):
organization_id = fields.Int(attribute="admin_unit_id")
organizer_id = fields.Int()
place_id = fields.Int(attribute="event_place_id")
photo_id = fields.Int()
category_ids = fields.Pluck(
EventCategoryIdSchema, "id", many=True, attribute="categories"
)
class EventRefSchema(EventIdSchema):
name = marshmallow.auto_field()
class EventSearchItemSchema(EventRefSchema):
description = marshmallow.auto_field()
start = marshmallow.auto_field()
end = marshmallow.auto_field()
recurrence_rule = marshmallow.auto_field()
photo = fields.Nested(ImageSchema)
place = fields.Nested(PlaceSearchItemSchema, attribute="event_place")
status = EnumField(EventStatus)
booked_up = marshmallow.auto_field()
organizer = fields.Nested(OrganizerRefSchema)
organization = fields.Nested(OrganizationRefSchema, attribute="admin_unit")
categories = fields.List(fields.Nested(EventCategoryRefSchema))
class EventListRequestSchema(PaginationRequestSchema):
pass
class EventListResponseSchema(PaginationResponseSchema):
items = fields.List(
fields.Nested(EventRefSchema), metadata={"description": "Events"}
)
class EventSearchRequestSchema(PaginationRequestSchema):
keyword = fields.Str(
metadata={"description": "Looks for keyword in name, description and tags."},
)
date_from = fields.Date(
metadata={
"description": "Looks for events at or after this date, e.g. 2020-12-31."
},
)
date_to = fields.Date(
metadata={
"description": "Looks for events at or before this date, e.g. 2020-12-31."
},
)
coordinate = fields.Str(
metadata={
"description": 'Looks for events around this coordinate. Expects comma separated latitude and longitude, e.g. "51.9077888,10.4333312". See distance.'
},
)
distance = fields.Int(
validate=validate.Range(min=1, max=100000),
metadata={
"description": "Looks for events around a coordinate within this distance. Expects distance in meters. See coordinate."
},
)
category_id = fields.List(
fields.Int(),
metadata={"description": "Looks for events with this category ids."},
)
weekday = fields.List(
fields.Int(validate=validate.Range(min=0, max=6)),
metadata={
"description": "Looks for events at this weekdays (0=Sunday, 1=Monday, ..)."
},
)
class EventSearchResponseSchema(PaginationResponseSchema):
items = fields.List(
fields.Nested(EventSearchItemSchema), metadata={"description": "Events"}
)
class EventWriteSchemaMixin(object):
organizer = fields.Nested(
OrganizerWriteIdSchema,
required=True,
metadata={"description": "Who is organizing the event."},
)
place = fields.Nested(
PlaceWriteIdSchema,
required=True,
attribute="event_place",
metadata={"description": "Where the event takes place."},
)
categories = fields.List(
fields.Nested(EventCategoryWriteIdSchema),
metadata={"description": "Categories that fit the event."},
)
rating = marshmallow.auto_field(
missing=50,
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), 5 (Default), 10 (Highlight)."
},
)
class EventPostRequestSchema(
EventModelSchema, EventBaseSchemaMixin, EventWriteSchemaMixin
):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.make_post_schema()
class EventPatchRequestSchema(
EventModelSchema, EventBaseSchemaMixin, EventWriteSchemaMixin
):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.make_patch_schema()