<li>
<a href="/statistics">{{ _("Statistics") }}</a>
</li>
+ {% elif hostname == "planet.ipfire.org" %}
+ <li>
+ <a href="/hottest">{{ _("Hottest posts") }}</a>
+ </li>
{% elif hostname == "talk.ipfire.org" and current_user %}
<li>
<a href="/phonebook">{{ _("Phonebook") }}</a>
<h2>
<a href="/post/{{ entry.slug }}">{{ entry.title }}</a>
+
+ <br>
+
+ <small>
+ {{ _("by") }} <a href="/user/{{ entry.author.uid }}">{{ entry.author.name }}</a>,
+ {{ locale.format_date(entry.published, shorter=True) }}
+ </small>
</h2>
{% raw entry.text %}
-<p class="pull-right clear">
- {{ _("Posted by") }} <a href="/user/{{ entry.author.uid }}">{{ entry.author.name }}</a>
- {{ _("on") }} {{ locale.format_date(entry.published, shorter=True) }}
-</p>
-
<hr class="separator clear">
--- /dev/null
+{% extends "base.html" %}
+
+{% block title %}{{ _("Hottest posts") }}{% end block %}
+
+{% block body %}
+ <div class="row">
+ <div class="col-md-8 col-md-offset-2">
+ <h3>{{ _("The hottest posts of the last month") }}</h3>
+
+ <dl>
+ {% for entry in entries %}
+ <dt><a href="/post/{{ entry.slug }}">{{ entry.title }}</a></dt>
+ <dd>
+ {{ _("by") }} <a href="/user/{{ entry.author.uid }}">{{ entry.author.name }}</a>
+ <span class="pull-right">{{ locale.format_date(entry.published, relative=True, shorter=True) }}</span>
+ </dd>
+
+ <br>
+ {% end %}
+ </dl>
+ </div>
+ </div>
+{% end block %}
--- /dev/null
+<div class="well pull-right ac" style="margin-left: 1em;">
+ <img class="img-thumbnail" src="{{ author.gravatar_icon(213) }}" alt="{{ author.name }}" />
+
+ <h3>
+ <a href="/user/{{ author.uid }}">{{ author.name }}</a>
+ </h3>
+
+ <br>
+
+ <ul class="list-inline">
+ <li>
+ <a href="mailto:{{ author.email }}" title="{{ _("Write an email") }}">
+ <i class="glyphicon glyphicon-envelope"></i>
+ </a>
+ </li>
+
+ {% if author.is_talk_enabled() %}
+ <li>
+ <a href="http://talk.ipfire.org/phonebook/{{ author.uid }}"
+ title="{{ _("%s on talk.ipfire.org") % author.name }}">
+ <i class="glyphicon glyphicon-earphone"></i>
+ </a>
+ </li>
+ {% end %}
+ </ul>
+</div>
-{% extends "user.html" %}
+{% extends "../base.html" %}
-{% block title %}{{ _("IPFire Planet") }} - {{ entry.title }}{% end block %}
+{% block title %}{{ entry.title }}{% end block %}
-{% block bodyA %}
+{% block body %}
<div class="page-header">
<h1>
<a href="/post/{{ entry.slug }}">{{ entry.title }}</a>
+
+ <br>
+
+ <small>
+ {{ _("by") }} <a href="/user/{{ entry.author.uid }}">{{ entry.author.name }}</a>,
+ {{ locale.format_date(entry.published, shorter=True) }}
+ </small>
</h1>
</div>
</div>
{% end %}
- {% raw entry.text %}
+ {% module PlanetAuthorBox(entry.author) %}
- <p class="clear pull-right">
- {{ _("Posted by") }} <a href="/user/{{ entry.author.uid }}">{{ entry.author.name }}</a>
- {{ _("on") }} {{ locale.format_date(entry.published, shorter=True) }}
- </p>
+ {% raw entry.text %}
{% end block %}
-{% extends "base.html" %}
+{% extends "../base.html" %}
{% block title %}{{ _("IPFire Planet") }} - {{ author.name }}{% end block %}
</div>
<div class="col-lg-3 col-md-3">
- <div class="well">
- <img class="img-thumbnail" src="{{ author.gravatar_icon(213) }}" alt="{{ author.name }}" />
-
- <hr>
-
- <i class="glyphicon glyphicon-user"></i>
- <a href="/user/{{ author.uid }}">
- {{ author.name }}
- </a>
-
- <hr>
-
- <i class="glyphicon glyphicon-envelope"></i>
- <a href="mailto:{{ author.email }}">
- {{ _("Mail") }}
- </a>
- </div>
+ {% module PlanetAuthorBox(entry.author) %}
</div>
</div>
{% end block %}
"NewsLine" : NewsLineModule,
"NewsTable" : NewsTableModule,
"NewsYearNavigation" : NewsYearNavigationModule,
+ "PlanetAuthorBox" : PlanetAuthorBoxModule,
"PlanetEntry" : PlanetEntryModule,
"PlanetSearchBox" : PlanetSearchBoxModule,
"ProgressBar" : ProgressBarModule,
# planet.ipfire.org
self.add_handlers(r"planet(\.dev)?\.ipfire\.org", [
(r"/", PlanetMainHandler),
+ (r"/hottest", PlanetHotEntriesHandler),
(r"/post/([A-Za-z0-9_-]+)", PlanetPostingHandler),
(r"/user/([a-z0-9_-]+)", PlanetUserHandler),
(r"/search", PlanetSearchHandler),
def is_published(self):
return self.status == "published"
- def increase_view_counter(self):
- self.db.execute("UPDATE planet SET views = views + 1 WHERE id = %s", self.id)
+ 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)
class Planet(Object):
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] + "..."
self.render("planet/index.html", entries=entries, offset=offset + limit, limit=limit)
+class PlanetHotEntriesHandler(PlanetBaseHandler):
+ def get(self):
+ days = self.get_argument("days", None)
+ try:
+ days = int(days)
+ except (TypeError, ValueError):
+ days = 30
+
+ entries = self.planet.get_hot_entries(days, limit=25)
+
+ self.render("planet/hottest.html", entries=entries)
+
+
class PlanetUserHandler(PlanetBaseHandler):
def get(self, author):
author = self.accounts.get_by_uid(author)
class PlanetPostingHandler(PlanetBaseHandler):
def get(self, slug):
- entry = self.planet.get_entry_by_slug(slug)
+ self.entry = self.planet.get_entry_by_slug(slug)
- if not entry:
+ if not self.entry:
raise tornado.web.HTTPError(404)
- # Update the view counter
- entry.increase_view_counter()
-
self.render("planet/posting.html",
- author=entry.author, entry=entry)
+ author=self.entry.author, entry=self.entry)
+
+ def on_finish(self):
+ assert self.entry
+
+ # Get the referer and location for statistical purposes
+ referer = self.request.headers.get("Referer", None)
+ location = self.get_remote_location()
+ if location:
+ location = location.country
+
+ self.entry.count_view(referer=referer, location=location)
class PlanetSearchHandler(PlanetBaseHandler):
release=release, image=best_image)
+class PlanetAuthorBoxModule(UIModule):
+ def render(self, author):
+ return self.render_string("planet/modules/author-box.html", author=author)
+
+
class PlanetEntryModule(UIModule):
def render(self, entry, show_avatar=True):
return self.render_string("modules/planet-entry.html",