понедельник, 10 декабря 2012 г.

[NoDeny] Создание плагина

Как я создавал новый плагин для системы биллинга NoDeny (версия 50.32).

1. Создать файл, в котором будет помещаться текст нового плагина, например, web/Sactivate.pl. В файле пока создал пустую подпрограмму с именем 'ACT_main'.

2. Отредактировать файл конфигурации биллинга nodeny.cfg.pl, а именно, в массив @Plugins дописать имя своего модуля, например, 'Sactivate'.



3. Отредактировать файл конфигурации плагинов web/plugin_reestr.cfg. Необходимо добавить в новой строке описание плагина, содержащее код плагина (номер должен быть уникальным, номер с 1 по 199 зарезервированы разработчиками для будущих модулей, поэтому я выбрал номер 500). Далее идёт имя плагина, в качестве которого используется имя файла плагина без расширения (В моём случае это 'Sactivate'). Далее необходимо указать имя главной программы, у меня это 'ACT_main'). Следующий параметр - название плагина, которое будет отображаться в меню. У меня это 'Активация'. Далее идёт флаг, определяющий публичный это плагин, или доступен только админу. Значение 1 означает доступность только админу, значение 0 - публичный. Я прописал 0. Последнее поле это перечень полей, которые являются ключевыми в URL. Поля перечисляются через запятую. Если писать в это поле нечего, необходимо прописать туда '0', что я и сделал. Итого, у меня получилась такая строка:

'500      Sactivate       ACT_main     Активация    0     0'

Внимание, параметры этой строки обязательно должны разделяться символами табуляции (с пробелами будет работать неправильно).

4. Не нашел стандартного способа динамически исключать плагин из списка доступных. В моём случае, кнопка вызова плагина активации должен исчезнуть из меню статистики после выполнения самой активации.

5. В составе системы есть файл calls.pl - это библиотека полезных процедур, многие из которых предназначены для генерации разного рода HTML-кода.
Вот список доступных процедур:

sub_zeroпустая процедура, ничего не делает
Go_out
DEBUG
DEBUGX
DebugError
Exit
VerWrong
divОбернуть данные в тэг <div>. Три параметра: имя класса, сам текст и флаг указывающий на необходимость вывода в конце тэга <br>.
Good_Exit
GoodC_Exit
Filtr
Filtr_all
Filtr_outФильтрует символы, которые являются управляющими для html
Filtr_sql
Filtr_mysql
Show_allэкранирование для html, замена \n на <br>, преобразование:
~url(текст1~)(текст2~) -> <a href='текст1'>текст2</a>
~frame(текст~) -> <div class=borderblue>текст</div>
~img(урл~) -> <img src='урл'>
~bold(текст~) -> <b>текст</b>
Знак ~ не должен встречаться в тексте!
URLEncodeкодирование спецсимволов и кирилицы в вид %xx пригодном для url
Get_fieldsИзвлекает из $p (ссылка на хеш данных о клиенте) массив значений, соответствующих массиву переданных наименований полей
Get_filtr_fields
split_nпреобразует число к виду '12 345 678'
lc_rusПриведение символов строки к нижнему регистру (только кириллица)
Вход:
 0 - исходная строка
Выход:
 преобразованная строка
translitПреобразование строки из кириллицы в транслит
Вход:
 0 - исходная строка
Выход:
 преобразованная строка
trimУдаляет пробельные символы в начале и в конце строки
Вход:
 0 - исходная строка
Выход:
 преобразованная строка
MessageВывод сообщения в рамке
Вход:
 0 - сообщение
 1 - [картинка]
 2 - [заголовок под картинкой]
 3 - [текст после сообщения в рамке]
 4 - [стиль рамки сообщения], если не задан, то 'message'
 5 - [количество переводов строк перед картинкой], если не указано, то принимается = количество переводов строк в тексте минус 5
