From 18b13823a19817386785b7c2543f388a03e44cfb Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Tue, 29 Oct 2019 10:32:50 +0000 Subject: [PATCH] people: Add group listing page Signed-off-by: Michael Tremer --- Makefile.am | 1 + src/backend/accounts.py | 82 ++++++++++++++++---------------- src/templates/people/groups.html | 25 ++++++++++ src/web/__init__.py | 1 + src/web/people.py | 10 ++++ 5 files changed, 77 insertions(+), 42 deletions(-) create mode 100644 src/templates/people/groups.html diff --git a/Makefile.am b/Makefile.am index 53e41d96..1ca3799b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -229,6 +229,7 @@ templates_people_DATA = \ src/templates/people/conferences.html \ src/templates/people/call.html \ src/templates/people/calls.html \ + src/templates/people/groups.html \ src/templates/people/index.html \ src/templates/people/passwd.html \ src/templates/people/search.html \ diff --git a/src/backend/accounts.py b/src/backend/accounts.py index 44952a34..306b50a5 100644 --- a/src/backend/accounts.py +++ b/src/backend/accounts.py @@ -681,30 +681,10 @@ class Account(Object): @lazy_property def groups(self): - groups = self.memcache.get("accounts:%s:groups" % self.dn) - if not groups: - # Fetch groups from LDAP - groups = self._get_groups() - - # Cache groups for 5 min - self.memcache.set("accounts:%s:groups" % self.dn, groups, 300) - - return sorted((Group(self.backend, gid) for gid in groups)) - - def _get_groups(self): - groups = [] - - res = self.accounts._query("(| \ + return self.backend.groups._get_groups("(| \ (&(objectClass=groupOfNames)(member=%s)) \ (&(objectClass=posixGroup)(memberUid=%s)) \ - )" % (self.dn, self.uid), ["cn"]) - - for dn, attrs in res: - cns = attrs.get("cn") - if cns: - groups.append(cns[0].decode()) - - return groups + )" % (self.dn, self.uid)) def is_member_of_group(self, gid): """ @@ -1088,16 +1068,44 @@ class StopForumSpam(Object): return 100 - min(confidences) - class Groups(Object): @property def search_base(self): return "ou=Group,%s" % self.backend.accounts.search_base + def _query(self, *args, **kwargs): + kwargs.update({ + "search_base" : self.backend.groups.search_base, + }) + + return self.backend.accounts._query(*args, **kwargs) + + def __iter__(self): + groups = self.get_all() + + return iter(groups) + + def _get_groups(self, query, **kwargs): + res = self._query(query, **kwargs) + + groups = [] + for dn, attrs in res: + g = Group(self.backend, dn, attrs) + groups.append(g) + + return sorted(groups) + + def get_all(self): + return self._get_groups( + "(|(objectClass=posixGroup)(objectClass=groupOfNames))", + ) + class Group(Object): - def init(self, gid): - self.gid = gid + def init(self, dn, attrs=None): + self.dn = dn + + self.attributes = attrs or {} def __repr__(self): if self.description: @@ -1120,24 +1128,14 @@ class Group(Object): if isinstance(other, self.__class__): return (self.description or self.gid) < (other.description or other.gid) - @lazy_property - def attributes(self): - attrs = self.memcache.get("groups:%s:attrs" % self.gid) - if not attrs: - attrs = self._get_attrs() - - # Cache this for 5 mins - self.memcache.set("groups:%s:attrs" % self.gid, attrs, 300) - - return attrs - - def _get_attrs(self): - res = self.backend.accounts._query( - "(&(|(objectClass=posixGroup)(objectClass=groupOfNames))(cn=%s))" % self.gid, - search_base=self.backend.groups.search_base, limit=1) + @property + def gid(self): + try: + gid = self.attributes["cn"][0] + except KeyError: + return None - for dn, attrs in res: - return attrs + return gid.decode() @property def description(self): diff --git a/src/templates/people/groups.html b/src/templates/people/groups.html new file mode 100644 index 00000000..64cdf97e --- /dev/null +++ b/src/templates/people/groups.html @@ -0,0 +1,25 @@ +{% extends "../base.html" %} + +{% block title %}{{ _("Groups") }}{% end block %} + +{% block content %} +
+
+

{{ _("Groups") }}

+ +
+ {% for group in backend.groups %} +
+
+
+
+ {{ group }} +
+
+
+
+ {% end %} +
+
+
+{% end block %} diff --git a/src/web/__init__.py b/src/web/__init__.py index 1db3b03b..072856f8 100644 --- a/src/web/__init__.py +++ b/src/web/__init__.py @@ -270,6 +270,7 @@ class Application(tornado.web.Application): (r"/", people.IndexHandler), (r"/activate/(\w+)/(\w+)", auth.ActivateHandler), (r"/conferences", people.ConferencesHandler), + (r"/groups", people.GroupsHandler), (r"/register", auth.RegisterHandler), (r"/search", people.SearchHandler), (r"/users", people.UsersHandler), diff --git a/src/web/people.py b/src/web/people.py index 8ed5f044..2d265cfa 100644 --- a/src/web/people.py +++ b/src/web/people.py @@ -113,6 +113,16 @@ class ConferencesHandler(auth.CacheMixin, base.BaseHandler): self.render("people/conferences.html", conferences=self.backend.talk.conferences) +class GroupsHandler(auth.CacheMixin, base.BaseHandler): + @tornado.web.authenticated + def get(self): + # Only staff can see other groups + if not self.current_user.is_staff(): + raise tornado.web.HTTPError(403) + + self.render("people/groups.html") + + class SearchHandler(auth.CacheMixin, base.BaseHandler): @tornado.web.authenticated def get(self): -- 2.47.3