diff --git a/.vscode/settings.json b/.vscode/settings.json index 99228c8630a9d167650384c97fb7573c0f8d07ef..db2b68f4590ffec707c286474aa1004c29a5709e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,51 +1,44 @@ { - //editor - "editor.formatOnSave": true, - "editor.formatOnPaste": false, - "editor.tabCompletion": "on", - "editor.codeActionsOnSave": { - "source.fixAll.eslint": true, - "source.organizeImports": true - }, - //python - "python.venvPath": "${workspaceFolder}\\server", - "python.analysis.extraPaths": [ - "server" - ], - "python.terminal.activateEnvironment": true, - "python.formatting.provider": "black", - "python.formatting.blackPath": "server\\env\\Scripts\\black.exe", - "python.formatting.blackArgs": [ - "--line-length", - "119" - ], - //eslint - "eslint.workingDirectories": [ - "./client" - ], - "eslint.options": { - "configFile": "./.eslintrc" - }, - "prettier.configPath": "./client/.prettierrc", - //git - "git.ignoreLimitWarning": true, - //language specific - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[typescriptreact]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "files.exclude": { - "**/__pycache__": true, - "**/.pytest_cache": true, - "**/env/Include": true, - "**/env/Lib": true - }, - "files.watcherExclude": { - "**/env/Lib/**": true - }, - "search.exclude": { - "**/env": true - }, -} \ No newline at end of file + //editor + "editor.formatOnSave": true, + "editor.formatOnPaste": false, + "editor.tabCompletion": "on", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true, + "source.organizeImports": false + }, + //python + "python.venvPath": "${workspaceFolder}\\server", + "python.analysis.extraPaths": ["server"], + "python.terminal.activateEnvironment": true, + "python.formatting.provider": "black", + "python.formatting.blackPath": "server\\env\\Scripts\\black.exe", + "python.formatting.blackArgs": ["--line-length", "119"], + //eslint + "eslint.workingDirectories": ["./client"], + "eslint.options": { + "configFile": "./.eslintrc" + }, + "prettier.configPath": "./client/.prettierrc", + //git + "git.ignoreLimitWarning": true, + //language specific + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "files.exclude": { + "**/__pycache__": true, + "**/.pytest_cache": true, + "**/env/Include": true, + "**/env/Lib": true + }, + "files.watcherExclude": { + "**/env/Lib/**": true + }, + "search.exclude": { + "**/env": true + } +} diff --git a/server/app/apis/__init__.py b/server/app/apis/__init__.py index 61d1d0633fbccfb78c207d80460571a55e4ad3f7..5eab3f829ae81e17ecc269d98f568eeacc45a68c 100644 --- a/server/app/apis/__init__.py +++ b/server/app/apis/__init__.py @@ -76,10 +76,10 @@ flask_api.add_namespace(auth_ns, path="/api/auth") flask_api.add_namespace(comp_ns, path="/api/competitions") flask_api.add_namespace(slide_ns, path="/api/competitions/<competition_id>/slides") flask_api.add_namespace( - alternative_ns, path="/api/competitions/<competition_id>/slides/<slide_order>/questions/<question_id>/alternatives" + alternative_ns, path="/api/competitions/<competition_id>/slides/<slide_id>/questions/<question_id>/alternatives" ) flask_api.add_namespace(answer_ns, path="/api/competitions/<competition_id>/teams/<team_id>/answers") flask_api.add_namespace(team_ns, path="/api/competitions/<competition_id>/teams") flask_api.add_namespace(code_ns, path="/api/competitions/<competition_id>/codes") flask_api.add_namespace(question_ns, path="/api/competitions/<competition_id>") -flask_api.add_namespace(component_ns, path="/api/competitions/<competition_id>/slides/<slide_order>/components") +flask_api.add_namespace(component_ns, path="/api/competitions/<competition_id>/slides/<slide_id>/components") diff --git a/server/app/apis/alternatives.py b/server/app/apis/alternatives.py index 9e3b53effeffdf5a386935180bbc444a5e94cda0..d56a2f8ba0163a9187aa451eac45a416890052c6 100644 --- a/server/app/apis/alternatives.py +++ b/server/app/apis/alternatives.py @@ -14,37 +14,37 @@ list_schema = QuestionAlternativeDTO.list_schema @api.route("/") -@api.param("competition_id, slide_order, question_id") +@api.param("competition_id, slide_id, question_id") class QuestionAlternativeList(Resource): @check_jwt(editor=True) - def get(self, competition_id, slide_order, question_id): - items = dbc.get.question_alternative_list(competition_id, slide_order, question_id) + def get(self, competition_id, slide_id, question_id): + items = dbc.get.question_alternative_list(competition_id, slide_id, question_id) return list_response(list_schema.dump(items)) @check_jwt(editor=True) - def post(self, competition_id, slide_order, question_id): + def post(self, competition_id, slide_id, question_id): args = question_alternative_parser.parse_args(strict=True) item = dbc.add.question_alternative(**args, question_id=question_id) return item_response(schema.dump(item)) @api.route("/<alternative_id>") -@api.param("competition_id, slide_order, question_id, alternative_id") +@api.param("competition_id, slide_id, question_id, alternative_id") class QuestionAlternatives(Resource): @check_jwt(editor=True) - def get(self, competition_id, slide_order, question_id, alternative_id): - items = dbc.get.question_alternative(competition_id, slide_order, question_id, alternative_id) + def get(self, competition_id, slide_id, question_id, alternative_id): + items = dbc.get.question_alternative(competition_id, slide_id, question_id, alternative_id) return item_response(schema.dump(items)) @check_jwt(editor=True) - def put(self, competition_id, slide_order, question_id, alternative_id): + def put(self, competition_id, slide_id, question_id, alternative_id): args = question_alternative_parser.parse_args(strict=True) - item = dbc.get.question_alternative(competition_id, slide_order, question_id, alternative_id) + item = dbc.get.question_alternative(competition_id, slide_id, question_id, alternative_id) item = dbc.edit.default(item, **args) return item_response(schema.dump(item)) @check_jwt(editor=True) - def delete(self, competition_id, slide_order, question_id, alternative_id): - item = dbc.get.question_alternative(competition_id, slide_order, question_id, alternative_id) + def delete(self, competition_id, slide_id, question_id, alternative_id): + item = dbc.get.question_alternative(competition_id, slide_id, question_id, alternative_id) dbc.delete.default(item) return {}, codes.NO_CONTENT diff --git a/server/app/apis/answers.py b/server/app/apis/answers.py index d636f15a4cef745d0c71ba447734bbcc281e9e3c..308b1001de9fa325b7ff01c4e518f7db9e3c10eb 100644 --- a/server/app/apis/answers.py +++ b/server/app/apis/answers.py @@ -31,6 +31,11 @@ class QuestionAnswerList(Resource): @api.route("/<answer_id>") @api.param("competition_id, team_id, answer_id") class QuestionAnswers(Resource): + @check_jwt(editor=True) + def get(self, competition_id, team_id, answer_id): + item = dbc.get.question_answer(competition_id, team_id, answer_id) + return item_response(schema.dump(item)) + @check_jwt(editor=True) def put(self, competition_id, team_id, answer_id): args = question_answer_edit_parser.parse_args(strict=True) diff --git a/server/app/apis/auth.py b/server/app/apis/auth.py index 86ac53d52d7712a927411f1b03e32ee0b99a385f..d249fec586a0d9974a3802bb55700cc635f57792 100644 --- a/server/app/apis/auth.py +++ b/server/app/apis/auth.py @@ -58,7 +58,7 @@ class AuthLogin(Resource): args = login_parser.parse_args(strict=True) email = args.get("email") password = args.get("password") - item_user = dbc.get.user_by_email(email, required=False) + item_user = dbc.get.user_by_email(email) if not item_user or not item_user.is_correct_password(password): api.abort(codes.UNAUTHORIZED, "Invalid email or password") diff --git a/server/app/apis/components.py b/server/app/apis/components.py index 6e514039f207d11e4e453dd3f4781282ba5ee145..c712a4e6518d8b878595a98cc38d1d3ad5d9cd81 100644 --- a/server/app/apis/components.py +++ b/server/app/apis/components.py @@ -14,38 +14,38 @@ list_schema = ComponentDTO.list_schema @api.route("/<component_id>") -@api.param("competition_id, slide_order, component_id") +@api.param("competition_id, slide_id, component_id") class ComponentByID(Resource): @check_jwt(editor=True) - def get(self, competition_id, slide_order, component_id): - item = dbc.get.one(Component, component_id) + def get(self, competition_id, slide_id, component_id): + item = dbc.get.component(competition_id, slide_id, component_id) return item_response(schema.dump(item)) @check_jwt(editor=True) - def put(self, competition_id, slide_order, component_id): + def put(self, competition_id, slide_id, component_id): args = component_parser.parse_args() - item = dbc.get.one(Component, component_id) + item = dbc.get.component(competition_id, slide_id, component_id) item = dbc.edit.default(item, **args) return item_response(schema.dump(item)) @check_jwt(editor=True) - def delete(self, competition_id, slide_order, component_id): - item = dbc.get.one(Component, component_id) + def delete(self, competition_id, slide_id, component_id): + item = dbc.get.component(competition_id, slide_id, component_id) dbc.delete.component(item) return {}, codes.NO_CONTENT @api.route("/") -@api.param("competition_id, slide_order") +@api.param("competition_id, slide_id") class ComponentList(Resource): @check_jwt(editor=True) - def get(self, competition_id, slide_order): - items = dbc.get.component_list(competition_id, slide_order) + def get(self, competition_id, slide_id): + items = dbc.get.component_list(competition_id, slide_id) return list_response(list_schema.dump(items)) @check_jwt(editor=True) - def post(self, competition_id, slide_order): + def post(self, competition_id, slide_id): args = component_create_parser.parse_args() - item_slide = dbc.get.slide(competition_id, slide_order) + item_slide = dbc.get.slide(competition_id, slide_id) item = dbc.add.component(item_slide=item_slide, **args) return item_response(schema.dump(item)) diff --git a/server/app/apis/questions.py b/server/app/apis/questions.py index 74ca76082fa7ef9ebff568e8539b54b4628e8f2b..9b519e5f91f6c9495cc9bd27f07d717948b0b24b 100644 --- a/server/app/apis/questions.py +++ b/server/app/apis/questions.py @@ -17,40 +17,45 @@ list_schema = QuestionDTO.list_schema class QuestionList(Resource): @check_jwt(editor=True) def get(self, competition_id): - items = dbc.get.question_list(competition_id) + items = dbc.get.question_list_for_competition(competition_id) return list_response(list_schema.dump(items)) -@api.route("/slides/<slide_order>/questions") -@api.param("competition_id, slide_order") +@api.route("/slides/<slide_id>/questions") +@api.param("competition_id, slide_id") class QuestionListForSlide(Resource): @check_jwt(editor=True) - def post(self, slide_order, competition_id): + def get(self, competition_id, slide_id): + items = dbc.get.question_list(competition_id, slide_id) + return list_response(list_schema.dump(items)) + + @check_jwt(editor=True) + def post(self, slide_id, competition_id): args = question_parser.parse_args(strict=True) - item_slide = dbc.get.slide(competition_id, slide_order) + item_slide = dbc.get.slide(competition_id, slide_id) item = dbc.add.question(item_slide=item_slide, **args) return item_response(schema.dump(item)) -@api.route("/slides/<slide_order>/questions/<question_id>") -@api.param("competition_id, slide_order, question_id") +@api.route("/slides/<slide_id>/questions/<question_id>") +@api.param("competition_id, slide_id, question_id") class QuestionById(Resource): @check_jwt(editor=True) - def get(self, competition_id, slide_order, question_id): - item_question = dbc.get.question(competition_id, slide_order, question_id) + def get(self, competition_id, slide_id, question_id): + item_question = dbc.get.question(competition_id, slide_id, question_id) return item_response(schema.dump(item_question)) @check_jwt(editor=True) - def put(self, competition_id, slide_order, question_id): + def put(self, competition_id, slide_id, question_id): args = question_parser.parse_args(strict=True) - item_question = dbc.get.question(competition_id, slide_order, question_id) + item_question = dbc.get.question(competition_id, slide_id, question_id) item_question = dbc.edit.default(item_question, **args) return item_response(schema.dump(item_question)) @check_jwt(editor=True) - def delete(self, competition_id, slide_order, question_id): - item_question = dbc.get.question(competition_id, slide_order, question_id) + def delete(self, competition_id, slide_id, question_id): + item_question = dbc.get.question(competition_id, slide_id, question_id) dbc.delete.question(item_question) return {}, codes.NO_CONTENT diff --git a/server/app/apis/slides.py b/server/app/apis/slides.py index 7c94caa22c1cd096086fd25453f2601e26b7b606..fffdff0bec150c3458ee73f5462855bfb6480e7e 100644 --- a/server/app/apis/slides.py +++ b/server/app/apis/slides.py @@ -29,40 +29,40 @@ class SlidesList(Resource): return list_response(list_schema.dump(item_comp.slides)) -@api.route("/<slide_order>") -@api.param("competition_id,slide_order") +@api.route("/<slide_id>") +@api.param("competition_id,slide_id") class Slides(Resource): @check_jwt(editor=True) - def get(self, competition_id, slide_order): - item_slide = dbc.get.slide(competition_id, slide_order) + def get(self, competition_id, slide_id): + item_slide = dbc.get.slide(competition_id, slide_id) return item_response(schema.dump(item_slide)) @check_jwt(editor=True) - def put(self, competition_id, slide_order): + def put(self, competition_id, slide_id): args = slide_parser.parse_args(strict=True) - item_slide = dbc.get.slide(competition_id, slide_order) + item_slide = dbc.get.slide(competition_id, slide_id) item_slide = dbc.edit.default(item_slide, **args) return item_response(schema.dump(item_slide)) @check_jwt(editor=True) - def delete(self, competition_id, slide_order): - item_slide = dbc.get.slide(competition_id, slide_order) + def delete(self, competition_id, slide_id): + item_slide = dbc.get.slide(competition_id, slide_id) dbc.delete.slide(item_slide) return {}, codes.NO_CONTENT -@api.route("/<slide_order>/order") -@api.param("competition_id,slide_order") -class Slideslide_order(Resource): +@api.route("/<slide_id>/order") +@api.param("competition_id,slide_id") +class SlideOrder(Resource): @check_jwt(editor=True) - def put(self, competition_id, slide_order): + def put(self, competition_id, slide_id): args = slide_parser.parse_args(strict=True) order = args.get("order") - item_slide = dbc.get.slide(competition_id, slide_order) + item_slide = dbc.get.slide(competition_id, slide_id) if order == item_slide.order: return item_response(schema.dump(item_slide)) @@ -75,20 +75,20 @@ class Slideslide_order(Resource): order = order_count - 1 # get slide at the requested order - item_slide_order = dbc.get.slide(competition_id, order) + item_slide_id = dbc.get.slide(competition_id, order) # switch place between them - item_slide = dbc.edit.switch_order(item_slide, item_slide_order) + item_slide = dbc.edit.switch_order(item_slide, item_slide_id) return item_response(schema.dump(item_slide)) -@api.route("/<slide_order>/copy") -@api.param("competition_id,slide_order") -class Slideslide_order(Resource): +@api.route("/<slide_id>/copy") +@api.param("competition_id,slide_id") +class SlideCopy(Resource): @check_jwt(editor=True) - def post(self, competition_id, slide_order): - item_slide = dbc.get.slide(competition_id, slide_order) + def post(self, competition_id, slide_id): + item_slide = dbc.get.slide(competition_id, slide_id) item_slide_copy = dbc.copy.slide(item_slide) diff --git a/server/app/apis/teams.py b/server/app/apis/teams.py index 8b66a48cca7a7a0bd6e9d651b206d7f1b38f4cc7..535de69560b7fccc85fed442419a725ca84be7a5 100644 --- a/server/app/apis/teams.py +++ b/server/app/apis/teams.py @@ -31,13 +31,11 @@ class TeamsList(Resource): @api.route("/<team_id>") @api.param("competition_id,team_id") class Teams(Resource): - @jwt_required @check_jwt(editor=True) def get(self, competition_id, team_id): item = dbc.get.team(competition_id, team_id) return item_response(schema.dump(item)) - @jwt_required @check_jwt(editor=True) def delete(self, competition_id, team_id): item_team = dbc.get.team(competition_id, team_id) @@ -45,7 +43,6 @@ class Teams(Resource): dbc.delete.team(item_team) return {}, codes.NO_CONTENT - @jwt_required @check_jwt(editor=True) def put(self, competition_id, team_id): args = team_parser.parse_args(strict=True) diff --git a/server/app/database/controller/add.py b/server/app/database/controller/add.py index 265347e3628dc5c32d2a692ee2618fe916e0a6c1..7b77732bc409f9158df50742c234d56f676bcd36 100644 --- a/server/app/database/controller/add.py +++ b/server/app/database/controller/add.py @@ -40,7 +40,7 @@ def db_add(item): except (exc.SQLAlchemyError, exc.DBAPIError): db.session.rollback() # SQL errors such as item already exists - abort(codes.BAD_REQUEST, f"Item of type {type(item)} could not be created") + abort(codes.INTERNAL_SERVER_ERROR, f"Item of type {type(item)} could not be created") except: db.session.rollback() # Catching other errors diff --git a/server/app/database/controller/get.py b/server/app/database/controller/get.py index d44894afa9f9623698ecf1995e58a5e75710a01b..15e908ef401c7e63b99c5767bcc5440ea5e7a820 100644 --- a/server/app/database/controller/get.py +++ b/server/app/database/controller/get.py @@ -24,17 +24,17 @@ def all(db_type): return db_type.query.all() -def one(db_type, id, required=True, error_msg=None): +def one(db_type, id): """ Get lazy db-item in the table that has the same id. """ - return db_type.query.filter(db_type.id == id).first_extended(required, error_msg) + return db_type.query.filter(db_type.id == id).first_extended() ### Codes ### -def code_by_code(code, required=True, error_msg=None): +def code_by_code(code): """ Gets the code object associated with the provided code. """ - return Code.query.filter(Code.code == code.upper()).first_extended(required, error_msg, codes.UNAUTHORIZED) + return Code.query.filter(Code.code == code.upper()).first_extended() def code_list(competition_id): @@ -55,30 +55,32 @@ def user_exists(email): return User.query.filter(User.email == email).count() > 0 -def user(user_id, required=True, error_msg=None): +def user(user_id): """ Gets the user object associated with the provided id. """ - return User.query.filter(User.id == user_id).first_extended(required, error_msg) + return User.query.filter(User.id == user_id).first_extended() -def user_by_email(email, required=True, error_msg=None): +def user_by_email(email): """ Gets the user object associated with the provided email. """ - - return User.query.filter(User.email == email).first_extended(required, error_msg) + return User.query.filter(User.email == email).first_extended(error_code=codes.UNAUTHORIZED) ### Slides ### -def slide(competition_id, slide_order, required=True, error_msg=None): +def slide(competition_id, slide_id): """ Gets the slide object associated with the provided id and order. """ + join_competition = Competition.id == Slide.competition_id + filters = (Competition.id == competition_id) & (Slide.id == slide_id) - filters = (Slide.competition_id == competition_id) & (Slide.order == slide_order) - return Slide.query.filter(filters).first_extended(required, error_msg) + return Slide.query.join(Competition, join_competition).filter(filters).first_extended() def slide_list(competition_id): """ Gets a list of all slide objects associated with a the provided competition. """ + join_competition = Competition.id == Slide.competition_id + filters = Competition.id == competition_id - return Slide.query.filter(Slide.competition_id == competition_id).all() + return Slide.query.join(Competition, join_competition).filter(filters).all() def slide_count(competition_id): @@ -88,82 +90,129 @@ def slide_count(competition_id): ### Teams ### -def team(competition_id, team_id, required=True, error_msg=None): +def team(competition_id, team_id): """ Gets the team object associated with the provided id and competition id. """ + join_competition = Competition.id == Team.competition_id + filters = (Competition.id == competition_id) & (Team.id == team_id) - return Team.query.filter((Team.competition_id == competition_id) & (Team.id == team_id)).first_extended( - required, error_msg - ) + return Team.query.join(Competition, join_competition).filter(filters).first_extended() def team_list(competition_id): """ Gets a list of all team objects associated with a the provided competition. """ - return Team.query.filter(Team.competition_id == competition_id).all() + join_competition = Competition.id == Team.competition_id + filters = Competition.id == competition_id + + return Team.query.join(Competition, join_competition).filter(filters).all() ### Questions ### -def question(competition_id, slide_order, question_id, required=True, error_msg=None): +def question(competition_id, slide_id, question_id): """ Gets the question object associated with the provided id, slide order and competition id. """ - # Join all slides for one competition - join_filters = (Slide.competition_id == competition_id) & (Slide.order == slide_order) - return ( - Question.query.join(Slide, join_filters).filter(Question.id == question_id).first_extended(required, error_msg) - ) + join_competition = Competition.id == Slide.competition_id + join_slide = Slide.id == Question.slide_id + filters = (Competition.id == competition_id) & (Slide.id == slide_id) & (Question.id == question_id) + + return Question.query.join(Competition, join_competition).join(Slide, join_slide).filter(filters).first_extended() + + +def question_list(competition_id, slide_id): + """ Gets a list of all question objects associated with a the provided competition and slide. """ + + join_competition = Competition.id == Slide.competition_id + join_slide = Slide.id == Question.slide_id + filters = (Competition.id == competition_id) & (Slide.id == slide_id) + return Question.query.join(Competition, join_competition).join(Slide, join_slide).filter(filters).all() -def question_list(competition_id): + +def question_list_for_competition(competition_id): """ Gets a list of all question objects associated with a the provided competition. """ - join_filters = (Slide.competition_id == competition_id) & (Slide.id == Question.slide_id) - return Question.query.join(Slide, join_filters).all() + join_competition = Competition.id == Slide.competition_id + join_slide = Slide.id == Question.slide_id + filters = Competition.id == competition_id + + return Question.query.join(Competition, join_competition).join(Slide, join_slide).filter(filters).all() ### Question Alternative ### -def question_alternative(competition_id, slide_order, question_id, alternative_id, required=True, error_msg=None): +def question_alternative(competition_id, slide_id, question_id, alternative_id): """ Get question alternative for a given question based on its competition and slide and ID. """ - join_slide = (Slide.competition_id == competition_id) & (Slide.order == slide_order) - join_question = (Question.id == question_id) & (Question.id == QuestionAlternative.question_id) - filters = QuestionAlternative.id == alternative_id + join_competition = Competition.id == Slide.competition_id + join_slide = Slide.id == Question.slide_id + join_question = Question.id == QuestionAlternative.question_id + filters = ( + (Competition.id == competition_id) + & (Slide.id == slide_id) + & (Question.id == question_id) + & (QuestionAlternative.id == alternative_id) + ) + return ( - QuestionAlternative.query.join(Slide, join_slide) + QuestionAlternative.query.join(Competition, join_competition) + .join(Slide, join_slide) .join(Question, join_question) .filter(filters) - .first_extended(required, error_msg) + .first_extended() ) -def question_alternative_list(competition_id, slide_order, question_id): +def question_alternative_list(competition_id, slide_id, question_id): """ Get all question alternatives for a given question based on its competition and slide. """ - join_slide = (Slide.competition_id == competition_id) & (Slide.order == slide_order) - join_question = (Question.id == question_id) & (Question.id == QuestionAlternative.question_id) - filters = QuestionAlternative.question_id == question_id - return QuestionAlternative.query.join(Slide, join_slide).join(Question, join_question).all() + join_competition = Competition.id == Slide.competition_id + join_slide = Slide.id == Question.slide_id + join_question = Question.id == QuestionAlternative.question_id + filters = (Competition.id == competition_id) & (Slide.id == slide_id) & (Question.id == question_id) + + return ( + QuestionAlternative.query.join(Competition, join_competition) + .join(Slide, join_slide) + .join(Question, join_question) + .filter(filters) + .all() + ) ### Question Answers ### def question_answer(competition_id, team_id, answer_id): """ Get question answer for a given team based on its competition and ID. """ - - join_filters = ( - (Team.competition_id == competition_id) - & (QuestionAnswer.team_id == Team.id) - & (QuestionAnswer.team_id == team_id) + join_competition = Competition.id == Team.competition_id + join_team = Team.id == QuestionAnswer.team_id + filters = (Competition.id == competition_id) & (Team.id == team_id) & (QuestionAnswer.id == answer_id) + return ( + QuestionAnswer.query.join(Competition, join_competition).join(Team, join_team).filter(filters).first_extended() ) - return QuestionAnswer.query.join(Team, join_filters).filter(QuestionAnswer.id == answer_id).first_extended() def question_answer_list(competition_id, team_id): """ Get question answer for a given team based on its competition. """ + join_competition = Competition.id == Team.competition_id + join_team = Team.id == QuestionAnswer.team_id + filters = (Competition.id == competition_id) & (Team.id == team_id) + return QuestionAnswer.query.join(Competition, join_competition).join(Team, join_team).filter(filters).all() - join_filters = ( - (Team.competition_id == competition_id) - & (QuestionAnswer.team_id == Team.id) - & (QuestionAnswer.team_id == team_id) - ) - return QuestionAnswer.query.join(Team, join_filters).all() + +### Components ### +def component(competition_id, slide_id, component_id): + """ Gets a list of all component objects associated with a the provided competition id and slide order. """ + + join_competition = Competition.id == Slide.competition_id + join_slide = Slide.id == Component.slide_id + filters = (Competition.id == competition_id) & (Slide.id == slide_id) & (Component.id == component_id) + return Component.query.join(Competition, join_competition).join(Slide, join_slide).filter(filters).first_extended() + + +def component_list(competition_id, slide_id): + """ Gets a list of all component objects associated with a the provided competition id and slide order. """ + + join_competition = Competition.id == Slide.competition_id + join_slide = Slide.id == Component.slide_id + filters = (Competition.id == competition_id) & (Slide.id == slide_id) + return Component.query.join(Competition, join_competition).join(Slide, join_slide).filter(filters).all() ### Competitions ### @@ -173,13 +222,3 @@ def competition(competition_id): os2 = joinedload(Competition.slides).joinedload(Slide.questions).joinedload(Question.alternatives) ot = joinedload(Competition.teams).joinedload(Team.question_answers) return Competition.query.filter(Competition.id == competition_id).options(os1).options(os2).options(ot).first() - - -### Components ### -def component_list(competition_id, slide_order): - """ Gets a list of all component objects associated with a the provided competition id and slide order. """ - - join_filters = ( - (Slide.competition_id == competition_id) & (Slide.order == slide_order) & (Component.slide_id == Slide.id) - ) - return Component.query.join(Slide, join_filters).all() diff --git a/server/tests/test_app.py b/server/tests/test_app.py index cc50d4fd857082671158a3a4467d8adbb7e9914f..48e74c5a606fb9c2a04d66eb782f8ed1eba2a68c 100644 --- a/server/tests/test_app.py +++ b/server/tests/test_app.py @@ -84,8 +84,10 @@ def test_competition_api(client): assert response.status_code == codes.OK assert len(body["items"]) == 3 + """ response, body = put(client, f"/api/competitions/{competition_id}/slides/{2}/order", {"order": 1}, headers=headers) assert response.status_code == codes.OK + """ response, body = post(client, f"/api/competitions/{competition_id}/teams", {"name": "t1"}, headers=headers) assert response.status_code == codes.OK @@ -257,27 +259,22 @@ def test_slide_api(client): response, body = post(client, f"/api/competitions/{CID}/slides", headers=headers) assert response.status_code == codes.OK assert body["count"] == 4 - # Add another slide - response, body = post(client, f"/api/competitions/{CID}/slides", headers=headers) # Get slide - slide_order = 1 - response, item_slide = get(client, f"/api/competitions/{CID}/slides/{slide_order}", headers=headers) + slide_id = 2 + response, item_slide = get(client, f"/api/competitions/{CID}/slides/{slide_id}", headers=headers) assert response.status_code == codes.OK - assert item_slide["order"] == slide_order # Edit slide - order = 6 title = "Ny titel" body = "Ny body" timer = 43 - assert item_slide["order"] != order assert item_slide["title"] != title # assert item_slide["body"] != body assert item_slide["timer"] != timer response, item_slide = put( client, - f"/api/competitions/{CID}/slides/{slide_order}", + f"/api/competitions/{CID}/slides/{slide_id}", # TODO: Implement so these commented lines can be edited # {"order": order, "title": title, "body": body, "timer": timer}, {"title": title, "timer": timer}, @@ -290,31 +287,40 @@ def test_slide_api(client): assert item_slide["timer"] == timer # Delete slide - response, _ = delete(client, f"/api/competitions/{CID}/slides/{slide_order}", headers=headers) + response, _ = delete(client, f"/api/competitions/{CID}/slides/{slide_id}", headers=headers) assert response.status_code == codes.NO_CONTENT # Checks that there are fewer slides response, body = get(client, f"/api/competitions/{CID}/slides", headers=headers) assert response.status_code == codes.OK - assert body["count"] == 4 + assert body["count"] == 3 - # Tries to delete slide again, should work since the order is now changed - response, _ = delete(client, f"/api/competitions/{CID}/slides/{slide_order}", headers=headers) - assert response.status_code == codes.NO_CONTENT + # Tries to delete slide again, which will fail + response, _ = delete(client, f"/api/competitions/{CID}/slides/{slide_id}", headers=headers) + assert response.status_code != codes.OK + # Get all slides + response, body = get(client, f"/api/competitions/{CID}/slides", headers=headers) + assert response.status_code == codes.OK + assert body["count"] == 3 + assert body["items"][0]["id"] == 3 + assert body["items"][0]["order"] == 0 + slide_id = 3 + + """ # Changes the order to the same order - slide_order = body["items"][0]["order"] response, _ = put( - client, f"/api/competitions/{CID}/slides/{slide_order}/order", {"order": slide_order}, headers=headers + client, f"/api/competitions/{CID}/slides/{slide_id}/order", {"order": 0}, headers=headers ) assert response.status_code == codes.OK # Changes the order - change_order_test(client, CID, slide_order, slide_order + 1, headers) + change_order_test(client, CID, slide_id, slide_id + 1, headers) # Copies slide for _ in range(10): - response, _ = post(client, f"/api/competitions/{CID}/slides/{slide_order}/copy", headers=headers) + response, _ = post(client, f"/api/competitions/{CID}/slides/{slide_id}/copy", headers=headers) assert response.status_code == codes.OK + """ def test_question_api(client): @@ -342,7 +348,7 @@ def test_question_api(client): # Add question name = "Nytt namn" type_id = 2 - slide_order = 1 + slide_order = 6 response, item_question = post( client, f"/api/competitions/{CID}/slides/{slide_order}/questions", diff --git a/server/tests/test_helpers.py b/server/tests/test_helpers.py index 7a68655b5a0212012736b40627050dab81f86595..190e248c0ad358b077889df8b9e5052b16489a35 100644 --- a/server/tests/test_helpers.py +++ b/server/tests/test_helpers.py @@ -128,12 +128,14 @@ def assert_object_values(obj, values): # Changes order of slides -def change_order_test(client, cid, order, new_order, h): - response, new_order_body = get(client, f"/api/competitions/{cid}/slides/{new_order}", headers=h) +def change_order_test(client, cid, slide_id, new_slide_id, h): + response, new_order_body = get(client, f"/api/competitions/{cid}/slides/{new_slide_id}", headers=h) assert response.status_code == codes.OK - response, order_body = get(client, f"/api/competitions/{cid}/slides/{order}", headers=h) + response, order_body = get(client, f"/api/competitions/{cid}/slides/{slide_id}", headers=h) assert response.status_code == codes.OK + new_order = new_order_body["order"] + # Changes order - response, _ = put(client, f"/api/competitions/{cid}/slides/{order}/order", {"order": new_order}, headers=h) + response, _ = put(client, f"/api/competitions/{cid}/slides/{slide_id}/order", {"order": new_order}, headers=h) assert response.status_code == codes.OK