diff --git a/app/api/routes.py b/app/api/routes.py index 748c5cef0e..bd28dcd29b 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -165,6 +165,7 @@ SessionListPost, SessionRelationshipOptional, SessionRelationshipRequired, + get_session_states, ) from app.api.settings import SettingDetail from app.api.social_links import ( diff --git a/app/api/sessions.py b/app/api/sessions.py index 96205bc7b2..ce8654961f 100644 --- a/app/api/sessions.py +++ b/app/api/sessions.py @@ -1,4 +1,4 @@ -from flask import request, g +from flask import Blueprint, g, jsonify, request from flask_jwt_extended import current_user from flask_rest_jsonapi import ResourceDetail, ResourceList, ResourceRelationship from flask_rest_jsonapi.querystring import QueryStringManager as QSManager @@ -29,6 +29,8 @@ from app.models.user import User from app.settings import get_settings +sessions_blueprint = Blueprint('sessions_blueprint', __name__, url_prefix='/v1/sessions') + class SessionListPost(ResourceList): """ @@ -200,7 +202,7 @@ def query(self, view_kwargs): 'rejected': True, 'confirmed': True, }, - 'withdrawn': {'accepted': True, 'rejected': True, 'confirmed': True}, + 'withdrawn': {}, # Withdrawn is final }, 'speaker': { 'draft': {'pending': True}, @@ -209,11 +211,16 @@ def query(self, view_kwargs): 'confirmed': {'withdrawn': True}, 'rejected': {'withdrawn': True}, 'canceled': {'withdrawn': True}, - 'withdrawn': {'pending': True}, + 'withdrawn': {}, # Withdrawn is final }, } +@sessions_blueprint.route('/states') +def get_session_states(): + return jsonify(SESSION_STATE_DICT) + + class SessionDetail(ResourceDetail): """ Session detail by id diff --git a/app/instance.py b/app/instance.py index 2ab4612837..c8ed665070 100644 --- a/app/instance.py +++ b/app/instance.py @@ -150,6 +150,7 @@ def create_app(): from app.api.auth import authorised_blueprint from app.api.admin_translations import admin_blueprint from app.api.orders import alipay_blueprint + from app.api.sessions import sessions_blueprint from app.api.settings import admin_misc_routes from app.api.server_version import info_route from app.api.custom.orders import ticket_blueprint @@ -176,6 +177,7 @@ def create_app(): app.register_blueprint(ticket_blueprint) app.register_blueprint(order_blueprint) app.register_blueprint(event_blueprint) + app.register_blueprint(sessions_blueprint) add_engine_pidguard(db.engine) diff --git a/docs/api/blueprint/session/sessions.apib b/docs/api/blueprint/session/sessions.apib index 254afe595b..5ad903e270 100644 --- a/docs/api/blueprint/session/sessions.apib +++ b/docs/api/blueprint/session/sessions.apib @@ -855,3 +855,68 @@ Delete a single session. **(Minimum Co-Organizer Access)** "self": "/v1/speakers/1/sessions" } } + + +## Sessions States [/v1/sessions/states] + +### Session States [GET] +Get possible session state transitions. **(Public)** + ++ Response 200 (application/json) + + { + "organizer": { + "accepted": { + "canceled": true, + "confirmed": true, + "rejected": true, + "withdrawn": true + }, + "canceled": { + "accepted": true, + "confirmed": true, + "rejected": true, + "withdrawn": true + }, + "confirmed": { + "accepted": true, + "canceled": true, + "rejected": true, + "withdrawn": true + }, + "draft": {}, + "pending": { + "accepted": true, + "confirmed": true, + "rejected": true, + "withdrawn": true + }, + "rejected": { + "accepted": true, + "confirmed": true, + "withdrawn": true + }, + "withdrawn": {} + }, + "speaker": { + "accepted": { + "withdrawn": true + }, + "canceled": { + "withdrawn": true + }, + "confirmed": { + "withdrawn": true + }, + "draft": { + "pending": true + }, + "pending": { + "withdrawn": true + }, + "rejected": { + "withdrawn": true + }, + "withdrawn": {} + } + } diff --git a/tests/all/integration/api/session/test_session_state_api.py b/tests/all/integration/api/session/test_session_state_api.py index 8f6ddc2b9a..e47126e526 100644 --- a/tests/all/integration/api/session/test_session_state_api.py +++ b/tests/all/integration/api/session/test_session_state_api.py @@ -28,6 +28,8 @@ def get_session(db, user, event_owner=True, **kwargs): return session +# TODO(Areeb): Remove some states from tests to reduce testing time. +# Not every state change needs to be tested def _test_state_change( db, client, user, jwt, new_state, state, event_owner=True, error=True ): @@ -121,10 +123,8 @@ def test_withdraw_speaker_allow(db, client, user, jwt, new_state, state): @pytest.mark.parametrize('state,new_state', states) -def test_revert_withdraw_speaker_allow(db, client, user, jwt, new_state, state): - _test_state_change( - db, client, user, jwt, new_state, state=state, event_owner=False, error=False - ) +def test_revert_withdraw_speaker_disallow(db, client, user, jwt, new_state, state): + _test_state_change(db, client, user, jwt, new_state, state=state, event_owner=False) def test_withdraw_speaker_error( @@ -147,8 +147,8 @@ def test_withdraw_organizer_allow(db, client, user, jwt, new_state, state): @pytest.mark.parametrize('state,new_state', states) -def test_revert_withdraw_organizer_allow(db, client, user, jwt, new_state, state): - _test_state_change(db, client, user, jwt, new_state, state=state, error=False) +def test_revert_withdraw_organizer_disallow(db, client, user, jwt, new_state, state): + _test_state_change(db, client, user, jwt, new_state, state=state) states = _create_permutations(['pending'], ['accepted', 'confirmed', 'rejected'])