From 1bae74c7b1bc328a07ecc487a2d93470e7811e18 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Wed, 10 Oct 2018 19:03:44 +0100 Subject: [PATCH] talk: Add a search Signed-off-by: Michael Tremer --- Makefile.am | 1 + src/backend/accounts.py | 56 +++++++++++++++++++++------------- src/backend/talk.py | 11 +++++++ src/templates/talk/search.html | 15 +++++++++ src/web/__init__.py | 1 + src/web/talk.py | 16 ++++++++++ 6 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 src/templates/talk/search.html diff --git a/Makefile.am b/Makefile.am index 01383c9b..3c5a1a7e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -164,6 +164,7 @@ templates_talk_DATA = \ src/templates/talk/base.html \ src/templates/talk/index.html \ src/templates/talk/registrations.html \ + src/templates/talk/search.html \ src/templates/talk/user.html \ src/templates/talk/users.html diff --git a/src/backend/accounts.py b/src/backend/accounts.py index faede4e3..0151fb71 100644 --- a/src/backend/accounts.py +++ b/src/backend/accounts.py @@ -14,9 +14,9 @@ from .misc import Object class Accounts(Object): def __iter__(self): # Only return developers (group with ID 1000) - accounts = self.search("(&(objectClass=posixAccount)(gidNumber=1000))") + accounts = self._search("(&(objectClass=posixAccount)(gidNumber=1000))") - return iter(accounts) + return iter(sorted(accounts)) @property def ldap(self): @@ -33,7 +33,7 @@ class Accounts(Object): return self._ldap - def _search(self, query, attrlist=None, limit=0): + def _query(self, query, attrlist=None, limit=0): logging.debug("Performing LDAP query: %s" % query) search_base = self.settings.get("ldap_search_base") @@ -49,28 +49,41 @@ class Accounts(Object): return results - def search(self, query, limit=0): - results = self._search(query, limit=limit) - + def _search(self, query, attrlist=None, limit=0): accounts = [] - for dn, attrs in results: + + for dn, attrs in self._query(query, attrlist=attrlist, limit=limit): account = Account(self.backend, dn, attrs) accounts.append(account) + return accounts + + def search(self, query): + # Search for exact matches + accounts = self._search("(&(objectClass=posixAccount) \ + (|(uid=%s)(mail=%s)(sipAuthenticationUser=%s)(telephoneNumber=%s)(homePhone=%s)(mobile=%s)))" \ + % (query, query, query, query, query, query)) + + # Find accounts by name + if not accounts: + for account in self._search("(&(objectClass=posixAccount)(cn=*%s*))" % query): + if not account in accounts: + accounts.append(account) + return sorted(accounts) - def search_one(self, query): - result = self.search(query, limit=1) + def _search_one(self, query): + result = self._search(query, limit=1) assert len(result) <= 1 if result: return result[0] def get_by_uid(self, uid): - return self.search_one("(&(objectClass=posixAccount)(uid=%s))" % uid) + return self._search_one("(&(objectClass=posixAccount)(uid=%s))" % uid) def get_by_mail(self, mail): - return self.search_one("(&(objectClass=posixAccount)(mail=%s))" % mail) + return self._search_one("(&(objectClass=posixAccount)(mail=%s))" % mail) find = get_by_uid @@ -82,7 +95,7 @@ class Accounts(Object): return self.get_by_mail(s) def get_by_sip_id(self, sip_id): - return self.search_one("(|(&(objectClass=sipUser)(sipAuthenticationUser=%s)) \ + return self._search_one("(|(&(objectClass=sipUser)(sipAuthenticationUser=%s)) \ (&(objectClass=sipRoutingObject)(sipLocalAddress=%s)))" % (sip_id, sip_id)) # Session stuff @@ -218,20 +231,19 @@ class Account(Object): def first_name(self): return self._get_first_attribute("givenName") - @property + @lazy_property def groups(self): - if not hasattr(self, "_groups"): - self._groups = [] + groups = [] - res = self.accounts._search("(&(objectClass=posixGroup) \ - (memberUid=%s))" % self.uid, ["cn"]) + res = self.accounts._query("(&(objectClass=posixGroup) \ + (memberUid=%s))" % self.uid, ["cn"]) - for dn, attrs in res: - cns = attrs.get("cn") - if cns: - self._groups.append(cns[0].decode()) + for dn, attrs in res: + cns = attrs.get("cn") + if cns: + groups.append(cns[0].decode()) - return self._groups + return groups @property def address(self): diff --git a/src/backend/talk.py b/src/backend/talk.py index 7f078a01..63626196 100644 --- a/src/backend/talk.py +++ b/src/backend/talk.py @@ -171,6 +171,17 @@ class Talk(Object): yield account + def search(self, query): + accounts = [] + + for account in self.backend.accounts.search(query): + if not account.is_talk_enabled(): + continue + + accounts.append(account) + + return accounts + def get_lines(self, account=None): accounts_cache = {} diff --git a/src/templates/talk/search.html b/src/templates/talk/search.html new file mode 100644 index 00000000..91b2e395 --- /dev/null +++ b/src/templates/talk/search.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block title %}{{ _("Search Results for \"%s\"") % q }}{% end block %} + +{% block main %} +

{{ _("Search Results for \"%s\"") % q }}

+ + {% if accounts %} + {% module TalkAccountsList(accounts) %} + {% else %} +

+ {{ _("There are no results for \"%s\"") % q }} +

+ {% end %} +{% end block %} diff --git a/src/web/__init__.py b/src/web/__init__.py index 133edefd..1ed25397 100644 --- a/src/web/__init__.py +++ b/src/web/__init__.py @@ -239,6 +239,7 @@ class Application(tornado.web.Application): # talk.ipfire.org self.add_handlers(r"talk(\.dev)?\.ipfire\.org", [ (r"/", talk.IndexHandler), + (r"/search", talk.SearchHandler), (r"/users", talk.UsersHandler), (r"/users/(\w+)", talk.UserHandler), (r"/users/(\w+)/registrations", talk.RegistrationsHandler), diff --git a/src/web/talk.py b/src/web/talk.py index 7ab6f946..fb9f3d87 100644 --- a/src/web/talk.py +++ b/src/web/talk.py @@ -31,6 +31,22 @@ class RegistrationsHandler(base.BaseHandler): self.render("talk/registrations.html", account=account) +class SearchHandler(base.BaseHandler): + @tornado.web.authenticated + def get(self): + q = self.get_argument("q") + + # Perform the search + accounts = self.backend.talk.search(q) + + # Redirect when only one result was found + if len(accounts) == 1: + self.redirect("/users/%s" % accounts[0].uid) + return + + self.render("talk/search.html", q=q, accounts=accounts) + + class UsersHandler(base.BaseHandler): @tornado.web.authenticated def get(self): -- 2.47.3