diff --git a/Dockerfile b/Dockerfile index b33c279..743ae43 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,10 +2,10 @@ FROM python:3.12-slim ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 WORKDIR /app -RUN apt-get update &&\ - apt-get install -y default-mysql-client &&\ - apt-get clean &&\ - rm -rf /var/lib/apt/lists/* +#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 RUN pip install --no-cache-dir -r ./requirements.txt diff --git a/api/backup.py b/api/backup.py index 6703951..12ff05d 100644 --- a/api/backup.py +++ b/api/backup.py @@ -1,5 +1,4 @@ import shutil -import zipfile from datetime import datetime from flask import Blueprint, send_file, jsonify @@ -60,6 +59,7 @@ def traverse(path_id, paths): with open(f"{md.title}.mdmeta", "w") as meta_file: meta_file.write(f"created_at: {md.created_at}\n") meta_file.write(f"order: {md.order}\n") + meta_file.write(f"shortcut: {md.shortcut}\n") children = [c for c in paths.values() if c.parent_id == path_id] for child in children: traverse(child.id, paths) diff --git a/api/markdown.py b/api/markdown.py index 878ac34..0607e52 100644 --- a/api/markdown.py +++ b/api/markdown.py @@ -1,6 +1,5 @@ from flask import Blueprint, request, jsonify from sqlalchemy import or_ - import api from api import require_auth, etag_response from contexts.RequestContext import RequestContext @@ -29,6 +28,7 @@ def get_home(): if markdown is None: return jsonify({}), 204 return jsonify(markdown.to_dict()), 200 + @markdown_bp.route('/by_path/', methods=['GET']) @limiter.limit(api.get_rate_limit) @etag_response @@ -36,6 +36,7 @@ def get_markdowns_by_path(path_id): with get_db() as session: markdowns = session.query(Markdown).filter(Markdown.path_id == path_id).all() return jsonify([md.to_dict() for md in markdowns]), 200 + @markdown_bp.route('/get_index/', methods=['GET']) @limiter.limit(api.get_rate_limit) @etag_response @@ -66,11 +67,16 @@ def create_markdown(): title = data.get('title') content = data.get('content') path_id = data.get('path_id') + shortcut = data.get('shortcut', "") if not title or not content: return jsonify({"error": "missing required fields"}), 400 - new_markdown = Markdown(title=title, content=content, path_id=path_id) + new_markdown = Markdown(title=title, content=content, path_id=path_id, shortcut=shortcut) with get_db() as session: try: + if shortcut != "": + r = session.query(Markdown).filter(Markdown.shortcut == shortcut).all() + if len(r) > 0: + return jsonify({"error": "duplicate shortcut"}), 400 session.add(new_markdown) session.commit() return jsonify(new_markdown.to_dict()), 201 @@ -89,10 +95,19 @@ def update_markdown(markdown_id): if markdown is None: return jsonify({"error": "file not found"}), 404 data = request.json + if data.get('shortcut', "") != "": + r = session.query(Markdown).filter( + Markdown.shortcut == data.get('shortcut') + ).filter( + Markdown.id != markdown_id + ).all() + if len(r) > 0: + return jsonify({"error": "duplicate shortcut"}), 400 if request.method == "PUT": markdown.title = data.get('title') markdown.content = data.get('content') markdown.path_id = data.get('path_id') + markdown.shortcut = data.get('shortcut', '') elif request.method == "PATCH": if 'title' in data: markdown.title = data.get('title') @@ -100,6 +115,8 @@ def update_markdown(markdown_id): markdown.content = data.get('content') if 'path_id' in data: markdown.path_id = data.get('path_id') + if 'shortcut' in data: + markdown.shortcut = data.get('shortcut') session.commit() return jsonify(markdown.to_dict()), 200 @@ -157,8 +174,16 @@ def move_backward(markdown_id): @markdown_bp.route('/search/', methods=['GET']) @limiter.limit(api.get_rate_limit) def search_markdowns(keyword): - with (get_db() as session): + with get_db() as session: res = session.query(Markdown).filter( or_(Markdown.title.like(keyword), Markdown.content.like(keyword)) ).all() return jsonify([md.to_dict() for md in res]), 200 + +@markdown_bp.route('/links', methods=['GET']) +@limiter.limit(api.get_rate_limit) +def get_links(): + with get_db() as session: + mds = [md.to_dict() for md in session.query(Markdown).filter(Markdown.shortcut != "").all()] + links = [f"[{md['shortcut']}]: {md['id']}" for md in mds] + return jsonify(links), 200 diff --git a/db/__init__.py b/db/__init__.py index 80111fd..d47eb99 100644 --- a/db/__init__.py +++ b/db/__init__.py @@ -21,14 +21,14 @@ def get_db(): finally: db.close() -def dump_db(): - try: - os.environ['MYSQL_PWD'] = DB_PASSWORD - dump_cmd = f"mysqldump --no-tablespaces -h {DB_HOST} -P {DB_PORT} -u {DB_USER} {DB_NAME} > /app/dump/db_dump.sql" - subprocess.run(dump_cmd, shell=True, check=True) - except subprocess.CalledProcessError as e: - print(f"Failed to dump database: {e}") - raise e +# def dump_db(): +# try: +# os.environ['MYSQL_PWD'] = DB_PASSWORD +# dump_cmd = f"mysqldump --no-tablespaces -h {DB_HOST} -P {DB_PORT} -u {DB_USER} {DB_NAME} > /app/dump/db_dump.sql" +# subprocess.run(dump_cmd, shell=True, check=True) +# except subprocess.CalledProcessError as e: +# print(f"Failed to dump database: {e}") +# raise e def clear_db(): with engine.connect() as conn: @@ -73,11 +73,11 @@ def init_payload(): def setup_db(): if DB_SCHEMA_UPDATED: - try: - dump_db() - print("[ x ] db dumped") - except Exception as e: - print(f"[ x ] Failed to dump database: {e}") + # try: + # dump_db() + # print("[ x ] db dumped") + # except Exception as e: + # print(f"[ x ] Failed to dump database: {e}") clear_db() print("[ x ] db cleared") create_all() diff --git a/db/models/Markdown.py b/db/models/Markdown.py index 37af431..35ac1e7 100644 --- a/db/models/Markdown.py +++ b/db/models/Markdown.py @@ -1,6 +1,6 @@ import uuid -from sqlalchemy import Column, Text, Integer, String, DateTime, ForeignKey, Float, text +from sqlalchemy import Column, Text, Integer, String, DateTime, ForeignKey, Float, text, UniqueConstraint from db.models import Base import datetime @@ -12,7 +12,7 @@ class Markdown(Base): created_at = Column(DateTime, default=datetime.datetime.utcnow) path_id = Column(Integer, ForeignKey('path.id'), nullable=False) order = Column(String(36), default=lambda: str(uuid.uuid4())) - + shortcut = Column(String(36), default="") def to_dict(self): return { 'id': self.id, @@ -21,6 +21,7 @@ class Markdown(Base): 'created_at': self.created_at, 'path_id': self.path_id, 'order': self.order, + 'shortcut': self.shortcut, } __pay_load__ = { 'dev': [