From 917434b81d8b2c3f10feb04be572a23e29e7897a Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Wed, 10 Oct 2018 14:24:32 +0100 Subject: [PATCH] talk: List active registrations Signed-off-by: Michael Tremer --- Makefile.am | 9 +++- src/backend/accounts.py | 17 ++++++- src/backend/talk.py | 48 +++++++++++++++++++ src/templates/talk/modules/registrations.html | 17 +++++++ src/templates/talk/registrations.html | 15 ++++++ src/web/__init__.py | 7 ++- src/web/talk.py | 22 +++++++++ 7 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 src/templates/talk/modules/registrations.html create mode 100644 src/templates/talk/registrations.html create mode 100644 src/web/talk.py diff --git a/Makefile.am b/Makefile.am index 5d44acd8..0e0ae04c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 = \ diff --git a/src/backend/accounts.py b/src/backend/accounts.py index dff71a7c..3a80b7b3 100644 --- a/src/backend/accounts.py +++ b/src/backend/accounts.py @@ -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 \ diff --git a/src/backend/talk.py b/src/backend/talk.py index 0d2e3b11..d9e47520 100644 --- a/src/backend/talk.py +++ b/src/backend/talk.py @@ -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 index 00000000..85e349f5 --- /dev/null +++ b/src/templates/talk/modules/registrations.html @@ -0,0 +1,17 @@ + + + {% for reg in account.sip_registrations %} + + + + + + {% end %} + +
{{ reg.user_agent }}{{ reg.protocol }}/{{ reg.network_ip }}:{{ reg.network_port }} + {% if reg.is_reachable() %} + {{ "%.2f ms" % reg.latency }} + {% else %} + {{ _("N/A") }} + {% end %} +
diff --git a/src/templates/talk/registrations.html b/src/templates/talk/registrations.html new file mode 100644 index 00000000..a0b8939b --- /dev/null +++ b/src/templates/talk/registrations.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block title %}{{ _("Registrations") }}{% end block %} + +{% block main %} +
+
+
+ {{ _("Active Registrations for %s") % current_user }} +
+ + {% module TalkRegistrations(current_user) %} +
+
+{% end block %} diff --git a/src/web/__init__.py b/src/web/__init__.py index 37a00a1a..2fb74651 100644 --- a/src/web/__init__.py +++ b/src/web/__init__.py @@ -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 index 00000000..b6a6da87 --- /dev/null +++ b/src/web/talk.py @@ -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) -- 2.39.2