From 226d267633db36597760a61f42c2dedcb688b5ae Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Thu, 21 Nov 2019 22:24:27 +0000 Subject: [PATCH] people: Show some stats Signed-off-by: Michael Tremer --- Makefile.am | 1 + src/backend/accounts.py | 28 +++++++++++++++++++++++++ src/templates/base.html | 6 ++++++ src/templates/people/stats.html | 37 +++++++++++++++++++++++++++++++++ src/web/__init__.py | 3 +++ src/web/people.py | 6 ++++++ 6 files changed, 81 insertions(+) create mode 100644 src/templates/people/stats.html diff --git a/Makefile.am b/Makefile.am index 53574dff..2705ad26 100644 --- a/Makefile.am +++ b/Makefile.am @@ -275,6 +275,7 @@ templates_people_DATA = \ src/templates/people/passwd.html \ src/templates/people/search.html \ src/templates/people/sip.html \ + src/templates/people/stats.html \ src/templates/people/subscribe.html \ src/templates/people/subscribed.html \ src/templates/people/unsubscribe.html \ diff --git a/src/backend/accounts.py b/src/backend/accounts.py index bc284bff..ff2988c1 100644 --- a/src/backend/accounts.py +++ b/src/backend/accounts.py @@ -5,6 +5,7 @@ import base64 import datetime import hashlib import hmac +import iso3166 import json import ldap import ldap.modlist @@ -164,6 +165,16 @@ class Accounts(Object): def init(self): self.search_base = self.settings.get("ldap_search_base") + def __len__(self): + count = self.memcache.get("accounts:count") + + if count is None: + count = self._count("(objectClass=person)") + + self.memcache.set("accounts:count", count, 300) + + return count + def __iter__(self): # Only return developers (group with ID 1000) accounts = self._search("(&(objectClass=posixAccount)(gidNumber=1000))") @@ -206,6 +217,11 @@ class Accounts(Object): return results + def _count(self, query): + res = self._query(query, attrlist=["dn"]) + + return len(res) + def _search(self, query, attrlist=None, limit=0): accounts = [] for dn, attrs in self._query(query, attrlist=["dn"], limit=limit): @@ -502,6 +518,18 @@ class Accounts(Object): return h.hexdigest() + @property + def countries(self): + ret = {} + + for country in iso3166.countries: + count = self._count("(&(objectClass=person)(st=%s))" % country.alpha2) + + if count: + ret[country] = count + + return ret + class Account(LDAPObject): def __str__(self): diff --git a/src/templates/base.html b/src/templates/base.html index 18ce5599..b97712a6 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -214,6 +214,12 @@ {{ _("Groups") }} + + {% end %} {% if current_user.has_sip() %} diff --git a/src/templates/people/stats.html b/src/templates/people/stats.html new file mode 100644 index 00000000..6b92d145 --- /dev/null +++ b/src/templates/people/stats.html @@ -0,0 +1,37 @@ +{% extends "../base.html" %} + +{% block title %}{{ _("Statistics") }}{% end block %} + +{% block content %} +

{{ _("Statistics") }}

+ +
+
+
+
+

{{ len(backend.accounts) }}

+
{{ _("Total Accounts") }}
+
+
+
+ +
+
+
+

{{ _("By Country") }}

+
+ +
    + {% set countries = backend.accounts.countries %} + + {% for country in sorted(countries, key=lambda c: countries[c], reverse=True) %} +
  • + {{ country.apolitical_name }} + {{ countries[country] }} +
  • + {% end %} +
+
+
+
+{% end block %} diff --git a/src/web/__init__.py b/src/web/__init__.py index 9adb39cd..6d6acf11 100644 --- a/src/web/__init__.py +++ b/src/web/__init__.py @@ -296,6 +296,9 @@ class Application(tornado.web.Application): (r"/password\-reset", auth.PasswordResetInitiationHandler), (r"/password\-reset/([a-z_][a-z0-9_-]{0,31})/(\w+)", auth.PasswordResetHandler), + # Stats + (r"/stats", people.StatsHandler), + # API (r"/api/check/uid", auth.APICheckUID), ] + authentication_handlers) diff --git a/src/web/people.py b/src/web/people.py index 1da6c275..1bd146d5 100644 --- a/src/web/people.py +++ b/src/web/people.py @@ -221,6 +221,12 @@ class SearchHandler(auth.CacheMixin, base.BaseHandler): self.render("people/search.html", q=q, accounts=accounts) +class StatsHandler(auth.CacheMixin, base.BaseHandler): + @tornado.web.authenticated + def get(self): + self.render("people/stats.html") + + class SubscribeHandler(auth.CacheMixin, base.BaseHandler): @tornado.web.authenticated def get(self): -- 2.47.3