diff --git a/api/__init__.py b/api/__init__.py index b444475..8aea364 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from flask import Blueprint +from flask import Blueprint, abort from flask_restplus import Api, Namespace api_authorizations = { @@ -40,3 +40,13 @@ from .example_api import * from .auth_api import * from .user_api import * from .group_api import * + + +@api_bp.route('/') +def catch_all_api(path): + """ + Default 404 response for undefined paths in API. + :param path: + :return: + """ + abort(404) diff --git a/api/auth_api.py b/api/auth_api.py index 75f9193..34e54d1 100644 --- a/api/auth_api.py +++ b/api/auth_api.py @@ -136,13 +136,14 @@ def oidc(redirect_url=None): return response -@auth_api_bp.route('/refresh', methods=['POST']) +@auth_api_bp.route('/refresh', methods=['GET']) @jwt_refresh_token_required def refresh(): """Refresh token endpoint. This will generate a new access token from the refresh token, but will mark that access token as non-fresh, as we do not actually verify a password in this endpoint.""" current_user = get_jwt_identity() + app.logger.info("Refreshing token for " + current_user) new_token = create_access_token(identity=current_user, fresh=False) ret = {'access_token': new_token} return jsonify(ret), 200 diff --git a/api/group_api.py b/api/group_api.py index 83584b2..dc0c7b3 100644 --- a/api/group_api.py +++ b/api/group_api.py @@ -17,8 +17,8 @@ group_model = api_group.model('Group', { 'id': fields.String(required=False, description='The group\'s identifier'), 'name': fields.String(required=True, description='The group\'s name'), 'description': fields.String(required=False, description='The group\'s description'), - 'users': fields.List(fields.Nested( - {'id': fields.Integer(), 'first_name': fields.String(), 'last_name': fields.String()}), + 'users': fields.List(fields.Nested(api_group.model('group_member', + {'id': fields.Integer(), 'first_name': fields.String(), 'last_name': fields.String()})), required=False, description='Group members.') }) diff --git a/api/user_api.py b/api/user_api.py index 06a8b81..11a5d0e 100644 --- a/api/user_api.py +++ b/api/user_api.py @@ -17,14 +17,14 @@ from backend.auth import oidc_auth from backend.models.user_model import User, Group - user_model = api_user.model('User', { 'id': fields.String(required=True, description='The user\'s identifier'), 'first_name': fields.String(required=True, description='The user\'s first name'), 'last_name': fields.String(required=True, description='The user\'s last name'), 'email': fields.String(required=True, description='The user\'s email address'), 'nickname': fields.String(required=False, description='The user\'s nick name'), - 'groups': fields.List(fields.Nested({'name': fields.String()}), required=False, description='Group memberships.'), + 'groups': fields.List(fields.Nested(api_user.model('user_group', {'id':fields.Integer(), 'name': fields.String()})), + required=False, description='Group memberships.'), }) diff --git a/models/recorder_model.py b/models/recorder_model.py new file mode 100644 index 0000000..390d3da --- /dev/null +++ b/models/recorder_model.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +""" +Models for lecture recorder +""" +import json + +from sqlalchemy import MetaData + +from backend import db, app, login_manager +import re +from sqlalchemy import or_ +from datetime import datetime, timedelta + + +metadata = MetaData() + +# This is the association table for the many-to-many relationship between +# groups and permissions. +recorder_recorder_command_table = db.Table('recorder_recorder_command', + db.Column('recorder_id', db.Integer, + db.ForeignKey('recorder.id', + onupdate="CASCADE", + ondelete="CASCADE"), + primary_key=True), + db.Column('recorder_command_id', db.Integer, + db.ForeignKey('recorder_command.id', + onupdate="CASCADE", + ondelete="CASCADE"), + primary_key=True)) + + +class Recorder(db.Model): + id = db.Column(db.Integer, autoincrement=True, primary_key=True) + created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow()) + name = db.Column(db.Unicode(63), unique=True, nullable=False) + description = db.Column(db.Unicode(255), unique=False, nullable=True, default="") + room = db.relationship('Room', uselist=False, back_populates='recorder') # one-to-one relation (uselist=False) + recorder_commands = db.relationship('RecorderCommand', secondary=recorder_recorder_command_table, back_populates='recorders') + + def __init__(self, **kwargs): + super(Recorder, self).__init__(**kwargs) + + + @staticmethod + def get_by_name(name): + """ + Find group by name + :param name: + :return: + """ + return Recorder.query.filter(Recorder.name == name).first() + + @staticmethod + def get_all(): + """ + Return all groups + :return: + """ + return Group.query.all() + + def __str__(self): + return self.name + + def to_dict(self): + return dict(id=self.id, name=self.name) + + def toJSON(self): + return json.dumps(self.to_dict(), default=lambda o: o.__dict__, + sort_keys=True, indent=4) + + +class RecorderCommand(db.Model): + """Table containing permissions associated with groups.""" + id = db.Column(db.Integer, autoincrement=True, primary_key=True) + name = db.Column(db.Unicode(63), unique=True, nullable=False) + description = db.Column(db.Unicode(511)) + recorders = db.relationship(Recorder, secondary=recorder_recorder_command_table, + back_populates='recorder_commands') diff --git a/models/room_model.py b/models/room_model.py new file mode 100644 index 0000000..b1455fc --- /dev/null +++ b/models/room_model.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +""" +Models for lecture recorder +""" +import json + +from sqlalchemy import MetaData + +from backend import db, app, login_manager +import re +from sqlalchemy import or_ +from datetime import datetime, timedelta + + +metadata = MetaData() + + +class Room(db.Model): + id = db.Column(db.Integer, autoincrement=True, primary_key=True) + created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow()) + name = db.Column(db.Unicode(127), unique=True, nullable=False) + number = db.Column(db.Unicode(63), unique=True, nullable=True) + description = db.Column(db.Unicode(255), unique=False, nullable=True, default="") + recorder = db.relationship('Recorder', uselist=False, back_populates='room') # one-to-one relation (uselist=False) + + def __init__(self, **kwargs): + super(Room, self).__init__(**kwargs) + + @staticmethod + def get_by_name(name): + """ + Find group by name + :param name: + :return: + """ + return Room.query.filter(Room.name == name).first() + + @staticmethod + def get_all(): + """ + Return all groups + :return: + """ + return Room.query.all() + + def __str__(self): + return self.name + + def to_dict(self): + return dict(id=self.id, name=self.name) + + def toJSON(self): + return json.dumps(self.to_dict(), default=lambda o: o.__dict__, + sort_keys=True, indent=4) + + +class Permission(db.Model): + """Table containing permissions associated with groups.""" + id = db.Column(db.Integer, autoincrement=True, primary_key=True) + name = db.Column(db.Unicode(63), unique=True, nullable=False) + description = db.Column(db.Unicode(511)) + groups = db.relationship(Room, secondary=room_permission_table, + back_populates='permissions')