cfg.site with markdown
This commit is contained in:
parent
6d015420c0
commit
4fbdb94caa
8 changed files with 99 additions and 91 deletions
|
@ -3,7 +3,8 @@ import tomllib
|
|||
from enum import Enum
|
||||
from random import Random
|
||||
|
||||
from pydantic import BaseModel, field_validator
|
||||
from markdown import markdown
|
||||
from pydantic import BaseModel, ConfigDict, field_validator
|
||||
|
||||
from .dav.webdav import WebDAV
|
||||
from .settings import SETTINGS
|
||||
|
@ -25,6 +26,8 @@ class TransformedString(BaseModel):
|
|||
# whitespace entfernen
|
||||
IGNORE = "IGNORE"
|
||||
|
||||
# special chars
|
||||
|
||||
class __Case(str, Enum):
|
||||
# unverändert
|
||||
KEEP = "KEEP"
|
||||
|
@ -78,10 +81,27 @@ class TransformedString(BaseModel):
|
|||
return result
|
||||
|
||||
|
||||
class Puzzle(BaseModel):
|
||||
class Site(BaseModel):
|
||||
model_config = ConfigDict(validate_default=True)
|
||||
|
||||
# Titel
|
||||
title: str
|
||||
|
||||
# Untertitel
|
||||
subtitle: str
|
||||
|
||||
# Inhalt der Seite
|
||||
content: str
|
||||
|
||||
# Fußzeile der Seite
|
||||
footer: str = "**Advent22** by [Lenaisten e.V.](//www.lenaisten.de)"
|
||||
|
||||
@field_validator("content", "footer", mode="after")
|
||||
def parse_md(cls, v) -> str:
|
||||
return markdown(v)
|
||||
|
||||
|
||||
class Puzzle(BaseModel):
|
||||
# Tag, an dem der Kalender startet
|
||||
begin_day: int = 1
|
||||
|
||||
|
@ -108,6 +128,7 @@ class Config(BaseModel):
|
|||
solution: TransformedString
|
||||
|
||||
# Weitere Einstellungen
|
||||
site: Site
|
||||
puzzle: Puzzle
|
||||
image: Image
|
||||
|
||||
|
@ -117,11 +138,6 @@ class Config(BaseModel):
|
|||
# Serverseitiger zusätzlicher "random" seed
|
||||
random_seed: str = ""
|
||||
|
||||
# Fußzeile der Seite
|
||||
footer: str = (
|
||||
'<strong>Advent22</strong> by <a href="//www.lenaisten.de">Lenaisten e.V.</a>'
|
||||
)
|
||||
|
||||
|
||||
async def get_config() -> Config:
|
||||
"""
|
||||
|
|
|
@ -5,7 +5,7 @@ from fastapi.responses import StreamingResponse
|
|||
from PIL import Image
|
||||
|
||||
from ..core.calendar_config import CalendarConfig, DoorsSaved, get_calendar_config
|
||||
from ..core.config import Config, get_config
|
||||
from ..core.config import Config, Site, get_config
|
||||
from ..core.depends import get_all_event_dates, get_day_image
|
||||
from ..core.helpers import EventDates, api_return_ico, api_return_jpeg, load_image
|
||||
from ._security import user_can_view_day, user_is_admin, user_visible_days
|
||||
|
@ -45,19 +45,15 @@ async def get_favicon(
|
|||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
|
||||
# - favicon
|
||||
# - "user-config-model"
|
||||
|
||||
|
||||
@router.get("/title")
|
||||
async def get_title(
|
||||
@router.get("/site_config")
|
||||
async def get_site_config(
|
||||
cfg: Config = Depends(get_config),
|
||||
) -> str:
|
||||
) -> Site:
|
||||
"""
|
||||
Lädt Kalendertitel
|
||||
Seiteninhalt
|
||||
"""
|
||||
|
||||
return cfg.puzzle.title
|
||||
return cfg.site
|
||||
|
||||
|
||||
@router.get("/doors")
|
||||
|
@ -72,17 +68,6 @@ async def get_doors(
|
|||
return [door for door in cal_cfg.doors if door.day in visible_days]
|
||||
|
||||
|
||||
@router.get("/footer")
|
||||
async def get_footer(
|
||||
cfg: Config = Depends(get_config),
|
||||
) -> str:
|
||||
"""
|
||||
Seiten-Fußzeile lesen
|
||||
"""
|
||||
|
||||
return cfg.footer
|
||||
|
||||
|
||||
@router.get(
|
||||
"/image_{day}",
|
||||
response_class=StreamingResponse,
|
||||
|
|
17
api/poetry.lock
generated
17
api/poetry.lock
generated
|
@ -580,6 +580,21 @@ html5 = ["html5lib"]
|
|||
htmlsoup = ["BeautifulSoup4"]
|
||||
source = ["Cython (>=0.29.35)"]
|
||||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "3.5.1"
|
||||
description = "Python implementation of John Gruber's Markdown."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "Markdown-3.5.1-py3-none-any.whl", hash = "sha256:5874b47d4ee3f0b14d764324d2c94c03ea66bee56f2d929da9f2508d65e722dc"},
|
||||
{file = "Markdown-3.5.1.tar.gz", hash = "sha256:b65d7beb248dc22f2e8a31fb706d93798093c308dc1aba295aedeb9d41a813bd"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"]
|
||||
testing = ["coverage", "pyyaml"]
|
||||
|
||||
[[package]]
|
||||
name = "mccabe"
|
||||
version = "0.7.0"
|
||||
|
@ -1376,4 +1391,4 @@ typing-extensions = ">=4.4.0"
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.11,<3.13"
|
||||
content-hash = "e97f2ab7e4314a0b6ce3725b8068a147a06e5ac5c9ee8e5406ca546dac3075cd"
|
||||
content-hash = "73d5978c4787027b57334c5e5ac98df12e7b9e958bc92a5c326b512861986c57"
|
||||
|
|
|
@ -21,6 +21,7 @@ redis = {extras = ["hiredis"], version = "^5.0.1"}
|
|||
tomli-w = "^1.0.0"
|
||||
uvicorn = {extras = ["standard"], version = "^0.23.2"}
|
||||
webdavclient3 = "^3.14.6"
|
||||
markdown = "^3.5.1"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^23.10.1"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<section class="hero is-small is-primary">
|
||||
<div class="hero-body">
|
||||
<h1 class="title is-uppercase">{{ title }}</h1>
|
||||
<h2 class="subtitle">{{ subtitle }}</h2>
|
||||
<h1 class="title is-uppercase">{{ store.site_config.title }}</h1>
|
||||
<h2 class="subtitle">{{ store.site_config.subtitle }}</h2>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
|||
<footer class="footer">
|
||||
<div class="level">
|
||||
<div class="level-item">
|
||||
<p v-html="footer" />
|
||||
<p v-html="store.site_config.footer" />
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="level-item">
|
||||
|
@ -50,25 +50,10 @@ import UserView from "./components/UserView.vue";
|
|||
},
|
||||
})
|
||||
export default class extends Vue {
|
||||
public title = "Adventskalender";
|
||||
public subtitle = "Lorem Ipsum";
|
||||
public footer = "";
|
||||
public readonly store = advent22Store();
|
||||
|
||||
public mounted(): void {
|
||||
Promise.all([
|
||||
this.$advent22.api_get<string>("user/title"),
|
||||
this.subtitle, // TODO
|
||||
this.$advent22.api_get<string>("user/footer"),
|
||||
])
|
||||
.then(([title, subtitle, footer]) => {
|
||||
document.title = `${title} – ${subtitle}`;
|
||||
|
||||
this.title = title;
|
||||
this.subtitle = subtitle;
|
||||
this.footer = footer;
|
||||
})
|
||||
.catch(this.$advent22.alert_user_error);
|
||||
this.store.init();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -37,9 +37,6 @@
|
|||
|
||||
<h3>Rätsel</h3>
|
||||
<dl>
|
||||
<dt>Titel</dt>
|
||||
<dd>{{ title }}</dd>
|
||||
|
||||
<dt>Offene Türchen</dt>
|
||||
<dd>{{ num_user_doors }}</dd>
|
||||
|
||||
|
@ -47,9 +44,6 @@
|
|||
<dd v-if="next_door === null">Kein nächstes Türchen</dd>
|
||||
<dd v-else><CountDown :millis="next_door" /></dd>
|
||||
|
||||
<dt>Fußzeile</dt>
|
||||
<dd class="is-family-monospace">{{ footer }}</dd>
|
||||
|
||||
<dt>Erstes Türchen</dt>
|
||||
<dd>{{ fmt_puzzle_date("first") }}</dd>
|
||||
|
||||
|
@ -218,8 +212,6 @@ export default class extends Vue {
|
|||
},
|
||||
};
|
||||
public doors: DoorsSaved = [];
|
||||
public title = "";
|
||||
public footer = "";
|
||||
public num_user_doors = 0;
|
||||
public next_door: number | null = null;
|
||||
public dav_credentials: Credentials = ["", ""];
|
||||
|
@ -237,22 +229,16 @@ export default class extends Vue {
|
|||
this.$advent22.api_get<AdminConfigModel>("admin/config_model"),
|
||||
this.$advent22.api_get<DoorsSaved>("admin/doors"),
|
||||
this.$advent22.api_get<DoorsSaved>("user/doors"),
|
||||
this.$advent22.api_get<string>("user/title"),
|
||||
this.$advent22.api_get<string>("user/footer"),
|
||||
this.$advent22.api_get<number | null>("user/next_door"),
|
||||
])
|
||||
.then(
|
||||
([admin_config_model, doors, user_doors, title, footer, next_door]) => {
|
||||
this.admin_config_model = admin_config_model;
|
||||
this.doors = doors;
|
||||
this.num_user_doors = user_doors.length;
|
||||
this.title = title;
|
||||
this.footer = footer;
|
||||
this.next_door = next_door;
|
||||
.then(([admin_config_model, doors, user_doors, next_door]) => {
|
||||
this.admin_config_model = admin_config_model;
|
||||
this.doors = doors;
|
||||
this.num_user_doors = user_doors.length;
|
||||
this.next_door = next_door;
|
||||
|
||||
ready();
|
||||
},
|
||||
)
|
||||
ready();
|
||||
})
|
||||
.catch(fail);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,13 @@ export interface AdminConfigModel {
|
|||
};
|
||||
}
|
||||
|
||||
export interface SiteConfigModel {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
content: string;
|
||||
footer: string;
|
||||
}
|
||||
|
||||
export interface NumStrDict {
|
||||
[key: number]: string;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Credentials } from "@/lib/api";
|
||||
import { Credentials, SiteConfigModel } from "@/lib/api";
|
||||
import { ADVENT22 } from "@/plugins/advent22";
|
||||
import { AxiosBasicCredentials } from "axios";
|
||||
import { acceptHMRUpdate, defineStore } from "pinia";
|
||||
|
@ -9,27 +9,17 @@ const empty_creds = () => ["", ""] as Credentials;
|
|||
export const advent22Store = defineStore({
|
||||
id: "advent22",
|
||||
|
||||
state: () => {
|
||||
ADVENT22.api_get_blob("user/favicon")
|
||||
.then((favicon_src) => {
|
||||
const link: HTMLLinkElement =
|
||||
document.querySelector("link[rel*='icon']") ||
|
||||
document.createElement("link");
|
||||
link.rel = "shortcut icon";
|
||||
link.type = "image/x-icon";
|
||||
link.href = favicon_src;
|
||||
|
||||
if (link.parentElement === null)
|
||||
document.getElementsByTagName("head")[0].appendChild(link);
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
return {
|
||||
api_creds: empty_creds(),
|
||||
is_admin: false,
|
||||
is_touch_device: check_touch_device(),
|
||||
};
|
||||
},
|
||||
state: () => ({
|
||||
api_creds: empty_creds(),
|
||||
is_admin: false,
|
||||
site_config: {
|
||||
title: "Adventskalender",
|
||||
subtitle: "Lorem Ipsum",
|
||||
content: "",
|
||||
footer: "",
|
||||
} as SiteConfigModel,
|
||||
is_touch_device: check_touch_device(),
|
||||
}),
|
||||
|
||||
getters: {
|
||||
axios_creds: (state): AxiosBasicCredentials => {
|
||||
|
@ -39,6 +29,29 @@ export const advent22Store = defineStore({
|
|||
},
|
||||
|
||||
actions: {
|
||||
init(): void {
|
||||
ADVENT22.api_get_blob("user/favicon")
|
||||
.then((favicon_src) => {
|
||||
const link: HTMLLinkElement =
|
||||
document.querySelector("link[rel*='icon']") ||
|
||||
document.createElement("link");
|
||||
link.rel = "shortcut icon";
|
||||
link.type = "image/x-icon";
|
||||
link.href = favicon_src;
|
||||
|
||||
if (link.parentElement === null)
|
||||
document.getElementsByTagName("head")[0].appendChild(link);
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
ADVENT22.api_get<SiteConfigModel>("user/site_config")
|
||||
.then((site_config) => {
|
||||
document.title = `${site_config.title} – ${site_config.subtitle}`;
|
||||
this.site_config = site_config;
|
||||
})
|
||||
.catch(ADVENT22.alert_user_error);
|
||||
},
|
||||
|
||||
login(creds: Credentials = empty_creds()): Promise<boolean> {
|
||||
this.api_creds = creds;
|
||||
|
||||
|
|
Loading…
Reference in a new issue