]>
git.ipfire.org Git - ipfire.org.git/blob - src/backend/blog.py
11 class Blog(misc
.Object
):
12 def _get_post(self
, query
, *args
):
13 res
= self
.db
.get(query
, *args
)
16 return Post(self
.backend
, res
.id, data
=res
)
18 def _get_posts(self
, query
, *args
):
19 res
= self
.db
.query(query
, *args
)
22 yield Post(self
.backend
, row
.id, data
=row
)
24 def get_by_id(self
, id):
25 return self
._get
_post
("SELECT * FROM blog \
28 def get_by_slug(self
, slug
):
29 return self
._get
_post
("SELECT * FROM blog \
30 WHERE slug = %s AND published_at <= NOW()", slug
)
32 def get_newest(self
, limit
=None):
33 return self
._get
_posts
("SELECT * FROM blog \
34 WHERE published_at IS NOT NULL \
35 AND published_at <= NOW() \
36 ORDER BY published_at DESC LIMIT %s", limit
)
38 def get_by_tag(self
, tag
, limit
=None):
39 return self
._get
_posts
("SELECT * FROM blog \
40 WHERE published_at IS NOT NULL \
41 AND published_at <= NOW() \
43 ORDER BY published_at DESC LIMIT %s", tag
, limit
)
45 def get_by_author(self
, author
, limit
=None):
46 return self
._get
_posts
("SELECT * FROM blog \
47 WHERE (author = %s OR author_uid = %s) \
48 AND published_at IS NOT NULL \
49 AND published_at <= NOW() \
50 ORDER BY published_at DESC LIMIT %s",
51 author
.name
, author
.uid
, limit
)
53 def get_by_year(self
, year
):
54 return self
._get
_posts
("SELECT * FROM blog \
55 WHERE EXTRACT(year FROM published_at) = %s \
56 AND published_at IS NOT NULL \
57 AND published_at <= NOW() \
58 ORDER BY published_at DESC", year
)
60 def get_drafts(self
, author
=None, limit
=None):
62 return self
._get
_posts
("SELECT * FROM blog \
63 WHERE author_uid = %s \
64 AND (published_at IS NULL OR published_at > NOW()) \
65 ORDER BY COALESCE(updated_at, created_at) DESC LIMIT %s",
68 return self
._get
_posts
("SELECT * FROM blog \
69 WHERE (published_at IS NULL OR published_at > NOW()) \
70 ORDER BY COALESCE(updated_at, created_at) DESC LIMIT %s", limit
)
72 def search(self
, query
, limit
=None):
73 return self
._get
_posts
("SELECT blog.* FROM blog \
74 LEFT JOIN blog_search_index search_index ON blog.id = search_index.post_id \
75 WHERE search_index.document @@ to_tsquery('english', %s) \
76 ORDER BY ts_rank(search_index.document, to_tsquery('english', %s)) DESC \
77 LIMIT %s", query
, query
, limit
)
79 def create_post(self
, title
, text
, author
, tags
=[]):
81 Creates a new post and returns the resulting Post object
83 return self
._get
_post
("INSERT INTO blog(title, slug, text, author_uid, tags) \
84 VALUES(%s, %s, %s, %s, %s) RETURNING *", title
, self
._make
_slug
(title
),
85 text
, author
.uid
, list(tags
))
87 def _make_slug(self
, s
):
88 # Remove any non-ASCII characters
90 s
= unicodedata
.normalize("NFKD", s
)
94 # Remove excessive whitespace
95 s
= re
.sub(r
"[^\w]+", " ", s
)
97 slug
= "-".join(s
.split()).lower()
100 e
= self
.db
.get("SELECT 1 FROM blog WHERE slug = %s", slug
)
110 Needs to be called after a post has been changed
111 and updates the search index.
113 self
.db
.execute("REFRESH MATERIALIZED VIEW blog_search_index")
117 res
= self
.db
.query("SELECT DISTINCT EXTRACT(year FROM published_at)::integer AS year \
118 FROM blog WHERE published_at IS NOT NULL AND published_at <= NOW() \
124 def update_feeds(self
):
126 Updates all enabled feeds
128 for feed
in self
.db
.query("SELECT * FROM blog_feeds WHERE enabled IS TRUE"):
130 f
= feedparser
.parse(feed
.url
)
131 except Exception as e
:
134 with self
.db
.transaction():
136 self
.db
.execute("UPDATE blog_feeds SET name = %s \
137 WHERE id = %s", f
.feed
.title
, feed
.id)
139 # Walk through all entries
140 for entry
in f
.entries
:
141 # Skip everything without the "blog.ipfire.org" tag
143 tags
= list((t
.term
for t
in entry
.tags
))
145 if not "blog.ipfire.org" in tags
:
147 except AttributeError:
150 # Get link to the posting site
151 link
= entry
.links
[0].href
153 # Check if the entry has already been imported
154 res
= self
.db
.get("SELECT id, (updated_at < %s) AS needs_update \
155 FROM blog WHERE feed_id = %s AND foreign_id = %s",
156 entry
.updated
, feed
.id, entry
.id)
158 # If the post needs to be updated, we do so
160 self
.db
.execute("UPDATE blog SET title = %s, author = %s, \
161 published_at = %s, updated_at = %s, html = %s, link = %s, \
162 tags = %s WHERE id = %s", entry
.title
, entry
.author
,
163 entry
.published
, entry
.updated
, entry
.summary
, link
,
164 feed
.tags
+ tags
, res
.id)
169 # Insert the new post
170 self
.db
.execute("INSERT INTO blog(title, slug, author, \
171 published_at, html, link, tags, updated_at, feed_id, foreign_id) \
172 VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
173 entry
.title
, self
._make
_slug
(entry
.title
), entry
.author
,
174 entry
.published
, entry
.summary
, link
, feed
.tags
+ tags
,
175 entry
.updated
, feed
.id, entry
.id)
177 # Mark feed as updated
178 self
.db
.execute("UPDATE blog_feeds SET last_updated_at = CURRENT_TIMESTAMP \
179 WHERE id = %s" % feed
.id)
181 # Refresh the search index
182 with self
.db
.transaction():
186 class Post(misc
.Object
):
187 def init(self
, id, data
=None):
194 return self
.data
.title
196 def set_title(self
, title
):
197 self
.db
.execute("UPDATE blog SET title = %s \
198 WHERE id = %s", title
, self
.id)
200 # Update slug if post is not published, yet
201 if not self
.is_published():
202 self
.db
.execute("UPDATE blog SET slug = %s \
203 WHERE id = %s", self
.backend
.blog
._make
_slug
(title
), self
.id)
205 title
= property(get_title
, set_title
)
209 return self
.data
.slug
214 if self
.data
.author_uid
:
215 return self
.backend
.accounts
.get_by_uid(self
.data
.author_uid
)
217 return self
.data
.author
220 def created_at(self
):
221 return self
.data
.created_at
226 def published_at(self
):
227 return self
.data
.published_at
229 def is_published(self
):
231 Returns True if the post is already published
233 return self
.published_at
and self
.published_at
<= datetime
.datetime
.now()
236 if self
.is_published():
239 self
.db
.execute("UPDATE blog SET published_at = NOW() \
240 WHERE id = %s", self
.id)
242 # Update search indices
243 self
.backend
.blog
.refresh()
248 def updated_at(self
):
249 return self
.data
.updated_at
252 self
.db
.execute("UPDATE blog SET updated_at = NOW() \
253 WHERE id = %s", self
.id)
255 # Update search indices
256 self
.backend
.blog
.refresh()
261 return self
.data
.text
263 def set_text(self
, text
):
264 self
.db
.execute("UPDATE blog SET text = %s \
265 WHERE id = %s", text
, self
.id)
267 text
= property(get_text
, set_text
)
274 Returns this post as rendered HTML
276 return self
.data
.html
or textile
.textile(self
.text
.decode("utf-8"))
281 return self
.data
.tags
283 def set_tags(self
, tags
):
284 self
.db
.execute("UPDATE blog SET tags = %s \
285 WHERE id = %s", list(tags
), self
.id)
287 tags
= property(get_tags
, set_tags
)
291 return self
.data
.link
296 return self
.backend
.releases
._get
_release
("SELECT * FROM releases \
297 WHERE published IS NOT NULL AND published <= NOW() AND blog_id = %s", self
.id)