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

Add api for competition codes

parent 0f4818a4
No related branches found
No related tags found
2 merge requests!63Resolve "Add components",!62Resolve "Use data from database in editor"
This commit is part of merge request !62. Comments created here will be created in the context of that merge request.
......@@ -43,6 +43,7 @@ def item_response(item, code=codes.OK):
from flask_restx import Api
from .auth import api as auth_ns
from .codes import api as code_ns
from .competitions import api as comp_ns
from .components import api as component_ns
from .media import api as media_ns
......@@ -60,5 +61,6 @@ 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/<CID>/slides")
flask_api.add_namespace(team_ns, path="/api/competitions/<CID>/teams")
flask_api.add_namespace(code_ns, path="/api/competitions/<CID>/codes")
flask_api.add_namespace(question_ns, path="/api/competitions/<CID>")
flask_api.add_namespace(component_ns, path="/api/competitions/<CID>/slides/<SID>/components/")
import app.core.http_codes as codes
import app.database.controller as dbc
from app.apis import admin_required, item_response, text_response
from app.core.dto import AuthDTO
from app.core.codes import verify_code
from app.core.dto import AuthDTO, CodeDTO
from app.core.parsers import create_user_parser, login_parser
from app.database.models import User
from flask_jwt_extended import (
......@@ -69,6 +70,20 @@ class AuthLogin(Resource):
return response
@api.route("/login/<code>")
@api.param("code")
class AuthLogin(Resource):
def post(self, code):
if not verify_code(code):
api.abort(codes.BAD_REQUEST, "Invalid code")
item_code = dbc.get.code_by_code(code)
if not item_code:
api.abort(codes.UNAUTHORIZED, "A presentation with that code does not exist")
return item_response(CodeDTO.schema.dump(item_code)), codes.OK
@api.route("/logout")
class AuthLogout(Resource):
@jwt_required
......
import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response
from app.core import http_codes as codes
from app.core.codes import generate_code
from app.core.dto import CodeDTO
from app.core.parsers import code_parser
from app.database.models import Competition
from flask_jwt_extended import jwt_required
from flask_restx import Resource
api = CodeDTO.api
schema = CodeDTO.schema
list_schema = CodeDTO.list_schema
@api.route("/")
@api.param("CID")
class CodesList(Resource):
@jwt_required
def get(self, CID):
items = dbc.get.code_list(CID)
return list_response(list_schema.dump(items), len(items)), codes.OK
@jwt_required
def post(self, CID):
args = code_parser.parse_args(strict=True)
item = dbc.add.code(**args)
return item_response(schema.dump(item)), codes.OK
@api.route("/<code_id>")
@api.param("CID, code_id")
class Competitions(Resource):
@jwt_required
def put(self, CID, code_id):
item_code = dbc.get.code(code_id)
item_code = dbc.edit.generate_new_code(item_code)
return item_response(schema.dump(item_code)), codes.OK
# @jwt_required
# def delete(self, CID, code_id):
# item_code = dbc.get.code(code_id)
# dbc.delete.code(item_code)
# return {}, http_codes.NOT_FOUND
import random
import re
import string
CODE_LENGTH = 6
ALLOWED_CHARS = string.ascii_uppercase + string.digits
CODE_RE = re.compile(f"^[{ALLOWED_CHARS}]{{{CODE_LENGTH}}}$")
def generate_code():
return "".join(random.choices(ALLOWED_CHARS, k=CODE_LENGTH))
def verify_code(c):
return CODE_RE.search(c.upper()) is not None
......@@ -37,6 +37,12 @@ class CompetitionDTO:
list_schema = schemas.CompetitionSchema(many=True)
class CodeDTO:
api = Namespace("codes")
schema = rich_schemas.CodeSchemaRich(many=False)
list_schema = schemas.CodeSchema(many=True)
class SlideDTO:
api = Namespace("slides")
schema = schemas.SlideSchema(many=False)
......
......@@ -60,6 +60,12 @@ question_parser.add_argument("total_score", type=int, default=None, location="js
question_parser.add_argument("type_id", type=int, default=None, location="json")
question_parser.add_argument("slide_id", type=int, location="json")
###QUESTION####
code_parser = reqparse.RequestParser()
code_parser.add_argument("pointer", type=str, default=None, location="json")
code_parser.add_argument("view_type_id", type=int, default=None, location="json")
###TEAM####
team_parser = reqparse.RequestParser()
team_parser.add_argument("name", type=str, location="json")
......
......@@ -43,6 +43,16 @@ class TeamSchemaRich(RichSchema):
question_answers = fields.Nested(schemas.QuestionAnswerSchema, many=True)
class CodeSchemaRich(RichSchema):
class Meta(RichSchema.Meta):
model = models.Code
id = ma.auto_field()
code = ma.auto_field()
pointer = ma.auto_field()
view_type = fields.Nested(schemas.ViewTypeSchema, many=False)
class SlideSchemaRich(RichSchema):
class Meta(RichSchema.Meta):
model = models.Slide
......
......@@ -31,6 +31,16 @@ class ComponentTypeSchema(IdNameSchema):
model = models.ComponentType
class CodeSchema(IdNameSchema):
class Meta(BaseSchema.Meta):
model = models.Code
id = ma.auto_field()
code = ma.auto_field()
pointer = ma.auto_field()
view_type_id = ma.auto_field()
class ViewTypeSchema(IdNameSchema):
class Meta(BaseSchema.Meta):
model = models.ViewType
......
import app.core.http_codes as codes
from app.core import db
from app.core.codes import generate_code
from app.database.models import (
Blacklist,
City,
Code,
Competition,
Component,
ComponentType,
......@@ -75,6 +77,11 @@ def team(name, item_competition):
return Team(name, item_competition.id)
@db_add
def code(pointer, view_type_id):
return Code(pointer, view_type_id)
@db_add
def mediaType(name):
return MediaType(name)
......
from app.core import db
from app.core.codes import generate_code
from app.database.models import Code
def switch_order(item1, item2):
......@@ -109,3 +111,16 @@ def question(item_question, name=None, total_score=None, type_id=None, slide_id=
db.session.refresh(item_question)
return item_question
def generate_new_code(item_code):
code = generate_code()
while db.session.query(Code).filter(Code.code == code).count():
code = generate_code()
item_code.code = code
db.session.commit()
db.session.refresh(item_code)
return item_code
from app.core import db
from app.database.models import (
City,
Code,
Competition,
Component,
ComponentType,
......@@ -11,8 +12,11 @@ from app.database.models import (
Slide,
Team,
User,
ViewType,
)
team_view_id = ViewType.query.filter(ViewType.name == "Team").one().id
def all(db_type):
return db_type.query.all()
......@@ -34,6 +38,25 @@ def competition(CID, required=True, error_msg=None):
return Competition.query.filter(Competition.id == CID).first_extended(required, error_msg)
def code(code_id, required=True, error_msg=None):
return Code.query.filter(Code.id == code_id).first_extended(required, error_msg)
def code_by_code(code):
return Code.query.filter(Code.code == code.upper()).first()
def code_list(competition_id):
return (
Code.query.join(Team, (Code.view_type_id == team_view_id) & (Team.id == Code.pointer), isouter=True)
.filter(
((Code.view_type_id != team_view_id) & (Code.pointer == competition_id))
| ((Code.view_type_id == team_view_id) & (competition_id == Team.competition_id))
)
.all()
)
def user(UID, required=True, error_msg=None):
return User.query.filter(User.id == UID).first_extended(required, error_msg)
......
import json
from app.core import bcrypt, db
from app.core.codes import generate_code
from sqlalchemy.ext.hybrid import hybrid_method, hybrid_property
from sqlalchemy.orm import backref
from sqlalchemy.types import TypeDecorator
......@@ -230,7 +231,12 @@ class Code(db.Model):
view_type_id = db.Column(db.Integer, db.ForeignKey("view_type.id"), nullable=False)
def __init__(self, code, pointer, view_type_id):
def __init__(self, pointer, view_type_id):
code = generate_code()
while db.session.query(Code).filter(Code.code == code).count():
code = generate_code()
self.code = code
self.pointer = pointer
self.view_type_id = view_type_id
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment