]> git.ipfire.org Git - ipfire.org.git/blobdiff - src/web/wiki.py
docs: Move the diff UI module
[ipfire.org.git] / src / web / wiki.py
index 916db35812a2244161158cb52091cfd6fe950ba5..bf9fe54e3325a80a83a07d832e72a4c64781b14f 100644 (file)
 
 import tornado.web
 
-from . import auth
 from . import base
 from . import ui_modules
 
-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)
-
-               # Edit
-               if 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
+class ActionEditHandler(base.BaseHandler):
+       @tornado.web.authenticated
+       def get(self, path):
+               if path is None:
+                       path = "/"
 
-                       # Render login
-                       return self.render("wiki/edit.html", page=page)
+               # 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))
 
-               # If the page does not exist, we send 404
-               if not page or page.was_deleted():
-                       raise tornado.web.HTTPError(404)
+               # Fetch the wiki page
+               page = self.backend.wiki.get_page(path)
 
-               # Fetch the latest revision
-               latest_revision = page.get_latest_revision()
+               # Empty page if it was deleted
+               if page and page.was_deleted():
+                       page = None
 
                # Render page
-               self.render("wiki/page.html", page=page, latest_revision=latest_revision)
+               self.render("wiki/edit.html", page=page, path=path)
 
        @tornado.web.authenticated
-       def post(self, page):
+       def post(self, path):
+               if path is None:
+                       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(page,
+                       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(base.BaseHandler):
+       @tornado.web.authenticated
+       @base.ratelimit(minutes=60, requests=24)
+       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")
+
+                       # Use filename from request if any
+                       filename = self.get_argument("filename", filename)
+
+                       # 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 ActionDeleteHandler(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))
+
+               # 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)
+
+               self.render("wiki/confirm-delete.html", file=file)
+
+       @tornado.web.authenticated
+       @base.ratelimit(minutes=60, requests=24)
+       def post(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)
+
+               with self.db.transaction():
+                       file.delete(self.current_user)
+
+               self.redirect("%s/_files" % file.path)
+
+
+class ActionRestoreHandler(base.BaseHandler):
+       @tornado.web.authenticated
+       @base.ratelimit(minutes=60, requests=24)
+       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))
 
-class SearchHandler(auth.CacheMixin, base.BaseHandler):
-       @base.blacklisted
+               # Check if we are asked to render a certain revision
+               revision = self.get_argument("revision", None)
+               comment = self.get_argument("comment", None)
+
+               # Fetch the wiki page
+               page = self.backend.wiki.get_page(path, revision=revision)
+
+               with self.db.transaction():
+                       page = page.restore(
+                               author=self.current_user,
+                               address=self.get_remote_ip(),
+                               comment=comment,
+                       )
+
+               # Redirect back to page
+               self.redirect(page.page)
+
+
+class ActionWatchHandler(base.BaseHandler):
+       @tornado.web.authenticated
+       @base.ratelimit(minutes=60, requests=180)
+       def get(self, path, action):
+               if path is None:
+                       path = "/"
+
+               page = self.backend.wiki.get_page(path)
+               if not page:
+                       raise tornado.web.HTTPError(404, "Page does not exist: %s" % 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))
+
+               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 ActionRenderHandler(base.BaseHandler):
+       def check_xsrf_cookie(self):
+               pass # disabled
+
+       @tornado.web.authenticated
+       @base.ratelimit(minutes=5, requests=180)
+       def post(self, path):
+               if path is None:
+                       path = "/"
+
+               content = self.get_argument("content")
+
+               # Render the content
+               html = self.backend.wiki.render(path, content)
+
+               self.finish(html)
+
+
+class FilesHandler(base.BaseHandler):
+       @tornado.web.authenticated
+       def get(self, path):
+               if path is None:
+                       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 SearchHandler(base.BaseHandler):
+       @base.ratelimit(minutes=5, requests=25)
        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):
+class RecentChangesHandler(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 WikiListModule(ui_modules.UIModule):
-       def render(self, pages, show_breadcrumbs=True, show_changes=False):
-               return self.render_string("wiki/modules/list.html",
-                       pages=pages, show_breadcrumbs=show_breadcrumbs, show_changes=show_changes)
+class TreeHandler(base.BaseHandler):
+       def get(self):
+               self.render("wiki/tree.html", pages=self.backend.wiki)
+
 
+class WatchlistHandler(base.BaseHandler):
+       @tornado.web.authenticated
+       def get(self):
+               pages = self.backend.wiki.get_watchlist(self.current_user)
 
-class WikiNavbarModule(ui_modules.UIModule):
-       def render(self, page, suffix=None):
-               breadcrumbs = self.backend.wiki.make_breadcrumbs(page.url)
+               self.render("wiki/watchlist.html", pages=pages)
 
-               return self.render_string("wiki/modules/navbar.html",
-                       breadcrumbs=breadcrumbs, page_title=page.title, suffix=suffix)
+
+class WikiListModule(ui_modules.UIModule):
+       def render(self, pages, link_revision=False, show_breadcrumbs=True,
+                       show_author=True, show_changes=False):
+               return self.render_string("wiki/modules/list.html", link_revision=link_revision,
+                       pages=pages, show_breadcrumbs=show_breadcrumbs,
+                       show_author=show_author, show_changes=show_changes)