From 9f05796cd29060d83ce632612464a78412c59322 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Wed, 10 Oct 2018 15:49:53 +0100 Subject: [PATCH] talk: Show active channels Signed-off-by: Michael Tremer --- Makefile.am | 1 + src/backend/accounts.py | 12 +-- src/backend/talk.py | 112 +++++++++++++++++------ src/templates/talk/index.html | 2 +- src/templates/talk/modules/channels.html | 52 +++++++++++ src/web/__init__.py | 1 + src/web/talk.py | 7 ++ 7 files changed, 150 insertions(+), 37 deletions(-) create mode 100644 src/templates/talk/modules/channels.html diff --git a/Makefile.am b/Makefile.am index 0e0ae04c..aafa6324 100644 --- a/Makefile.am +++ b/Makefile.am @@ -168,6 +168,7 @@ templates_talk_DATA = \ templates_talkdir = $(templatesdir)/talk templates_talk_modules_DATA = \ + src/templates/talk/modules/channels.html \ src/templates/talk/modules/registrations.html templates_talk_modulesdir = $(templates_talkdir)/modules diff --git a/src/backend/accounts.py b/src/backend/accounts.py index 7e6e4431..faede4e3 100644 --- a/src/backend/accounts.py +++ b/src/backend/accounts.py @@ -12,6 +12,12 @@ from .decorators import * from .misc import Object class Accounts(Object): + def __iter__(self): + # Only return developers (group with ID 1000) + accounts = self.search("(&(objectClass=posixAccount)(gidNumber=1000))") + + return iter(accounts) + @property def ldap(self): if not hasattr(self, "_ldap"): @@ -60,12 +66,6 @@ class Accounts(Object): if result: return result[0] - def get_all(self): - # Only return developers (group with ID 1000) - return self.search("(&(objectClass=posixAccount)(gidNumber=1000))") - - list = get_all - def get_by_uid(self, uid): return self.search_one("(&(objectClass=posixAccount)(uid=%s))" % uid) diff --git a/src/backend/talk.py b/src/backend/talk.py index 9b7d2f62..53ec4106 100644 --- a/src/backend/talk.py +++ b/src/backend/talk.py @@ -3,6 +3,7 @@ import ipaddress import logging import re +import time from . import database @@ -33,6 +34,15 @@ class Freeswitch(Object): for row in res: yield SIPRegistration(self, data=row) + def get_sip_channels(self, account): + res = self.db.query("SELECT * FROM channels \ + WHERE (direction = %s AND cid_num = %s) OR \ + (direction = %s AND callee_num = %s) ORDER BY created_epoch", + "inbound", account.sip_id, "outbound", account.sip_id) + + for row in res: + yield Channel(self, data=row) + class SIPRegistration(object): def __init__(self, freeswitch, data): @@ -67,33 +77,86 @@ class SIPRegistration(object): return self.data.ping_time / 1000.0 +class Channel(object): + def __init__(self, freeswitch, data): + self.freeswitch = freeswitch + self.data = data -class Talk(Object): - def init(self): - # Connect to FreeSWITCH - self.freeswitch = Freeswitch(self.backend) + @property + def backend(self): + return self.freeswitch.backend - def get_phonebook(self, account=None): - accounts = [] - for a in self.accounts.list(): - if account and a == account: - continue + @property + def uuid(self): + return self.data.uuid - if not a.is_talk_enabled(): - continue + @property + def direction(self): + return self.data.direction + + @lazy_property + def caller(self): + return self.backend.accounts.get_by_sip_id(self.caller_number) + + @property + def caller_name(self): + return self.data.cid_name + + @property + def caller_number(self): + return self.data.cid_num + + @lazy_property + def callee(self): + return self.backend.accounts.get_by_sip_id(self.callee_number) - accounts.append(a) + @property + def callee_name(self): + return self.data.callee_name + + @property + def callee_number(self): + return self.data.callee_num + + @property + def called_number(self): + return self.data.dest + + @property + def application(self): + return self.data.application - return accounts + @property + def application_data(self): + return self.data.application_data - def user_is_online(self, sip_id): - res = self.db.get("SELECT 1 FROM location WHERE username = %s \ - AND expires >= NOW() LIMIT 1", sip_id) + @property + def duration(self): + return time.time() - self.data.created_epoch - if res: - return True + @property + def codec(self): + # We always assume a symmetric codec + s = [ + "%s @ %s kHz" % (self.data.write_codec, int(self.data.write_rate) / 1000.0), + ] + + if self.data.write_bit_rate == "0": + s.append("VBR") + else: + s.append("%.0f kBit/s" % (int(self.data.write_bit_rate) / 1000.0)) - return False + return " ".join(s) + + @property + def secure(self): + return self.data.secure + + +class Talk(Object): + def init(self): + # Connect to FreeSWITCH + self.freeswitch = Freeswitch(self.backend) def get_lines(self, account=None): accounts_cache = {} @@ -230,17 +293,6 @@ class Talk(Object): return self._process_cdr(res, replace_sip_uris=True) - # Favourites - - def get_favourite_contacts(self, account, limit=6): - res = self.db.query("SELECT src_user AS caller, dst_ouser AS called, \ - COUNT(*) AS count FROM acc WHERE method = %s AND src_user = %s AND \ - dst_ouser BETWEEN %s AND %s AND time >= NOW() - INTERVAL '1 year' \ - GROUP BY caller, called ORDER BY count DESC LIMIT %s", - "INVITE", account.sip_id, "1000", "1999", limit) - - return self._process_cdr(res) - # Conferences @property diff --git a/src/templates/talk/index.html b/src/templates/talk/index.html index 669cb857..268f9c7a 100644 --- a/src/templates/talk/index.html +++ b/src/templates/talk/index.html @@ -3,5 +3,5 @@ {% block title %}{{ _("Home") }}{% end block %} {% block main %} - XXX + {% module TalkChannels(current_user) %} {% end block %} diff --git a/src/templates/talk/modules/channels.html b/src/templates/talk/modules/channels.html new file mode 100644 index 00000000..336c4298 --- /dev/null +++ b/src/templates/talk/modules/channels.html @@ -0,0 +1,52 @@ +{% if channels %} +
+
+ + + {% for chan in channels %} + + + + + + {% end %} + +
+ {{ chan.direction }} + + {% if chan.direction == "inbound" %} + {% if chan.application == "conference" %} + CONFERENCE + + {% else %} + {% if chan.callee %} + {{ chan.callee }} + {% else %} + {{ chan.callee_name }} + {% end %} + + ({{ chan.callee_number }}) + {% end %} + {% elif chan.direction == "outbound" %} + {% if chan.caller %} + {{ chan.caller }} + {% else %} + {{ chan.caller_name }} + {% end %} + + ({{ chan.caller_number }}) + {% end %} + +
+ + {{ chan.codec }} + + {% if chan.secure %} + {{ chan.secure }} + {% end %} +
+ {{ format_time(chan.duration) }} +
+
+
+{% end %} diff --git a/src/web/__init__.py b/src/web/__init__.py index 78651713..8c62f830 100644 --- a/src/web/__init__.py +++ b/src/web/__init__.py @@ -53,6 +53,7 @@ class Application(tornado.web.Application): "Map" : ui_modules.MapModule, # Talk + "TalkChannels" : talk.ChannelsModule, "TalkRegistrations" : talk.RegistrationsModule, # Old modules diff --git a/src/web/talk.py b/src/web/talk.py index c3158eec..f0f52c14 100644 --- a/src/web/talk.py +++ b/src/web/talk.py @@ -31,6 +31,13 @@ class RegistrationsHandler(base.BaseHandler): self.render("talk/registrations.html", account=account) +class ChannelsModule(ui_modules.UIModule): + def render(self, account): + channels = self.backend.talk.freeswitch.get_sip_channels(account) + + return self.render_string("talk/modules/channels.html", account=account, channels=channels) + + class RegistrationsModule(ui_modules.UIModule): def render(self, account): return self.render_string("talk/modules/registrations.html", account=account) -- 2.39.2