From 3f25163dc15e2e552f5755fbeee40a259029f971 Mon Sep 17 00:00:00 2001
From: Jared Hancock <jared@osticket.com>
Date: Mon, 29 Jun 2015 14:08:54 -0500
Subject: [PATCH] Add quick add for teams

---
 include/ajax.admin.php                        | 51 +++++++++++++++++--
 include/class.dept.php                        |  7 +--
 include/class.filter_action.php               | 28 ++++++++--
 include/class.forms.php                       | 15 +++++-
 include/class.team.php                        | 38 ++++++++++++--
 include/staff/helptopic.inc.php               | 17 ++++---
 include/staff/helptopics.inc.php              |  1 -
 ...department.tmpl.php => quick-add.tmpl.php} |  2 +-
 scp/ajax.php                                  |  3 +-
 scp/css/scp.css                               |  5 +-
 scp/js/scp.js                                 | 16 +++---
 11 files changed, 149 insertions(+), 34 deletions(-)
 rename include/staff/templates/{quick-add-department.tmpl.php => quick-add.tmpl.php} (95%)

diff --git a/include/ajax.admin.php b/include/ajax.admin.php
index 2e6ac9561..0cee34e4c 100644
--- a/include/ajax.admin.php
+++ b/include/ajax.admin.php
@@ -1,6 +1,7 @@
 <?php
 
 require_once(INCLUDE_DIR . 'class.dept.php');
