add: markdown permission setting

improve: template
This commit is contained in:
h z
2025-04-25 00:39:01 +01:00
parent cf247231e4
commit 35c8934963
11 changed files with 140 additions and 21 deletions

View File

@@ -79,6 +79,17 @@ def verify_token(token):
print(e) print(e)
return None return None
def is_user_admin():
is_admin = False
auth_header = request.headers.get('Authorization')
if auth_header and auth_header.startswith('Bearer'):
token = auth_header.split(" ")[1]
decoded = verify_token(token)
if decoded:
user_roles = decoded.get("resource_access", {}).get(env_provider.KC_CLIENT_ID, {}).get("roles", [])
is_admin = 'admin' in user_roles
return is_admin
def require_auth(roles=[]): def require_auth(roles=[]):
def decorator(func): def decorator(func):
@wraps(func) @wraps(func)
@@ -158,4 +169,3 @@ def etag_response(f):
return resp return resp
return response return response
return decorator return decorator

View File

@@ -1,12 +1,15 @@
from flask import Blueprint, request, jsonify from flask import Blueprint, request, jsonify
from sqlalchemy import or_ from sqlalchemy import or_
from api import limiter from api import limiter
from api import require_auth, etag_response from api import require_auth, etag_response, verify_token, is_user_admin
from contexts.RequestContext import RequestContext from contexts.RequestContext import RequestContext
from db import get_db from db import get_db
from db.models.Markdown import Markdown from db.models.Markdown import Markdown
from db.models.MarkdownSetting import MarkdownSetting
from db.models.MarkdownPermissionSetting import MarkdownPermissionSetting
from events import markdown_created, markdown_updated, markdown_deleted from events import markdown_created, markdown_updated, markdown_deleted
import api import api
import env_provider
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -54,10 +57,23 @@ def get_index(path_id):
@limiter.limit(api.get_rate_limit) @limiter.limit(api.get_rate_limit)
@etag_response @etag_response
def get_markdown(markdown_id): def get_markdown(markdown_id):
is_admin = is_user_admin()
with get_db() as session: with get_db() as session:
markdown = session.query(Markdown).get(markdown_id) markdown = session.query(Markdown).get(markdown_id)
if markdown is None: if markdown is None:
return jsonify({"error": "file not found"}), 404 return jsonify({"error": "file not found"}), 404
if not is_admin and markdown.setting_id is not None:
setting = session.query(MarkdownSetting).get(markdown.setting_id)
if setting and setting.permission_setting_id:
permission_setting = session.query(MarkdownPermissionSetting).get(setting.permission_setting_id)
if permission_setting:
if permission_setting.permission == 'private':
return jsonify({"msg": "permission denied"}), 403
elif permission_setting.permission == 'protected':
return jsonify({"msg": "permission denied"}), 203
return jsonify(markdown.to_dict()), 200 return jsonify(markdown.to_dict()), 200
@markdown_bp.route('/', methods=['POST']) @markdown_bp.route('/', methods=['POST'])

View File

@@ -1,4 +1,3 @@
#api/resource.py
import api import api
from flask import Blueprint, jsonify, request from flask import Blueprint, jsonify, request
from contexts.RequestContext import RequestContext from contexts.RequestContext import RequestContext

View File

@@ -23,7 +23,11 @@ def get_markdown_path(setting_id):
def create_markdown_setting(): def create_markdown_setting():
data = request.json data = request.json
template_setting_id = data.get('template_setting_id') template_setting_id = data.get('template_setting_id')
setting = MarkdownSetting(template_setting_id=template_setting_id) permission_setting_id = data.get('permission_setting_id')
setting = MarkdownSetting(
template_setting_id=template_setting_id,
permission_setting_id=permission_setting_id
)
try: try:
with get_db() as session: with get_db() as session:
session.add(setting) session.add(setting)
@@ -42,7 +46,9 @@ def update_markdown_setting(setting_id):
if setting is None: if setting is None:
return jsonify({"error": "setting not exists"}), 400 return jsonify({"error": "setting not exists"}), 400
template_setting_id = data.get('template_setting_id', setting.template_setting_id) template_setting_id = data.get('template_setting_id', setting.template_setting_id)
permission_setting_id = data.get('permission_setting_id', setting.permission_setting_id)
setting.template_setting_id = template_setting_id setting.template_setting_id = template_setting_id
setting.permission_setting_id = permission_setting_id
session.commit() session.commit()
return jsonify(setting.to_dict()), 200 return jsonify(setting.to_dict()), 200
except Exception as e: except Exception as e:

View File

@@ -0,0 +1,56 @@
from flask import jsonify, request
import api
from api import etag_response, limiter, require_auth
from api.setting import setting_bp
from db import get_db
from db.models.MarkdownPermissionSetting import MarkdownPermissionSetting
@setting_bp.route('/markdown/permission/<int:setting_id>/', methods=['GET'])
@etag_response
@limiter.limit(api.get_rate_limit)
def get_permission_setting(setting_id):
with get_db() as session:
setting = session.query(MarkdownPermissionSetting).get(setting_id)
if not setting:
return jsonify({}), 204
return jsonify(setting.to_dict()), 200
@setting_bp.route('/markdown/permission/', methods=['POST'])
@require_auth(roles=['admin'])
def create_permission_setting():
data = request.json
permission = data.get('permission')
new_setting = MarkdownPermissionSetting(permission=permission)
with get_db() as session:
session.add(new_setting)
session.commit()
return jsonify(new_setting.to_dict()), 201
@setting_bp.route('/markdown/permission/<int:setting_id>', methods=['PUT', 'PATCH'])
@require_auth(roles=['admin'])
def update_permission_setting(setting_id):
with get_db() as session:
setting = session.get(MarkdownPermissionSetting, setting_id)
if setting is None:
return jsonify({"error": "permission setting not found"}), 404
data = request.json
if request.method == 'PUT':
setting.permission = data.get('permission')
elif request.method == 'PATCH':
if 'permission' in data:
setting.permission = data.get('permission')
session.commit()
return jsonify(setting.to_dict()), 200
@setting_bp.route('/markdown/permission/<int:setting_id>', methods=['DELETE'])
@require_auth(roles=['admin'])
def delete_permission_setting(setting_id):
with get_db() as session:
setting = session.get(MarkdownPermissionSetting, setting_id)
st = setting.to_dict()
session.delete(setting)
session.commit()
return jsonify(st), 200

