]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - webapp/backend/planet.py
planet: Remove tags.
[people/shoehn/ipfire.org.git] / webapp / backend / planet.py
1 #!/usr/bin/python
2
3 import datetime
4 import re
5 import textile
6 import unicodedata
7
8 from misc import Object
9
10 class PlanetEntry(Object):
11 def __init__(self, backend, data):
12 Object.__init__(self, backend)
13
14 self.data = data
15
16 @property
17 def id(self):
18 return self.data.id
19
20 @property
21 def slug(self):
22 return self.data.slug
23
24 def set_title(self, title):
25 if self.title == title:
26 return
27
28 self.db.execute("UPDATE planet SET title = %s WHERE id = %s", title, self.id)
29 self.data["title"] = title
30
31 title = property(lambda s: s.data.title, set_title)
32
33 @property
34 def url(self):
35 return "http://planet.ipfire.org/post/%s" % self.slug
36
37 def set_published(self, published):
38 if self.published == published:
39 return
40
41 self.db.execute("UPDATE planet SET published = %s WHERE id = %s",
42 published, self.id)
43 self.data["published"] = published
44
45 published = property(lambda s: s.data.published, set_published)
46
47 @property
48 def year(self):
49 return self.published.year
50
51 @property
52 def month(self):
53 return self.published.month
54
55 @property
56 def updated(self):
57 return self.data.updated
58
59 def get_markdown(self):
60 return self.data.markdown
61
62 def set_markdown(self, markdown):
63 if self.markdown == markdown:
64 return
65
66 markup = self.render(markdown)
67 self.db.execute("UPDATE planet SET markdown = %s, markup = %s WHERE id = %s",
68 markdown, markup, self.id)
69
70 self.data.update({
71 "markdown" : markdown,
72 "markup" : markup,
73 })
74
75 markdown = property(get_markdown, set_markdown)
76
77 @property
78 def markup(self):
79 if self.data.markup:
80 return self.data.markup
81
82 return self.render(self.markdown)
83
84 @property
85 def abstract(self):
86 return self.render(self.markdown, 400)
87
88 def render(self, text, limit=0):
89 return self.planet.render(text, limit)
90
91 @property
92 def text(self):
93 # Compat for markup
94 return self.markup
95
96 @property
97 def author(self):
98 if not hasattr(self, "__author"):
99 self.__author = self.accounts.search(self.data.author_id)
100
101 return self.__author
102
103 def set_status(self, status):
104 if self.status == status:
105 return
106
107 self.db.execute("UPDATE planet SET status = %s WHERE id = %s", status, self.id)
108 self.data["status"] = status
109
110 status = property(lambda s: s.data.status, set_status)
111
112 def is_draft(self):
113 return self.status == "draft"
114
115 def is_published(self):
116 return self.status == "published"
117
118
119 class Planet(Object):
120 def get_authors(self):
121 query = self.db.query("SELECT DISTINCT author_id FROM planet WHERE status = %s \
122 AND published IS NOT NULL AND published <= NOW()", "published")
123
124 authors = []
125 for author in query:
126 author = self.accounts.search(author.author_id)
127 if author:
128 authors.append(author)
129
130 return sorted(authors)
131
132 def get_years(self):
133 res = self.db.query("SELECT DISTINCT EXTRACT(YEAR FROM published)::integer AS year \
134 FROM planet WHERE status = %s ORDER BY year DESC", "published")
135
136 return [row.year for row in res]
137
138 def get_entry_by_slug(self, slug):
139 entry = self.db.get("SELECT * FROM planet WHERE slug = %s", slug)
140
141 if entry:
142 return PlanetEntry(self.backend, entry)
143
144 def get_entry_by_id(self, id):
145 entry = self.db.get("SELECT * FROM planet WHERE id = %s", id)
146
147 if entry:
148 return PlanetEntry(self.backend, entry)
149
150 def get_entries(self, limit=3, offset=None, status="published", author_id=None):
151 query = "SELECT * FROM planet"
152 args, clauses = [], []
153
154 if status:
155 clauses.append("status = %s")
156 args.append(status)
157
158 if author_id:
159 clauses.append("author_id = %s")
160 args.append(author_id)
161
162 if clauses:
163 query += " WHERE %s" % " AND ".join(clauses)
164
165 query += " ORDER BY published DESC"
166
167 # Respect limit and offset
168 if limit:
169 query += " LIMIT %s"
170 args.append(limit)
171
172 if offset:
173 query += " OFFSET %s"
174 args.append(offset)
175
176 entries = []
177 for entry in self.db.query(query, *args):
178 entry = PlanetEntry(self.backend, entry)
179 entries.append(entry)
180
181 return entries
182
183 def get_entries_by_author(self, author_id, limit=None, offset=None):
184 return self.get_entries(limit=limit, offset=offset, author_id=author_id)
185
186 def get_entries_by_year(self, year):
187 entries = self.db.query("SELECT * FROM planet \
188 WHERE status = %s AND EXTRACT(YEAR FROM published) = %s \
189 ORDER BY published DESC", "published", year)
190
191 return [PlanetEntry(self.backend, e) for e in entries]
192
193 def render(self, text, limit=0):
194 if limit and len(text) >= limit:
195 text = text[:limit] + "..."
196
197 return textile.textile(text)
198
199 def _generate_slug(self, title):
200 slug = unicodedata.normalize("NFKD", title).encode("ascii", "ignore")
201 slug = re.sub(r"[^\w]+", " ", slug)
202 slug = "-".join(slug.lower().strip().split())
203
204 if not slug:
205 slug = "entry"
206
207 while True:
208 e = self.db.get("SELECT * FROM planet WHERE slug = %s", slug)
209 if not e:
210 break
211 slug += "-"
212
213 return slug
214
215 def create(self, title, markdown, author, status="published", published=None):
216 slug = self._generate_slug(title)
217 markup = self.render(markdown)
218
219 if published is None:
220 published = datetime.datetime.utcnow()
221
222 id = self.db.execute("INSERT INTO planet(author_id, slug, title, status, \
223 markdown, markup, published) VALUES(%s, %s, %s, %s, %s, %s, %s) RETURNING id",
224 author.uid, slug, title, status, markdown, markup, published)
225
226 if id:
227 return self.get_entry_by_id(id)
228
229 def update_entry(self, entry):
230 self.db.execute("UPDATE planet SET title = %s, markdown = %s WHERE id = %s",
231 entry.title, entry.markdown, entry.id)
232
233 def save_entry(self, entry):
234 slug = self._generate_slug(entry.title)
235
236 id = self.db.execute("INSERT INTO planet(author_id, title, slug, markdown, published) \
237 VALUES(%s, %s, %s, %s, NOW())", entry.author.uid, entry.title, slug, entry.markdown)
238
239 return id
240
241 def search(self, what):
242 res = self.db.query("WITH \
243 q AS (SELECT plainto_tsquery(%s, %s) AS query), \
244 ranked AS (SELECT id, query, ts_rank_cd(to_tsvector(%s, markdown), query) AS rank \
245 FROM planet, q WHERE markdown @@ query ORDER BY rank DESC) \
246 SELECT *, ts_headline(markup, ranked.query, 'MinWords=100, MaxWords=110') AS markup FROM planet \
247 JOIN ranked ON planet.id = ranked.id \
248 WHERE status = %s AND published IS NOT NULL AND published <= NOW() \
249 ORDER BY ranked DESC LIMIT 10",
250 "english", what, "english", "published")
251
252 return [PlanetEntry(self.backend, e) for e in res]