Message_ExitВывод сообщения, завершение страницы и выход
Вход: все параметры передаются подпрограмме Message
ErrorMessВывод окна с ошибкой
Вход:
 0 - текст
 1 - [текст после сообщения в окне]
ErrorВывод окна с ошибкой и выход
Вход:
 0 - текст
 1 - [текст после сообщения в окне]
OkMessВывод окна OK
Вход:
 0 - текст
 1 - [текст после сообщения в окне]
 2 - [картинка], если не указана, то выводится ok.gif. Если указана 'nopic' - не выводится вообще
MessXПодпрограмма &MessX формирует рамку вокруг текста. В NoDeny есть несколько вариантов формирования блоков с рамками. &MessX рекомендуется применять для небольших блоков текста. Особенностью является то, что рамка не имеет отступы по бокам, а также не занимает всю доступную ширину, а только ширину объекта, который обрамляет.
Вход:
 0 - текст сообщения
 1 - флаг, указывающий, использовать или нет тэг <br> перед и после текста
 2 - флаг, указывающий, добавлять или нет после сообщения тэг <br>
Mess0
Mess2
Mess3Формирует рамку, обычно применяемую для менюшек, вокруг 'данных'
T_Head
Error
boldДелает текст "жирным"
Вход:
 0 - текст
bold_brВыделяет текст "жирным" и пустыми строками выше и ниже
Вход:
 0 - текст
commasПомещает текст внутрь кавычек "елочек"
Вход:
 0 - текст
tagФормирование тега HTML    
Вход:
 0 - тег HTML
 1 - данные тега
 2 - атрибуты тега
Start_Row
PRow
RRow
Table
table
Center
Center_Mess
ahref
CenterA
Printf
input_hФормирование элемента <input> типа hidden
Вход: имя элемента, значение. Значение фильтруется по &Filtr_out
input_tФормирование элемента <input> типа text
Вход: имя элемента, значение, размер, максимальная длина, доп.данные
input_taимя, значение, колонок, строк
FormSubmitEvent
form_a
form
submit_a
submit
Post_To_GetКонвертация хеша (имя => значение) в "&имя=значение&имя=значение". Значения фильтруются &Filtr_out
Вход: ссылка на хеш
Del_Sort_Prefix
SetCharSetУстановка кодировки БД в cp1251
sql_select_lineВыборка одной строки из таблицы БД
 0 - ссылка dbh
 1 - sql-запрос
 2 - [комментарий]
 3 - [скрытый запрос]
Выход: хэш со значениями полей запроса
sqlВыборка нескольких строк из таблицы БД
 0 - ссылка dbh
 1 - sql-запрос
 2 - [комментарий]
 3 - [скрытый запрос]
Выход: ссылка на ->execute
sql_doПредназначена для выполнения запросов обновления (INSERT, UPDATE, DELETE).
Вход:
 0 - ссылка dbh
 1 - sql-запрос
 2 - [комментарий]
 3 - [скрытый запрос]
Выход: количество обновленных строк либо ноль, если ошибка.
Обратите внимание, что количество обновленных строк может быть равно нулю, но это не будет означать ошибку, Т.е. условию будет соответствовать 0 строк. Эта ситуация разруливается стандартным методом: если ошибки нет и обновлено 0 строк, то возвращается значение, которое НЕ является нулем, однако при сравнении РАВНО нулю. Возможно, это выглядит как хак, однако это вполне неормально для perl.
the_timeВремя в виде dd.mm.gg hh:mm
the_hourВремя в виде hh:mm
the_short_timeВремя в виде dd.mm.gg hh:mm или hh:mm, если день равен текущему
 Вход:
 0 - время
 1 - текущее время
 2 - если установлен (XXX) и день = текущему, то возврат:
     XXX=1 :  сегодня в hh:mm
     XXX!=1:  <span class='XXX'>hh:mm</span>
