return sorted(users)
+ @property
+ def top(self):
+ """
+ Returns the top users (with the most builds in the last year)
+ """
+ users = self._get_users("""
+ SELECT
+ DISTINCT users.*,
+ COUNT(builds.id) AS _sort
+ FROM
+ users
+ LEFT JOIN
+ builds ON users.id = builds.owner_id
+ GROUP BY
+ users.id
+ ORDER BY
+ _sort DESC
+ LIMIT
+ 30
+ """,
+ )
+
+ return list(users)
+
class User(base.DataObject):
table = "users"
return 0
+ # Stats
+
+ @lazy_property
+ def total_builds(self):
+ res = self.db.get("""
+ SELECT
+ COUNT(*) AS builds
+ FROM
+ builds
+ WHERE
+ owner_id = %s
+ """, self.id,
+ )
+
+ if res:
+ return res.builds
+
+ return 0
+
+ @lazy_property
+ def total_build_time(self):
+ res = self.db.get("""
+ SELECT
+ SUM(jobs.finished_at - jobs.started_at) AS total_time
+ FROM
+ jobs
+ LEFT JOIN
+ builds ON jobs.build_id = builds.id
+ WHERE
+ jobs.finished_at IS NOT NULL
+ AND
+ jobs.started_at IS NOT NULL
+ AND
+ builds.owner_id = %s
+ """, self.id,
+ )
+
+ if res:
+ return res.total_time
+
# Custom repositories
@property
{% block title %}{{ _("Users") }}{% end block %}
{% block container %}
- <nav aria-label="{{ _("You are here:") }}" role="navigation">
- <ul class="breadcrumbs">
- <li>
- <a href="/">{{ _("Home") }}</a>
- </li>
- <li>
- <span class="show-for-sr">{{ _("Current") }}: </span> {{ _("Users") }}
+ <nav class="breadcrumb" aria-label="breadcrumbs">
+ <ul>
+ <li class="is-active">
+ <a href="#" aria-current="page">
+ {{ _("Users") }}
+ </a>
</li>
</ul>
</nav>
- <h1 class="text-center">{{ _("Users") }}</h1>
-
- {#
- XXX TODO
- This will need to be filled with some interesting stats like new users,
- top users, and so on...
- #}
+ <h1 class="title">{{ _("Users") }}</h1>
- <section>
+ <section class="section">
{% module UsersList(users) %}
</section>
{% end block %}
-{% for user in users %}
- <div class="callout">
- <h5 class="clearfix">
- <img class="float-right" src="{{ user.avatar(64) }}" alt="{{ user.realname }}">
+{% for rank, user in enumerate(users) %}
+ <div class="box">
+ <div class="columns">
+ <div class="column is-2 is-hidden-mobile">
+ <figure class="image is-1by1">
+ <img src="{{ user.avatar(256) }}" alt="{{ user }}" />
+ </figure>
+ </div>
- <a href="/users/{{ user.name }}">{{ user }}</a>
+ <div class="column">
+ <h5 class="title is-5">
+ <a href="/users/{{ user.name }}">{{ user }}</a>
- <small>{{ user.name }}</small>
- </h5>
+ <span class="is-pulled-right">
+ #{{ rank + 1 }}
+ </span>
+ </h6>
+ <h6 class="subtitle is-6">{{ user.name }}</h6>
+
+ <nav class="level">
+ <div class="level-left">
+ <div class="level-item has-text-centered">
+ <div>
+ <p class="heading">{{ _("Total Builds") }}</p>
+ <p class="title">{{ user.total_builds }}</p>
+ </div>
+ </div>
+
+ <div class="level-item has-text-centered">
+ <div>
+ <p class="heading">{{ _("Total Build Time") }}</p>
+ <p class="title">
+ {% if user.total_build_time %}
+ {{ format_time(user.total_build_time) }}
+ {% else %}
+ {{ _("N/A") }}
+ {% end %}
+ </p>
+ </div>
+ </div>
+ </div>
+ </nav>
+ </div>
+ </div>
</div>
{% end %}
class IndexHandler(base.BaseHandler):
def get(self):
- self.render("users/index.html", users=self.backend.users)
+ self.render("users/index.html", users=self.backend.users.top)
class ShowHandler(base.BaseHandler):