View File

@@ -59,8 +59,5 @@ def delete_template_setting(setting_id):
setting = session.get(MarkdownTemplateSetting, setting_id) setting = session.get(MarkdownTemplateSetting, setting_id)
st = setting.to_dict() st = setting.to_dict()
session.delete(setting) session.delete(setting)
session.commit()
return jsonify(st), 200 return jsonify(st), 200

View File

@@ -1,27 +1,49 @@
from flask import Blueprint, request, jsonify from flask import Blueprint, request, jsonify
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from sqlalchemy import and_, or_
import api import api
from api import etag_response from api import etag_response, verify_token, is_user_admin
from db import get_db from db import get_db
from db.models.Markdown import Markdown from db.models.Markdown import Markdown
from db.models.Path import Path from db.models.Path import Path
from db.models.MarkdownSetting import MarkdownSetting
from db.models.MarkdownPermissionSetting import MarkdownPermissionSetting
from api import limiter from api import limiter
import env_provider
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
tree_bp = Blueprint('tree', __name__, url_prefix='/api/tree') tree_bp = Blueprint('tree', __name__, url_prefix='/api/tree')
def build_tree(db: Session, parent_id: int = None): def build_tree(db: Session, parent_id: int = None, is_admin=False):
path_nodes = db.query(Path).filter(Path.parent_id == parent_id).all() path_nodes = db.query(Path).filter(Path.parent_id == parent_id).all()
md_nodes = db.query(
markdown_query = db.query(
Markdown.id, Markdown.id,
Markdown.title, Markdown.title,
Markdown.order, Markdown.order,
Markdown.shortcut, Markdown.shortcut,
Markdown.setting_id Markdown.setting_id
).filter(Markdown.path_id == parent_id).all() ).filter(Markdown.path_id == parent_id)
if not is_admin:
markdown_query = markdown_query.outerjoin(
MarkdownSetting,
Markdown.setting_id == MarkdownSetting.id
).outerjoin(
MarkdownPermissionSetting,
MarkdownSetting.permission_setting_id == MarkdownPermissionSetting.id
).filter(
or_(
MarkdownPermissionSetting.permission != 'private',
MarkdownPermissionSetting.permission == None
)
)
md_nodes = markdown_query.all()
t0 = [ t0 = [
{ {
"id": node.id, "id": node.id,
@@ -32,7 +54,7 @@ def build_tree(db: Session, parent_id: int = None):
} for node in md_nodes } for node in md_nodes
] ]
t1 = [ t1 = [
{**node.to_dict(), "type": "path", "children": build_tree(db, node.id)} for node in path_nodes {**node.to_dict(), "type": "path", "children": build_tree(db, node.id, is_admin)} for node in path_nodes
] ]
for node in t1: for node in t1:
for child in node["children"]: for child in node["children"]:
@@ -45,8 +67,10 @@ def build_tree(db: Session, parent_id: int = None):
@limiter.limit(api.get_rate_limit) @limiter.limit(api.get_rate_limit)
@etag_response @etag_response
def get_tree(): def get_tree():
is_admin = is_user_admin()
with get_db() as session: with get_db() as session:
children = build_tree(session, 1) children = build_tree(session, 1, is_admin)
root = session.query(Path).get(1) root = session.query(Path).get(1)
return jsonify( return jsonify(

View File

@@ -0,0 +1,15 @@
from sqlalchemy import Column, Integer, ForeignKey, String
from db.models import Base
class MarkdownPermissionSetting(Base):
__tablename__ = 'markdown_permission_setting'
id = Column(Integer, primary_key=True, autoincrement=True)
permission = Column(String(255), nullable=True)
def to_dict(self):
return {
"id": self.id,
"permission": self.permission,
}

View File

@@ -1,15 +1,14 @@
from sqlalchemy import Column, Integer, ForeignKey from sqlalchemy import Column, Integer, ForeignKey
from db.models import Base from db.models import Base
class MarkdownSetting(Base): class MarkdownSetting(Base):
__tablename__ = 'markdown_setting' __tablename__ = 'markdown_setting'
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
template_setting_id = Column(Integer, ForeignKey('markdown_template_setting.id'), nullable=True) template_setting_id = Column(Integer, ForeignKey('markdown_template_setting.id'), nullable=True)
permission_setting_id = Column(Integer, ForeignKey('markdown_permission_setting.id'), nullable=True)
def to_dict(self): def to_dict(self):
return { return {
"id": self.id, "id": self.id,
"template_setting_id": self.template_setting_id, "template_setting_id": self.template_setting_id,
"permission_setting_id": self.permission_setting_id,
} }

View File

@@ -1,4 +1,3 @@
#env_provider.py
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv

View File

@@ -1,5 +1,3 @@
#logging_handlers/DatabaseLogHandler.py
import logging import logging
from db import get_db from db import get_db
from db.models.Log import Log from db.models.Log import Log