the_dateВремя в виде dd.mm.gggg
the_hh_mmПереводит минуты в часы и минуты
ToLogЗапись сообщения в лог
Вход: сообщение
Set_mon_in_listФормирования выпадающего списка с месяцами с заданным активным месяцем
Вход: № месяца (1-12)
Возврат:
 1 - выпадающий список
 2 - название месяца
Set_year_in_listФормирования выпадающего списка с годами и selected делается запрошенный год
Вход: год (отсчет от нуля!)
Возврат: выпадающий список
GetMaxDayInMonthВозвращает максимальное число дней в запрошенном месяце
Вход: месяц (1..12), год (0..ххх)
Show_navigate_listФормирование кнопочек с сылками на страницы если результат sql-запроса не вмещается на страницу
Вход:
 0 - sql-запрос без команды LIMIT и обязательно начинающийся с SELECT
 1 - номер страницы, которая должна быть выведена
 2 - максимальное количество записей на страницу
 3 - урл, который будет вписан в кнопочки (в урл будут добавлены строки &start=xx)
 4 - [$dbh], по умолчанию берет текущую $dbh
 5 - [строк] - если указано, то указание общее количество строк считать таким
Выход:
 0 - sql-запрос с проставленными LIMIT
 1 - html с кнопочками
 2 - общее количество строк в полном запросе
 3 - указатель на $sth c сформированным результатом, т.е для которого можно сделать $sth->fetchrow_hashref
Get_Office_ListФормирование выпадающего списка отделов
Вход: № отдела, который необходимо выделить в списке
Выход: список отделов
Get_admsФормирование списка админов
Возврат:
 0 - ссылка на хеш со списком админов (везде &Filtr)
 1 - ссылка на отсортированный массив со списком id админов
Get_usersВход:
 0 - если установлен, то извлекаются данные только этого клиента (учитывая алиасы)
Get_workersВход:
 0 - если установлен, то извлекаются данные только этого работника
Возврат:
 0 - ссылка на хеш со списком работников (&Filtr применен)
ShowModeAuthПоказывает режим авторизации в виде ключика определенного цвета
ShowClientФормирование url-а на данные клиента
Вход:
 1 - id
 2 - отображаемая в ссылке строка, например логин
 3 - [что будет выведено в ссылке если нет прав на просмотр ФИО], если параметр не задан, то выводится ссылка: id=номер
ShowUserInfoВход:
 1 - id клиента
Возврат:
 0 - html-таблица с данными клиента
 1 - группа клиента
 2 - id основной записи
 3 - ip
GetClientTraf
GetProtoПолучение имени протокола по его номеру
Вход:
 1 - номер протокола
 2 - порт или номер icmp
Выход:
 1 - строка с названием протокола, подкрашивается в нужный цвет
 2 - пустая строка либо ' class=xxxx' - css для подкрашивания строки
Check_Ip_in_NetsПроверка попадания ip в одну из заданных подсетей
Вход:
 1 - ip,
 2 - список подсетей в виде xx.xx.xx.xx/yy, если подсеть одна, то все равно передавать как список из одного элемента
Возврат: 1 - попал, 0 - нет
Get_list_of_stat_daysФормирование списка дней на которые есть статистика трафика
Вход:
 1 - $dbh
 2 - тип таблицы: 'x','y' или 'z'
 3 - url для сылок
 4 - [любой time дня, на который показана статистика, будет выделен]
Get_list_of_login_days
List_select_grpФормирование списка групп, включая объединения групп, с возможностью пометить некоторые группы галками
Если, например, $F{g5} установлена, то галка с id=g5 делается активной
Возврат:
 0 - html-список
 1 - список выбранных групп, разделенных запятыми
Print_trafВозвращает трафик в указанных единицах измерения
Вход:
 0  - трафик
 1  - единица измерения
 [2] - период времени
Ед.изм:
 7 мбайт/сек
 6 кбит/сек
 5 кбайт/сек
 4 байт
 3 целые кбайт
 2 кбайт
 1 целые Мбайт
 0 Мбайт
