eventcally/project/api/event/resources.py
2023-05-21 19:05:28 +02:00

204 lines
6.1 KiB
Python

from flask import make_response, request
from flask_apispec import doc, marshal_with, use_kwargs
from sqlalchemy import and_
from sqlalchemy.orm import lazyload, load_only
from project import db
from project.access import (
access_or_401,
can_read_event_or_401,
can_read_private_events,
login_api_user,
login_api_user_or_401,
)
from project.api import add_api_resource, rest_api
from project.api.event.schemas import (
EventListRequestSchema,
EventListResponseSchema,
EventPatchRequestSchema,
EventPostRequestSchema,
EventReportPostSchema,
EventSchema,
EventSearchRequestSchema,
EventSearchResponseSchema,
)
from project.api.event_date.schemas import (
EventDateListRequestSchema,
EventDateListResponseSchema,
)
from project.api.resources import BaseResource, require_api_access
from project.api.schemas import NoneSchema
from project.models import AdminUnit, Event, EventDate, PublicStatus
from project.services.event import (
get_event_with_details_or_404,
get_events_query,
get_significant_event_changes,
update_event,
)
from project.services.event_search import EventSearchParams
from project.views.event import (
send_event_report_mails,
send_referenced_event_changed_mails,
)
def api_can_read_event_or_401(event: Event):
if (
event.public_status != PublicStatus.published
or not event.admin_unit.is_verified
):
login_api_user()
can_read_event_or_401(event)
def api_can_read_private_events(admin_unit: AdminUnit):
login_api_user()
return can_read_private_events(admin_unit)
class EventListResource(BaseResource):
@doc(summary="List events", tags=["Events"])
@use_kwargs(EventListRequestSchema, location=("query"))
@marshal_with(EventListResponseSchema)
@require_api_access()
def get(self, **kwargs):
pagination = (
Event.query.join(Event.admin_unit)
.filter(
and_(
Event.public_status == PublicStatus.published,
AdminUnit.is_verified,
)
)
.paginate()
)
return pagination
class EventResource(BaseResource):
@doc(summary="Get event", tags=["Events"])
@marshal_with(EventSchema)
@require_api_access()
def get(self, id):
login_api_user()
event = get_event_with_details_or_404(id)
api_can_read_event_or_401(event)
return event
@doc(
summary="Update event",
tags=["Events"],
)
@use_kwargs(EventPostRequestSchema, location="json", apply=False)
@marshal_with(None, 204)
@require_api_access("event:write")
def put(self, id):
login_api_user_or_401()
event = Event.query.get_or_404(id)
access_or_401(event.admin_unit, "event:update")
event = self.update_instance(EventPostRequestSchema, instance=event)
update_event(event)
changes = get_significant_event_changes(event)
db.session.commit()
if changes:
send_referenced_event_changed_mails(event)
return make_response("", 204)
@doc(
summary="Patch event",
tags=["Events"],
)
@use_kwargs(EventPatchRequestSchema, location="json", apply=False)
@marshal_with(None, 204)
@require_api_access("event:write")
def patch(self, id):
login_api_user_or_401()
event = Event.query.get_or_404(id)
access_or_401(event.admin_unit, "event:update")
event = self.update_instance(EventPatchRequestSchema, instance=event)
update_event(event)
changes = get_significant_event_changes(event)
db.session.commit()
if changes:
send_referenced_event_changed_mails(event)
return make_response("", 204)
@doc(
summary="Delete event",
tags=["Events"],
)
@marshal_with(None, 204)
@require_api_access("event:write")
def delete(self, id):
login_api_user_or_401()
event = Event.query.get_or_404(id)
access_or_401(event.admin_unit, "event:delete")
db.session.delete(event)
db.session.commit()
return make_response("", 204)
class EventDatesResource(BaseResource):
@doc(summary="List dates for event", tags=["Events", "Event Dates"])
@use_kwargs(EventDateListRequestSchema, location=("query"))
@marshal_with(EventDateListResponseSchema)
@require_api_access()
def get(self, id, **kwargs):
event = Event.query.options(
load_only(Event.id, Event.public_status)
).get_or_404(id)
api_can_read_event_or_401(event)
return (
EventDate.query.options(lazyload(EventDate.event))
.filter(EventDate.event_id == event.id)
.order_by(EventDate.start)
.paginate()
)
class EventSearchResource(BaseResource):
@doc(summary="Search for events", tags=["Events"])
@use_kwargs(EventSearchRequestSchema, location=("query"))
@marshal_with(EventSearchResponseSchema)
@require_api_access()
def get(self, **kwargs):
login_api_user()
params = EventSearchParams()
params.load_from_request()
pagination = get_events_query(params).paginate()
return pagination
class EventReportsResource(BaseResource):
@doc(summary="Add event report", tags=["Events"])
@use_kwargs(EventReportPostSchema, location="json", apply=False)
@marshal_with(NoneSchema, 204)
@require_api_access()
def post(self, id):
event = Event.query.options(
load_only(Event.id, Event.public_status)
).get_or_404(id)
api_can_read_event_or_401(event)
report = EventReportPostSchema().load(request.json)
send_event_report_mails(event, report)
return make_response("", 204)
add_api_resource(EventListResource, "/events", "api_v1_event_list")
add_api_resource(EventResource, "/events/<int:id>", "api_v1_event")
add_api_resource(EventDatesResource, "/events/<int:id>/dates", "api_v1_event_dates")
add_api_resource(EventSearchResource, "/events/search", "api_v1_event_search")
rest_api.add_resource(
EventReportsResource, "/events/<int:id>/reports", endpoint="api_v1_event_reports"
)