add permissions to files api

This commit is contained in:
grimhilt 2023-09-12 15:08:54 +02:00
parent 5eefea90fa
commit 3b50112c10
6 changed files with 102 additions and 27 deletions

View File

@ -3,6 +3,7 @@ from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS from flask_cors import CORS
from flask_login import LoginManager from flask_login import LoginManager
from os import path from os import path
from config.config import get_secret_key
import logging import logging
@ -15,7 +16,7 @@ def create_api():
CORS(app) CORS(app)
logging.getLogger('flask_cors').level = logging.DEBUG logging.getLogger('flask_cors').level = logging.DEBUG
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}' app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
app.secret_key = b'_5#y2L"F4Qfj8zxec]' app.secret_key = get_secret_key()
login_manager = LoginManager() login_manager = LoginManager()
login_manager.init_app(app) login_manager.init_app(app)

View File

@ -1,4 +1,6 @@
from flask import Blueprint, request, jsonify, send_file from flask import Blueprint, request, jsonify, send_file
from flask_login import login_required
from ..permissions import Perm, permissions
from ..models import File from ..models import File
from .. import db from .. import db
@ -6,6 +8,8 @@ files = Blueprint('files', __name__)
FILE_DIR = './data/' FILE_DIR = './data/'
@files.route('/files', methods=['POST']) @files.route('/files', methods=['POST'])
@login_required
@permissions.require([Perm.EDIT_PLAYLIST])
def upload(): def upload():
res = [] res = []
for file_key in request.files: for file_key in request.files:
@ -22,6 +26,8 @@ def upload():
return jsonify(res) return jsonify(res)
@files.route('/files', methods=['GET']) @files.route('/files', methods=['GET'])
@login_required
@permissions.require([Perm.EDIT_PLAYLIST])
def list(): def list():
files = db.session.query(File).all() files = db.session.query(File).all()
res = [] res = []
@ -30,12 +36,17 @@ def list():
return jsonify(res) return jsonify(res)
@files.route('/files/<int:file_id>', methods=['GET']) @files.route('/files/<int:file_id>', methods=['GET'])
@login_required
@permissions.require([Perm.VIEW_PLAYLIST])
def load(file_id): def load(file_id):
file = db.session.query(File).filter(File.id == file_id).first() file = db.session.query(File).filter(File.id == file_id).first()
return send_file(('../../data/' + file.name), mimetype=file.type) return send_file(('../../data/' + file.name), mimetype=file.type)
@files.route('/files/<int:file_id>', methods=['DELETE']) @files.route('/files/<int:file_id>', methods=['DELETE'])
@login_required
@permissions.require([Perm.OWN_PLAYLIST])
def delete(file_id): def delete(file_id):
# todo warning if file is still in use
rows = db.session.query(File).filter(File.id == file_id).all() rows = db.session.query(File).filter(File.id == file_id).all()
for row in rows: for row in rows:
db.session.delete(row) db.session.delete(row)

View File

@ -13,3 +13,32 @@ class PlaylistDao:
files.append(file) files.append(file)
return (query, files) return (query, files)
def get_playlist_q(playlist_id):
query = db.session.query(Playlist).filter(Playlist.id == playlist_id).first()
return query
def has_role_view_d(playlist_id, user_id):
has_role_to_view = db.session.query(Playlist) \
.filter(Playlist.id == playlist_id) \
.filter( \
Playlist.view.any( \
# check if a role belongs to this user
Role.user_id == user_id or \
# check if a this user has a role to view
Role.users.any(User.id == user_id) \
)) \
.first()
return has_role_to_view
def has_role_view_d(playlist_id, user_id):
has_role_to_edit = db.session.query(Playlist) \
.filter( \
Playlist.edit.any( \
# check if a role belongs to this user
Role.user_id == user_id or \
# check if a this user has a role to edit
Role.users.any(User.id == user_id) \
)) \
.first()
return has_role_to_edit

24
src/api/dao/UsersDao.py Normal file
View File

@ -0,0 +1,24 @@
from .. import db
from ..models import User, Role
class UsersDao:
def has_role_view_q(user_id):
has_role_to_view = db.session.query(User) \
.filter(User.id == user_id) \
.filter( \
User.roles.any( \
Role.users.any(Role.playlists_view is not None) \
)) \
.first()
return has_role_to_view
def has_role_edit_q(user_id):
has_role_to_edit = db.session.query(User) \
.filter(User.id == user_id) \
.filter( \
User.roles.any( \
Role.users.any(Role.playlists_edit is not None) \
)) \
.first()
return has_role_to_edit

