@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):
"""
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:
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):
--- /dev/null
+{% extends "../base.html" %}
+
+{% block title %}{{ _("Groups") }}{% end block %}
+
+{% block content %}
+ <div class="row justify-content-center">
+ <div class="col col-md-8">
+ <h1>{{ _("Groups") }}</h1>
+
+ <div class="row">
+ {% for group in backend.groups %}
+ <div class="col-12 col-lg-6 mb-3">
+ <div class="card">
+ <div class="card-body">
+ <h6 class="card-title mb-0">
+ <a href="/groups/{{ group.gid }}">{{ group }}</a>
+ </h6>
+ </div>
+ </div>
+ </div>
+ {% end %}
+ </div>
+ </div>
+ </div>
+{% end block %}
(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),
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):