]> git.ipfire.org Git - ipfire.org.git/commitdiff
people: List ongoing conferences
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 19 Oct 2018 08:39:26 +0000 (09:39 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 19 Oct 2018 08:39:26 +0000 (09:39 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/backend/talk.py
src/templates/people/base.html
src/templates/people/conferences.html [new file with mode: 0644]
src/templates/people/modules/channels.html
src/web/__init__.py
src/web/people.py

index 1424e8247b1e78cd93cc5eb09416db77c307c289..43033d44102b2a61cf3a647db53e850cc7c57967 100644 (file)
@@ -152,6 +152,7 @@ templates_newsletter_DATA = \
 templates_newsletterdir = $(templatesdir)/newsletter
 
 templates_people_DATA = \
+       src/templates/people/conferences.html \
        src/templates/people/base.html \
        src/templates/people/call.html \
        src/templates/people/calls.html \
index 4f692f041bd25731bca496841c0ad3d11629a7b0..8eb2f37c65fe3e3153cd023db8db65e7a1056bdd 100644 (file)
@@ -34,22 +34,24 @@ 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 OR callee_num = ANY(%s))) \
-                               ORDER BY created_epoch",
-                       "inbound", account.sip_id, "outbound", account.sip_id,
-                       account._all_telephone_numbers)
+       def _get_channels(self, query, *args):
+               res = self.db.query(query, *args)
 
                channels = []
-
                for row in res:
                        c = Channel(self, data=row)
                        channels.append(c)
 
                return channels
 
