add: webhook
This commit is contained in:
@@ -41,20 +41,19 @@ def get_jwks():
|
||||
|
||||
def get_public_key_for_kid(kid):
|
||||
global _public_key_cache
|
||||
if kid in _public_key_cache:
|
||||
return _public_key_cache[kid]
|
||||
jwks = get_jwks()
|
||||
res = []
|
||||
for key_data in jwks["keys"]:
|
||||
if key_data["kid"] == kid and key_data["use"] == "sig" and key_data["alg"] == "RS256" and key_data["kty"] == "RSA":
|
||||
x5c = key_data["x5c"][0]
|
||||
pem_public_key = x5c_to_public_key(x5c)
|
||||
_public_key_cache[kid] = pem_public_key
|
||||
res.append(pem_public_key)
|
||||
if len(res) > 0:
|
||||
print(len(res))
|
||||
return res[0]
|
||||
|
||||
with _lock:
|
||||
if kid in _public_key_cache:
|
||||
return _public_key_cache[kid]
|
||||
jwks = get_jwks()
|
||||
res = []
|
||||
for key_data in jwks["keys"]:
|
||||
if key_data["kid"] == kid and key_data["use"] == "sig" and key_data["alg"] == "RS256" and key_data["kty"] == "RSA":
|
||||
x5c = key_data["x5c"][0]
|
||||
pem_public_key = x5c_to_public_key(x5c)
|
||||
_public_key_cache[kid] = pem_public_key
|
||||
res.append(pem_public_key)
|
||||
if len(res) > 0:
|
||||
return res[0]
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -41,3 +41,4 @@ def create_log():
|
||||
extra = data.get('extra', None)
|
||||
log_entry = Log(level=level, message=message, application=application, extra=extra)
|
||||
insert_log(log_entry)
|
||||
return jsonify({"message": "log created"}), 201
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from sqlalchemy import or_
|
||||
import api
|
||||
from api import limiter
|
||||
from api import require_auth, etag_response
|
||||
from contexts.RequestContext import RequestContext
|
||||
from db import get_db
|
||||
from db.models.Markdown import Markdown
|
||||
from events import markdown_created, markdown_updated, markdown_deleted
|
||||
import api
|
||||
import logging
|
||||
from api import limiter
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
markdown_bp = Blueprint('markdown', __name__, url_prefix='/api/markdown')
|
||||
@@ -79,6 +80,7 @@ def create_markdown():
|
||||
return jsonify({"error": "duplicate shortcut"}), 400
|
||||
session.add(new_markdown)
|
||||
session.commit()
|
||||
markdown_created.send(None, new_markdown.to_dict())
|
||||
return jsonify(new_markdown.to_dict()), 201
|
||||
except Exception as e:
|
||||
logger.error(f"failed to create markdown: {e}")
|
||||
@@ -118,6 +120,7 @@ def update_markdown(markdown_id):
|
||||
if 'shortcut' in data:
|
||||
markdown.shortcut = data.get('shortcut')
|
||||
session.commit()
|
||||
markdown_updated.send(None, markdown.to_dict())
|
||||
return jsonify(markdown.to_dict()), 200
|
||||
|
||||
@markdown_bp.route('/<int:markdown_id>', methods=['DELETE'])
|
||||
@@ -130,8 +133,10 @@ def delete_markdown(markdown_id):
|
||||
logger.error(f"failed to delete markdown: {markdown_id}")
|
||||
errno = RequestContext.get_error_id()
|
||||
return jsonify({"error": f"file not found - {errno}"}), 404
|
||||
md = markdown.to_dict()
|
||||
session.delete(markdown)
|
||||
session.commit()
|
||||
markdown_deleted.send(None, md)
|
||||
return jsonify({"message": "deleted"}), 200
|
||||
|
||||
|
||||
@@ -150,6 +155,7 @@ def move_forward(markdown_id):
|
||||
previous_markdown = siblings[current_index - 1]
|
||||
markdown.order, previous_markdown.order = previous_markdown.order, markdown.order
|
||||
session.commit()
|
||||
markdown_updated.send(None, markdown.to_dict())
|
||||
return jsonify(markdown.to_dict()), 200
|
||||
|
||||
|
||||
@@ -167,8 +173,9 @@ def move_backward(markdown_id):
|
||||
return jsonify({"error": "already at the last position"}), 400
|
||||
|
||||
next_markdown = siblings[current_index + 1]
|
||||
markdown.order, next_markdown.order = next_markdown.order, next_markdown.order
|
||||
markdown.order, next_markdown.order = next_markdown.order, markdown.order
|
||||
session.commit()
|
||||
markdown_updated.send(None, markdown.to_dict())
|
||||
return jsonify(markdown.to_dict()), 200
|
||||
|
||||
@markdown_bp.route('/search/<string:keyword>', methods=['GET'])
|
||||
|
||||
10
api/path.py
10
api/path.py
@@ -7,6 +7,9 @@ from db.models.Markdown import Markdown
|
||||
from db.models.Path import Path
|
||||
from api import limiter
|
||||
import logging
|
||||
|
||||
from events import path_created, path_updated, path_deleted
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
path_bp = Blueprint('path', __name__, url_prefix='/api/path')
|
||||
@@ -52,6 +55,7 @@ def create_path():
|
||||
new_path = Path(name=data['name'], parent_id=data['parent_id'])
|
||||
session.add(new_path)
|
||||
session.commit()
|
||||
path_created.send(None, new_path.to_dict())
|
||||
return jsonify(new_path.to_dict()), 201
|
||||
|
||||
@path_bp.route('/<int:path_id>', methods=['PUT'])
|
||||
@@ -70,6 +74,7 @@ def update_path(path_id):
|
||||
path.name = data['name']
|
||||
path.parent_id = data['parent_id']
|
||||
session.commit()
|
||||
path_updated.send(None, path.to_dict())
|
||||
return jsonify(path.to_dict()), 200
|
||||
|
||||
@path_bp.route('/<int:path_id>', methods=['PATCH'])
|
||||
@@ -91,6 +96,7 @@ def patch_path(path_id):
|
||||
path.name = updated_name
|
||||
path.parent_id = updated_parent_id
|
||||
session.commit()
|
||||
path_updated.send(None, path.to_dict())
|
||||
return jsonify(path.to_dict()), 200
|
||||
|
||||
|
||||
@@ -106,8 +112,10 @@ def delete_path(path_id):
|
||||
return jsonify({"error": "can not delete non empty path"}), 409
|
||||
if session.query(Markdown).filter_by(path_id=path_id).first():
|
||||
return jsonify({"error": "can not delete non empty path"}), 409
|
||||
pth = path.to_dict()
|
||||
session.delete(path)
|
||||
session.commit()
|
||||
path_deleted.send(None, pth)
|
||||
return jsonify({"message": "path deleted"}), 200
|
||||
|
||||
|
||||
@@ -126,6 +134,7 @@ def move_forward(path_id):
|
||||
previous_path = siblings[current_index - 1]
|
||||
path.order, previous_path.order = previous_path.order, path.order
|
||||
session.commit()
|
||||
path_updated.send(None, path.to_dict())
|
||||
return jsonify(path.to_dict()), 200
|
||||
|
||||
|
||||
@@ -145,5 +154,6 @@ def move_backward(path_id):
|
||||
next_path = siblings[current_index + 1]
|
||||
path.order, next_path.order = next_path.order, path.order
|
||||
session.commit()
|
||||
path_updated.send(None, path.to_dict())
|
||||
return jsonify(path.to_dict()), 200
|
||||
|
||||
|
||||
152
api/webhook.py
Normal file
152
api/webhook.py
Normal file
@@ -0,0 +1,152 @@
|
||||
from flask import Blueprint, jsonify, request
|
||||
from api import require_auth, limiter
|
||||
from db import get_db
|
||||
from db.models.Webhook import Webhook
|
||||
from db.models.WebhookSetting import WebhookSetting
|
||||
|
||||
webhook_bp = Blueprint('webhook', __name__, url_prefix='/api/webhook')
|
||||
|
||||
|
||||
@webhook_bp.route('/', methods=['GET'])
|
||||
@require_auth(roles=['admin'])
|
||||
def list_webhooks():
|
||||
with get_db() as session:
|
||||
hooks = session.query(Webhook).all()
|
||||
return jsonify([h.to_dict() for h in hooks]), 200
|
||||
|
||||
|
||||
@webhook_bp.route('/', methods=['POST'])
|
||||
@require_auth(['admin'])
|
||||
def create_webhook():
|
||||
data = request.json
|
||||
hook_url = data.get('hook_url')
|
||||
if not hook_url:
|
||||
return jsonify({'error': 'hook_url required'}), 400
|
||||
|
||||
with get_db() as session:
|
||||
existing = session.query(Webhook).filter_by(hook_url=hook_url).first()
|
||||
if existing:
|
||||
return jsonify({'error': 'Webhook URL already exists'}), 409
|
||||
webhook = Webhook(hook_url=hook_url)
|
||||
session.add(webhook)
|
||||
session.commit()
|
||||
return jsonify(webhook.to_dict()), 201
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@webhook_bp.route('/<int:webhook_id>', methods=['PUT', 'PATCH'])
|
||||
@require_auth(roles=['admin'])
|
||||
def update_webhook(webhook_id):
|
||||
data = request.json
|
||||
if 'hook_url' not in data:
|
||||
return jsonify({'error': 'hook_url is required'}), 400
|
||||
|
||||
with get_db() as session:
|
||||
webhook = session.query(Webhook).get(webhook_id)
|
||||
if not webhook:
|
||||
return jsonify({'error': 'Webhook not found'}), 404
|
||||
|
||||
existing = session.query(Webhook).filter_by(hook_url=data['hook_url']).filter(Webhook.id != webhook_id).first()
|
||||
if existing:
|
||||
return jsonify({'error': 'Webhook URL already exists'}), 409
|
||||
|
||||
webhook.hook_url = data['hook_url']
|
||||
session.commit()
|
||||
return jsonify(webhook.to_dict()), 200
|
||||
|
||||
|
||||
@webhook_bp.route('/<int:webhook_id>', methods=['DELETE'])
|
||||
@require_auth(roles=['admin'])
|
||||
def delete_webhook(webhook_id):
|
||||
with get_db() as session:
|
||||
webhook = session.query(Webhook).get(webhook_id)
|
||||
if not webhook:
|
||||
return jsonify({'error': 'Webhook not found'}), 404
|
||||
|
||||
session.delete(webhook)
|
||||
session.commit()
|
||||
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/path/<int:path_id>', methods=['GET'])
|
||||
@require_auth(roles=['admin'])
|
||||
def webhook_setting_by_path(path_id):
|
||||
with get_db() as session:
|
||||
setting = session.query(WebhookSetting).filter(WebhookSetting.path_id == path_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
|
||||
print(data)
|
||||
required = ['path_id', 'webhook_id']
|
||||
for key in required:
|
||||
if key not in data:
|
||||
return jsonify({'error': 'Required field missing'}), 400
|
||||
with get_db() as session:
|
||||
setting = WebhookSetting(
|
||||
path_id=data.get('path_id'),
|
||||
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 '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
|
||||
Reference in New Issue
Block a user