mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 19:44:20 +00:00
Readd bios to profiles
This commit is contained in:
parent
c0fca28c9a
commit
04d360c20f
16 changed files with 328 additions and 93 deletions
|
@ -2,7 +2,7 @@ from sqlalchemy import Column, \
|
||||||
Integer, \
|
Integer, \
|
||||||
Text, \
|
Text, \
|
||||||
ForeignKey
|
ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship, backref
|
||||||
from sqlalchemy.ext.declarative import declared_attr
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from .royals import Royal
|
from .royals import Royal
|
||||||
|
|
||||||
|
@ -16,11 +16,11 @@ class Bio:
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def royal(self):
|
def royal(self):
|
||||||
return relationship("Royal")
|
return relationship("Royal", backref=backref("bio", uselist=False))
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def contents(self):
|
def contents(self):
|
||||||
return Column(Text, unique=True, nullable=False)
|
return Column(Text, nullable=False, default="")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Bio of {self.royal}>"
|
return f"<Bio of {self.royal}>"
|
||||||
|
|
|
@ -22,7 +22,7 @@ class WikiPage:
|
||||||
return Column(String, nullable=False)
|
return Column(String, nullable=False)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def content(self):
|
def contents(self):
|
||||||
return Column(Text)
|
return Column(Text)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
|
|
29
royalnet/utils/wikirender.py
Normal file
29
royalnet/utils/wikirender.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import re
|
||||||
|
import markdown2
|
||||||
|
|
||||||
|
|
||||||
|
class RenderError(Exception):
|
||||||
|
"""An error occurred while trying to render the page."""
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_page_markdown(markdown):
|
||||||
|
if list(markdown).count(">") > 99:
|
||||||
|
raise RenderError("Too many nested quotes")
|
||||||
|
converted_md = markdown2.markdown(markdown.replace("<", "<"),
|
||||||
|
extras=["spoiler", "tables", "smarty-pants", "fenced-code-blocks"])
|
||||||
|
converted_md = re.sub(r"{https?://(?:www\.)?(?:youtube\.com/watch\?.*?&?v=|youtu.be/)([0-9A-Za-z-]+).*?}",
|
||||||
|
r'<div class="youtube-embed">'
|
||||||
|
r' <iframe src="https://www.youtube-nocookie.com/embed/\1?rel=0&showinfo=0"'
|
||||||
|
r' frameborder="0"'
|
||||||
|
r' allow="autoplay; encrypted-media"'
|
||||||
|
r' allowfullscreen'
|
||||||
|
r' width="640px"'
|
||||||
|
r' height="320px">'
|
||||||
|
r' </iframe>'
|
||||||
|
r'</div>', converted_md)
|
||||||
|
converted_md = re.sub(r"{https?://clyp.it/([a-z0-9]+)}",
|
||||||
|
r'<div class="clyp-embed">'
|
||||||
|
r' <iframe width="100%" height="160" src="https://clyp.it/\1/widget" frameborder="0">'
|
||||||
|
r' </iframe>'
|
||||||
|
r'</div>', converted_md)
|
||||||
|
return converted_md
|
|
@ -23,7 +23,7 @@
|
||||||
<div class="diario-quote">
|
<div class="diario-quote">
|
||||||
—
|
—
|
||||||
{% if entry.quoted_account %}
|
{% if entry.quoted_account %}
|
||||||
<a href="{{ url_for("profile.profile_by_username", username=entry.quoted_account.username) }}" class="diario-quoted">{{ entry.quoted }}</a>
|
<a href="{{ url_for("profile.profile_page", username=entry.quoted_account.username) }}" class="diario-quoted">{{ entry.quoted }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="diario-quoted">{{ entry.quoted }}</span>
|
<span class="diario-quoted">{{ entry.quoted }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if entry.creator %}
|
{% if entry.creator %}
|
||||||
<div class="diario-created">Salvato da <a href="{{ url_for("profile.profile_by_username", username=entry.creator.username) }}" class="diario-creator">{{ entry.creator.username }}</a></div>
|
<div class="diario-created">Salvato da <a href="{{ url_for("profile.profile_page", username=entry.creator.username) }}" class="diario-creator">{{ entry.creator.username }}</a></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<time class="diario-timestamp" datetime="{{ entry.timestamp.isoformat() }}">{{ entry.timestamp.strftime("%d %b %Y %H:%M:%S") }}</time>
|
<time class="diario-timestamp" datetime="{{ entry.timestamp.isoformat() }}">{{ entry.timestamp.strftime("%d %b %Y %H:%M:%S") }}</time>
|
||||||
<span class="diario-id">#{{ entry.diario_id }}</span>
|
<span class="diario-id">#{{ entry.diario_id }}</span>
|
||||||
|
|
|
@ -5,13 +5,14 @@ import os
|
||||||
from ...royalprint import Royalprint
|
from ...royalprint import Royalprint
|
||||||
from ...shortcuts import error
|
from ...shortcuts import error
|
||||||
from ....database.tables import *
|
from ....database.tables import *
|
||||||
|
from ....utils.wikirender import prepare_page_markdown, RenderError
|
||||||
|
|
||||||
|
|
||||||
# Maybe some of these tables are optional...
|
# Maybe some of these tables are optional...
|
||||||
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
|
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
|
||||||
rp = Royalprint("profile", __name__, url_prefix="/profile", template_folder=tmpl_dir,
|
rp = Royalprint("profile", __name__, url_prefix="/profile", template_folder=tmpl_dir,
|
||||||
required_tables={Royal, ActiveKvGroup, Alias, Diario, Discord, Keygroup, Keyvalue, Telegram, WikiPage,
|
required_tables={Royal, ActiveKvGroup, Alias, Diario, Discord, Keygroup, Keyvalue, Telegram, WikiPage,
|
||||||
WikiRevision})
|
WikiRevision, Bio})
|
||||||
|
|
||||||
|
|
||||||
@rp.route("/")
|
@rp.route("/")
|
||||||
|
@ -22,9 +23,39 @@ def profile_index():
|
||||||
|
|
||||||
|
|
||||||
@rp.route("/<username>")
|
@rp.route("/<username>")
|
||||||
def profile_by_username(username):
|
def profile_page(username):
|
||||||
alchemy, alchemy_session = f.current_app.config["ALCHEMY"], f.current_app.config["ALCHEMY_SESSION"]
|
alchemy, alchemy_session = f.current_app.config["ALCHEMY"], f.current_app.config["ALCHEMY_SESSION"]
|
||||||
royal = alchemy_session.query(alchemy.Royal).filter_by(username=username).one_or_none()
|
royal = alchemy_session.query(alchemy.Royal).filter_by(username=username).one_or_none()
|
||||||
if royal is None:
|
if royal is None:
|
||||||
return error(404, "Non esiste nessun utente con l'username richiesto.")
|
return error(404, "Non esiste nessun utente con l'username richiesto.")
|
||||||
return f.render_template("profile_page.html", royal=royal)
|
if royal.bio is not None and royal.bio.contents != "":
|
||||||
|
try:
|
||||||
|
parsed_bio = f.Markup(prepare_page_markdown(royal.bio.contents))
|
||||||
|
except RenderError as e:
|
||||||
|
return error(500, f"Il profilo non può essere visualizzato a causa di un errore nella bio: {str(e)}")
|
||||||
|
else:
|
||||||
|
parsed_bio = None
|
||||||
|
return f.render_template("profile_page.html", royal=royal, parsed_bio=parsed_bio)
|
||||||
|
|
||||||
|
|
||||||
|
@rp.route("/<username>/editbio", methods=["GET", "POST"])
|
||||||
|
def profile_editbio(username):
|
||||||
|
if "royal" not in f.session:
|
||||||
|
return error(403, "Devi aver effettuato il login per modificare una bio.")
|
||||||
|
alchemy, alchemy_session = f.current_app.config["ALCHEMY"], f.current_app.config["ALCHEMY_SESSION"]
|
||||||
|
royal = alchemy_session.query(alchemy.Royal).filter_by(username=username).one_or_none()
|
||||||
|
if not (f.session["royal"]["uid"] == royal.uid or f.session["royal"]["role"] == "Admin"):
|
||||||
|
return error(403, "Non sei autorizzato a modificare questa pagina bio.")
|
||||||
|
|
||||||
|
if f.request.method == "GET":
|
||||||
|
return f.render_template("profile_editbio.html", royal=royal)
|
||||||
|
|
||||||
|
elif f.request.method == "POST":
|
||||||
|
fd = f.request.form
|
||||||
|
if royal.bio is None:
|
||||||
|
bio = alchemy.Bio(royal=royal, contents=fd.get("contents", ""))
|
||||||
|
alchemy_session.add(bio)
|
||||||
|
else:
|
||||||
|
royal.bio.contents = fd.get("contents", "")
|
||||||
|
alchemy_session.commit()
|
||||||
|
return f.redirect(f.url_for(".profile_page", username=username))
|
||||||
|
|
126
royalnet/web/royalprints/profile/templates/profile_editbio.html
Normal file
126
royalnet/web/royalprints/profile/templates/profile_editbio.html
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{{ royal.username }} - RYGbioeditor
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="dbox">
|
||||||
|
<div class="dbox-top">
|
||||||
|
<span class="left">
|
||||||
|
Editor Bio
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="dbox-bot">
|
||||||
|
<form method="POST" class="full">
|
||||||
|
<!--suppress HtmlFormInputWithoutLabel -->
|
||||||
|
<textarea id="profile-editbio-contents" name="contents">{{ royal.bio.contents }}</textarea>
|
||||||
|
<label for="profile-editbio-submit">
|
||||||
|
<input id="profile-editbio-submit" type="submit" value="Salva">
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block footscripts %}
|
||||||
|
<script>
|
||||||
|
//TODO: maybe enable autosave?
|
||||||
|
let simplemde = new SimpleMDE({
|
||||||
|
element: document.getElementById("profile-editbio-contents"),
|
||||||
|
blockStyles: {
|
||||||
|
italic: "_"
|
||||||
|
},
|
||||||
|
tabSize: 4,
|
||||||
|
spellChecker: false,
|
||||||
|
toolbar: [
|
||||||
|
{
|
||||||
|
name: "bold",
|
||||||
|
action: SimpleMDE.toggleBold,
|
||||||
|
className: "fas fa-bold no-icon",
|
||||||
|
title: "Grassetto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "italic",
|
||||||
|
action: SimpleMDE.toggleItalic,
|
||||||
|
className: "fas fa-italic no-icon",
|
||||||
|
title: "Corsivo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "strikethrough",
|
||||||
|
action: SimpleMDE.toggleStrikethrough,
|
||||||
|
className: "fas fa-strikethrough no-icon",
|
||||||
|
title: "Barrato",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "link",
|
||||||
|
action: SimpleMDE.drawLink,
|
||||||
|
className: "fas fa-link no-icon",
|
||||||
|
title: "Link",
|
||||||
|
},
|
||||||
|
"|",
|
||||||
|
{
|
||||||
|
name: "heading-smaller",
|
||||||
|
action: SimpleMDE.toggleHeadingSmaller,
|
||||||
|
className: "fas fa-header no-icon",
|
||||||
|
title: "(Rimpicciolisci) Titolo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "heading",
|
||||||
|
action: SimpleMDE.toggleHeadingBigger,
|
||||||
|
className: "fas fa-header fa-lg no-icon",
|
||||||
|
title: "(Ingrandisci) Titolo",
|
||||||
|
},
|
||||||
|
"|",
|
||||||
|
{
|
||||||
|
name: "code",
|
||||||
|
action: SimpleMDE.toggleCodeBlock,
|
||||||
|
className: "fas fa-code no-icon",
|
||||||
|
title: "Codice",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "quote",
|
||||||
|
action: SimpleMDE.toggleBlockquote,
|
||||||
|
className: "fas fa-quote-left no-icon",
|
||||||
|
title: "Citazione",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unordered-list",
|
||||||
|
action: SimpleMDE.toggleUnorderedList,
|
||||||
|
className: "fas fa-list-ul no-icon",
|
||||||
|
title: "Lista puntata",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ordered-list",
|
||||||
|
action: SimpleMDE.toggleOrderedList,
|
||||||
|
className: "fas fa-list-ol no-icon",
|
||||||
|
title: "Lista ordinata",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "horizontal-rule",
|
||||||
|
action: SimpleMDE.drawHorizontalRule,
|
||||||
|
className: "fas fa-minus no-icon",
|
||||||
|
title: "Separatore",
|
||||||
|
},
|
||||||
|
"|",
|
||||||
|
{
|
||||||
|
name: "image",
|
||||||
|
action: SimpleMDE.drawImage,
|
||||||
|
className: "fas fa-picture-o no-icon",
|
||||||
|
title: "Immagine",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "table",
|
||||||
|
action: SimpleMDE.drawTable,
|
||||||
|
className: "fas fa-table no-icon",
|
||||||
|
title: "Tabella",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
|
@ -14,7 +14,7 @@
|
||||||
<div class="dbox-bot">
|
<div class="dbox-bot">
|
||||||
<ul>
|
<ul>
|
||||||
{% for royal in royals %}
|
{% for royal in royals %}
|
||||||
<li><a href="{{ url_for("profile.profile_by_username", username=royal.username) }}">{{ royal.username }}</a></li>
|
<li><a href="{{ url_for("profile.profile_page", username=royal.username) }}">{{ royal.username }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,6 +9,29 @@
|
||||||
<h1>
|
<h1>
|
||||||
{{ royal.username }}
|
{{ royal.username }}
|
||||||
</h1>
|
</h1>
|
||||||
|
<div class="profile-bio">
|
||||||
|
<div class="dbox">
|
||||||
|
<div class="dbox-top">
|
||||||
|
<span class="left">
|
||||||
|
Bio
|
||||||
|
</span>
|
||||||
|
<span class="right">
|
||||||
|
{% if session["royal"]["uid"] == royal.uid or session["royal"]["role"] == "Admin" %}
|
||||||
|
<a class="edit no-icon" href="{{ url_for("profile.profile_editbio", username=royal.username) }}">Modifica</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="edit no-icon disabled" title="Non sei autorizzato a modificare questa bio.">Modifica</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="dbox-bot">
|
||||||
|
{% if parsed_bio %}
|
||||||
|
{{ parsed_bio }}
|
||||||
|
{% else %}
|
||||||
|
<span class="disabled">Questo utente non ha nessuna bio.</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="columns-3">
|
<div class="columns-3">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="dbox profile-links">
|
<div class="dbox profile-links">
|
||||||
|
@ -17,7 +40,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="dbox-bot">
|
<div class="dbox-bot">
|
||||||
<ul class="links-list">
|
<ul class="links-list">
|
||||||
<li><span class="links-item links-linked">royalnet:{{ royal.username }}</span></li>
|
<li><span class="links-item links-linked" title="{{ royal.uid }}">royalnet:{{ royal.username }}</span></li>
|
||||||
{% for telegram in royal.telegram %}
|
{% for telegram in royal.telegram %}
|
||||||
{% if telegram.username %}
|
{% if telegram.username %}
|
||||||
<li><a class="links-item links-linked" href="https://t.me/{{ telegram.username }}">telegram:{{ telegram.mention() }}</a></li>
|
<li><a class="links-item links-linked" href="https://t.me/{{ telegram.username }}">telegram:{{ telegram.mention() }}</a></li>
|
||||||
|
@ -70,11 +93,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h2>
|
|
||||||
Medals
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
TODO
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -24,12 +24,12 @@ def wikiedit_newpage():
|
||||||
|
|
||||||
elif f.request.method == "POST":
|
elif f.request.method == "POST":
|
||||||
fd = f.request.form
|
fd = f.request.form
|
||||||
if not ("title" in fd and "content" in fd and "css" in fd):
|
if not ("title" in fd and "contents" in fd and "css" in fd):
|
||||||
return error(400, "Uno dei campi obbligatori non è stato compilato. Controlla e riprova!")
|
return error(400, "Uno dei campi obbligatori non è stato compilato. Controlla e riprova!")
|
||||||
alchemy, alchemy_session = f.current_app.config["ALCHEMY"], f.current_app.config["ALCHEMY_SESSION"]
|
alchemy, alchemy_session = f.current_app.config["ALCHEMY"], f.current_app.config["ALCHEMY_SESSION"]
|
||||||
page = alchemy.WikiPage(page_id=uuid.uuid4(),
|
page = alchemy.WikiPage(page_id=uuid.uuid4(),
|
||||||
title=fd["title"],
|
title=fd["title"],
|
||||||
content=fd["content"],
|
contents=fd["contents"],
|
||||||
format="markdown",
|
format="markdown",
|
||||||
css=fd["css"] if fd["css"] != "None" else None)
|
css=fd["css"] if fd["css"] != "None" else None)
|
||||||
revision = alchemy.WikiRevision(revision_id=uuid.uuid4(),
|
revision = alchemy.WikiRevision(revision_id=uuid.uuid4(),
|
||||||
|
@ -37,7 +37,7 @@ def wikiedit_newpage():
|
||||||
author_id=f.session["royal"]["uid"],
|
author_id=f.session["royal"]["uid"],
|
||||||
timestamp=datetime.datetime.now(),
|
timestamp=datetime.datetime.now(),
|
||||||
reason=fd.get("reason"),
|
reason=fd.get("reason"),
|
||||||
diff="\n".join(difflib.unified_diff([], page.content.split("\n"))))
|
diff="\n".join(difflib.unified_diff([], page.contents.split("\n"))))
|
||||||
alchemy_session.add(page)
|
alchemy_session.add(page)
|
||||||
alchemy_session.add(revision)
|
alchemy_session.add(revision)
|
||||||
alchemy_session.commit()
|
alchemy_session.commit()
|
||||||
|
@ -61,7 +61,7 @@ def wikiedit_by_id(page_id: str, title: str):
|
||||||
|
|
||||||
elif f.request.method == "POST":
|
elif f.request.method == "POST":
|
||||||
fd = f.request.form
|
fd = f.request.form
|
||||||
if not ("title" in fd and "content" in fd and "css" in fd):
|
if not ("title" in fd and "contents" in fd and "css" in fd):
|
||||||
return error(400, "Uno dei campi obbligatori non è stato compilato. Controlla e riprova!")
|
return error(400, "Uno dei campi obbligatori non è stato compilato. Controlla e riprova!")
|
||||||
# Create new revision
|
# Create new revision
|
||||||
revision = alchemy.WikiRevision(revision_id=uuid.uuid4(),
|
revision = alchemy.WikiRevision(revision_id=uuid.uuid4(),
|
||||||
|
@ -69,10 +69,10 @@ def wikiedit_by_id(page_id: str, title: str):
|
||||||
author_id=f.session["royal"]["uid"],
|
author_id=f.session["royal"]["uid"],
|
||||||
timestamp=datetime.datetime.now(),
|
timestamp=datetime.datetime.now(),
|
||||||
reason=fd.get("reason"),
|
reason=fd.get("reason"),
|
||||||
diff="\n".join(difflib.unified_diff(page.content.split("\n"), fd["content"].split("\n"))))
|
diff="\n".join(difflib.unified_diff(page.contents.split("\n"), fd["contents"].split("\n"))))
|
||||||
alchemy_session.add(revision)
|
alchemy_session.add(revision)
|
||||||
# Apply changes
|
# Apply changes
|
||||||
page.content = fd["content"]
|
page.contents = fd["contents"]
|
||||||
page.title = fd["title"]
|
page.title = fd["title"]
|
||||||
page.css = fd["css"] if fd["css"] != "None" else None
|
page.css = fd["css"] if fd["css"] != "None" else None
|
||||||
alchemy_session.commit()
|
alchemy_session.commit()
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<input id="wikiedit-format" type="text" name="format" disabled value="markdown">
|
<input id="wikiedit-format" type="text" name="format" disabled value="markdown">
|
||||||
</label>
|
</label>
|
||||||
<!--suppress HtmlFormInputWithoutLabel -->
|
<!--suppress HtmlFormInputWithoutLabel -->
|
||||||
<textarea id="wikiedit-content" name="content">{{ page.content }}</textarea>
|
<textarea id="wikiedit-contents" name="contents">{{ page.contents }}</textarea>
|
||||||
<label for="wikiedit-css">
|
<label for="wikiedit-css">
|
||||||
<span class="label-text">Tema</span>
|
<span class="label-text">Tema</span>
|
||||||
<select id="wikiedit-css" name="css">
|
<select id="wikiedit-css" name="css">
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
<script>
|
<script>
|
||||||
//TODO: maybe enable autosave?
|
//TODO: maybe enable autosave?
|
||||||
let simplemde = new SimpleMDE({
|
let simplemde = new SimpleMDE({
|
||||||
element: document.getElementById("wikiedit-content"),
|
element: document.getElementById("wikiedit-contents"),
|
||||||
blockStyles: {
|
blockStyles: {
|
||||||
italic: "_"
|
italic: "_"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
"""A Royal Games Wiki viewer :py:class:`royalnet.web.Royalprint`. Doesn't support any kind of edit."""
|
"""A Royal Games Wiki viewer :py:class:`royalnet.web.Royalprint`. Doesn't support any kind of edit."""
|
||||||
|
|
||||||
import flask as f
|
import flask as f
|
||||||
import markdown2
|
|
||||||
import re
|
|
||||||
import os
|
import os
|
||||||
from ...royalprint import Royalprint
|
from ...royalprint import Royalprint
|
||||||
from ...shortcuts import error, from_urluuid
|
from ...shortcuts import error, from_urluuid
|
||||||
from ....database.tables import Royal, WikiPage, WikiRevision
|
from ....database.tables import Royal, WikiPage, WikiRevision
|
||||||
|
from ....utils.wikirender import prepare_page_markdown, RenderError
|
||||||
|
|
||||||
|
|
||||||
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
|
tmpl_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
|
||||||
|
@ -14,48 +13,21 @@ rp = Royalprint("wikiview", __name__, url_prefix="/wiki/view", template_folder=t
|
||||||
required_tables={Royal, WikiPage, WikiRevision})
|
required_tables={Royal, WikiPage, WikiRevision})
|
||||||
|
|
||||||
|
|
||||||
class WikiRenderError(Exception):
|
|
||||||
"""An error occurred while trying to render the wiki page."""
|
|
||||||
|
|
||||||
|
|
||||||
def prepare_page_markdown(page):
|
|
||||||
if list(page.content).count(">") > 99:
|
|
||||||
raise WikiRenderError("Too many nested quotes")
|
|
||||||
converted_md = markdown2.markdown(page.content.replace("<", "<"),
|
|
||||||
extras=["spoiler", "tables", "smarty-pants", "fenced-code-blocks"])
|
|
||||||
converted_md = re.sub(r"{https?://(?:www\.)?(?:youtube\.com/watch\?.*?&?v=|youtu.be/)([0-9A-Za-z-]+).*?}",
|
|
||||||
r'<div class="youtube-embed">'
|
|
||||||
r' <iframe src="https://www.youtube-nocookie.com/embed/\1?rel=0&showinfo=0"'
|
|
||||||
r' frameborder="0"'
|
|
||||||
r' allow="autoplay; encrypted-media"'
|
|
||||||
r' allowfullscreen'
|
|
||||||
r' width="640px"'
|
|
||||||
r' height="320px">'
|
|
||||||
r' </iframe>'
|
|
||||||
r'</div>', converted_md)
|
|
||||||
converted_md = re.sub(r"{https?://clyp.it/([a-z0-9]+)}",
|
|
||||||
r'<div class="clyp-embed">'
|
|
||||||
r' <iframe width="100%" height="160" src="https://clyp.it/\1/widget" frameborder="0">'
|
|
||||||
r' </iframe>'
|
|
||||||
r'</div>', converted_md)
|
|
||||||
return f.Markup(converted_md)
|
|
||||||
|
|
||||||
|
|
||||||
def prepare_page(page):
|
def prepare_page(page):
|
||||||
try:
|
try:
|
||||||
if page.format == "markdown":
|
if page.format == "markdown":
|
||||||
return f.render_template("wikiview_page.html",
|
return f.render_template("wikiview_page.html",
|
||||||
page=page,
|
page=page,
|
||||||
parsed_content=f.Markup(prepare_page_markdown(page)),
|
parsed_contents=f.Markup(prepare_page_markdown(page.contents)),
|
||||||
css=page.css)
|
css=page.css)
|
||||||
elif page.format == "html":
|
elif page.format == "html":
|
||||||
return f.render_template("wikiview_page.html",
|
return f.render_template("wikiview_page.html",
|
||||||
page=page,
|
page=page,
|
||||||
parsed_content=f.Markup(page.content),
|
parsed_contents=f.Markup(page.contents),
|
||||||
css=page.css)
|
css=page.css)
|
||||||
else:
|
else:
|
||||||
return error(500, f"Non esiste nessun handler in grado di preparare pagine con il formato {page.format}.")
|
return error(500, f"Non esiste nessun handler in grado di preparare pagine con il formato {page.format}.")
|
||||||
except WikiRenderError as e:
|
except RenderError as e:
|
||||||
return error(500, f"La pagina Wiki non può essere preparata a causa di un errore: {str(e)}")
|
return error(500, f"La pagina Wiki non può essere preparata a causa di un errore: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="edit no-icon disabled" title="Devi fare il login per modificare pagine!">Modifica</a>
|
<a class="edit no-icon disabled" title="Devi fare il login per modificare pagine!">Modifica</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
<a class="permalink no-icon" href="{{ url_for("wikiview.wikiview_by_id", page_id=page.page_short_id, title=page.title) }}">Permalink</a>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="dbox-bot">
|
<div class="dbox-bot">
|
||||||
|
@ -26,8 +24,8 @@
|
||||||
<h1 class="wikiview-title">
|
<h1 class="wikiview-title">
|
||||||
{{ page.title }}
|
{{ page.title }}
|
||||||
</h1>
|
</h1>
|
||||||
<div class="wikiview-content">
|
<div class="wikiview-contents">
|
||||||
{{ parsed_content }}
|
{{ parsed_contents }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -160,16 +160,6 @@ blockquote {
|
||||||
padding: 2px 4px 2px 8px;
|
padding: 2px 4px 2px 8px;
|
||||||
margin: 8px;
|
margin: 8px;
|
||||||
}
|
}
|
||||||
blockquote.spoiler {
|
|
||||||
color: transparent;
|
|
||||||
background-color: rgba(255, 125, 125, 0.1);
|
|
||||||
border: 1px solid rgba(255, 125, 125, 0.1);
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
blockquote.spoiler:hover {
|
|
||||||
color: #ff7d7d;
|
|
||||||
}
|
|
||||||
textarea {
|
textarea {
|
||||||
background-color: rgba(160, 204, 255, 0.1);
|
background-color: rgba(160, 204, 255, 0.1);
|
||||||
color: #a0ccff;
|
color: #a0ccff;
|
||||||
|
@ -353,6 +343,7 @@ form.full label.label-big * {
|
||||||
border-left: 1px solid rgba(160, 204, 255, 0.2) !important;
|
border-left: 1px solid rgba(160, 204, 255, 0.2) !important;
|
||||||
border-right: 1px solid rgba(160, 204, 255, 0.2) !important;
|
border-right: 1px solid rgba(160, 204, 255, 0.2) !important;
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
|
caret-color: white;
|
||||||
}
|
}
|
||||||
.CodeMirror .cm-link {
|
.CodeMirror .cm-link {
|
||||||
color: #7dffff !important;
|
color: #7dffff !important;
|
||||||
|
@ -378,6 +369,9 @@ form.full label.label-big * {
|
||||||
.CodeMirror .cm-header {
|
.CodeMirror .cm-header {
|
||||||
color: #ffffff !important;
|
color: #ffffff !important;
|
||||||
}
|
}
|
||||||
|
.CodeMirror .CodeMirror-cursor {
|
||||||
|
border-left: 1px solid #a0ccff !important;
|
||||||
|
}
|
||||||
.editor-toolbar,
|
.editor-toolbar,
|
||||||
.editor-statusbar {
|
.editor-statusbar {
|
||||||
background-color: #1c2b4f !important;
|
background-color: #1c2b4f !important;
|
||||||
|
@ -404,6 +398,30 @@ form.full label.label-big * {
|
||||||
background-color: rgba(160, 204, 255, 0.2) !important;
|
background-color: rgba(160, 204, 255, 0.2) !important;
|
||||||
color: #ffffff !important;
|
color: #ffffff !important;
|
||||||
}
|
}
|
||||||
|
.editor-toolbar .fas,
|
||||||
|
.editor-statusbar .fas,
|
||||||
|
.editor-toolbar .far,
|
||||||
|
.editor-statusbar .far,
|
||||||
|
.editor-toolbar .fab,
|
||||||
|
.editor-statusbar .fab {
|
||||||
|
color: #a0ccff !important;
|
||||||
|
}
|
||||||
|
.editor-toolbar .fas:hover,
|
||||||
|
.editor-statusbar .fas:hover,
|
||||||
|
.editor-toolbar .far:hover,
|
||||||
|
.editor-statusbar .far:hover,
|
||||||
|
.editor-toolbar .fab:hover,
|
||||||
|
.editor-statusbar .fab:hover {
|
||||||
|
color: #a0ccff !important;
|
||||||
|
}
|
||||||
|
.editor-toolbar .fas:active,
|
||||||
|
.editor-statusbar .fas:active,
|
||||||
|
.editor-toolbar .far:active,
|
||||||
|
.editor-statusbar .far:active,
|
||||||
|
.editor-toolbar .fab:active,
|
||||||
|
.editor-statusbar .fab:active {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
.editor-toolbar {
|
.editor-toolbar {
|
||||||
border-top: 1px solid #2b3e62 !important;
|
border-top: 1px solid #2b3e62 !important;
|
||||||
border-left: 1px solid #2b3e62 !important;
|
border-left: 1px solid #2b3e62 !important;
|
||||||
|
@ -607,31 +625,56 @@ form.full label.label-big * {
|
||||||
}
|
}
|
||||||
.spoiler {
|
.spoiler {
|
||||||
color: transparent;
|
color: transparent;
|
||||||
border: 1px solid rgba(160, 204, 255, 0.1);
|
background-color: rgba(255, 125, 125, 0.1);
|
||||||
|
border: 1px solid rgba(255, 125, 125, 0.1);
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
.spoiler b,
|
||||||
|
.spoiler strong,
|
||||||
|
.spoiler i,
|
||||||
|
.spoiler em {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
.spoiler b:hover,
|
||||||
|
.spoiler strong:hover,
|
||||||
|
.spoiler i:hover,
|
||||||
|
.spoiler em:hover {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
.spoilerblockquote {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
.spoiler:hover {
|
.spoiler:hover {
|
||||||
color: #a0ccff;
|
color: #ff7d7d;
|
||||||
}
|
}
|
||||||
.wiki .wiki-doublebox .dbox-bot {
|
.wiki .wiki-doublebox .dbox-bot,
|
||||||
|
.profile-bio .wiki-doublebox .dbox-bot {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
border-bottom: 4px solid rgba(160, 204, 255, 0.2);
|
border-bottom: 4px solid rgba(160, 204, 255, 0.2);
|
||||||
border-left: 4px solid rgba(160, 204, 255, 0.2);
|
border-left: 4px solid rgba(160, 204, 255, 0.2);
|
||||||
border-right: 4px solid rgba(160, 204, 255, 0.2);
|
border-right: 4px solid rgba(160, 204, 255, 0.2);
|
||||||
}
|
}
|
||||||
.wiki .wiki-doublebox .dbox-bot .wikiview-title {
|
.wiki .wiki-doublebox .dbox-bot .wikiview-title,
|
||||||
|
.profile-bio .wiki-doublebox .dbox-bot .wikiview-title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 42px;
|
font-size: 42px;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
.wiki h1,
|
.wiki h1,
|
||||||
|
.profile-bio h1,
|
||||||
.wiki h2,
|
.wiki h2,
|
||||||
|
.profile-bio h2,
|
||||||
.wiki h3,
|
.wiki h3,
|
||||||
|
.profile-bio h3,
|
||||||
.wiki h4,
|
.wiki h4,
|
||||||
|
.profile-bio h4,
|
||||||
.wiki h5,
|
.wiki h5,
|
||||||
.wiki h6 {
|
.profile-bio h5,
|
||||||
|
.wiki h6,
|
||||||
|
.profile-bio h6 {
|
||||||
margin-top: revert;
|
margin-top: revert;
|
||||||
margin-bottom: revert;
|
margin-bottom: revert;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -209,18 +209,6 @@ blockquote {
|
||||||
background-color: fade(@pastel-lime, 10%);
|
background-color: fade(@pastel-lime, 10%);
|
||||||
padding: 2px 4px 2px 8px;
|
padding: 2px 4px 2px 8px;
|
||||||
margin: 8px;
|
margin: 8px;
|
||||||
|
|
||||||
&.spoiler {
|
|
||||||
color: transparent;
|
|
||||||
background-color: fade(@pastel-red, 10%);
|
|
||||||
border: 1px solid fade(@pastel-red, 10%);
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 4px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: @pastel-red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
|
@ -440,6 +428,7 @@ form.full {
|
||||||
border-left: 1px solid @fg-twenty !important;
|
border-left: 1px solid @fg-twenty !important;
|
||||||
border-right: 1px solid @fg-twenty !important;
|
border-right: 1px solid @fg-twenty !important;
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
|
caret-color: white;
|
||||||
|
|
||||||
.cm-link {
|
.cm-link {
|
||||||
color: @pastel-cyan !important;
|
color: @pastel-cyan !important;
|
||||||
|
@ -472,6 +461,10 @@ form.full {
|
||||||
.cm-header {
|
.cm-header {
|
||||||
color: @ec !important;
|
color: @ec !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.CodeMirror-cursor {
|
||||||
|
border-left: 1px solid @fg !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.editor-toolbar, .editor-statusbar {
|
.editor-toolbar, .editor-statusbar {
|
||||||
background-color: @fg-ten-hard !important;
|
background-color: @fg-ten-hard !important;
|
||||||
|
@ -497,6 +490,18 @@ form.full {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fas, .far, .fab {
|
||||||
|
color: @fg !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @fg !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.editor-toolbar {
|
.editor-toolbar {
|
||||||
border-top: 1px solid @fg-twenty-hard !important;
|
border-top: 1px solid @fg-twenty-hard !important;
|
||||||
|
@ -754,17 +759,31 @@ form.full {
|
||||||
//A spoiler
|
//A spoiler
|
||||||
.spoiler {
|
.spoiler {
|
||||||
color: transparent;
|
color: transparent;
|
||||||
border: 1px solid @fg-ten;
|
background-color: fade(@pastel-red, 10%);
|
||||||
|
border: 1px solid fade(@pastel-red, 10%);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
|
||||||
|
b, strong, i, em {
|
||||||
|
color: inherit;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&blockquote {
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: @fg;
|
color: @pastel-red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Wiki page
|
//Wiki page
|
||||||
.wiki {
|
.wiki, .profile-bio {
|
||||||
.wiki-doublebox {
|
.wiki-doublebox {
|
||||||
.dbox-bot {
|
.dbox-bot {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<div class="nav-right">
|
<div class="nav-right">
|
||||||
<span>
|
<span>
|
||||||
{% if session["royal"] %}
|
{% if session["royal"] %}
|
||||||
<a href="{{ url_for("profile.profile_by_username", username=session["royal"]["username"]) }}" class="no-icon nav-profile">
|
<a href="{{ url_for("profile.profile_page", username=session["royal"]["username"]) }}" class="no-icon nav-profile">
|
||||||
<span class="nav-accountname">{{ session["royal"]["username"] }}</span>
|
<span class="nav-accountname">{{ session["royal"]["username"] }}</span>
|
||||||
{% if session["royal"]["avatar"] %}
|
{% if session["royal"]["avatar"] %}
|
||||||
<img class="nav-image" alt="" src="{{ session["royal"]["avatar"] }}">
|
<img class="nav-image" alt="" src="{{ session["royal"]["avatar"] }}">
|
||||||
|
|
Loading…
Reference in a new issue