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
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 = \
import urllib.parse
import urllib.request
+from .decorators import *
from .misc import Object
class Accounts(Object):
self.__attrs = attrs or {}
+ def __str__(self):
+ return self.name
+
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, self.dn)
@property
def classes(self):
- return self.attributes.get("objectClass", [])
+ return (x.decode() for x in self.attributes.get("objectClass", []))
@property
def uid(self):
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 \
#!/usr/bin/python
+import ipaddress
+import logging
import re
from . import database
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):
--- /dev/null
+<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>
--- /dev/null
+{% 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 %}
from . import blog
from . import download
from . import location
+from . import talk
from . import ui_modules
class Application(tornado.web.Application):
# Location
"Map" : ui_modules.MapModule,
+ # Talk
+ "TalkRegistrations" : talk.RegistrationsModule,
+
# Old modules
"LanguageName" : ui_modules.LanguageNameModule,
# 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),
--- /dev/null
+#!/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)