Разработка дополнительных своих модулей
Рассмотрим пример создания интерфейса для редактирования списка абстрактных элементов
Постановка задачи
- Есть панель управления ISPmanager;
- В файле /etc/myconf хранится список элементов, для редактирования которых необходимо создать интерфейс.
Порядок действий
- Создайте файл описания плагина /usr/local/mgr5/etc/xml/ispmgr_mod_myconf.xml со следующим содержимым:
<?xml version="1.0" encoding="UTF-8"?> <mgrdata> <handler name="myconf" type="cgi"> <func name="myconf"/> <func name="myconf.edit"/> <func name="myconf.delete"/> </handler> <mainmenu level="30"> <node name="tool"> <node name="myconf"/> </node> </mainmenu> <metadata name="myconf" type="list" key="item"> <toolbar> <toolbtn func="myconf.edit" type="new" img="t-new" name="new"/> <toolbtn func="myconf.edit" type="edit" img="t-edit" name="edit" default="yes"/> <toolbtn func="myconf.delete" type="group" img="t-delete" name="delete"/> </toolbar> <coldata> <col sort="alpha" sorted="yes" name="item" type="data"/> </coldata> </metadata> <metadata name="myconf.edit" type="form"> <form> <field name="item"> <input type="text" name="item"/> </field> </form> </metadata> <lang name="en"> <messages name="desktop"> <msg name="menu_myconf">Test module</msg> </messages> <messages name="myconf"> <msg name="title">Test module</msg> <msg name="item">Item from myconf</msg> <msg name="msg_myconf_delete">Delete item </msg> <msg name="hint_new">New item</msg> <msg name="hint_edit">Edit item</msg> <msg name="hint_delete">Delete item</msg> </messages> <messages name="myconf.edit"> <msg name="title">Edit item</msg> <msg name="title_new">New item</msg> <msg name="item">Item value</msg> <msg name="hint_item">The value of the item from myconf</msg> </messages> </lang> <lang name="ru"> <messages name="desktop"> <msg name="menu_myconf">Тестовый модуль</msg> </messages> <messages name="myconf"> <msg name="title">Тестовый модуль</msg> <msg name="item">Элемент из myconf</msg> <msg name="msg_myconf_delete">Удалить элемент </msg> <msg name="hint_new">Новый элемент</msg> <msg name="hint_edit">Редактировать элемент</msg> <msg name="hint_delete">Удалить элемент</msg> </messages> <messages name="myconf.edit"> <msg name="title">Редактировать элемент</msg> <msg name="title_new">Новый элемент</msg> <msg name="item">Значение</msg> <msg name="hint_item">Значение элемента из myconf</msg> </messages> </lang> </mgrdata>
- Создайте файл обработчик /usr/local/mgr5/addon/myconf.pl со следующим содержимым:
#!/usr/bin/perl use CGI qw/:standard/; $Q = new CGI; $func = $Q->param(func); print "<doc>"; if( $func eq "myconf" ){ &List; } elsif( $func eq "myconf.delete" ){ &Delete; } elsif( $func eq "myconf.edit" ){ if( $Q->param( "sok" ) ){ if( $Q->param( "elid" ) ){ &Set; } else{ &New; } print "<ok/>"; } else{ &Get; } } print "</doc>"; exit 0; sub List { if( open( IN, "/etc/myconf" ) ){ while( <IN> ){ chomp; print "<elem><item>$_</item></elem>"; } close( IN ); } } sub Get { $elid = $Q->param( "elid" ); print "<elid>$elid</elid><item>$elid</item>" if( $elid ); } sub Set { $elid = $Q->param( "elid" ); $item = $Q->param( "item" ); if( open( IN, "/etc/myconf" ) ){ if( open( OUT, ">/etc/myconf.new" ) ){ for( <IN> ){ chomp; if( $_ eq $elid ){ print OUT "$item\n"; $ok = 1; } else { print OUT "$_\n"; } } close( OUT ); } close( IN ); } if( $ok ){ rename( "/etc/myconf.new", "/etc/myconf" ); print "<ok/>"; } else { print "<error>Item hasn`t been updated</error>"; } } sub New { $item = $Q->param( "item" ); if( open( ADD, ">>/etc/myconf" ) ){ print ADD "$item\n"; close( ADD ); print "<ok/>"; } else { print "<error>Item hasn`t been added</error>"; } } sub Delete { @all_elem = split(", ", $Q->param( "elid" )); if( open( IN, "/etc/myconf" ) ){ if( open( OUT, ">/etc/myconf.new" ) ){ for( <IN> ){ chomp; $found = "0"; for my $elid (@all_elem) { if ($elem eq $_) { $found = "1"; last; } } print OUT "$_\n" if( $found ne "1" ); } close( OUT ); } close( IN ); } rename( "/etc/myconf.new", "/etc/myconf" ); print "<ok/>"; }
- Устанавите права на файл обработчик:
chmod 750 /usr/local/mgr5/addon/myconf.pl chown 0:0 /usr/local/mgr5/addon/myconf.pl
- Перезапустите ISPmanager:
/usr/local/mgr5/sbin/mgrctl -m ispmgr exit
Пояснения
Создайте описание скрипта-обработчик и укажите, что он будет выполняться при вызове собственных функций. Описание выглядит аналогично описанию событий, только вместо тега event используется тег func:
<handler name="myconf.pl" type="cgi">
<func>myconf</func>
<func>myconf.edit</func>
<func>myconf.delete</func>
</handler>
Опишите ссылку в меню:
<mainmenu level="30">
<node name="tool">
<node name="myconf"/>
</node>
</mainmenu>
Опишите, как будет выглядеть таблица с данными:
<metadata name="myconf" type="list" key="item">
<toolbar>
<toolbtn func="myconf.edit" type="new" img="t-new" name="new"/>
<toolbtn func="myconf.edit" type="edit" img="t-edit" name="edit" default="yes"/>
<toolbtn func="myconf.delete" type="group" img="t-delete" name="delete"/>
</toolbar>
<coldata>
<col sort="alpha" sorted="yes" name="item" type="data"/>
</coldata>
</metadata>
В нашем примере, таблица с данными имеет одну колонку, а панель инструментов 3 кнопки: создать, изменить, удалить. Более подробное описание тегов и атрибутов смотрите в Описание списков.
Опишите, как будет выглядеть форма редактирования:
<metadata name="myconf.edit" type="form">
<form>
<field name="item">
<input type="text" name="item"/>
</field>
</form>
</metadata>
В этом примере, форма имеет всего одно поле ввода. Более подробное описание тегов и атрибутов см. в статье Описание форм.
Далее опишите текстовые сообщения для наших новых интерфейсов, для понимания каким образом формируются имена сообщений см. статью Правила именования сообщений
Перейдем к рассмотрению скрипта обработчика.
Получите данные, и определить имя вызываемой функции:
use CGI qw/:standard/;
$Q = new CGI;
$func = $Q->param(func);
В зависимости от вызванной функции вызовите соответствующую процедуру:
if( $func eq "myconf" ){
&List;
} elsif( $func eq "myconf.delete" ){
&Delete;
} elsif( $func eq "myconf.edit" ){
if( $Q->param( "sok" ) ){
if( $Q->param( "elid" ) ){
&Set;
} else{
&New;
}
print "<ok/>";
} else{
&Get;
}
}
Вывод списка данных:
sub List {
if( open( IN, "/etc/myconf" ) ){
while( <IN> ){
chomp;
print "<elem><item>$_</item></elem>";
}
close( IN );
}
}
Считайте построчно файл с данными /etc/myconf и сформируйте XML-документ с данными. Тег elem — обозначает строку данных, и содержит в себе дочерние элементы описывающие данные по столбцам, имя вложенного тега item может быть произвольным, но должно соответствовать атрибуту name в описании столбца таблицы (тег col).
Чтение данных при открытии формы редактирования элемента:
sub Get {
$elid = $Q->param( "elid" );
print "<elid>$elid</elid><item>$elid</item>" if( $elid );
}
Данная функция будет вызвана при открытии формы редактирования, для случая создания и для редактирования имеющегося элемента. В случае если параметр elid не пустой, значит элемент редактируется. Данный параметр содержит значение из колонки списка с именем указанным в атрибуте key тега metadata при описании интерфейса таблицы с данными.
Поскольку в примере достаточно простой интерфейс и форма содержит всего одно поле данных, из файлов ничего не читается, а просто возвращается параметр запрашиваемого элемента. лучшим вариантом будет проверить наличие элемента в файле с данными и в случае его отсутствия вывести ошибку. Тег elid указывает ключевое значение для редактируемого элемента, оно же будет отображено в заголовке формы. Тег item в примере содержит значение, которое будет отображено в поле ввода с именем item.
Редактирование записи:
sub Set {
$elid = $Q->param( "elid" );
$item = $Q->param( "item" );
.......
}
При редактировании записи важны 2 параметра. elid — содержит имя (ключевое поле) редактируемого элемента, а параметр item значение введенное пользователем в поле с именем item. Далее нужно прочитать файл с данными, найти в нём элемент из параметра elid и заменить его значение на значение параметра item. Если искомый элемент не найден, то вывести сообщение об ошибке.
Создание нового элемента:
sub New {
$item = $Q->param( "item" );
if( open( ADD, ">>/etc/myconf" ) ){
print ADD "$item\n";
close( ADD );
print "<ok/>";
} else {
print "<error>Item hasn`t been added</error>";
}
}
Нужно взять значение из параметра item и добавить его в конец файла с данными. Если файл не удалось открыть по каким-то причинам, то вывести сообщение об ошибке.
Удаление элемента списка:
sub Delete {
@all_elem = split(", ", $Q->param( "elid" ));
......
}
Поскольку операция удаления является групповой, то есть за один вызов можно удалить несколько элементов, то параметр elid может содержать несколько имен, разделенных символами ", " (запятая и пробел). Сформируйте массив удаляемых элементов, далее прочитайте файл с данными и удалите из него строки содержащиеся в массиве удаляемых элементов.