Chapter 4: Plugin Advanced Feature Overview Up Main page

5 Case Studies

As mentioned previously, only a small subset of files are actually necessary for the most basic of plugins. As more in-depth functionality is needed, however, more files may be required. The following programs contain examples of how additional utility can be achieved with the InterWorx plugin system.

5.1 Plugin Case Study: auto-enable-shell-account

Auto Enable Shell Account is a plugin designed to activate shell account access for all new SiteWorx users added to an account. To accomplish this, it needs to perform only a small handful of tasks, but far more than we’ve seen thus far.
  • The first new function encountered here is initializeMyEditForm() (line 18). This optional function allows us to define settings that will be configurable via the plugin menu in NodeWorx > Plugin Management. It takes a form object as input, Form_NW_Plugins_Edit. At the start of the function a new form group is added (line 19), and datastore variables within the plugin (lines 20 and 22) are accessed (they are stored in the expected fashion, seen below). [see Figure 5.1↓]
Figure 5.1 ~iworx/plugins/auto-enable-shell-account/Plugin/AutoEnableShellAccount.php
1/**
2 * Plugin to auto-enable ssh shell users on account creation.
3 *
4 * @package    InterWorx
5 * @subpackage Plugin
6 */ 
7class Plugin_AutoEnableShellAccount extends Plugin {
8  /**
9   * Init my edit form.
10   *
11   * Add plugin settings that specify which resellers this feature is enabled
12   * for.
13   *
14   * @param Form_NW_Plugins_Edit $Form
15   */
16  public function initializeMyEditForm( Form_NW_Plugins_Edit $Form ) {
17    $Group = $Form->addGroup( ’extra_options’, ’Extra Plugin Settings’ );
18    $all_resellers = $this->getDatastoreVar( ’all_resellers’ );
19    $Group->addInput( new Input_Flag( ’all_resellers’, $all_resellers ) );
20    $resellers = $this->getDatastoreVar( ’resellers’ );
21    if( $resellers === ’’ ) {
22      $resellers = array();
23    }
24    $Group->addInput( new Input_Select( ’resellers’, $resellers ) )
25      ->setDataSource( new DataSource_NW_ResellerIds() )
26      ->setRequired( true )
27      ->setMultipleAllowed( true );
28  }
  • The next function processes the edit form we just initialized — the aptly-named processMyEditForm() (line 8). Taking the same form as input, we use this space to handle the data submitted in the previous step, optionally storing it with setDatastoreVar() (lines 14 and 15). [see Figure 5.2↓]
Figure 5.2 ~iworx/plugins/auto-enable-shell-account/Plugin/AutoEnableShellAccount.php
1  /**
2   * Process my edit form.
3   *
4   * @param Form_NW_Plugins_Edit $Form
5   */
6  public function processMyEditForm( Form_NW_Plugins_Edit $Form ) {
7    if( $Form->getValue( ’all_resellers’ ) ) {
8      $resellers = array();
9    } else {
10      $resellers = $Form->getValue( ’resellers’ );
11    }
12    $this->setDatastoreVar( ’all_resellers’, $Form->getValue( ’all_resellers’ ) );
13    $this->setDatastoreVar( ’resellers’, $resellers );
14  }
  • Next, we simply set the priority of the plugin. Plugin priority determines the order in which plugins are initialized in the system. [see Figure 5.3↓]
Figure 5.3 ~iworx/plugins/auto-enable-shell-account/Plugin/AutoEnableShellAccount.php
1  /**
2   * Get priority.
3   *
4   * @return integer
5   */
6  public function getPriority() {
7    return 40;
8  }
  • Lastly, we have the postAction(), where the majority of the plugin functionality resides. It accepts inputs that include the Controller, Action, and Form, and proceeds to use routeFromPHP() (lines 37 and 40) to call the NodeWorx Shell controller, which then enables the recently-added SiteWorx user (line 46). [see Figure 5.4↓]
Figure 5.4 ~iworx/plugins/auto-enable-shell-account/Plugin/AutoEnableShellAccount.php
1  /**
2   * Handle the controller:action we care about.
3   *
4   * @param string        $ctrl_act
5   * @param Ctrl_Abstract $Ctrl
6   * @param string        $action
7   * @param mixed         $params
8   */
9  public function postAction( $ctrl_act, Ctrl_Abstract $Ctrl, $action, $params ) {
10    if( $ctrl_act !== ’Ctrl_Nodeworx_Siteworx:addCommit’ ) {
11      return;
12    }
13    if( !$Ctrl->isViewSuccess() ) {
14      return;
15    }
16    if( $this->_userHasNoAccess() ) {
17      return;
18    }
19    assert( $params instanceof Form );
20    /**
21     * @var Form.
22     */
23    $Form     = $params;
24    $uniqname = $Form->getValue( ’uniqname’ );
25    $password = $Form->getValue( ’password’ );
26    $ctrl = ’Ctrl_Nodeworx_Shell’;
27    if( IW::NW()->isReseller() ) {
28      $NW = new NodeWorx( NodeWorx::MASTER_ID );
29    } else {
30      $NW = IW::NW();
31    }
32    $action = ’changeshell’;
33    $input = array( ’shell’ => Ini::get( Ini::SHELL, ’default’ ),
34                    ’users’ => array( $uniqname ) );
35    $Reply = IW::FC()->routeFromPHP( $ctrl, $action, $input, $NW );
36    $action = ’enable’;
37    $input = array( ’users’ => array( $uniqname ) );
38    $Reply = IW::FC()->routeFromPHP( $ctrl, $action, $input, $NW );
39    $sshConfig = SSHD::readConfig();
40    if( count( $sshConfig[’allowusers’] ) > 0 ) {
41      $SSH       = new SSHD();
42      $allowed   = $sshConfig[’allowusers’];
43      $allowed[] = $uniqname;
44      $SSH->setAllowUsers( $allowed );
45      $SSH->writeConfig();
46    }
47    if( $Reply->wasSuccessful() === true ) {
48      $msg = ’Shell account user enabled’;
49    } else {
50      $msg = "Tried to enable shell user {$uniqname}, but failed.";
51    }
52    $Ctrl->getView()->addMessage( $msg );
53  }

5.2 Plugin Case Study: CloudFlare

The InterWorx CloudFlare plugin allows for full support of CloudFlare’s CDN technology from within SiteWorx. As one of the larger plugins, it is a prime example of how easily the core plugin functionality can be extended.
  • The CloudFlare SiteWorx controller contains two prime examples of previously mentioned commit actions (lines 8 and 25). Both actions take very similar forms as input and call similar private functions (lines 12 and 29), defined elsewhere. [see Figure 5.5↓]
Figure 5.5 ~iworx/plugins/cloudflare/Ctrl/SW/Cloudflare.php
1  /**
2   * Enable Cloudflare for a subdomain.
3   *
4   * @param Form_SW_Cloudflare_Enable $Form
5   */
6  public function enableCommitAction( Form_SW_Cloudflare_Enable $Form ) {
7    $parent    = $Form->getValue( ’parent’ );
8    $subdomain = $Form->getValue( ’subdomain’ );
9    $errors = array();
10    $this->_enableSubdomain( $subdomain, $parent, $errors );
11    if( empty( $errors ) ) {
12      $this->_getPlugin()->setDomainStatusData( $subdomain, ’1’ );
13      $this->_displaySuccess( ’index’, ’CloudFlare Enabled on ’ . $subdomain );
14    } else {
15      $this->_displayFailure( ’index’, $errors );
16    }
17  }
1819  /**
20   * Disable Cloudflare for a subdomain.
21   *    * @param Form_SW_Cloudflare_Disable $Form
22   */
23  public function disableCommitAction( Form_SW_Cloudflare_Disable $Form ) {
24    $parent    = $Form->getValue( ’parent’ );
25    $subdomain = $Form->getValue( ’subdomain’ );
26    $errors = array();
27    $this->_disableSubdomain( $subdomain, $parent, $errors );
28    if( empty( $errors ) ) {
29      $this->_getPlugin()->setDomainStatusData( $subdomain, ’0’ );
30      $this->_displaySuccess( ’index’, ’CloudFlare Disabled on ’ . $subdomain );
31    } else {
32      $this->_displayFailure( ’index’, $errors );
33    }
34  }
  • Looking at that first form, we can see that building a basic input form isn’t complicated. [see Figure 5.6↓]
Figure 5.6 ~iworx/plugins/cloudflare/Form/SW/Cloudflare/Enable.php
1/**
2 * Form_SW_Cloudflare_Enable class.
3 *
4 * @package    InterWorx
5 * @subpackage Form
6 *
7 */
8class Form_SW_Cloudflare_Enable extends Form {
9  /**
10   * GetInputForm function.
11   */
12  public function initInputForm() {
13    $Form = new Form_Input();
14    $Form->addInput( new Input_String( ’parent’ ) );
15    $parent = $Form->getValue( ’parent’ );
16    $DS = new DataSource_Subdomains( $parent );
17    $Form->addInput( new Input_Select( ’subdomain’ ) )
18      ->setDataSource( $DS );
19    $this->setInputForm( $Form );
20  }
2122  /**
23   * Initialize.
24   */
25  protected function _initialize() {
26    parent::_initialize( ’enable_cloudflare_domain’ );
27    $this->addInput( $this->getInput( ’subdomain’ )->getDisabledCopy() );
28  }
29}
  • After the form is instantiated, the subdomain input is added using DataSource_Subdomains() (line 18), described below. Shown here, it can be seen that the datasource simply consists of a subset of CNAME DNS records, passed to the constructor as an array of subdomain names (line 28). [see Figure 5.7↓]
Figure 5.7 ~iworx/plugins/cloudflare/DataSource/Subdomains.php
1/**
2 * DataSource for CloudFlare subdomains.
3 *  * @package    InterWorx
4 * @subpackage Input
5 */
6class DataSource_Subdomains extends DataSource_Array {
7  /**
8   * Constructor.
9   *
10   * @param string $parent
11   */
12  public function __construct( $parent ) {
13    $subdomains = array();
14    $dns = IW::SW()->getSimpleDnsRecordsFor( $parent );
15    foreach( $dns as $record ) {
16      if( preg_match( ’/^ftp\.*/’, $record[’host’] ) ) {
17        continue;
18      }
19      if( preg_match( ’/^cloudflare-resolve-to\.*/’, $record[’host’] ) ) {
20        continue;
21      }
22      if( $record[’type’] === Dns_Record::CNAME ) {
23        $subdomains[] = $record[’host’];
24      }
25    }
26    parent::__construct( $subdomains );
27  }
28} 
  • Building a payload, while one of the more complicated objects, is still straightforward. Columns are added to the payload by creating new Payload_Columns (lines 25, 26, 31 and 32), and have a considerable number of functions for configuration ( setName, setOrderBy, etc ). [see Figure 5.8↓]
Figure 5.8 ~iworx/plugins/cloudflare/Payload/Factory/SW/Cloudflare.php
1/**
2 * Factory for CloudFlare configuration.
3 *
4 * @package    InterWorx
5 * @subpackage Payload
6 */
7class Payload_Factory_SW_Cloudflare {
8  /**
9   * Domains payload.
10   *
11   * @param SiteWorx $SW
12   * @param string   $domain
13   * @return Payload
14   */
15  static public function subdomains( SiteWorx $SW, $domain = null ) {
16    $plugin = IW::PluginManager()->getPlugin( ’cloudflare’ );
17    $domains = self::_getDomains( $SW, $domain );
18 
19    $Payload = new Payload( $domains );
20    $Payload->setName( ’cloudflare_domains’ );
21    $Payload->setTitle( ’Cloudflare DNS Settings’ );
2223    $Payload->setColumn( new Payload_Column( ’type’ ) );
24    $Payload->setColumn( new Payload_Column( ’subdomain’ ) )
25      ->setIsSortable( true )
26      ->setOrderBy( ’subdomain’ )
27      ->setLabel( ’Subdomain’ );
2829    $Payload->setColumn( new Payload_Column( ’record’ ) );
30    $Payload->setColumn( new Payload_Column( ’status’ ) )
31      ->addFormatter( new IWorx_Formatter_CloudflareEnabledDisabled( ’subdomain’ ) )
32      ->setLabel( ’##LG_STATUS##’ );
3334    return $Payload;
35  }
36}

5.3 Plugin Case Study: Session History

The Session History plugin allows the system administrator to log user activity across the system for any number of purposes. It provides very standard examples of both formatters and templates.
  • The page formatter takes a row from the payload output (line 19) and parses the controller and action name into a convenient link (line 21). [see Figure 5.9↓]
Figure 5.9 ~iworx/plugins/history/IWorx/Formatter/History/Page.php
1/**
2 * Displays the page uri based on the ctrl and action name.
3 *
4 * @package    InterWorx
5 * @subpackage Payload
6 */
7class IWorx_Formatter_History_Page extends IWorx_Formatter_Complex {
8  /**
9   * Format.
10   *
11   * @param mixed  $value The value being rendered
12   * @param object $row   The data for the entire row
13   * @param array  $data  The entire dataset of the Payload
14   *
15   * @return string
16   */
17  public function format( $value, $row, array $data ) {
18    $ctrl = Ctrl_Util::convertClassNameToPath( $row->ctrl_name );
19    $link = "{$ctrl}?action={$row->action_name}";
20    return $link;
21  }
22}
  • Finally, the history template is a textbook sample of the possibilities of the template system, using the Smarty syntax. [see Figure 5.10↓]
Figure 5.10 ~iworx/plugins/history/templates/history.tpl
1{iw_add_js file="/plugins/images/history/search_session_history.js"}
23{literal}
4<style scoped>
5  .iw-fake-table-hd .iw-form-img {   display: none;   }
6  .td-timestamp {   white-space: nowrap;   min-width: 120px;   }
7  .td-query_string {   white-space: nowrap;   }
8  .td-change, .th-change {   max-width: 200px;   }
9</style>
10{/literal}
1112<div id="history-search" class="iw-fake-table-hd">
13  <div class="right">
14    {iw_form_input form=$search_form input_name=search}
15    {iw_quickhelp id="LG_QH_SESSION_HISTORY_SEARCH"}
16    {iw_form_buttons form=$search_form}
17  </div>
1819  <div class="clear">
20  </div>
21</div>
22{iw_payload payload=$iw_payload} 

(C) 2017 by InterWorx LLC