Дмитрий Кайдаш
19.02.2019
274

Ограничение внутренних вызовов через AstDB

В данной статье будет рассмотрен способ настройки ограничения внутренней связи по группам. Задачи: 1. Разрешить вызов внутреннего номера только группе номеров 2. Разрешить внутреннему номеру вызов ограниченной группы номеров Для решения поставленных задач нам понадобится создать отдельный custom-context для целевого внутреннего номера. Создаём новый connectivity->custom-context->Add context Выставляем необходимые внешние маршруты, как входящие так и исходящие, […]

В данной статье будет рассмотрен способ настройки ограничения внутренней связи по группам.

Задачи:

1. Разрешить вызов внутреннего номера только группе номеров

2. Разрешить внутреннему номеру вызов ограниченной группы номеров

Для решения поставленных задач нам понадобится создать отдельный custom-context для целевого внутреннего номера. Создаём новый connectivity->custom-context->Add context

Выставляем необходимые внешние маршруты, как входящие так и исходящие, при этом запрещая все внутренние.

Создаём контекст

После чего назначаем внутреннему номеру новый контекст:

Назначаем контекст

И приступаем непосредственно к обработке логики диалпланом. Допустим нам необходимо разрешить вызов номера директора только от заместителя и представителей руководства. Номер первого: 771. Группа разрешенных номеров: 117, 131, 136, 169, 186, 194, 501, 508, 514, 540, 701, 702, 736, 901, 908, 921.

Небольшое отступление: причина использовать базу, не воспользовавшись стандартными возможностями диалплана asterisk вида:

exten => 771/_[1579][0-4689][ 1246-9],1,...

Очень проста. Во-первых чтобы поменять допустимое значение потребуется переписывать конфигурационный файл extensions_custom.conf и контекст [from-internal-custom], в частности. После чего будет необходимо выполнить применение настроек командой: dialplan reload. Что не всегда возможно и удобно. В тоже время добавив один раз небольшие правки в диалплан и AstDB мы получим гибкую систему настройки. Помимо прочего, которой можно будет управлять извне, какими-либо средствами.

Приступим к заполнению базы нашими номерами. Для этого потребуются следующие команды CLI-консоли:

  • добавление одной записи:
# asterisk -rx 'database put 771_ALLOW 115 1'
  • удаление одной записи:
 asterisk -rx 'database del 771_ALLOW 115'
  • удаление древа записей:
# asterisk -rx 'database deltree 771_ALLOW'
  • просмотр текущего древа:
# asterisk -rx 'database show 771_ALLOW'
Проверяем записи в AstDB

Подробнее о работе с AstDB рассказано в статье.

И наконец обработчик в диалплане будет выглядеть следующим образом:

; ------------------ Inbount calls ------------------
exten => 771,1,GotoIf(${DB_EXISTS(${EXTEN}_ALLOW/${CALLERID(num)})}?from-internal-additional,${EXTEN},1)
same => n,Busy(5)
same => n,Hangup

Здесь мы разрешаем вызов номера 771 только номерам разрешенным в базе.

; ------------------ Outbound calls ------------------
[for-771-custom]
exten => _X.,1,GotoIf(${DB_EXISTS(771_ALLOW/${EXTEN})}?from-internal,${EXTEN},1)
same => n,Busy(5)
same => n,Hangup

Здесь разрешаем самому внутреннему номеру 771 вызывать только номера указанные в базе. Остальным будет выдан сигнал “занято” и вызов завершится.

Как уже говорилось ранее, добавить в файл extensions_custom.conf, контекст [from-internal-custom]

Web-интерфейс

Пример приложения

Упростим эксплуатацию так, чтобы она была доступна пользователям без прямого доступа в терминал сервера. Для этого понадобится редактор и некоторый интерфейс, который будет переписывать значения в базе. Его можно написать самостоятельно или воспользоваться кодом ниже. Используем возможность гибридизации html и php для сокращения размера кода и наглядности. Подробных пояснений к разметке давать не будем, пройдёмся лишь по скриптам-обработчикам. Первый фрагмент:

$exec_out_1=[];
exec('mysql -u freepbxuser -pd45c7ea6a5460b03300977b1cd61f148 -D asterisk -N -e "select id from devices"',$exec_out_1);
foreach($exec_out_1 as $element){
	$check=($_POST['for_exten']==$element)?'checked':'';
	echo '<label><input type="radio" name="for_exten" value="'.$element.'" '.$check.' />'.$element.'</label>';
};

