add: auto link feature
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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/<int:path_id>', 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/<int:path_id>', 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/<string:keyword>', 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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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': [
|
||||
|
||||
Reference in New Issue
Block a user