return self._get_page("SELECT * FROM wiki WHERE page = %s \
ORDER BY timestamp DESC LIMIT 1", page)
- def get_recent_changes(self, limit=None):
- return self._get_pages("SELECT * FROM wiki \
+ def get_recent_changes(self, account, limit=None):
+ pages = self._get_pages("SELECT * FROM wiki \
WHERE timestamp >= NOW() - INTERVAL '4 weeks' \
- ORDER BY timestamp DESC LIMIT %s", limit)
+ ORDER BY timestamp DESC")
+
+ for page in pages:
+ if not page.check_acl(account):
+ continue
+
+ yield page
+
+ limit -= 1
+ if not limit:
+ break
def create_page(self, page, author, content, changes=None, address=None):
page = Page.sanitise_page_name(page)
return ret
- def search(self, query, limit=None):
+ def search(self, query, account=None, limit=None):
query = util.parse_search_query(query)
res = self._get_pages("SELECT wiki.* FROM wiki_search_index search_index \
LEFT JOIN wiki ON search_index.wiki_id = wiki.id \
WHERE search_index.document @@ to_tsquery('english', %s) \
- ORDER BY ts_rank(search_index.document, to_tsquery('english', %s)) DESC \
- LIMIT %s", query, query, limit)
+ ORDER BY ts_rank(search_index.document, to_tsquery('english', %s)) DESC",
+ query, query)
- return list(res)
+ for page in res:
+ # Skip any pages the user doesn't have permission for
+ if not page.check_acl(account):
+ continue
+
+ # Return any other pages
+ yield page
+
+ limit -= 1
+ if not limit:
+ break
def refresh(self):
"""
"""
self.db.execute("REFRESH MATERIALIZED VIEW wiki_search_index")
+ # ACL
+
+ def check_acl(self, page, account):
+ res = self.db.query("SELECT * FROM wiki_acls \
+ WHERE %s ILIKE (path || '%%') ORDER BY LENGTH(path) DESC LIMIT 1", page)
+
+ for row in res:
+ # Access not permitted when user is not logged in
+ if not account:
+ return False
+
+ # If user is in a matching group, we grant permission
+ for group in row.groups:
+ if group in account.groups:
+ return True
+
+ # Otherwise access is not permitted
+ return False
+
+ # If no ACLs are found, we permit access
+ return True
+
# Files
def _get_files(self, query, *args):
def changes(self):
return self.data.changes
+ # ACL
+
+ def check_acl(self, account):
+ return self.backend.wiki.check_acl(self.page, account)
+
# Sidebar
@lazy_property
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")
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)
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)
@tornado.web.removeslash
def get(self, page):
+ # Check permissions
+ if not self.backend.wiki.check_acl(page, self.current_user):
+ raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (page, self.current_user))
+
# Check if we are asked to render a certain revision
revision = self.get_argument("revision", None)
@tornado.web.authenticated
def post(self, page):
+ # Check permissions
+ if not self.backend.wiki.check_acl(page, self.current_user):
+ raise tornado.web.HTTPError(403, "Access to %s not allowed for %s" % (page, self.current_user))
+
content = self.get_argument("content", None)
changes = self.get_argument("changes")
def get(self):
q = self.get_argument("q")
- pages = self.backend.wiki.search(q, limit=50)
+ pages = self.backend.wiki.search(q, account=self.current_user, limit=50)
- self.render("wiki/search-results.html", q=q, pages=pages)
+ self.render("wiki/search-results.html", q=q, pages=list(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)