self.data = data
+ def __cmp__(self, other):
+ return cmp(self.published, other.published)
+
@property
def id(self):
return self.data.id
@property
def author(self):
- if not hasattr(self, "__author"):
- self.__author = self.accounts.search(self.data.author_id)
+ if not hasattr(self, "_author"):
+ self._author = self.accounts.get_by_uid(self.data.author_id)
- return self.__author
+ return self._author
def set_status(self, status):
if self.status == status:
def is_published(self):
return self.status == "published"
- # Tags
-
- def get_tags(self):
- if not hasattr(self, "__tags"):
- res = self.db.query("SELECT tag FROM planet_tags \
- WHERE post_id = %s ORDER BY tag", self.id)
- self.__tags = []
- for row in res:
- self.__tags.append(row.tag)
-
- return self.__tags
+ def count_view(self, referer=None, location=None):
+ self.db.execute("INSERT INTO planet_views(post_id, referer, location) \
+ VALUES(%s, %s, %s)", self.id, referer, location)
- def set_tags(self, tags):
- # Delete all existing tags.
- self.db.execute("DELETE FROM planet_tags WHERE post_id = %s", self.id)
+ if hasattr(self, "_views"):
+ self._views += 1
- self.db.executemany("INSERT INTO planet_tags(post_id, tag) VALUES(%s, %s)",
- ((self.id, tag) for tag in tags))
+ @property
+ def views(self):
+ if not hasattr(self, "_views"):
+ res = self.db.get("SELECT COUNT(*) AS views FROM planet_views \
+ WHERE post_id = %s", self.id)
- # Update cache.
- self.__tags = tags
- self.__tags.sort()
+ self._views = res.views
- tags = property(get_tags, set_tags)
+ return self._views
class Planet(Object):
clauses.append("status = %s")
args.append(status)
+ if status == "published":
+ clauses.append("published <= NOW()")
+
if author_id:
clauses.append("author_id = %s")
args.append(author_id)
return [PlanetEntry(self.backend, e) for e in entries]
+ def get_hot_entries(self, days=30, limit=8):
+ entries = self.db.query("WITH hottest AS (SELECT post_id, COUNT(post_id) AS count \
+ FROM planet_views WHERE \"when\" >= NOW() - INTERVAL '%s days' \
+ GROUP BY post_id ORDER BY count DESC) SELECT * FROM planet \
+ LEFT JOIN hottest ON planet.id = hottest.post_id \
+ WHERE hottest.count IS NOT NULL \
+ ORDER BY hottest.count DESC LIMIT %s",
+ days, limit)
+
+ return [PlanetEntry(self.backend, e) for e in entries]
+
def render(self, text, limit=0):
if limit and len(text) >= limit:
text = text[:limit] + "..."
return slug
- def create(self, title, markdown, author, status="published", tags=None, published=None):
+ def create(self, title, markdown, author, status="published", published=None):
slug = self._generate_slug(title)
markup = self.render(markdown)
published = datetime.datetime.utcnow()
id = self.db.execute("INSERT INTO planet(author_id, slug, title, status, \
- markdown, markup, published) VALUES(%s, %s, %s, %s, %s, %s, %s)",
+ markdown, markup, published) VALUES(%s, %s, %s, %s, %s, %s, %s) RETURNING id",
author.uid, slug, title, status, markdown, markup, published)
- entry = self.get_entry_by_id(id)
-
- if tags:
- entry.tags = tags
-
- return entry
+ if id:
+ return self.get_entry_by_id(id)
def update_entry(self, entry):
self.db.execute("UPDATE planet SET title = %s, markdown = %s WHERE id = %s",
return id
def search(self, what):
- # Split tags.
- tags = what.split()
-
- query = "SELECT planet.* FROM planet INNER JOIN ( \
- SELECT post_id FROM planet_tags \
- INNER JOIN planet ON planet_tags.post_id = planet.id \
- WHERE %s GROUP BY post_id HAVING COUNT(post_id) = %%s \
- ) pt ON planet.id = pt.post_id ORDER BY published DESC"
-
- args = (tags, len(tags))
-
- clauses, args = [], tags
- for tag in tags:
- clauses.append("planet_tags.tag = %s")
- args.append(len(tags))
-
- entries = self.db.query(query % " OR ".join(clauses), *args)
- return [PlanetEntry(self.backend, e) for e in entries]
-
- def search_autocomplete(self, what):
- tags = what.split()
- last_tag = tags.pop()
-
- res = self.db.query("SELECT tag, COUNT(tag) AS count FROM planet_tags \
- WHERE tag LIKE %s GROUP BY tag ORDER BY count DESC", "%s%%" % last_tag)
-
- if tags:
- return ["%s %s" % (" ".join(tags), row.tag) for row in res]
-
- return [row.tag for row in res]
+ res = self.db.query("WITH \
+ q AS (SELECT plainto_tsquery(%s, %s) AS query), \
+ ranked AS (SELECT id, query, ts_rank_cd(to_tsvector(%s, markdown), query) AS rank \
+ FROM planet, q WHERE markdown @@ query ORDER BY rank DESC) \
+ SELECT *, ts_headline(markup, ranked.query, 'MinWords=100, MaxWords=110') AS markup FROM planet \
+ JOIN ranked ON planet.id = ranked.id \
+ WHERE status = %s AND published IS NOT NULL AND published <= NOW() \
+ ORDER BY ranked DESC LIMIT 25",
+ "english", what, "english", "published")
+
+ return [PlanetEntry(self.backend, e) for e in res]