+       def get_sip_channels(self, account):
+               return self._get_channels("SELECT * FROM channels \
+                       WHERE (direction = %s AND cid_num = %s) OR \
+                               (direction = %s AND (callee_num = %s OR callee_num = ANY(%s))) \
+                               ORDER BY created_epoch",
+                       "inbound", account.sip_id, "outbound", account.sip_id,
+                       account._all_telephone_numbers)
+
        def get_cdr_by_account(self, account, date=None, limit=None):
                res = self.db.query("SELECT * FROM cdr \
                        WHERE ((caller_id_number = ANY(%s) AND bleg_uuid IS NOT NULL) \
@@ -68,6 +70,18 @@ class Freeswitch(Object):
                if res:
                        return CDR(self, data=res)
 
+       def get_conferences(self):
+               res = self.db.query("SELECT DISTINCT application_data AS handle FROM channels \
+                       WHERE application = %s AND application_data LIKE %s \
+                       ORDER BY application_data", "conference", "%%@ipfire.org")
+
+               conferences = []
+               for row in res:
+                       c = Conference(self, row.handle)
+                       conferences.append(c)
+
+               return conferences
+
 
 class SIPRegistration(object):
        def __init__(self, freeswitch, data):
@@ -155,6 +169,11 @@ class Channel(object):
        def application_data(self):
                return self.data.application_data
 
+       @lazy_property
+       def conference(self):
+               if self.application == "conference":
+                       return Conference(self.freeswitch, self.application_data)
+
        @property
        def duration(self):
                return time.time() - self.data.created_epoch
@@ -261,57 +280,51 @@ class CDR(object):
                return self.data.rtp_audio_in_mos
 
 
-class Talk(Object):
-       def init(self):
-               # Connect to FreeSWITCH
-               self.freeswitch = Freeswitch(self.backend)
-
-       # Conferences
-
-       @property
-       def conferences(self):
-               conferences = []
-
-               for no in range(1, 10):
-                       conference = Conference(self.backend, no)
-                       conferences.append(conference)
-
-               return conferences
+class Conference(object):
+       def __init__(self, freeswitch, handle):
+               self.freeswitch = freeswitch
+               self.handle = handle
 
-       def get_conference(self, id):
-               for c in self.conferences:
-                       if not c.sip_id == id:
-                               continue
+       def __repr__(self):
+               return "<%s %s>" % (self.__class__.__name__, self.handle)
 
-                       return c
+       def __len__(self):
+               return len(self.channels)
 
+       def __eq__(self, other):
+               if isinstance(other, self.__class__):
+                       return self.handle == other.handle
 
-class Conference(Object):
-       def __init__(self, backend, no):
-               Object.__init__(self, backend)
-               self.no = no
+       def __iter__(self):
+               return iter(self.channels)
 
-       def __cmp__(self, other):
-               return cmp(self.no, other.no)
+       @lazy_property
+       def number(self):
+               m = re.match(r"conf(\d+)@", self.handle)
+               if m:
+                       i = m.group(1)
 
-       @property
-       def name(self):
-               return "IPFire Conference Room %s" % self.no
+                       return int(i)
 
        @property
        def sip_id(self):
-               return "%s" % (9000 + self.no)
+               return 900 + self.number
 
-       @property
-       def sip_url(self):
-               return "%s@ipfire.org" % self.sip_id
+       @lazy_property
+       def channels(self):
+               return self.freeswitch._get_channels("SELECT * FROM channels \
+                       WHERE application = %s AND application_data = %s \
+                       ORDER BY created_epoch", "conference", self.handle)
 
-       @property
-       def participants(self):
-               if not hasattr(self, "_participants"):
-                       self._participants = self.backend.talk.get_ongoing_calls(sip_id=self.sip_id)
 
-               return self._participants
+class Talk(Object):
+       def init(self):
+               # Connect to FreeSWITCH
+               self.freeswitch = Freeswitch(self.backend)
+
+       @property
+       def conferences(self):
+               return self.freeswitch.get_conferences()
 
 
 def format_codec(name, bit_rate, bandwidth):
index 44b3e913d2b9c31e09b227ec086b3f422eb37dbb..342974a19cd5b6bcaa528d7853caea5864bf9178 100644 (file)
                                                {{ _("Users") }}
                                        </a>
                                </li>
+
+                               <li class="nav-item">
+                                       <a class="nav-link {% if request.path.startswith("/conferences") %}active{% end %}" href="/conferences">
+                                               {{ _("Conferences") }}
+                                       </a>
+                               </li>
                        </ul>
 
                        <form class="form-inline my-2 my-lg-0" action="/search" method="GET">
diff --git a/src/templates/people/conferences.html b/src/templates/people/conferences.html
new file mode 100644 (file)
index 0000000..8b0ac71
--- /dev/null
@@ -0,0 +1,57 @@
+{% extends "base.html" %}
+
+{% block title %}{{ _("Conferences") }}{% end block %}
+
+{% block content %}
+       <div class="row justify-content-center">
+               <div class="col col-md-8">
+                       <h1>{{ _("Conferences") }}</h1>
+
+                       {% if conferences %}
+                               {% for c in conferences %}
+                                       <div class="card mb-3" name="{{ c.handle }}">
+                                               <div class="card-body">
+                                                       <h5 class="card-title">{{ _("Conference Room %s") % c.number }}</h5>
+
+                                                       <p class="card-text small text-muted">
+                                                               {{ _("This conference room has one participant", "This conference room has %(num)s participants", len(c)) % { "num" : len(c) } }}
+                                                       </p>
+                                               </div>
+
+                                               <ul class="list-group list-group-flush">
+                                                       {% for chan in c.channels %}
+                                                               <li class="list-group-item">
+                                                                       <div class="d-flex w-100 justify-content-between">
+                                                                               <div>
+                                                                                       {% if chan.caller %}
+                                                                                               <a href="/users/{{ chan.caller.uid }}">{{ chan.caller }}</a>
+                                                                                       {% else %}
+                                                                                               {{ chan.caller_name }}
+                                                                                       {% end %}
+               
+                                                                                       <span class="text-muted">({{ format_phone_number(chan.caller_number) }})</span>
+                                                                               </div>
+
+                                                                               <span>{{ format_time(chan.duration) }}</span>
+                                                                       </div>
+
+                                                                       <span class="text-muted small">
+                                                                               {% if chan.is_secure() %}
+                                                                                       <span class="fas fa-lock" title="{{ chan.secure }}"></span>
+                                                                               {% end %}
+       
+                                                                               {{ chan.codec }}
+                                                                       </span>
+                                                               </li>
+                                                       {% end %}
+                                               </ul>
+                                       </div>
+                               {% end %}
+                       {% else %}
+                               <p class="text-muted text-center my-5">
+                                       {{ _("There are currently no conferences") }}
+                               </p>
+                       {% end %}
+               </div>
+       </div>
+{% end block %}
index 89f1d0d6426d506766e82f2edbaffb653b210824..aa0959c550d33137709b3682f7722f762a9ec057 100644 (file)
                                                                {% if chan.direction == "inbound" %}
                                                                        <span class="fas fa-arrow-right text-danger"></span>
 
-                                                                       {% if chan.application == "conference" %}
-                                                                               CONFERENCE
+                                                                       {% if chan.conference %}
+                                                                               <a href="/conferences#{{ chan.conference.handle }}">{{ _("Conference Room %s") % chan.conference.number }}</a>
 
+                                                                               <span class="text-muted">
+                                                                                       ({{ _("One Participant", "%(num)s Participants", len(chan.conference)) % { "num" : len(chan.conference) } }})
+                                                                               </span>
                                                                        {% elif chan.application == "echo" %}
                                                                                {{ _("Echo Test") }}
 
index 7072108c19173ff5bf24dfaaa5573789b3630dad..20c3f2ced712c9026cc480f745d2512c62c348bf 100644 (file)
@@ -255,6 +255,7 @@ class Application(tornado.web.Application):
                # people.ipfire.org
                self.add_handlers(r"people(\.dev)?\.ipfire\.org", [
                        (r"/", people.IndexHandler),
+                       (r"/conferences", people.ConferencesHandler),
                        (r"/search", people.SearchHandler),
                        (r"/users", people.UsersHandler),
                        (r"/users/(\w+)", people.UserHandler),
index f6e615e44b75fff5d3b3ba30b06bdd8936346ad5..7fbbe34d2ffd1d11036c7bf51bd6b3f242881acd 100644 (file)
@@ -88,6 +88,12 @@ class CallHandler(base.BaseHandler):
                self.render("people/call.html", account=account, call=call)
 
 
+class ConferencesHandler(base.BaseHandler):
+       @tornado.web.authenticated
+       def get(self):
+               self.render("people/conferences.html", conferences=self.backend.talk.conferences)
+
+
 class SearchHandler(base.BaseHandler):
        @tornado.web.authenticated
        def get(self):