diff --git a/app/api/events.py b/app/api/events.py index ec2e4ad378..09a2f1bd73 100644 --- a/app/api/events.py +++ b/app/api/events.py @@ -853,3 +853,38 @@ def clear_export_urls(event): event.xcal_url = None event.pentabarf_url = None save_to_db(event) + + +class UpcomingEventList(EventList): + """ + List Upcoming Events + """ + + def before_get(self, args, kwargs): + """ + method for assigning schema based on admin access + :param args: + :param kwargs: + :return: + """ + super().before_get(args, kwargs) + self.schema.self_view_many = 'v1.upcoming_event_list' + + def query(self, view_kwargs): + """ + query method for upcoming events list + :param view_kwargs: + :return: + """ + current_time = datetime.now(pytz.utc) + query_ = self.session.query(Event).filter( + Event.ends_at > current_time, + Event.state == 'published', + Event.privacy == 'public').order_by(Event.starts_at) + return query_ + + data_layer = { + 'session': db.session, + 'model': Event, + 'methods': {'query': query}, + } diff --git a/app/api/routes.py b/app/api/routes.py index 6e617d88b7..79493606c2 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -83,7 +83,7 @@ ) from app.api.event_topics import EventTopicDetail, EventTopicList, EventTopicRelationship from app.api.event_types import EventTypeDetail, EventTypeList, EventTypeRelationship -from app.api.events import EventDetail, EventList, EventRelationship +from app.api.events import EventDetail, EventList, EventRelationship, UpcomingEventList from app.api.events_role_permission import ( EventsRolePermissionDetail, EventsRolePermissionList, @@ -610,6 +610,12 @@ '/users//sales-admin-events', ) +api.route( + UpcomingEventList, + 'upcoming_event_list', + '/events/upcoming', +) + api.route( EventDetail, 'event_detail', diff --git a/docs/api/blueprint/event/events.apib b/docs/api/blueprint/event/events.apib index 25b7ab867a..c6afb631c8 100644 --- a/docs/api/blueprint/event/events.apib +++ b/docs/api/blueprint/event/events.apib @@ -1177,6 +1177,257 @@ Delete a single event. } +## Upcoming Events Collection [/v1/events/upcoming] + +### List All Upcoming Events [GET] +Get a list of upcoming events. + ++ Request + + + Headers + + Accept: application/vnd.api+json + + Authorization: JWT + ++ Response 200 (application/vnd.api+json) + + { + "meta": { + "count": 1 + }, + "data": [ + { + "relationships": { + "tickets": { + "links": { + "self": "/v1/events/1/relationships/tickets", + "related": "/v1/events/1/tickets" + } + }, + "orders": { + "links": { + "self": "/v1/events/1/relationships/orders", + "related": "/v1/orders" + } + }, + "owner": { + "links": { + "self": "/v1/events/1/relationships/owner", + "related": "/v1/events/1/owner" + } + }, + "organizers": { + "links": { + "self": "/v1/events/1/relationships/organizers", + "related": "/v1/users" + } + }, + "coorganizers": { + "links": { + "self": "/v1/events/1/relationships/coorganizers", + "related": "/v1/users" + } + }, + "track-organizers": { + "links": { + "self": "/v1/events/1/relationships/track-coorganizers", + "related": "/v1/users" + } + }, + "registrars": { + "links": { + "self": "/v1/events/1/relationships/registrars", + "related": "/v1/users" + } + }, + "moderators": { + "links": { + "self": "/v1/events/1/relationships/moderators", + "related": "/v1/users" + } + }, + "custom-forms": { + "links": { + "self": "/v1/events/1/relationships/custom-forms", + "related": "/v1/events/1/custom-forms" + } + }, + "faqs": { + "links": { + "self": "/v1/events/1/relationships/faqs", + "related": "/v1/events/1/faqs" + } + }, + "faq-types": { + "links": { + "self": "/v1/events/1/relationships/faq-types", + "related": "/v1/events/1/faq-types" + } + }, + "attendees": { + "links": { + "self": "/v1/events/1/relationships/attendees", + "related": "/v1/events/1/attendees" + } + }, + "role-invites": { + "links": { + "self": "/v1/events/1/relationships/role-invites", + "related": "/v1/events/1/role-invites" + } + }, + "event-sub-topic": { + "links": { + "self": "/v1/events/1/relationships/event-sub-topic", + "related": "/v1/events/1/event-sub-topic" + } + }, + "speakers-call": { + "links": { + "self": "/v1/events/1/relationships/speakers-call", + "related": "/v1/events/1/speakers-call" + } + }, + "event-copyright": { + "links": { + "self": "/v1/events/1/relationships/event-copyright", + "related": "/v1/events/1/event-copyright" + } + }, + "sessions": { + "links": { + "self": "/v1/events/1/relationships/sessions", + "related": "/v1/events/1/sessions" + } + }, + "tax": { + "links": { + "self": "/v1/events/1/relationships/tax", + "related": "/v1/events/1/tax" + } + }, + "event-topic": { + "links": { + "self": "/v1/events/1/relationships/event-topic", + "related": "/v1/events/1/event-topic" + } + }, + "social-links": { + "links": { + "self": "/v1/events/1/relationships/social-links", + "related": "/v1/events/1/social-links" + } + }, + "sponsors": { + "links": { + "self": "/v1/events/1/relationships/sponsors", + "related": "/v1/events/1/sponsors" + } + }, + "tracks": { + "links": { + "self": "/v1/events/1/relationships/tracks", + "related": "/v1/events/1/tracks" + } + }, + "event-invoices": { + "links": { + "self": "/v1/events/1/relationships/event-invoices", + "related": "/v1/events/1/event-invoices" + } + }, + "session-types": { + "links": { + "self": "/v1/events/1/relationships/session-types", + "related": "/v1/events/1/session-types" + } + }, + "microlocations": { + "links": { + "self": "/v1/events/1/relationships/microlocations", + "related": "/v1/events/1/microlocations" + } + }, + "event-type": { + "links": { + "self": "/v1/events/1/relationships/event-type", + "related": "/v1/events/1/event-type" + } + }, + "discount-codes": { + "links": { + "self": "/v1/events/1/relationships/discount-codes", + "related": "/v1/events/1/discount-codes" + } + } + }, + "attributes": { + "payment-country": "US", + "paypal-email": "example@example.com", + "thumbnail-image-url": null, + "schedule-published-on": null, + "payment-currency": "USD", + "owner-description": "example", + "is-map-shown": true, + "original-image-url": "http://example.com/example.png", + "onsite-details": "example", + "owner-name": "example", + "can-pay-by-stripe": true, + "large-image-url": null, + "timezone": "UTC", + "can-pay-onsite": true, + "deleted-at": null, + "ticket-url": "http://example.com", + "can-pay-by-paypal": true, + "location-name": "example", + "is-sponsors-enabled": false, + "is-event-online": false, + "has-owner-info": false, + "is-sessions-speakers-enabled": true, + "privacy": "public", + "code-of-conduct": "example", + "state": "published", + "latitude": 1.23456789, + "starts-at": "2099-12-13T23:59:59.123456+00:00", + "searchable-location-name": "example", + "can-pay-by-cheque": true, + "can-pay-by-omise": false, + "description": "example", + "pentabarf-url": null, + "xcal-url": null, + "logo-url": "http://example.com/example.png", + "external-event-url": null, + "is-tax-enabled": true, + "icon-image-url": null, + "ical-url": null, + "name": "example", + "can-pay-by-bank": true, + "ends-at": "2099-12-14T23:59:59.123456+00:00", + "created-at": "2020-06-07T15:22:37.205399+00:00", + "longitude": 1.23456789, + "bank-details": "example", + "cheque-details": "example", + "identifier": "b8324ae2", + "refund-policy": "All sales are final. No refunds shall be issued in any case.", + "is-stripe-linked": "false" + }, + "type": "event", + "id": "1", + "links": { + "self": "/v1/events/1" + } + } + ], + "jsonapi": { + "version": "1.0" + }, + "links": { + "self": "/v1/events/upcoming" + } + } + + ## Events of an Event Type [/v1/event-types/{event_type_id}/events{?page%5bsize%5d,page%5bnumber%5d,sort,filter}] + Parameters + event_type_id: 1 (integer) - ID of the event type in the form of an integer diff --git a/tests/hook_main.py b/tests/hook_main.py index 5a0be3d95c..f6907160da 100644 --- a/tests/hook_main.py +++ b/tests/hook_main.py @@ -361,6 +361,19 @@ def event_post(transaction): db.session.commit() +@hooks.before("Events > Upcoming Events Collection > List All Upcoming Events") +def upcoming_event_get_list(transaction): + """ + GET /events/upcoming + :param transaction: + :return: + """ + with stash['app'].app_context(): + event = EventFactoryBasic(state="published") + db.session.add(event) + db.session.commit() + + @hooks.before("Events > Event Details > Event Details") def event_get_detail(transaction): """