]> git.ipfire.org Git - ipfire.org.git/commitdiff
talk: Add a search
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 10 Oct 2018 18:03:44 +0000 (19:03 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 10 Oct 2018 18:03:44 +0000 (19:03 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/backend/accounts.py
src/backend/talk.py
src/templates/talk/search.html [new file with mode: 0644]
src/web/__init__.py
src/web/talk.py

index 01383c9bb448b1b54ce6f1362891fe7e4892d44b..3c5a1a7e17a777e8c70088011a22d081166b0356 100644 (file)
@@ -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
 
index faede4e31f10625746bb1e88ef8a4c9a34a1d91c..0151fb71edf8b769d13a9943bf8e5b0c3c1e1ea1 100644 (file)
@@ -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):
index 7f078a01d213cbfa5acac98ef05eb7f61d5ceb79..636261968a2ae5c3a5d5f8701e683a966720ce92 100644 (file)
@@ -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 (file)
index 0000000..91b2e39
--- /dev/null
@@ -0,0 +1,15 @@
+{% extends "base.html" %}
+
+{% block title %}{{ _("Search Results for \"%s\"") % q }}{% end block %}
+
+{% block main %}
+       <h3 class="mb-4">{{ _("Search Results for \"%s\"") % q }}</h3>
+
+       {% if accounts %}
+               {% module TalkAccountsList(accounts) %}
+       {% else %}
+               <p class="text-muted text-center my-5">
+                       {{ _("There are no results for \"%s\"") % q }}
+               </p>
+       {% end %}
+{% end block %}
index 133edefd34598d651c35f7da35c519edc786866e..1ed253978978efe99d8dd102f8607ae1d10ea7ff 100644 (file)
@@ -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),
index 7ab6f946b7d6ad968820009eca2a49f95222f834..fb9f3d87fbd8a2fe2c9a3eb4a4e7af9936e3272d 100644 (file)
@@ -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):