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
|
|
|
|
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
|
|
|
|
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'
|
|
|
|
|
|
|
|
def __init__(self, request):
|
|
|
|
self.request = request
|
|
|
|
|
|
|
|
def render(self):
|
2015-11-03 11:35:45 +01:00
|
|
|
zone = PhoneZone()
|
|
|
|
zone.request = self.request
|
2015-09-24 15:15:10 +02:00
|
|
|
context = RequestContext(self.request)
|
2015-11-03 11:35:45 +01:00
|
|
|
context.update(zone.get_context_data())
|
2015-09-24 15:15:10 +02:00
|
|
|
tmpl = template.loader.get_template('welco/phone_home.html')
|
|
|
|
return tmpl.render(context)
|
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'
|
|
|
|
|
|
|
|
def get_context_data(self, **kwargs):
|
|
|
|
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)
|
|
|
|
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:
|
|
|
|
|
|
|
|
{
|
|
|
|
'event': 'start' or 'stop',
|
|
|
|
'caller': '003399999999',
|
|
|
|
'callee': '102',
|
|
|
|
'data': {
|
|
|
|
'user': 'zozo',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
|
|
|
payload = json.loads(request.body)
|
|
|
|
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"'
|
|
|
|
assert isinstance(payload['caller'], unicode), 'caller must be a string'
|
|
|
|
assert isinstance(payload['callee'], unicode), 'callee must be a string'
|
|
|
|
if 'data' in payload:
|
|
|
|
assert isinstance(payload['data'], dict), 'data must be a JSON object'
|
|
|
|
except (TypeError, ValueError, AssertionError), e:
|
|
|
|
return HttpResponseBadRequest(json.dumps({'err': 1, 'msg':
|
|
|
|
unicode(e)}),
|
|
|
|
content_type='application/json')
|
|
|
|
# terminate all existing calls between these two endpoints
|
|
|
|
PhoneCall.objects.filter(caller=payload['caller'],
|
|
|
|
callee=payload['callee'], stop__isnull=True) \
|
|
|
|
.update(stop=now())
|
|
|
|
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'])
|
|
|
|
else:
|
|
|
|
logger.info('stop call from %s to %s', payload['caller'], payload['callee'])
|
|
|
|
return HttpResponse(json.dumps({'err': 0}), content_type='application/json')
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
def current_calls(request):
|
|
|
|
'''Returns the list of current calls for current user as JSON:
|
|
|
|
|
|
|
|
{
|
|
|
|
'err': 0,
|
|
|
|
'data': {
|
|
|
|
'calls': [
|
|
|
|
{
|
|
|
|
'caller': '00334545445',
|
|
|
|
'callee': '102',
|
|
|
|
'data': { ... },
|
|
|
|
},
|
|
|
|
...
|
|
|
|
],
|
|
|
|
'lines': [
|
|
|
|
'102',
|
|
|
|
],
|
|
|
|
'all-lines': [
|
|
|
|
'102',
|
|
|
|
],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lines are number the user is currently watching, all-lines is all
|
|
|
|
registered numbers.
|
|
|
|
'''
|
|
|
|
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' }
|
|
|
|
'''
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
|
|
|
payload = json.loads(request.body)
|
|
|
|
assert isinstance(payload, dict), 'payload is not a JSON object'
|
|
|
|
assert payload.keys() == ['callee'], 'payload must have only one key: callee'
|
|
|
|
except (TypeError, ValueError, AssertionError), e:
|
|
|
|
return HttpResponseBadRequest(json.dumps({'err': 1, 'msg':
|
|
|
|
unicode(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' }
|
|
|
|
'''
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
|
|
|
payload = json.loads(request.body)
|
|
|
|
assert isinstance(payload, dict), 'payload is not a JSON object'
|
|
|
|
assert payload.keys() == ['callee'], 'payload must have only one key: callee'
|
|
|
|
except (TypeError, ValueError, AssertionError), e:
|
|
|
|
return HttpResponseBadRequest(json.dumps({'err': 1, 'msg':
|
|
|
|
unicode(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')
|