Add Wiki plugin to Rophako
This commit is contained in:
parent
a69e013fb5
commit
6fdf0ae0ea
|
@ -165,6 +165,13 @@ time_format = %(_date_format)s
|
||||||
# a gravatar.
|
# a gravatar.
|
||||||
default_avatar =
|
default_avatar =
|
||||||
|
|
||||||
|
###
|
||||||
|
# Wiki
|
||||||
|
###
|
||||||
|
[wiki]
|
||||||
|
default_page = Main Page
|
||||||
|
time_format = %(_date_format)s
|
||||||
|
|
||||||
#------------------------------------------------------------------------------#
|
#------------------------------------------------------------------------------#
|
||||||
# List of Enabled Plugins #
|
# List of Enabled Plugins #
|
||||||
#------------------------------------------------------------------------------#
|
#------------------------------------------------------------------------------#
|
||||||
|
@ -178,6 +185,7 @@ default_avatar =
|
||||||
# like shown in the plugins section).
|
# like shown in the plugins section).
|
||||||
blueprints =
|
blueprints =
|
||||||
rophako.modules.blog
|
rophako.modules.blog
|
||||||
|
rophako.modules.wiki
|
||||||
rophako.modules.photo
|
rophako.modules.photo
|
||||||
rophako.modules.comment
|
rophako.modules.comment
|
||||||
rophako.modules.emoticons
|
rophako.modules.emoticons
|
||||||
|
|
|
@ -107,14 +107,26 @@ def exists(document):
|
||||||
return os.path.isfile(path)
|
return os.path.isfile(path)
|
||||||
|
|
||||||
|
|
||||||
def list_docs(path):
|
def list_docs(path, recursive=False):
|
||||||
"""List all the documents at the path."""
|
"""List all the documents at the path."""
|
||||||
path = mkpath("{}/*".format(path))
|
root = os.path.join(Config.db.db_root, path)
|
||||||
docs = list()
|
docs = list()
|
||||||
|
|
||||||
for item in glob.glob(path):
|
for item in sorted(os.listdir(root)):
|
||||||
|
target = os.path.join(root, item)
|
||||||
|
db_path = os.path.join(path, item)
|
||||||
|
|
||||||
|
# Descend into subdirectories?
|
||||||
|
if os.path.isdir(target):
|
||||||
|
if recursive:
|
||||||
|
docs += [
|
||||||
|
os.path.join(item, name) for name in list_docs(db_path)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if target.endswith(".json"):
|
||||||
name = re.sub(r'\.json$', '', item)
|
name = re.sub(r'\.json$', '', item)
|
||||||
name = name.split("/")[-1]
|
|
||||||
docs.append(name)
|
docs.append(name)
|
||||||
|
|
||||||
return docs
|
return docs
|
||||||
|
|
121
rophako/model/wiki.py
Normal file
121
rophako/model/wiki.py
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Wiki models."""
|
||||||
|
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
import rophako.jsondb as JsonDB
|
||||||
|
from rophako.log import logger
|
||||||
|
|
||||||
|
def get_page(name):
|
||||||
|
"""Get a Wiki page. Returns `None` if the page isn't found."""
|
||||||
|
name = name.strip("/") # Remove any surrounding slashes.
|
||||||
|
path = "wiki/pages/{}".format(name)
|
||||||
|
if not JsonDB.exists(path):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# TODO: case insensitive page names...
|
||||||
|
|
||||||
|
db = JsonDB.get(path)
|
||||||
|
return db
|
||||||
|
|
||||||
|
|
||||||
|
def list_pages():
|
||||||
|
"""Get a list of all existing wiki pages."""
|
||||||
|
return JsonDB.list_docs("wiki/pages", recursive=True)
|
||||||
|
|
||||||
|
|
||||||
|
def edit_page(name, author, body, note, history=True):
|
||||||
|
"""Write to a page."""
|
||||||
|
name = name.strip("/") # Remove any surrounding slashes.
|
||||||
|
|
||||||
|
# Get the old page first.
|
||||||
|
page = get_page(name)
|
||||||
|
if not page:
|
||||||
|
# Initialize the page.
|
||||||
|
page = dict(
|
||||||
|
revisions=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
# The new revision to be added.
|
||||||
|
rev = dict(
|
||||||
|
id=hashlib.md5(str(int(time.time()))).hexdigest(),
|
||||||
|
time=int(time.time()),
|
||||||
|
author=author,
|
||||||
|
body=body,
|
||||||
|
note=note or "Updated the page.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Updating the history?
|
||||||
|
if history:
|
||||||
|
page["revisions"].insert(0, rev)
|
||||||
|
else:
|
||||||
|
# Replacing the original item.
|
||||||
|
if len(page["revisions"]):
|
||||||
|
page["revisions"][0] = rev
|
||||||
|
else:
|
||||||
|
page["revisions"].append(rev)
|
||||||
|
|
||||||
|
# Write it.
|
||||||
|
logger.info("Write to Wiki page {}".format(name))
|
||||||
|
JsonDB.commit("wiki/pages/{}".format(name), page)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def delete_history(name, revision):
|
||||||
|
"""Delete a revision entry from the history."""
|
||||||
|
name = name.strip("/")
|
||||||
|
|
||||||
|
# Get page first.
|
||||||
|
page = get_page(name)
|
||||||
|
if not page:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Revise history.
|
||||||
|
history = list()
|
||||||
|
for rev in page["revisions"]:
|
||||||
|
if rev["id"] == revision:
|
||||||
|
logger.info("Delete history ID {} from Wiki page {}".format(revision, name))
|
||||||
|
continue
|
||||||
|
history.append(rev)
|
||||||
|
|
||||||
|
# Empty history = delete the page.
|
||||||
|
if len(history) == 0:
|
||||||
|
logger.info("Deleted last history item; Remove Wiki page {}".format(name))
|
||||||
|
return delete_page(name)
|
||||||
|
|
||||||
|
page["revisions"] = history
|
||||||
|
JsonDB.commit("wiki/pages/{}".format(name), page)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def delete_page(name):
|
||||||
|
"""Completely delete a wiki page."""
|
||||||
|
name = name.strip("/")
|
||||||
|
path = "wiki/pages/{}".format(name)
|
||||||
|
|
||||||
|
if JsonDB.exists(path):
|
||||||
|
logger.info("Delete Wiki page {}".format(name))
|
||||||
|
JsonDB.delete(path)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def name_to_url(name):
|
||||||
|
"""Convert a Wiki page name into a URL safe version.
|
||||||
|
|
||||||
|
All non-alphanumerics are replaced with dashes, multiple dashes in a row
|
||||||
|
are flattened down to one, and any preceeding or trailing dashes are also
|
||||||
|
stripped off."""
|
||||||
|
name = re.sub(r'[^A-Za-z0-9/]', '-', name).replace('--', '-').strip('-')
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def url_to_name(url):
|
||||||
|
"""Convert a URL to a page name, for 404'd links.
|
||||||
|
|
||||||
|
Turns a link like /wiki/New-Page-Name into 'New Page Name'"""
|
||||||
|
return url.replace("-", " ")
|
203
rophako/modules/wiki/__init__.py
Normal file
203
rophako/modules/wiki/__init__.py
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Endpoints for the wiki."""
|
||||||
|
|
||||||
|
from flask import Blueprint, g, request, redirect, url_for, flash
|
||||||
|
|
||||||
|
import rophako.model.user as User
|
||||||
|
import rophako.model.wiki as Wiki
|
||||||
|
import rophako.model.emoticons as Emoticons
|
||||||
|
from rophako.utils import (template, render_markdown, pretty_time,
|
||||||
|
login_required)
|
||||||
|
from rophako.settings import Config
|
||||||
|
|
||||||
|
mod = Blueprint("wiki", __name__, url_prefix="/wiki")
|
||||||
|
|
||||||
|
@mod.route("/")
|
||||||
|
def index():
|
||||||
|
"""Wiki index. Redirects to the default page from the config."""
|
||||||
|
default = Wiki.name_to_url(Config.wiki.default_page)
|
||||||
|
return redirect(url_for("wiki.view_page", name=default))
|
||||||
|
|
||||||
|
|
||||||
|
@mod.route("/_pages")
|
||||||
|
def list_pages():
|
||||||
|
"""Wiki page list."""
|
||||||
|
g.info["pages"] = [
|
||||||
|
{"name": name, "link": Wiki.name_to_url(name)} \
|
||||||
|
for name in Wiki.list_pages()
|
||||||
|
]
|
||||||
|
return template("wiki/list.html")
|
||||||
|
|
||||||
|
|
||||||
|
@mod.route("/<path:name>")
|
||||||
|
def view_page(name):
|
||||||
|
"""Show a specific wiki page."""
|
||||||
|
name = Wiki.url_to_name(name)
|
||||||
|
|
||||||
|
# Look up the page.
|
||||||
|
page = Wiki.get_page(name)
|
||||||
|
if not page:
|
||||||
|
# Page doesn't exist... yet!
|
||||||
|
g.info["title"] = Wiki.url_to_name(name)
|
||||||
|
return template("wiki/missing.html"), 404
|
||||||
|
|
||||||
|
# Which revision to show?
|
||||||
|
version = request.args.get("revision", None)
|
||||||
|
if version:
|
||||||
|
# Find this one.
|
||||||
|
rev = None
|
||||||
|
for item in page["revisions"]:
|
||||||
|
if item["id"] == version:
|
||||||
|
rev = item
|
||||||
|
break
|
||||||
|
|
||||||
|
if rev is None:
|
||||||
|
flash("That revision was not found for this page.")
|
||||||
|
rev = page["revisions"][0]
|
||||||
|
else:
|
||||||
|
# Show the latest one.
|
||||||
|
rev = page["revisions"][0]
|
||||||
|
|
||||||
|
# Render it!
|
||||||
|
g.info["link"] = Wiki.name_to_url(name)
|
||||||
|
g.info["title"] = name
|
||||||
|
g.info["rendered_body"] = render_markdown(rev["body"])
|
||||||
|
g.info["rendered_body"] = Emoticons.render(g.info["rendered_body"])
|
||||||
|
g.info["pretty_time"] = pretty_time(Config.wiki.time_format, rev["time"])
|
||||||
|
|
||||||
|
# Author info
|
||||||
|
g.info["author"] = User.get_user(uid=rev["author"])
|
||||||
|
|
||||||
|
return template("wiki/page.html")
|
||||||
|
|
||||||
|
|
||||||
|
@mod.route("/<path:name>/_revisions")
|
||||||
|
def history(name):
|
||||||
|
"""Page history."""
|
||||||
|
name = Wiki.url_to_name(name)
|
||||||
|
|
||||||
|
# Look up the page.
|
||||||
|
page = Wiki.get_page(name)
|
||||||
|
if not page:
|
||||||
|
flash("Wiki page not found.")
|
||||||
|
return redirect(url_for(".index"))
|
||||||
|
|
||||||
|
authors = dict()
|
||||||
|
history = list()
|
||||||
|
for rev in page["revisions"]:
|
||||||
|
uid = rev["author"]
|
||||||
|
if not uid in authors:
|
||||||
|
authors[uid] = User.get_user(uid=uid)
|
||||||
|
|
||||||
|
history.append(dict(
|
||||||
|
id=rev["id"],
|
||||||
|
author=authors[uid],
|
||||||
|
note=rev["note"],
|
||||||
|
pretty_time=pretty_time(Config.wiki.time_format, rev["time"]),
|
||||||
|
))
|
||||||
|
|
||||||
|
g.info["link"] = Wiki.name_to_url(name)
|
||||||
|
g.info["title"] = name
|
||||||
|
g.info["history"] = history
|
||||||
|
return template("wiki/history.html")
|
||||||
|
|
||||||
|
|
||||||
|
@mod.route("/_edit", methods=["GET", "POST"])
|
||||||
|
@login_required
|
||||||
|
def edit():
|
||||||
|
"""Wiki page editor."""
|
||||||
|
title = request.args.get("name", "")
|
||||||
|
body = ""
|
||||||
|
history = True # Update History box is always checked by default
|
||||||
|
note = request.args.get("note", "")
|
||||||
|
|
||||||
|
# Editing an existing page?
|
||||||
|
page = Wiki.get_page(title)
|
||||||
|
if page:
|
||||||
|
head = page["revisions"][0]
|
||||||
|
body = head["body"]
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
# Submitting the form.
|
||||||
|
action = request.form.get("action", "preview")
|
||||||
|
title = request.form.get("name", "")
|
||||||
|
body = request.form.get("body", "")
|
||||||
|
history = request.form.get("history", "false") == "true"
|
||||||
|
note = request.form.get("note", "")
|
||||||
|
|
||||||
|
if action == "preview":
|
||||||
|
# Just previewing it.
|
||||||
|
g.info["preview"] = True
|
||||||
|
|
||||||
|
# Render markdown
|
||||||
|
g.info["rendered_body"] = render_markdown(body)
|
||||||
|
|
||||||
|
# Render emoticons.
|
||||||
|
g.info["rendered_body"] = Emoticons.render(g.info["rendered_body"])
|
||||||
|
elif action == "publish":
|
||||||
|
# Publishing! Validate inputs.
|
||||||
|
invalid = False
|
||||||
|
|
||||||
|
if len(title) == 0:
|
||||||
|
invalid = True
|
||||||
|
flash("You must have a page title.")
|
||||||
|
if len(body) == 0:
|
||||||
|
invalid = True
|
||||||
|
flash("You must have a page body.")
|
||||||
|
|
||||||
|
if not invalid:
|
||||||
|
# Update the page.
|
||||||
|
Wiki.edit_page(
|
||||||
|
author=g.info["session"]["uid"],
|
||||||
|
name=title,
|
||||||
|
body=body,
|
||||||
|
note=note,
|
||||||
|
history=history,
|
||||||
|
)
|
||||||
|
return redirect(url_for("wiki.view_page",
|
||||||
|
name=Wiki.name_to_url(title)
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
g.info["title"] = title
|
||||||
|
g.info["body"] = body
|
||||||
|
g.info["note"] = note
|
||||||
|
g.info["history"] = history
|
||||||
|
return template("wiki/edit.html")
|
||||||
|
|
||||||
|
|
||||||
|
@mod.route("/_delete_history/<path:name>/<revision>", methods=["GET", "POST"])
|
||||||
|
@login_required
|
||||||
|
def delete_revision(name, revision):
|
||||||
|
"""Delete a wiki page revision from history."""
|
||||||
|
link = name
|
||||||
|
name = Wiki.url_to_name(name)
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
Wiki.delete_history(name, revision)
|
||||||
|
flash("Revision deleted.")
|
||||||
|
return redirect(url_for("wiki.view_page", name=Wiki.name_to_url(name)))
|
||||||
|
|
||||||
|
g.info["confirm_url"] = url_for("wiki.delete_revision", name=link, revision=revision)
|
||||||
|
g.info["title"] = name
|
||||||
|
g.info["type"] = "revision"
|
||||||
|
return template("wiki/delete.html")
|
||||||
|
|
||||||
|
|
||||||
|
@mod.route("/_delete_page/<path:name>", methods=["GET", "POST"])
|
||||||
|
@login_required
|
||||||
|
def delete_page(name):
|
||||||
|
"""Delete a wiki page entirely."""
|
||||||
|
link = name
|
||||||
|
name = Wiki.url_to_name(name)
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
Wiki.delete_page(name)
|
||||||
|
flash("Page completely deleted.")
|
||||||
|
return redirect(url_for("wiki.index"))
|
||||||
|
|
||||||
|
g.info["confirm_url"] = url_for("wiki.delete_page", name=link)
|
||||||
|
g.info["title"] = name
|
||||||
|
g.info["type"] = "page"
|
||||||
|
return template("wiki/delete.html")
|
14
rophako/modules/wiki/templates/wiki/delete.html
Normal file
14
rophako/modules/wiki/templates/wiki/delete.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block title %}Confirm Deletion{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Delete {% if type == "revision" %}Revision{% else %}Page{% endif %}: {{ title }}</h1>
|
||||||
|
|
||||||
|
Are you sure you want to delete this {{ type }}?<p>
|
||||||
|
|
||||||
|
<form name="confirm" action="{{ confirm_url }}" method="POST">
|
||||||
|
<input type="hidden" name="token" value="{{ csrf_token() }}">
|
||||||
|
<button type="submit" name="confirm" value="true">Confirm Deletion</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
39
rophako/modules/wiki/templates/wiki/edit.html
Normal file
39
rophako/modules/wiki/templates/wiki/edit.html
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block title %}Edit Wiki{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% if preview %}
|
||||||
|
<h1>Preview: {{ subject }}</h1>
|
||||||
|
|
||||||
|
{{ rendered_body|safe }}
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h1>Edit Wiki</h1>
|
||||||
|
|
||||||
|
<form name="editor" action="{{ url_for('wiki.edit') }}" method="POST">
|
||||||
|
<input type="hidden" name="token" value="{{ csrf_token() }}">
|
||||||
|
|
||||||
|
<strong>Title:</strong><br>
|
||||||
|
<input type="text" class="form-control" size="80" name="name" value="{{ title }}"><p>
|
||||||
|
|
||||||
|
<strong>Body:</strong><br>
|
||||||
|
<textarea class="form-control input-lg" cols="80" rows="20" name="body">{{ body }}</textarea><br>
|
||||||
|
Markdown syntax.
|
||||||
|
<a href="{{ url_for('emoticons.index') }}" target="_blank">Emoticon reference</a> (opens in new window)<p>
|
||||||
|
|
||||||
|
<strong>Revision Note (optional):</strong><br>
|
||||||
|
<input type="text" size="80" name="note" value="{{ note }}"><p>
|
||||||
|
|
||||||
|
<strong>Options:</strong><br>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="history" value="true"{% if history %} checked{% endif %}> Add this revision to the page history
|
||||||
|
(if unchecked, it will replace the most recent version with this version)
|
||||||
|
</label><p>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-default" name="action" value="preview">Preview</button>
|
||||||
|
<button type="submit" class="btn btn-primary" name="action" value="publish">Publish</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
40
rophako/modules/wiki/templates/wiki/history.html
Normal file
40
rophako/modules/wiki/templates/wiki/history.html
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block title %}Wiki{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>History: {{ title }}</h1>
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Edited By</th>
|
||||||
|
<th>Revision Note</th>
|
||||||
|
{% if session["login"] %}
|
||||||
|
<th>Delete?</th>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in history %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ item["pretty_time"] }}</td>
|
||||||
|
<td>{{ item["author"]["name"] }}</td>
|
||||||
|
<td><a href="{{ url_for('wiki.view_page', name=link, revision=item['id']) }}">{{ item["note"] }}</a></td>
|
||||||
|
{% if session["login"] %}
|
||||||
|
<td><a href="{{ url_for('wiki.delete_revision', name=link, revision=item['id']) }}">Delete</a></td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% if session["login"] %}
|
||||||
|
<p>
|
||||||
|
<strong>Admin Actions:</strong>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{{ url_for('wiki.delete_page', name=link) }}">Delete Page</a></li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
19
rophako/modules/wiki/templates/wiki/list.html
Normal file
19
rophako/modules/wiki/templates/wiki/list.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block title %}Wiki Pages{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% if session["login"] %}
|
||||||
|
<div class="right">
|
||||||
|
[ <a href="{{ url_for('wiki.edit') }}">New Page</a> ]
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h1>Wiki Pages</h1>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for page in pages %}
|
||||||
|
<li><a href="{{ url_for('wiki.view_page', name=page['link']) }}">{{ page['name'] }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% endblock %}
|
15
rophako/modules/wiki/templates/wiki/missing.html
Normal file
15
rophako/modules/wiki/templates/wiki/missing.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block title %}{{ title }}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
|
||||||
|
This wiki page does not exist yet (that means it's a 404 error!)
|
||||||
|
|
||||||
|
{% if session["login"] %}
|
||||||
|
<ul>
|
||||||
|
<li><a href="{{ url_for('wiki.edit', name=title, note='Created initial page.') }}">Create This Page</a></li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
21
rophako/modules/wiki/templates/wiki/page.html
Normal file
21
rophako/modules/wiki/templates/wiki/page.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
{% block title %}Wiki{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="right">
|
||||||
|
Last edited by {{ author["name"] }} on {{ pretty_time }}
|
||||||
|
|
||||||
|
[ <a href="{{ url_for('wiki.history', name=link) }}">History</a>
|
||||||
|
| <a href="{{ url_for('wiki.list_pages') }}">Index</a>
|
||||||
|
{% if session["login"] %}
|
||||||
|
| <a href="{{ url_for('wiki.edit', name=title) }}">Edit</a>
|
||||||
|
| <a href="{{ url_for('wiki.edit') }}">New Page</a>
|
||||||
|
{% endif %}
|
||||||
|
]
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
|
||||||
|
{{ rendered_body|safe }}
|
||||||
|
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user