templates_people_DATA = \
src/templates/people/base.html \
+ src/templates/people/call.html \
src/templates/people/calls.html \
src/templates/people/index.html \
src/templates/people/passwd.html \
src/templates/people/modules/accounts-list.html \
src/templates/people/modules/cdr.html \
src/templates/people/modules/channels.html \
+ src/templates/people/modules/mos.html \
src/templates/people/modules/registrations.html
templates_people_modulesdir = $(templates_peopledir)/modules
for row in res:
yield CDR(self, data=row)
+ def get_call_by_uuid(self, uuid):
+ res = self.db.get("SELECT * FROM cdr \
+ WHERE uuid = %s", uuid)
+
+ if res:
+ return CDR(self, data=res)
+
class SIPRegistration(object):
def __init__(self, freeswitch, data):
def backend(self):
return self.freeswitch.backend
+ @property
+ def db(self):
+ return self.freeswitch.db
+
+ @property
+ def uuid(self):
+ return self.data.uuid
+
+ @lazy_property
+ def bleg(self):
+ if self.data.bleg_uuid:
+ return self.freeswitch.get_call_by_uuid(self.data.bleg_uuid)
+
+ # If we are the bleg, we need to search for one where UUID is the bleg
+ res = self.db.get("SELECT * FROM cdr WHERE bleg_uuid = %s", self.uuid)
+
+ if res:
+ return CDR(self.freeswitch, data=res)
+
@property
def direction(self):
if self.data.bleg_uuid:
@property
def user_agent(self):
- return self.data.user_agent.replace("_", " ")
+ if self.data.user_agent:
+ return self.data.user_agent.replace("_", " ")
@property
def size(self):
--- /dev/null
+{% extends "base.html" %}
+
+{% block title %}{{ _("Call") }}{% end block %}
+
+{% block main %}
+ <div class="card">
+ <div class="card-body">
+ <h4 class="card-title mb-1">
+ {% if call.direction == "inbound" %}
+ {{ _("Call to") }}
+
+ {% if call.callee %}
+ <a href="/users/{{ call.callee.uid }}">{{ call.callee }}</a>
+ {% else %}
+ {{ format_phone_number(call.callee_number) }}
+ {% end %}
+ {% elif call.direction == "outbound" %}
+ {{ _("Call from") }}
+
+ {% if call.caller %}
+ <a href="/users/{{ call.caller.uid }}">{{ call.caller }}</a>
+ {% else %}
+ {{ format_phone_number(call.caller_number) }}
+ {% end %}
+ {% end %}
+ </h4>
+ <h6 class="card-subtitle text-muted mb-4">{{ locale.format_date(call.time_answered or call.time_start) }}</h6>
+
+ <h3 class="text-center my-5">
+ {% if call.duration %}
+ {{ format_time(call.duration) }}
+ {% else %}
+ {{ _("Not Answered") }}
+ {% end %}
+ </h3>
+
+ <h6>{{ _("Media Information") }}</h6>
+
+ <div class="row">
+ {% for c in (call, call.bleg) %}
+ {% if c %}
+ <div class="col">
+ <div class="card card-body bg-light">
+ <p>
+ <strong>
+ {% if c == call %}
+ {{ _("Your Leg") }}
+ {% else %}
+ {{ _("Other Leg") }}
+ {% end %}
+ </strong>
+ </p>
+
+ <p class="text-center">
+ {% module MOS(c) %}
+ </p>
+
+ <dl class="row mb-0">
+ <dt class="col-sm-6">{{ _("Codec") }}</dt>
+ <dd class="col-sm-6">{{ c.codec or _("N/A") }}</dd>
+
+ <dt class="col-sm-6">{{ _("Data Transferred") }}</dt>
+ <dd class="col-sm-6">{{ format_size(c.size) }}</dd>
+
+ <dt class="col-sm-6">{{ _("User Agent") }}</dt>
+ <dd class="col-sm-6">{{ c.user_agent or _("N/A") }}</dd>
+ </dl>
+ </div>
+ </div>
+ {% end %}
+ {% end %}
+ </div>
+ </div>
+ </div>
+{% end %}
{% if c.direction == "inbound" %}
<span class="fas fa-arrow-right text-danger"></span>
- {% if c.callee %}
- <a href="/users/{{ c.callee.uid }}">{{ c.callee }}</a>
- {% else %}
- {{ format_phone_number(c.callee_number) }}
- {% end %}
+ <a href="/users/{{ account.uid }}/calls/{{ c.uuid }}">
+ {% if c.callee %}
+ {{ c.callee }}
+ {% else %}
+ {{ format_phone_number(c.callee_number) }}
+ {% end %}
+ </a>
{% elif c.direction == "outbound" %}
<span class="fas fa-arrow-left text-success"></span>
- {% if c.caller %}
- <a href="/users/{{ c.caller.uid }}">{{ c.caller }}</a>
- {% else %}
- {{ format_phone_number(c.caller_number) }}
- {% end %}
+ <a href="/users/{{ account.uid }}/calls/{{ c.uuid }}">
+ {% if c.caller %}
+ {{ c.caller }}
+ {% else %}
+ {{ format_phone_number(c.caller_number) }}
+ {% end %}
+ </a>
{% end %}
<br>
- {% if c.mos %}
- <span class="small text-muted" title="{{ "%.2f" % c.mos }}/5">
- {% for i in range(1, 6) %}
- {% if c.mos > (i + 0.5) %}
- <span class="fas fa-star"></span>
- {% elif c.mos > i %}
- <span class="fas fa-star-half-alt"></span>
- {% else %}
- <span class="far fa-star"></span>
- {% end %}
- {% end %}
- </span>
- {% end %}
+ {% module MOS(c) %}
</td>
<td class="text-right">
--- /dev/null
+{% if call.mos %}
+ <span class="small text-muted" title="{{ "%.2f" % call.mos }}/5">
+ {% for i in range(1, 6) %}
+ {% if call.mos > (i + 0.5) %}
+ <span class="fas fa-star"></span>
+ {% elif call.mos > i %}
+ <span class="fas fa-star-half-alt"></span>
+ {% else %}
+ <span class="far fa-star"></span>
+ {% end %}
+ {% end %}
+ </span>
+{% end %}
"AccountsList" : people.AccountsListModule,
"CDR" : people.CDRModule,
"Channels" : people.ChannelsModule,
+ "MOS" : people.MOSModule,
"Registrations" : people.RegistrationsModule,
# Old modules
(r"/users", people.UsersHandler),
(r"/users/(\w+)", people.UserHandler),
(r"/users/(\w+)\.jpg", people.AvatarHandler),
+ (r"/users/(\w+)/calls/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})", people.CallHandler),
(r"/users/(\w+)/calls(?:/(\d{4}-\d{2}-\d{2}))?", people.CallsHandler),
(r"/users/(\w+)/edit", people.UserEditHandler),
(r"/users/(\w+)/passwd", people.UserPasswdHandler),
self.render("people/calls.html", account=account, date=date)
+class CallHandler(base.BaseHandler):
+ @tornado.web.authenticated
+ def get(self, uid, uuid):
+ call = self.backend.talk.freeswitch.get_call_by_uuid(uuid)
+ if not call:
+ raise tornado.web.HTTPError(404, "Could not find call %s" % uuid)
+
+ # XXX limit
+
+ self.render("people/call.html", call=call)
+
+
class RegistrationsHandler(base.BaseHandler):
@tornado.web.authenticated
def get(self, uid):
return self.render_string("people/modules/channels.html", account=account, channels=channels)
+class MOSModule(ui_modules.UIModule):
+ def render(self, call):
+ return self.render_string("people/modules/mos.html", call=call)
+
+
class RegistrationsModule(ui_modules.UIModule):
def render(self, account):
return self.render_string("people/modules/registrations.html", account=account)