Compare commits
1 Commits
6626fac452
...
fa855bc7bb
| Author | SHA1 | Date | |
|---|---|---|---|
| fa855bc7bb |
@@ -2,10 +2,6 @@ FROM python:3.12-slim
|
|||||||
ENV PYTHONDONTWRITEBYTECODE 1
|
ENV PYTHONDONTWRITEBYTECODE 1
|
||||||
ENV PYTHONUNBUFFERED 1
|
ENV PYTHONUNBUFFERED 1
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
#RUN apt-get update &&\
|
|
||||||
# apt-get install -y default-mysql-client &&\
|
|
||||||
# apt-get clean &&\
|
|
||||||
# rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
COPY requirements.txt ./requirements.txt
|
COPY requirements.txt ./requirements.txt
|
||||||
RUN pip install --no-cache-dir -r ./requirements.txt
|
RUN pip install --no-cache-dir -r ./requirements.txt
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
|
import pkgutil
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from cryptography import x509
|
from cryptography import x509
|
||||||
@@ -17,8 +18,6 @@ import hashlib
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_public_key_cache = {}
|
_public_key_cache = {}
|
||||||
_lock = Lock()
|
_lock = Lock()
|
||||||
|
|
||||||
@@ -126,17 +125,18 @@ limiter = Limiter(
|
|||||||
|
|
||||||
|
|
||||||
def register_blueprints(app):
|
def register_blueprints(app):
|
||||||
current_dir = os.path.dirname(__file__)
|
|
||||||
for filename in os.listdir(current_dir):
|
|
||||||
if filename == "__init__.py" or not filename.endswith(".py"):
|
|
||||||
continue
|
|
||||||
module_name = filename[:-3]
|
|
||||||
module = importlib.import_module(f"api.{module_name}")
|
|
||||||
for attr in dir(module):
|
|
||||||
bp = getattr(module, attr)
|
|
||||||
if isinstance(bp, Blueprint):
|
|
||||||
app.register_blueprint(bp)
|
|
||||||
|
|
||||||
|
package_name = __name__
|
||||||
|
package_path = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
for finder, mod_name, is_pkg in pkgutil.walk_packages([package_path], package_name + "."):
|
||||||
|
module = importlib.import_module(mod_name)
|
||||||
|
for attr_name in dir(module):
|
||||||
|
item = getattr(module, attr_name)
|
||||||
|
if isinstance(item, Blueprint):
|
||||||
|
if item.name in app.blueprints:
|
||||||
|
continue
|
||||||
|
app.register_blueprint(item)
|
||||||
|
|
||||||
|
|
||||||
def generate_etag(data):
|
def generate_etag(data):
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ def update_markdown(markdown_id):
|
|||||||
@limiter.limit(api.get_rate_limit)
|
@limiter.limit(api.get_rate_limit)
|
||||||
def delete_markdown(markdown_id):
|
def delete_markdown(markdown_id):
|
||||||
with get_db() as session:
|
with get_db() as session:
|
||||||
markdown = session.query(Markdown).get(markdown_id)
|
markdown = session.get(Markdown, markdown_id)
|
||||||
if markdown is None:
|
if markdown is None:
|
||||||
logger.error(f"failed to delete markdown: {markdown_id}")
|
logger.error(f"failed to delete markdown: {markdown_id}")
|
||||||
errno = RequestContext.get_error_id()
|
errno = RequestContext.get_error_id()
|
||||||
@@ -137,7 +137,7 @@ def delete_markdown(markdown_id):
|
|||||||
session.delete(markdown)
|
session.delete(markdown)
|
||||||
session.commit()
|
session.commit()
|
||||||
markdown_deleted.send(None, payload=md)
|
markdown_deleted.send(None, payload=md)
|
||||||
return jsonify({"message": "deleted"}), 200
|
return jsonify(md), 200
|
||||||
|
|
||||||
|
|
||||||
@markdown_bp.route('/move_forward/<int:markdown_id>', methods=['PATCH'])
|
@markdown_bp.route('/move_forward/<int:markdown_id>', methods=['PATCH'])
|
||||||
@@ -164,7 +164,7 @@ def move_forward(markdown_id):
|
|||||||
@limiter.limit(api.get_rate_limit)
|
@limiter.limit(api.get_rate_limit)
|
||||||
def move_backward(markdown_id):
|
def move_backward(markdown_id):
|
||||||
with get_db() as session:
|
with get_db() as session:
|
||||||
markdown = session.query(Markdown).get(markdown_id)
|
markdown = session.get(Markdown, markdown_id)
|
||||||
if not markdown:
|
if not markdown:
|
||||||
return jsonify({"error": "file not found"}), 404
|
return jsonify({"error": "file not found"}), 404
|
||||||
siblings = session.query(Markdown).filter(Markdown.path_id == markdown.path_id).order_by(Markdown.order).all()
|
siblings = session.query(Markdown).filter(Markdown.path_id == markdown.path_id).order_by(Markdown.order).all()
|
||||||
|
|||||||
8
api/setting/__init__.py
Normal file
8
api/setting/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
|
||||||
|
from flask import Blueprint
|
||||||
|
setting_bp = Blueprint('setting', __name__, url_prefix='/api/setting')
|
||||||
|
|
||||||
|
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__, prefix=__name__ + "."):
|
||||||
|
importlib.import_module(module_name)
|
||||||
61
api/setting/markdown/__init__.py
Normal file
61
api/setting/markdown/__init__.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
from flask import jsonify, request
|
||||||
|
|
||||||
|
import api
|
||||||
|
from api import limiter, etag_response, require_auth
|
||||||
|
from api.setting import setting_bp
|
||||||
|
from db import get_db
|
||||||
|
from db.models.MarkdownSetting import MarkdownSetting
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/markdown/<int:setting_id>', methods=['GET'])
|
||||||
|
@limiter.limit(api.get_rate_limit)
|
||||||
|
@etag_response
|
||||||
|
def get_markdown_path(setting_id):
|
||||||
|
with get_db() as session:
|
||||||
|
setting = session.query(MarkdownSetting).get(setting_id)
|
||||||
|
if setting is None:
|
||||||
|
return jsonify({}), 204
|
||||||
|
return jsonify(setting.to_dict()), 200
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/markdown/', methods=['POST'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def create_markdown_setting():
|
||||||
|
data = request.json
|
||||||
|
template_setting_id = data.get('template_setting_id')
|
||||||
|
setting = MarkdownSetting(template_setting_id=template_setting_id)
|
||||||
|
try:
|
||||||
|
with get_db() as session:
|
||||||
|
session.add(setting)
|
||||||
|
session.commit()
|
||||||
|
return jsonify(setting.to_dict()), 200
|
||||||
|
except Exception:
|
||||||
|
return jsonify({"error": "failed to create setting"}), 500
|
||||||
|
|
||||||
|
@setting_bp.route('/markdown/<int:setting_id>', methods=['PUT', 'PATCH'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def update_markdown_setting(setting_id):
|
||||||
|
data = request.json
|
||||||
|
try:
|
||||||
|
with get_db() as session:
|
||||||
|
setting = session.query(MarkdownSetting).get(setting_id)
|
||||||
|
if setting is None:
|
||||||
|
return jsonify({"error": "setting not exists"}), 400
|
||||||
|
template_setting_id = data.get('template_setting_id', setting.template_setting_id)
|
||||||
|
setting.template_setting_id = template_setting_id
|
||||||
|
session.commit()
|
||||||
|
return jsonify(setting.to_dict()), 200
|
||||||
|
except Exception:
|
||||||
|
return jsonify({"error": "failed to update setting"}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/markdown/<int:setting_id>', methods=['DELETE'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def delete_markdown_setting(setting_id):
|
||||||
|
with get_db() as session:
|
||||||
|
setting = session.query(MarkdownSetting).get(setting_id)
|
||||||
|
if setting is None:
|
||||||
|
return jsonify({"error": "setting not exists"}), 400
|
||||||
|
session.delete(setting)
|
||||||
|
session.commit()
|
||||||
|
return jsonify({"message": "deleted"}), 200
|
||||||
65
api/setting/markdown/template.py
Normal file
65
api/setting/markdown/template.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
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.MarkdownTemplateSetting import MarkdownTemplateSetting
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/markdown/template/', methods=['GET'])
|
||||||
|
@etag_response
|
||||||
|
def list_template_settings():
|
||||||
|
with get_db() as session:
|
||||||
|
settings = session.query(MarkdownTemplateSetting).all()
|
||||||
|
return jsonify([s.to_dict() for s in settings]), 200
|
||||||
|
|
||||||
|
@setting_bp.route('/markdown/template/<int:setting_id>/', methods=['GET'])
|
||||||
|
@etag_response
|
||||||
|
@limiter.limit(api.get_rate_limit)
|
||||||
|
def get_template_setting(setting_id):
|
||||||
|
with get_db() as session:
|
||||||
|
setting = session.query(MarkdownTemplateSetting).get(setting_id)
|
||||||
|
if not setting:
|
||||||
|
return jsonify({}), 204
|
||||||
|
return jsonify(setting.to_dict()), 200
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/markdown/template/', methods=['POST'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def create_template_setting():
|
||||||
|
data = request.json
|
||||||
|
template_id = data.get('template_id')
|
||||||
|
new_setting = MarkdownTemplateSetting(template_id=template_id)
|
||||||
|
with get_db() as session:
|
||||||
|
session.add(new_setting)
|
||||||
|
return jsonify(new_setting.to_dict()), 201
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/markdown/template/<int:setting_id>', methods=['PUT', 'PATCH'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def update_template_setting(setting_id):
|
||||||
|
with get_db() as session:
|
||||||
|
setting = session.get(MarkdownTemplateSetting, setting_id)
|
||||||
|
if setting is None:
|
||||||
|
return jsonify({"error": "template setting not found"}), 404
|
||||||
|
data = request.json
|
||||||
|
if request.method == 'PUT':
|
||||||
|
setting.template_id = data.get('template_id')
|
||||||
|
elif request.method == 'PATCH':
|
||||||
|
if 'template_id' in data:
|
||||||
|
setting.template_id = data.get('template_id')
|
||||||
|
session.commit()
|
||||||
|
return jsonify(setting.to_dict()), 200
|
||||||
|
|
||||||
|
@setting_bp.route('/markdown/template/<int:setting_id>', methods=['DELETE'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def delete_template_setting(setting_id):
|
||||||
|
with get_db() as session:
|
||||||
|
setting = session.get(MarkdownTemplateSetting, setting_id)
|
||||||
|
st = setting.to_dict()
|
||||||
|
session.delete(setting)
|
||||||
|
return jsonify(st), 200
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
from flask import Blueprint, jsonify, request
|
from flask import jsonify, request
|
||||||
from api import limiter, etag_response, require_auth
|
|
||||||
from db import get_db
|
|
||||||
from db.models.MarkdownSetting import MarkdownSetting
|
|
||||||
from db.models.PathSetting import PathSetting
|
|
||||||
import api
|
import api
|
||||||
|
from api import limiter, require_auth, etag_response
|
||||||
|
from api.setting import setting_bp
|
||||||
|
from db import get_db
|
||||||
|
from db.models.PathSetting import PathSetting
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
setting_bp = Blueprint('setting', __name__, url_prefix='/api/setting')
|
|
||||||
|
|
||||||
@setting_bp.route('/path/<int:setting_id>', methods=['GET'])
|
@setting_bp.route('/path/<int:setting_id>', methods=['GET'])
|
||||||
@limiter.limit(api.get_rate_limit)
|
@limiter.limit(api.get_rate_limit)
|
||||||
@etag_response
|
@etag_response
|
||||||
@@ -67,56 +67,3 @@ def delete_path_setting(setting_id):
|
|||||||
session.delete(setting)
|
session.delete(setting)
|
||||||
return jsonify({"message": "deleted"}), 200
|
return jsonify({"message": "deleted"}), 200
|
||||||
|
|
||||||
|
|
||||||
@setting_bp.route('/markdown/<int:setting_id>', methods=['GET'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
@etag_response
|
|
||||||
def get_markdown_path(setting_id):
|
|
||||||
with get_db() as session:
|
|
||||||
setting = session.query(MarkdownSetting).get(setting_id)
|
|
||||||
if setting is None:
|
|
||||||
return jsonify({}), 204
|
|
||||||
return jsonify(setting.to_dict()), 200
|
|
||||||
|
|
||||||
|
|
||||||
@setting_bp.route('/markdown/', methods=['POST'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def create_markdown_setting():
|
|
||||||
data = request.json
|
|
||||||
template_setting_id = data.get('template_setting_id')
|
|
||||||
setting = MarkdownSetting(template_setting_id=template_setting_id)
|
|
||||||
try:
|
|
||||||
with get_db() as session:
|
|
||||||
session.add(setting)
|
|
||||||
session.commit()
|
|
||||||
return jsonify(setting.to_dict()), 200
|
|
||||||
except Exception:
|
|
||||||
return jsonify({"error": "failed to create setting"}), 500
|
|
||||||
|
|
||||||
@setting_bp.route('/markdown/<int:setting_id>', methods=['PUT', 'PATCH'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def update_markdown_setting(setting_id):
|
|
||||||
data = request.json
|
|
||||||
try:
|
|
||||||
with get_db() as session:
|
|
||||||
setting = session.query(MarkdownSetting).get(setting_id)
|
|
||||||
if setting is None:
|
|
||||||
return jsonify({"error": "setting not exists"}), 400
|
|
||||||
template_setting_id = data.get('template_setting_id', setting.template_setting_id)
|
|
||||||
setting.template_setting_id = template_setting_id
|
|
||||||
session.commit()
|
|
||||||
return jsonify(setting.to_dict()), 200
|
|
||||||
except Exception:
|
|
||||||
return jsonify({"error": "failed to update setting"}), 500
|
|
||||||
|
|
||||||
|
|
||||||
@setting_bp.route('/markdown/<int:setting_id>', methods=['DELETE'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def delete_markdown_setting(setting_id):
|
|
||||||
with get_db() as session:
|
|
||||||
setting = session.query(MarkdownSetting).get(setting_id)
|
|
||||||
if setting is None:
|
|
||||||
return jsonify({"error": "setting not exists"}), 400
|
|
||||||
session.delete(setting)
|
|
||||||
session.commit()
|
|
||||||
return jsonify({"message": "deleted"}), 200
|
|
||||||
77
api/setting/path/webhook.py
Normal file
77
api/setting/path/webhook.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
from flask import jsonify, request
|
||||||
|
from api import require_auth
|
||||||
|
from api.setting import setting_bp
|
||||||
|
from db import get_db
|
||||||
|
from db.models.WebhookSetting import WebhookSetting
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/path/webhook/', methods=['GET'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def list_webhook_settings():
|
||||||
|
with get_db() as session:
|
||||||
|
settings = session.query(WebhookSetting).all()
|
||||||
|
return jsonify([s.to_dict() for s in settings]), 200
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/path/webhook/<int:setting_id>', methods=['GET'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def webhook_setting(setting_id):
|
||||||
|
with get_db() as session:
|
||||||
|
setting = session.query(WebhookSetting).filter(WebhookSetting.id == setting_id).first()
|
||||||
|
if not setting:
|
||||||
|
return jsonify({}), 204
|
||||||
|
return jsonify(setting.to_dict()), 200
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/path/webhook/', methods=['POST'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def create_webhook_setting():
|
||||||
|
data = request.json
|
||||||
|
with get_db() as session:
|
||||||
|
setting = WebhookSetting(
|
||||||
|
webhook_id=data.get('webhook_id'),
|
||||||
|
recursive=data.get('recursive', False),
|
||||||
|
additional_header=data.get('additional_header', ''),
|
||||||
|
enabled=data.get('enabled', True),
|
||||||
|
on_events=data.get('on_events', 1),
|
||||||
|
)
|
||||||
|
session.add(setting)
|
||||||
|
session.commit()
|
||||||
|
return jsonify(setting.to_dict()), 201
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/path/webhook/<int:setting_id>', methods=['PUT', 'PATCH'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def update_webhook_setting(setting_id):
|
||||||
|
data = request.json
|
||||||
|
with get_db() as session:
|
||||||
|
setting = session.query(WebhookSetting).get(setting_id)
|
||||||
|
if not setting:
|
||||||
|
return jsonify({'error': 'Webhook setting not found'}), 404
|
||||||
|
if 'webhook_id' in data:
|
||||||
|
setting.webhook_id = data['webhook_id']
|
||||||
|
if 'recursive' in data:
|
||||||
|
setting.recursive = data['recursive']
|
||||||
|
if 'additional_header' in data:
|
||||||
|
setting.additional_header = data['additional_header']
|
||||||
|
if 'enabled' in data:
|
||||||
|
setting.enabled = data['enabled']
|
||||||
|
if 'on_events' in data:
|
||||||
|
setting.on_events = data['on_events']
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
return jsonify(setting.to_dict()), 200
|
||||||
|
|
||||||
|
|
||||||
|
@setting_bp.route('/path/webhook/<int:setting_id>', methods=['DELETE'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def delete_webhook_setting(setting_id):
|
||||||
|
with get_db() as session:
|
||||||
|
setting = session.query(WebhookSetting).get(setting_id)
|
||||||
|
if not setting:
|
||||||
|
return jsonify({'error': 'Webhook setting not found'}), 404
|
||||||
|
|
||||||
|
session.delete(setting)
|
||||||
|
session.commit()
|
||||||
|
return jsonify({'message': 'Webhook setting deleted'}), 200
|
||||||
|
|
||||||
136
api/template.py
136
api/template.py
@@ -1,136 +0,0 @@
|
|||||||
from flask import Blueprint, jsonify, request
|
|
||||||
from db import get_db
|
|
||||||
from api import require_auth, etag_response
|
|
||||||
from db.models.MarkdownTemplate import MarkdownTemplate
|
|
||||||
from db.models.PathTemplate import PathTemplate
|
|
||||||
|
|
||||||
template_bp = Blueprint('template', __name__, url_prefix='/api/template')
|
|
||||||
|
|
||||||
@template_bp.route('/path/<int:template_id>', methods=['GET'])
|
|
||||||
@etag_response
|
|
||||||
def get_path_template(template_id):
|
|
||||||
with get_db() as session:
|
|
||||||
template = session.query(PathTemplate).get(template_id)
|
|
||||||
if template is None:
|
|
||||||
return jsonify({}), 204
|
|
||||||
return jsonify(template.to_dict()), 200
|
|
||||||
|
|
||||||
@template_bp.route('/path/', methods=['GET'])
|
|
||||||
@etag_response
|
|
||||||
def get_path_templates():
|
|
||||||
with get_db() as session:
|
|
||||||
templates = session.query(PathTemplate).all()
|
|
||||||
return jsonify([template.to_dict() for template in templates]), 200
|
|
||||||
|
|
||||||
|
|
||||||
@template_bp.route('/path/', methods=['POST'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def create_path_template():
|
|
||||||
data = request.json
|
|
||||||
if "title" not in data:
|
|
||||||
return jsonify({"error": "title is missing"}), 400
|
|
||||||
title = data.get("title")
|
|
||||||
structure = data.get("structure")
|
|
||||||
template = PathTemplate(title=title, structure=structure)
|
|
||||||
try:
|
|
||||||
with get_db() as session:
|
|
||||||
session.add(template)
|
|
||||||
session.commit()
|
|
||||||
return template.to_dict(), 200
|
|
||||||
except Exception as e:
|
|
||||||
return jsonify({"error": "failed to create path template"}), 400
|
|
||||||
|
|
||||||
|
|
||||||
@template_bp.route('/path/<int:template_id>', methods=['PUT', 'PATCH'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def update_path_template(template_id):
|
|
||||||
data = request.json
|
|
||||||
with get_db() as session:
|
|
||||||
template = session.query(PathTemplate).get(template_id)
|
|
||||||
if template is None:
|
|
||||||
return jsonify({'error': 'path template not found'}), 400
|
|
||||||
title = data.get("title", template.title)
|
|
||||||
structure = data.get("structure", template.structure)
|
|
||||||
template.title = title
|
|
||||||
template.structure = structure
|
|
||||||
session.commit()
|
|
||||||
return jsonify(template.to_dict()), 200
|
|
||||||
|
|
||||||
|
|
||||||
@template_bp.route('/path/<int:template_id>', methods=['DELETE'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def delete_path_template(template_id):
|
|
||||||
with get_db() as session:
|
|
||||||
template = session.query(PathTemplate).get(template_id)
|
|
||||||
if template is None:
|
|
||||||
return jsonify({'error': 'path template not found'}), 400
|
|
||||||
session.delete(template)
|
|
||||||
session.commit()
|
|
||||||
return jsonify({'message': 'deleted'}), 200
|
|
||||||
|
|
||||||
|
|
||||||
@template_bp.route('/markdown/<int:template_id>', methods=['GET'])
|
|
||||||
@etag_response
|
|
||||||
def get_markdown_template(template_id):
|
|
||||||
with get_db() as session:
|
|
||||||
template = session.query(MarkdownTemplate).get(template_id)
|
|
||||||
if template is None:
|
|
||||||
return jsonify({}), 204
|
|
||||||
return jsonify(template.to_dict()), 200
|
|
||||||
|
|
||||||
@template_bp.route('/markdown/', methods=['GET'])
|
|
||||||
@etag_response
|
|
||||||
def get_markdown_templates():
|
|
||||||
with get_db() as session:
|
|
||||||
templates = session.query(MarkdownTemplate).all()
|
|
||||||
return jsonify([template.to_dict() for template in templates]), 200
|
|
||||||
|
|
||||||
|
|
||||||
@template_bp.route('/markdown/', methods=['POST'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def create_markdown_template():
|
|
||||||
data = request.json
|
|
||||||
if "title" not in data:
|
|
||||||
return jsonify({"error": "title is missing"}), 400
|
|
||||||
title = data.get("title")
|
|
||||||
parameters = data.get("parameters")
|
|
||||||
define = data.get("define")
|
|
||||||
template = MarkdownTemplate(title=title, parameters=parameters, define=define)
|
|
||||||
try:
|
|
||||||
with get_db() as session:
|
|
||||||
session.add(template)
|
|
||||||
session.commit()
|
|
||||||
return template.to_dict(), 200
|
|
||||||
except Exception as e:
|
|
||||||
return jsonify({"error": "failed to create markdown template"}), 400
|
|
||||||
|
|
||||||
|
|
||||||
@template_bp.route('/markdown/<int:template_id>', methods=['PUT', 'PATCH'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def update_markdown_template(template_id):
|
|
||||||
data = request.json
|
|
||||||
with get_db() as session:
|
|
||||||
template = session.query(MarkdownTemplate).get(template_id)
|
|
||||||
if template is None:
|
|
||||||
return jsonify({'error': 'markdown template not found'}), 400
|
|
||||||
title = data.get("title", template.title)
|
|
||||||
parameters = data.get("parameters", template.parameters)
|
|
||||||
define = data.get("define", template.define)
|
|
||||||
template.title = title
|
|
||||||
template.parameters = parameters
|
|
||||||
template.define = define
|
|
||||||
session.commit()
|
|
||||||
return jsonify(template.to_dict()), 200
|
|
||||||
|
|
||||||
|
|
||||||
@template_bp.route('/markdown/<int:template_id>', methods=['DELETE'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def delete_markdown_template(template_id):
|
|
||||||
with get_db() as session:
|
|
||||||
template = session.query(MarkdownTemplate).get(template_id)
|
|
||||||
if template is None:
|
|
||||||
return jsonify({'error': 'markdown template not found'}), 400
|
|
||||||
session.delete(template)
|
|
||||||
session.commit()
|
|
||||||
return jsonify({'message': 'deleted'}), 200
|
|
||||||
|
|
||||||
9
api/template/__init__.py
Normal file
9
api/template/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
|
||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
|
template_bp = Blueprint('template', __name__, url_prefix='/api/template')
|
||||||
|
|
||||||
|
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__, prefix=__name__ + "."):
|
||||||
|
importlib.import_module(module_name)
|
||||||
92
api/template/markdown/__init__.py
Normal file
92
api/template/markdown/__init__.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import json
|
||||||
|
from flask import jsonify, request
|
||||||
|
from api import etag_response, require_auth
|
||||||
|
from api.template import template_bp
|
||||||
|
from db import get_db
|
||||||
|
from db.models.MarkdownTemplate import MarkdownTemplate
|
||||||
|
|
||||||
|
cached_templates = {}
|
||||||
|
def inflate_template(template):
|
||||||
|
template.parameters = json.loads(template.parameters)
|
||||||
|
for parameter in template.parameters:
|
||||||
|
if parameter.get('type', {}).get('base_type') == 'template':
|
||||||
|
sub_template_id = parameter.get('type', {}).get('definition', {}).get('template', {}).get('id', 0)
|
||||||
|
if sub_template_id in cached_templates.keys():
|
||||||
|
parameter['type']['definition']['template'] = cached_templates[sub_template_id]
|
||||||
|
else:
|
||||||
|
with get_db() as session:
|
||||||
|
sub_template = session.query(MarkdownTemplate).get(sub_template_id)
|
||||||
|
parameter['type']['definition']['template'] = inflate_template(sub_template)
|
||||||
|
cached_templates[template.id] = template
|
||||||
|
return template
|
||||||
|
|
||||||
|
|
||||||
|
@template_bp.route('/markdown/<int:template_id>', methods=['GET'])
|
||||||
|
@etag_response
|
||||||
|
def get_markdown_template(template_id):
|
||||||
|
with get_db() as session:
|
||||||
|
template = session.query(MarkdownTemplate).get(template_id)
|
||||||
|
if template is None:
|
||||||
|
return jsonify({}), 204
|
||||||
|
return jsonify(inflate_template(template.to_dict())), 200
|
||||||
|
|
||||||
|
@template_bp.route('/markdown/', methods=['GET'])
|
||||||
|
@etag_response
|
||||||
|
def get_markdown_templates():
|
||||||
|
with get_db() as session:
|
||||||
|
templates = session.query(MarkdownTemplate).all()
|
||||||
|
return jsonify([inflate_template(template.to_dict()) for template in templates]), 200
|
||||||
|
|
||||||
|
|
||||||
|
@template_bp.route('/markdown/', methods=['POST'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def create_markdown_template():
|
||||||
|
data = request.json
|
||||||
|
if "title" not in data:
|
||||||
|
return jsonify({"error": "title is missing"}), 400
|
||||||
|
title = data.get("title")
|
||||||
|
parameters = data.get("parameters")
|
||||||
|
layout = data.get("layout")
|
||||||
|
template = MarkdownTemplate(title=title, parameters=parameters, layout=layout)
|
||||||
|
try:
|
||||||
|
with get_db() as session:
|
||||||
|
session.add(template)
|
||||||
|
session.commit()
|
||||||
|
return template.to_dict(), 200
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": "failed to create markdown template"}), 400
|
||||||
|
|
||||||
|
|
||||||
|
@template_bp.route('/markdown/<int:template_id>', methods=['PUT', 'PATCH'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def update_markdown_template(template_id):
|
||||||
|
data = request.json
|
||||||
|
with get_db() as session:
|
||||||
|
template = session.query(MarkdownTemplate).get(template_id)
|
||||||
|
if template is None:
|
||||||
|
return jsonify({'error': 'markdown template not found'}), 400
|
||||||
|
title = data.get("title", template.title)
|
||||||
|
parameters = data.get("parameters", template.parameters)
|
||||||
|
define = data.get("define", template.define)
|
||||||
|
template.title = title
|
||||||
|
template.parameters = parameters
|
||||||
|
template.define = define
|
||||||
|
session.commit()
|
||||||
|
if template_id in cached_templates.keys():
|
||||||
|
cached_templates[template_id] = inflate_template(template.to_dict())
|
||||||
|
return jsonify(template.to_dict()), 200
|
||||||
|
|
||||||
|
|
||||||
|
@template_bp.route('/markdown/<int:template_id>', methods=['DELETE'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def delete_markdown_template(template_id):
|
||||||
|
with get_db() as session:
|
||||||
|
template = session.query(MarkdownTemplate).get(template_id)
|
||||||
|
if template is None:
|
||||||
|
return jsonify({'error': 'markdown template not found'}), 400
|
||||||
|
session.delete(template)
|
||||||
|
session.commit()
|
||||||
|
if template_id in cached_templates.keys():
|
||||||
|
cached_templates.pop(template_id)
|
||||||
|
return jsonify({'message': 'deleted'}), 200
|
||||||
|
|
||||||
9
api/template/markdown/type.py
Normal file
9
api/template/markdown/type.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from flask import jsonify
|
||||||
|
|
||||||
|
from api.template import template_bp
|
||||||
|
|
||||||
|
|
||||||
|
@template_bp.route('/markdown/type/', methods=['GET'])
|
||||||
|
def get_types():
|
||||||
|
return jsonify(["template", "text", "string", "list", "enum"]), 200
|
||||||
|
|
||||||
69
api/template/path/__init__.py
Normal file
69
api/template/path/__init__.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
from flask import jsonify, request
|
||||||
|
|
||||||
|
from api import etag_response, require_auth
|
||||||
|
from api.template import template_bp
|
||||||
|
from db import get_db
|
||||||
|
from db.models.PathTemplate import PathTemplate
|
||||||
|
|
||||||
|
|
||||||
|
@template_bp.route('/path/<int:template_id>', methods=['GET'])
|
||||||
|
@etag_response
|
||||||
|
def get_path_template(template_id):
|
||||||
|
with get_db() as session:
|
||||||
|
template = session.query(PathTemplate).get(template_id)
|
||||||
|
if template is None:
|
||||||
|
return jsonify({}), 204
|
||||||
|
return jsonify(template.to_dict()), 200
|
||||||
|
|
||||||
|
@template_bp.route('/path/', methods=['GET'])
|
||||||
|
@etag_response
|
||||||
|
def get_path_templates():
|
||||||
|
with get_db() as session:
|
||||||
|
templates = session.query(PathTemplate).all()
|
||||||
|
return jsonify([template.to_dict() for template in templates]), 200
|
||||||
|
|
||||||
|
|
||||||
|
@template_bp.route('/path/', methods=['POST'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def create_path_template():
|
||||||
|
data = request.json
|
||||||
|
if "title" not in data:
|
||||||
|
return jsonify({"error": "title is missing"}), 400
|
||||||
|
title = data.get("title")
|
||||||
|
structure = data.get("structure")
|
||||||
|
template = PathTemplate(title=title, structure=structure)
|
||||||
|
try:
|
||||||
|
with get_db() as session:
|
||||||
|
session.add(template)
|
||||||
|
session.commit()
|
||||||
|
return template.to_dict(), 200
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": "failed to create path template"}), 400
|
||||||
|
|
||||||
|
|
||||||
|
@template_bp.route('/path/<int:template_id>', methods=['PUT', 'PATCH'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def update_path_template(template_id):
|
||||||
|
data = request.json
|
||||||
|
with get_db() as session:
|
||||||
|
template = session.query(PathTemplate).get(template_id)
|
||||||
|
if template is None:
|
||||||
|
return jsonify({'error': 'path template not found'}), 400
|
||||||
|
title = data.get("title", template.title)
|
||||||
|
structure = data.get("structure", template.structure)
|
||||||
|
template.title = title
|
||||||
|
template.structure = structure
|
||||||
|
session.commit()
|
||||||
|
return jsonify(template.to_dict()), 200
|
||||||
|
|
||||||
|
|
||||||
|
@template_bp.route('/path/<int:template_id>', methods=['DELETE'])
|
||||||
|
@require_auth(roles=['admin'])
|
||||||
|
def delete_path_template(template_id):
|
||||||
|
with get_db() as session:
|
||||||
|
template = session.query(PathTemplate).get(template_id)
|
||||||
|
if template is None:
|
||||||
|
return jsonify({'error': 'path template not found'}), 400
|
||||||
|
session.delete(template)
|
||||||
|
session.commit()
|
||||||
|
return jsonify({'message': 'deleted'}), 200
|
||||||
10
api/tree.py
10
api/tree.py
@@ -2,7 +2,7 @@ from flask import Blueprint, request, jsonify
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
import api
|
import api
|
||||||
from api import require_auth, etag_response
|
from api import etag_response
|
||||||
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
|
||||||
@@ -15,7 +15,13 @@ 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):
|
||||||
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.id, Markdown.title, Markdown.order, Markdown.shortcut, Markdown.setting_id).filter(Markdown.path_id == parent_id).all()
|
md_nodes = db.query(
|
||||||
|
Markdown.id,
|
||||||
|
Markdown.title,
|
||||||
|
Markdown.order,
|
||||||
|
Markdown.shortcut,
|
||||||
|
Markdown.setting_id
|
||||||
|
).filter(Markdown.path_id == parent_id).all()
|
||||||
t0 = [
|
t0 = [
|
||||||
{
|
{
|
||||||
"id": node.id,
|
"id": node.id,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ from flask import Blueprint, jsonify, request
|
|||||||
from api import require_auth
|
from api import require_auth
|
||||||
from db import get_db
|
from db import get_db
|
||||||
from db.models.Webhook import Webhook
|
from db.models.Webhook import Webhook
|
||||||
from db.models.WebhookSetting import WebhookSetting
|
|
||||||
|
|
||||||
webhook_bp = Blueprint('webhook', __name__, url_prefix='/api/webhook')
|
webhook_bp = Blueprint('webhook', __name__, url_prefix='/api/webhook')
|
||||||
|
|
||||||
@@ -33,9 +32,6 @@ def create_webhook():
|
|||||||
return jsonify(webhook.to_dict()), 201
|
return jsonify(webhook.to_dict()), 201
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@webhook_bp.route('/<int:webhook_id>', methods=['PUT', 'PATCH'])
|
@webhook_bp.route('/<int:webhook_id>', methods=['PUT', 'PATCH'])
|
||||||
@require_auth(roles=['admin'])
|
@require_auth(roles=['admin'])
|
||||||
def update_webhook(webhook_id):
|
def update_webhook(webhook_id):
|
||||||
@@ -67,75 +63,4 @@ def delete_webhook(webhook_id):
|
|||||||
|
|
||||||
session.delete(webhook)
|
session.delete(webhook)
|
||||||
session.commit()
|
session.commit()
|
||||||
return jsonify({'message': 'Webhook deleted'}), 200
|
return jsonify({'message': 'Webhook deleted'}), 200
|
||||||
|
|
||||||
|
|
||||||
@webhook_bp.route('/setting/', methods=['GET'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def list_webhook_settings():
|
|
||||||
with get_db() as session:
|
|
||||||
settings = session.query(WebhookSetting).all()
|
|
||||||
return jsonify([s.to_dict() for s in settings]), 200
|
|
||||||
|
|
||||||
|
|
||||||
@webhook_bp.route('/setting/<int:setting_id>', methods=['GET'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def webhook_setting(setting_id):
|
|
||||||
with get_db() as session:
|
|
||||||
setting = session.query(WebhookSetting).filter(WebhookSetting.id == setting_id).first()
|
|
||||||
if not setting:
|
|
||||||
return jsonify({'info': 'Webhook setting not found'}), 204
|
|
||||||
return jsonify(setting.to_dict()), 200
|
|
||||||
|
|
||||||
|
|
||||||
@webhook_bp.route('/setting/', methods=['POST'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def create_webhook_setting():
|
|
||||||
data = request.json
|
|
||||||
with get_db() as session:
|
|
||||||
setting = WebhookSetting(
|
|
||||||
webhook_id=data.get('webhook_id'),
|
|
||||||
recursive=data.get('recursive', False),
|
|
||||||
additional_header=data.get('additional_header', ''),
|
|
||||||
enabled=data.get('enabled', True),
|
|
||||||
on_events=data.get('on_events', 1),
|
|
||||||
)
|
|
||||||
session.add(setting)
|
|
||||||
session.commit()
|
|
||||||
return jsonify(setting.to_dict()), 201
|
|
||||||
|
|
||||||
|
|
||||||
@webhook_bp.route('/setting/<int:setting_id>', methods=['PUT', 'PATCH'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def update_webhook_setting(setting_id):
|
|
||||||
data = request.json
|
|
||||||
with get_db() as session:
|
|
||||||
setting = session.query(WebhookSetting).get(setting_id)
|
|
||||||
if not setting:
|
|
||||||
return jsonify({'error': 'Webhook setting not found'}), 404
|
|
||||||
if 'webhook_id' in data:
|
|
||||||
setting.webhook_id = data['webhook_id']
|
|
||||||
if 'recursive' in data:
|
|
||||||
setting.recursive = data['recursive']
|
|
||||||
if 'additional_header' in data:
|
|
||||||
setting.additional_header = data['additional_header']
|
|
||||||
if 'enabled' in data:
|
|
||||||
setting.enabled = data['enabled']
|
|
||||||
if 'on_events' in data:
|
|
||||||
setting.on_events = data['on_events']
|
|
||||||
|
|
||||||
session.commit()
|
|
||||||
return jsonify(setting.to_dict()), 200
|
|
||||||
|
|
||||||
|
|
||||||
@webhook_bp.route('/setting/<int:setting_id>', methods=['DELETE'])
|
|
||||||
@require_auth(roles=['admin'])
|
|
||||||
def delete_webhook_setting(setting_id):
|
|
||||||
with get_db() as session:
|
|
||||||
setting = session.query(WebhookSetting).get(setting_id)
|
|
||||||
if not setting:
|
|
||||||
return jsonify({'error': 'Webhook setting not found'}), 404
|
|
||||||
|
|
||||||
session.delete(setting)
|
|
||||||
session.commit()
|
|
||||||
return jsonify({'message': 'Webhook setting deleted'}), 200
|
|
||||||
1
app.py
1
app.py
@@ -54,6 +54,5 @@ def log_request():
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
api.init_rate_limits(app)
|
api.init_rate_limits(app)
|
||||||
#logger.info("Starting app")
|
|
||||||
pprint(env_provider.summerize())
|
pprint(env_provider.summerize())
|
||||||
app.run(host='0.0.0.0', port=5000)
|
app.run(host='0.0.0.0', port=5000)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from sqlalchemy.orm import sessionmaker
|
|||||||
from sqlalchemy.dialects.mysql import insert
|
from sqlalchemy.dialects.mysql import insert
|
||||||
from sqlalchemy import create_engine, text, inspect
|
from sqlalchemy import create_engine, text, inspect
|
||||||
from env_provider import DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD, DB_SCHEMA_UPDATED, ENVIRONMENT
|
from env_provider import DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD, DB_SCHEMA_UPDATED, ENVIRONMENT
|
||||||
|
print(f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}")
|
||||||
engine = create_engine(f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}")
|
engine = create_engine(f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}")
|
||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ class Markdown(Base):
|
|||||||
}
|
}
|
||||||
__payload__ = {
|
__payload__ = {
|
||||||
'dev': [
|
'dev': [
|
||||||
{'id': 1, 'title': 'index', 'content': ' ', 'created_at': datetime.datetime.utcnow, 'path_id': 1 },
|
{'id': 1, 'title': 'index', 'content': '{"markdown": ""}', 'created_at': datetime.datetime.utcnow, 'path_id': 1 },
|
||||||
],
|
],
|
||||||
'prod': [
|
'prod': [
|
||||||
{'id': 1, 'title': 'index', 'content': ' ', 'created_at': datetime.datetime.utcnow, 'path_id': 1},
|
{'id': 1, 'title': 'index', 'content': '{"markdown": ""}', 'created_at': datetime.datetime.utcnow, 'path_id': 1},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class MarkdownTemplate(Base):
|
|||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
title = Column(String(255), nullable=False)
|
title = Column(String(255), nullable=False)
|
||||||
parameters = Column(Text, nullable=True)
|
parameters = Column(Text, nullable=True)
|
||||||
define = Column(Text, nullable=True)
|
layout = Column(Text, nullable=True)
|
||||||
__table_args__ = (UniqueConstraint("title", name="unique_title"),)
|
__table_args__ = (UniqueConstraint("title", name="unique_title"),)
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
@@ -14,5 +14,5 @@ class MarkdownTemplate(Base):
|
|||||||
'id': self.id,
|
'id': self.id,
|
||||||
'title': self.title,
|
'title': self.title,
|
||||||
'parameters': self.parameters,
|
'parameters': self.parameters,
|
||||||
'define': self.define,
|
'layout': self.layout,
|
||||||
}
|
}
|
||||||
|
|||||||
16
db/models/MarkdownTemplateSetting.py
Normal file
16
db/models/MarkdownTemplateSetting.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from sqlalchemy import Column, Integer, ForeignKey
|
||||||
|
|
||||||
|
from db.models import Base
|
||||||
|
|
||||||
|
|
||||||
|
class MarkdownTemplateSetting(Base):
|
||||||
|
__tablename__ = 'markdown_template_setting'
|
||||||
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
|
template_id = Column(Integer, ForeignKey('markdown_template.id'))
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
'id': self.id,
|
||||||
|
'template_id': self.template_id,
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user