Объявляем массив для хранения переменных, запрашиваем у системы список внутренних номеров и сохраняем в нём. После чего выполняем проход по массиву и генерируем html-элементы соответствующие типу radio (для однозначного выбора).

Второй:

if(isset($_POST['give'],$_POST['for_exten'])){
	$exec_out_2=[];
	exec('asterisk -rx "database show IN_ALLOW_'.$_POST['for_exten'].'" | grep IN_ALLOW_',$exec_out_2);
	foreach($exec_out_1 as $element){
		$check=(in_array('/IN_ALLOW_'.$_POST['for_exten'].'/'.$element.'                                 : 1',$exec_out_2))?'checked':'';
		echo '<label><input type="checkbox" name="granted_in[]" value="'.$element.'" '.$check.' />'.$element.'</label>';
	};
}
if(isset($_POST['send'],$_POST['for_exten'],$_POST['granted_in'])){
	exec('asterisk -rx "database deltree IN_ALLOW_'.$_POST['for_exten'].'"',$null);
	foreach($_POST['granted_in'] as $element){
		exec('asterisk -rx "database put IN_ALLOW_'.$_POST['for_exten'].' '.$element.' 1"',$null);
	}
}
elseif(isset($_POST['send'],$_POST['for_exten'])){
	exec('asterisk -rx "database deltree IN_ALLOW_'.$_POST['for_exten'].'"',$null);
}

Здесь возможно три развития событий в зависимости от аргументов POST-запроса:

  1. Внутренний номер «for_exten» и параметр запроса «give».
    Получаем в массив все разрешения, выполнив запрос в AstDB, для текущего выбранного номера. После чего перебираем все внутренние номера и в зависимости от наличия в новом массиве строки разрешения генерируем html-элементы checkbox (для множественного выбора) в активном или пассивном состоянии.
  2. Внутренний номер «for_exten» и параметр сохранения «send».
    Удаляем древо базы AstDB по текущему выбранному номеру. Таким образом реализована очистка базы если не выбран ни один разрешенный номер.
  3. Внутренний номер «for_exten», параметр запроса «give» и массив новых правил «granted_in»

Выполняем перебор всех переданных правил и вносим их в AstDB под соответствующее древо и внутренний номер.

Третий:

if(isset($_POST['give'],$_POST['for_exten'])){
	$exec_out_3=[];
	exec('asterisk -rx "database show OUT_ALLOW_'.$_POST['for_exten'].'" | grep OUT_ALLOW_',$exec_out_3);
	foreach($exec_out_1 as $element){
		$check=(in_array('/OUT_ALLOW_'.$_POST['for_exten'].'/'.$element.'                                : 1',$exec_out_3))?'checked':'';
		echo '<label><input type="checkbox" name="granted_out[]" value="'.$element.'" '.$check.' />'.$element.'</label>';
	};
}
if(isset($_POST['send'],$_POST['for_exten'],$_POST['granted_out'])){
	exec('asterisk -rx "database deltree OUT_ALLOW_'.$_POST['for_exten'].'"',$null);
	foreach($_POST['granted_out'] as $element){
		exec('asterisk -rx "database put OUT_ALLOW_'.$_POST['for_exten'].' '.$element.' 1"',$null);
	}
}
elseif(isset($_POST['send'],$_POST['for_exten'])){
	exec('asterisk -rx "database deltree OUT_ALLOW_'.$_POST['for_exten'].'"',$null);
}

Выполняется аналогично трём пунктам предыдущего фрагмента с заменой наименования древа: с IN_ALLOW_<номер> на OUT_ALLOW_<номер>.

Совместив это всё с разметкой получим следующий скрипт:

