]>
git.ipfire.org Git - ipfire.org.git/blob - src/backend/blog.py
1a73d04a4d54c03c09b2e108a006f54944433c5d
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
, published
=True):
30 return self
._get
_post
("SELECT * FROM blog \
31 WHERE slug = %s AND published_at <= NOW()", slug
)
33 return self
._get
_post
("SELECT * FROM blog \
34 WHERE slug = %s", slug
)
37 def get_newest(self
, limit
=None):
38 return self
._get
_posts
("SELECT * FROM blog \
39 WHERE published_at IS NOT NULL \
40 AND published_at <= NOW() \
41 ORDER BY published_at DESC LIMIT %s", limit
)
43 def get_by_tag(self
, tag
, limit
=None):
44 return self
._get
_posts
("SELECT * FROM blog \
45 WHERE published_at IS NOT NULL \
46 AND published_at <= NOW() \
48 ORDER BY published_at DESC LIMIT %s", tag
, limit
)
50 def get_by_author(self
, author
, limit
=None):
51 return self
._get
_posts
("SELECT * FROM blog \
52 WHERE (author = %s OR author_uid = %s) \
53 AND published_at IS NOT NULL \
54 AND published_at <= NOW() \
55 ORDER BY published_at DESC LIMIT %s",
56 author
.name
, author
.uid
, limit
)
58 def get_by_year(self
, year
):
59 return self
._get
_posts
("SELECT * FROM blog \
60 WHERE EXTRACT(year FROM published_at) = %s \
61 AND published_at IS NOT NULL \
62 AND published_at <= NOW() \
63 ORDER BY published_at DESC", year
)
65 def get_drafts(self
, author
=None, limit
=None):
67 return self
._get
_posts
("SELECT * FROM blog \
68 WHERE author_uid = %s \
69 AND (published_at IS NULL OR published_at > NOW()) \
70 ORDER BY COALESCE(updated_at, created_at) DESC LIMIT %s",
73 return self
._get
_posts
("SELECT * FROM blog \
74 WHERE (published_at IS NULL OR published_at > NOW()) \
75 ORDER BY COALESCE(updated_at, created_at) DESC LIMIT %s", limit
)
77 def search(self
, query
, limit
=None):
78 return self
._get
_posts
("SELECT blog.* FROM blog \
79 LEFT JOIN blog_search_index search_index ON blog.id = search_index.post_id \
80 WHERE search_index.document @@ to_tsquery('english', %s) \
81 ORDER BY ts_rank(search_index.document, to_tsquery('english', %s)) DESC \
82 LIMIT %s", query
, query
, limit
)
84 def create_post(self
, title
, text
, author
, tags
=[]):
86 Creates a new post and returns the resulting Post object
88 return self
._get
_post
("INSERT INTO blog(title, slug, text, author_uid, tags) \
89 VALUES(%s, %s, %s, %s, %s) RETURNING *", title
, self
._make
_slug
(title
),
90 text
, author
.uid
, list(tags
))
92 def _make_slug(self
, s
):
93 # Remove any non-ASCII characters
95 s
= unicodedata
.normalize("NFKD", s
)
99 # Remove excessive whitespace
100 s
= re
.sub(r
"[^\w]+", " ", s
)
102 slug
= "-".join(s
.split()).lower()
105 e
= self
.db
.get("SELECT 1 FROM blog WHERE slug = %s", slug
)
115 Needs to be called after a post has been changed
116 and updates the search index.
118 self
.db
.execute("REFRESH MATERIALIZED VIEW blog_search_index")
122 res
= self
.db
.query("SELECT DISTINCT EXTRACT(year FROM published_at)::integer AS year \
123 FROM blog WHERE published_at IS NOT NULL AND published_at <= NOW() \
129 def update_feeds(self
):
131 Updates all enabled feeds
133 for feed
in self
.db
.query("SELECT * FROM blog_feeds WHERE enabled IS TRUE"):
135 f
= feedparser
.parse(feed
.url
)
136 except Exception as e
:
139 with self
.db
.transaction():
141 self
.db
.execute("UPDATE blog_feeds SET name = %s \
142 WHERE id = %s", f
.feed
.title
, feed
.id)
144 # Walk through all entries
145 for entry
in f
.entries
:
146 # Skip everything without the "blog.ipfire.org" tag
148 tags
= list((t
.term
for t
in entry
.tags
))
150 if not "blog.ipfire.org" in tags
:
152 except AttributeError:
155 # Get link to the posting site
156 link
= entry
.links
[0].href
158 # Check if the entry has already been imported
159 res
= self
.db
.get("SELECT id, (updated_at < %s) AS needs_update \
160 FROM blog WHERE feed_id = %s AND foreign_id = %s",
161 entry
.updated
, feed
.id, entry
.id)
163 # If the post needs to be updated, we do so
165 self
.db
.execute("UPDATE blog SET title = %s, author = %s, \
166 published_at = %s, updated_at = %s, html = %s, link = %s, \
167 tags = %s WHERE id = %s", entry
.title
, entry
.author
,
168 entry
.published
, entry
.updated
, entry
.summary
, link
,
169 feed
.tags
+ tags
, res
.id)
174 # Insert the new post
175 self
.db
.execute("INSERT INTO blog(title, slug, author, \
176 published_at, html, link, tags, updated_at, feed_id, foreign_id) \
177 VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
178 entry
.title
, self
._make
_slug
(entry
.title
), entry
.author
,
179 entry
.published
, entry
.summary
, link
, feed
.tags
+ tags
,
180 entry
.updated
, feed
.id, entry
.id)
182 # Mark feed as updated
183 self
.db
.execute("UPDATE blog_feeds SET last_updated_at = CURRENT_TIMESTAMP \
184 WHERE id = %s" % feed
.id)
186 # Refresh the search index
187 with self
.db
.transaction():
191 class Post(misc
.Object
):
192 def init(self
, id, data
=None):
199 return self
.data
.title
201 def set_title(self
, title
):
202 self
.db
.execute("UPDATE blog SET title = %s \
203 WHERE id = %s", title
, self
.id)
205 # Update slug if post is not published, yet
206 if not self
.is_published():
207 self
.db
.execute("UPDATE blog SET slug = %s \
208 WHERE id = %s", self
.backend
.blog
._make
_slug
(title
), self
.id)
210 title
= property(get_title
, set_title
)
214 return self
.data
.slug
219 if self
.data
.author_uid
:
220 return self
.backend
.accounts
.get_by_uid(self
.data
.author_uid
)
222 return self
.data
.author
225 def created_at(self
):
226 return self
.data
.created_at
231 def published_at(self
):
232 return self
.data
.published_at
234 def is_published(self
):
236 Returns True if the post is already published
238 return self
.published_at
and self
.published_at
<= datetime
.datetime
.now()
241 if self
.is_published():
244 self
.db
.execute("UPDATE blog SET published_at = NOW() \
245 WHERE id = %s", self
.id)
247 # Update search indices
248 self
.backend
.blog
.refresh()
253 def updated_at(self
):
254 return self
.data
.updated_at
257 self
.db
.execute("UPDATE blog SET updated_at = NOW() \
258 WHERE id = %s", self
.id)
260 # Update search indices
261 self
.backend
.blog
.refresh()
266 return self
.data
.text
268 def set_text(self
, text
):
269 self
.db
.execute("UPDATE blog SET text = %s \
270 WHERE id = %s", text
, self
.id)
272 text
= property(get_text
, set_text
)
279 Returns this post as rendered HTML
281 return self
.data
.html
or textile
.textile(self
.text
.decode("utf-8"))
286 return self
.data
.tags
288 def set_tags(self
, tags
):
289 self
.db
.execute("UPDATE blog SET tags = %s \
290 WHERE id = %s", list(tags
), self
.id)
292 tags
= property(get_tags
, set_tags
)
296 return self
.data
.link
301 return self
.backend
.releases
._get
_release
("SELECT * FROM releases \
302 WHERE published IS NOT NULL AND published <= NOW() AND blog_id = %s", self
.id)