Создание собственных интерфейсов панели управления

Материал из ISPWiki

Перейти к: навигация, поиск

Рассмотрим пример создания интерфейса для редактирования списка абстрактных элементов

Постановка задачи

  • Имеем панель управления ISPmanager
  • Файле /etc/myconf хранится список элементов, для редактирования которых необходимо создать интерфейс

Действия

1) Создаем файл описания плагина /usr/local/ispmgr/etc/ispmgr_mod_myconf.xml со следующим содержимым

 <?xml version="1.0" encoding="UTF-8"?>
 <mgrdata>
     <handler name="myconf.pl" type="cgi">
       <func>myconf</func>
       <func>myconf.edit</func>
       <func>myconf.delete</func>
    </handler>
 
    <mainmenu level="7">
      <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>

2) Создаем файл обработчик /usr/local/ispmgr/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/>";
 }

3) Устанавливаем права на файл обработчик

chmod 750 /usr/local/ispmgr/addon/myconf.pl
chown 0:0 /usr/local/ispmgr/addon/myconf.pl

4) Перезапускаем ISPmanager

Пояснения

Описываем скрипт-обработчик и указываем что он будет выполняться при вызове наших собственных функций, описание выглядит аналогично описанию событий, только вместо тэга event мы теперь используем тэг func

   <handler name="myconf.pl" type="cgi">
      <func>myconf</func>
      <func>myconf.edit</func>
      <func>myconf.delete</func>
   </handler>

Описываем ссылку в меню, так же как мы это делали ранее

   <mainmenu level="7">
     <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 может содержать несколько имен, разделенных символами ", " (запятая и пробел). Формируем массив удаляемых элементов, далее читаем наш файл с данными и удаляем из него строки содержащиеся в массиве удаляемых элементов.

Была ли эта информация полезной? Да | Нет
Личные инструменты