+require_once(INCLUDE_DIR . 'class.team.php');
 
 class AdminAjaxAPI extends AjaxController {
 
@@ -31,12 +32,12 @@ class AdminAjaxAPI extends AjaxController {
             $vars += array(
                 'group_membership' => Dept::ALERTS_DEPT_AND_GROUPS,
             );
-            if ($dept->update($vars, $errors))
+            if ($dept->update($vars, $errors)) {
                 Http::response(201, $this->encode(array(
                     'id' => $dept->id,
                     'name' => $dept->name,
                 ), 'application/json'));
-
+            }
             foreach ($errors as $name=>$desc)
                 if ($F = $form->getField($name))
                     $F->addError($desc);
@@ -45,6 +46,50 @@ class AdminAjaxAPI extends AjaxController {
         $title = __("Add New Department");
         $path = $ost->get_path_info();
 
-        include STAFFINC_DIR . 'templates/quick-add-department.tmpl.php';
+        include STAFFINC_DIR . 'templates/quick-add.tmpl.php';
+    }
+
+    /**
+     * Ajax: GET /admin/add/team
+     *
+     * Uses a dialog to add a new team
+     *
+     * Returns:
+     * 200 - HTML form for addition
+     * 201 - {id: <id>, name: <name>}
+     *
+     * Throws:
+     * 403 - Not logged in
+     */
+    function addTeam() {
+        global $ost, $thisstaff;
+
+        if (!$thisstaff)
+            Http::response(403, 'Agent login required');
+
+        $form = new TeamQuickAddForm($_POST);
+
+        if ($_POST && $form->isValid()) {
+            $team = Team::create();
+            $errors = array();
+            $vars = $form->getClean();
+            $vars += array(
+                'isenabled' => true,
+            );
+            if ($team->update($vars, $errors)) {
+                Http::response(201, $this->encode(array(
+                    'id' => $team->getId(),
+                    'name' => $team->name,
+                ), 'application/json'));
+            }
+            foreach ($errors as $name=>$desc)
+                if ($F = $form->getField($name))
+                    $F->addError($desc);
+        }
+
+        $title = __("Add New Team");
+        $path = $ost->get_path_info();
+
+        include STAFFINC_DIR . 'templates/quick-add.tmpl.php';
     }
 }
diff --git a/include/class.dept.php b/include/class.dept.php
index bd2de00cd..473dca73b 100644
--- a/include/class.dept.php
+++ b/include/class.dept.php
@@ -557,13 +557,14 @@ implements TemplateVariable {
     function update($vars, &$errors) {
         global $cfg;
 
-        if (isset($this->id) && $this->getId() != $vars['id'])
+        $id = $this->id;
+        if ($id != $vars['id'])
             $errors['err']=__('Missing or invalid Dept ID (internal error).');
 
         if (!$vars['name']) {
             $errors['name']=__('Name required');
-        } elseif (($did=static::getIdByName($vars['name'], $vars['pid']))
-                && (!isset($this->id) || $did!=$this->getId())) {
+        } elseif (($did = static::getIdByName($vars['name'], $vars['pid']))
+                && $did != $this->id) {
             $errors['name']=__('Department already exists');
         }
 
diff --git a/include/class.filter_action.php b/include/class.filter_action.php
index c9815d137..4cdac2e7a 100644
--- a/include/class.filter_action.php
+++ b/include/class.filter_action.php
@@ -281,8 +281,18 @@ class FA_RouteDepartment extends TriggerAction {
     function getConfigurationOptions() {
         return array(
             'dept_id' => new ChoiceField(array(
-                'configuration' => array('prompt' => __('Unchanged')),
-                'choices' => Dept::getDepartments(),
+                'configuration' => array(
+                    'prompt' => __('Unchanged'),
+                    'data' => array('quick-add' => 'department'),
+                ),
+                'choices' => array_merge(
+                    Dept::getDepartments(),
+                    array(':new:' => '— '.__('Add New').' —')
+                ),
+                'validators' => function($self) {
+                    if ($self->getClean() === ':new:')
+                        $self->addError(__('Select a department'));
+                }
             )),
         );
     }
@@ -353,8 +363,18 @@ class FA_AssignTeam extends TriggerAction {
         $choices = Team::getTeams();
         return array(
             'team_id' => new ChoiceField(array(
-                'configuration' => array('prompt' => __('Unchanged')),
-                'choices' => $choices,
+                'configuration' => array(
+                    'prompt' => __('Unchanged'),
+                    'data' => array('quick-add' => 'team'),
+                ),
+                'choices' => array_merge(
+                    $choices,
+                    array(':new:' => '— '.__('Add New').' —')
+                ),
+                'validators' => function($self) {
+                    if ($self->getClean() === ':new:')
+                        $self->addError(__('Select a team'));
+                }
             )),
         );
     }
diff --git a/include/class.forms.php b/include/class.forms.php
index bacfe3b36..3c898f26a 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -301,12 +301,22 @@ class Form {
  *
  */
 class SimpleForm extends Form {
-
     function __construct($fields=array(), $source=null, $options=array()) {
         parent::__construct($source, $options);
         $this->setFields($fields);
     }
+}
 
+abstract class AbstractForm extends Form {
+    function __construct($source=null, $options=array()) {
+        parent::__construct($source, $options);
+        $this->setFields($this->buildFields());
+    }
+    /**
+     * Fetch the fields defined for this form. This method is only called
+     * once.
+     */
+    abstract function buildFields();
 }
 
 require_once(INCLUDE_DIR . "class.json.php");
@@ -2920,6 +2930,9 @@ class ChoicesWidget extends Widget {
         <select name="<?php echo $this->name; ?>[]"
             <?php echo implode(' ', array_filter(array($classes))); ?>
             id="<?php echo $this->id; ?>"
+            <?php foreach ($config['data'] as $D=>$V) {
+              echo ' data-'.$D.'="'.Format::htmlchars($V).'"';
+            } ?>
             data-placeholder="<?php echo $prompt; ?>"
             <?php if ($config['multiselect'])
                 echo ' multiple="multiple"'; ?>>
diff --git a/include/class.team.php b/include/class.team.php
index 12d14e713..1e397d684 100644
--- a/include/class.team.php
+++ b/include/class.team.php
@@ -162,18 +162,16 @@ implements TemplateVariable {
               ($vars['isenabled'] ? self::FLAG_ENABLED : 0)
             | (isset($vars['noalerts']) ? self::FLAG_NOALERTS : 0);
         $this->lead_id = $vars['lead_id'] ?: 0;
-        $this->name = $vars['name'];
+        $this->name = Format::striptags($vars['name']);
         $this->notes = Format::sanitize($vars['notes']);
 
         if ($this->save()) {
             // Remove checked members
             if ($vars['remove'] && is_array($vars['remove'])) {
                 TeamMember::objects()
-                    ->filter(array(
-                        'staff_id__in' => $vars['remove']))
+                    ->filter(array('staff_id__in' => $vars['remove']))
                     ->delete();
             }
-
             return true;
         }
 
@@ -301,4 +299,34 @@ class TeamMember extends VerySimpleModel {
         ),
     );
 }
-?>
+
+class TeamQuickAddForm
+extends AbstractForm {
+    function buildFields() {
+        return array(
+            'name' => new TextboxField(array(
+                'required' => true,
+                'configuration' => array(
+                    'placeholder' => __('Name'),
+                    'classes' => 'span12',
+                    'autofocus' => true,
+                    'length' => 128,
+                ),
+            )),
+            'lead_id' => new ChoiceField(array(
+                'default' => 0,
+                'choices' => array_merge(
+                    array(0 => '— '.__('No Leader').' —'),
+                    Staff::getStaffMembers()
+                ),
+                'configuration' => array(
+                    'classes' => 'span12',
+                ),
+            )),
+        );
+    }
+
+    function render($staff=true) {
+        return parent::render($staff, false, array('template' => 'dynamic-form-simple.tmpl.php'));
+    }
+}
diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php
index 93e98cc08..bd3e28dc3 100644
--- a/include/staff/helptopic.inc.php
+++ b/include/staff/helptopic.inc.php
@@ -286,7 +286,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 <?php echo __('Auto-assign To');?>:
             </td>
             <td>
-                <select name="assign">
+                <select name="assign" data-quick-add>
                     <option value="0">&mdash; <?php echo __('Unassigned'); ?> &mdash;</option>
                     <?php
                     if (($users=Staff::getStaffMembers())) {
@@ -302,19 +302,20 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                         }
                         echo '</OPTGROUP>';
                     }
-                    if (($teams=Team::getTeams())) {
-                        echo sprintf('<OPTGROUP label="%s">',
-                                sprintf(__('Teams (%d)'), count($teams)));
+                    if ($teams = Team::getTeams()) { ?>
+                      <optgroup data-quick-add="team" label="<?php
+                        echo sprintf(__('Teams (%d)'), count($teams)); ?>"><?php
                         foreach ($teams as $id => $name) {
                             $k="t$id";
                             $selected = ($info['assign']==$k || $info['team_id']==$id) ? 'selected="selected"' : '';
                             ?>
                             <option value="<?php echo $k; ?>"<?php echo $selected; ?>><?php echo $name; ?></option>
                         <?php
-                        }
-                        echo '</OPTGROUP>';
-                    }
-                    ?>
+                        } ?>
+                        <option value="0" data-quick-add data-id-prefix="t">— <?php echo __('Add New Team'); ?> —</option>
+                      </optgroup>
+                    <?php
+                    } ?>
                 </select>
                 &nbsp;<span class="error">&nbsp;<?php echo $errors['assign']; ?></span>
                 <i class="help-tip icon-question-sign" href="#auto_assign_to"></i>
diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php
index 1c91d64cb..e9eda32bf 100644
--- a/include/staff/helptopics.inc.php
+++ b/include/staff/helptopics.inc.php
@@ -168,4 +168,3 @@ endif;
      </p>
     <div class="clear"></div>
 </div>
-
diff --git a/include/staff/templates/quick-add-department.tmpl.php b/include/staff/templates/quick-add.tmpl.php
similarity index 95%
rename from include/staff/templates/quick-add-department.tmpl.php
rename to include/staff/templates/quick-add.tmpl.php
index 4d0e71e79..fc5c01c66 100644
--- a/include/staff/templates/quick-add-department.tmpl.php
+++ b/include/staff/templates/quick-add.tmpl.php
@@ -3,7 +3,7 @@
 <div class="clear"></div>
 <hr/>
 <form method="post" action="#<?php echo $path; ?>">
-  <div class="inset">
+  <div class="inset quick-add">
     <?php $form->render(); ?>
   </div>
   <hr>
diff --git a/scp/ajax.php b/scp/ajax.php
index 3634a6cdb..55dee8d6d 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -227,7 +227,8 @@ $dispatcher = patterns('',
     )),
     url('^/admin', patterns('',
         url('^/quick-add', patterns('ajax.admin.php:AdminAjaxAPI',
-            url('^/department$', 'addDepartment')
+            url('^/department$', 'addDepartment'),
+            url('^/team', 'addTeam')
         ))
     ))
 );
diff --git a/scp/css/scp.css b/scp/css/scp.css
index a3e0b4b8e..af77ddc98 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -2450,9 +2450,12 @@ td.indented {
 .iblock {
     display: inline-block;
 }
-form.inset {
+form .inset {
     padding: 10px;
 }
+.dialog form .inset {
+  min-height: 150px;
+}
 .span12 {
     width: 100%;
 }
diff --git a/scp/js/scp.js b/scp/js/scp.js
index b8e861843..041502735 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -959,18 +959,22 @@ if ($.support.pjax) {
 // Quick-Add dialogs
 $(document).on('change', 'select[data-quick-add]', function() {
     var $select = $(this),
-        selected = $select.find('option:selected');
-    if (selected.data('quick-add') === undefined)
+        selected = $select.find('option:selected'),
+        type = selected.parent().closest('[data-quick-add]').data('quickAdd');
+    if (!type || (selected.data('quickAdd') === undefined && selected.val() !== ':new:'))
         return;
-    $.dialog('ajax.php/admin/quick-add/' + $select.data('quick-add'), 201,
+    $.dialog('ajax.php/admin/quick-add/' + type, 201,
     function(xhr, data) {
         data = JSON.parse(data);
         if (data && data.id && data.name) {
+          var id = data.id;
+          if (selected.data('idPrefix'))
+            id = selected.data('idPrefix') + id;
           $('<option>')
-            .attr('value', data.id)
+            .attr('value', id)
             .text(data.name)
-            .insertBefore($select.find('option[data-quick-add]'));
-          $select.val(data.id);
+            .insertBefore(selected);
+          $select.val(id);
         }
     });
 });
-- 
GitLab