]> git.ipfire.org Git - ipfire.org.git/blame - src/web/docs.py
docs: Move the diff UI module
[ipfire.org.git] / src / web / docs.py
CommitLineData
1958a22b
MT
1#!/usr/bin/python3
2
3import difflib
4import tornado.web
5
6from . import base
cf59466c 7from . import ui_modules
1958a22b
MT
8
9class PageHandler(base.BaseHandler):
10 @property
11 def action(self):
12 return self.get_argument("action", None)
13
14 def write_error(self, status_code, **kwargs):
15 # Render a custom page for 404
16 if status_code == 404:
17 self.render("wiki/404.html", **kwargs)
18 return
19
20 # Otherwise raise this to one layer above
21 super().write_error(status_code, **kwargs)
22
23 @tornado.web.removeslash
24 def get(self, path):
25 if path is None:
26 path = "/"
27
28 # Check permissions
29 if not self.backend.wiki.check_acl(path, self.current_user):
30 raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
31
32 # Check if we are asked to render a certain revision
33 revision = self.get_argument("revision", None)
34
35 # Fetch the wiki page
36 page = self.backend.wiki.get_page(path, revision=revision)
37
38 # Diff
39 if self.action == "diff":
40 # Get both revisions
41 a = self.get_argument("a")
42 b = self.get_argument("b")
43
44 # Fetch both versions of the page
45 a = self.backend.wiki.get_page(path, revision=a)
46 b = self.backend.wiki.get_page(path, revision=b)
47 if not a or not b:
48 raise tornado.web.HTTPError(404)
49
50 # Cannot render a diff for the identical page
51 if a == b:
52 raise tornado.web.HTTPError(400)
53
54 # Make sure that b is newer than a
55 if a > b:
56 a, b = b, a
57
bd448717 58 self.render("docs/diff.html", page=page, a=a, b=b)
1958a22b
MT
59 return
60
61 # Restore
62 elif self.action == "restore":
a0a9be06 63 self.render("docs/confirm-restore.html", page=page)
1958a22b
MT
64 return
65
66 # Revisions
67 elif self.action == "revisions":
e9ee938d 68 self.render("docs/revisions.html", page=page)
1958a22b
MT
69 return
70
71 # If the page does not exist, we send 404
72 if not page or page.was_deleted():
73 # Handle /start links which were in the format of DokuWiki
74 if path.endswith("/start"):
75 # Strip /start from path
76 path = path[:-6] or "/"
77
78 # Redirect user to page if it exists
79 page = self.backend.wiki.page_exists(path)
80 if page:
81 self.redirect(path)
82
83 raise tornado.web.HTTPError(404)
84
85 # Fetch the latest revision
86 latest_revision = page.get_latest_revision()
87
88 # Render page
cf59466c
MT
89 self.render("docs/page.html", page=page, latest_revision=latest_revision)
90
91
4a1bfdd5
MT
92class FileHandler(base.BaseHandler):
93 @property
94 def action(self):
95 return self.get_argument("action", None)
96
97 def get(self, path):
98 # Check permissions
99 if not self.backend.wiki.check_acl(path, self.current_user):
100 raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
101
102 # Check if we are asked to render a certain revision
103 revision = self.get_argument("revision", None)
104
105 # Fetch the file
106 file = self.backend.wiki.get_file_by_path(path, revision=revision)
107 if not file:
108 raise tornado.web.HTTPError(404, "Could not find %s" % path)
109
110 # Render detail page
111 if self.action == "detail":
112 page = None
113
114 for breadcrumb, title in self.backend.wiki.make_breadcrumbs(path):
115 page = self.backend.wiki.get_page(breadcrumb)
116 if page:
117 break
118
119 self.render("wiki/files/detail.html", page=page, file=file)
120 return
121
122 size = self.get_argument_int("s", None)
123
124 # Check if image should be resized
125 if size and file.is_bitmap_image():
126 blob = file.get_thumbnail(size)
127 else:
128 blob = file.blob
129
130 # Set headers
131 self.set_header("Content-Type", file.mimetype or "application/octet-stream")
132 self.set_header("Content-Length", len(blob))
133
134 # Set expires
135 self.set_expires(3600)
136
137 # Deliver content
138 self.finish(blob)
139
140
cf59466c
MT
141class HeaderModule(ui_modules.UIModule):
142 @property
143 def page(self):
144 """
145 Returns the path of the page (without any actions)
146 """
147 path = self.request.path.removeprefix("/docs")
148
149 return "/".join((p for p in path.split("/") if not p.startswith("_")))
150
151 def render(self, suffix=None):
152 _ = self.locale.translate
153
154 breadcrumbs = self.backend.wiki.make_breadcrumbs(self.page)
155 title = self.backend.wiki.get_page_title(self.page)
156
157 if self.request.path.endswith("/_edit"):
158 suffix = _("Edit")
159 elif self.request.path.endswith("/_files"):
160 suffix = _("Files")
161
162 return self.render_string("docs/modules/header.html",
163 breadcrumbs=breadcrumbs, page=self.page, page_title=title, suffix=suffix)
739fff76
MT
164
165
166class DiffModule(ui_modules.UIModule):
167 differ = difflib.Differ()
168
169 def render(self, a, b):
170 diff = self.differ.compare(
171 a.markdown.splitlines(),
172 b.markdown.splitlines(),
173 )
174
175 return self.render_string("docs/modules/diff.html", diff=diff)