29 changed files with 1 additions and 1076 deletions
-
40abonapp/locale/ru/LC_MESSAGES/django.po
-
45abonapp/templates/abonapp/dial_log.html
-
10abonapp/templates/abonapp/editAbon.html
-
5abonapp/templates/abonapp/ext.htm
-
1abonapp/urls.py
-
55abonapp/views.py
-
0dialing_app/__init__.py
-
3dialing_app/admin.py
-
5dialing_app/apps.py
-
8dialing_app/forms.py
-
172dialing_app/locale/ru/LC_MESSAGES/django.po
-
81dialing_app/migrations/0001_initial.py
-
27dialing_app/migrations/0002_auto_20180808_1236.py
-
0dialing_app/migrations/__init__.py
-
109dialing_app/models.py
-
58dialing_app/templates/ext.html
-
37dialing_app/templates/inbox_sms.html
-
78dialing_app/templates/index.html
-
23dialing_app/templates/modal_send_sms.html
-
48dialing_app/templates/vmail.html
-
0dialing_app/templatetags/__init__.py
-
20dialing_app/templatetags/telephone_filters.py
-
3dialing_app/tests.py
-
15dialing_app/urls.py
-
221dialing_app/views.py
-
1djing/settings.py
-
1djing/urls.py
-
2docs/install.md
-
9templates/base.html
@ -1,45 +0,0 @@ |
|||||
{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %} |
|
||||
{% load i18n %} |
|
||||
{% block content %} |
|
||||
|
|
||||
<table class="table table-striped table-bordered"> |
|
||||
<thead> |
|
||||
<tr> |
|
||||
<th>{% trans 'Play' %}</th> |
|
||||
<th>{% trans 'calldate' %}</th> |
|
||||
<th>{% trans 'src' %}</th> |
|
||||
<th>{% trans 'dst' %}</th> |
|
||||
<th>{% trans 'duration' %}</th> |
|
||||
<th>{% trans 'start' %}</th> |
|
||||
<th>{% trans 'answer' %}</th> |
|
||||
<th>{% trans 'end' %}</th> |
|
||||
<th>{% trans 'disposition' %}</th> |
|
||||
</tr> |
|
||||
</thead> |
|
||||
<tbody> |
|
||||
{% for log in logs %} |
|
||||
<tr> |
|
||||
<td> |
|
||||
<audio preload="metadata" controls> |
|
||||
<source src="{{ log.url }}" type="audio/wav"/> |
|
||||
</audio> |
|
||||
</td> |
|
||||
<td>{{ log.calldate|date:'d E Y, H:i:s' }}</td> |
|
||||
<td>{{ log.src }}</td> |
|
||||
<td>{{ log.dst }}</td> |
|
||||
<td>{{ log.duration }}</td> |
|
||||
<td>{{ log.start|date:'d E Y, H:i:s' }}</td> |
|
||||
<td>{{ log.answer|date:'d E Y, H:i:s' }}</td> |
|
||||
<td>{{ log.end|date:'d E Y, H:i:s' }}</td> |
|
||||
<td>{{ log.locate_disposition }}</td> |
|
||||
</tr> |
|
||||
{% empty %} |
|
||||
<tr> |
|
||||
<td colspan="9">{% trans 'Calls was not found' %}</td> |
|
||||
</tr> |
|
||||
{% endfor %} |
|
||||
</tbody> |
|
||||
|
|
||||
</table> |
|
||||
|
|
||||
{% endblock %} |
|
||||
@ -1,3 +0,0 @@ |
|||||
from django.contrib import admin |
|
||||
|
|
||||
# Register your models here. |
|
||||
@ -1,5 +0,0 @@ |
|||||
from django.apps import AppConfig |
|
||||
|
|
||||
|
|
||||
class DialingAppConfig(AppConfig): |
|
||||
name = 'dialing_app' |
|
||||
@ -1,8 +0,0 @@ |
|||||
from django import forms |
|
||||
from .models import SMSOut |
|
||||
|
|
||||
|
|
||||
class SMSOutForm(forms.ModelForm): |
|
||||
class Meta: |
|
||||
model = SMSOut |
|
||||
fields = ('dst', 'text') |
|
||||
@ -1,172 +0,0 @@ |
|||||
# SOME DESCRIPTIVE TITLE. |
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER |
|
||||
# This file is distributed under the same license as the PACKAGE package. |
|
||||
# Dmitry Novikov nerosketch@gmail.com, 2017. |
|
||||
# |
|
||||
#, fuzzy |
|
||||
msgid "" |
|
||||
msgstr "" |
|
||||
"Project-Id-Version: PACKAGE VERSION\n" |
|
||||
"Report-Msgid-Bugs-To: \n" |
|
||||
"POT-Creation-Date: 2018-08-09 14:59+0300\n" |
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
|
||||
"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n" |
|
||||
"Language: \n" |
|
||||
"MIME-Version: 1.0\n" |
|
||||
"Content-Type: text/plain; charset=UTF-8\n" |
|
||||
"Content-Transfer-Encoding: 8bit\n" |
|
||||
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" |
|
||||
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" |
|
||||
"%100>=11 && n%100<=14)? 2 : 3);\n" |
|
||||
|
|
||||
#: models.py:9 models.py:44 |
|
||||
msgid "No answer" |
|
||||
msgstr "Не отвечен" |
|
||||
|
|
||||
#: models.py:10 models.py:46 models.py:101 |
|
||||
msgid "Failed" |
|
||||
msgstr "С ошибкой" |
|
||||
|
|
||||
#: models.py:11 models.py:48 |
|
||||
msgid "Busy" |
|
||||
msgstr "Занято" |
|
||||
|
|
||||
#: models.py:12 models.py:50 |
|
||||
msgid "Answered" |
|
||||
msgstr "Отвечен" |
|
||||
|
|
||||
#: models.py:13 models.py:52 |
|
||||
msgid "Unknown" |
|
||||
msgstr "Не определён" |
|
||||
|
|
||||
#: models.py:86 models.py:87 |
|
||||
msgid "SMS" |
|
||||
msgstr "СМС" |
|
||||
|
|
||||
#: models.py:95 |
|
||||
msgid "When" |
|
||||
msgstr "Когда" |
|
||||
|
|
||||
#: models.py:96 templates/index.html:25 |
|
||||
msgid "Telephone" |
|
||||
msgstr "Телефон" |
|
||||
|
|
||||
#: models.py:97 |
|
||||
msgid "Text" |
|
||||
msgstr "Текст" |
|
||||
|
|
||||
#: models.py:99 |
|
||||
msgid "New" |
|
||||
msgstr "Новое" |
|
||||
|
|
||||
#: models.py:100 |
|
||||
msgid "Sent" |
|
||||
msgstr "Отправленное" |
|
||||
|
|
||||
#: models.py:103 |
|
||||
msgid "Status" |
|
||||
msgstr "Статус" |
|
||||
|
|
||||
#: models.py:111 models.py:112 |
|
||||
msgid "Out SMS" |
|
||||
msgstr "Исходящие СМС" |
|
||||
|
|
||||
#: templates/ext.html:8 templates/ext.html:25 views.py:45 |
|
||||
msgid "Last calls" |
|
||||
msgstr "Последние звонки" |
|
||||
|
|
||||
#: templates/ext.html:32 views.py:74 |
|
||||
msgid "Voice mail request" |
|
||||
msgstr "Заявки на подключение" |
|
||||
|
|
||||
#: templates/ext.html:39 views.py:83 |
|
||||
msgid "Voice mail report" |
|
||||
msgstr "Заявки на поломки" |
|
||||
|
|
||||
#: templates/ext.html:46 templates/inbox_sms.html:7 |
|
||||
msgid "Inbox sms" |
|
||||
msgstr "Входящие смс" |
|
||||
|
|
||||
#: templates/inbox_sms.html:23 |
|
||||
msgid "Message history is empty" |
|
||||
msgstr "История сообщений пуста" |
|
||||
|
|
||||
#: templates/inbox_sms.html:31 templates/modal_send_sms.html:5 |
|
||||
msgid "Send sms" |
|
||||
msgstr "Отправить смс" |
|
||||
|
|
||||
#: templates/index.html:9 templates/vmail.html:10 |
|
||||
msgid "Play" |
|
||||
msgstr "Слушать" |
|
||||
|
|
||||
#: templates/index.html:10 templates/index.html:36 templates/vmail.html:11 |
|
||||
msgid "calldate" |
|
||||
msgstr "дата звонка" |
|
||||
|
|
||||
#: templates/index.html:11 templates/vmail.html:12 |
|
||||
msgid "src" |
|
||||
msgstr "кто" |
|
||||
|
|
||||
#: templates/index.html:12 |
|
||||
msgid "dst" |
|
||||
msgstr "куда" |
|
||||
|
|
||||
#: templates/index.html:13 templates/vmail.html:13 |
|
||||
msgid "duration" |
|
||||
msgstr "продолжительность" |
|
||||
|
|
||||
#: templates/index.html:14 templates/vmail.html:14 |
|
||||
msgid "start" |
|
||||
msgstr "начало" |
|
||||
|
|
||||
#: templates/index.html:15 templates/vmail.html:15 |
|
||||
msgid "answer" |
|
||||
msgstr "ответ" |
|
||||
|
|
||||
#: templates/index.html:16 templates/vmail.html:16 |
|
||||
msgid "end" |
|
||||
msgstr "конец" |
|
||||
|
|
||||
#: templates/index.html:17 templates/vmail.html:17 |
|
||||
msgid "disposition" |
|
||||
msgstr "состояние" |
|
||||
|
|
||||
#: templates/index.html:23 views.py:94 |
|
||||
msgid "Find dials" |
|
||||
msgstr "Найти звонки" |
|
||||
|
|
||||
#: templates/index.html:34 |
|
||||
msgid "Find by dates" |
|
||||
msgstr "Найти по дате" |
|
||||
|
|
||||
#: templates/index.html:64 |
|
||||
msgid "Download" |
|
||||
msgstr "Скачать" |
|
||||
|
|
||||
#: templates/index.html:80 templates/vmail.html:42 |
|
||||
msgid "Calls was not found" |
|
||||
msgstr "Звонки не найдены" |
|
||||
|
|
||||
#: templates/modal_send_sms.html:19 |
|
||||
msgid "Send" |
|
||||
msgstr "Отправить" |
|
||||
|
|
||||
#: views.py:55 |
|
||||
msgid "Multiple users with the telephone number" |
|
||||
msgstr "Несколько абонентов с указанным номером телефона" |
|
||||
|
|
||||
#: views.py:57 |
|
||||
msgid "User with the telephone number not found" |
|
||||
msgstr "Абонент с таким номером телефона не найден" |
|
||||
|
|
||||
#: views.py:114 |
|
||||
msgid "Make sure that your date format is correct" |
|
||||
msgstr "Убедитесь что формат времени корректен" |
|
||||
|
|
||||
#: views.py:138 |
|
||||
msgid "Message was enqueued for sending" |
|
||||
msgstr "Сообщение было поставлено в очередь для отправки" |
|
||||
|
|
||||
#: views.py:151 |
|
||||
msgid "fix form errors" |
|
||||
msgstr "Некоторые поля заполнены не правильно, проверте ещё раз" |
|
||||
@ -1,81 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
# Generated by Django 1.11 on 2018-02-26 00:20 |
|
||||
from __future__ import unicode_literals |
|
||||
|
|
||||
from django.db import migrations, models |
|
||||
|
|
||||
|
|
||||
class Migration(migrations.Migration): |
|
||||
initial = True |
|
||||
|
|
||||
dependencies = [ |
|
||||
] |
|
||||
|
|
||||
operations = [ |
|
||||
migrations.CreateModel( |
|
||||
name='AsteriskCDR', |
|
||||
fields=[ |
|
||||
('calldate', models.DateTimeField(default='0000-00-00 00:00:00', primary_key=True, serialize=False)), |
|
||||
('clid', models.CharField(default='', max_length=80)), |
|
||||
('src', models.CharField(default='', max_length=80)), |
|
||||
('dst', models.CharField(default='', max_length=80)), |
|
||||
('dcontext', models.CharField(default='', max_length=80)), |
|
||||
('channel', models.CharField(default='', max_length=80)), |
|
||||
('dstchannel', models.CharField(default='', max_length=80)), |
|
||||
('lastapp', models.CharField(default='', max_length=80)), |
|
||||
('lastdata', models.CharField(default='', max_length=80)), |
|
||||
('duration', models.IntegerField(default=0)), |
|
||||
('billsec', models.IntegerField(default=0)), |
|
||||
('start', models.DateTimeField(blank=True, default=None, null=True)), |
|
||||
('answer', models.DateTimeField(blank=True, default=None, null=True)), |
|
||||
('end', models.DateTimeField(blank=True, default=None, null=True)), |
|
||||
('disposition', models.CharField( |
|
||||
choices=[('NO ANSWER', 'No answer'), ('FAILED', 'Failed'), ('BUSY', 'Busy'), |
|
||||
('ANSWERED', 'Answered'), ('UNKNOWN', 'Unknown')], default='', max_length=45)), |
|
||||
('amaflags', models.IntegerField(default=0)), |
|
||||
('accountcode', models.CharField(default='', max_length=20)), |
|
||||
('userfield', models.CharField(default='', max_length=255)), |
|
||||
('uniqueid', models.CharField(default='', max_length=32)), |
|
||||
], |
|
||||
options={ |
|
||||
'db_table': 'cdr', |
|
||||
'ordering': ['-calldate'], |
|
||||
'managed': False, |
|
||||
}, |
|
||||
), |
|
||||
migrations.CreateModel( |
|
||||
name='SMSModel', |
|
||||
fields=[ |
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
||||
('when', models.DateTimeField(auto_now_add=True)), |
|
||||
('who', models.CharField(max_length=32)), |
|
||||
('dev', models.CharField(max_length=20)), |
|
||||
('text', models.CharField(max_length=255)), |
|
||||
], |
|
||||
options={ |
|
||||
'verbose_name': 'SMS', |
|
||||
'verbose_name_plural': 'SMS', |
|
||||
'db_table': 'sms', |
|
||||
'ordering': ['-when'], |
|
||||
'permissions': (('can_view_sms', 'Can view sms'),), |
|
||||
}, |
|
||||
), |
|
||||
migrations.CreateModel( |
|
||||
name='SMSOut', |
|
||||
fields=[ |
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
||||
('when', models.DateTimeField(auto_now_add=True, verbose_name='When')), |
|
||||
('dst', models.CharField(max_length=16, verbose_name='Telephone')), |
|
||||
('text', models.CharField(max_length=255, verbose_name='Text')), |
|
||||
('status', |
|
||||
models.CharField(choices=[('nw', 'New'), ('st', 'Sent'), ('fd', 'Failed')], default='nw', max_length=2, |
|
||||
verbose_name='Status')), |
|
||||
], |
|
||||
options={ |
|
||||
'verbose_name': 'Out SMS', |
|
||||
'verbose_name_plural': 'Out SMS', |
|
||||
'db_table': 'out_sms', |
|
||||
'permissions': (('can_view_sms', 'Can view sms'), ('can_send_sms', 'Can send sms')), |
|
||||
}, |
|
||||
), |
|
||||
] |
|
||||
@ -1,27 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
# Generated by Django 1.11 on 2018-08-08 12:36 |
|
||||
from __future__ import unicode_literals |
|
||||
|
|
||||
from django.db import migrations |
|
||||
|
|
||||
|
|
||||
class Migration(migrations.Migration): |
|
||||
|
|
||||
dependencies = [ |
|
||||
('dialing_app', '0001_initial'), |
|
||||
] |
|
||||
|
|
||||
operations = [ |
|
||||
migrations.AlterModelOptions( |
|
||||
name='asteriskcdr', |
|
||||
options={'managed': False, 'ordering': ('-calldate',)}, |
|
||||
), |
|
||||
migrations.AlterModelOptions( |
|
||||
name='smsmodel', |
|
||||
options={'ordering': ('-when',), 'permissions': (('can_view_sms', 'Can view sms'),), 'verbose_name': 'SMS', 'verbose_name_plural': 'SMS'}, |
|
||||
), |
|
||||
migrations.AlterModelOptions( |
|
||||
name='smsout', |
|
||||
options={'ordering': ('-when',), 'permissions': (('can_view_sms', 'Can view sms'), ('can_send_sms', 'Can send sms')), 'verbose_name': 'Out SMS', 'verbose_name_plural': 'Out SMS'}, |
|
||||
), |
|
||||
] |
|
||||
@ -1,109 +0,0 @@ |
|||||
from django.db import models |
|
||||
from datetime import datetime |
|
||||
from django.utils.translation import gettext_lazy as _ |
|
||||
from django.conf import settings |
|
||||
|
|
||||
|
|
||||
class AsteriskCDR(models.Model): |
|
||||
DISPOSITION_CHOICES = ( |
|
||||
('NO ANSWER', _('No answer')), |
|
||||
('FAILED', _('Failed')), |
|
||||
('BUSY', _('Busy')), |
|
||||
('ANSWERED', _('Answered')), |
|
||||
('UNKNOWN', _('Unknown')) |
|
||||
) |
|
||||
calldate = models.DateTimeField(default='0000-00-00 00:00:00', primary_key=True) |
|
||||
clid = models.CharField(max_length=80, default='') |
|
||||
src = models.CharField(max_length=80, default='') |
|
||||
dst = models.CharField(max_length=80, default='') |
|
||||
dcontext = models.CharField(max_length=80, default='') |
|
||||
channel = models.CharField(max_length=80, default='') |
|
||||
dstchannel = models.CharField(max_length=80, default='') |
|
||||
lastapp = models.CharField(max_length=80, default='') |
|
||||
lastdata = models.CharField(max_length=80, default='') |
|
||||
duration = models.IntegerField(default=0) |
|
||||
billsec = models.IntegerField(default=0) |
|
||||
start = models.DateTimeField(null=True, blank=True, default=None) |
|
||||
answer = models.DateTimeField(null=True, blank=True, default=None) |
|
||||
end = models.DateTimeField(null=True, blank=True, default=None) |
|
||||
disposition = models.CharField(max_length=45, choices=DISPOSITION_CHOICES, default='') |
|
||||
amaflags = models.IntegerField(default=0) |
|
||||
accountcode = models.CharField(max_length=20, default='') |
|
||||
userfield = models.CharField(max_length=255, default='') |
|
||||
uniqueid = models.CharField(max_length=32, default='') |
|
||||
|
|
||||
def save(self, *args, **kwargs): |
|
||||
return |
|
||||
|
|
||||
def delete(self, *args, **kwargs): |
|
||||
return |
|
||||
|
|
||||
def locate_disposition(self): |
|
||||
dsp = self.disposition |
|
||||
if dsp == 'NO ANSWER': |
|
||||
return _('No answer') |
|
||||
elif dsp == 'FAILED': |
|
||||
return _('Failed') |
|
||||
elif dsp == 'BUSY': |
|
||||
return _('Busy') |
|
||||
elif dsp == 'ANSWERED': |
|
||||
return _('Answered') |
|
||||
elif dsp == 'UNKNOWN': |
|
||||
return _('Unknown') |
|
||||
return '' |
|
||||
|
|
||||
def path_to_media(self): |
|
||||
path = getattr(settings, 'DIALING_MEDIA', '/media') |
|
||||
if self.userfield == 'request': |
|
||||
return "%s/recording/request" % path |
|
||||
elif self.userfield == 'report': |
|
||||
return "%s/recording/bug" % path |
|
||||
return "%s/monitor" % path |
|
||||
|
|
||||
def url(self): |
|
||||
if type(self.calldate) is datetime: |
|
||||
return "%s/%s-%s-%s.wav" % ( |
|
||||
self.path_to_media(), self.calldate.strftime('%Y/%m/%d/%H_%M'), self.src, self.dst |
|
||||
) |
|
||||
|
|
||||
class Meta: |
|
||||
db_table = 'cdr' |
|
||||
managed = False |
|
||||
ordering = ('-calldate',) |
|
||||
|
|
||||
|
|
||||
class SMSModel(models.Model): |
|
||||
when = models.DateTimeField(auto_now_add=True) |
|
||||
who = models.CharField(max_length=32) |
|
||||
dev = models.CharField(max_length=20) |
|
||||
text = models.CharField(max_length=255) |
|
||||
|
|
||||
class Meta: |
|
||||
db_table = 'sms' |
|
||||
verbose_name = _('SMS') |
|
||||
verbose_name_plural = _('SMS') |
|
||||
ordering = ('-when',) |
|
||||
|
|
||||
def __str__(self): |
|
||||
return self.text |
|
||||
|
|
||||
|
|
||||
class SMSOut(models.Model): |
|
||||
when = models.DateTimeField(_('When'), auto_now_add=True) |
|
||||
dst = models.CharField(_('Telephone'), max_length=16) |
|
||||
text = models.CharField(_('Text'), max_length=255) |
|
||||
SMS_OUT_STATUS = ( |
|
||||
('nw', _('New')), |
|
||||
('st', _('Sent')), |
|
||||
('fd', _('Failed')) |
|
||||
) |
|
||||
status = models.CharField(_('Status'), max_length=2, choices=SMS_OUT_STATUS, default='nw') |
|
||||
|
|
||||
class Meta: |
|
||||
db_table = 'out_sms' |
|
||||
verbose_name = _('Out SMS') |
|
||||
verbose_name_plural = _('Out SMS') |
|
||||
ordering = ('-when',) |
|
||||
|
|
||||
def __str__(self): |
|
||||
return self.text |
|
||||
@ -1,58 +0,0 @@ |
|||||
{% extends request.is_ajax|yesno:'bajax.html,base.html' %} |
|
||||
{% load i18n %} |
|
||||
|
|
||||
|
|
||||
{% block breadcrumb %} |
|
||||
<ol class="breadcrumb"> |
|
||||
<li><span class="glyphicon glyphicon-home"></span></li> |
|
||||
<li class="active">{% trans 'Last calls' %}</li> |
|
||||
</ol> |
|
||||
{% endblock %} |
|
||||
|
|
||||
|
|
||||
{% block page-header %} |
|
||||
{{ title }} |
|
||||
{% endblock %} |
|
||||
|
|
||||
|
|
||||
{% block main %} |
|
||||
|
|
||||
<ul class="nav nav-tabs"> |
|
||||
|
|
||||
{% url 'dialapp:home' as dialhome %} |
|
||||
<li{% if dialhome == request.path %} class="active"{% endif %}> |
|
||||
<a href="{{ dialhome }}"> |
|
||||
{% trans 'Last calls' %} |
|
||||
</a> |
|
||||
</li> |
|
||||
|
|
||||
{% url 'dialapp:vmail_request' as dialmail %} |
|
||||
<li{% if dialmail == request.path %} class="active"{% endif %}> |
|
||||
<a href="{{ dialmail }}"> |
|
||||
{% trans 'Voice mail request' %} |
|
||||
</a> |
|
||||
</li> |
|
||||
|
|
||||
{% url 'dialapp:vmail_report' as dialmail %} |
|
||||
<li{% if dialmail == request.path %} class="active"{% endif %}> |
|
||||
<a href="{{ dialmail }}"> |
|
||||
{% trans 'Voice mail report' %} |
|
||||
</a> |
|
||||
</li> |
|
||||
|
|
||||
{% url 'dialapp:inbox_sms' as dialsmsin %} |
|
||||
<li{% if dialsmsin == request.path %} class="active"{% endif %}> |
|
||||
<a href="{{ dialsmsin }}"> |
|
||||
{% trans 'Inbox sms' %} |
|
||||
</a> |
|
||||
</li> |
|
||||
|
|
||||
</ul> |
|
||||
|
|
||||
<div class="tab-content"> |
|
||||
<div class="tab-pane active"> |
|
||||
{% block content %}{% endblock %} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
{% endblock %} |
|
||||
@ -1,37 +0,0 @@ |
|||||
{% extends request.is_ajax|yesno:'nullcont.htm,ext.html' %} |
|
||||
{% load i18n %} |
|
||||
{% block content %} |
|
||||
|
|
||||
<div class="panel panel-default"> |
|
||||
<div class="panel-heading"> |
|
||||
<h3 class="panel-title">{% trans 'Inbox sms' %}</h3> |
|
||||
</div> |
|
||||
<div class="list-group scroll-area"> |
|
||||
|
|
||||
{% for msg in sms_messages %} |
|
||||
|
|
||||
<div class="list-group-item"> |
|
||||
<h5>From {{ msg.who }} |
|
||||
<small>{{ msg.when|date:'d M, H:i:s' }} via {{ msg.dev }}</small> |
|
||||
</h5> |
|
||||
|
|
||||
<pre>{{ msg.text }}</pre> |
|
||||
</div> |
|
||||
|
|
||||
{% empty %} |
|
||||
<div class="list-group-item"> |
|
||||
<h4 class="list-group-item-heading">{% trans 'Message history is empty' %}</h4> |
|
||||
</div> |
|
||||
{% endfor %} |
|
||||
|
|
||||
</div> |
|
||||
<div class="panel-footer"> |
|
||||
{% if perms.dialing_app.add_smsout %} |
|
||||
<a href="{% url 'dialapp:send_sms' %}" class="btn btn-default btn-modal"> |
|
||||
<span class="glyphicon glyphicon-envelope"></span> {% trans 'Send sms' %} |
|
||||
</a> |
|
||||
{% endif %} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
{% endblock %} |
|
||||
@ -1,78 +0,0 @@ |
|||||
{% extends request.is_ajax|yesno:'nullcont.htm,ext.html' %} |
|
||||
{% load i18n telephone_filters %} |
|
||||
{% block content %} |
|
||||
<div class="table-responsive"> |
|
||||
<table class="table table-striped table-bordered"> |
|
||||
<thead> |
|
||||
<tr> |
|
||||
<th>{% trans 'Play' %}</th> |
|
||||
<th>{% trans 'calldate' %}</th> |
|
||||
<th>{% trans 'src' %}</th> |
|
||||
<th>{% trans 'dst' %}</th> |
|
||||
<th>{% trans 'duration' %}</th> |
|
||||
<th>{% trans 'start' %}</th> |
|
||||
<th>{% trans 'answer' %}</th> |
|
||||
<th>{% trans 'end' %}</th> |
|
||||
<th>{% trans 'disposition' %}</th> |
|
||||
</tr> |
|
||||
<tr> |
|
||||
<th colspan="9"> |
|
||||
<form class="form-inline" action="{% url 'dialapp:vfilter' %}" method="get"> |
|
||||
<div class="form-group"> |
|
||||
<label class="sr-only" for="dialsearch">{% trans 'Find dials' %}</label> |
|
||||
<div class="input-group input-group-sm"> |
|
||||
<input type="text" class="form-control" id="dialsearch" placeholder="{% trans 'Telephone' %}" name="s"{% if s %} value="{{ s }}"{% endif %}> |
|
||||
<div class="input-group-btn"> |
|
||||
<button class="btn btn-default" type="submit"> |
|
||||
<span class="glyphicon glyphicon-search"></span> |
|
||||
</button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="form-group"> |
|
||||
<label class="sr-only" for="dialtime">{% trans 'Find by dates' %}</label> |
|
||||
<div class="input-group input-group-sm"> |
|
||||
<input type="datetime-local" class="form-control" id="dialtime" placeholder="{% trans 'calldate' %}" name="sd"{% if sd %} value="{{ sd }}"{% endif %}> |
|
||||
<div class="input-group-btn"> |
|
||||
<button class="btn btn-default" type="submit"> |
|
||||
<span class="glyphicon glyphicon-search"></span> |
|
||||
</button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</form> |
|
||||
</th> |
|
||||
</tr> |
|
||||
</thead> |
|
||||
<tbody> |
|
||||
{% for log in logs %} |
|
||||
<tr> |
|
||||
{% with lurl=log.url %} |
|
||||
<td class="btn-group btn-group-xs btn-group-justify"> |
|
||||
<button class="btn btn-default player-btn disabled"> |
|
||||
<span class="glyphicon glyphicon-play"></span> |
|
||||
<audio preload="metadata" src="{{ lurl|default:'#' }}"></audio> |
|
||||
</button> |
|
||||
<a href="{{ lurl|default:'#' }}" class="btn btn-default disabled" title="{% trans 'Download' %}"> |
|
||||
<span class="glyphicon glyphicon-download-alt"></span> |
|
||||
</a> |
|
||||
</td> |
|
||||
<td>{{ log.calldate|date:'d M, H:i:s' }}</td> |
|
||||
<td>{{ log.src|abon_if_telephone|safe }}</td> |
|
||||
<td>{{ log.dst|abon_if_telephone|safe }}</td> |
|
||||
<td>{{ log.duration }}</td> |
|
||||
<td>{{ log.start|date:'d M, H:i:s' }}</td> |
|
||||
<td>{{ log.answer|date:'d M, H:i:s' }}</td> |
|
||||
<td>{{ log.end|date:'d M, H:i:s' }}</td> |
|
||||
<td>{{ log.locate_disposition }}</td> |
|
||||
{% endwith %} |
|
||||
</tr> |
|
||||
{% empty %} |
|
||||
<tr> |
|
||||
<td colspan="9">{% trans 'Calls was not found' %}</td> |
|
||||
</tr> |
|
||||
{% endfor %} |
|
||||
</tbody> |
|
||||
</table> |
|
||||
</div> |
|
||||
{% endblock %} |
|
||||
@ -1,23 +0,0 @@ |
|||||
{% load i18n bootstrap3 %} |
|
||||
<form action="{% url 'dialapp:send_sms' %}?path={{ path|default:'' }}" method="post"> {% csrf_token %} |
|
||||
<div class="modal-header primary"> |
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> |
|
||||
<h4 class="modal-title"><span class="glyphicon glyphicon-envelope"></span>{% trans 'Send sms' %}</h4> |
|
||||
</div> |
|
||||
|
|
||||
{% include '_messages.html' %} |
|
||||
|
|
||||
<div class="modal-body"> |
|
||||
|
|
||||
{% bootstrap_icon 'earphone' as ic %} |
|
||||
{% bootstrap_field form.dst label_class='col-sm-2' field_class='col-sm-10' addon_before=ic %} |
|
||||
|
|
||||
{% bootstrap_icon 'pencil' as ic %} |
|
||||
{% bootstrap_field form.text label_class='col-sm-2' field_class='col-sm-10' addon_before=ic %} |
|
||||
|
|
||||
<button type="submit" class="btn btn-sm btn-success"> |
|
||||
<span class="glyphicon glyphicon-send"></span> {% trans 'Send' %} |
|
||||
</button> |
|
||||
</div> |
|
||||
|
|
||||
</form> |
|
||||
@ -1,48 +0,0 @@ |
|||||
{% extends request.is_ajax|yesno:'nullcont.htm,ext.html' %} |
|
||||
{% load i18n telephone_filters %} |
|
||||
{% block content %} |
|
||||
|
|
||||
<div class="table-responsive"> |
|
||||
<table class="table table-striped table-bordered"> |
|
||||
<thead> |
|
||||
<tr> |
|
||||
<th>{% trans 'Play' %}</th> |
|
||||
<th>{% trans 'calldate' %}</th> |
|
||||
<th>{% trans 'src' %}</th> |
|
||||
<th>{% trans 'duration' %}</th> |
|
||||
<th>{% trans 'start' %}</th> |
|
||||
<th>{% trans 'answer' %}</th> |
|
||||
<th>{% trans 'end' %}</th> |
|
||||
<th>{% trans 'disposition' %}</th> |
|
||||
</tr> |
|
||||
</thead> |
|
||||
<tbody> |
|
||||
{% for vmail in vmessages %} |
|
||||
<tr> |
|
||||
<td class="btn-group btn-group-xs"> |
|
||||
<button class="btn btn-default player-btn disabled"> |
|
||||
<span class="glyphicon glyphicon-play"></span> |
|
||||
<audio preload="metadata" src="{{ vmail.path_to_media }}/{{ vmail.calldate|date:"YmdHi" }}-{{ vmail.src }}-{{ vmail.dst }}.wav"></audio> |
|
||||
</button> |
|
||||
<a href="{{ vmail.path_to_media }}/{{ vmail.calldate|date:"YmdHi" }}-{{ vmail.src }}-{{ vmail.dst }}.wav" class="btn btn-default disabled" target="_blank"> |
|
||||
<span class="glyphicon glyphicon-download-alt"></span> |
|
||||
</a> |
|
||||
</td> |
|
||||
<td>{{ vmail.calldate|date:'d E Y, H:i:s' }}</td> |
|
||||
<td>{{ vmail.src|abon_if_telephone|safe }}</td> |
|
||||
<td>{{ vmail.duration }}</td> |
|
||||
<td>{{ vmail.start|date:'d E Y, H:i:s' }}</td> |
|
||||
<td>{{ vmail.answer|date:'d E Y, H:i:s' }}</td> |
|
||||
<td>{{ vmail.end|date:'d E Y, H:i:s' }}</td> |
|
||||
<td>{{ vmail.locate_disposition }}</td> |
|
||||
</tr> |
|
||||
{% empty %} |
|
||||
<tr> |
|
||||
<td colspan="8">{% trans 'Calls was not found' %}</td> |
|
||||
</tr> |
|
||||
{% endfor %} |
|
||||
</tbody> |
|
||||
</table> |
|
||||
</div> |
|
||||
|
|
||||
{% endblock %} |
|
||||
@ -1,20 +0,0 @@ |
|||||
import re |
|
||||
from django import template |
|
||||
from django.shortcuts import resolve_url |
|
||||
from django.template.defaultfilters import stringfilter |
|
||||
|
|
||||
register = template.Library() |
|
||||
|
|
||||
|
|
||||
@register.filter |
|
||||
@stringfilter |
|
||||
def abon_if_telephone(value): |
|
||||
"""Возвращаем ссыль на абонента если передали номер телефона""" |
|
||||
if re.match(r'^\+?\d+$', value): |
|
||||
if value[0] != '+': |
|
||||
value = '+' + value |
|
||||
url = resolve_url('dialapp:to_abon', tel=value) |
|
||||
a = '<a href="%s">%s</a>' % (url, value) |
|
||||
return a |
|
||||
else: |
|
||||
return value |
|
||||
@ -1,3 +0,0 @@ |
|||||
from django.test import TestCase |
|
||||
|
|
||||
# Create your tests here. |
|
||||
@ -1,15 +0,0 @@ |
|||||
from django.urls import path, re_path |
|
||||
from . import views |
|
||||
|
|
||||
app_name = 'dialing_app' |
|
||||
|
|
||||
urlpatterns = [ |
|
||||
path('', views.LastCallsListView.as_view(), name='home'), |
|
||||
path('filter/', views.DialsFilterListView.as_view(), name='vfilter'), |
|
||||
re_path('^to_abon(?P<tel>\+?\d+)/$', views.to_abon, name='to_abon'), |
|
||||
path('requests/', views.VoiceMailRequestsListView.as_view(), name='vmail_request'), |
|
||||
path('reports/', views.VoiceMailReportsListView.as_view(), name='vmail_report'), |
|
||||
path('sms/in/', views.InboxSMSListView.as_view(), name='inbox_sms'), |
|
||||
path('sms/send/', views.send_sms, name='send_sms'), |
|
||||
path('api/sms/', views.SmsManager.as_view()) |
|
||||
] |
|
||||
@ -1,221 +0,0 @@ |
|||||
from datetime import datetime |
|
||||
from subprocess import run |
|
||||
from django.contrib.auth.decorators import login_required |
|
||||
from django.contrib import messages |
|
||||
|
|
||||
from django.db import ProgrammingError |
|
||||
from django.shortcuts import redirect, render |
|
||||
from django.utils.translation import gettext_lazy as _ |
|
||||
from django.utils.decorators import method_decorator |
|
||||
from django.views.generic import ListView |
|
||||
from guardian.decorators import permission_required_or_403 as permission_required |
|
||||
from django.db.models import Q |
|
||||
from django.conf import settings |
|
||||
|
|
||||
from abonapp.models import Abon |
|
||||
from djing.global_base_views import SecureApiView |
|
||||
from djing import JSONType |
|
||||
from djing.lib import safe_int |
|
||||
from djing.lib.decorators import only_admins, json_view |
|
||||
from .models import AsteriskCDR, SMSModel, SMSOut |
|
||||
from .forms import SMSOutForm |
|
||||
|
|
||||
|
|
||||
login_decs = login_required, only_admins |
|
||||
|
|
||||
|
|
||||
class BaseListView(ListView): |
|
||||
http_method_names = 'get', |
|
||||
paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10) |
|
||||
|
|
||||
|
|
||||
@method_decorator(login_decs, name='dispatch') |
|
||||
@method_decorator(permission_required('dialing_app.change_asteriskcdr'), name='dispatch') |
|
||||
class LastCallsListView(BaseListView): |
|
||||
template_name = 'index.html' |
|
||||
context_object_name = 'logs' |
|
||||
queryset = AsteriskCDR.objects.exclude(userfield='request') |
|
||||
|
|
||||
def get(self, request, *args, **kwargs): |
|
||||
try: |
|
||||
return super(LastCallsListView, self).get(request, *args, **kwargs) |
|
||||
except ProgrammingError as e: |
|
||||
messages.error(self.request, e) |
|
||||
return redirect('abonapp:group_list') |
|
||||
|
|
||||
def get_context_data(self, **kwargs): |
|
||||
context = super(LastCallsListView, self).get_context_data(**kwargs) |
|
||||
context['title'] = _('Last calls') |
|
||||
return context |
|
||||
|
|
||||
|
|
||||
@login_required |
|
||||
@only_admins |
|
||||
def to_abon(request, tel): |
|
||||
abon = Abon.objects.filter( |
|
||||
Q(telephone__icontains=tel) | |
|
||||
Q(additional_telephones__telephone__icontains=tel) |
|
||||
) |
|
||||
abon_count = abon.count() |
|
||||
if abon_count > 1: |
|
||||
messages.warning( |
|
||||
request, _('Multiple users with the telephone number') |
|
||||
) |
|
||||
elif abon_count == 0: |
|
||||
messages.error(request, _('User with the telephone number not found')) |
|
||||
return redirect('dialapp:home') |
|
||||
abon = abon[0] |
|
||||
if abon.group: |
|
||||
return redirect( |
|
||||
'abonapp:abon_home', gid=abon.group.pk, |
|
||||
uname=abon.username |
|
||||
) |
|
||||
else: |
|
||||
return redirect('abonapp:group_list') |
|
||||
|
|
||||
|
|
||||
@method_decorator(login_decs, name='dispatch') |
|
||||
class VoiceMailRequestsListView(BaseListView): |
|
||||
template_name = 'vmail.html' |
|
||||
context_object_name = 'vmessages' |
|
||||
queryset = AsteriskCDR.objects.filter(userfield='request') |
|
||||
|
|
||||
def get_context_data(self, **kwargs): |
|
||||
context = super(VoiceMailRequestsListView, self).get_context_data(**kwargs) |
|
||||
context['title'] = _('Voice mail request') |
|
||||
return context |
|
||||
|
|
||||
|
|
||||
class VoiceMailReportsListView(VoiceMailRequestsListView): |
|
||||
queryset = AsteriskCDR.objects.filter(userfield='report') |
|
||||
|
|
||||
def get_context_data(self, **kwargs): |
|
||||
context = super(VoiceMailRequestsListView, self).get_context_data(**kwargs) |
|
||||
context['title'] = _('Voice mail report') |
|
||||
return context |
|
||||
|
|
||||
|
|
||||
@method_decorator(login_decs, name='dispatch') |
|
||||
class DialsFilterListView(BaseListView): |
|
||||
context_object_name = 'logs' |
|
||||
template_name = 'index.html' |
|
||||
|
|
||||
def get_context_data(self, **kwargs): |
|
||||
context = super(DialsFilterListView, self).get_context_data(**kwargs) |
|
||||
context['title'] = _('Find dials') |
|
||||
context['s'] = self.request.GET.get('s') |
|
||||
context['sd'] = self.request.GET.get('sd') |
|
||||
return context |
|
||||
|
|
||||
def get_queryset(self): |
|
||||
s = self.request.GET.get('s') |
|
||||
sd = self.request.GET.get('sd') |
|
||||
if isinstance(s, str) and s != '': |
|
||||
cdr_q = Q(src__icontains=s) | Q(dst__icontains=s) |
|
||||
else: |
|
||||
cdr_q = None |
|
||||
try: |
|
||||
if isinstance(sd, str) and sd != '': |
|
||||
sd_date = datetime.strptime(sd, '%Y-%m-%d') |
|
||||
if cdr_q: |
|
||||
cdr_q |= Q(calldate__date=sd_date) |
|
||||
else: |
|
||||
cdr_q = Q(calldate__date=sd_date) |
|
||||
except ValueError: |
|
||||
messages.add_message(self.request, messages.ERROR, _('Make sure that your date format is correct')) |
|
||||
if cdr_q is None: |
|
||||
cdr = AsteriskCDR.objects.all() |
|
||||
else: |
|
||||
cdr = AsteriskCDR.objects.filter(cdr_q) |
|
||||
return cdr |
|
||||
|
|
||||
|
|
||||
@method_decorator(login_decs, name='dispatch') |
|
||||
@method_decorator(permission_required('dialing_app.view_smsmodel'), name='dispatch') |
|
||||
class InboxSMSListView(BaseListView): |
|
||||
template_name = 'inbox_sms.html' |
|
||||
context_object_name = 'sms_messages' |
|
||||
model = SMSModel |
|
||||
|
|
||||
|
|
||||
@login_required |
|
||||
@only_admins |
|
||||
@permission_required('dialing_app.add_smsout') |
|
||||
def send_sms(request): |
|
||||
path = request.GET.get('path') |
|
||||
initial_dst = request.GET.get('dst') |
|
||||
if request.method == 'POST': |
|
||||
frm = SMSOutForm(request.POST) |
|
||||
if frm.is_valid(): |
|
||||
frm.save() |
|
||||
messages.success(request, _('Message was enqueued for sending')) |
|
||||
pidfile_name = '/run/dialing.py.pid' |
|
||||
try: |
|
||||
with open(pidfile_name, 'r') as f: |
|
||||
pid = int(f.read()) |
|
||||
run(['/usr/bin/kill', '-SIGUSR1', str(pid)]) |
|
||||
except FileNotFoundError: |
|
||||
print('Failed sending, %s not found' % pidfile_name) |
|
||||
if path: |
|
||||
return redirect(path) |
|
||||
else: |
|
||||
return redirect('dialapp:inbox_sms') |
|
||||
else: |
|
||||
messages.error(request, _('fix form errors')) |
|
||||
else: |
|
||||
frm = SMSOutForm(initial={'dst': initial_dst}) |
|
||||
return render(request, 'modal_send_sms.html', { |
|
||||
'form': frm, |
|
||||
'path': path |
|
||||
}) |
|
||||
|
|
||||
|
|
||||
class SmsManager(SecureApiView): |
|
||||
# |
|
||||
# Api view for management sms from dongle |
|
||||
# |
|
||||
http_method_names = ('get',) |
|
||||
|
|
||||
@staticmethod |
|
||||
def bad_cmd() -> JSONType: |
|
||||
return {'text': 'Command is not allowed'} |
|
||||
|
|
||||
@method_decorator(json_view) |
|
||||
def get(self, request, *args, **kwargs): |
|
||||
cmd = request.GET.get('cmd') |
|
||||
data = request.GET.dict() |
|
||||
handler = getattr(self, cmd.lower(), self.bad_cmd) |
|
||||
del data['cmd'] |
|
||||
del data['sign'] |
|
||||
return handler(**data) |
|
||||
|
|
||||
@staticmethod |
|
||||
def save_sms(**kwargs) -> JSONType: |
|
||||
sms = SMSModel.objects.create( |
|
||||
who=kwargs.get('who'), |
|
||||
dev=kwargs.get('dev'), |
|
||||
text=kwargs.get('text') |
|
||||
) |
|
||||
return {'status': 'ok', 'sms_id': sms.pk} |
|
||||
|
|
||||
@staticmethod |
|
||||
def update_status(**kwargs) -> JSONType: |
|
||||
msg_id = safe_int(kwargs.get('mid')) |
|
||||
if msg_id != 0: |
|
||||
status = kwargs.get('status') |
|
||||
update_count = SMSOut.objects.filter(pk=msg_id).update(status=status) |
|
||||
return { |
|
||||
'text': 'Status updated', |
|
||||
'update_count': update_count |
|
||||
} |
|
||||
return {'text': 'Bad mid parameter'} |
|
||||
|
|
||||
@staticmethod |
|
||||
def get_new() -> JSONType: |
|
||||
msgs = SMSOut.objects.filter(status='nw').defer('status') |
|
||||
res = [{ |
|
||||
'when': round(m.timestamp), |
|
||||
'dst': m.dst, |
|
||||
'text': m.text |
|
||||
} for m in msgs] |
|
||||
return res |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue