mirror of
https://github.com/lucaspalomodevelop/eventcally.git
synced 2026-03-13 00:07:22 +00:00
Merge pull request #56 from DanielGrams/issue/55-dump
Dump data to file #55
This commit is contained in:
commit
1dce5c4f23
@ -23,3 +23,4 @@
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
README.md
|
||||
tmp
|
||||
|
||||
@ -47,6 +47,7 @@ Jobs that should run on a regular basis.
|
||||
|
||||
```sh
|
||||
flask event update-recurring-dates
|
||||
flask dump all
|
||||
```
|
||||
|
||||
## Administration
|
||||
|
||||
@ -15,6 +15,11 @@ from flask_restful import Api
|
||||
from apispec import APISpec
|
||||
from apispec.ext.marshmallow import MarshmallowPlugin
|
||||
from flask_apispec.extension import FlaskApiSpec
|
||||
import pathlib
|
||||
import logging
|
||||
|
||||
logging.basicConfig()
|
||||
logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
|
||||
|
||||
# Create app
|
||||
app = Flask(__name__)
|
||||
@ -39,6 +44,11 @@ app.config["SECURITY_PASSWORD_SALT"] = os.environ.get(
|
||||
"SECURITY_PASSWORD_SALT", "146585145368132386173505678016728509634"
|
||||
)
|
||||
|
||||
# Temporary pathes
|
||||
temp_path = os.path.join(app.root_path, "tmp")
|
||||
dump_path = os.path.join(temp_path, "dump")
|
||||
pathlib.Path(dump_path).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# i18n
|
||||
app.config["BABEL_DEFAULT_LOCALE"] = "de"
|
||||
app.config["BABEL_DEFAULT_TIMEZONE"] = "Europe/Berlin"
|
||||
@ -55,9 +65,12 @@ app.config.update(
|
||||
{
|
||||
"APISPEC_SPEC": APISpec(
|
||||
title="Oveda API",
|
||||
version="1.0.0",
|
||||
version="0.1.0",
|
||||
plugins=[marshmallow_plugin],
|
||||
openapi_version="2.0",
|
||||
info=dict(
|
||||
description="This API provides endpoints to interact with the Oveda data. At the moment, there is no authorization neeeded."
|
||||
),
|
||||
),
|
||||
}
|
||||
)
|
||||
@ -123,6 +136,7 @@ from project.views import (
|
||||
event_date,
|
||||
event_place,
|
||||
event_suggestion,
|
||||
dump,
|
||||
image,
|
||||
manage,
|
||||
organizer,
|
||||
@ -140,6 +154,7 @@ import project.api
|
||||
|
||||
# Command line
|
||||
import project.cli.event
|
||||
import project.cli.dump
|
||||
import project.cli.user
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
from project import rest_api, api_docs
|
||||
|
||||
|
||||
def enum_to_properties(self, field, **kwargs):
|
||||
"""
|
||||
Add an OpenAPI extension for marshmallow_enum.EnumField instances
|
||||
@ -9,6 +12,11 @@ def enum_to_properties(self, field, **kwargs):
|
||||
return {}
|
||||
|
||||
|
||||
def add_api_resource(resource, url, endpoint):
|
||||
rest_api.add_resource(resource, url, endpoint=endpoint)
|
||||
api_docs.register(resource, endpoint=endpoint)
|
||||
|
||||
|
||||
from project import marshmallow_plugin
|
||||
|
||||
marshmallow_plugin.converter.add_attribute_function(enum_to_properties)
|
||||
@ -16,6 +24,8 @@ marshmallow_plugin.converter.add_attribute_function(enum_to_properties)
|
||||
import project.api.event.resources
|
||||
import project.api.event_category.resources
|
||||
import project.api.event_date.resources
|
||||
import project.api.event_reference.resources
|
||||
import project.api.dump.resources
|
||||
import project.api.image.resources
|
||||
import project.api.location.resources
|
||||
import project.api.organization.resources
|
||||
|
||||
0
project/api/dump/__init__.py
Normal file
0
project/api/dump/__init__.py
Normal file
20
project/api/dump/resources.py
Normal file
20
project/api/dump/resources.py
Normal file
@ -0,0 +1,20 @@
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.schemas import NoneSchema
|
||||
from project.api.dump.schemas import DumpResponseSchema
|
||||
|
||||
|
||||
class DumpResource(MethodResource):
|
||||
@doc(
|
||||
summary="Dump model definition",
|
||||
description="Always returns 404 because the endpoint is just for response definition of the dump data file. Go to the developers page to learn how to download the dump data file.",
|
||||
tags=["Dump"],
|
||||
)
|
||||
@marshal_with(NoneSchema, 404)
|
||||
@marshal_with(DumpResponseSchema, 200)
|
||||
def get(self, **kwargs):
|
||||
return None, 404
|
||||
|
||||
|
||||
add_api_resource(DumpResource, "/dump", "api_v1_dump")
|
||||
21
project/api/dump/schemas.py
Normal file
21
project/api/dump/schemas.py
Normal file
@ -0,0 +1,21 @@
|
||||
from project import marshmallow
|
||||
from marshmallow import fields
|
||||
from project.api.event.schemas import EventDumpSchema
|
||||
from project.api.place.schemas import PlaceDumpSchema
|
||||
from project.api.location.schemas import LocationDumpSchema
|
||||
from project.api.event_category.schemas import EventCategoryDumpSchema
|
||||
from project.api.organizer.schemas import OrganizerDumpSchema
|
||||
from project.api.image.schemas import ImageDumpSchema
|
||||
from project.api.organization.schemas import OrganizationDumpSchema
|
||||
from project.api.event_reference.schemas import EventReferenceDumpSchema
|
||||
|
||||
|
||||
class DumpResponseSchema(marshmallow.Schema):
|
||||
events = fields.List(fields.Nested(EventDumpSchema))
|
||||
places = fields.List(fields.Nested(PlaceDumpSchema))
|
||||
locations = fields.List(fields.Nested(LocationDumpSchema))
|
||||
event_categories = fields.List(fields.Nested(EventCategoryDumpSchema))
|
||||
organizers = fields.List(fields.Nested(OrganizerDumpSchema))
|
||||
images = fields.List(fields.Nested(ImageDumpSchema))
|
||||
organizations = fields.List(fields.Nested(OrganizationDumpSchema))
|
||||
event_references = fields.List(fields.Nested(EventReferenceDumpSchema))
|
||||
@ -1,4 +1,4 @@
|
||||
from project import rest_api, api_docs
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc, use_kwargs
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.event.schemas import (
|
||||
@ -18,7 +18,7 @@ from project.services.event_search import EventSearchParams
|
||||
|
||||
|
||||
class EventListResource(MethodResource):
|
||||
@doc(tags=["Events"])
|
||||
@doc(summary="List events", tags=["Events"])
|
||||
@use_kwargs(EventListRequestSchema, location=("query"))
|
||||
@marshal_with(EventListResponseSchema)
|
||||
def get(self, **kwargs):
|
||||
@ -27,14 +27,14 @@ class EventListResource(MethodResource):
|
||||
|
||||
|
||||
class EventResource(MethodResource):
|
||||
@doc(tags=["Events"])
|
||||
@doc(summary="Get event", tags=["Events"])
|
||||
@marshal_with(EventSchema)
|
||||
def get(self, id):
|
||||
return Event.query.get_or_404(id)
|
||||
|
||||
|
||||
class EventDatesResource(MethodResource):
|
||||
@doc(tags=["Events", "Event Dates"])
|
||||
@doc(summary="List dates for event", tags=["Events", "Event Dates"])
|
||||
@use_kwargs(EventDateListRequestSchema, location=("query"))
|
||||
@marshal_with(EventDateListResponseSchema)
|
||||
def get(self, id):
|
||||
@ -43,7 +43,7 @@ class EventDatesResource(MethodResource):
|
||||
|
||||
|
||||
class EventSearchResource(MethodResource):
|
||||
@doc(tags=["Events"])
|
||||
@doc(summary="Search for events", tags=["Events"])
|
||||
@use_kwargs(EventSearchRequestSchema, location=("query"))
|
||||
@marshal_with(EventSearchResponseSchema)
|
||||
def get(self, **kwargs):
|
||||
@ -53,14 +53,7 @@ class EventSearchResource(MethodResource):
|
||||
return pagination
|
||||
|
||||
|
||||
rest_api.add_resource(EventListResource, "/events")
|
||||
api_docs.register(EventListResource)
|
||||
|
||||
rest_api.add_resource(EventResource, "/events/<int:id>")
|
||||
api_docs.register(EventResource)
|
||||
|
||||
rest_api.add_resource(EventDatesResource, "/events/<int:id>/dates")
|
||||
api_docs.register(EventDatesResource)
|
||||
|
||||
rest_api.add_resource(EventSearchResource, "/events/search")
|
||||
api_docs.register(EventSearchResource)
|
||||
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")
|
||||
|
||||
@ -12,26 +12,25 @@ from project.api.organization.schemas import OrganizationRefSchema
|
||||
from project.api.organizer.schemas import OrganizerRefSchema
|
||||
from project.api.image.schemas import ImageRefSchema
|
||||
from project.api.place.schemas import PlaceRefSchema, PlaceSearchItemSchema
|
||||
from project.api.event_category.schemas import EventCategoryRefSchema
|
||||
from project.api.event_category.schemas import (
|
||||
EventCategoryRefSchema,
|
||||
EventCategoryIdSchema,
|
||||
)
|
||||
|
||||
|
||||
class EventSchema(marshmallow.SQLAlchemySchema):
|
||||
class EventBaseSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = Event
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
created_at = marshmallow.auto_field()
|
||||
updated_at = marshmallow.auto_field()
|
||||
organization = fields.Nested(OrganizationRefSchema, attribute="admin_unit")
|
||||
organizer = fields.Nested(OrganizerRefSchema)
|
||||
place = fields.Nested(PlaceRefSchema, attribute="event_place")
|
||||
|
||||
name = marshmallow.auto_field()
|
||||
description = marshmallow.auto_field()
|
||||
external_link = marshmallow.auto_field()
|
||||
ticket_link = marshmallow.auto_field()
|
||||
|
||||
photo = fields.Nested(ImageRefSchema)
|
||||
categories = fields.List(fields.Nested(EventCategoryRefSchema))
|
||||
tags = marshmallow.auto_field()
|
||||
kid_friendly = marshmallow.auto_field()
|
||||
accessible_for_free = marshmallow.auto_field()
|
||||
@ -52,12 +51,29 @@ class EventSchema(marshmallow.SQLAlchemySchema):
|
||||
end = marshmallow.auto_field()
|
||||
|
||||
|
||||
class EventSchema(EventBaseSchema):
|
||||
organization = fields.Nested(OrganizationRefSchema, attribute="admin_unit")
|
||||
organizer = fields.Nested(OrganizerRefSchema)
|
||||
place = fields.Nested(PlaceRefSchema, attribute="event_place")
|
||||
photo = fields.Nested(ImageRefSchema)
|
||||
categories = fields.List(fields.Nested(EventCategoryRefSchema))
|
||||
|
||||
|
||||
class EventDumpSchema(EventBaseSchema):
|
||||
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(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = Event
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
href = marshmallow.URLFor("eventresource", values=dict(id="<id>"))
|
||||
name = marshmallow.auto_field()
|
||||
|
||||
|
||||
@ -73,6 +89,7 @@ class EventSearchItemSchema(EventRefSchema):
|
||||
place = fields.Nested(PlaceSearchItemSchema, attribute="event_place")
|
||||
status = EnumField(EventStatus)
|
||||
organizer = fields.Nested(OrganizerRefSchema)
|
||||
organization = fields.Nested(OrganizationRefSchema, attribute="admin_unit")
|
||||
categories = fields.List(fields.Nested(EventCategoryRefSchema))
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from project import rest_api, api_docs
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc, use_kwargs
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.event_category.schemas import (
|
||||
@ -9,7 +9,7 @@ from project.models import EventCategory
|
||||
|
||||
|
||||
class EventCategoryListResource(MethodResource):
|
||||
@doc(tags=["Event Categories"])
|
||||
@doc(summary="List event categories", tags=["Event Categories"])
|
||||
@use_kwargs(EventCategoryListRequestSchema, location=("query"))
|
||||
@marshal_with(EventCategoryListResponseSchema)
|
||||
def get(self, **kwargs):
|
||||
@ -17,5 +17,6 @@ class EventCategoryListResource(MethodResource):
|
||||
return pagination
|
||||
|
||||
|
||||
rest_api.add_resource(EventCategoryListResource, "/event_categories")
|
||||
api_docs.register(EventCategoryListResource)
|
||||
add_api_resource(
|
||||
EventCategoryListResource, "/event-categories", "api_v1_event_category_list"
|
||||
)
|
||||
|
||||
@ -4,14 +4,21 @@ from project.models import EventCategory
|
||||
from project.api.schemas import PaginationRequestSchema, PaginationResponseSchema
|
||||
|
||||
|
||||
class EventCategoryRefSchema(marshmallow.SQLAlchemySchema):
|
||||
class EventCategoryIdSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = EventCategory
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
|
||||
class EventCategoryRefSchema(EventCategoryIdSchema):
|
||||
name = marshmallow.auto_field()
|
||||
|
||||
|
||||
class EventCategoryDumpSchema(EventCategoryRefSchema):
|
||||
pass
|
||||
|
||||
|
||||
class EventCategoryListRequestSchema(PaginationRequestSchema):
|
||||
pass
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from project import rest_api, api_docs
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc, use_kwargs
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.event_date.schemas import (
|
||||
@ -14,7 +14,7 @@ from project.services.event_search import EventSearchParams
|
||||
|
||||
|
||||
class EventDateListResource(MethodResource):
|
||||
@doc(tags=["Event Dates"])
|
||||
@doc(summary="List event dates", tags=["Event Dates"])
|
||||
@use_kwargs(EventDateListRequestSchema, location=("query"))
|
||||
@marshal_with(EventDateListResponseSchema)
|
||||
def get(self, **kwargs):
|
||||
@ -23,14 +23,14 @@ class EventDateListResource(MethodResource):
|
||||
|
||||
|
||||
class EventDateResource(MethodResource):
|
||||
@doc(tags=["Event Dates"])
|
||||
@doc(summary="Get event date", tags=["Event Dates"])
|
||||
@marshal_with(EventDateSchema)
|
||||
def get(self, id):
|
||||
return EventDate.query.get_or_404(id)
|
||||
|
||||
|
||||
class EventDateSearchResource(MethodResource):
|
||||
@doc(tags=["Event Dates"])
|
||||
@doc(summary="Search for event dates", tags=["Event Dates"])
|
||||
@use_kwargs(EventDateSearchRequestSchema, location=("query"))
|
||||
@marshal_with(EventDateSearchResponseSchema)
|
||||
def get(self, **kwargs):
|
||||
@ -40,11 +40,8 @@ class EventDateSearchResource(MethodResource):
|
||||
return pagination
|
||||
|
||||
|
||||
rest_api.add_resource(EventDateListResource, "/event_dates")
|
||||
api_docs.register(EventDateListResource)
|
||||
|
||||
rest_api.add_resource(EventDateResource, "/event_dates/<int:id>")
|
||||
api_docs.register(EventDateResource)
|
||||
|
||||
rest_api.add_resource(EventDateSearchResource, "/event_dates/search")
|
||||
api_docs.register(EventDateSearchResource)
|
||||
add_api_resource(EventDateListResource, "/event-dates", "api_v1_event_date_list")
|
||||
add_api_resource(EventDateResource, "/event-dates/<int:id>", "api_v1_event_date")
|
||||
add_api_resource(
|
||||
EventDateSearchResource, "/event-dates/search", "api_v1_event_date_search"
|
||||
)
|
||||
|
||||
@ -24,7 +24,6 @@ class EventDateRefSchema(marshmallow.SQLAlchemySchema):
|
||||
model = EventDate
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
href = marshmallow.URLFor("eventdateresource", values=dict(id="<id>"))
|
||||
start = marshmallow.auto_field()
|
||||
|
||||
|
||||
|
||||
0
project/api/event_reference/__init__.py
Normal file
0
project/api/event_reference/__init__.py
Normal file
17
project/api/event_reference/resources.py
Normal file
17
project/api/event_reference/resources.py
Normal file
@ -0,0 +1,17 @@
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.event_reference.schemas import EventReferenceSchema
|
||||
from project.models import EventReference
|
||||
|
||||
|
||||
class EventReferenceResource(MethodResource):
|
||||
@doc(summary="Get event reference", tags=["Event References"])
|
||||
@marshal_with(EventReferenceSchema)
|
||||
def get(self, id):
|
||||
return EventReference.query.get_or_404(id)
|
||||
|
||||
|
||||
add_api_resource(
|
||||
EventReferenceResource, "/event-references/<int:id>", "api_v1_event_reference"
|
||||
)
|
||||
38
project/api/event_reference/schemas.py
Normal file
38
project/api/event_reference/schemas.py
Normal file
@ -0,0 +1,38 @@
|
||||
from marshmallow import fields
|
||||
from project import marshmallow
|
||||
from project.models import EventReference
|
||||
from project.api.schemas import PaginationRequestSchema, PaginationResponseSchema
|
||||
from project.api.event.schemas import EventRefSchema
|
||||
from project.api.organization.schemas import OrganizationRefSchema
|
||||
|
||||
|
||||
class EventReferenceIdSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = EventReference
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
|
||||
class EventReferenceRefSchema(EventReferenceIdSchema):
|
||||
event = fields.Nested(EventRefSchema)
|
||||
|
||||
|
||||
class EventReferenceSchema(EventReferenceIdSchema):
|
||||
event = fields.Nested(EventRefSchema)
|
||||
organization = fields.Nested(OrganizationRefSchema, attribute="admin_unit")
|
||||
|
||||
|
||||
class EventReferenceDumpSchema(EventReferenceIdSchema):
|
||||
event_id = marshmallow.auto_field()
|
||||
organization_id = fields.Int(attribute="admin_unit_id")
|
||||
|
||||
|
||||
class EventReferenceListRequestSchema(PaginationRequestSchema):
|
||||
pass
|
||||
|
||||
|
||||
class EventReferenceListResponseSchema(PaginationResponseSchema):
|
||||
items = fields.List(
|
||||
fields.Nested(EventReferenceRefSchema),
|
||||
metadata={"description": "Event references"},
|
||||
)
|
||||
@ -1,16 +1,15 @@
|
||||
from project import rest_api, api_docs
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.image.schemas import ImageSchema
|
||||
from project.models import AdminUnit
|
||||
from project.models import Image
|
||||
|
||||
|
||||
class ImageResource(MethodResource):
|
||||
@doc(tags=["Images"])
|
||||
@doc(summary="Get image", tags=["Images"])
|
||||
@marshal_with(ImageSchema)
|
||||
def get(self, id):
|
||||
return AdminUnit.query.get_or_404(id)
|
||||
return Image.query.get_or_404(id)
|
||||
|
||||
|
||||
rest_api.add_resource(ImageResource, "/images/<int:id>")
|
||||
api_docs.register(ImageResource)
|
||||
add_api_resource(ImageResource, "/images/<int:id>", "api_v1_image")
|
||||
|
||||
@ -2,24 +2,26 @@ from project import marshmallow
|
||||
from project.models import Image
|
||||
|
||||
|
||||
class ImageSchema(marshmallow.SQLAlchemySchema):
|
||||
class ImageIdSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = Image
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
|
||||
class ImageBaseSchema(ImageIdSchema):
|
||||
created_at = marshmallow.auto_field()
|
||||
updated_at = marshmallow.auto_field()
|
||||
image_url = marshmallow.URLFor("image", values=dict(id="<id>"))
|
||||
copyright_text = marshmallow.auto_field()
|
||||
|
||||
|
||||
class ImageRefSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = Image
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
class ImageSchema(ImageBaseSchema):
|
||||
image_url = marshmallow.URLFor("image", values=dict(id="<id>"))
|
||||
|
||||
|
||||
class ImageDumpSchema(ImageBaseSchema):
|
||||
pass
|
||||
|
||||
|
||||
class ImageRefSchema(ImageIdSchema):
|
||||
image_url = marshmallow.URLFor("image", values=dict(id="<id>"))
|
||||
href = marshmallow.URLFor(
|
||||
"imageresource",
|
||||
values=dict(id="<id>"),
|
||||
)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from project import rest_api, api_docs
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.location.schemas import LocationSchema
|
||||
@ -6,11 +6,10 @@ from project.models import Location
|
||||
|
||||
|
||||
class LocationResource(MethodResource):
|
||||
@doc(tags=["Locations"])
|
||||
@doc(summary="Get location", tags=["Locations"])
|
||||
@marshal_with(LocationSchema)
|
||||
def get(self, id):
|
||||
return Location.query.get_or_404(id)
|
||||
|
||||
|
||||
rest_api.add_resource(LocationResource, "/locations/<int:id>")
|
||||
api_docs.register(LocationResource)
|
||||
add_api_resource(LocationResource, "/locations/<int:id>", "api_v1_location")
|
||||
|
||||
@ -3,11 +3,14 @@ from project import marshmallow
|
||||
from project.models import Location
|
||||
|
||||
|
||||
class LocationSchema(marshmallow.SQLAlchemySchema):
|
||||
class LocationIdSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = Location
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
|
||||
class LocationSchema(LocationIdSchema):
|
||||
created_at = marshmallow.auto_field()
|
||||
updated_at = marshmallow.auto_field()
|
||||
street = marshmallow.auto_field()
|
||||
@ -19,15 +22,12 @@ class LocationSchema(marshmallow.SQLAlchemySchema):
|
||||
latitude = fields.Str()
|
||||
|
||||
|
||||
class LocationRefSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = Location
|
||||
class LocationDumpSchema(LocationSchema):
|
||||
pass
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
href = marshmallow.URLFor(
|
||||
"locationresource",
|
||||
values=dict(id="<id>"),
|
||||
)
|
||||
|
||||
class LocationRefSchema(LocationIdSchema):
|
||||
pass
|
||||
|
||||
|
||||
class LocationSearchItemSchema(LocationRefSchema):
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from project import rest_api, api_docs
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc, use_kwargs
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.organization.schemas import (
|
||||
@ -19,6 +19,14 @@ from project.api.organizer.schemas import (
|
||||
OrganizerListRequestSchema,
|
||||
OrganizerListResponseSchema,
|
||||
)
|
||||
from project.api.event_reference.schemas import (
|
||||
EventReferenceListRequestSchema,
|
||||
EventReferenceListResponseSchema,
|
||||
)
|
||||
from project.services.reference import (
|
||||
get_reference_incoming_query,
|
||||
get_reference_outgoing_query,
|
||||
)
|
||||
from project.api.place.schemas import PlaceListRequestSchema, PlaceListResponseSchema
|
||||
from project.services.event import get_event_dates_query, get_events_query
|
||||
from project.services.event_search import EventSearchParams
|
||||
@ -30,21 +38,18 @@ from project.services.admin_unit import (
|
||||
|
||||
|
||||
class OrganizationResource(MethodResource):
|
||||
@doc(tags=["Organizations"])
|
||||
@doc(summary="Get organization", tags=["Organizations"])
|
||||
@marshal_with(OrganizationSchema)
|
||||
def get(self, id):
|
||||
return AdminUnit.query.get_or_404(id)
|
||||
|
||||
|
||||
class OrganizationByShortNameResource(MethodResource):
|
||||
@doc(tags=["Organizations"])
|
||||
@marshal_with(OrganizationSchema)
|
||||
def get(self, short_name):
|
||||
return AdminUnit.query.filter(AdminUnit.short_name == short_name).first_or_404()
|
||||
|
||||
|
||||
class OrganizationEventDateSearchResource(MethodResource):
|
||||
@doc(tags=["Organizations", "Event Dates"])
|
||||
@doc(
|
||||
summary="Search for event dates of organization",
|
||||
description="Includes events that organization is referencing.",
|
||||
tags=["Organizations", "Event Dates"],
|
||||
)
|
||||
@use_kwargs(EventDateSearchRequestSchema, location=("query"))
|
||||
@marshal_with(EventDateSearchResponseSchema)
|
||||
def get(self, id, **kwargs):
|
||||
@ -59,7 +64,7 @@ class OrganizationEventDateSearchResource(MethodResource):
|
||||
|
||||
|
||||
class OrganizationEventSearchResource(MethodResource):
|
||||
@doc(tags=["Organizations", "Events"])
|
||||
@doc(summary="Search for events of organization", tags=["Organizations", "Events"])
|
||||
@use_kwargs(EventSearchRequestSchema, location=("query"))
|
||||
@marshal_with(EventSearchResponseSchema)
|
||||
def get(self, id, **kwargs):
|
||||
@ -74,7 +79,7 @@ class OrganizationEventSearchResource(MethodResource):
|
||||
|
||||
|
||||
class OrganizationListResource(MethodResource):
|
||||
@doc(tags=["Organizations"])
|
||||
@doc(summary="List organizations", tags=["Organizations"])
|
||||
@use_kwargs(OrganizationListRequestSchema, location=("query"))
|
||||
@marshal_with(OrganizationListResponseSchema)
|
||||
def get(self, **kwargs):
|
||||
@ -84,7 +89,9 @@ class OrganizationListResource(MethodResource):
|
||||
|
||||
|
||||
class OrganizationOrganizerListResource(MethodResource):
|
||||
@doc(tags=["Organizations", "Organizers"])
|
||||
@doc(
|
||||
summary="List organizers of organization", tags=["Organizations", "Organizers"]
|
||||
)
|
||||
@use_kwargs(OrganizerListRequestSchema, location=("query"))
|
||||
@marshal_with(OrganizerListResponseSchema)
|
||||
def get(self, id, **kwargs):
|
||||
@ -96,7 +103,7 @@ class OrganizationOrganizerListResource(MethodResource):
|
||||
|
||||
|
||||
class OrganizationPlaceListResource(MethodResource):
|
||||
@doc(tags=["Organizations", "Places"])
|
||||
@doc(summary="List places of organization", tags=["Organizations", "Places"])
|
||||
@use_kwargs(PlaceListRequestSchema, location=("query"))
|
||||
@marshal_with(PlaceListResponseSchema)
|
||||
def get(self, id, **kwargs):
|
||||
@ -107,35 +114,63 @@ class OrganizationPlaceListResource(MethodResource):
|
||||
return pagination
|
||||
|
||||
|
||||
rest_api.add_resource(OrganizationResource, "/organizations/<int:id>")
|
||||
api_docs.register(OrganizationResource)
|
||||
class OrganizationIncomingEventReferenceListResource(MethodResource):
|
||||
@doc(
|
||||
summary="List incoming event references of organization",
|
||||
tags=["Organizations", "Event References"],
|
||||
)
|
||||
@use_kwargs(EventReferenceListRequestSchema, location=("query"))
|
||||
@marshal_with(EventReferenceListResponseSchema)
|
||||
def get(self, id, **kwargs):
|
||||
admin_unit = AdminUnit.query.get_or_404(id)
|
||||
|
||||
rest_api.add_resource(
|
||||
OrganizationByShortNameResource, "/organizations/<string:short_name>"
|
||||
)
|
||||
api_docs.register(OrganizationByShortNameResource)
|
||||
pagination = get_reference_incoming_query(admin_unit).paginate()
|
||||
return pagination
|
||||
|
||||
rest_api.add_resource(
|
||||
|
||||
class OrganizationOutgoingEventReferenceListResource(MethodResource):
|
||||
@doc(
|
||||
summary="List outgoing event references of organization",
|
||||
tags=["Organizations", "Event References"],
|
||||
)
|
||||
@use_kwargs(EventReferenceListRequestSchema, location=("query"))
|
||||
@marshal_with(EventReferenceListResponseSchema)
|
||||
def get(self, id, **kwargs):
|
||||
admin_unit = AdminUnit.query.get_or_404(id)
|
||||
|
||||
pagination = get_reference_outgoing_query(admin_unit).paginate()
|
||||
return pagination
|
||||
|
||||
|
||||
add_api_resource(OrganizationResource, "/organizations/<int:id>", "api_v1_organization")
|
||||
add_api_resource(
|
||||
OrganizationEventDateSearchResource,
|
||||
"/organizations/<int:id>/event_dates/search",
|
||||
"/organizations/<int:id>/event-dates/search",
|
||||
"api_v1_organization_event_date_search",
|
||||
)
|
||||
api_docs.register(OrganizationEventDateSearchResource)
|
||||
|
||||
rest_api.add_resource(
|
||||
OrganizationEventSearchResource, "/organizations/<int:id>/events/search"
|
||||
add_api_resource(
|
||||
OrganizationEventSearchResource,
|
||||
"/organizations/<int:id>/events/search",
|
||||
"api_v1_organization_event_search",
|
||||
)
|
||||
api_docs.register(OrganizationEventSearchResource)
|
||||
|
||||
rest_api.add_resource(OrganizationListResource, "/organizations")
|
||||
api_docs.register(OrganizationListResource)
|
||||
|
||||
rest_api.add_resource(
|
||||
OrganizationOrganizerListResource, "/organizations/<int:id>/organizers"
|
||||
add_api_resource(OrganizationListResource, "/organizations", "api_v1_organization_list")
|
||||
add_api_resource(
|
||||
OrganizationOrganizerListResource,
|
||||
"/organizations/<int:id>/organizers",
|
||||
"api_v1_organization_organizer_list",
|
||||
)
|
||||
api_docs.register(OrganizationOrganizerListResource)
|
||||
|
||||
rest_api.add_resource(
|
||||
add_api_resource(
|
||||
OrganizationPlaceListResource,
|
||||
"/organizations/<int:id>/places",
|
||||
"api_v1_organization_place_list",
|
||||
)
|
||||
add_api_resource(
|
||||
OrganizationIncomingEventReferenceListResource,
|
||||
"/organizations/<int:id>/event-references/incoming",
|
||||
"api_v1_organization_incoming_event_reference_list",
|
||||
)
|
||||
add_api_resource(
|
||||
OrganizationOutgoingEventReferenceListResource,
|
||||
"/organizations/<int:id>/event-references/outgoing",
|
||||
"api_v1_organization_outgoing_event_reference_list",
|
||||
)
|
||||
api_docs.register(OrganizationPlaceListResource)
|
||||
|
||||
@ -6,30 +6,36 @@ from project.api.image.schemas import ImageRefSchema
|
||||
from project.api.schemas import PaginationRequestSchema, PaginationResponseSchema
|
||||
|
||||
|
||||
class OrganizationSchema(marshmallow.SQLAlchemySchema):
|
||||
class OrganizationIdSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = AdminUnit
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
|
||||
class OrganizationBaseSchema(OrganizationIdSchema):
|
||||
created_at = marshmallow.auto_field()
|
||||
updated_at = marshmallow.auto_field()
|
||||
name = marshmallow.auto_field()
|
||||
short_name = marshmallow.auto_field()
|
||||
location = fields.Nested(LocationRefSchema)
|
||||
logo = fields.Nested(ImageRefSchema)
|
||||
url = marshmallow.auto_field()
|
||||
email = marshmallow.auto_field()
|
||||
phone = marshmallow.auto_field()
|
||||
fax = marshmallow.auto_field()
|
||||
|
||||
|
||||
class OrganizationRefSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = AdminUnit
|
||||
class OrganizationSchema(OrganizationBaseSchema):
|
||||
location = fields.Nested(LocationRefSchema)
|
||||
logo = fields.Nested(ImageRefSchema)
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
class OrganizationDumpSchema(OrganizationBaseSchema):
|
||||
location_id = fields.Int()
|
||||
logo_id = fields.Int()
|
||||
|
||||
|
||||
class OrganizationRefSchema(OrganizationIdSchema):
|
||||
name = marshmallow.auto_field()
|
||||
href = marshmallow.URLFor("organizationresource", values=dict(id="<id>"))
|
||||
|
||||
|
||||
class OrganizationListRefSchema(OrganizationRefSchema):
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from project import rest_api, api_docs
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.organizer.schemas import OrganizerSchema
|
||||
@ -6,14 +6,14 @@ from project.models import EventOrganizer
|
||||
|
||||
|
||||
class OrganizerResource(MethodResource):
|
||||
@doc(tags=["Organizers"])
|
||||
@doc(summary="Get organizer", tags=["Organizers"])
|
||||
@marshal_with(OrganizerSchema)
|
||||
def get(self, id):
|
||||
return EventOrganizer.query.get_or_404(id)
|
||||
|
||||
|
||||
rest_api.add_resource(
|
||||
add_api_resource(
|
||||
OrganizerResource,
|
||||
"/organizers/<int:id>",
|
||||
"api_v1_organizer",
|
||||
)
|
||||
api_docs.register(OrganizerResource)
|
||||
|
||||
@ -7,11 +7,14 @@ from project.api.organization.schemas import OrganizationRefSchema
|
||||
from project.api.schemas import PaginationRequestSchema, PaginationResponseSchema
|
||||
|
||||
|
||||
class OrganizerSchema(marshmallow.SQLAlchemySchema):
|
||||
class OrganizerIdSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = EventOrganizer
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
|
||||
class OrganizerBaseSchema(OrganizerIdSchema):
|
||||
created_at = marshmallow.auto_field()
|
||||
updated_at = marshmallow.auto_field()
|
||||
name = marshmallow.auto_field()
|
||||
@ -19,21 +22,22 @@ class OrganizerSchema(marshmallow.SQLAlchemySchema):
|
||||
email = marshmallow.auto_field()
|
||||
phone = marshmallow.auto_field()
|
||||
fax = marshmallow.auto_field()
|
||||
|
||||
|
||||
class OrganizerSchema(OrganizerBaseSchema):
|
||||
location = fields.Nested(LocationRefSchema)
|
||||
logo = fields.Nested(ImageRefSchema)
|
||||
organization = fields.Nested(OrganizationRefSchema, attribute="adminunit")
|
||||
|
||||
|
||||
class OrganizerRefSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = EventOrganizer
|
||||
class OrganizerDumpSchema(OrganizerBaseSchema):
|
||||
location_id = fields.Int()
|
||||
logo_id = fields.Int()
|
||||
organization_id = fields.Int(attribute="admin_unit_id")
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
class OrganizerRefSchema(OrganizerIdSchema):
|
||||
name = marshmallow.auto_field()
|
||||
href = marshmallow.URLFor(
|
||||
"organizerresource",
|
||||
values=dict(id="<id>"),
|
||||
)
|
||||
|
||||
|
||||
class OrganizerListRequestSchema(PaginationRequestSchema):
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from project import rest_api, api_docs
|
||||
from project.api import add_api_resource
|
||||
from flask_apispec import marshal_with, doc
|
||||
from flask_apispec.views import MethodResource
|
||||
from project.api.place.schemas import PlaceSchema
|
||||
@ -6,14 +6,10 @@ from project.models import EventPlace
|
||||
|
||||
|
||||
class PlaceResource(MethodResource):
|
||||
@doc(tags=["Places"])
|
||||
@doc(summary="Get place", tags=["Places"])
|
||||
@marshal_with(PlaceSchema)
|
||||
def get(self, id):
|
||||
return EventPlace.query.get_or_404(id)
|
||||
|
||||
|
||||
rest_api.add_resource(
|
||||
PlaceResource,
|
||||
"/places/<int:id>",
|
||||
)
|
||||
api_docs.register(PlaceResource)
|
||||
add_api_resource(PlaceResource, "/places/<int:id>", "api_v1_place")
|
||||
|
||||
@ -7,31 +7,35 @@ from project.api.organization.schemas import OrganizationRefSchema
|
||||
from project.api.schemas import PaginationRequestSchema, PaginationResponseSchema
|
||||
|
||||
|
||||
class PlaceSchema(marshmallow.SQLAlchemySchema):
|
||||
class PlaceIdSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = EventPlace
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
|
||||
class PlaceBaseSchema(PlaceIdSchema):
|
||||
created_at = marshmallow.auto_field()
|
||||
updated_at = marshmallow.auto_field()
|
||||
name = marshmallow.auto_field()
|
||||
location = fields.Nested(LocationRefSchema)
|
||||
photo = fields.Nested(ImageRefSchema)
|
||||
url = marshmallow.auto_field()
|
||||
description = marshmallow.auto_field()
|
||||
|
||||
|
||||
class PlaceSchema(PlaceBaseSchema):
|
||||
location = fields.Nested(LocationRefSchema)
|
||||
photo = fields.Nested(ImageRefSchema)
|
||||
organization = fields.Nested(OrganizationRefSchema, attribute="adminunit")
|
||||
|
||||
|
||||
class PlaceRefSchema(marshmallow.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = EventPlace
|
||||
class PlaceDumpSchema(PlaceBaseSchema):
|
||||
location_id = fields.Int()
|
||||
photo_id = fields.Int()
|
||||
organization_id = fields.Int(attribute="admin_unit_id")
|
||||
|
||||
id = marshmallow.auto_field()
|
||||
|
||||
class PlaceRefSchema(PlaceIdSchema):
|
||||
name = marshmallow.auto_field()
|
||||
href = marshmallow.URLFor(
|
||||
"placeresource",
|
||||
values=dict(id="<id>"),
|
||||
)
|
||||
|
||||
|
||||
class PlaceSearchItemSchema(PlaceRefSchema):
|
||||
|
||||
@ -41,3 +41,7 @@ class PaginationResponseSchema(marshmallow.Schema):
|
||||
required=True,
|
||||
metadata={"description": "The total number of items matching the query"},
|
||||
)
|
||||
|
||||
|
||||
class NoneSchema(marshmallow.Schema):
|
||||
pass
|
||||
|
||||
100
project/cli/dump.py
Normal file
100
project/cli/dump.py
Normal file
@ -0,0 +1,100 @@
|
||||
import click
|
||||
from flask.cli import AppGroup
|
||||
from project import app, dump_path
|
||||
from project.models import (
|
||||
Event,
|
||||
EventPlace,
|
||||
EventReference,
|
||||
Location,
|
||||
EventCategory,
|
||||
EventOrganizer,
|
||||
Image,
|
||||
AdminUnit,
|
||||
)
|
||||
from sqlalchemy.orm import joinedload
|
||||
import json
|
||||
from project.api.event.schemas import EventDumpSchema
|
||||
from project.api.place.schemas import PlaceDumpSchema
|
||||
from project.api.location.schemas import LocationDumpSchema
|
||||
from project.api.event_category.schemas import EventCategoryDumpSchema
|
||||
from project.api.organizer.schemas import OrganizerDumpSchema
|
||||
from project.api.image.schemas import ImageDumpSchema
|
||||
from project.api.organization.schemas import OrganizationDumpSchema
|
||||
from project.api.event_reference.schemas import EventReferenceDumpSchema
|
||||
import os.path
|
||||
import shutil
|
||||
import pathlib
|
||||
|
||||
dump_cli = AppGroup("dump")
|
||||
|
||||
|
||||
def dump_items(items, schema, file_base_name, dump_path):
|
||||
result = schema.dump(items)
|
||||
path = os.path.join(dump_path, file_base_name + ".json")
|
||||
|
||||
with open(path, "w") as outfile:
|
||||
json.dump(result, outfile, ensure_ascii=False)
|
||||
|
||||
click.echo(f"{len(items)} item(s) dumped to {path}.")
|
||||
|
||||
|
||||
@dump_cli.command("all")
|
||||
def dump_all():
|
||||
# Setup temp dir
|
||||
tmp_path = os.path.join(dump_path, "tmp")
|
||||
pathlib.Path(tmp_path).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Events
|
||||
events = Event.query.options(joinedload(Event.categories)).all()
|
||||
dump_items(events, EventDumpSchema(many=True), "events", tmp_path)
|
||||
|
||||
# Places
|
||||
places = EventPlace.query.all()
|
||||
dump_items(places, PlaceDumpSchema(many=True), "places", tmp_path)
|
||||
|
||||
# Locations
|
||||
locations = Location.query.all()
|
||||
dump_items(locations, LocationDumpSchema(many=True), "locations", tmp_path)
|
||||
|
||||
# Event categories
|
||||
event_categories = EventCategory.query.all()
|
||||
dump_items(
|
||||
event_categories,
|
||||
EventCategoryDumpSchema(many=True),
|
||||
"event_categories",
|
||||
tmp_path,
|
||||
)
|
||||
|
||||
# Organizers
|
||||
organizers = EventOrganizer.query.all()
|
||||
dump_items(organizers, OrganizerDumpSchema(many=True), "organizers", tmp_path)
|
||||
|
||||
# Images
|
||||
images = Image.query.all()
|
||||
dump_items(images, ImageDumpSchema(many=True), "images", tmp_path)
|
||||
|
||||
# Organizations
|
||||
organizations = AdminUnit.query.all()
|
||||
dump_items(
|
||||
organizations, OrganizationDumpSchema(many=True), "organizations", tmp_path
|
||||
)
|
||||
|
||||
# Event references
|
||||
event_references = EventReference.query.all()
|
||||
dump_items(
|
||||
event_references,
|
||||
EventReferenceDumpSchema(many=True),
|
||||
"event_references",
|
||||
tmp_path,
|
||||
)
|
||||
|
||||
# Zip
|
||||
zip_base_name = os.path.join(dump_path, "all")
|
||||
zip_path = shutil.make_archive(zip_base_name, "zip", tmp_path)
|
||||
click.echo(f"Zipped all up to {zip_path}.")
|
||||
|
||||
# Clean up temp dir
|
||||
shutil.rmtree(tmp_path, ignore_errors=True)
|
||||
|
||||
|
||||
app.cli.add_command(dump_cli)
|
||||
@ -1,10 +1,13 @@
|
||||
from project import db
|
||||
from project.models import (
|
||||
AdminUnit,
|
||||
EventCategory,
|
||||
Event,
|
||||
EventDate,
|
||||
EventOrganizer,
|
||||
EventReference,
|
||||
EventPlace,
|
||||
Image,
|
||||
Location,
|
||||
)
|
||||
from project.dateutils import (
|
||||
@ -14,6 +17,7 @@ from project.dateutils import (
|
||||
)
|
||||
from sqlalchemy import and_, or_, func
|
||||
from sqlalchemy.sql import extract
|
||||
from sqlalchemy.orm import joinedload, contains_eager
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
|
||||
@ -89,9 +93,24 @@ def get_event_dates_query(params):
|
||||
date_filter = and_(date_filter, extract("dow", EventDate.start).in_(weekdays))
|
||||
|
||||
return (
|
||||
EventDate.query.join(Event)
|
||||
.join(EventPlace, isouter=True)
|
||||
.join(Location, isouter=True)
|
||||
EventDate.query.join(EventDate.event)
|
||||
.join(Event.event_place, isouter=True)
|
||||
.join(EventPlace.location, isouter=True)
|
||||
.options(
|
||||
contains_eager(EventDate.event)
|
||||
.contains_eager(Event.event_place)
|
||||
.contains_eager(EventPlace.location),
|
||||
joinedload(EventDate.event)
|
||||
.joinedload(Event.categories)
|
||||
.load_only(EventCategory.id, EventCategory.name),
|
||||
joinedload(EventDate.event)
|
||||
.joinedload(Event.organizer)
|
||||
.load_only(EventOrganizer.id, EventOrganizer.name),
|
||||
joinedload(EventDate.event).joinedload(Event.photo).load_only(Image.id),
|
||||
joinedload(EventDate.event)
|
||||
.joinedload(Event.admin_unit)
|
||||
.load_only(AdminUnit.id, AdminUnit.name),
|
||||
)
|
||||
.filter(date_filter)
|
||||
.filter(event_filter)
|
||||
.order_by(EventDate.start)
|
||||
@ -117,6 +136,13 @@ def get_events_query(params):
|
||||
return (
|
||||
Event.query.join(EventPlace, isouter=True)
|
||||
.join(Location, isouter=True)
|
||||
.options(
|
||||
contains_eager(Event.event_place).contains_eager(EventPlace.location),
|
||||
joinedload(Event.categories),
|
||||
joinedload(Event.organizer),
|
||||
joinedload(Event.photo),
|
||||
joinedload(Event.admin_unit),
|
||||
)
|
||||
.filter(event_filter)
|
||||
.order_by(Event.start)
|
||||
)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from project import db
|
||||
from project.models import (
|
||||
Event,
|
||||
EventReference,
|
||||
EventReferenceRequest,
|
||||
EventReferenceRequestReviewStatus,
|
||||
@ -24,6 +25,14 @@ def create_event_reference_for_request(request):
|
||||
return result
|
||||
|
||||
|
||||
def get_reference_incoming_query(admin_unit):
|
||||
return EventReference.query.filter(EventReference.admin_unit_id == admin_unit.id)
|
||||
|
||||
|
||||
def get_reference_outgoing_query(admin_unit):
|
||||
return EventReference.query.join(Event).filter(Event.admin_unit_id == admin_unit.id)
|
||||
|
||||
|
||||
def get_reference_requests_incoming_query(admin_unit):
|
||||
return EventReferenceRequest.query.filter(
|
||||
and_(
|
||||
|
||||
@ -7,18 +7,21 @@
|
||||
|
||||
<h1>Developer</h1>
|
||||
|
||||
<h2>Endpoint for all events</h2>
|
||||
<input class="form-control" value="{{ url_for('api_events', _external=True) }}" />
|
||||
<p><a class="btn btn-outline-info my-2" href="{{ url_for('api_events', _external=True) }}" target="_blank">Open <i class="fa fa-external-link-alt"></i></a></p>
|
||||
|
||||
<h2>Endpoint to search events</h2>
|
||||
{% set search_url = url_for('api_event_dates', page='1', per_page='10', coordinate='51.9077888,10.4333312', distance='1000', date_from='2020-10-03', date_to='2021-10-03', keyword='stadtrundgang', _external=True) %}
|
||||
<input class="form-control" value="{{ search_url }}" />
|
||||
<p><a class="btn btn-outline-info my-2" href="{{ search_url }}" target="_blank">Open <i class="fa fa-external-link-alt"></i></a></p>
|
||||
|
||||
<h2>Documentation</h2>
|
||||
<h2>API</h2>
|
||||
<ul>
|
||||
<li>Format: <a href="https://schema.org/Project" target="_blank">https://schema.org/Project</a></li>
|
||||
<li>Documentation: <a href="/swagger-ui" target="_blank">Swagger/OpenAPI</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Data download</h2>
|
||||
<ul>
|
||||
<li>
|
||||
{% if dump_file %}
|
||||
<a href="{{ dump_file.url }}">Dump of all data</a> <span class="badge badge-pill badge-light">{{ dump_file.ctime | datetimeformat }}</span> <span class="badge badge-pill badge-light">{{ dump_file.size }} Bytes</span>
|
||||
{% else %}
|
||||
No files available
|
||||
{% endif %}
|
||||
</li>
|
||||
<li>The data file format is part of the <a href="/swagger-ui" target="_blank">API spec</a>. Watch for the <code>*Dump</code> models.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
@ -130,7 +130,7 @@
|
||||
req_data += '&page=' + page + '&per_page=' + per_page;
|
||||
|
||||
$.ajax({
|
||||
url: "{{ url_for('eventdatesearchresource') }}",
|
||||
url: "{{ url_for('api_v1_event_date_search') }}",
|
||||
type: "get",
|
||||
dataType: "json",
|
||||
data: req_data,
|
||||
|
||||
@ -19,7 +19,7 @@ $( function() {
|
||||
tbody.empty();
|
||||
|
||||
$.ajax({
|
||||
url: "{{ url_for('eventdatesearchresource', per_page=max_events) }}",
|
||||
url: "{{ url_for('api_v1_event_date_search', per_page=max_events) }}",
|
||||
type: "get",
|
||||
dataType: "json",
|
||||
data: $(this).serialize(),
|
||||
|
||||
7
project/views/dump.py
Normal file
7
project/views/dump.py
Normal file
@ -0,0 +1,7 @@
|
||||
from project import app, dump_path
|
||||
from flask import send_from_directory
|
||||
|
||||
|
||||
@app.route("/dump/<path:path>")
|
||||
def dump_files(path):
|
||||
return send_from_directory(dump_path, path)
|
||||
@ -9,6 +9,10 @@ from project.forms.reference import (
|
||||
UpdateEventReferenceForm,
|
||||
DeleteReferenceForm,
|
||||
)
|
||||
from project.services.reference import (
|
||||
get_reference_incoming_query,
|
||||
get_reference_outgoing_query,
|
||||
)
|
||||
from flask import render_template, flash, redirect, url_for, abort
|
||||
from flask_babelex import gettext
|
||||
from flask_security import auth_required
|
||||
@ -86,7 +90,7 @@ def event_reference_update(id):
|
||||
def manage_admin_unit_references_incoming(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
references = (
|
||||
EventReference.query.filter(EventReference.admin_unit_id == admin_unit.id)
|
||||
get_reference_incoming_query(admin_unit)
|
||||
.order_by(desc(EventReference.created_at))
|
||||
.paginate()
|
||||
)
|
||||
@ -104,8 +108,7 @@ def manage_admin_unit_references_incoming(id):
|
||||
def manage_admin_unit_references_outgoing(id):
|
||||
admin_unit = get_admin_unit_for_manage_or_404(id)
|
||||
references = (
|
||||
EventReference.query.join(Event)
|
||||
.filter(Event.admin_unit_id == admin_unit.id)
|
||||
get_reference_outgoing_query(admin_unit)
|
||||
.order_by(desc(EventReference.created_at))
|
||||
.paginate()
|
||||
)
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
from project import app
|
||||
from project import app, dump_path
|
||||
from project.services.admin import upsert_settings
|
||||
from project.views.utils import track_analytics
|
||||
from flask import url_for, render_template, request, redirect
|
||||
from flask_babelex import gettext
|
||||
from markupsafe import Markup
|
||||
import os.path
|
||||
|
||||
|
||||
@app.route("/")
|
||||
@ -54,4 +55,15 @@ def privacy():
|
||||
|
||||
@app.route("/developer")
|
||||
def developer():
|
||||
return render_template("developer/read.html")
|
||||
file_name = "all.zip"
|
||||
all_path = os.path.join(dump_path, file_name)
|
||||
dump_file = None
|
||||
|
||||
if os.path.exists(all_path):
|
||||
dump_file = {
|
||||
"url": url_for("dump_files", path=file_name),
|
||||
"size": os.path.getsize(all_path),
|
||||
"ctime": os.path.getctime(all_path),
|
||||
}
|
||||
|
||||
return render_template("developer/read.html", dump_file=dump_file)
|
||||
|
||||
3
tests/api/test_dump.py
Normal file
3
tests/api/test_dump.py
Normal file
@ -0,0 +1,3 @@
|
||||
def test_read(client, seeder, utils):
|
||||
response = utils.get_endpoint("api_v1_dump")
|
||||
utils.assert_response_notFound(response)
|
||||
@ -12,7 +12,7 @@ def test_read(client, app, db, seeder, utils):
|
||||
update_event(event)
|
||||
db.session.commit()
|
||||
|
||||
url = utils.get_url("eventresource", id=event_id)
|
||||
url = utils.get_url("api_v1_event", id=event_id)
|
||||
response = utils.get_ok(url)
|
||||
assert response.json["status"] == "scheduled"
|
||||
|
||||
@ -21,7 +21,7 @@ def test_list(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.create_event(admin_unit_id)
|
||||
|
||||
url = utils.get_url("eventlistresource")
|
||||
url = utils.get_url("api_v1_event_list")
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ def test_search(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.create_event(admin_unit_id)
|
||||
|
||||
url = utils.get_url("eventsearchresource")
|
||||
url = utils.get_url("api_v1_event_search")
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
@ -37,5 +37,5 @@ def test_dates(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
event_id = seeder.create_event(admin_unit_id)
|
||||
|
||||
url = utils.get_url("eventdatesresource", id=event_id)
|
||||
url = utils.get_url("api_v1_event_dates", id=event_id)
|
||||
utils.get_ok(url)
|
||||
|
||||
@ -2,5 +2,5 @@ def test_list(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.create_event(admin_unit_id)
|
||||
|
||||
url = utils.get_url("eventcategorylistresource")
|
||||
url = utils.get_url("api_v1_event_category_list")
|
||||
utils.get_ok(url)
|
||||
|
||||
@ -2,7 +2,7 @@ def test_read(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.create_event(admin_unit_id)
|
||||
|
||||
url = utils.get_url("eventdateresource", id=1)
|
||||
url = utils.get_url("api_v1_event_date", id=1)
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ def test_list(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.create_event(admin_unit_id)
|
||||
|
||||
url = utils.get_url("eventdatelistresource")
|
||||
url = utils.get_url("api_v1_event_date_list")
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
@ -18,5 +18,5 @@ def test_search(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.create_event(admin_unit_id)
|
||||
|
||||
url = utils.get_url("eventdatesearchresource")
|
||||
url = utils.get_url("api_v1_event_date_search")
|
||||
utils.get_ok(url)
|
||||
|
||||
11
tests/api/test_event_reference.py
Normal file
11
tests/api/test_event_reference.py
Normal file
@ -0,0 +1,11 @@
|
||||
def test_read(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
(
|
||||
other_user_id,
|
||||
other_admin_unit_id,
|
||||
event_id,
|
||||
reference_id,
|
||||
) = seeder.create_any_reference(admin_unit_id)
|
||||
|
||||
url = utils.get_url("api_v1_event_reference", id=reference_id)
|
||||
utils.get_ok(url)
|
||||
@ -2,5 +2,5 @@ def test_read(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
image_id = seeder.upsert_default_image()
|
||||
|
||||
url = utils.get_url("imageresource", id=image_id)
|
||||
url = utils.get_url("api_v1_image", id=image_id)
|
||||
utils.get_ok(url)
|
||||
|
||||
@ -15,6 +15,6 @@ def test_read(client, app, db, seeder, utils):
|
||||
db.session.commit()
|
||||
location_id = location.id
|
||||
|
||||
url = utils.get_url("locationresource", id=location_id)
|
||||
url = utils.get_url("api_v1_location", id=location_id)
|
||||
response = utils.get_ok(url)
|
||||
assert response.json["latitude"] == "51.9077888000000000"
|
||||
|
||||
@ -1,21 +1,14 @@
|
||||
def test_read(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
|
||||
url = utils.get_url("organizationresource", id=admin_unit_id)
|
||||
url = utils.get_url("api_v1_organization", id=admin_unit_id)
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
def test_list(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
|
||||
url = utils.get_url("organizationlistresource", keyword="crew")
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
def test_read_by_short_name(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
|
||||
url = utils.get_url("organizationbyshortnameresource", short_name="meinecrew")
|
||||
url = utils.get_url("api_v1_organization_list", keyword="crew")
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
@ -23,7 +16,7 @@ def test_event_date_search(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.create_event(admin_unit_id)
|
||||
|
||||
url = utils.get_url("organizationeventdatesearchresource", id=admin_unit_id)
|
||||
url = utils.get_url("api_v1_organization_event_date_search", id=admin_unit_id)
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
@ -31,7 +24,7 @@ def test_event_search(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.create_event(admin_unit_id)
|
||||
|
||||
url = utils.get_url("organizationeventsearchresource", id=admin_unit_id)
|
||||
url = utils.get_url("api_v1_organization_event_search", id=admin_unit_id)
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
@ -40,7 +33,7 @@ def test_organizers(client, seeder, utils):
|
||||
seeder.upsert_default_event_organizer(admin_unit_id)
|
||||
|
||||
url = utils.get_url(
|
||||
"organizationorganizerlistresource", id=admin_unit_id, name="crew"
|
||||
"api_v1_organization_organizer_list", id=admin_unit_id, name="crew"
|
||||
)
|
||||
utils.get_ok(url)
|
||||
|
||||
@ -49,5 +42,38 @@ def test_places(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.upsert_default_event_place(admin_unit_id)
|
||||
|
||||
url = utils.get_url("organizationplacelistresource", id=admin_unit_id, name="crew")
|
||||
url = utils.get_url("api_v1_organization_place_list", id=admin_unit_id, name="crew")
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
def test_references_incoming(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
(
|
||||
other_user_id,
|
||||
other_admin_unit_id,
|
||||
event_id,
|
||||
reference_id,
|
||||
) = seeder.create_any_reference(admin_unit_id)
|
||||
|
||||
url = utils.get_url(
|
||||
"api_v1_organization_incoming_event_reference_list",
|
||||
id=admin_unit_id,
|
||||
name="crew",
|
||||
)
|
||||
utils.get_ok(url)
|
||||
|
||||
|
||||
def test_references_outgoing(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
event_id = seeder.create_event(admin_unit_id)
|
||||
|
||||
other_user_id = seeder.create_user("other@test.de")
|
||||
other_admin_unit_id = seeder.create_admin_unit(other_user_id, "Other Crew")
|
||||
seeder.create_reference(event_id, other_admin_unit_id)
|
||||
|
||||
url = utils.get_url(
|
||||
"api_v1_organization_outgoing_event_reference_list",
|
||||
id=admin_unit_id,
|
||||
name="crew",
|
||||
)
|
||||
utils.get_ok(url)
|
||||
|
||||
@ -2,5 +2,5 @@ def test_read(client, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
organizer_id = seeder.upsert_default_event_organizer(admin_unit_id)
|
||||
|
||||
url = utils.get_url("organizerresource", id=organizer_id)
|
||||
url = utils.get_url("api_v1_organizer", id=organizer_id)
|
||||
utils.get_ok(url)
|
||||
|
||||
@ -2,5 +2,5 @@ def test_read(client, app, db, seeder, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
place_id = seeder.upsert_default_event_place(admin_unit_id)
|
||||
|
||||
url = utils.get_url("placeresource", id=place_id)
|
||||
url = utils.get_url("api_v1_place", id=place_id)
|
||||
utils.get_ok(url)
|
||||
|
||||
9
tests/cli/test_dump.py
Normal file
9
tests/cli/test_dump.py
Normal file
@ -0,0 +1,9 @@
|
||||
def test_all(client, seeder, app, utils):
|
||||
user_id, admin_unit_id = seeder.setup_base()
|
||||
seeder.create_event(admin_unit_id, "RRULE:FREQ=DAILY;COUNT=7")
|
||||
|
||||
runner = app.test_cli_runner()
|
||||
result = runner.invoke(args=["dump", "all"])
|
||||
assert "Zipped all up" in result.output
|
||||
|
||||
utils.get_endpoint_ok("dump_files", path="all.zip")
|
||||
Loading…
x
Reference in New Issue
Block a user