]>
git.ipfire.org Git - ipfire.org.git/blob - src/backend/wiki.py
9 from .decorators
import *
11 # Used to automatically link some things
14 (re
.compile(r
"(?:#(\d+))", re
.I
), r
"https://bugzilla.ipfire.org/show_bug.cgi?id=\1"),
17 (re
.compile(r
"([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)"), r
"mailto:\1"),
20 (re
.compile(r
"(?:CVE)[\s\-](\d{4}\-\d+)"), r
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=\1"),
23 class Wiki(misc
.Object
):
24 def _get_pages(self
, query
, *args
):
25 res
= self
.db
.query(query
, *args
)
28 yield Page(self
.backend
, row
.id, data
=row
)
30 def _get_page(self
, query
, *args
):
31 res
= self
.db
.get(query
, *args
)
34 return Page(self
.backend
, res
.id, data
=res
)
36 def get_page_title(self
, page
, default
=None):
37 doc
= self
.get_page(page
)
43 def get_page(self
, page
, revision
=None):
44 page
= Page
.sanitise_page_name(page
)
48 return self
._get
_page
("SELECT * FROM wiki WHERE page = %s \
49 AND timestamp = %s", page
, revision
)
51 return self
._get
_page
("SELECT * FROM wiki WHERE page = %s \
52 ORDER BY timestamp DESC LIMIT 1", page
)
54 def get_recent_changes(self
, limit
=None):
55 return self
._get
_pages
("SELECT * FROM wiki \
56 WHERE timestamp >= NOW() - INTERVAL '4 weeks' \
57 ORDER BY timestamp DESC LIMIT %s", limit
)
59 def create_page(self
, page
, author
, content
, changes
=None, address
=None):
60 page
= Page
.sanitise_page_name(page
)
62 return self
._get
_page
("INSERT INTO wiki(page, author_uid, markdown, changes, address) \
63 VALUES(%s, %s, %s, %s, %s) RETURNING *", page
, author
.uid
, content
, changes
, address
)
65 def delete_page(self
, page
, author
, **kwargs
):
66 # Do nothing if the page does not exist
67 if not self
.get_page(page
):
70 # Just creates a blank last version of the page
71 self
.create_page(page
, author
=author
, content
=None, **kwargs
)
75 parts
= list(e
for e
in url
.split("/") if e
)
77 num_parts
= len(parts
)
78 for i
in range(num_parts
):
79 yield "/".join(parts
[:i
])
81 def make_breadcrumbs(self
, url
):
82 for part
in self
._split
_url
(url
):
83 title
= self
.get_page_title(part
, os
.path
.basename(part
))
85 yield ("/%s" % part
, title
)
88 class Page(misc
.Object
):
89 def init(self
, id, data
=None):
93 def __lt__(self
, other
):
94 if isinstance(other
, self
.__class
__):
95 if self
.page
== other
.page
:
96 return self
.timestamp
< other
.timestamp
98 return self
.page
< other
.page
101 def sanitise_page_name(page
):
105 # Make sure that the page name does NOT end with a /
106 if page
.endswith("/"):
109 # Make sure the page name starts with a /
110 if not page
.startswith("/"):
113 # Remove any double slashes
114 page
= page
.replace("//", "/")
124 return self
.data
.page
128 return self
._title
or self
.page
[1:]
132 if not self
.markdown
:
135 # Find first H1 headline in markdown
136 markdown
= self
.markdown
.splitlines()
138 m
= re
.match(r
"^# (.*)( #)?$", markdown
[0])
144 if self
.data
.author_uid
:
145 return self
.backend
.accounts
.get_by_uid(self
.data
.author_uid
)
147 def _render(self
, text
):
148 logging
.debug("Rendering %s" % self
)
150 return markdown2
.markdown(text
, link_patterns
=link_patterns
,
151 extras
=["footnotes", "link-patterns", "wiki-tables"])
155 return self
.data
.markdown
159 return self
.data
.html
or self
._render
(self
.markdown
)
163 return self
.data
.timestamp
165 def was_deleted(self
):
166 return self
.markdown
is None
169 def breadcrumbs(self
):
170 return self
.backend
.wiki
.make_breadcrumbs(self
.page
)
172 def get_latest_revision(self
):
173 return self
.backend
.wiki
.get_page(self
.page
)
177 return self
.data
.changes
183 parts
= self
.page
.split("/")
186 sidebar
= self
.backend
.wiki
.get_page(os
.path
.join(*parts
, "sidebar"))