b2evolution PHP Cross Reference Blogging Systems

Source: /inc/users/views/_user_subscriptions.form.php - 449 lines - 20442 bytes - Text - Print

Description: This file implements the UI view for the user subscriptions. This file is part of the evoCore framework - {@link http://evocore.net/} See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**

   3   * This file implements the UI view for the user subscriptions.

   4   *

   5   * This file is part of the evoCore framework - {@link http://evocore.net/}

   6   * See also {@link http://sourceforge.net/projects/evocms/}.

   7   *

   8   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}

   9   * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.

  10   *

  11   * {@internal License choice

  12   * - If you have received this file as part of a package, please find the license.txt file in

  13   *   the same folder or the closest folder above for complete license terms.

  14   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)

  15   *   then you must choose one of the following licenses before using the file:

  16   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php

  17   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php

  18   * }}

  19   *

  20   * {@internal Open Source relicensing agreement:

  21   * The Evo Factory grants Francois PLANQUE the right to license

  22   * The Evo Factory's contributions to this file and the b2evolution project

  23   * under any OSI approved OSS license (http://www.opensource.org/licenses/).

  24   *

  25   * Daniel HAHLER grants Francois PLANQUE the right to license

  26   * Daniel HAHLER's contributions to this file and the b2evolution project

  27   * under any OSI approved OSS license (http://www.opensource.org/licenses/).

  28   * }}

  29   *

  30   * @package admin

  31   *

  32   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}

  33   * @author fplanque: Francois PLANQUE

  34   *

  35   * @version $Id: _user_subscriptions.form.php 1498 2012-07-09 09:10:04Z yura $

  36   */
  37  
  38  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  39  
  40  /**

  41   * @var instance of GeneralSettings class

  42   */
  43  global $Settings;
  44  /**

  45   * @var instance of UserSettings class

  46   */
  47  global $UserSettings;
  48  /**

  49   * @var instance of User class

  50   */
  51  global $edited_User;
  52  /**

  53   * @var current action

  54   */
  55  global $action;
  56  /**

  57   * @var user permission, if user is only allowed to edit his profile

  58   */
  59  global $user_profile_only;
  60  /**

  61   * @var the action destination of the form (NULL for pagenow)

  62   */
  63  global $form_action;
  64  /**

  65   * @var Blog

  66   */
  67  global $Blog;
  68  /**

  69   * @var DB

  70   */
  71  global $DB;
  72  
  73  global $unread_messsage_reminder_threshold, $unread_message_reminder_delay, $activate_account_reminder_threshold, $comment_moderation_reminder_threshold;
  74  
  75  // Default params:

  76  $default_params = array(
  77          'skin_form_params' => array(),
  78      );
  79  
  80  if( isset( $params ) )
  81  {    // Merge with default params
  82      $params = array_merge( $default_params, $params );
  83  }
  84  else
  85  {    // Use a default params
  86      $params = $default_params;
  87  }
  88  
  89  // ------------------- PREV/NEXT USER LINKS -------------------

  90  user_prevnext_links( array(
  91          'block_start'  => '<table class="prevnext_user"><tr>',
  92          'prev_start'   => '<td width="33%">',
  93          'prev_end'     => '</td>',
  94          'prev_no_user' => '<td width="33%">&nbsp;</td>',
  95          'back_start'   => '<td width="33%" class="back_users_list">',
  96          'back_end'     => '</td>',
  97          'next_start'   => '<td width="33%" class="right">',
  98          'next_end'     => '</td>',
  99          'next_no_user' => '<td width="33%">&nbsp;</td>',
 100          'block_end'    => '</tr></table>',
 101          'user_tab'     => 'subs'
 102      ) );
 103  // ------------- END OF PREV/NEXT USER LINKS -------------------

 104  
 105  $Form = new Form( $form_action, 'user_checkchanges' );
 106  
 107  $Form->switch_template_parts( $params['skin_form_params'] );
 108  
 109  if( !$user_profile_only )
 110  {
 111      echo_user_actions( $Form, $edited_User, $action );
 112  }
 113  
 114  $is_admin_page = is_admin_page();
 115  if( $is_admin_page )
 116  {
 117      $form_title = get_usertab_header( $edited_User, 'subs', T_( 'Edit notifications' ) );
 118      $form_class = 'fform';
 119      $Form->title_fmt = '<span style="float:right">$global_icons$</span><div>$title$</div>'."\n";
 120      $checklist_params = array();
 121  }
 122  else
 123  {
 124      $form_title = '';
 125      $form_class = 'bComment';
 126      $checklist_params = array( 'wide' => true );
 127  }
 128  
 129  $Form->begin_form( $form_class, $form_title );
 130  
 131      $Form->add_crumb( 'user' );
 132      $Form->hidden_ctrl();
 133      $Form->hidden( 'user_tab', 'subs' );
 134      $Form->hidden( 'subscriptions_form', '1' );
 135  
 136      $Form->hidden( 'user_ID', $edited_User->ID );
 137      $Form->hidden( 'edited_user_login', $edited_User->login );
 138      if( isset( $Blog ) )
 139      {
 140          $Form->hidden( 'blog', $Blog->ID );
 141      }
 142  
 143  if( $action != 'view' )
 144  {    // We can edit the values:
 145      $disabled = false;
 146  }
 147  else
 148  {    // display only
 149      $disabled = true;
 150  }
 151  
 152  $has_messaging_perm = $edited_User->check_perm( 'perm_messaging', 'reply', false );
 153  
 154  $Form->begin_fieldset( T_('Email') );
 155  
 156      $email_fieldnote = '<a href="mailto:'.$edited_User->get('email').'" class="roundbutton">'.get_icon( 'email', 'imgtag', array('title'=>T_('Send an email')) ).'</a>';
 157  
 158      if( $action != 'view' )
 159      { // We can edit the values:
 160          $Form->text_input( 'edited_user_email', $edited_User->email, 30, T_('Email address'), $email_fieldnote, array( 'maxlength' => 100, 'required' => true ) );
 161          $disabled = false;
 162      }
 163      else
 164      { // display only
 165          $Form->info( T_('Email'), $edited_User->get('email'), $email_fieldnote );
 166          $disabled = true;
 167      }
 168  
 169      $Form->radio_input( 'edited_user_email_format', $UserSettings->get( 'email_format',  $edited_User->ID ), array(
 170                  array(
 171                      'value'   => 'auto',
 172                      'label'   => T_('Automatic (HTML + Plain text)') ),
 173                  array(
 174                      'value'   => 'html',
 175                      'label'   => T_('HTML') ),
 176                  array(
 177                      'value'   => 'text',
 178                      'label'   => T_('Plain text') ),
 179              ), T_('Email format'), array( 'lines' => true ) );
 180  
 181  $Form->end_fieldset();
 182  
 183  $Form->begin_fieldset( T_('Communications') );
 184  
 185      $has_messaging_perm = $edited_User->check_perm( 'perm_messaging', 'reply', false );
 186      $messaging_options = array(    array( 'PM', 1, T_( 'private messages on this site.' ), ( ( $UserSettings->get( 'enable_PM', $edited_User->ID ) ) && ( $has_messaging_perm ) ), !$has_messaging_perm || $disabled ) );
 187      $emails_msgform = $Settings->get( 'emails_msgform' );
 188      if( $emails_msgform == 'userset' )
 189      { // user can set
 190          $messaging_options[] = array( 'email', 2, T_( 'emails through a message form that will NOT reveal my email address.' ), $UserSettings->get( 'enable_email', $edited_User->ID ), $disabled );
 191      }
 192      elseif( ( $emails_msgform == 'adminset' ) && ( $current_User->check_perm( 'users', 'edit' ) ) )
 193      { // only administrator users can set and current User is in 'Administrators' group
 194          $messaging_options[] = array( 'email', 2, T_( 'emails through a message form that will NOT reveal my email address. [Admin]' ), $UserSettings->get( 'enable_email', $edited_User->ID ), $disabled );
 195      }
 196      $Form->checklist( $messaging_options, 'edited_user_msgform', T_('Other users can send me'), false, false, $checklist_params );
 197  
 198  $Form->end_fieldset();
 199  
 200  $Form->begin_fieldset( T_('Notifications') );
 201  
 202      // User notification options

 203      $notify_options = array();
 204      if( $has_messaging_perm )
 205      { // show messaging notification settings only if messaging is available for edited user
 206          $notify_options[] = array( 'edited_user_notify_messages', 1, T_('I receive a private message.'),  $UserSettings->get( 'notify_messages', $edited_User->ID ), $disabled );
 207          $notify_options[] = array( 'edited_user_notify_unread_messages', 1, sprintf( T_('I have unread private messages for more than %s.'), seconds_to_period( $unread_messsage_reminder_threshold ) ),  $UserSettings->get( 'notify_unread_messages', $edited_User->ID ), $disabled, sprintf( T_('This notification is sent only once every %s days.'), array_shift( $unread_message_reminder_delay ) ) );
 208      }
 209      if( $edited_User->check_role( 'post_owner' ) )
 210      { // user has at least one post or user has right to create new post
 211          $notify_options[] = array( 'edited_user_notify_publ_comments', 1, T_('a comment is published on one of <strong>my</strong> posts.'), $UserSettings->get( 'notify_published_comments', $edited_User->ID ), $disabled );
 212      }
 213      $is_comment_moderator = $edited_User->check_role( 'comment_moderator' );
 214      if( $is_comment_moderator || $edited_User->check_role( 'comment_editor' ) )
 215      { // edited user has permission to edit other than his own comments at least in one status in one blog
 216          $notify_options[] = array( 'edited_user_notify_cmt_moderation', 1, T_('a comment is posted and I have permissions to moderate it.'), $UserSettings->get( 'notify_comment_moderation', $edited_User->ID ), $disabled );
 217      }
 218      if( $is_comment_moderator )
 219      { // edited user is comment moderator at least in one blog
 220          $notify_options[] = array( 'edited_user_send_cmt_moderation_reminder', 1, sprintf( T_('comments are awaiting moderation for more than %s.'), seconds_to_period( $comment_moderation_reminder_threshold ) ), $UserSettings->get( 'send_cmt_moderation_reminder', $edited_User->ID ), $disabled );
 221      }
 222      if( $edited_User->check_role( 'post_moderator' ) )
 223      { // edited user is post moderator at least in one blog
 224          $notify_options[] = array( 'edited_user_notify_post_moderation', 1, T_('a post is created and I have permissions to moderate it.'), $UserSettings->get( 'notify_post_moderation', $edited_User->ID ), $disabled );
 225      }
 226      if( $current_User->check_perm( 'users', 'edit' ) )
 227      { // current User is an administrator
 228          $notify_options[] = array( 'edited_user_send_activation_reminder', 1, sprintf( T_('my account was deactivated or is not activated for more than %s. [Admin]'), seconds_to_period( $activate_account_reminder_threshold ) ), $UserSettings->get( 'send_activation_reminder', $edited_User->ID ) );
 229      }
 230      if( $edited_User->check_perm( 'users', 'edit' ) )
 231      { // edited user has permission to edit all users, save notification preferences
 232          $notify_options[] = array( 'edited_user_notify_new_user_registration', 1, T_( 'a new user has registered.' ), $UserSettings->get( 'notify_new_user_registration', $edited_User->ID ), $disabled );
 233          $notify_options[] = array( 'edited_user_notify_activated_account', 1, T_( 'an account was activated.' ), $UserSettings->get( 'notify_activated_account',  $edited_User->ID ), $disabled );
 234          $notify_options[] = array( 'edited_user_notify_closed_account', 1, T_( 'an account was closed.' ), $UserSettings->get( 'notify_closed_account',  $edited_User->ID ), $disabled );
 235          $notify_options[] = array( 'edited_user_notify_reported_account', 1, T_( 'an account was reported.' ), $UserSettings->get( 'notify_reported_account',  $edited_User->ID ), $disabled );
 236      }
 237      if( $edited_User->check_perm( 'options', 'edit' ) )
 238      { // edited user has permission to edit options, save notification preferences
 239          $notify_options[] = array( 'edited_user_notify_cronjob_error', 1, T_( 'a scheduled task ends with an error or timeout.' ), $UserSettings->get( 'notify_cronjob_error',  $edited_User->ID ), $disabled );
 240      }
 241      if( !empty( $notify_options ) )
 242      {
 243          $Form->checklist( $notify_options, 'edited_user_notification', T_( 'Notify me by email whenever' ), false, false, $checklist_params );
 244      }
 245  
 246      // Limit notifications:

 247      if( $is_admin_page )
 248      { // Back office view
 249          $Form->text_input( 'edited_user_notification_email_limit', $UserSettings->get( 'notification_email_limit',  $edited_User->ID ), 3, T_( 'Limit notifications to' ), '', array( 'maxlength' => 3, 'required' => true, 'input_suffix' => ' <b>'.T_('emails per day').'</b>' ) );
 250      }
 251      else
 252      { // Front office view
 253          $Form->text_input( 'edited_user_notification_email_limit', $UserSettings->get( 'notification_email_limit',  $edited_User->ID ), 3, T_( 'Limit notifications to %s emails per day' ), '', array( 'maxlength' => 3, 'required' => true, 'inline' => true ) );
 254      }
 255  
 256  $Form->end_fieldset();
 257  
 258  $Form->begin_fieldset( T_('Newsletters') );
 259  
 260      $newsletter_options = array(
 261          array( 'edited_user_newsletter_news', 1, T_( 'Send me news about this site.' ).' <span class="note">'.T_('Each message contains an easy 1 click unsubscribe link.').'</span>', $UserSettings->get( 'newsletter_news',  $edited_User->ID ) ),
 262          array( 'edited_user_newsletter_ads', 1, T_( 'I want to receive ADs that may be relevant to my interests.' ), $UserSettings->get( 'newsletter_ads',  $edited_User->ID ) )
 263      );
 264      $Form->checklist( $newsletter_options, 'edited_user_newsletter', T_( 'Newsletter' ), false, false, $checklist_params );
 265  
 266      // Limit newsletters:

 267      if( $is_admin_page )
 268      { // Back office view
 269          $Form->text_input( 'edited_user_newsletter_limit', $UserSettings->get( 'newsletter_limit',  $edited_User->ID ), 3, T_( 'Limit newsletters to' ), '', array( 'maxlength' => 3, 'required' => true, 'input_suffix' => ' <b>'.T_('emails per day').'</b>' ) );
 270      }
 271      else
 272      { // Front office view
 273          $Form->text_input( 'edited_user_newsletter_limit', $UserSettings->get( 'newsletter_limit',  $edited_User->ID ), 3, T_( 'Limit newsletters to %s emails per day' ), '', array( 'maxlength' => 3, 'required' => true, 'inline' => true ) );
 274      }
 275  
 276  $Form->end_fieldset();
 277  
 278  $Form->begin_fieldset( T_('Blog subscriptions'), array( 'id' => 'subs' ) );
 279  
 280          // Get those blogs for which we have already subscriptions (for this user)

 281          $sql = 'SELECT blog_ID, blog_shortname, sub_items, sub_comments
 282                    FROM T_blogs INNER JOIN T_subscriptions ON ( blog_ID = sub_coll_ID AND sub_user_ID = '.$edited_User->ID.' )
 283                                 INNER JOIN T_coll_settings ON ( blog_ID = cset_coll_ID AND cset_name = "allow_subscriptions" AND cset_value = "1" )';
 284          $blog_subs = $DB->get_results( $sql );
 285  
 286          $encountered_current_blog = false;
 287          $subs_blog_IDs = array();
 288          foreach( $blog_subs AS $blog_sub )
 289          {
 290              if( isset( $Blog ) && $blog_sub->blog_ID == $Blog->ID )
 291              {
 292                  $encountered_current_blog = true;
 293              }
 294  
 295              $subs_blog_IDs[] = $blog_sub->blog_ID;
 296              $subscriptions = array(
 297                      array( 'sub_items_'.$blog_sub->blog_ID,    '1', T_('All posts'),    $blog_sub->sub_items ),
 298                      array( 'sub_comments_'.$blog_sub->blog_ID, '1', T_('All comments'), $blog_sub->sub_comments )
 299                  );
 300              $Form->checklist( $subscriptions, 'subscriptions', format_to_output( $blog_sub->blog_shortname, 'htmlbody' ) );
 301          }
 302  
 303          $Form->hidden( 'subs_blog_IDs', implode( ',', $subs_blog_IDs ) );
 304  
 305  if( $is_admin_page && $Settings->get( 'subscribe_new_blogs' ) == 'page' )
 306  {    // To subscribe from blog page only
 307      $Form->info_field( '', T_('In order to subscribe to a new blog, go to the relevant blog and subscribe from there.'), array( 'class' => 'info_full' ) );
 308  }
 309  else
 310  {    // To subscribe from current list of blogs
 311  
 312      // Init $BlogCache object to display a select list to subscribe

 313      $BlogCache = new BlogCache();
 314      $BlogCache_SQL = $BlogCache->get_SQL_object();
 315  
 316      load_class( 'collections/model/_collsettings.class.php', 'CollectionSettings' );
 317      $CollectionSettings = new CollectionSettings();
 318      if( $CollectionSettings->get_default( 'allow_subscriptions' ) == 0 )
 319      {    // If default setting disables to subscribe on blogs, we should get only the blogs which allow the subsriptions
 320          $BlogCache_SQL->FROM_add( 'LEFT JOIN T_coll_settings ON cset_coll_ID = blog_ID' );
 321          $BlogCache_SQL->WHERE_and( 'cset_name = \'allow_subscriptions\'' );
 322          $BlogCache_SQL->WHERE_and( 'cset_value = 1' );
 323      }
 324      else// 'allow_subscriptions' == 1
 325      {    // If default setting enables to subscribe on blogs, we should exclude the blogs which don't allow the subsriptions
 326          $blogs_settings_SQL = new SQL( 'Get blogs which don\'t allow the subscriptions' );
 327          $blogs_settings_SQL->SELECT( 'cset_coll_ID' );
 328          $blogs_settings_SQL->FROM( 'T_coll_settings' );
 329          $blogs_settings_SQL->WHERE( 'cset_name = \'allow_subscriptions\'' );
 330          $blogs_settings_SQL->WHERE_and( 'cset_value = 0' );
 331          $blogs_disabled_subscriptions_IDs = $DB->get_col( $blogs_settings_SQL->get() );
 332          // Exclude the blogs which don't allow the subscriptions

 333          $BlogCache_SQL->WHERE_and( 'blog_ID NOT IN ('.$DB->quote( $blogs_disabled_subscriptions_IDs ).')' );
 334      }
 335      if( $Settings->get( 'subscribe_new_blogs' ) == 'public' )
 336      {    // If a subscribing to new blogs available only for the public blogs
 337          $BlogCache_SQL->WHERE_and( 'blog_in_bloglist = 1' );
 338      }
 339      if( !empty( $subs_blog_IDs ) )
 340      {    // Exclude the blogs from the list if user already is subscribed on them
 341          $BlogCache_SQL->WHERE_and( 'blog_ID NOT IN ('.$DB->quote( $subs_blog_IDs ).')' );
 342      }
 343      $BlogCache->load_by_sql( $BlogCache_SQL );
 344      if( empty( $BlogCache->cache ) )
 345      {    // No blogs to subscribe
 346          if( empty( $subs_blog_IDs ) )
 347          {    // Display this info if really no blogs to subscribe
 348              $Form->info_field( '', T_('Sorry, no blogs available to subscribe.'), array( 'class' => 'info_full' ) );
 349          }
 350      }
 351      else
 352      { // Display a form to subscribe on new blog
 353          $Form->info_field( '', T_('Choose additional subscriptions').':', array( 'class' => 'info_full' ) );
 354          $label_blogs_prefix = $label_blogs_suffix = '';
 355  
 356          $Form->switch_layout( 'none' );
 357          $Form->output = false;
 358  
 359          $subscribe_blogs_select = $Form->select_input_object( 'subscribe_blog', param( 'subscribe_blog' , '', isset( $Blog ) ? $Blog->ID : 0 ), $BlogCache, '', array( 'object_callback' => 'get_option_list_parent' ) ).'</span>';
 360          $subscribe_blogs_button = $Form->button( array(
 361              'name'  => 'actionArray[subscribe]',
 362              'value' => T_('Subscribe'),
 363              'style' => 'float:left;margin-left:20px;'
 364          ) );
 365  
 366          $Form->switch_layout( NULL );
 367          $Form->switch_template_parts( $params['skin_form_params'] );
 368          $Form->output = true;
 369  
 370          $subscriptions = array(
 371                  array( 'sub_items_new',    '1', T_('All posts'),    0 ),
 372                  array( 'sub_comments_new', '1', T_('All comments'), 0 )
 373              );
 374          $Form->checklist( $subscriptions, 'subscribe_blog', trim( $subscribe_blogs_select ), false, false, array(
 375              'field_suffix' => $subscribe_blogs_button,
 376              'input_prefix' => '<div class="floatleft">',
 377              'input_suffix' => '</div>' ) );
 378      }
 379  }
 380  $Form->end_fieldset();
 381  
 382  $Form->begin_fieldset( T_('Individual post subscriptions') );
 383  
 384      $sql = 'SELECT DISTINCT post_ID, blog_ID, blog_shortname
 385                  FROM T_items__subscriptions
 386                      INNER JOIN T_items__item ON isub_item_ID = post_ID
 387                      INNER JOIN T_categories ON post_main_cat_ID = cat_ID
 388                      INNER JOIN T_blogs ON cat_blog_ID = blog_ID
 389                  WHERE isub_user_ID = '.$edited_User->ID.' AND isub_comments <> 0
 390                  ORDER BY blog_ID, post_ID ASC';
 391      $individual_posts_subs = $DB->get_results( $sql );
 392      $subs_item_IDs = array();
 393      if( empty( $individual_posts_subs ) )
 394      {
 395          $Form->info_field( '', T_( 'You are not subscribed to any updates on specific posts yet.' ), array( 'class' => 'info_full' ) );
 396      }
 397      else
 398      {
 399          global $admin_url;
 400          $ItemCache = & get_ItemCache();
 401  
 402          $Form->info_field( '', T_( 'You are subscribed to be notified on all updates on the following posts' ).':', array( 'class' => 'info_full' ) );
 403          $blog_name = NULL;
 404          foreach( $individual_posts_subs as $row )
 405          {
 406              if( ! ( $Item = $ItemCache->get_by_ID( $row->post_ID, false, false ) ) )
 407              { // Item doesn't exist anymore
 408                  continue;
 409              }
 410              $subs_item_IDs[] = $row->post_ID;
 411              if( $blog_name != $row->blog_shortname )
 412              {
 413                  if( !empty( $blog_name ) )
 414                  {
 415                      $Form->checklist( $post_subs, 'item_subscriptions', $blog_name );
 416                  }
 417                  $blog_name = $row->blog_shortname;
 418                  $post_subs = array();
 419              }
 420              if( is_admin_page() && $current_User->check_perm( 'item_post!CURSTATUS', 'view', false, $Item ) )
 421              { // Link title to back-office if user has a permission
 422                  $item_title = '<a href="'.$admin_url.'?ctrl=items&amp;blog='.$row->blog_ID.'&amp;p='.$Item->ID.'">'.format_to_output( $Item->title ).'</a>';
 423              }
 424              else
 425              { // Link title to front-office
 426                  $item_title = $Item->get_permanent_link( '#title#' );
 427              }
 428              $post_subs[] = array( 'item_sub_'.$row->post_ID, 1, $item_title, 1 );
 429          }
 430          // display individual post subscriptions from the last Blog

 431          $Form->checklist( $post_subs, 'item_subscriptions', $blog_name );
 432      }
 433      $Form->hidden( 'subs_item_IDs', implode( ',', $subs_item_IDs ) );
 434      $Form->info_field( '', T_( 'To subscribe to notifications on a specifc post, go to that post and click "Notify me when someone comments" at the end of the comment list.' ), array( 'class' => 'info_full' ) );
 435  
 436  $Form->end_fieldset();
 437  
 438      /***************  Buttons  **************/

 439  
 440  if( $action != 'view' )
 441  {    // Edit buttons
 442      $Form->buttons( array(
 443          array( '', 'actionArray[update]', T_('Save !'), 'SaveButton' ),
 444          array( 'reset', '', T_('Reset'), 'ResetButton' ) ) );
 445  }
 446  
 447  $Form->end_form();
 448  
 449  ?>

title

Description

title

Description

title

Description

title

title

Body