2015-09-24 15:15:10 +02:00
|
|
|
# welco - multichannel request processing
|
|
|
|
# Copyright (C) 2015 Entr'ouvert
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
|
|
# under the terms of the GNU Affero General Public License as published
|
|
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Affero General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2015-10-28 17:41:14 +01:00
|
|
|
import json
|
|
|
|
import logging
|
|
|
|
|
2015-09-24 15:15:10 +02:00
|
|
|
from django import template
|
2017-05-31 20:37:27 +02:00
|
|
|
from django.conf import settings
|
2015-09-24 15:15:10 +02:00
|
|
|
from django.contrib.contenttypes.models import ContentType
|
|
|
|
from django.template import RequestContext
|
2015-10-28 17:41:14 +01:00
|
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
|
|
from django.contrib.auth.decorators import login_required
|
|
|
|
from django.http import HttpResponseBadRequest, HttpResponse
|
2020-01-19 19:11:28 +01:00
|
|
|
from django.utils import six
|
|
|
|
from django.utils.encoding import force_text
|
2015-10-28 17:41:14 +01:00
|
|
|
from django.utils.timezone import now
|
2015-11-03 10:02:13 +01:00
|
|
|
from django.views.generic import TemplateView
|
2015-10-28 17:41:14 +01:00
|
|
|
|
|
|
|
from .models import PhoneCall, PhoneLine
|
2015-09-24 15:15:10 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Home(object):
|
|
|
|
source_key = 'phone'
|
|
|
|
|
2016-03-22 13:25:48 +01:00
|
|
|
def __init__(self, request, **kwargs):
|
2015-09-24 15:15:10 +02:00
|
|
|
self.request = request
|
2016-03-22 13:25:48 +01:00
|
|
|
self.kwargs = kwargs
|
2015-09-24 15:15:10 +02:00
|
|
|
|
|
|
|
def render(self):
|
2015-11-03 11:35:45 +01:00
|
|
|
zone = PhoneZone()
|
|
|
|
zone.request = self.request
|
2017-12-28 09:52:27 +01:00
|
|
|
context = zone.get_context_data()
|
2017-04-24 17:49:02 +02:00
|
|
|
# always use ajax to get list of phone calls
|
|
|
|
del context['phonecalls']
|
2015-09-24 15:15:10 +02:00
|
|
|
tmpl = template.loader.get_template('welco/phone_home.html')
|
2017-12-28 09:52:27 +01:00
|
|
|
return tmpl.render(context, request=self.request)
|
2015-10-28 17:41:14 +01:00
|
|
|
|
|
|
|
|
2015-11-03 10:02:13 +01:00
|
|
|
class PhoneZone(TemplateView):
|
|
|
|
template_name = 'welco/phone_home.html'
|
|
|
|
|
2016-02-04 10:15:47 +01:00
|
|
|
def get_context_data(self, **kwargs):
|
2017-05-31 23:55:20 +02:00
|
|
|
if settings.PHONE_AUTOTAKE_MELLON_USERNAME:
|
|
|
|
username = self.request.session.get('mellon_session', {}).get('username')
|
2016-02-04 02:54:51 +01:00
|
|
|
if username:
|
2017-05-31 23:55:20 +02:00
|
|
|
# user is from SSO, username is a phone line (callee), create a link to it
|
|
|
|
username = username[0].split('@', 1)[0][:80] # remove realm
|
|
|
|
if username:
|
|
|
|
PhoneLine.take(callee=username, user=self.request.user)
|
2015-11-03 10:02:13 +01:00
|
|
|
context = super(PhoneZone, self).get_context_data(**kwargs)
|
|
|
|
context['source_type'] = ContentType.objects.get_for_model(PhoneCall)
|
|
|
|
context['phonelines'] = PhoneLine.objects.filter(users__id=self.request.user.id)
|
2015-11-03 12:01:04 +01:00
|
|
|
context['phonecalls'] = PhoneCall.get_current_calls(self.request.user)
|
2015-11-03 10:02:13 +01:00
|
|
|
return context
|
|
|
|
|
|
|
|
|
|
|
|
zone = csrf_exempt(PhoneZone.as_view())
|
|
|
|
|
|
|
|
|
2015-10-28 17:41:14 +01:00
|
|
|
@csrf_exempt
|
|
|
|
def call_event(request):
|
|
|
|
"""Log a new call start or stop, input is JSON:
|
2021-01-11 20:10:12 +01:00
|
|
|
|
2015-10-28 17:41:14 +01:00
|
|
|
{
|
|
|
|
'event': 'start' or 'stop',
|
|
|
|
'caller': '003399999999',
|
|
|
|
'callee': '102',
|
|
|
|
'data': {
|
|
|
|
'user': 'zozo',
|
|
|
|
},
|
|
|
|
}
|
2021-01-11 20:10:12 +01:00
|
|
|
"""
|
2015-10-28 17:41:14 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
2020-01-19 19:46:54 +01:00
|
|
|
payload = json.loads(force_text(request.body))
|
2015-10-28 17:41:14 +01:00
|
|
|
assert isinstance(payload, dict), 'payload is not a JSON object'
|
|
|
|
assert set(payload.keys()) <= set(
|
|
|
|
['event', 'caller', 'callee', 'data']
|
|
|
|
), 'payload keys must be "event", "caller", "callee" and optionnaly "data"'
|
|
|
|
assert set(['event', 'caller', 'callee']) <= set(
|
|
|
|
payload.keys()
|
|
|
|
), 'payload keys must be "event", "caller", "callee" and optionnaly "data"'
|
|
|
|
assert payload['event'] in ('start', 'stop'), 'event must be "start" or "stop"'
|
2020-01-19 19:11:28 +01:00
|
|
|
assert isinstance(payload['caller'], six.string_types), 'caller must be a string'
|
|
|
|
assert isinstance(payload['callee'], six.string_types), 'callee must be a string'
|
2015-10-28 17:41:14 +01:00
|
|
|
if 'data' in payload:
|
|
|
|
assert isinstance(payload['data'], dict), 'data must be a JSON object'
|
2020-01-19 19:12:30 +01:00
|
|
|
except (TypeError, ValueError, AssertionError) as e:
|
2015-10-28 17:41:14 +01:00
|
|
|
return HttpResponseBadRequest(
|
|
|
|
json.dumps({'err': 1, 'msg': force_text(e)}), content_type='application/json'
|
|
|
|
)
|
2017-05-31 20:37:27 +02:00
|
|
|
# janitoring: stop active calls to the callee
|
|
|
|
if settings.PHONE_ONE_CALL_PER_CALLEE:
|
|
|
|
logger.info('stop all calls to %s', payload['callee'])
|
|
|
|
PhoneCall.objects.filter(callee=payload['callee'], stop__isnull=True).update(stop=now())
|
|
|
|
else:
|
|
|
|
logger.info('stop call from %s to %s', payload['caller'], payload['callee'])
|
|
|
|
PhoneCall.objects.filter(
|
|
|
|
caller=payload['caller'], callee=payload['callee'], stop__isnull=True
|
|
|
|
).update(stop=now())
|
2015-10-28 17:41:14 +01:00
|
|
|
if payload['event'] == 'start':
|
|
|
|
# start a new call
|
|
|
|
kwargs = {
|
|
|
|
'caller': payload['caller'],
|
|
|
|
'callee': payload['callee'],
|
|
|
|
}
|
|
|
|
if 'data' in payload:
|
|
|
|
kwargs['data'] = json.dumps(payload['data'])
|
|
|
|
PhoneCall.objects.create(**kwargs)
|
|
|
|
logger.info('start call from %s to %s', payload['caller'], payload['callee'])
|
|
|
|
return HttpResponse(json.dumps({'err': 0}), content_type='application/json')
|
2015-11-09 16:23:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def active_call(request, *args, **kwargs):
|
|
|
|
call = PhoneCall.objects.get(id=kwargs.get('pk'))
|
|
|
|
result = {
|
|
|
|
'caller': call.caller,
|
|
|
|
'callee': call.callee,
|
|
|
|
'active': not (bool(call.stop)),
|
|
|
|
'start_timestamp': call.start.strftime('%Y-%m-%dT%H:%M:%S'),
|
|
|
|
}
|
|
|
|
return HttpResponse(json.dumps(result, indent=2), content_type='application/json')
|
2015-10-28 17:41:14 +01:00
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def current_calls(request):
|
|
|
|
"""Returns the list of current calls for current user as JSON:
|
2021-01-11 20:10:12 +01:00
|
|
|
|
2015-10-28 17:41:14 +01:00
|
|
|
{
|
|
|
|
'err': 0,
|
|
|
|
'data': {
|
|
|
|
'calls': [
|
|
|
|
{
|
|
|
|
'caller': '00334545445',
|
|
|
|
'callee': '102',
|
|
|
|
'data': { ... },
|
|
|
|
},
|
|
|
|
...
|
|
|
|
],
|
|
|
|
'lines': [
|
|
|
|
'102',
|
|
|
|
],
|
|
|
|
'all-lines': [
|
|
|
|
'102',
|
|
|
|
],
|
|
|
|
}
|
|
|
|
}
|
2021-01-11 20:10:12 +01:00
|
|
|
|
2015-10-28 17:41:14 +01:00
|
|
|
lines are number the user is currently watching, all-lines is all
|
|
|
|
registered numbers.
|
2021-01-11 20:10:12 +01:00
|
|
|
"""
|
2015-10-28 17:41:14 +01:00
|
|
|
all_callees = PhoneCall.get_all_callees()
|
|
|
|
callees = PhoneLine.get_callees(request.user)
|
|
|
|
phonecalls = PhoneCall.get_current_calls(request.user)
|
|
|
|
|
|
|
|
calls = []
|
|
|
|
payload = {
|
|
|
|
'err': 0,
|
|
|
|
'data': {
|
|
|
|
'calls': calls,
|
|
|
|
'lines': list(callees),
|
|
|
|
'all-lines': list(all_callees),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for call in phonecalls:
|
|
|
|
calls.append(
|
|
|
|
{
|
|
|
|
'caller': call.caller,
|
|
|
|
'callee': call.callee,
|
|
|
|
'start': call.start.isoformat('T').split('.')[0],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
if call.data:
|
|
|
|
calls[-1]['data'] = json.loads(call.data)
|
|
|
|
response = HttpResponse(content_type='application/json')
|
|
|
|
json.dump(payload, response, indent=2)
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
2015-11-03 10:02:13 +01:00
|
|
|
@csrf_exempt
|
2015-10-28 17:41:14 +01:00
|
|
|
@login_required
|
|
|
|
def take_line(request):
|
|
|
|
"""Take a line, input is JSON:
|
|
|
|
|
|
|
|
{ 'callee': '003369999999' }
|
2021-01-11 20:10:12 +01:00
|
|
|
"""
|
2015-10-28 17:41:14 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
2020-01-19 19:46:54 +01:00
|
|
|
payload = json.loads(force_text(request.body))
|
2015-10-28 17:41:14 +01:00
|
|
|
assert isinstance(payload, dict), 'payload is not a JSON object'
|
2020-01-19 19:34:55 +01:00
|
|
|
assert list(payload.keys()) == ['callee'], 'payload must have only one key: callee'
|
2020-01-19 19:12:30 +01:00
|
|
|
except (TypeError, ValueError, AssertionError) as e:
|
2015-10-28 17:41:14 +01:00
|
|
|
return HttpResponseBadRequest(
|
|
|
|
json.dumps({'err': 1, 'msg': force_text(e)}), content_type='application/json'
|
|
|
|
)
|
|
|
|
PhoneLine.take(payload['callee'], request.user)
|
|
|
|
logger.info(u'user %s took line %s', request.user, payload['callee'])
|
|
|
|
return HttpResponse(json.dumps({'err': 0}), content_type='application/json')
|
|
|
|
|
|
|
|
|
2015-11-03 10:02:13 +01:00
|
|
|
@csrf_exempt
|
2015-10-28 17:41:14 +01:00
|
|
|
@login_required
|
|
|
|
def release_line(request):
|
|
|
|
"""Release a line, input is JSON:
|
|
|
|
|
|
|
|
{ 'callee': '003369999999' }
|
2021-01-11 20:10:12 +01:00
|
|
|
"""
|
2015-10-28 17:41:14 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
2020-01-19 19:46:54 +01:00
|
|
|
payload = json.loads(force_text(request.body))
|
2015-10-28 17:41:14 +01:00
|
|
|
assert isinstance(payload, dict), 'payload is not a JSON object'
|
2020-01-19 19:34:55 +01:00
|
|
|
assert list(payload.keys()) == ['callee'], 'payload must have only one key: callee'
|
2020-01-19 19:12:30 +01:00
|
|
|
except (TypeError, ValueError, AssertionError) as e:
|
2015-10-28 17:41:14 +01:00
|
|
|
return HttpResponseBadRequest(
|
|
|
|
json.dumps({'err': 1, 'msg': force_text(e)}), content_type='application/json'
|
|
|
|
)
|
|
|
|
PhoneLine.release(payload['callee'], request.user)
|
|
|
|
logger.info(u'user %s released line %s', request.user, payload['callee'])
|
|
|
|
return HttpResponse(json.dumps({'err': 0}), content_type='application/json')
|