<html>
	<head>
		<title>CallLimit</title>
		<link rel="shortcut icon" href="favicon.png" type="image/png">
		<link rel="stylesheet" href="style.css" type="text/css">
	</head>
	<body>
		<form action="" method="post">
			<fieldset>
				<legend>Ограничения вызовов</legend>
				<fieldset class="subfield">
					<legend>Внутренний номер</legend>
					<?php
						$exec_out_1=[];
						exec('mysql -u freepbxuser -pd45c7ea6a5460b03300977b1cd61f148 -D asterisk -N -e "select id from devices"',$exec_out_1);
						foreach($exec_out_1 as $element){
							$check=($_POST['for_exten']==$element)?'checked':'';
							echo '<label><input type="radio" name="for_exten" value="'.$element.'" '.$check.' />'.$element.'</label>';
						};
					?>
				</fieldset>
				<fieldset class="subfield">
					<legend>Входящие</legend>
					<?php
						if(isset($_POST['give'],$_POST['for_exten'])){
							$exec_out_2=[];
							exec('asterisk -rx "database show IN_ALLOW_'.$_POST['for_exten'].'" | grep IN_ALLOW_',$exec_out_2);
							foreach($exec_out_1 as $element){
								$check=(in_array('/IN_ALLOW_'.$_POST['for_exten'].'/'.$element.'                                 : 1',$exec_out_2))?'checked':'';
								echo '<label><input type="checkbox" name="granted_in[]" value="'.$element.'" '.$check.' />'.$element.'</label>';
							};
						}
						if(isset($_POST['send'],$_POST['for_exten'],$_POST['granted_in'])){
							exec('asterisk -rx "database deltree IN_ALLOW_'.$_POST['for_exten'].'"',$null);
							foreach($_POST['granted_in'] as $element){
								exec('asterisk -rx "database put IN_ALLOW_'.$_POST['for_exten'].' '.$element.' 1"',$null);
							}
						}
						elseif(isset($_POST['send'],$_POST['for_exten'])){
							exec('asterisk -rx "database deltree IN_ALLOW_'.$_POST['for_exten'].'"',$null);
						}
					?>
				</fieldset>
				<fieldset class="subfield">
					<legend>Исходящие</legend>
					<?php
						if(isset($_POST['give'],$_POST['for_exten'])){
							$exec_out_3=[];
							exec('asterisk -rx "database show OUT_ALLOW_'.$_POST['for_exten'].'" | grep OUT_ALLOW_',$exec_out_3);
							foreach($exec_out_1 as $element){
								$check=(in_array('/OUT_ALLOW_'.$_POST['for_exten'].'/'.$element.'                                : 1',$exec_out_3))?'checked':'';
								echo '<label><input type="checkbox" name="granted_out[]" value="'.$element.'" '.$check.' />'.$element.'</label>';
							};
						}
						if(isset($_POST['send'],$_POST['for_exten'],$_POST['granted_out'])){
							exec('asterisk -rx "database deltree OUT_ALLOW_'.$_POST['for_exten'].'"',$null);
							foreach($_POST['granted_out'] as $element){
								exec('asterisk -rx "database put OUT_ALLOW_'.$_POST['for_exten'].' '.$element.' 1"',$null);
							}
						}
						elseif(isset($_POST['send'],$_POST['for_exten'])){
							exec('asterisk -rx "database deltree OUT_ALLOW_'.$_POST['for_exten'].'"',$null);
						}
					?>
				</fieldset>
				<div>
					<button name="give" value="ok">Получить</button>
					<button name="send" value="ok">Сохранить</button>
				</div>
			</fieldset>
		</form>
	</body>
</html>

Дополнительно в архиве есть закреплённый файл CSS-стилей и иконка.

Таким образом у нас есть интерфейс редактирования разрешений дозвона средствами внутренней базы asterisk AstDB.

Результат работы в базе

Остаётся лишь подкорректировать диалплан для работы с новыми записями. В файл

# nano /etc/asterisk/extensions_custom.conf

Внести следующте изменения в контекст [from-internal-custom]

exten => _XXX,1,GotoIf(${DB_EXISTS(IN_ALLOW_${EXTEN}/${CALLERID(num)})}?from-internal-additional,${EXTEN},1)
same => n,GotoIf(${DB_EXISTS(OUT_ALLOW_${CALLERID(num)}/${EXTEN})}?from-internal-additional,${EXTEN},1)
same => n,Busy(5)
same => n,Hangup

Из приведённых примеров видно, что на 200ый могут звонить 101,103,105,107,109. В то же время номер 200 может вызывать номера: 101-108. Таким образом реализовано ограничение внутренних звонков по номеру звонящего средствами внутренней базы AstDB.

 
avatar
  Подписаться  
Уведомление о

Остались вопросы?

Я - Першин Артём, менеджер компании Voxlink. Хотите уточнить детали или готовы оставить заявку? Укажите номер телефона, я перезвоню в течение 3-х секунд.

VoIP оборудование

ближайшие курсы

ближайшие Вебинары

ONLINE

Why Choose HUGE?

Unlimited pre-designed elements

Each and every design element is designed for retina ready display on all kind of devices

User friendly interface and design

Each and every design element is designed for retina ready display on all kind of devices

100% editable layered PSD files

Each and every design element is designed for retina ready display on all kind of devices

Created using shape layers

Each and every design element is designed for retina ready display on all kind of devices