SmtpОтправка сообщения на мыло админу(ам)
Вход: сообщение, [email], [email от кого]
Send_smtpПередаёт почтовому серверу блок данных, затем читает ответ. В случае указания в ответе на ошибку, возвращает эту ошибку.
Вход:
 0 - блок данных (текст)
Выход:
 строка-ошибка из ответа почтового сервера в случае ошибки
DB2_ConnectПодключается к серверу базы данных, используя переменные $DSS,$user,$pw. Дескриптор соединения сохраняет в переменной $dbs
LoadModЗагружает данный модуль. В случае ошибки выводит соответствующее диагностическое сообщение.
Вход:
 0 - имя файла
 1 - наименование модуля
LoadMoneyMod
LoadPaysTypeMod
LoadJobMod
LoadNetMod
LoadEquipMod
LoadDopdataMod

6. В хэше %F содержатся переменные, которые клиент передает через браузер.

7. В списке всех таблиц есть две таблицы, с помощью которых можно произвольно расширять набор параметров, хранящих информацию о клиенте. Это таблицы dopfields и dopvalues (а также вьюшка, объединяющая обе таблицы - dopdata). Таблица dopfields описывает названия параметров и их характеристики, а таблица dopvalues хранит сами значения этих параметров.
Короткое описание некоторых полей таблицы dopfields:
 - field_type - тип поля. Доступны следующие типы полей: 0 - целочисленное, 1 - целочисленное положительное, 2 - вещественное, 3 - вещественное положительное; 4 - строковое однострочное; 5 - строковое многострочное; 6 - логическое (да/нет, 0/1); 7 - привязка к объекту (не знаю, не видел примеров); 8 - выпадающий список (данные выбираются из БД, параметры для выбора данных находятся в поле field_type); 9 - пароль. Любое другое значение типа - это текстовое многострочное значение.

По поводу поля  template_num пока не совсем понятно. Скорее всего используется для группировки параметров для вывода их на определённую страницу раздела настроек. На данный момент имеет всего два значения (1 и 2). Для активации задействовал значение 3 (когда установил значение 2, это поле автоматически появилось в форме редактирования адреса).

Поле field_flags содержит перечень флагов. Вот значения этих флагов: 'a' - допускается пустое значение; 'b' - убирать пробелы вначале, 'c' - убирать пробелы в конце; 'd' - преобразовать к нижнему регистру; 'e' - транслировать в латинские символы; 'f' - убрать все пробелы; 'q' - титульное поле (выводится при поиске).

Таким образом, чтобы добавить новый параметр, необходимо занести в таблицу следующую информацию:

insert into dopfields (id, template_num, parent_type, field_type, field_name, field_alias, field_flags, field_template, comment) values (0, 3, 0, 6, 'Активация', 'activation', 'abc', '', '');

Предусмотрен механизм ревизий - при изменении данных, старые значения сохраняются, а новые добавляются с бОльшим номером ревизии. Благодаря этому появляются такие возможности:

1) Нет необходимости вести логи изменений т.к. в каждой ревизии есть поле `администратор, внесший изменения`;
2) Возможность вернуться к любой версии данных;
3) В удаленных модулях нет необходимости постоянно отслеживать изменения данных - достаточно мониторить изменения ревизий. Например, в модуле управления фаерволом используются данные по персональным скоростям, которые извлекаются из таблицы dopdata когда обнаружено их изменение по номеру ревизии;
4) При параллельном редактировании данных не будет конфликтных ситуаций.

Ревизия для значения хранится в поле revision таблицы dopvalues.

8. Внутри своего модуля можно вызывать другой существующий модуль. Вот так, например, я загрузил модуль Ssetpacket.pl и вызывал его подпрограмму SP_SetPaket():

   my $Ssetpacket="$Nodeny_dir/web/Ssetpacket.pl";
   require $Ssetpacket;
   &{ 'SP_SetPaket' };


9. Здесь должно быть описание подпрограмм модуля Ssetpacket.pl...

Комментариев нет:

Отправить комментарий