Skip to content
Snippets Groups Projects
Commit b0bf59fb authored by Victor Löfgren's avatar Victor Löfgren
Browse files

Add competitions api

parent 560af59d
No related branches found
No related tags found
1 merge request!161Resolve "replace-restx-with-smorest"
......@@ -139,9 +139,11 @@ flask_api = Api()
def init_api():
from .auth import blp as auth_blp
from .competitions import blp as competitions_blp
from .misc import blp as misc_blp
from .users import blp as user_blp
flask_api.register_blueprint(user_blp)
flask_api.register_blueprint(auth_blp)
flask_api.register_blueprint(competitions_blp)
flask_api.register_blueprint(misc_blp)
......@@ -4,101 +4,103 @@ Default route: /api/competitions
"""
import app.database.controller as dbc
from app.apis import item_response, list_response, protect_route
from app.core.dto import CompetitionDTO
from app.core.parsers import search_parser, sentinel
from app.apis import http_codes, protect_route
from app.core import ma
from app.core.rich_schemas import CompetitionSchemaRich
from app.core.schemas import BaseSchema, CompetitionSchema
from app.database import models
from app.database.models import Competition
from flask_restx import Resource, reqparse
from flask.views import MethodView
from flask_smorest import Blueprint, arguments
api = CompetitionDTO.api
schema = CompetitionDTO.schema
rich_schema = CompetitionDTO.rich_schema
list_schema = CompetitionDTO.list_schema
blp = Blueprint("competitions", "competitions", url_prefix="/api/competitions", description="Operations competitions")
competition_parser_add = reqparse.RequestParser()
competition_parser_add.add_argument("name", type=str, required=True, location="json")
competition_parser_add.add_argument("year", type=int, required=True, location="json")
competition_parser_add.add_argument("city_id", type=int, required=True, location="json")
competition_parser_edit = reqparse.RequestParser()
competition_parser_edit.add_argument("name", type=str, default=sentinel, location="json")
competition_parser_edit.add_argument("year", type=int, default=sentinel, location="json")
competition_parser_edit.add_argument("city_id", type=int, default=sentinel, location="json")
competition_parser_edit.add_argument("background_image_id", default=sentinel, type=int, location="json")
class CompetitionAddArgsSchema(BaseSchema):
class Meta(BaseSchema.Meta):
model = models.Competition
competition_parser_search = search_parser.copy()
competition_parser_search.add_argument("name", type=str, default=sentinel, location="args")
competition_parser_search.add_argument("year", type=int, default=sentinel, location="args")
competition_parser_search.add_argument("city_id", type=int, default=sentinel, location="args")
name = ma.auto_field()
year = ma.auto_field()
city_id = ma.auto_field()
@api.route("")
class CompetitionsList(Resource):
@protect_route(allowed_roles=["*"])
def post(self):
""" Posts a new competition. """
class CompetitionEditArgsSchema(BaseSchema):
class Meta(BaseSchema.Meta):
model = models.Competition
name = ma.auto_field(required=False)
year = ma.auto_field(required=False)
city_id = ma.auto_field(required=False)
background_image_id = ma.auto_field(required=False)
class CompetitionSearchArgsSchema(BaseSchema):
class Meta(BaseSchema.Meta):
model = models.Competition
args = competition_parser_add.parse_args(strict=True)
name = ma.auto_field(required=False)
year = ma.auto_field(required=False)
city_id = ma.auto_field(required=False)
background_image_id = ma.auto_field(required=False)
# Add competition
item = dbc.add.competition(**args)
# Add default slide
# dbc.add.slide(item.id)
return item_response(schema.dump(item))
@blp.route("")
class CompetitionsList(MethodView):
@protect_route(allowed_roles=["*"])
@blp.arguments(CompetitionAddArgsSchema)
@blp.response(http_codes.OK, CompetitionSchema)
@blp.alt_response(http_codes.CONFLICT, None, description="Competition could not be added")
def post(self, args):
""" Adds a new competition. """
return dbc.add.competition(**args)
@api.route("/<competition_id>")
@api.param("competition_id")
class Competitions(Resource):
@blp.route("/<competition_id>")
class Competitions(MethodView):
@protect_route(allowed_roles=["*"], allowed_views=["*"])
@blp.response(http_codes.OK, CompetitionSchemaRich)
@blp.alt_response(http_codes.NOT_FOUND, None, description="Competition not found")
def get(self, competition_id):
""" Gets the specified competition. """
item = dbc.get.competition(competition_id)
return item_response(rich_schema.dump(item))
return dbc.get.competition(competition_id)
@protect_route(allowed_roles=["*"])
def put(self, competition_id):
@blp.arguments(CompetitionEditArgsSchema)
@blp.response(http_codes.OK, CompetitionSchema)
@blp.alt_response(http_codes.NOT_FOUND, None, description="Competition not found")
@blp.alt_response(http_codes.CONFLICT, None, description="Competition could not be updated")
def put(self, args, competition_id):
""" Edits the specified competition with the specified arguments. """
args = competition_parser_edit.parse_args(strict=True)
item = dbc.get.one(Competition, competition_id)
item = dbc.edit.default(item, **args)
return item_response(schema.dump(item))
return dbc.edit.default(dbc.get.one(Competition, competition_id), **args)
@protect_route(allowed_roles=["*"])
@blp.response(http_codes.NO_CONTENT, None)
@blp.alt_response(http_codes.NOT_FOUND, None, description="Competition not found")
@blp.alt_response(http_codes.CONFLICT, None, description="Competition could not be deleted")
def delete(self, competition_id):
""" Deletes the specified competition. """
dbc.delete.competition(dbc.get.one(Competition, competition_id))
return None
item = dbc.get.one(Competition, competition_id)
dbc.delete.competition(item)
return "deleted"
@api.route("/search")
class CompetitionSearch(Resource):
@blp.route("/search")
class CompetitionSearch(MethodView):
@protect_route(allowed_roles=["*"])
def get(self):
@blp.arguments(CompetitionSearchArgsSchema, location="query")
@blp.paginate()
@blp.response(http_codes.OK, CompetitionSchema(many=True))
def get(self, args, pagination_parameters):
""" Finds a specific competition based on the provided arguments. """
args = competition_parser_search.parse_args(strict=True)
items, total = dbc.search.competition(**args)
return list_response(list_schema.dump(items), total)
return dbc.search.competition(pagination_parameters, **args)
@api.route("/<competition_id>/copy")
@api.param("competition_id")
class SlidesOrder(Resource):
@blp.route("/<competition_id>/copy")
class SlidesOrder(MethodView):
@protect_route(allowed_roles=["*"])
@blp.response(http_codes.OK, CompetitionSchema)
@blp.alt_response(http_codes.NOT_FOUND, None, description="Competition not found")
@blp.alt_response(http_codes.CONFLICT, None, description="Competition could not be copied")
def post(self, competition_id):
""" Creates a deep copy of the specified competition. """
item_competition = dbc.get.competition(competition_id)
item_competition_copy = dbc.copy.competition(item_competition)
return item_response(schema.dump(item_competition_copy))
return dbc.copy.competition(dbc.get.competition(competition_id))
......@@ -37,8 +37,8 @@ class UserEditArgsSchema(BaseSchema):
class Meta(BaseSchema.Meta):
model = models.User
name = ma.auto_field()
email = ma.auto_field()
name = ma.auto_field(required=False)
email = ma.auto_field(required=False)
role_id = ma.auto_field(required=False)
city_id = ma.auto_field(required=False)
......
......@@ -46,7 +46,7 @@ class ExtendedQuery(BaseQuery):
item = self.first()
if required and not item:
abort(error_code, error_message or "Object not found")
abort(error_code, message=error_message or "Objektet hittades inte")
return item
......
......@@ -3,7 +3,7 @@ This file contains functionality to copy and duplicate data to the database.
"""
from app.database.controller import add, get, search, utils
from app.database.models import Question
from app.database.models import Competition, Question
from app.database.types import IMAGE_COMPONENT_ID, QUESTION_COMPONENT_ID, TEXT_COMPONENT_ID
......@@ -115,9 +115,9 @@ def competition(item_competition_old):
"""
name = "Kopia av " + item_competition_old.name
item_competition, total = search.competition(name=name)
if item_competition:
name = "Kopia av " + item_competition[total - 1].name
while item_competition := Competition.query.filter(Competition.name == name).first():
name = "Kopia av " + item_competition.name
item_competition_new = add._competition_no_slides(
name,
......
......@@ -297,7 +297,7 @@ def component_list(competition_id, slide_id):
### Competitions ###
def competition(competition_id):
def competition(competition_id, required=True):
""" Get Competition and all it's sub-entities. """
join_component = joinedload(Competition.slides).subqueryload(Slide.components)
......@@ -310,5 +310,5 @@ def competition(competition_id):
.options(join_alternatives)
.options(join_question_alternative_answer)
.options(join_question_score)
.first()
.first_api(required, "Tävlingen kunde inte hittas")
)
......@@ -40,13 +40,10 @@ def user(
def competition(
pagination_parameters,
name=None,
year=None,
city_id=None,
page=0,
page_size=15,
order=1,
order_by=None,
):
""" Finds and returns a competition from the provided parameters. """
......@@ -58,11 +55,9 @@ def competition(
if city_id:
query = query.filter(Competition.city_id == city_id)
order_column = Competition.year # Default order_by
if order_by:
order_column = getattr(Competition.columns, order_by)
return query.pagination(page, page_size, order_column, order)
pagination = query.paginate(page=pagination_parameters.page, per_page=pagination_parameters.page_size)
pagination_parameters.item_count = pagination.total
return pagination.items
def slide(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment