#!/usr/bin/python3
+import difflib
import tornado.web
from . import auth
from . import base
from . import ui_modules
+class ActionEditHandler(auth.CacheMixin, base.BaseHandler):
+ @tornado.web.authenticated
+ def post(self):
+ path = self.get_argument("path")
+
+ # Check permissions
+ if not self.backend.wiki.check_acl(path, self.current_user):
+ raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
+
+ content = self.get_argument("content", None)
+ changes = self.get_argument("changes")
+
+ # Create a new page in the database
+ with self.db.transaction():
+ page = self.backend.wiki.create_page(path,
+ self.current_user, content, changes=changes, address=self.get_remote_ip())
+
+ # Add user as a watcher if wanted
+ watch = self.get_argument("watch", False)
+ if watch:
+ page.add_watcher(self.current_user)
+
+ # Redirect back
+ if page.was_deleted():
+ self.redirect("/")
+ else:
+ self.redirect(page.url)
+
+ def on_finish(self):
+ """
+ Updates the search index after the page has been edited
+ """
+ # This is being executed in the background and after
+ # the response has been set to the client
+ with self.db.transaction():
+ self.backend.wiki.refresh()
+
+
+class ActionUploadHandler(auth.CacheMixin, base.BaseHandler):
+ @tornado.web.authenticated
+ def post(self):
+ path = self.get_argument("path")
+
+ # Check permissions
+ if not self.backend.wiki.check_acl(path, self.current_user):
+ raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
+
+ try:
+ filename, data, mimetype = self.get_file("file")
+
+ # XXX check valid mimetypes
+
+ with self.db.transaction():
+ file = self.backend.wiki.upload(path, filename, data,
+ mimetype=mimetype, author=self.current_user,
+ address=self.get_remote_ip())
+
+ except TypeError as e:
+ raise e
+
+ self.redirect("%s/files" % path)
+
+
+class ActionWatchHandler(auth.CacheMixin, base.BaseHandler):
+ @tornado.web.authenticated
+ def get(self, action, path):
+ page = self.backend.wiki.get_page(path)
+ if not page:
+ raise tornado.web.HTTPError(404, "Page does not exist: %s" % path)
+
+ with self.db.transaction():
+ if action == "watch":
+ page.add_watcher(self.current_user)
+ elif action == "unwatch":
+ page.remove_watcher(self.current_user)
+
+ # Redirect back to page
+ self.redirect(page.url)
+
+
+class FilesHandler(auth.CacheMixin, base.BaseHandler):
+ @tornado.web.authenticated
+ def get(self, path):
+ # Check permissions
+ if not self.backend.wiki.check_acl(path, self.current_user):
+ raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
+
+ files = self.backend.wiki.get_files(path)
+
+ self.render("wiki/files/index.html", path=path, files=files)
+
+
+class FileHandler(base.BaseHandler):
+ @property
+ def action(self):
+ return self.get_argument("action", None)
+
+ def get(self, path):
+ # Check permissions
+ if not self.backend.wiki.check_acl(path, self.current_user):
+ raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
+
+ # Fetch the file
+ file = self.backend.wiki.get_file_by_path(path)
+ if not file:
+ raise tornado.web.HTTPError(404, "Could not find %s" % path)
+
+ # Render detail page
+ if self.action == "detail":
+ for breadcrumb, title in self.backend.wiki.make_breadcrumbs(path):
+ page = self.backend.wiki.get_page(breadcrumb)
+ if page:
+ break
+
+ self.render("wiki/files/detail.html", page=page, file=file)
+ return
+
+ size = self.get_argument_int("s", None)
+
+ # Check if image should be resized
+ if file.is_image() and size:
+ blob = file.get_thumbnail(size)
+ else:
+ blob = file.blob
+
+ # Set headers
+ self.set_header("Content-Type", file.mimetype or "application/octet-stream")
+ self.set_header("Content-Length", len(blob))
+
+ # Set expires
+ self.set_expires(3600)
+
+ # Deliver content
+ self.finish(blob)
+
+
class PageHandler(auth.CacheMixin, base.BaseHandler):
+ @property
+ def action(self):
+ return self.get_argument("action", None)
+
+ def write_error(self, status_code, **kwargs):
+ # Render a custom page for 404
+ if status_code == 404:
+ self.render("wiki/404.html", **kwargs)
+ return
+
+ # Otherwise raise this to one layer above
+ super().write_error(status_code, **kwargs)
+
@tornado.web.removeslash
- def get(self, page):
- page = self.backend.wiki.get_page(page)
+ def get(self, path):
+ # Check permissions
+ if not self.backend.wiki.check_acl(path, self.current_user):
+ raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
+
+ # Check if we are asked to render a certain revision
+ revision = self.get_argument("revision", None)
+
+ # Fetch the wiki page
+ page = self.backend.wiki.get_page(path, revision=revision)
+
+ # Diff
+ if self.action == "diff":
+ # Get both revisions
+ a = self.get_argument("a")
+ b = self.get_argument("b")
+
+ # Fetch both versions of the page
+ a = self.backend.wiki.get_page(path, revision=a)
+ b = self.backend.wiki.get_page(path, revision=b)
+ if not a or not b:
+ raise tornado.web.HTTPError(404)
+
+ # Cannot render a diff for the identical page
+ if a == b:
+ raise tornado.web.HTTPError(400)
+
+ # Make sure that b is newer than a
+ if a > b:
+ a, b = b, a
+
+ self.render("wiki/diff.html", page=page, a=a, b=b)
+ return
+
+ # Edit
+ elif self.action == "edit":
+ if not self.current_user:
+ raise tornado.web.HTTPError(401)
+
+ # Empty page if it was deleted
+ if page and page.was_deleted():
+ page = None
+
+ # Render page
+ self.render("wiki/edit.html", page=page)
+ return
+
+ # Revisions
+ elif self.action == "revisions":
+ self.render("wiki/revisions.html", page=page)
+ return
# If the page does not exist, we send 404
if not page or page.was_deleted():
# Render page
self.render("wiki/page.html", page=page, latest_revision=latest_revision)
- @tornado.web.authenticated
- def post(self, page):
- content = self.get_argument("content", None)
-
- # Delete the page if content is empty
- if not content:
- with self.db.transaction():
- self.backend.wiki.delete_page(page, self.current_user)
-
- return self.redirect("/")
-
- # Create a new page in the database
- page = self.backend.wiki.create_page(page, self.current_user, content)
-
- # Redirect
- self.redirect(page.url)
-
class SearchHandler(auth.CacheMixin, base.BaseHandler):
@base.blacklisted
def get(self):
q = self.get_argument("q")
- pages = self.backend.wiki.search(q, limit=50)
- if not pages:
- raise tornado.web.HTTPError(404, "Nothing found")
+ pages = self.backend.wiki.search(q, account=self.current_user, limit=50)
self.render("wiki/search-results.html", q=q, pages=pages)
class RecentChangesHandler(auth.CacheMixin, base.BaseHandler):
def get(self):
- recent_changes = self.backend.wiki.get_recent_changes(limit=50)
+ recent_changes = self.backend.wiki.get_recent_changes(self.current_user, limit=50)
self.render("wiki/recent-changes.html", recent_changes=recent_changes)
+class WikiDiffModule(ui_modules.UIModule):
+ differ = difflib.Differ()
+
+ def render(self, a, b):
+ diff = self.differ.compare(
+ a.markdown.splitlines(),
+ b.markdown.splitlines(),
+ )
+
+ return self.render_string("wiki/modules/diff.html", diff=diff)
+
+
class WikiListModule(ui_modules.UIModule):
- def render(self, pages):
- return self.render_string("wiki/modules/list.html", pages=pages)
+ def render(self, pages, link_revision=False, show_breadcrumbs=True, show_changes=False):
+ return self.render_string("wiki/modules/list.html", link_revision=link_revision,
+ pages=pages, show_breadcrumbs=show_breadcrumbs, show_changes=show_changes)
class WikiNavbarModule(ui_modules.UIModule):
- def render(self, page, suffix=None):
- breadcrumbs = self.backend.wiki.make_breadcrumbs(page.url)
+ def render(self, suffix=None):
+ _ = self.locale.translate
+
+ breadcrumbs = self.backend.wiki.make_breadcrumbs(self.request.path)
+
+ # Don't search for a title for the file manager
+ if self.request.path.endswith("/files"):
+ title = _("Files")
+ else:
+ title = self.backend.wiki.get_page_title(self.request.path)
return self.render_string("wiki/modules/navbar.html",
- breadcrumbs=breadcrumbs, page_title=page.title, suffix=suffix)
+ breadcrumbs=breadcrumbs, page_title=title, suffix=suffix)