]> git.ipfire.org Git - ipfire.org.git/commitdiff
talk: List active registrations
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 10 Oct 2018 13:24:32 +0000 (14:24 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 10 Oct 2018 13:24:32 +0000 (14:24 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/backend/accounts.py
src/backend/talk.py
src/templates/talk/modules/registrations.html [new file with mode: 0644]
src/templates/talk/registrations.html [new file with mode: 0644]
src/web/__init__.py
src/web/talk.py [new file with mode: 0644]

index 5d44acd87e952612d158cbd1479d80c394ea073f..0e0ae04c048b07ebb0a77e491319429e65830092 100644 (file)
@@ -89,6 +89,7 @@ web_PYTHON = \
        src/web/handlers_nopaste.py \
        src/web/handlers_talk.py \
        src/web/location.py \
+       src/web/talk.py \
        src/web/ui_modules.py
 
 webdir = $(backenddir)/web
@@ -161,10 +162,16 @@ templates_staticdir = $(templatesdir)/static
 
 templates_talk_DATA = \
        src/templates/talk/base.html \
-       src/templates/talk/index.html
+       src/templates/talk/index.html \
+       src/templates/talk/registrations.html
 
 templates_talkdir = $(templatesdir)/talk
 
+templates_talk_modules_DATA = \
+       src/templates/talk/modules/registrations.html
+
+templates_talk_modulesdir = $(templates_talkdir)/modules
+
 # ------------------------------------------------------------------------------
 
 SCSS_FILES = \
index dff71a7c042c099f44e86ceaa1982508170e5e69..3a80b7b39b1c7c2a90ee4bb2aea742ef3396a672 100644 (file)
@@ -8,6 +8,7 @@ import logging
 import urllib.parse
 import urllib.request
 
+from .decorators import *
 from .misc import Object
 
 class Accounts(Object):
@@ -135,6 +136,9 @@ class Account(Object):
 
                self.__attrs = attrs or {}
 
+       def __str__(self):
+               return self.name
+
        def __repr__(self):
                return "<%s %s>" % (self.__class__.__name__, self.dn)
 
@@ -200,7 +204,7 @@ class Account(Object):
 
        @property
        def classes(self):
-               return self.attributes.get("objectClass", [])
+               return (x.decode() for x in self.attributes.get("objectClass", []))
 
        @property
        def uid(self):
@@ -289,6 +293,17 @@ class Account(Object):
 
                return self._is_online
 
+       @lazy_property
+       def sip_registrations(self):
+               sip_registrations = []
+
+               for reg in self.backend.talk.freeswitch.get_sip_registrations(self.sip_url):
+                       reg.account = self
+
+                       sip_registrations.append(reg)
+
+               return sip_registrations
+
        @property
        def telephone_numbers(self):
                return self._telephone_numbers + self.mobile_telephone_numbers \
index 0d2e3b11de93375c3c9ebcccd4a366083491e52a..d9e475202305cf2fcffe26d4576b098fea8df518 100644 (file)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+import ipaddress
+import logging
 import re
 
 from . import database
@@ -19,6 +21,52 @@ class Freeswitch(Object):
 
                return database.Connection(**credentials)
 
+       def get_sip_registrations(self, sip_uri):
+               logging.debug("Fetching SIP registrations for %s" % sip_uri)
+
+               user, delim, domain = sip_uri.partition("@")
+
+               res = self.db.query("SELECT * FROM sip_registrations \
+                       WHERE sip_user = %s AND sip_host = %s AND expires >= EXTRACT(epoch FROM CURRENT_TIMESTAMP) \
+                       ORDER BY contact", user, domain)
+
+               for row in res:
+                       yield SIPRegistration(self, data=row)
+
+
+class SIPRegistration(object):
+       def __init__(self, freeswitch, data):
+               self.freeswitch = freeswitch
+               self.data = data
+
+       @lazy_property
+       def protocol(self):
+               m = re.match(r"Registered\(([A-Z]+)(\-NAT)?\)", self.data.status)
+
+               if m:
+                       return m.group(1)
+
+       @property
+       def network_ip(self):
+               return ipaddress.ip_address(self.data.network_ip)
+
+       @property
+       def network_port(self):
+               return self.data.network_port
+
+       @property
+       def user_agent(self):
+               return self.data.user_agent
+
+       def is_reachable(self):
+               return self.data.ping_status == "Reachable"
+
+       @lazy_property
+       def latency(self):
+               if self.is_reachable():
+                       return self.data.ping_time / 1000.0
+
+
 
 class Talk(Object):
        def init(self):
diff --git a/src/templates/talk/modules/registrations.html b/src/templates/talk/modules/registrations.html
new file mode 100644 (file)
index 0000000..85e349f
--- /dev/null
@@ -0,0 +1,17 @@
+<table class="table table-sm mb-0">
+       <tbody>
+               {% for reg in account.sip_registrations %}
+                       <tr>
+                               <td>{{ reg.user_agent }}</td>
+                               <td>{{ reg.protocol }}/{{ reg.network_ip }}:{{ reg.network_port }}</td>
+                               <td class="text-right">
+                                       {% if reg.is_reachable() %}
+                                               {{ "%.2f ms" % reg.latency }}
+                                       {% else %}
+                                               <span class="text-muted">{{ _("N/A") }}</span>
+                                       {% end %}
+                               </td>
+                       </tr>
+               {% end %}
+       </tbody>
+</table>
diff --git a/src/templates/talk/registrations.html b/src/templates/talk/registrations.html
new file mode 100644 (file)
index 0000000..a0b8939
--- /dev/null
@@ -0,0 +1,15 @@
+{% extends "base.html" %}
+
+{% block title %}{{ _("Registrations") }}{% end block %}
+
+{% block main %}
+    <div class="card">
+        <div class="card-body">
+            <h6 class="card-title">
+                {{ _("Active Registrations for %s") % current_user }}
+            </h6>
+
+            {% module TalkRegistrations(current_user) %}
+        </div>
+    </div>
+{% end block %}
index 37a00a1a4824b0ad9f33a5f0c5387e1815b66b3a..2fb746512a50b86f2368445d8230d41618bf133e 100644 (file)
@@ -14,6 +14,7 @@ from . import auth
 from . import blog
 from . import download
 from . import location
+from . import talk
 from . import ui_modules
 
 class Application(tornado.web.Application):
@@ -51,6 +52,9 @@ class Application(tornado.web.Application):
                                # Location
                                "Map"                  : ui_modules.MapModule,
 
+                               # Talk
+                               "TalkRegistrations"    : talk.RegistrationsModule,
+
                                # Old modules
                                "LanguageName"         : ui_modules.LanguageNameModule,
 
@@ -234,7 +238,8 @@ class Application(tornado.web.Application):
 
                # talk.ipfire.org
                self.add_handlers(r"talk(\.dev)?\.ipfire\.org", [
-                       (r"/", TalkIndexHandler),
+                       (r"/", talk.IndexHandler),
+                       (r"/registrations", talk.RegistrationsHandler),
                        (r"/conferences", TalkConferencesHandler),
                        (r"/diagnosis", TalkDiagnosisHandler),
                        (r"/hangup/(.*)", TalkHangupChannelHandler),
diff --git a/src/web/talk.py b/src/web/talk.py
new file mode 100644 (file)
index 0000000..b6a6da8
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+
+import tornado.web
+
+from . import handlers_base as base
+from . import ui_modules
+
+class IndexHandler(base.BaseHandler):
+       @tornado.web.authenticated
+       def get(self):
+               self.render("talk/index.html")
+
+
+class RegistrationsHandler(base.BaseHandler):
+       @tornado.web.authenticated
+       def get(self):
+               self.render("talk/registrations.html")
+
+
+class RegistrationsModule(ui_modules.UIModule):
+       def render(self, account):
+               return self.render_string("talk/modules/registrations.html", account=account)