]> git.ipfire.org Git - ipfire.org.git/blob - src/backend/blog.py
346e3184052a913ed29060f9117890d1aeafcd69
[ipfire.org.git] / src / backend / blog.py
1 #!/usr/bin/python
2
3 import textile
4
5 from . import misc
6
7 class Blog(misc.Object):
8 def _get_post(self, query, *args):
9 res = self.db.get(query, *args)
10
11 if res:
12 return Post(self.backend, res.id, data=res)
13
14 def _get_posts(self, query, *args):
15 res = self.db.query(query, *args)
16
17 for row in res:
18 yield Post(self.backend, row.id, data=row)
19
20 def get_by_id(self, id):
21 return self._get_post("SELECT * FROM blog \
22 WHERE id = %s", id)
23
24 def get_by_slug(self, slug):
25 return self._get_post("SELECT * FROM blog \
26 WHERE slug = %s AND published_at <= NOW()", slug)
27
28 def get_newest(self, limit=None):
29 return self._get_posts("SELECT * FROM blog \
30 WHERE published_at IS NOT NULL \
31 AND published_at <= NOW() \
32 ORDER BY published_at DESC LIMIT %s", limit)
33
34 def get_by_tag(self, tag, limit=None):
35 return self._get_posts("SELECT * FROM blog \
36 WHERE published_at IS NOT NULL \
37 AND published_at <= NOW() \
38 AND %s = ANY(tags) \
39 ORDER BY published_at DESC LIMIT %s", tag, limit)
40
41 def get_by_author(self, author, limit=None):
42 return self._get_posts("SELECT * FROM blog \
43 WHERE (author = %s OR author_uid = %s) \
44 AND published_at IS NOT NULL \
45 AND published_at <= NOW() \
46 ORDER BY published_at DESC LIMIT %s",
47 author.name, author.uid, limit)
48
49 def get_by_year(self, year):
50 return self._get_posts("SELECT * FROM blog \
51 WHERE EXTRACT(year FROM published_at) = %s \
52 AND published_at IS NOT NULL \
53 AND published_at <= NOW() \
54 ORDER BY published_at DESC", year)
55
56 def search(self, query, limit=None):
57 return self._get_posts("SELECT blog.* FROM blog \
58 LEFT JOIN blog_search_index search_index ON blog.id = search_index.post_id \
59 WHERE search_index.document @@ to_tsquery('english', %s) \
60 ORDER BY ts_rank(search_index.document, to_tsquery('english', %s)) DESC \
61 LIMIT %s", query, query, limit)
62
63 def refresh(self):
64 """
65 Needs to be called after a post has been changed
66 and updates the search index.
67 """
68 self.db.execute("REFRESH MATERIALIZED VIEW blog_search_index")
69
70 @property
71 def years(self):
72 res = self.db.query("SELECT DISTINCT EXTRACT(year FROM published_at)::integer AS year \
73 FROM blog WHERE published_at IS NOT NULL AND published_at <= NOW() \
74 ORDER BY year DESC")
75
76 for row in res:
77 yield row.year
78
79
80 class Post(misc.Object):
81 def init(self, id, data=None):
82 self.id = id
83 self.data = data
84
85 @property
86 def title(self):
87 return self.data.title
88
89 @property
90 def slug(self):
91 return self.data.slug
92
93 # XXX needs caching
94 @property
95 def author(self):
96 if self.data.author_uid:
97 return self.backend.accounts.get_by_uid(self.data.author_uid)
98
99 return self.data.author
100
101 @property
102 def created_at(self):
103 return self.data.created_at
104
105 @property
106 def published_at(self):
107 return self.data.published_at
108
109 @property
110 def markdown(self):
111 return self.data.markdown
112
113 @property
114 def html(self):
115 """
116 Returns this post as rendered HTML
117 """
118 return self.data.html or textile.textile(self.markdown.decode("utf-8"))
119
120 @property
121 def tags(self):
122 return self.data.tags
123
124 @property
125 def link(self):
126 return self.data.link