View File

@ -4,6 +4,9 @@ from flask import request, jsonify
from flask_login import current_user from flask_login import current_user
from . import db from . import db
from .models import Playlist, PlaylistFile, User, Role, UserRole from .models import Playlist, PlaylistFile, User, Role, UserRole
from .dao.Playlist import PlaylistDao
from .dao.UsersDao import UsersDao
class Perm(IntEnum): class Perm(IntEnum):
CREATE_USER = 0 CREATE_USER = 0
@ -59,11 +62,10 @@ def CheckPermissionFactory(perm):
def get_playlist_id(args): def get_playlist_id(args):
if 'playlist_id' in args: if 'playlist_id' in args:
return args['playlist_id'] return args['playlist_id']
json = request.get_json() json = request.get_json(silent=True)
if 'playlist_id' in json: if json is not None and 'playlist_id' in json:
print("in")
return json['playlist_id'] return json['playlist_id']
return return None
def checkBit(permissions, index): def checkBit(permissions, index):
binStr = bin(permissions) binStr = bin(permissions)
@ -84,12 +86,14 @@ class CheckOwnPlaylist:
def is_valid(self, args): def is_valid(self, args):
playlist_id = get_playlist_id(args) playlist_id = get_playlist_id(args)
query = db.session.query(Playlist).filter(Playlist.id == playlist_id).first() if playlist_id is None:
return False
query = PlaylistDao.get_playlist_q(playlist_id)
if query is None: if query is None:
self.message = "This playlist doesn't exist" self.message = "This playlist doesn't exist"
self.status_code = 404 self.status_code = 404
return False return False
print(query.as_dict())
return query.as_dict()['owner_id'] == current_user.as_dict()['id'] return query.as_dict()['owner_id'] == current_user.as_dict()['id']
class CheckViewPlaylist: class CheckViewPlaylist:
@ -109,15 +113,18 @@ class CheckViewPlaylist:
playlist_id = get_playlist_id(args) playlist_id = get_playlist_id(args)
user_id = current_user.as_dict()['id'] user_id = current_user.as_dict()['id']
has_role_to_view = db.session.query(Playlist) \
.filter( \ # if playlist_id is none then there is not precise playlist
Playlist.view.any( \ # to compare the permissions, so we check if the user has
# check if a role belongs to this user # a permission on any playlist
Role.user_id == user_id or \ has_role_to_view = None
# check if a this user has a role to view if playlist_id is not None:
Role.users.any(User.id == user_id) \ # check if has role on one precise playlist
)) \ has_role_to_view = PlaylistDao.has_role_to_view(playlist_id, user_id)
.first() else:
# check if has role to view any playlist
has_role_to_view = UsersDao.has_role_view_q(user_id)
return has_role_to_view is not None return has_role_to_view is not None
class CheckEditPlaylist: class CheckEditPlaylist:
@ -133,18 +140,21 @@ class CheckEditPlaylist:
self.message = "This playlist doesn't exist" self.message = "This playlist doesn't exist"
self.status_code = 404 self.status_code = 404
return False return False
playlist_id = get_playlist_id(args) playlist_id = get_playlist_id(args)
user_id = current_user.as_dict()['id'] user_id = current_user.as_dict()['id']
has_role_to_edit = db.session.query(Playlist) \
.filter( \ # if playlist_id is none then there is not precise playlist
Playlist.edit.any( \ # to compare the permissions, so we check if the user has
# check if a role belongs to this user # a permission on any playlist
Role.user_id == user_id or \ has_role_to_edit = None
# check if a this user has a role to edit if playlist_id is not None:
Role.users.any(User.id == user_id) \ # check if has role on one precise playlist
)) \ has_role_to_edit = PlaylistDao.has_role_to_edit(playlist_id, user_id)
.first() else:
# check if has role to view any playlist
has_role_to_edit = UsersDao.has_role_edit_q(user_id)
return has_role_to_edit is not None return has_role_to_edit is not None
class CheckCreateUser: class CheckCreateUser:

View File

@ -2,7 +2,7 @@ import os
import random import random
import string import string
SECRET_KEY_FILE = './src/config/SECRET_KEY' SECRET_KEY_FILE = './config/SECRET_KEY'
def get_secret_key(): def get_secret_key():
if os.path.isfile(SECRET_KEY_FILE): if os.path.isfile(SECRET_KEY_FILE):