From: Michael Tremer Date: Tue, 17 Jul 2018 18:24:00 +0000 (+0100) Subject: blog: Implement read-only backend X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0a6875dc4cce3b061255672bd583c099cf74506c;p=ipfire.org.git blog: Implement read-only backend Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 8761a283..ef9dbcc9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -51,6 +51,7 @@ backend_PYTHON = \ src/backend/accounts.py \ src/backend/ads.py \ src/backend/base.py \ + src/backend/blog.py \ src/backend/countries.py \ src/backend/database.py \ src/backend/fireinfo.py \ diff --git a/src/backend/base.py b/src/backend/base.py index 47d22c8b..9a403fab 100644 --- a/src/backend/base.py +++ b/src/backend/base.py @@ -19,6 +19,7 @@ import releases import settings import talk +from . import blog from . import zeiterfassung DEFAULT_CONFIG = StringIO.StringIO(""" @@ -60,6 +61,7 @@ class Backend(object): self.releases = releases.Releases(self) self.talk = talk.Talk(self) + self.blog = blog.Blog(self) self.zeiterfassung = zeiterfassung.ZeiterfassungClient(self) def read_config(self, configfile): diff --git a/src/backend/blog.py b/src/backend/blog.py new file mode 100644 index 00000000..f0044c89 --- /dev/null +++ b/src/backend/blog.py @@ -0,0 +1,89 @@ +#!/usr/bin/python + +from . import misc + +class Blog(misc.Object): + def _get_post(self, query, *args): + res = self.db.get(query, *args) + + if res: + return Post(self.backend, res.id, data=res) + + def _get_posts(self, query, *args): + res = self.db.query(query, *args) + + for row in res: + yield Post(self.backend, row.id, data=row) + + def get_by_slug(self, slug): + return self._get_post("SELECT * FROM blog \ + WHERE slug = %s AND published_at <= NOW()", slug) + + def get_newest(self, limit=None): + return self._get_posts("SELECT * FROM blog \ + WHERE published_at IS NOT NULL \ + AND published_at <= NOW() \ + ORDER BY published_at DESC LIMIT %s", limit) + + def get_by_tag(self, tag, limit=None): + return self._get_posts("SELECT * FROM blog \ + WHERE published_at IS NOT NULL \ + AND published_at <= NOW() \ + AND %s = ANY(tags) \ + ORDER BY published_at DESC LIMIT %s", limit) + + def get_by_author(self, uid, limit=None): + return self._get_posts("SELECT * FROM blog \ + WHERE author_uid = %s \ + AND published_at IS NOT NULL \ + AND published_at <= NOW() \ + ORDER BY published_at DESC LIMIT %s", uid, limit) + + def search(self, query, limit=None): + return self._get_posts("SELECT blog.* FROM blog \ + LEFT JOIN blog_search_index search_index ON blog.id = search_index.post_id \ + WHERE search_index.document @@ to_tsquery('english', %s) \ + ORDER BY ts_rank(search_index.document, to_tsquery('english', %s)) DESC \ + LIMIT %s", query, query, limit) + + def refresh(self): + """ + Needs to be called after a post has been changed + and updates the search index. + """ + self.db.execute("REFRESH MATERIALIZED VIEW blog_search_index") + + +class Post(misc.Object): + def init(self, id, data=None): + self.id = id + self.data = data + + @property + def title(self): + return self.data.title + + @property + def slug(self): + return self.data.slug + + # XXX needs caching + @property + def author(self): + if self.data.author_uid: + return self.backend.accounts.get_by_uid(self.data.author_uid) + + @property + def created_at(self): + return self.data.created_at + + @property + def published_at(self): + return self.data.published_at + + @property + def html(self): + """ + Returns this post as rendered HTML + """ + return self.data.html diff --git a/src/backend/misc.py b/src/backend/misc.py index 6dc85c88..c4b04807 100644 --- a/src/backend/misc.py +++ b/src/backend/misc.py @@ -1,12 +1,12 @@ #!/usr/bin/python class Object(object): - def __init__(self, backend): + def __init__(self, backend, *args, **kwargs): self.backend = backend - self.init() + self.init(*args, **kwargs) - def init(self): + def init(self, *args, **kwargs): """ Function for custom initialization. """ diff --git a/src/templates/blog/author.html b/src/templates/blog/author.html index 81792aa7..dc50dcaa 100644 --- a/src/templates/blog/author.html +++ b/src/templates/blog/author.html @@ -12,7 +12,7 @@ {{ post.title }}

- {{ locale.format_date(post.published, shorter=True, relative=False) }} + {{ locale.format_date(post.published_at, shorter=True, relative=False) }}

{% end %} diff --git a/src/templates/blog/feed.xml b/src/templates/blog/feed.xml index f159bc2a..69eaba34 100644 --- a/src/templates/blog/feed.xml +++ b/src/templates/blog/feed.xml @@ -28,9 +28,9 @@ {{ post.title }} https://blog.ipfire.org/post/{{ post.slug }} {{ post.author.email }} ({{ post.author.name }}) - {{ post.published.strftime("%a, %d %b %Y %H:%M:%S +0200") }} + {{ post.published_at.strftime("%a, %d %b %Y %H:%M:%S +0200") }} - + {% end %} diff --git a/src/templates/blog/modules/post.html b/src/templates/blog/modules/post.html index c8ab8e66..5f0bcba6 100644 --- a/src/templates/blog/modules/post.html +++ b/src/templates/blog/modules/post.html @@ -3,8 +3,8 @@

{{ _("by") }} {{ post.author.name }}, - {{ locale.format_date(post.published, shorter=True, relative=False) }} + {{ locale.format_date(post.published_at, shorter=True, relative=False) }}

- {% raw post.text %} + {% raw post.html %} diff --git a/src/web/blog.py b/src/web/blog.py index 635c224d..f297fdbb 100644 --- a/src/web/blog.py +++ b/src/web/blog.py @@ -9,7 +9,7 @@ from . import ui_modules class IndexHandler(base.BaseHandler): def get(self): - posts = self.planet.get_entries(limit=3) + posts = self.backend.blog.get_newest(limit=3) self.render("blog/index.html", posts=posts) @@ -21,7 +21,7 @@ class AuthorHandler(base.BaseHandler): raise tornado.web.HTTPError(404, "User is unknown") # Get all posts from this author - posts = self.planet.get_entries_by_author(author.uid) + posts = self.backend.blog.get_by_author(author.uid) if not posts: raise tornado.web.HTTPError(404, "User has no posts") @@ -35,7 +35,7 @@ class FeedHandler(base.BaseHandler): # Get feed from cache if possible feed = self.memcached.get(cache_key) if not feed: - posts = self.planet.get_entries(limit=50) + posts = self.backend.blog.get_newest(limit=50) # Render the feed feed = self.render_string("blog/feed.xml", posts=posts, @@ -53,18 +53,18 @@ class FeedHandler(base.BaseHandler): class PostHandler(base.BaseHandler): def get(self, slug): - entry = self.planet.get_entry_by_slug(slug) - if not entry: + post = self.backend.blog.get_by_slug(slug) + if not post: raise tornado.web.HTTPError(404) - self.render("blog/post.html", post=entry) + self.render("blog/post.html", post=post) class SearchHandler(base.BaseHandler): def get(self): q = self.get_argument("q") - posts = self.planet.search(q) + posts = self.backend.blog.search(q, limit=50) if not posts: raise tornado.web.HTTPError(404, "Nothing found") @@ -78,4 +78,4 @@ class PostModule(ui_modules.UIModule): class PostsModule(ui_modules.UIModule): def render(self, posts): - return self.render_string("blog/modules/posts.html", posts=posts) + return self.render_string("blog/modules/posts.html", posts=list(posts))