211 lines
7.6 KiB
Python
211 lines
7.6 KiB
Python
import json
|
|
import os
|
|
import uuid
|
|
from flask import Flask, redirect, render_template, g, request, send_file, session, url_for
|
|
from pathlib import Path
|
|
|
|
from kanken_online.api import get_kanji_by_character
|
|
from kanken_online.database import get_database
|
|
from .auth import login_required
|
|
|
|
|
|
DATABASE_NAME = "kanken_online.sqlite"
|
|
JITEN_DB_NAME = "kanken.db"
|
|
PFP_DIRECTORY_NAME = "pfp"
|
|
def create_app(test_config=None):
|
|
app = Flask(__name__, instance_relative_config=True)
|
|
app.config.from_mapping(
|
|
SECRET_KEY="dev",
|
|
DATABASE=str(Path(app.instance_path) / DATABASE_NAME),
|
|
JITEN_DB=str(Path(app.instance_path) / JITEN_DB_NAME),
|
|
PFP_STORE=str(Path(app.instance_path) / PFP_DIRECTORY_NAME)
|
|
)
|
|
|
|
if test_config is None:
|
|
app.config.from_pyfile("config.py", silent=True)
|
|
else:
|
|
app.config.from_mapping(test_config)
|
|
|
|
# Ensure instance path exists
|
|
os.makedirs(app.instance_path, exist_ok=True)
|
|
|
|
@app.route("/hello")
|
|
def hello():
|
|
return "Hello, World!"
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return render_template("index.html")
|
|
|
|
@app.route("/about")
|
|
def about_page():
|
|
return render_template("about.html")
|
|
|
|
def update_settings(form, files):
|
|
db = get_database()
|
|
# Set values in the database
|
|
settings = db.execute("SELECT * FROM user_settings WHERE user_id = ?",
|
|
(session["user_id"],)
|
|
).fetchone()
|
|
if settings:
|
|
db.execute("UPDATE user_settings SET lang = ?, theme = ? WHERE user_id = ?",
|
|
(form["language"], form["theme"], session["user_id"]))
|
|
else:
|
|
db.execute("INSERT INTO user_settings (user_id, lang, theme) VALUES (?, ?, ?)",
|
|
(session["user_id"], form["language"], form["theme"]))
|
|
|
|
if "pfp" in files and files["pfp"].filename != "":
|
|
stored_filename = str(uuid.uuid4())
|
|
pfp = files["pfp"]
|
|
pfp.save(os.path.join(app.config["PFP_STORE"], stored_filename))
|
|
|
|
# Remove old PFP
|
|
if settings and settings["pfp_filename"]:
|
|
os.remove(os.path.join(app.config["PFP_STORE"], settings["pfp_filename"]))
|
|
|
|
db.execute("UPDATE user_settings SET pfp_filename = ?", (stored_filename,))
|
|
|
|
db.commit()
|
|
|
|
update_logged_out_settings(form)
|
|
|
|
return redirect("/options")
|
|
|
|
def update_logged_out_settings(form):
|
|
# Set values directly in the session
|
|
session["language"] = form["language"]
|
|
session["theme"] = form["theme"]
|
|
return redirect("/public_options")
|
|
|
|
@app.route("/options", methods=["GET", "POST"])
|
|
def options():
|
|
if request.method == "GET":
|
|
if "user_id" in session:
|
|
return render_template("options.html")
|
|
else:
|
|
return redirect("/public_options")
|
|
else:
|
|
return update_settings(request.form, request.files)
|
|
|
|
@app.route("/public_options", methods=["GET", "POST"])
|
|
def public_options():
|
|
if request.method == "GET":
|
|
if "user_id" in session:
|
|
return redirect("/public_options")
|
|
else:
|
|
return render_template("logged_out_options.html")
|
|
else:
|
|
return update_logged_out_settings(request.form)
|
|
|
|
@app.get("/user/<int:user_id>")
|
|
def user_page(user_id: int):
|
|
db = get_database()
|
|
(username,pfp_filename) = db.execute("SELECT username, pfp_filename FROM user, user_settings WHERE user.id = ? AND user_settings.user_id = ?", (user_id,user_id)).fetchone()
|
|
return render_template("user_page.html", username=username, pfp_filename=os.path.join(app.config["PFP_STORE"], pfp_filename))
|
|
|
|
@app.get("/me")
|
|
@login_required
|
|
def my_page():
|
|
return user_page(session["user_id"])
|
|
|
|
@app.get("/exam")
|
|
def exam():
|
|
return render_template("exams/level1.html")
|
|
|
|
@app.get("/examresult")
|
|
def exam_result():
|
|
return render_template("exams/level1_results.html", score=200, user_id=1, user_name="username")
|
|
|
|
def format_reading(reading: str) -> str:
|
|
"""Apply bold to the part of the reading which the kanji represents; for kun, this can be
|
|
e.g. 選: えら-ぶ --> <b>えら</b>ぶ. For reading strings which don't have any "-" character in them,
|
|
one is added to the end and the entire reading is emboldened.
|
|
Example: 簡: かん --> <b>かん</b>
|
|
"""
|
|
if "-" not in reading:
|
|
reading += "-"
|
|
|
|
okurigana_position = reading.index("-")
|
|
emboldened_part = reading[:okurigana_position]
|
|
return f"<b>{emboldened_part}</b>{reading[okurigana_position+1:]}"
|
|
|
|
|
|
@app.route("/kanji/<kanji>")
|
|
def kanji_page(kanji: str):
|
|
kanji_obj = get_kanji_by_character(kanji)
|
|
|
|
class Kanji():
|
|
pass
|
|
|
|
out = Kanji()
|
|
out.character = kanji_obj.character
|
|
out.is_joyo = "常用" if kanji_obj.level not in ["1", "準1"] else "表外"
|
|
out.level = kanji_obj.level
|
|
out.strokes = kanji_obj.stroke_count
|
|
out.radical = kanji_obj.radical
|
|
out.added_strokes = kanji_obj.radical_added_stroke_count
|
|
out.goon = [format_reading(obj.reading) for obj in kanji_obj.goon]
|
|
out.kanon = [format_reading(obj.reading) for obj in kanji_obj.kanon]
|
|
out.toon = [format_reading(obj.reading) for obj in kanji_obj.toon]
|
|
out.soon = [format_reading(obj.reading) for obj in kanji_obj.soon]
|
|
out.kanyoon = [format_reading(obj.reading) for obj in kanji_obj.kanyoon]
|
|
out.kun = [format_reading(obj.reading) for obj in kanji_obj.kun]
|
|
out.meanings = kanji_obj.meanings
|
|
out.glyph_origin = kanji_obj.glyph_origin
|
|
|
|
|
|
return render_template("kanji.html", kanji=out)
|
|
|
|
@app.route("/kotoba/<kotoba>")
|
|
def kotoba_page(kotoba: str):
|
|
return render_template("kotoba.html", kotoba=kotoba)
|
|
|
|
from . import database
|
|
database.initialize_app(app)
|
|
|
|
from . import auth, api, forum, search, indices
|
|
app.register_blueprint(auth.blueprint)
|
|
app.register_blueprint(api.blueprint)
|
|
app.register_blueprint(forum.blueprint)
|
|
app.register_blueprint(search.blueprint)
|
|
app.register_blueprint(indices.blueprint)
|
|
|
|
from . import lang
|
|
lang.add_translation_commands(app)
|
|
|
|
@app.route("/translations", methods=["GET", "POST"])
|
|
def strings_translation():
|
|
if request.method == "GET":
|
|
strings = {}
|
|
for language, language_data in lang.LANGUAGES.items():
|
|
strings[language] = {
|
|
string: translation for string, translation in language_data.items()
|
|
}
|
|
|
|
return render_template("translations.html", strings=strings)
|
|
else:
|
|
strings = {}
|
|
for i, language in enumerate(lang.LANGUAGES):
|
|
strings[language] = {
|
|
string: request.form.getlist(string)[i] for string in request.form
|
|
}
|
|
with open(Path(app.root_path, "static", "lang", f"{language}.json"), mode="w") as f:
|
|
json.dump(strings[language], f, ensure_ascii=False, indent=0)
|
|
|
|
lang.update_languages()
|
|
return redirect("/translations")
|
|
|
|
@app.get(app.config["PFP_STORE"] + "/<img>")
|
|
def get_pfp(img: str):
|
|
return send_file(os.path.join(app.config["PFP_STORE"], img))
|
|
|
|
@app.route("/data")
|
|
def data_page():
|
|
return render_template("data.html")
|
|
|
|
# def use_english(text_id: str):
|
|
# return lang.localize(text_id, lang.JAPANESE)
|
|
app.jinja_env.globals.update(localize=lang.localize)
|
|
|
|
|
|
return app |