Skip to content
Snippets Groups Projects
Commit a0618abb authored by Carl Schönfelder's avatar Carl Schönfelder
Browse files

Resolve "Fix api response"

parent 833fe128
No related branches found
No related tags found
1 merge request!73Resolve "Fix api response"
Pipeline #41338 passed with warnings
Showing
with 182 additions and 118 deletions
...@@ -7,4 +7,4 @@ htmlcov ...@@ -7,4 +7,4 @@ htmlcov
.pytest_cache .pytest_cache
/.idea /.idea
.vs/ .vs/
*/static **/static
\ No newline at end of file \ No newline at end of file
...@@ -17239,7 +17239,8 @@ ...@@ -17239,7 +17239,8 @@
}, },
"ssri": { "ssri": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
"requires": { "requires": {
"figgy-pudding": "^3.5.1" "figgy-pudding": "^3.5.1"
} }
......
...@@ -7,7 +7,7 @@ from app.core.dto import MediaDTO ...@@ -7,7 +7,7 @@ from app.core.dto import MediaDTO
def create_app(config_name="configmodule.DevelopmentConfig"): def create_app(config_name="configmodule.DevelopmentConfig"):
app = Flask(__name__) app = Flask(__name__, static_url_path="/static", static_folder="static")
app.config.from_object(config_name) app.config.from_object(config_name)
app.url_map.strict_slashes = False app.url_map.strict_slashes = False
with app.app_context(): with app.app_context():
......
from functools import wraps from functools import wraps
import app.core.http_codes as codes import app.core.http_codes as http_codes
from flask_jwt_extended import verify_jwt_in_request from flask_jwt_extended import verify_jwt_in_request
from flask_jwt_extended.utils import get_jwt_claims from flask_jwt_extended.utils import get_jwt_claims
from flask_restx.errors import abort from flask_restx.errors import abort
def admin_required(): def validate_editor(db_item, *views):
claims = get_jwt_claims()
city_id = int(claims.get("city_id"))
if db_item.city_id != city_id:
abort(http_codes.UNAUTHORIZED)
def check_jwt(editor=False, *views):
def wrapper(fn): def wrapper(fn):
@wraps(fn) @wraps(fn)
def decorator(*args, **kwargs): def decorator(*args, **kwargs):
verify_jwt_in_request() verify_jwt_in_request()
claims = get_jwt_claims() claims = get_jwt_claims()
if claims["role"] == "Admin": role = claims.get("role")
view = claims.get("view")
if role == "Admin":
return fn(*args, **kwargs)
elif editor and role == "Editor":
return fn(*args, **kwargs)
elif view in views:
return fn(*args, **kwargs) return fn(*args, **kwargs)
else: else:
return {"message:": "Admins only"}, codes.FORBIDDEN abort(http_codes.UNAUTHORIZED)
return decorator return decorator
return wrapper return wrapper
def text_response(message, code=codes.OK): def text_response(message, code=http_codes.OK):
return {"message": message}, code return {"message": message}, code
def list_response(items, total=None, code=codes.OK): def list_response(items, total=None, code=http_codes.OK):
if type(items) is not list: if type(items) is not list:
abort(codes.INTERNAL_SERVER_ERROR) abort(http_codes.INTERNAL_SERVER_ERROR)
if not total: if not total:
total = len(items) total = len(items)
return {"items": items, "count": len(items), "total_count": total}, code return {"items": items, "count": len(items), "total_count": total}, code
def item_response(item, code=codes.OK): def item_response(item, code=http_codes.OK):
if isinstance(item, list): if isinstance(item, list):
abort(codes.INTERNAL_SERVER_ERROR) abort(http_codes.INTERNAL_SERVER_ERROR)
return item, code return item, code
......
import app.core.http_codes as codes import app.core.http_codes as codes
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, text_response from app.apis import check_jwt, item_response, text_response
from app.core.codes import verify_code from app.core.codes import verify_code
from app.core.dto import AuthDTO, CodeDTO from app.core.dto import AuthDTO, CodeDTO
from app.core.parsers import create_user_parser, login_parser from app.core.parsers import create_user_parser, login_code_parser, login_parser
from app.database.models import User from app.database.models import User
from flask_jwt_extended import ( from flask_jwt_extended import (
create_access_token, create_access_token,
...@@ -21,12 +21,12 @@ list_schema = AuthDTO.list_schema ...@@ -21,12 +21,12 @@ list_schema = AuthDTO.list_schema
def get_user_claims(item_user): def get_user_claims(item_user):
return {"role": item_user.role.name, "city": item_user.city.name} return {"role": item_user.role.name, "city_id": item_user.city_id}
@api.route("/signup") @api.route("/signup")
class AuthSignup(Resource): class AuthSignup(Resource):
@jwt_required @check_jwt(editor=False)
def post(self): def post(self):
args = create_user_parser.parse_args(strict=True) args = create_user_parser.parse_args(strict=True)
email = args.get("email") email = args.get("email")
...@@ -41,7 +41,7 @@ class AuthSignup(Resource): ...@@ -41,7 +41,7 @@ class AuthSignup(Resource):
@api.route("/delete/<ID>") @api.route("/delete/<ID>")
@api.param("ID") @api.param("ID")
class AuthDelete(Resource): class AuthDelete(Resource):
@jwt_required @check_jwt(editor=False)
def delete(self, ID): def delete(self, ID):
item_user = dbc.get.user(ID) item_user = dbc.get.user(ID)
...@@ -70,23 +70,22 @@ class AuthLogin(Resource): ...@@ -70,23 +70,22 @@ class AuthLogin(Resource):
return response return response
@api.route("/login/<code>") @api.route("/login/code")
@api.param("code") class AuthLoginCode(Resource):
class AuthLogin(Resource): def post(self):
def post(self, code): args = login_code_parser.parse_args()
code = args["code"]
if not verify_code(code): if not verify_code(code):
api.abort(codes.BAD_REQUEST, "Invalid code") api.abort(codes.BAD_REQUEST, "Invalid code")
item_code = dbc.get.code_by_code(code) item_code = dbc.get.code_by_code(code, True, "A presentation with that code does not exist")
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 return item_response(CodeDTO.schema.dump(item_code)), codes.OK
@api.route("/logout") @api.route("/logout")
class AuthLogout(Resource): class AuthLogout(Resource):
@jwt_required @check_jwt(editor=True)
def post(self): def post(self):
jti = get_raw_jwt()["jti"] jti = get_raw_jwt()["jti"]
dbc.add.blacklist(jti) dbc.add.blacklist(jti)
...@@ -95,7 +94,7 @@ class AuthLogout(Resource): ...@@ -95,7 +94,7 @@ class AuthLogout(Resource):
@api.route("/refresh") @api.route("/refresh")
class AuthRefresh(Resource): class AuthRefresh(Resource):
@jwt_required @check_jwt(editor=True)
@jwt_refresh_token_required @jwt_refresh_token_required
def post(self): def post(self):
old_jti = get_raw_jwt()["jti"] old_jti = get_raw_jwt()["jti"]
......
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response from app.apis import item_response, list_response
from app.core import http_codes as codes from app.core import http_codes as codes
from app.core.dto import CodeDTO from app.core.dto import CodeDTO
from app.core.parsers import code_parser from app.core.parsers import code_parser
from app.database.models import Code, Competition from app.database.models import Code, Competition
from flask_jwt_extended import jwt_required from flask_jwt_extended import jwt_required
from flask_restx import Resource from flask_restx import Resource
from app.apis import check_jwt
api = CodeDTO.api api = CodeDTO.api
schema = CodeDTO.schema schema = CodeDTO.schema
...@@ -15,7 +16,7 @@ list_schema = CodeDTO.list_schema ...@@ -15,7 +16,7 @@ list_schema = CodeDTO.list_schema
@api.route("/") @api.route("/")
@api.param("CID") @api.param("CID")
class CodesList(Resource): class CodesList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, CID): def get(self, CID):
items = dbc.get.code_list(CID) items = dbc.get.code_list(CID)
return list_response(list_schema.dump(items), len(items)), codes.OK return list_response(list_schema.dump(items), len(items)), codes.OK
...@@ -24,7 +25,7 @@ class CodesList(Resource): ...@@ -24,7 +25,7 @@ class CodesList(Resource):
@api.route("/<code_id>") @api.route("/<code_id>")
@api.param("CID, code_id") @api.param("CID, code_id")
class CodesById(Resource): class CodesById(Resource):
@jwt_required @check_jwt(editor=False)
def put(self, CID, code_id): def put(self, CID, code_id):
item = dbc.get.one(Code, code_id) item = dbc.get.one(Code, code_id)
item.code = dbc.utils.generate_unique_code() item.code = dbc.utils.generate_unique_code()
......
import time
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response from app.apis import check_jwt, item_response, list_response
from app.core import rich_schemas
from app.core.dto import CompetitionDTO from app.core.dto import CompetitionDTO
from app.core.parsers import competition_parser, competition_search_parser from app.core.parsers import competition_parser, competition_search_parser
from app.database.models import Competition from app.database.models import Competition
...@@ -8,12 +11,13 @@ from flask_restx import Resource ...@@ -8,12 +11,13 @@ from flask_restx import Resource
api = CompetitionDTO.api api = CompetitionDTO.api
schema = CompetitionDTO.schema schema = CompetitionDTO.schema
rich_schema = CompetitionDTO.rich_schema
list_schema = CompetitionDTO.list_schema list_schema = CompetitionDTO.list_schema
@api.route("/") @api.route("/")
class CompetitionsList(Resource): class CompetitionsList(Resource):
@jwt_required @check_jwt(editor=True)
def post(self): def post(self):
args = competition_parser.parse_args(strict=True) args = competition_parser.parse_args(strict=True)
...@@ -28,12 +32,13 @@ class CompetitionsList(Resource): ...@@ -28,12 +32,13 @@ class CompetitionsList(Resource):
@api.route("/<CID>") @api.route("/<CID>")
@api.param("CID") @api.param("CID")
class Competitions(Resource): class Competitions(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, CID): def get(self, CID):
item = dbc.get.one(Competition, CID) item = dbc.get.competition(CID)
return item_response(schema.dump(item))
return item_response(rich_schema.dump(item))
@jwt_required @check_jwt(editor=True)
def put(self, CID): def put(self, CID):
args = competition_parser.parse_args(strict=True) args = competition_parser.parse_args(strict=True)
item = dbc.get.one(Competition, CID) item = dbc.get.one(Competition, CID)
...@@ -41,7 +46,7 @@ class Competitions(Resource): ...@@ -41,7 +46,7 @@ class Competitions(Resource):
return item_response(schema.dump(item)) return item_response(schema.dump(item))
@jwt_required @check_jwt(editor=True)
def delete(self, CID): def delete(self, CID):
item = dbc.get.one(Competition, CID) item = dbc.get.one(Competition, CID)
dbc.delete.competition(item) dbc.delete.competition(item)
...@@ -51,7 +56,7 @@ class Competitions(Resource): ...@@ -51,7 +56,7 @@ class Competitions(Resource):
@api.route("/search") @api.route("/search")
class CompetitionSearch(Resource): class CompetitionSearch(Resource):
@jwt_required @check_jwt(editor=True)
def get(self): def get(self):
args = competition_search_parser.parse_args(strict=True) args = competition_search_parser.parse_args(strict=True)
items, total = dbc.search.competition(**args) items, total = dbc.search.competition(**args)
......
import app.core.http_codes as codes import app.core.http_codes as codes
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response from app.apis import check_jwt, item_response, list_response
from app.core.dto import ComponentDTO from app.core.dto import ComponentDTO
from app.core.parsers import component_create_parser, component_parser from app.core.parsers import component_create_parser, component_parser
from app.database.models import Competition, Component from app.database.models import Competition, Component
...@@ -16,19 +16,19 @@ list_schema = ComponentDTO.list_schema ...@@ -16,19 +16,19 @@ list_schema = ComponentDTO.list_schema
@api.route("/<component_id>") @api.route("/<component_id>")
@api.param("CID, SOrder, component_id") @api.param("CID, SOrder, component_id")
class ComponentByID(Resource): class ComponentByID(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, CID, SOrder, component_id): def get(self, CID, SOrder, component_id):
item = dbc.get.one(Component, component_id) item = dbc.get.one(Component, component_id)
return item_response(schema.dump(item)) return item_response(schema.dump(item))
@jwt_required @check_jwt(editor=True)
def put(self, CID, SOrder, component_id): def put(self, CID, SOrder, component_id):
args = component_parser.parse_args() args = component_parser.parse_args()
item = dbc.get.one(Component, component_id) item = dbc.get.one(Component, component_id)
item = dbc.edit.component(item, **args) item = dbc.edit.component(item, **args)
return item_response(schema.dump(item)) return item_response(schema.dump(item))
@jwt_required @check_jwt(editor=True)
def delete(self, CID, SOrder, component_id): def delete(self, CID, SOrder, component_id):
item = dbc.get.one(Component, component_id) item = dbc.get.one(Component, component_id)
dbc.delete.component(item) dbc.delete.component(item)
...@@ -38,12 +38,12 @@ class ComponentByID(Resource): ...@@ -38,12 +38,12 @@ class ComponentByID(Resource):
@api.route("/") @api.route("/")
@api.param("CID, SOrder") @api.param("CID, SOrder")
class ComponentList(Resource): class ComponentList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, CID, SOrder): def get(self, CID, SOrder):
items = dbc.get.component_list(SOrder) items = dbc.get.component_list(CID, SOrder)
return list_response(list_schema.dump(items)) return list_response(list_schema.dump(items))
@jwt_required @check_jwt(editor=True)
def post(self, CID, SOrder): def post(self, CID, SOrder):
args = component_create_parser.parse_args() args = component_create_parser.parse_args()
item_slide = dbc.get.slide(CID, SOrder) item_slide = dbc.get.slide(CID, SOrder)
......
import os
import app.core.http_codes as codes import app.core.http_codes as codes
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response from app.apis import check_jwt, item_response, list_response
from app.core.dto import MediaDTO from app.core.dto import MediaDTO
from app.core.parsers import media_parser_search from app.core.parsers import media_parser_search
from app.database.models import City, Media, MediaType, QuestionType, Role from app.database.models import City, Media, MediaType, QuestionType, Role
from flask import request from flask import current_app, request
from flask_jwt_extended import get_jwt_identity, jwt_required from flask_jwt_extended import get_jwt_identity, jwt_required
from flask_restx import Resource, reqparse from flask_restx import Resource, reqparse
from flask_uploads import UploadNotAllowed from flask_uploads import UploadNotAllowed
from PIL import Image from PIL import Image
from sqlalchemy import exc
api = MediaDTO.api api = MediaDTO.api
image_set = MediaDTO.image_set image_set = MediaDTO.image_set
schema = MediaDTO.schema schema = MediaDTO.schema
list_schema = MediaDTO.list_schema list_schema = MediaDTO.list_schema
PHOTO_PATH = current_app.config["UPLOADED_PHOTOS_DEST"]
def generate_thumbnail(filename): def generate_thumbnail(filename):
with Image.open(f"./static/images/{filename}") as im: thumbnail_size = current_app.config["THUMBNAIL_SIZE"]
im.thumbnail((120, 120)) path = os.path.join(PHOTO_PATH, filename)
im.save(f"./static/images/thumbnail_{filename}") thumb_path = os.path.join(PHOTO_PATH, f"thumbnail_{filename}")
with Image.open(path) as im:
im.thumbnail(thumbnail_size)
im.save(thumb_path)
def delete_image(filename):
path = os.path.join(PHOTO_PATH, filename)
thumb_path = os.path.join(PHOTO_PATH, f"thumbnail_{filename}")
os.remove(path)
os.remove(thumb_path)
@api.route("/images") @api.route("/images")
class ImageList(Resource): class ImageList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self): def get(self):
args = media_parser_search.parse_args(strict=True) args = media_parser_search.parse_args(strict=True)
items, total = dbc.search.image(**args) items, total = dbc.search.image(**args)
return list_response(list_schema.dump(items), total) return list_response(list_schema.dump(items), total)
@jwt_required @check_jwt(editor=True)
def post(self): def post(self):
if "image" not in request.files: if "image" not in request.files:
api.abort(codes.BAD_REQUEST, "Missing image in request.files") api.abort(codes.BAD_REQUEST, "Missing image in request.files")
try: try:
filename = image_set.save(request.files["image"]) filename = image_set.save(request.files["image"])
generate_thumbnail(filename) generate_thumbnail(filename)
print(filename) print(filename)
item = dbc.add.image(filename, get_jwt_identity()) item = dbc.add.image(filename, get_jwt_identity())
return item_response(schema.dump(item))
except UploadNotAllowed: except UploadNotAllowed:
api.abort(codes.BAD_REQUEST, "Could not save the image") api.abort(codes.BAD_REQUEST, "Could not save the image")
except: except:
api.abort(codes.INTERNAL_SERVER_ERROR, "Something went wrong when trying to save image") api.abort(codes.INTERNAL_SERVER_ERROR, "Something went wrong when trying to save image")
finally:
return item_response(schema.dump(item))
@api.route("/images/<ID>")
@api.param("ID")
class ImageList(Resource):
@check_jwt(editor=True)
def get(self, ID):
item = dbc.get.one(Media, ID)
return item_response(schema.dump(item))
@check_jwt(editor=True)
def delete(self, ID):
item = dbc.get.one(Media, ID)
try:
delete_image(item.filename)
dbc.delete.default(item)
except OSError:
api.abort(codes.BAD_REQUEST, "Could not delete the file image")
except exc.SQLAlchemyError:
api.abort(codes.INTERNAL_SERVER_ERROR, "Something went wrong when trying to delete image")
finally:
return {}, codes.NO_CONTENT
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response from app.apis import check_jwt, item_response, list_response
from app.core.dto import MiscDTO from app.core.dto import MiscDTO
from app.database.models import City, ComponentType, MediaType, QuestionType, Role, ViewType from app.database.models import City, ComponentType, MediaType, QuestionType, Role, ViewType
from flask_jwt_extended import jwt_required
from flask_restx import Resource, reqparse from flask_restx import Resource, reqparse
api = MiscDTO.api api = MiscDTO.api
...@@ -22,7 +21,7 @@ name_parser.add_argument("name", type=str, required=True, location="json") ...@@ -22,7 +21,7 @@ name_parser.add_argument("name", type=str, required=True, location="json")
@api.route("/types") @api.route("/types")
class TypesList(Resource): class TypesList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self): def get(self):
result = {} result = {}
result["media_types"] = media_type_schema.dump(dbc.get.all(MediaType)) result["media_types"] = media_type_schema.dump(dbc.get.all(MediaType))
...@@ -34,7 +33,7 @@ class TypesList(Resource): ...@@ -34,7 +33,7 @@ class TypesList(Resource):
@api.route("/roles") @api.route("/roles")
class RoleList(Resource): class RoleList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self): def get(self):
items = dbc.get.all(Role) items = dbc.get.all(Role)
return list_response(role_schema.dump(items)) return list_response(role_schema.dump(items))
...@@ -42,12 +41,12 @@ class RoleList(Resource): ...@@ -42,12 +41,12 @@ class RoleList(Resource):
@api.route("/cities") @api.route("/cities")
class CitiesList(Resource): class CitiesList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self): def get(self):
items = dbc.get.all(City) items = dbc.get.all(City)
return list_response(city_schema.dump(items)) return list_response(city_schema.dump(items))
@jwt_required @check_jwt(editor=False)
def post(self): def post(self):
args = name_parser.parse_args(strict=True) args = name_parser.parse_args(strict=True)
dbc.add.city(args["name"]) dbc.add.city(args["name"])
...@@ -58,7 +57,7 @@ class CitiesList(Resource): ...@@ -58,7 +57,7 @@ class CitiesList(Resource):
@api.route("/cities/<ID>") @api.route("/cities/<ID>")
@api.param("ID") @api.param("ID")
class Cities(Resource): class Cities(Resource):
@jwt_required @check_jwt(editor=False)
def put(self, ID): def put(self, ID):
item = dbc.get.one(City, ID) item = dbc.get.one(City, ID)
args = name_parser.parse_args(strict=True) args = name_parser.parse_args(strict=True)
...@@ -67,7 +66,7 @@ class Cities(Resource): ...@@ -67,7 +66,7 @@ class Cities(Resource):
items = dbc.get.all(City) items = dbc.get.all(City)
return list_response(city_schema.dump(items)) return list_response(city_schema.dump(items))
@jwt_required @check_jwt(editor=False)
def delete(self, ID): def delete(self, ID):
item = dbc.get.one(City, ID) item = dbc.get.one(City, ID)
dbc.delete.default(item) dbc.delete.default(item)
......
import app.core.http_codes as codes import app.core.http_codes as codes
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response from app.apis import check_jwt, item_response, list_response
from app.core.dto import QuestionDTO from app.core.dto import QuestionDTO
from app.core.parsers import question_parser from app.core.parsers import question_parser
from app.database.models import Question from app.database.models import Question
...@@ -15,7 +15,7 @@ list_schema = QuestionDTO.list_schema ...@@ -15,7 +15,7 @@ list_schema = QuestionDTO.list_schema
@api.route("/questions") @api.route("/questions")
@api.param("CID") @api.param("CID")
class QuestionsList(Resource): class QuestionsList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, CID): def get(self, CID):
items = dbc.get.question_list(CID) items = dbc.get.question_list(CID)
return list_response(list_schema.dump(items)) return list_response(list_schema.dump(items))
...@@ -24,7 +24,7 @@ class QuestionsList(Resource): ...@@ -24,7 +24,7 @@ class QuestionsList(Resource):
@api.route("/slides/<SID>/questions") @api.route("/slides/<SID>/questions")
@api.param("CID, SID") @api.param("CID, SID")
class QuestionsList(Resource): class QuestionsList(Resource):
@jwt_required @check_jwt(editor=True)
def post(self, SID, CID): def post(self, SID, CID):
args = question_parser.parse_args(strict=True) args = question_parser.parse_args(strict=True)
del args["slide_id"] del args["slide_id"]
...@@ -38,12 +38,12 @@ class QuestionsList(Resource): ...@@ -38,12 +38,12 @@ class QuestionsList(Resource):
@api.route("/slides/<SID>/questions/<QID>") @api.route("/slides/<SID>/questions/<QID>")
@api.param("CID, SID, QID") @api.param("CID, SID, QID")
class Questions(Resource): class Questions(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, CID, SID, QID): def get(self, CID, SID, QID):
item_question = dbc.get.question(CID, SID, QID) item_question = dbc.get.question(CID, SID, QID)
return item_response(schema.dump(item_question)) return item_response(schema.dump(item_question))
@jwt_required @check_jwt(editor=True)
def put(self, CID, SID, QID): def put(self, CID, SID, QID):
args = question_parser.parse_args(strict=True) args = question_parser.parse_args(strict=True)
...@@ -52,7 +52,7 @@ class Questions(Resource): ...@@ -52,7 +52,7 @@ class Questions(Resource):
return item_response(schema.dump(item_question)) return item_response(schema.dump(item_question))
@jwt_required @check_jwt(editor=True)
def delete(self, CID, SID, QID): def delete(self, CID, SID, QID):
item_question = dbc.get.question(CID, SID, QID) item_question = dbc.get.question(CID, SID, QID)
dbc.delete.question(item_question) dbc.delete.question(item_question)
......
import app.core.http_codes as codes import app.core.http_codes as codes
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response from app.apis import check_jwt, item_response, list_response
from app.core.dto import SlideDTO from app.core.dto import SlideDTO
from app.core.parsers import slide_parser from app.core.parsers import slide_parser
from app.database.models import Competition, Slide from app.database.models import Competition, Slide
...@@ -15,12 +15,12 @@ list_schema = SlideDTO.list_schema ...@@ -15,12 +15,12 @@ list_schema = SlideDTO.list_schema
@api.route("/") @api.route("/")
@api.param("CID") @api.param("CID")
class SlidesList(Resource): class SlidesList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, CID): def get(self, CID):
items = dbc.get.slide_list(CID) items = dbc.get.slide_list(CID)
return list_response(list_schema.dump(items)) return list_response(list_schema.dump(items))
@jwt_required @check_jwt(editor=True)
def post(self, CID): def post(self, CID):
item_comp = dbc.get.one(Competition, CID) item_comp = dbc.get.one(Competition, CID)
item_slide = dbc.add.slide(item_comp) item_slide = dbc.add.slide(item_comp)
...@@ -32,12 +32,12 @@ class SlidesList(Resource): ...@@ -32,12 +32,12 @@ class SlidesList(Resource):
@api.route("/<SOrder>") @api.route("/<SOrder>")
@api.param("CID,SOrder") @api.param("CID,SOrder")
class Slides(Resource): class Slides(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, CID, SOrder): def get(self, CID, SOrder):
item_slide = dbc.get.slide(CID, SOrder) item_slide = dbc.get.slide(CID, SOrder)
return item_response(schema.dump(item_slide)) return item_response(schema.dump(item_slide))
@jwt_required @check_jwt(editor=True)
def put(self, CID, SOrder): def put(self, CID, SOrder):
args = slide_parser.parse_args(strict=True) args = slide_parser.parse_args(strict=True)
title = args.get("title") title = args.get("title")
...@@ -48,7 +48,7 @@ class Slides(Resource): ...@@ -48,7 +48,7 @@ class Slides(Resource):
return item_response(schema.dump(item_slide)) return item_response(schema.dump(item_slide))
@jwt_required @check_jwt(editor=True)
def delete(self, CID, SOrder): def delete(self, CID, SOrder):
item_slide = dbc.get.slide(CID, SOrder) item_slide = dbc.get.slide(CID, SOrder)
...@@ -59,7 +59,7 @@ class Slides(Resource): ...@@ -59,7 +59,7 @@ class Slides(Resource):
@api.route("/<SOrder>/order") @api.route("/<SOrder>/order")
@api.param("CID,SOrder") @api.param("CID,SOrder")
class SlidesOrder(Resource): class SlidesOrder(Resource):
@jwt_required @check_jwt(editor=True)
def put(self, CID, SOrder): def put(self, CID, SOrder):
args = slide_parser.parse_args(strict=True) args = slide_parser.parse_args(strict=True)
order = args.get("order") order = args.get("order")
......
import app.core.http_codes as codes import app.core.http_codes as codes
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response from app.apis import check_jwt, item_response, list_response
from app.core.dto import TeamDTO from app.core.dto import TeamDTO
from app.core.parsers import team_parser from app.core.parsers import team_parser
from app.database.models import Competition, Team from app.database.models import Competition, Team
...@@ -15,12 +15,12 @@ list_schema = TeamDTO.list_schema ...@@ -15,12 +15,12 @@ list_schema = TeamDTO.list_schema
@api.route("/") @api.route("/")
@api.param("CID") @api.param("CID")
class TeamsList(Resource): class TeamsList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, CID): def get(self, CID):
items = dbc.get.team_list(CID) items = dbc.get.team_list(CID)
return list_response(list_schema.dump(items)) return list_response(list_schema.dump(items))
@jwt_required @check_jwt(editor=True)
def post(self, CID): def post(self, CID):
args = team_parser.parse_args(strict=True) args = team_parser.parse_args(strict=True)
item_comp = dbc.get.one(Competition, CID) item_comp = dbc.get.one(Competition, CID)
...@@ -32,11 +32,13 @@ class TeamsList(Resource): ...@@ -32,11 +32,13 @@ class TeamsList(Resource):
@api.param("CID,TID") @api.param("CID,TID")
class Teams(Resource): class Teams(Resource):
@jwt_required @jwt_required
@check_jwt(editor=True)
def get(self, CID, TID): def get(self, CID, TID):
item = dbc.get.team(CID, TID) item = dbc.get.team(CID, TID)
return item_response(schema.dump(item)) return item_response(schema.dump(item))
@jwt_required @jwt_required
@check_jwt(editor=True)
def delete(self, CID, TID): def delete(self, CID, TID):
item_team = dbc.get.team(CID, TID) item_team = dbc.get.team(CID, TID)
...@@ -44,6 +46,7 @@ class Teams(Resource): ...@@ -44,6 +46,7 @@ class Teams(Resource):
return {}, codes.NO_CONTENT return {}, codes.NO_CONTENT
@jwt_required @jwt_required
@check_jwt(editor=True)
def put(self, CID, TID): def put(self, CID, TID):
args = team_parser.parse_args(strict=True) args = team_parser.parse_args(strict=True)
name = args.get("name") name = args.get("name")
......
import app.core.http_codes as codes import app.core.http_codes as codes
import app.database.controller as dbc import app.database.controller as dbc
from app.apis import admin_required, item_response, list_response from app.apis import check_jwt, item_response, list_response
from app.core.dto import UserDTO from app.core.dto import UserDTO
from app.core.parsers import user_parser, user_search_parser from app.core.parsers import user_parser, user_search_parser
from app.database.models import User from app.database.models import User
...@@ -24,12 +24,12 @@ def edit_user(item_user, args): ...@@ -24,12 +24,12 @@ def edit_user(item_user, args):
@api.route("/") @api.route("/")
class UsersList(Resource): class UsersList(Resource):
@jwt_required @check_jwt(editor=True)
def get(self): def get(self):
item = dbc.get.user(get_jwt_identity()) item = dbc.get.user(get_jwt_identity())
return item_response(schema.dump(item)) return item_response(schema.dump(item))
@jwt_required @check_jwt(editor=True)
def put(self): def put(self):
args = user_parser.parse_args(strict=True) args = user_parser.parse_args(strict=True)
item = dbc.get.user(get_jwt_identity()) item = dbc.get.user(get_jwt_identity())
...@@ -40,12 +40,12 @@ class UsersList(Resource): ...@@ -40,12 +40,12 @@ class UsersList(Resource):
@api.route("/<ID>") @api.route("/<ID>")
@api.param("ID") @api.param("ID")
class Users(Resource): class Users(Resource):
@jwt_required @check_jwt(editor=True)
def get(self, ID): def get(self, ID):
item = dbc.get.user(ID) item = dbc.get.user(ID)
return item_response(schema.dump(item)) return item_response(schema.dump(item))
@jwt_required @check_jwt(editor=False)
def put(self, ID): def put(self, ID):
args = user_parser.parse_args(strict=True) args = user_parser.parse_args(strict=True)
item = dbc.get.user(ID) item = dbc.get.user(ID)
...@@ -55,7 +55,7 @@ class Users(Resource): ...@@ -55,7 +55,7 @@ class Users(Resource):
@api.route("/search") @api.route("/search")
class UserSearch(Resource): class UserSearch(Resource):
@jwt_required @check_jwt(editor=True)
def get(self): def get(self):
args = user_search_parser.parse_args(strict=True) args = user_search_parser.parse_args(strict=True)
items, total = dbc.search.user(**args) items, total = dbc.search.user(**args)
......
...@@ -19,25 +19,26 @@ class MediaDTO: ...@@ -19,25 +19,26 @@ class MediaDTO:
class AuthDTO: class AuthDTO:
api = Namespace("auth") api = Namespace("auth")
schema = rich_schemas.UserSchemaRich(many=False) schema = schemas.UserSchema(many=False)
list_schema = rich_schemas.UserSchemaRich(many=True) list_schema = schemas.UserSchema(many=True)
class UserDTO: class UserDTO:
api = Namespace("users") api = Namespace("users")
schema = rich_schemas.UserSchemaRich(many=False) schema = schemas.UserSchema(many=False)
list_schema = schemas.UserSchema(many=True) list_schema = schemas.UserSchema(many=True)
class CompetitionDTO: class CompetitionDTO:
api = Namespace("competitions") api = Namespace("competitions")
schema = rich_schemas.CompetitionSchemaRich(many=False) schema = schemas.CompetitionSchema(many=False)
list_schema = schemas.CompetitionSchema(many=True) list_schema = schemas.CompetitionSchema(many=True)
rich_schema = rich_schemas.CompetitionSchemaRich(many=False)
class CodeDTO: class CodeDTO:
api = Namespace("codes") api = Namespace("codes")
schema = rich_schemas.CodeSchemaRich(many=False) schema = schemas.CodeSchema(many=False)
list_schema = schemas.CodeSchema(many=True) list_schema = schemas.CodeSchema(many=True)
...@@ -65,5 +66,5 @@ class MiscDTO: ...@@ -65,5 +66,5 @@ class MiscDTO:
class QuestionDTO: class QuestionDTO:
api = Namespace("questions") api = Namespace("questions")
schema = rich_schemas.QuestionSchemaRich(many=False) schema = schemas.QuestionSchema(many=False)
list_schema = schemas.QuestionSchema(many=True) list_schema = schemas.QuestionSchema(many=True)
...@@ -86,3 +86,6 @@ component_parser.add_argument("data", type=dict, default=None, location="json") ...@@ -86,3 +86,6 @@ component_parser.add_argument("data", type=dict, default=None, location="json")
component_create_parser = component_parser.copy() component_create_parser = component_parser.copy()
component_create_parser.replace_argument("data", type=dict, required=True, location="json") component_create_parser.replace_argument("data", type=dict, required=True, location="json")
component_create_parser.add_argument("type_id", type=int, required=True, location="json") component_create_parser.add_argument("type_id", type=int, required=True, location="json")
login_code_parser = reqparse.RequestParser()
login_code_parser.add_argument("code", type=str, location="json")
...@@ -11,17 +11,6 @@ class RichSchema(ma.SQLAlchemySchema): ...@@ -11,17 +11,6 @@ class RichSchema(ma.SQLAlchemySchema):
include_relationships = True include_relationships = True
class UserSchemaRich(RichSchema):
class Meta(RichSchema.Meta):
model = models.User
id = ma.auto_field()
name = ma.auto_field()
email = ma.auto_field()
role = fields.Nested(schemas.RoleSchema, many=False)
city = fields.Nested(schemas.CitySchema, many=False)
class QuestionSchemaRich(RichSchema): class QuestionSchemaRich(RichSchema):
class Meta(RichSchema.Meta): class Meta(RichSchema.Meta):
model = models.Question model = models.Question
...@@ -30,7 +19,8 @@ class QuestionSchemaRich(RichSchema): ...@@ -30,7 +19,8 @@ class QuestionSchemaRich(RichSchema):
name = ma.auto_field() name = ma.auto_field()
total_score = ma.auto_field() total_score = ma.auto_field()
slide_id = ma.auto_field() slide_id = ma.auto_field()
type = fields.Nested(schemas.QuestionTypeSchema, many=False) type_id = ma.auto_field()
alternatives = fields.Nested(schemas.QuestionAlternative, many=True)
class TeamSchemaRich(RichSchema): class TeamSchemaRich(RichSchema):
...@@ -43,16 +33,6 @@ class TeamSchemaRich(RichSchema): ...@@ -43,16 +33,6 @@ class TeamSchemaRich(RichSchema):
question_answers = fields.Nested(schemas.QuestionAnswerSchema, many=True) 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 SlideSchemaRich(RichSchema):
class Meta(RichSchema.Meta): class Meta(RichSchema.Meta):
model = models.Slide model = models.Slide
...@@ -73,7 +53,7 @@ class CompetitionSchemaRich(RichSchema): ...@@ -73,7 +53,7 @@ class CompetitionSchemaRich(RichSchema):
id = ma.auto_field() id = ma.auto_field()
name = ma.auto_field() name = ma.auto_field()
year = ma.auto_field() year = ma.auto_field()
city = fields.Nested(schemas.CitySchema, many=False) city_id = ma.auto_field()
slides = fields.Nested( slides = fields.Nested(
SlideSchemaRich, SlideSchemaRich,
many=True, many=True,
......
...@@ -68,6 +68,16 @@ class QuestionAnswerSchema(BaseSchema): ...@@ -68,6 +68,16 @@ class QuestionAnswerSchema(BaseSchema):
team_id = ma.auto_field() team_id = ma.auto_field()
class QuestionAlternative(BaseSchema):
class Meta(BaseSchema.Meta):
model = models.QuestionAlternative
id = ma.auto_field()
text = ma.auto_field()
value = ma.auto_field()
question_id = ma.auto_field()
class RoleSchema(BaseSchema): class RoleSchema(BaseSchema):
class Meta(BaseSchema.Meta): class Meta(BaseSchema.Meta):
model = models.Role model = models.Role
......
...@@ -41,7 +41,7 @@ class ExtendedQuery(BaseQuery): ...@@ -41,7 +41,7 @@ class ExtendedQuery(BaseQuery):
class Dictionary(TypeDecorator): class Dictionary(TypeDecorator):
impl = Text(1024) impl = Text
def process_bind_param(self, value, dialect): def process_bind_param(self, value, dialect):
if value is not None: if value is not None:
......
...@@ -3,6 +3,7 @@ This file contains functionality to get data from the database. ...@@ -3,6 +3,7 @@ This file contains functionality to get data from the database.
""" """
from app.core import db from app.core import db
from app.core import http_codes as codes
from app.database.models import ( from app.database.models import (
City, City,
Code, Code,
...@@ -18,16 +19,17 @@ from app.database.models import ( ...@@ -18,16 +19,17 @@ from app.database.models import (
User, User,
ViewType, ViewType,
) )
from sqlalchemy.orm import contains_eager, joinedload, subqueryload
def all(db_type): def all(db_type):
""" Gets all elements in the provided table. """ """ Gets lazy db-item in the provided table. """
return db_type.query.all() return db_type.query.all()
def one(db_type, id, required=True, error_msg=None): def one(db_type, id, required=True, error_msg=None):
""" Gets the element in the table that has the same 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(required, error_msg)
...@@ -38,10 +40,10 @@ def user_exists(email): ...@@ -38,10 +40,10 @@ def user_exists(email):
return User.query.filter(User.email == email).count() > 0 return User.query.filter(User.email == email).count() > 0
def code_by_code(code): def code_by_code(code, required=True, error_msg=None):
""" Gets the code object associated with the provided code. """ """ Gets the code object associated with the provided code. """
return Code.query.filter(Code.code == code.upper()).first() return Code.query.filter(Code.code == code.upper()).first_extended(required, error_msg, codes.UNAUTHORIZED)
def user(UID, required=True, error_msg=None): def user(UID, required=True, error_msg=None):
...@@ -76,6 +78,16 @@ def question(CID, SOrder, QID, required=True, error_msg=None): ...@@ -76,6 +78,16 @@ def question(CID, SOrder, QID, required=True, error_msg=None):
return Question.query.join(Slide, join_filters).filter(Question.id == QID).first_extended(required, error_msg) return Question.query.join(Slide, join_filters).filter(Question.id == QID).first_extended(required, error_msg)
def competition(CID):
""" Get Competition and all it's sub-entities """
""" HOT PATH """
os1 = joinedload(Competition.slides).joinedload(Slide.components)
os2 = joinedload(Competition.slides).joinedload(Slide.questions).joinedload(Question.alternatives)
ot = joinedload(Competition.teams).joinedload(Team.question_answers)
return Competition.query.filter(Competition.id == CID).options(os1).options(os2).options(ot).first()
def code_list(competition_id): def code_list(competition_id):
""" Gets a list of all code objects associated with a the provided competition. """ """ Gets a list of all code objects associated with a the provided competition. """
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment