]> git.ipfire.org Git - ipfire.org.git/blame - src/web/wiki.py
wiki: Make bottom bar less eye-catching
[ipfire.org.git] / src / web / wiki.py
CommitLineData
181d08f3
MT
1#!/usr/bin/python3
2
c21ffadb 3import difflib
181d08f3
MT
4import tornado.web
5
6from . import auth
7from . import base
6ac7e934 8from . import ui_modules
181d08f3 9
b6e8b28f
MT
10class ActionEditHandler(auth.CacheMixin, base.BaseHandler):
11 @tornado.web.authenticated
12 def post(self):
13 path = self.get_argument("path")
14
15 # Check permissions
16 if not self.backend.wiki.check_acl(path, self.current_user):
17 raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
18
19 content = self.get_argument("content", None)
20 changes = self.get_argument("changes")
21
22 # Create a new page in the database
23 with self.db.transaction():
24 page = self.backend.wiki.create_page(path,
25 self.current_user, content, changes=changes, address=self.get_remote_ip())
26
d64a1e35
MT
27 # Add user as a watcher if wanted
28 watch = self.get_argument("watch", False)
29 if watch:
30 page.add_watcher(self.current_user)
31
b6e8b28f
MT
32 # Redirect back
33 if page.was_deleted():
34 self.redirect("/")
35 else:
36 self.redirect(page.url)
37
38 def on_finish(self):
39 """
40 Updates the search index after the page has been edited
41 """
42 # This is being executed in the background and after
43 # the response has been set to the client
44 with self.db.transaction():
45 self.backend.wiki.refresh()
46
47
f2cfd873
MT
48class ActionUploadHandler(auth.CacheMixin, base.BaseHandler):
49 @tornado.web.authenticated
50 def post(self):
51 path = self.get_argument("path")
52
11afe905
MT
53 # Check permissions
54 if not self.backend.wiki.check_acl(path, self.current_user):
55 raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
56
f2cfd873
MT
57 try:
58 filename, data, mimetype = self.get_file("file")
59
60 # XXX check valid mimetypes
61
62 with self.db.transaction():
63 file = self.backend.wiki.upload(path, filename, data,
64 mimetype=mimetype, author=self.current_user,
65 address=self.get_remote_ip())
66
67 except TypeError as e:
68 raise e
69
70 self.redirect("%s/files" % path)
71
72
d64a1e35
MT
73class ActionWatchHandler(auth.CacheMixin, base.BaseHandler):
74 @tornado.web.authenticated
75 def get(self, action, path):
76 page = self.backend.wiki.get_page(path)
77 if not page:
78 raise tornado.web.HTTPError(404, "Page does not exist: %s" % path)
79
80 with self.db.transaction():
81 if action == "watch":
82 page.add_watcher(self.current_user)
83 elif action == "unwatch":
84 page.remove_watcher(self.current_user)
85
86 # Redirect back to page
87 self.redirect(page.url)
88
89
f2cfd873
MT
90class FilesHandler(auth.CacheMixin, base.BaseHandler):
91 @tornado.web.authenticated
92 def get(self, path):
11afe905
MT
93 # Check permissions
94 if not self.backend.wiki.check_acl(path, self.current_user):
95 raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
96
f2cfd873
MT
97 files = self.backend.wiki.get_files(path)
98
99 self.render("wiki/files/index.html", path=path, files=files)
100
101
568b265b 102class FileHandler(base.BaseHandler):
8cb0bea4
MT
103 @property
104 def action(self):
105 return self.get_argument("action", None)
106
f2cfd873 107 def get(self, path):
11afe905
MT
108 # Check permissions
109 if not self.backend.wiki.check_acl(path, self.current_user):
110 raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (path, self.current_user))
111
112 # Fetch the file
f2cfd873
MT
113 file = self.backend.wiki.get_file_by_path(path)
114 if not file:
115 raise tornado.web.HTTPError(404, "Could not find %s" % path)
116
8cb0bea4
MT
117 # Render detail page
118 if self.action == "detail":
119 self.render("wiki/files/detail.html", file=file)
120 return
121
79dd9a0f
MT
122 size = self.get_argument_int("s", None)
123
124 # Check if image should be resized
125 if file.is_image() and size:
126 blob = file.get_thumbnail(size)
127 else:
128 blob = file.blob
129
f2cfd873
MT
130 # Set headers
131 self.set_header("Content-Type", file.mimetype or "application/octet-stream")
79dd9a0f 132 self.set_header("Content-Length", len(blob))
f2cfd873 133
568b265b
MT
134 # Set expires
135 self.set_expires(3600)
136
79dd9a0f
MT
137 # Deliver content
138 self.finish(blob)
f2cfd873
MT
139
140
181d08f3 141class PageHandler(auth.CacheMixin, base.BaseHandler):
d398ca08
MT
142 @property
143 def action(self):
144 return self.get_argument("action", None)
145
a446dcb9
MT
146 def write_error(self, status_code, **kwargs):
147 # Render a custom page for 404
148 if status_code == 404:
149 self.render("wiki/404.html", **kwargs)
150 return
151
152 # Otherwise raise this to one layer above
153 super().write_error(status_code, **kwargs)
154
181d08f3
MT
155 @tornado.web.removeslash
156 def get(self, page):
11afe905
MT
157 # Check permissions
158 if not self.backend.wiki.check_acl(page, self.current_user):
159 raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (page, self.current_user))
160
7d699684
MT
161 # Check if we are asked to render a certain revision
162 revision = self.get_argument("revision", None)
163
164 # Fetch the wiki page
165 page = self.backend.wiki.get_page(page, revision=revision)
181d08f3 166
c21ffadb
MT
167 # Diff
168 if self.action == "diff":
169 # Get both revisions
170 a = self.get_argument("a")
171 b = self.get_argument("b")
172
173 # Fetch both versions of the page
174 a = self.backend.wiki.get_page(page.page, revision=a)
175 b = self.backend.wiki.get_page(page.page, revision=b)
176 if not a or not b:
177 raise tornado.web.HTTPError(404)
178
179 # Cannot render a diff for the identical page
180 if a == b:
181 raise tornado.web.HTTPError(400)
182
183 # Make sure that b is newer than a
184 if a > b:
185 a, b = b, a
186
187 self.render("wiki/diff.html", page=page, a=a, b=b)
188 return
189
d398ca08 190 # Edit
c21ffadb 191 elif self.action == "edit":
d398ca08
MT
192 if not self.current_user:
193 raise tornado.web.HTTPError(401)
194
195 # Empty page if it was deleted
addc4eb7 196 if page and page.was_deleted():
d398ca08
MT
197 page = None
198
7d699684
MT
199 # Render page
200 self.render("wiki/edit.html", page=page)
201 return
202
203 # Revisions
204 elif self.action == "revisions":
205 self.render("wiki/revisions.html", page=page)
206 return
d398ca08 207
181d08f3
MT
208 # If the page does not exist, we send 404
209 if not page or page.was_deleted():
210 raise tornado.web.HTTPError(404)
211
212 # Fetch the latest revision
213 latest_revision = page.get_latest_revision()
214
215 # Render page
216 self.render("wiki/page.html", page=page, latest_revision=latest_revision)
217
181d08f3
MT
218
219class SearchHandler(auth.CacheMixin, base.BaseHandler):
220 @base.blacklisted
221 def get(self):
222 q = self.get_argument("q")
223
11afe905 224 pages = self.backend.wiki.search(q, account=self.current_user, limit=50)
181d08f3 225
11afe905 226 self.render("wiki/search-results.html", q=q, pages=list(pages))
6ac7e934
MT
227
228
f9db574a
MT
229class RecentChangesHandler(auth.CacheMixin, base.BaseHandler):
230 def get(self):
11afe905 231 recent_changes = self.backend.wiki.get_recent_changes(self.current_user, limit=50)
f9db574a
MT
232
233 self.render("wiki/recent-changes.html", recent_changes=recent_changes)
234
235
c21ffadb
MT
236class WikiDiffModule(ui_modules.UIModule):
237 differ = difflib.Differ()
238
239 def render(self, a, b):
240 diff = self.differ.compare(
241 a.markdown.splitlines(),
242 b.markdown.splitlines(),
243 )
244
245 return self.render_string("wiki/modules/diff.html", diff=diff)
246
247
f9db574a 248class WikiListModule(ui_modules.UIModule):
7d699684
MT
249 def render(self, pages, link_revision=False, show_breadcrumbs=True, show_changes=False):
250 return self.render_string("wiki/modules/list.html", link_revision=link_revision,
66a814d9 251 pages=pages, show_breadcrumbs=show_breadcrumbs, show_changes=show_changes)
f9db574a
MT
252
253
6ac7e934 254class WikiNavbarModule(ui_modules.UIModule):
67573803 255 def render(self, suffix=None):
f2cfd873
MT
256 _ = self.locale.translate
257
67573803
MT
258 breadcrumbs = self.backend.wiki.make_breadcrumbs(self.request.path)
259
f2cfd873
MT
260 # Don't search for a title for the file manager
261 if self.request.path.endswith("/files"):
262 title = _("Files")
263 else:
264 title = self.backend.wiki.get_page_title(self.request.path)
6ac7e934
MT
265
266 return self.render_string("wiki/modules/navbar.html",
67573803 267 breadcrumbs=breadcrumbs, page_title=title, suffix=suffix)