Creating a custom control panel interfaces

From ISPWiki

Jump to: navigation, search

Following is an example on how to create an interface to edit a list of abstract elements.

Task

  • ISPmanager
  • The /etc/myconf file contains a list of elements, for which we need to create an interface

Solution

1) Create the file /usr/local/ispmgr/etc/ispmgr_mod_myconf.xml with the following contents

 <?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">Test module</msg>
      </messages>
      <messages name="myconf">
        <msg name="title">Test module</msg>
        <msg name="item">element from myconf</msg>
        <msg name="msg_myconf_delete">Delete element </msg>
        <msg name="hint_new">New element</msg>
        <msg name="hint_edit">Edit element</msg>
        <msg name="hint_delete">Delete element</msg>
      </messages>
      <messages name="myconf.edit">
        <msg name="title">Edit element</msg>
        <msg name="title_new">New element</msg>
        <msg name="item">Value</msg>
        <msg name="hint_item">Element value from myconf</msg>
      </messages>
    </lang>
 </mgrdata>

2) Create the file handler /usr/local/ispmgr/addon/myconf.pl with the following contents

 #!/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) Set privileges on the file handler

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

4) Restart ISPmanager

Comments

Describe a script handler by specifying that it will be executed while calling your functions. You can describe it in the same manner as events, but change the event tag into the func element.

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

The information on how to describe a link can be found in the article Adding external links to the menu

   <mainmenu level="7">
     <node name="tool">
       <node name="myconf"/>
     </node>
   </mainmenu>

Describe a data table:

   <metadata name="myconf" type="list" key="item">
     <toolbar>
       <toolbtn func="myconf.edit" type="new"  img="t-new.gif" name="new"/>
       <toolbtn func="myconf.edit" type="edit" img="t-edit.gif" name="edit" default="yes"/>
       <toolbtn func="myconf.delete" type="group" img="t-delete.gif" name="delete"/>
     </toolbar>
     <coldata>
       <col sort="alpha" sorted="yes" name="item" type="data"/>
     </coldata>
   </metadata>

We have a table with one column. The control panel has three buttons that can be used to create, edit and delete an element. More information about tags and attributes can be found in the article Form descriptions


Describe the edit form:

   <metadata name="myconf.edit" type="form">
     <form>
       <field name="item">
         <input type="text" name="item"/>
       </field>
     </form>
   </metadata>

The form has one input field. More information about tags and attributes can be found in the article Form descriptions

Describe text messages for your newly created interfaces. Information on how to add a message name can be found in the article Message names

Script handler

Get parameters and a name of the function to be called

 use CGI qw/:standard/;

 $Q = new CGI;
 $func = $Q->param(func);

Depending on the function, call a corresponding procedure

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;
	}
}

Data list output

sub List {
	if( open( IN, "/etc/myconf" ) ){
		while( <IN> ){
			chomp;
			print "<elem><item>$_</item></elem>";
		}
		close( IN );
	}
}

Read the data file "/etc/myconf" and form the XML document. The elem tag defines a data line and contains child elements that describe data by columns, you can use a random name for the item tag, but it should correspond to the name attribute in the table column description (the col tag).


Reading data while opening an element edit form

sub Get {
	$elid = $Q->param( "elid" );
	print "<elid>$elid</elid><item>$elid</item>" if( $elid );
}

This function will be called when opening an edit form to create or edit an element. If the elid parameter is not empty, we will edit the element. This parameter contains a value from the list column and its name is specified in the key attribute of the metadata tag when describing a data table interface.

As we have a very simple interface and the form only contains an input field, we do not read anything from the files, but return a parameter from the requested element. It would be a good thing to check that this element exists in the data file., if not, return an error. The elid tag defines a key value for the element, it will be displayed on the form heading. The item tag in our case contains the value that will be displayed in the item input form.


Editing the line

sub Set {
	$elid = $Q->param( "elid" );
	$item = $Q->param( "item" );
       .......
} 

Pay attention to the two parameters when editing a line. elid contains a name (key field) of the element to be edited. The item parameter contains a value that a user provided in the item field. If a required parameter is not found, an error message should be returned.

Creating a new element

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>";
	}
}

Take a value from the item parameter and add it into the end of our data file. If you failed to open the file, the error message will return.


Deleting the element

sub Delete {
	@all_elem = split(", ", $Q->param( "elid" ));
       ......
}

Since we can delete several elements at one call, the elid parameter may contain several names separated by the ", " symbols (a comma and a space). Form an array of elements to be deleted, read our data file and delete the lines that are included into the element array.

Was this helpful? Yes | No
Views
Personal tools