Added: vcl/trunk/web/.ht-inc/resource.php
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/resource.php?rev=1624325&view=auto
==============================================================================
--- vcl/trunk/web/.ht-inc/resource.php (added)
+++ vcl/trunk/web/.ht-inc/resource.php Thu Sep 11 16:01:48 2014
@@ -0,0 +1,1640 @@
+<?php
+/*
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn resource($type)
+///
+/// \param $type - type of resource
+///
+/// \brief wrapper to create appropriate object and call selectionText for that
+/// object
+///
+////////////////////////////////////////////////////////////////////////////////
+function resource($type) {
+       switch($type) {
+               case 'config':
+                       $obj = new Config();
+                       break;
+               case 'image':
+                       $obj = new Image();
+                       break;
+               case 'computer':
+                       $obj = new Computer();
+                       break;
+               case 'managementnode':
+                       $obj = new ManagementNode();
+                       break;
+               case 'schedule':
+                       $obj = new Schedule();
+                       break;
+       }
+
+       $html = $obj->selectionText();
+       print $html;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \class Resource
+///
+/// \brief base class for all resources; provides functionality useful to all
+/// types of resources
+///
+////////////////////////////////////////////////////////////////////////////////
+class Resource {
+       var $restype;
+       var $restypename;
+       var $hasmapping;
+       var $maptype;
+       var $maptypename;
+       var $basecdata;
+       var $defaultGetDataArgs;
+       var $deletable;
+       var $deletetoggled;
+       var $errmsg;
+       var $namefield;
+       var $noadd;
+       var $jsondata;
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn __construct()
+       ///
+       /// \brief class construstor
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function __construct() {
+               # defines if resource type is mapped to another type
+               $this->hasmapping = 0;
+               # type of resource this resource maps to
+               $this->maptype = '';
+               # display name for $this->maptype
+               $this->maptypename = '';
+               # can this resource type be deleted
+               $this->deletable = 1;
+               # can this resource type be flagged as deleted
+               $this->deletetoggled = 1;
+               # array of arguments and default values that should be passed 
to getData function
+               $this->defaultGetDataArgs = array();
+               # base data for continuations
+               $this->basecdata = array('obj' => $this);
+               # field in database table used for the name of this resource 
type
+               $this->namefield = 'name';
+               # can this resource have new resources directly added
+               $this->addable = 1;
+               # base data for sending JSON response to AJAX call; this allows 
an
+               #   inheriting function to set some additional data before 
calling base
+               #   function
+               $this->jsondata = array();
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn getData($args)
+       ///
+       /// \param $args - array of arguments that determine what data gets 
returned
+       ///
+       /// \return empty array
+       ///
+       /// \brief stub function; each inheriting class should implement this
+       /// function
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function getData($args) {
+               return array();
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn selectionText()
+       ///
+       /// \brief generates HTML to select what management function to perform
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function selectionText() {
+               global $user;
+               # get a count of resources user can administer
+               $tmp = getUserResources(array("{$this->restype}Admin"), 
array("administer"));
+               $resAdminCnt = count($tmp[$this->restype]);
+
+               # get a count of resources user has access to
+               $tmp = getUserResources(array("{$this->restype}Admin"), 
array("available"));
+               $resCnt = count($tmp[$this->restype]);
+
+               # get a count of resource groups user can manage
+               $tmp = getUserResources(array("{$this->restype}Admin"), 
array("manageGroup"), 1);
+               $resGroupCnt = count($tmp[$this->restype]);
+
+               if($this->hasmapping) {
+                       # get a count of $restype groups and $maptype groups 
user can map
+                       $tmp = getUserResources(array("{$this->restype}Admin"), 
array("manageMapping"), 1);
+                       $resMapCnt = count($tmp[$this->restype]);
+                       $tmp = getUserResources(array("{$this->maptype}Admin"), 
array("manageMapping"), 1);
+                       $maptypeMapCnt = count($tmp[$this->maptype]);
+               }
+               else {
+                       $resMapCnt = 0;
+                       $maptypeMapCnt = 0;
+               }
+
+               $h = '';
+
+               $h .= "<H2>Manage {$this->restypename}s</H2>\n";
+               $h .= "<FORM action=\"" . BASEURL . SCRIPT . "\" 
method=post>\n";
+               $showsubmit = 0;
+               if(in_array("{$this->restype}Admin", $user["privileges"]) &&
+                  ($this->addable == 1 || $resAdminCnt)) {
+                       $cont = addContinuationsEntry("viewResources", 
$this->basecdata);
+                       $h .= "<INPUT type=radio name=continuation 
value=\"$cont\" checked ";
+                       $h .= "id=\"{$this->restype}edit\"><label 
for=\"{$this->restype}edit\">Edit ";
+                       $h .= "{$this->restypename} Profiles</label><br>\n";
+                       $showsubmit = 1;
+               }
+
+               if(($resAdminCnt && $resGroupCnt) || ($resMapCnt && 
$maptypeMapCnt)) {
+                       if($this->hasmapping)
+                               $label = "Edit Grouping &amp; Mapping";
+                       else
+                               $label = "Edit Grouping";
+                       $cont = addContinuationsEntry("groupMapHTML", 
$this->basecdata);
+                       $h .= "<INPUT type=radio name=continuation 
value=\"$cont\" id=\"";
+                       $h .= "resgroupmap\"><label 
for=\"resgroupmap\">$label</label><br>\n";
+                       $showsubmit = 1;
+               }
+
+               if($resAdminCnt)
+                       $h .= $this->extraSelectAdminOptions();
+
+               if($showsubmit)
+                       $h .= "<br><INPUT type=submit value=Submit>\n";
+               else
+                       $h .= "You don't have access to manage any 
{$this->restype}s.<br>\n";
+               $h .= "</FORM>\n";
+
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn viewResources()
+       ///
+       /// \brief prints a page to view resource information
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function viewResources() {
+               global $user, $mode;
+               $h = '';
+               $h .= "<h2>{$this->restypename} Profiles</h2>\n";
+
+               $resdata = $this->getData($this->defaultGetDataArgs);
+               if(! empty($resdata)) {
+                       $tmp = array_keys($resdata);
+                       $testid = $tmp[0];
+                       $fields = array_keys($resdata[$testid]);
+               }
+
+               # hidden elements
+               $cdata = $this->basecdata;
+               $cdata['add'] = 1;
+               $cont = addContinuationsEntry('AJsaveResource', $cdata);
+               $h .= "<input type=\"hidden\" id=\"addresourcecont\" 
value=\"$cont\">\n";
+               if(! empty($resdata)) {
+                       $h .= "<input type=\"hidden\" 
id=\"saveresourcecont\">\n";
+                       $cont = addContinuationsEntry('AJeditResource', 
$this->basecdata);
+                       $h .= "<input type=\"hidden\" id=\"editresourcecont\" 
value=\"$cont\">\n";
+                       if($this->deletable) {
+                               $cont = 
addContinuationsEntry('AJpromptToggleDeleteResource', $this->basecdata);
+                               $h .= "<input type=\"hidden\" 
id=\"deleteresourcecont\" value=\"$cont\">\n";
+                       }
+                       $cont = addContinuationsEntry('jsonResourceStore', 
$this->basecdata);
+                       $h .= "<div dojoType=\"dojo.data.ItemFileWriteStore\" 
url=\"" . BASEURL;
+                       $h .= SCRIPT . "?continuation=$cont\" 
jsid=\"resourcestore\" ";
+                       $h .= "comparatorMap=\"\{\}\"></div>\n";
+                       /*$h .= "<div 
dojoType=\"dojo.data.ItemFileWriteStore\"\n";
+                       $h .= "data=\"{'identifier':'id', 'label':'name', 
'items':[]}\" \n";
+                       $h .= "jsid=\"affiliationstore\"></div>\n";
+                       $h .= "<div 
dojoType=\"dojo.data.ItemFileWriteStore\"\n";
+                       $h .= "data=\"{'identifier':'id', 'label':'name', 
'items':[]}\" \n";
+                       $h .= "jsid=\"ownerstore\"></div>\n";
+                       $h .= "<div 
dojoType=\"dojo.data.ItemFileWriteStore\"\n";
+                       $h .= "data=\"{'identifier':'id', 'label':'name', 
'items':[]}\" \n";
+                       $h .= "jsid=\"editgroupstore\"></div>\n";*/
+               }
+
+               if($this->addable)
+                       $h .= dijitButton('', "Add New {$this->restypename}", 
"addNewResource('Add {$this->restypename}');");
+
+               if(empty($resdata)) {
+                       $h .= "<br><br>(No {$this->restypename}s found to which 
you have access.)\n";
+                       $cont = addContinuationsEntry("viewResources", 
$this->basecdata);
+                       $url = BASEURL . SCRIPT . "?continuation=$cont";
+                       $h .= "<input type=\"hidden\" id=\"reloadpageurl\" 
value=\"$url\">\n";
+               }
+
+               $h .= $this->addEditDialogHTML(0);
+
+               if(empty($resdata)) {
+                       print $h;
+                       return;
+               }
+
+               # filters
+               $h .= "<div dojoType=\"dijit.TitlePane\" title=\"Filters (click 
to expand)\" ";
+               $h .= "open=\"false\">\n";
+               $h .= "<span id=\"namefilter\">\n";
+               $h .= "<strong>Name</strong>:\n";
+               $h .= "<div dojoType=\"dijit.form.TextBox\" id=\"namefilter\" 
length=\"80\">";
+               $h .= "  <script type=\"dojo/connect\" event=\"onKeyUp\" 
args=\"event\">\n";
+               $h .= "    if(event.keyCode == 13) resource.GridFilter();\n";
+               $h .= "  </script>\n";
+               $h .= "</div>\n";
+
+               $h .= dijitButton('', "Apply Name Filter", 
"resource.GridFilter();");
+               $h .= "<br>\n";
+
+               $h .= "</span>\n"; # namefilter
+               $h .= "<strong>Displayed Fields</strong>:<br>\n";
+               $h .= $this->addDisplayCheckboxes($fields, $resdata[$testid]);
+               if($this->deletetoggled) {
+                       $h .= "<label for=\"showdeleted\"><strong>Include 
Deleted ";
+                       $h .= "{$this->restypename}s:</strong>:</label>\n";
+                       $h .= "<input type=\"checkbox\" 
dojoType=\"dijit.form.CheckBox\" ";
+                       $h .= "id=\"showdeleted\" 
onChange=\"resource.GridFilter();\">\n";
+               }
+               $h .= "</div>\n";
+
+               $h .= $this->extraResourceFilters();
+
+               $h .= "<div id=\"gridcontainer\">\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"resourcegrid\" ";
+               $h .= "sortInfo=3 store=\"resourcestore\" autoWidth=\"true\" 
style=\"";
+               #$h .= "height: 580px;\" query=\"{type: new 
RegExp('normal|federated|courseroll')}\">\n";
+               if($this->deletetoggled)
+                       $h .= "height: 580px;\" query=\"{deleted: '0'}\">\n";
+               else
+                       $h .= "height: 580px;\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               if(preg_match('/MSIE/i', $_SERVER['HTTP_USER_AGENT']))
+                       $w = array('64px', '38px', '200px', '142px', '65px', 
'142px', '59px', '58px', '63px', '73px');
+               else
+                       $w = array('5em', '3em', '17em', '12em', '5em', '12em', 
'5em', '5em', '5.6em', '6.3em');
+               $h .= "<th field=\"id\" id=\"delcolth\" width=\"{$w[0]}\" 
formatter=\"resource.DeleteBtn\" styles=\"text-align: center;\">&nbsp;</th>\n";
+               $h .= "<th field=\"id\" width=\"{$w[1]}\" 
formatter=\"resource.EditBtn\" styles=\"text-align: center;\">&nbsp;</th>\n";
+               $h .= "<th field=\"name\" width=\"{$w[2]}\">Name</th>\n";
+               $h .= "<th field=\"owner\" width=\"{$w[3]}\">Owner</th>\n";
+               foreach($fields as $field) {
+                       if($field == $this->namefield ||
+                          $field == 'name' ||
+                          $field == 'owner' ||
+                          is_array($resdata[$testid][$field]) ||
+                          preg_match('/id$/', $field))
+                               continue;
+                       $h .= "<th field=\"$field\" hidden=\"true\" 
formatter=\"resource.colformatter\">";
+                       $h .= $this->fieldDisplayName($field);
+                       $h .= "</th>\n";
+               }
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</div>\n";
+
+               if($this->deletable) {
+                       # toggle delete dialog
+                       $h .= "<div id=\"toggleDeleteDialog\" 
dojoType=\"dijit.Dialog\">\n";
+                       $h .= "<h2 id=\"toggleDeleteHeading\"></h2>\n";
+                       $h .= "<span id=\"toggleDeleteQuestion\"></span><br>\n";
+                       $h .= "<div id=\"confdelrescontent\"></div>\n";
+                       $h .= dijitButton('toggleDeleteBtn', "Delete 
{$this->restypename}", "submitToggleDeleteResource();");
+                       $h .= dijitButton('', "Cancel", 
"clearHideConfirmDelete();");
+                       $h .= "<input type=hidden id=\"submitdeletecont\">\n";
+                       $h .= "</div>\n";
+               }
+
+               print $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn addDisplayCheckboxes($allfields, $sample)
+       ///
+       /// \param $allfields - array of fields for which to generate checkboxes
+       /// \param $sample - sample data item that is used to determine what 
fields
+       /// to use for generating checkboxes
+       ///
+       /// \return html
+       ///
+       /// \brief generates checkboxes to be used as filters on the 
viewResources
+       /// page
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function addDisplayCheckboxes($allfields, $sample) {
+               $fields = array('owner');
+               foreach($allfields as $field) {
+                       if($field == $this->namefield ||
+                          $field == 'name' ||
+                          $field == 'owner' ||
+                          is_array($sample[$field]) ||
+                          preg_match('/id$/', $field))
+                               continue;
+                       $fields[] = $field;
+               }
+               $h = '';
+               $fieldcnt = count($fields);
+               $cols = $fieldcnt / 4;
+               if($cols > 4)
+                       $cols = 4;
+               if($fieldcnt < 6) {
+                       foreach($fields as $field) {
+                               if($field == 'name' || $field == 'owner')
+                                       $h .= "<input type=checkbox 
id=chk$field checked onClick=\"resource.toggleResFieldDisplay(this, 
'$field')\">";
+                               else
+                                       $h .= "<input type=checkbox 
id=chk$field onClick=\"resource.toggleResFieldDisplay(this, '$field')\">";
+                               $h .= "<label for=chk$field>";
+                               $h .= $this->fieldDisplayName($field);
+                               $h .= "</label><br>\n";
+                       }
+               }
+               else {
+                       $h .= "<table>\n";
+                       $cnt = 0;
+                       foreach($fields as $field) {
+                               $mod = $cols;
+                               if($cnt % $mod == 0)
+                                       $h .= "<tr>\n";
+                               if($field == 'name' || $field == 'owner')
+                                       $h .= "  <td><input type=checkbox 
id=chk$field checked onClick=\"resource.toggleResFieldDisplay(this, 
'$field')\">";
+                               else
+                                       $h .= "  <td><input type=checkbox 
id=chk$field onClick=\"resource.toggleResFieldDisplay(this, '$field')\">";
+                               $h .= "<label for=chk$field>";
+                               $h .= $this->fieldDisplayName($field);
+                               $h .= "</label><br>\n";
+                               $cnt++;
+                               if($cnt % $mod == 0)
+                                       $h .= "</tr>\n";
+                       }
+                       if($cnt % $mod != 0)
+                               $h .= "</tr>\n";
+                       $h .= "</table>\n";
+               }
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn fieldDisplayName($field)
+       ///
+       /// \param $field - name of a resource field
+       ///
+       /// \return display value for $field
+       ///
+       /// \brief generates the display value for $field; this base function 
just
+       /// uppercases the first letter; each inheriting class should create 
its own
+       /// function
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function fieldDisplayName($field) {
+               return ucfirst($field);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn extraResourceFilters()
+       ///
+       /// \return empty string
+       ///
+       /// \brief base function; allows inheriting classes to generate 
additional
+       /// filters to be displayed on the viewResources page
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function extraResourceFilters() {
+               return '';
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn jsonResourceStore()
+       ///
+       /// \brief generates and sends a JSON formatted store of resource data
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function jsonResourceStore() {
+               global $user;
+               $args = $this->defaultGetDataArgs;
+               $args['includedeleted'] = 1;
+               $resdata = $this->getData($args);
+               $resources = getUserResources(array($this->restype . "Admin"), 
array("administer"), 0, 1);
+               foreach($resources as $type => $tmp) {
+                       if($type != $this->restype)
+                               unset($resources[$type]);
+               }
+
+
+               // this method may include fields for some records but not 
others
+               /*$items = array();
+               foreach($resdata as $id => $res) {
+                       if(! array_key_exists($id, $resources[$this->restype]))
+                               continue;
+                       $g = array('id' => $id);
+                       $g['name'] = $res[$this->namefield];
+                       $g['owner'] = $res['owner'];
+                       foreach($res as $key => $val) {
+                               if($key == 'name' ||
+                                  $key == 'owner' ||
+                                  $key == $this->namefield ||
+                                  is_array($val) ||
+                                  preg_match('/id$/', $key))
+                                       continue;
+                               $g[$key] = $val;
+                       }
+                       $items[] = $g;
+               }
+               return $items;*/
+
+
+
+               // this method only includes keys that exist in the first 
element
+               reset($resdata);
+               $id = key($resdata);
+               $fields = array_keys($resdata[$id]);
+               $items = array();
+               foreach($resdata as $id => $res) {
+                       if(! array_key_exists($id, $resources[$this->restype]))
+                               continue;
+                       $item = array('id' => $id);
+                       $item['name'] = $res[$this->namefield];
+                       $item['owner'] = $res['owner'];
+                       foreach($fields as $field) {
+                               if($field == 'name' ||
+                                  $field == 'owner' ||
+                                  $field == $this->namefield ||
+                                  ! array_key_exists($field, $res) ||
+                                  is_array($res[$field]) ||
+                                  preg_match('/id$/', $field))
+                                       continue;
+                               $item[$field] = $res[$field];
+                       }
+                       $items[] = $item;
+                       unset($resdata[$id]);
+               }
+               sendJSON($items, 'id');
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn toggleDeleteResource($rscid)
+       ///
+       /// \param $rscid - id of a resource (from table specific to that 
resource,
+       /// not from the resource table)
+       ///
+       /// \return 1 on success, 0 on failure
+       ///
+       /// \brief if resource type allows resources to be flagged as deleted;
+       /// toggles the deleted flag; otherwise deletes the entry from that 
resources
+       /// table and the general resource table
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function toggleDeleteResource($rscid) {
+               if($this->deletetoggled) {
+                       $query = "SELECT deleted "
+                              . "FROM `{$this->restype}` "
+                              . "WHERE id = $rscid";
+                       $qh = doQuery($query);
+                       if($row = mysql_fetch_assoc($qh)) {
+                               $newval = (int)(! (int)$row['deleted']);
+                               $query = "UPDATE {$this->restype} "
+                                      . "SET deleted = $newval "
+                                      . "WHERE id = $rscid";
+                               doQuery($query);
+                               $this->submitToggleDeleteResourceExtra($rscid, 
$row['deleted']);
+                       }
+                       else
+                               return 0;
+               }
+               else {
+                       $query = "DELETE r "
+                              . "FROM resource r, "
+                              .      "resourcetype rt "
+                              . "WHERE r.resourcetypeid = rt.id AND "
+                              .       "rt.name = '{$this->restype}' AND "
+                              .       "r.subid = $rscid";
+                       doQuery($query);
+                       $query = "DELETE FROM `{$this->restype}` "
+                              . "WHERE id = $rscid";
+                       doQuery($query);
+
+                       $this->submitToggleDeleteResourceExtra($rscid);
+               }
+
+               # clear user resource cache for this type
+               $key = getKey(array(array($this->restype . "Admin"), 
array("administer"), 0, 1, 0));
+               unset($_SESSION['userresources'][$key]);
+               $key = getKey(array(array($this->restype . "Admin"), 
array("administer"), 0, 0, 0));
+               unset($_SESSION['userresources'][$key]);
+
+               return 1;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJpromptToggleDeleteResource()
+       ///
+       /// \brief generates and sends content prompting user to confirm 
deletion of
+       /// resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJpromptToggleDeleteResource() {
+               $rscid = processInputVar('rscid', ARG_NUMERIC);
+               # check access to $rscid
+               $resources = getUserResources(array("{$this->restype}Admin"), 
array("administer"), 0, 1);
+               if(! array_key_exists($rscid, $resources[$this->restype])) {
+                       $type = strtolower($this->restypename);
+                       $rt = array('status' => 'noaccess',
+                                   'msg' => "You do not have access to delete 
the selected $type.",
+                                   'rscid' => $rscid);
+                       sendJSON($rt);
+                       return;
+               }
+               $rt = array('html' => '',
+                           'title' => "Confirm Delete {$this->restypename}",
+                           'question' => "Delete the following 
{$this->restype}?",
+                           'btntxt' => "Delete {$this->restypename}",
+                           'status' => 'success');
+               $args = $this->defaultGetDataArgs;
+               if($this->deletetoggled)
+                       $args['includedeleted'] = 1;
+               $args['rscid'] = $rscid;
+               $resdata = $this->getData($args);
+               if($this->deletetoggled && $resdata[$rscid]['deleted']) {
+                       $rt['title'] = "Confirm Undelete {$this->restypename}";
+                       $rt['question'] = "Undelete the following 
{$this->restype}?";
+                       $rt['btntxt'] = "Undelete {$this->restypename}";
+               }
+               $fields = array_keys($resdata[$rscid]);
+               $rt['html'] .= "<table>";
+               $rt['html'] .= 
"<tr><th>Name:</th><td>{$resdata[$rscid][$this->namefield]}</td></tr>";
+               $rt['html'] .= 
"<tr><th>Owner:</th><td>{$resdata[$rscid]['owner']}</td></tr>";
+               foreach($fields as $field) {
+                       if($field == $this->namefield ||
+                          $field == 'name' ||
+                          $field == 'owner' ||
+                          is_array($resdata[$rscid][$field]) ||
+                          preg_match('/id$/', $field))
+                               continue;
+                       $rt['html'] .= "<tr><th>";
+                       $rt['html'] .= ucfirst($field);
+                       $rt['html'] .= 
":</th><td>{$resdata[$rscid][$field]}</td></tr>";
+               }
+               $rt['html'] .= "</table>";
+               $rt['html'] .= $this->toggleDeleteResourceExtra();
+
+               $cdata = getContinuationVar();
+               $cdata['rscid'] = $rscid;
+               $cont = addContinuationsEntry('AJsubmitToggleDeleteResource', 
$cdata);
+               $rt['cont'] = $cont;
+               sendJSON($rt);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn toggleDeleteResourceExtra()
+       ///
+       /// \return empty string
+       ///
+       /// \brief allows inheriting class to generate additional information 
to be
+       /// included on the confirm toggle delete resource page
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function toggleDeleteResourceExtra() {
+               return '';
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJsubmitToggleDeleteResource()
+       ///
+       /// \brief AJAX callable wrapper for toggleDeleteResource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJsubmitToggleDeleteResource() {
+               $rscid = getContinuationVar('rscid');
+               if($this->toggleDeleteResource($rscid))
+                       $rt = array('status' => 'success', 'rscid' => $rscid);
+               else
+                       $rt = array('status' => 'failed', 'rscid' => $rscid);
+               sendJSON($rt);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn submitToggleDeleteResourceExtra($rscid, $deleted)
+       ///
+       /// \param $rscid - id of a resource (from table specific to that 
resource,
+       /// not from the resource table)
+       /// \param $deleted - (optional, default=0) 1 if resource was previously
+       /// deleted; 0 if not
+       ///
+       /// \brief function to do any extra stuff specific to a resource type 
when
+       /// toggling delete for a resource; to be implemented by inheriting 
class if
+       /// needed
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function submitToggleDeleteResourceExtra($rscid, $deleted=0) {
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn groupMapHTML()
+       ///
+       /// \brief prints HTML for groupping and mapping page
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function groupMapHTML() {
+               $h = '';
+               $h .= "<div dojoType=\"dojo.data.ItemFileWriteStore\" 
jsId=\"resourcetogroupsstore\" ";
+               $h .= "data=\"resourcetogroupsdata\"></div>\n";
+               $h .= "<div dojoType=\"dojo.data.ItemFileWriteStore\" 
jsId=\"grouptoresourcesstore\" ";
+               $h .= "data=\"grouptoresourcesdata\"></div>\n";
+               $h .= "<div dojoType=\"dojo.data.ItemFileWriteStore\" 
jsId=\"mapbyresgroupstore\" ";
+               $h .= "data=\"mapbyresgroupdata\"></div>\n";
+               $h .= "<div dojoType=\"dojo.data.ItemFileWriteStore\" 
jsId=\"mapbymaptogroupstore\" ";
+               $h .= "data=\"mapbymaptogroupdata\"></div>\n";
+               $h .= "<div id=\"mainTabContainer\" 
dojoType=\"dijit.layout.TabContainer\"\n";
+               $h .= "     style=\"width:600px;height:600px\">\n";
+               $h .= $this->groupByResourceHTML();
+               $h .= $this->groupByGroupHTML();
+               if($this->hasmapping) {
+                       $h .= "<input type=\"hidden\" id=\"domapping\" 
value=\"1\">\n";
+                       $h .= $this->mapByResGroupHTML();
+                       $h .= $this->mapByMapToGroupHTML();
+               }
+               else
+                       $h .= "<input type=\"hidden\" id=\"domapping\" 
value=\"0\">\n";
+               $h .= "</div>\n";
+               print $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn groupByResourceHTML()
+       ///
+       /// \return html
+       ///
+       /// \brief generates HTML for resource grouping by selecting a resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function groupByResourceHTML() {
+               # build list of resources
+               $tmp = getUserResources(array($this->restype . "Admin"), 
array('manageGroup'));
+               if(empty($tmp[$this->restype]))
+                       return '';
+               $resources = $tmp[$this->restype];
+               uasort($resources, 'sortKeepIndex');
+               $h = '';
+               $h .= "<div id=\"groupbyresourcediv\" 
dojoType=\"dijit.layout.ContentPane\" title=\"Group By 
{$this->restypename}\">\n";
+               $h .= "<div id=\"groupbyresourcedesc\">\n";
+               $h .= "Select an item from the drop-down box and click \"Get 
Groups\" ";
+               $h .= "to see<br>all of the groups it is in. Then, select a 
group it ";
+               $h .= "is in and click the Remove<br>button to remove it from 
that group, ";
+               $h .= "or select a group it is not in and click<br>the Add 
button to ";
+               $h .= "add it to that group.<br><br>\n";
+               $h .= "</div>\n"; # groupbyresourcedesc
+               $h .= "<div id=\"groupbyresourcesel\">\n";
+               $h .= "{$this->restypename}:<select id=\"resources\">\n";
+               foreach($resources as $id => $res)
+                       $h .= "<option value=$id>$res</option>\n";
+               $h .= "</select>\n";
+               $h .= dijitButton('fetchGrpsButton', "Get Groups",
+                                      "populateLists('resources', 'ingroups', 
'inresourcename', 'outresourcename', 'resgroupinggroupscont');");
+               $h .= "</div>\n"; # groupbyresourcesel
+               $h .= "<table><tbody><tr>\n";
+               # select for groups resource is in
+               $h .= "<td valign=top>\n";
+               $h .= "Groups <span style=\"font-weight: bold;\" 
id=\"inresourcename\"></span> is in:<br>\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"ingroups\" ";
+               $h .= "store=\"resourcetogroupsstore\" style=\"width: 240px; 
height: 250px;\" query=\"{inout: 1}\" ";
+               $h .= "selectionMode=\"extended\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               $h .= "<th field=\"name\" width=\"160px\"></th>\n";
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</td>\n";
+               # transfer buttons
+               $h .= "<td style=\"vertical-align: middle;\">\n";
+               $h .= dijitButton('', "<div style=\"width: 
50px;\">&lt;-Add</div>", "resource.addRemItem('addgrpcont', 'resources', 
'outgroups');");
+               $cdata = $this->basecdata;
+               $cdata['mode'] = 'add';
+               $cont = addContinuationsEntry('AJaddRemGroupResource', $cdata);
+               $h .= "<input type=\"hidden\" id=\"addgrpcont\" 
value=\"$cont\">\n";
+               $h .= "<br><br><br>\n";
+               $h .= dijitButton('', "<div style=\"width: 
50px;\">Remove-&gt;</div>", "resource.addRemItem('remgrpcont', 'resources', 
'ingroups');");
+               $cdata['mode'] = 'remove';
+               $cont = addContinuationsEntry('AJaddRemGroupResource', $cdata);
+               $h .= "<input type=\"hidden\" id=\"remgrpcont\" 
value=\"$cont\">\n";
+               $h .= "</td>\n";
+               # select for groups resource is not in
+               $h .= "<td valign=top>\n";
+               $h .= "Groups <span style=\"font-weight: bold;\" 
id=\"outresourcename\"></span> is not in:<br>\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"outgroups\" ";
+               $h .= "store=\"resourcetogroupsstore\" style=\"width: 240px; 
height: 250px;\" query=\"{inout: 1}\" ";
+               $h .= "selectionMode=\"extended\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               $h .= "<th field=\"name\" width=\"160px\"></th>\n";
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</td>\n";
+               $h .= "</tr></tbody></table>\n";
+               $cdata = $this->basecdata;
+               $cdata['store'] = 'resourcetogroupsstore';
+               $cdata['intitle'] = 'ingroups';
+               $cdata['outtitle'] = 'outgroups';
+               $cont = addContinuationsEntry('jsonResourceGroupingGroups', 
$cdata);
+               $h .= "<input type=hidden id=\"resgroupinggroupscont\" 
value=\"$cont\">\n";
+               $h .= "</div>\n";
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn jsonResourceGroupingGroups()
+       ///
+       /// \brief sends JSON of resource groups for resource grouping by 
selecting a
+       /// resource page
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function jsonResourceGroupingGroups() {
+               $resid = processInputVar('id', ARG_NUMERIC);
+               $resources = getUserResources(array($this->restype . "Admin"), 
array("manageGroup"));
+               if(! array_key_exists($resid, $resources[$this->restype])) {
+                       sendJSON(array('status' => 'noaccess'));
+                       return;
+               }
+               $groups = getUserResources(array($this->restype . 'Admin'), 
array('manageGroup'), 1);
+               $memberships = getResourceGroupMemberships($this->restype);
+               $all = array();
+               foreach($groups[$this->restype] as $id => $group) {
+                       if(array_key_exists($resid, 
$memberships[$this->restype]) &&
+                               in_array($id, 
$memberships[$this->restype][$resid]))
+                               $all[] = array('id' => $id, 'name' => $group, 
'inout' => 1);
+                       else
+                               $all[] = array('id' => $id, 'name' => $group, 
'inout' => 0);
+               }
+               $arr = array('items' => $all,
+                            'intitle' => getContinuationVar('intitle'),
+                            'outtitle' => getContinuationVar('outtitle'));
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJaddRemGroupResource()
+       ///
+       /// \brief adds or removes groups for a resource and sends JSON response
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJaddRemGroupResource() {
+               $rscid = processInputVar('id', ARG_NUMERIC);
+               $resources = getUserResources(array($this->restype . "Admin"), 
array("manageGroup"));
+               if(! array_key_exists($rscid, $resources[$this->restype])) {
+                       $arr = array('status' => 'noaccess');
+                       sendJSON($arr);
+                       return;
+               }
+
+               $groups = getUserResources(array($this->restype . "Admin"), 
array("manageGroup"), 1);
+               $tmp = processInputVar('listids', ARG_STRING);
+               $tmp = explode(',', $tmp);
+               $groupids = array();
+               foreach($tmp as $id) {
+                       if(! is_numeric($id))
+                               continue;
+                       if(! array_key_exists($id, $groups[$this->restype])) {
+                               $arr = array('status' => 'noaccess');
+                               sendJSON($arr);
+                               return;
+                       }
+                       $groupids[] = $id;
+               }
+
+               $mode = getContinuationVar('mode');
+
+               $args = $this->defaultGetDataArgs;
+               $args['rscid'] = $rscid;
+               $resdata = $this->getData($args);
+
+               if($mode == 'add') {
+                       $adds = array();
+                       foreach($groupids as $id)
+                               $adds[] = "({$resdata[$rscid]['resourceid']}, 
$id)";
+                       $query = "INSERT IGNORE INTO resourcegroupmembers "
+                                        . "(resourceid, resourcegroupid) 
VALUES ";
+                       $query .= implode(',', $adds);
+                       doQuery($query);
+               }
+               else {
+                       $rems = implode(',', $groupids);
+                       $query = "DELETE FROM resourcegroupmembers "
+                                        . "WHERE resourceid = 
{$resdata[$rscid]['resourceid']} AND "
+                                        .       "resourcegroupid IN ($rems)";
+                       doQuery($query);
+               }
+
+               $_SESSION['userresources'] = array();
+               $regids = "^" . implode('$|^', $groupids) . "$";
+               $arr = array('status' => 'success',
+                            'regids' => $regids,
+                            'inselobj' => 'ingroups',
+                            'outselobj' => 'outgroups');
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn groupByGroupHTML()
+       ///
+       /// \return html
+       ///
+       /// \brief generates HTML for resource grouping by selecting a resource 
group
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function groupByGroupHTML() {
+               $resources = getUserResources(array($this->restype . 'Admin'), 
array('manageGroup'));
+               if(empty($resources[$this->restype]))
+                       return '';
+               $h = '';
+               $h .= "<div id=\"groupbygroupdiv\" 
dojoType=\"dijit.layout.ContentPane\" title=\"Group By Group\">\n";
+               $h .= "Select a group from the drop-down box and click \"Get 
{$this->restypename}s\"<br>";
+               $h .= "to see all of the resources in it. Then, select a 
resource in it and click the<br>";
+               $h .= "Remove button to remove it from that group, or select a 
resource that is not ";
+               $h .= "<br>in it and click the Add button to add it to that 
group.<br><br>\n";
+               $h .= "Group:<select id=\"resgroups\">\n";
+               # build list of groups
+               $tmp = getUserResources(array($this->restype . "Admin"), 
array('manageGroup'), 1);
+               $groups = $tmp[$this->restype];
+               uasort($groups, 'sortKeepIndex');
+               foreach($groups as $id => $group)
+                       $h .= "<option value=$id>$group</option>\n";
+               $h .= "</select>\n";
+               $h .= dijitButton('fetchResourcesButton', "Get 
{$this->restypename}s",
+                                 "populateLists('resgroups', 'inresources', 
'ingroupname', 'outgroupname', 'resgroupingresourcescont');");
+               $h .= "<table><tbody><tr>\n";
+               # select for resources in group
+               $h .= "<td valign=top>\n";
+               $h .= "{$this->restypename}s in <span style=\"font-weight: 
bold;\" id=\"ingroupname\"></span>:<br>\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"inresources\" ";
+               $h .= "store=\"grouptoresourcesstore\" style=\"width: 240px; 
height: 250px;\" query=\"{inout: 1}\" ";
+               $h .= "selectionMode=\"extended\" sortInfo=\"1\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               $h .= "<th field=\"name\" width=\"160px\"></th>\n";
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</td>\n";
+               # transfer buttons
+               $h .= "<td style=\"vertical-align: middle;\">\n";
+               $h .= dijitButton('', "<div style=\"width: 
50px;\">&lt;-Add</div>", "resource.addRemItem('additemcont', 'resgroups', 
'outresources');");
+               $cdata = $this->basecdata;
+               $cdata['mode'] = 'add';
+               $cont = addContinuationsEntry('AJaddRemResourceGroup', $cdata);
+               $h .= "<input type=\"hidden\" id=\"additemcont\" 
value=\"$cont\">\n";
+               $h .= "<br><br><br>\n";
+               $h .= dijitButton('', "<div style=\"width: 
50px;\">Remove-&gt;</div>", "resource.addRemItem('remitemcont', 'resgroups', 
'inresources');");
+               $cdata['mode'] = 'remove';
+               $cont = addContinuationsEntry('AJaddRemResourceGroup', $cdata);
+               $h .= "<input type=\"hidden\" id=\"remitemcont\" 
value=\"$cont\">\n";
+               $h .= "</td>\n";
+               # select for groups resource is not in
+               $h .= "<td valign=top>\n";
+               $h .= "{$this->restypename}s not in <span style=\"font-weight: 
bold;\" id=\"outgroupname\"></span>:<br>\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"outresources\" ";
+               $h .= "store=\"grouptoresourcesstore\" style=\"width: 240px; 
height: 250px;\" query=\"{inout: 1}\" ";
+               $h .= "selectionMode=\"extended\" sortInfo=\"1\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               $h .= "<th field=\"name\" width=\"160px\"></th>\n";
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</td>\n";
+               $h .= "</tr></tbody></table>\n";
+               $cdata = $this->basecdata;
+               $cdata['store'] = 'grouptoresourcesstore';
+               $cdata['intitle'] = 'inresources';
+               $cdata['outtitle'] = 'outresources';
+               $cont = addContinuationsEntry('jsonResourceGroupingResources', 
$cdata);
+               $h .= "<input type=hidden id=\"resgroupingresourcescont\" 
value=\"$cont\">\n";
+               $h .= "</div>\n";
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn jsonResourceGroupingResources()
+       ///
+       /// \brief sends JSON of resources for resource grouping by selecting a
+       /// resource group
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function jsonResourceGroupingResources() {
+               $groupid = processInputVar('id', ARG_NUMERIC);
+               $groups = getUserResources(array($this->restype . "Admin"), 
array("manageGroup"), 1);
+               if(! array_key_exists($groupid, $groups[$this->restype])) {
+                       sendJSON(array('status' => 'noaccess'));
+                       return;
+               }
+               $resources = getUserResources(array($this->restype . 'Admin'), 
array('manageGroup'));
+               #uasort($resources[$this->restype], 'sortKeepIndex');
+               $memberships = getResourceGroupMemberships($this->restype);
+               $all = array();
+               foreach($resources[$this->restype] as $id => $res) {
+                       if(array_key_exists($id, $memberships[$this->restype]) 
&&
+                               in_array($groupid, 
$memberships[$this->restype][$id]))
+                               $all[] = array('id' => $id, 'name' => $res, 
'inout' => 1);
+                       else
+                               $all[] = array('id' => $id, 'name' => $res, 
'inout' => 0);
+               }
+               $arr = array('items' => $all,
+                            'intitle' => getContinuationVar('intitle'),
+                            'outtitle' => getContinuationVar('outtitle'));
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJaddRemResourceGroup()
+       ///
+       /// \brief adds or removes resources for a resource group and sends JSON
+       /// response
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJaddRemResourceGroup() {
+               $groupid = processInputVar('id', ARG_NUMERIC);
+               $groups = getUserResources(array($this->restype . "Admin"), 
array("manageGroup"), 1);
+               if(! array_key_exists($groupid, $groups[$this->restype])) {
+                       $arr = array('status' => 'noaccess');
+                       sendJSON($arr);
+                       return;
+               }
+
+               $resources = getUserResources(array($this->restype . "Admin"), 
array("manageGroup"));
+               $tmp = processInputVar('listids', ARG_STRING);
+               $tmp = explode(',', $tmp);
+               $rscids = array();
+               foreach($tmp as $id) {
+                       if(! is_numeric($id))
+                               continue;
+                       if(! array_key_exists($id, $resources[$this->restype])) 
{
+                               $arr = array('status' => 'noaccess');
+                               sendJSON($arr);
+                               return;
+                       }
+                       $rscids[] = $id;
+               }
+
+               $mode = getContinuationVar('mode');
+
+               $resdata = $this->getData($this->defaultGetDataArgs);
+
+               if($mode == 'add') {
+                       $adds = array();
+                       foreach($rscids as $id)
+                               $adds[] = "({$resdata[$id]['resourceid']}, 
$groupid)";
+                       $query = "INSERT IGNORE INTO resourcegroupmembers "
+                                        . "(resourceid, resourcegroupid) 
VALUES ";
+                       $query .= implode(',', $adds);
+               }
+               else {
+                       $delids = array();
+                       foreach($rscids as $id)
+                               $delids[] = $resdata[$id]['resourceid'];
+                       $inlist = implode(',', $delids);
+                       $query = "DELETE FROM resourcegroupmembers "
+                                        . "WHERE resourcegroupid = $groupid 
AND "
+                                        .       "resourceid IN ($inlist)";
+                       doQuery($query);
+               }
+
+               doQuery($query);
+               $_SESSION['userresources'] = array();
+               $regids = "^" . implode('$|^', $rscids) . "$";
+               $arr = array('status' => 'success',
+                            'regids' => $regids,
+                            'inselobj' => 'inresources',
+                            'outselobj' => 'outresources');
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn 
+       ///
+       /// \brief Resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function groupByGridHTML() {
+               # TODO
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn mapByResGroupHTML()
+       ///
+       /// \return html
+       ///
+       /// \brief generates HTML for resource mapping by selecting a resource 
group
+       /// of this type of resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function mapByResGroupHTML() {
+               $tmp = getUserResources(array($this->restype . "Admin"),
+                                       array("manageMapping"), 1);
+               $groups = $tmp[$this->restype];
+               uasort($groups, "sortKeepIndex");
+               $tmp = getUserResources(array($this->maptype . "Admin"),
+                                       array("manageMapping"), 1);
+               $mapgroups = $tmp[$this->maptype];
+               uasort($mapgroups, "sortKeepIndex");
+               $h = '';
+
+               if(! count($groups) || ! count($mapgroups)) {
+                       $h .= "You don't have access to manage any mappings for 
this resource ";
+                       $h .= "type.<br>\n";
+                       return $h;
+               }
+
+               $h .= "<div id=\"mapbyresgroupdiv\" 
dojoType=\"dijit.layout.ContentPane\" title=\"Map By {$this->restypename} 
Group\">\n";
+               $h .= "Select an item from the drop-down box and click \"Get 
{$this->maptypename} Groups\"<br>";
+               $h .= "to see all of the groups it maps to. Then, select a 
group ";
+               $h .= "it does not map<br>to and click the Add button to map it 
to that group, ";
+               $h .= "or select a group it<br>maps to and click the Remove ";
+               $h .= "button to unmap it from that group.<br><br>\n";
+               $h .= "{$this->restypename} Group:<select id=\"groups\">\n";
+               foreach($groups as $id => $group)
+                       $h .= "<option value=$id>$group</option>\n";
+               $h .= "</select>\n";
+               $h .= dijitButton('', "Get {$this->maptypename} Groups",
+                                 "populateLists('groups', 'inmapgroups', 
'inmapgroupname', 'outmapgroupname', 'mapbyresgroupcont');");
+               $h .= "<table><tbody><tr>\n";
+               # select for groups mapped to
+               $h .= "<td valign=top>\n";
+               $h .= "{$this->maptypename} Groups <span style=\"font-weight: 
bold;\" id=\"inmapgroupname\"></span> maps to:<br>\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"inmapgroups\" ";
+               $h .= "store=\"mapbyresgroupstore\" style=\"width: 240px; 
height: 250px;\" query=\"{inout: 1}\" ";
+               $h .= "selectionMode=\"extended\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               $h .= "<th field=\"name\" width=\"160px\"></th>\n";
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</td>\n";
+               # transfer buttons
+               $h .= "<td style=\"vertical-align: middle;\">\n";
+               $h .= dijitButton('', "<div style=\"width: 
50px;\">&lt;-Add</div>", "resource.addRemItem('addmapgrpcont', 'groups', 
'outmapgroups');");
+               $cdata = $this->basecdata;
+               $cdata['mode'] = 'add';
+               $cont = addContinuationsEntry('AJaddRemMapToGroup', $cdata);
+               $h .= "<input type=\"hidden\" id=\"addmapgrpcont\" 
value=\"$cont\">\n";
+               $h .= "<br>\n";
+               $h .= "<br>\n";
+               $h .= "<br>\n";
+               $h .= dijitButton('', "<div style=\"width: 
50px;\">Remove-&gt;</div>", "resource.addRemItem('remmapgrpcont', 'groups', 
'inmapgroups');");
+               $cdata['mode'] = 'remove';
+               $cont = addContinuationsEntry('AJaddRemMapToGroup', $cdata);
+               $h .= "<input type=\"hidden\" id=\"remmapgrpcont\" 
value=\"$cont\">\n";
+               $h .= "</td>\n";
+               # select for groups resource is not in
+               $h .= "<td valign=top>\n";
+               $h .= "{$this->maptypename} Groups <span style=\"font-weight: 
bold;\" id=\"outmapgroupname\"></span> does not map to:<br>\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"outmapgroups\" ";
+               $h .= "store=\"mapbyresgroupstore\" style=\"width: 240px; 
height: 250px;\" query=\"{inout: 1}\" ";
+               $h .= "selectionMode=\"extended\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               $h .= "<th field=\"name\" width=\"160px\"></th>\n";
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</td>\n";
+               $h .= "</tr></tbody></table>\n";
+               $cdata = $this->basecdata;
+               $cdata['store'] = 'mapbyresgroupstore';
+               $cdata['intitle'] = 'inmapgroups';
+               $cdata['outtitle'] = 'outmapgroups';
+               $cont = addContinuationsEntry('jsonResourceMappingMapToGroups', 
$cdata);
+               $h .= "<input type=hidden id=\"mapbyresgroupcont\" 
value=\"$cont\">\n";
+               $h .= "</div>\n";
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn jsonResourceMappingMapToGroups()
+       ///
+       /// \brief sends JSON of resource groups for resource mapping by 
selecting a
+       /// resource group of this resource type
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function jsonResourceMappingMapToGroups() {
+               $resgrpid = processInputVar('id', ARG_NUMERIC);
+               $resources = getUserResources(array($this->restype . "Admin"), 
array("manageMapping"), 1);
+               if(! array_key_exists($resgrpid, $resources[$this->restype])) {
+                       sendJSON(array('status' => 'noaccess'));
+                       return;
+               }
+               $mapgroups = getUserResources(array($this->maptype . 'Admin'), 
array('manageMapping'), 1);
+               $mapping = getResourceMapping($this->restype, $this->maptype);
+               $all = array();
+
+               foreach($mapgroups[$this->maptype] as $id => $group) {
+                       if(array_key_exists($resgrpid, $mapping) &&
+                               in_array($id, $mapping[$resgrpid]))
+                               $all[] = array('id' => $id, 'name' => $group, 
'inout' => 1);
+                       else
+                               $all[] = array('id' => $id, 'name' => $group, 
'inout' => 0);
+               }
+               $arr = array('items' => $all,
+                            'intitle' => getContinuationVar('intitle'),
+                            'outtitle' => getContinuationVar('outtitle'));
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJaddRemMapToGroup()
+       ///
+       /// \brief adds or removes groups that map to a group of this resource 
type
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJaddRemMapToGroup() {
+               $groupid = processInputVar('id', ARG_NUMERIC);
+               $groups = getUserResources(array($this->restype . "Admin"),
+                                          array("manageMapping"), 1);
+               if(! array_key_exists($groupid, $groups[$this->restype])) {
+                       $arr = array('status' => 'noaccess');
+                       sendJSON($arr);
+                       return;
+               }
+
+               $mapgroups = getUserResources(array($this->maptype . "Admin"),
+                                             array("manageMapping"), 1);
+               $tmp = processInputVar('listids', ARG_STRING);
+               $tmp = explode(',', $tmp);
+               $mapids = array();
+               foreach($tmp as $id) {
+                       if(! is_numeric($id))
+                               continue;
+                       if(! array_key_exists($id, $mapgroups[$this->maptype])) 
{
+                               $arr = array('status' => 'noaccess');
+                               sendJSON($arr);
+                               return;
+                       }
+                       $mapids[] = $id;
+               }
+
+               $mytypeid = getResourceTypeID($this->restype);
+               $maptypeid = getResourceTypeID($this->maptype);
+
+               $mode = getContinuationVar('mode');
+
+               if($mode == 'add') {
+                       $adds = array();
+                       foreach($mapids as $id)
+                               $adds[] = "($groupid, $mytypeid, $id, 
$maptypeid)";
+                       $query = "INSERT IGNORE INTO resourcemap "
+                                        .        "(resourcegroupid1, 
resourcetypeid1, "
+                                        .         "resourcegroupid2, 
resourcetypeid2) "
+                                        . "VALUES ";
+                       $query .= implode(',', $adds);
+                       doQuery($query);
+               }
+               else {
+                       foreach($mapids as $id) {
+                               $query = "DELETE FROM resourcemap "
+                                                . "WHERE resourcegroupid1 = 
$groupid AND "
+                                                .       "resourcetypeid1 = 
$mytypeid AND "
+                                                .       "resourcegroupid2 = 
$id AND "
+                                                .       "resourcetypeid2 = 
$maptypeid";
+                               doQuery($query);
+                       }
+               }
+               $regids = "^" . implode('$|^', $mapids) . "$";
+               $arr = array('status' => 'success',
+                            'regids' => $regids,
+                            'inselobj' => 'inmapgroups',
+                            'outselobj' => 'outmapgroups');
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn mapByMapToGroupHTML()
+       ///
+       /// \return html
+       ///
+       /// \brief generates HTML for resource mapping by selecting a resource 
group
+       /// of the type that this type maps to
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function mapByMapToGroupHTML() {
+               $tmp = getUserResources(array($this->maptype . "Admin"),
+                                       array("manageMapping"), 1);
+               $mapgroups = $tmp[$this->maptype];
+               uasort($mapgroups, "sortKeepIndex");
+               $tmp = getUserResources(array($this->restype . "Admin"),
+                                       array("manageMapping"), 1);
+               $groups = $tmp[$this->restype];
+               uasort($groups, "sortKeepIndex");
+               $h = '';
+
+               if(! count($mapgroups) || ! count($groups)) {
+                       $h .= "You don't have access to manage any mappings for 
this resource ";
+                       $h .= "type.<br>\n";
+                       return $h;
+               }
+
+               $h .= "<div id=\"mapbymaptogroupdiv\" 
dojoType=\"dijit.layout.ContentPane\" title=\"Map By {$this->maptypename} 
Group\">\n";
+               $h .= "Select an item from the drop-down box and click \"Get 
{$this->restypename} Groups\"<br>";
+               $h .= "to see all of the groups it maps to. Then, select a 
group ";
+               $h .= "it does not map<br>to and click the Add button to map it 
to that group, ";
+               $h .= "or select a group it<br>maps to and click the Remove ";
+               $h .= "button to unmap it from that group.<br><br>\n";
+               $h .= "{$this->maptypename} Group:<select 
id=\"maptogroups\">\n";
+               foreach($mapgroups as $id => $group)
+                       $h .= "<option value=$id>$group</option>\n";
+               $h .= "</select>\n";
+               $h .= dijitButton('', "Get {$this->restypename} Groups",
+                                 "populateLists('maptogroups', 
'inmaptogroups', 'inmaptogroupname', 'outmaptogroupname', 
'mapbymaptogroupcont');");
+               $h .= "<table><tbody><tr>\n";
+               # select for groups mapped to
+               $h .= "<td valign=top>\n";
+               $h .= "{$this->restypename} Groups <span style=\"font-weight: 
bold;\" id=\"inmaptogroupname\"></span> maps to:<br>\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"inmaptogroups\" ";
+               $h .= "store=\"mapbymaptogroupstore\" style=\"width: 240px; 
height: 250px;\" query=\"{inout: 1}\" ";
+               $h .= "selectionMode=\"extended\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               $h .= "<th field=\"name\" width=\"160px\"></th>\n";
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</td>\n";
+               # transfer buttons
+               $h .= "<td style=\"vertical-align: middle;\">\n";
+               $h .= dijitButton('', "<div style=\"width: 
50px;\">&lt;-Add</div>",
+                                 "resource.addRemItem('addmaptogrpcont', 
'maptogroups', 'outmaptogroups');");
+               $cdata = $this->basecdata;
+               $cdata['mode'] = 'add';
+               $cont = addContinuationsEntry('AJaddRemGroupMapTo', $cdata);
+               $h .= "<input type=\"hidden\" id=\"addmaptogrpcont\" 
value=\"$cont\">\n";
+               $h .= "<br><br><br>\n";
+               $h .= dijitButton('', "<div style=\"width: 
50px;\">Remove-&gt;</div>",
+                                 "resource.addRemItem('remmaptogrpcont', 
'maptogroups', 'inmaptogroups');");
+               $cdata['mode'] = 'remove';
+               $cont = addContinuationsEntry('AJaddRemGroupMapTo', $cdata);
+               $h .= "<input type=\"hidden\" id=\"remmaptogrpcont\" 
value=\"$cont\">\n";
+               $h .= "</td>\n";
+               # select for groups resource is not in
+               $h .= "<td valign=top>\n";
+               $h .= "{$this->restypename} Groups <span style=\"font-weight: 
bold;\" id=\"outmaptogroupname\"></span> does not map to:<br>\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"outmaptogroups\" ";
+               $h .= "store=\"mapbymaptogroupstore\" style=\"width: 240px; 
height: 250px;\" query=\"{inout: 1}\" ";
+               $h .= "selectionMode=\"extended\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               $h .= "<th field=\"name\" width=\"160px\"></th>\n";
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</td>\n";
+               $h .= "</tr></tbody></table>\n";
+               $cdata = $this->basecdata;
+               $cdata['store'] = 'mapbymaptogroupstore';
+               $cdata['intitle'] = 'inmaptogroups';
+               $cdata['outtitle'] = 'outmaptogroups';
+               $cont = addContinuationsEntry('jsonResourceMappingGroups', 
$cdata);
+               $h .= "<input type=hidden id=\"mapbymaptogroupcont\" 
value=\"$cont\">\n";
+               $h .= "</div>\n";
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn jsonResourceMappingGroups()
+       ///
+       /// \brief sends JSON of resource groups for resource mapping by 
selecting a
+       /// resource group of the type this type maps to
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function jsonResourceMappingGroups() {
+               $resmaptogrpid = processInputVar('id', ARG_NUMERIC);
+               $resources = getUserResources(array($this->maptype . "Admin"), 
array("manageMapping"), 1);
+               if(! array_key_exists($resmaptogrpid, 
$resources[$this->maptype])) {
+                       sendJSON(array('status' => 'noaccess'));
+                       return;
+               }
+               $groups = getUserResources(array($this->restype . 'Admin'), 
array('manageMapping'), 1);
+               $mapping = getResourceMapping($this->maptype, $this->restype);
+               $all = array();
+
+               foreach($groups[$this->restype] as $id => $group) {
+                       if(array_key_exists($resmaptogrpid, $mapping) &&
+                               in_array($id, $mapping[$resmaptogrpid]))
+                               $all[] = array('id' => $id, 'name' => $group, 
'inout' => 1);
+                       else
+                               $all[] = array('id' => $id, 'name' => $group, 
'inout' => 0);
+               }
+               $arr = array('items' => $all,
+                            'intitle' => getContinuationVar('intitle'),
+                            'outtitle' => getContinuationVar('outtitle'));
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJaddRemGroupMapTo()
+       ///
+       /// \brief adds or removes groups that map to a group of the type this
+       /// resource maps to
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJaddRemGroupMapTo() {
+               $mapgroupid = processInputVar('id', ARG_NUMERIC);
+               $mapgroups = getUserResources(array($this->maptype . "Admin"),
+                                             array("manageMapping"), 1);
+               if(! array_key_exists($mapgroupid, $mapgroups[$this->maptype])) 
{
+                       $arr = array('status' => 'noaccess');
+                       sendJSON($arr);
+                       return;
+               }
+
+               $groups = getUserResources(array($this->restype . "Admin"),
+                                          array("manageMapping"), 1);
+               $tmp = processInputVar('listids', ARG_STRING);
+               $tmp = explode(',', $tmp);
+               $groupids = array();
+               foreach($tmp as $id) {
+                       if(! is_numeric($id))
+                               continue;
+                       if(! array_key_exists($id, $groups[$this->restype])) {
+                               $arr = array('status' => 'noaccess');
+                               sendJSON($arr);
+                               return;
+                       }
+                       $groupids[] = $id;
+               }
+
+               $mytypeid = getResourceTypeID($this->restype);
+               $maptypeid = getResourceTypeID($this->maptype);
+
+               $mode = getContinuationVar('mode');
+
+               if($mode == 'add') {
+                       $adds = array();
+                       foreach($groupids as $id)
+                               $adds[] = "($id, $mytypeid, $mapgroupid, 
$maptypeid)";
+                       $query = "INSERT IGNORE INTO resourcemap "
+                                        .        "(resourcegroupid1, 
resourcetypeid1, "
+                                        .         "resourcegroupid2, 
resourcetypeid2) "
+                                        . "VALUES ";
+                       $query .= implode(',', $adds);
+                       doQuery($query);
+               }
+               else {
+                       foreach($groupids as $id) {
+                               $query = "DELETE FROM resourcemap "
+                                                . "WHERE resourcegroupid1 = 
$id AND "
+                                                .       "resourcetypeid1 = 
$mytypeid AND "
+                                                .       "resourcegroupid2 = 
$mapgroupid AND "
+                                                .       "resourcetypeid2 = 
$maptypeid";
+                               doQuery($query);
+                       }
+               }
+               $regids = "^" . implode('$|^', $groupids) . "$";
+               $arr = array('status' => 'success',
+                            'regids' => $regids,
+                            'inselobj' => 'inmaptogroups',
+                            'outselobj' => 'outmaptogroups');
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn mapByGridHTML()
+       ///
+       /// \brief
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function mapByGridHTML() {
+               # TODO
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJsaveResource()
+       ///
+       /// \brief saves changes to a resource; must be implemented by 
inheriting
+       /// class
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJsaveResource() {
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJeditResource()
+       ///
+       /// \brief sends data for editing a resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJeditResource() {
+               $rscid = processInputVar('rscid', ARG_NUMERIC);
+               $resources = getUserResources(array($this->restype . 'Admin'), 
array('administer'), 0, 1);
+               if(! array_key_exists($rscid, $resources[$this->restype])) {
+                       $ret = array('status' => 'noaccess');
+                       sendJSON($ret);
+                       return;
+               }
+               $args = $this->defaultGetDataArgs;
+               $args['rscid'] = $rscid;
+               $tmp = $this->getData($args);
+               $data = $tmp[$rscid];
+               $cdata = $this->basecdata;
+               $cdata['rscid'] = $rscid;
+               $cdata['olddata'] = $data;
+
+               # save continuation
+               $cont = addContinuationsEntry('AJsaveResource', $cdata);
+
+               $ret = $this->jsondata;
+               $ret['title'] = "Edit {$this->restypename}";
+               $ret['cont'] = $cont;
+               $ret['resid'] = $rscid;
+               $ret['data'] = $data;
+               $ret['status'] = 'success';
+               sendJSON($ret);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn addResource($data)
+       ///
+       /// \param $data - array of needed data for adding a new resource
+       ///
+       /// \return id of new resource
+       ///
+       /// \brief handles all parts of adding a new resource to the database; 
should
+       /// be implemented by inheriting class, but not required since it is 
only
+       /// called by functions in the inheriting class (nothing in this base 
class
+       /// calls it directly)
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function addResource($data) {
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn addEditDialogHTML($add)
+       ///
+       /// \param $add (optional, defaul=0) - 0 for edit, 1 for add
+       ///
+       /// \brief handles generating HTML for dialog used to edit resource; 
must be
+       /// implemented by inheriting class
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function addEditDialogHTML($add) {
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn extraSelectAdminOptions()
+       ///
+       /// \return html
+       ///
+       /// \brief generates any HTML for additional options that should be 
shown on
+       /// selectionText page
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function extraSelectAdminOptions() {
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn AJstartImage()
+///
+/// \brief starts the imaging process for a reservation
+///
+////////////////////////////////////////////////////////////////////////////////
+function AJstartImage() {
+       global $user;
+       $requestid = getContinuationVar("requestid");
+       $checkpoint = getContinuationVar("checkpoint", 0);
+
+       $data = getRequestInfo($requestid);
+       $disableUpdate = 1;
+       $imageid = '';
+       if(count($data['reservations']) == 1) {
+               $imageid = $data['reservations'][0]['imageid'];
+               $revid = $data['reservations'][0]['imagerevisionid'];
+       }
+       else {
+               foreach($data["reservations"] as $res) {
+                       if($res["forcheckout"]) {
+                               $imageid = $res["imageid"];
+                               $revid = $res['imagerevisionid'];
+                               break;
+                       }
+               }
+       }
+       if(! empty($imageid)) {
+               $imageData = getImages(0, $imageid);
+               if($imageData[$imageid]['ownerid'] == $user['id'])
+                       $disableUpdate = 0;
+               if($imageData[$imageid]['installtype'] == 'none' ||
+                  $imageData[$imageid]['installtype'] == 'kickstart')
+                       $disableUpdate = 1;
+       }
+       else {
+               $data['status'] = 'error';
+               $data['errmsg'] = _("There was an error in starting the imaging 
process. Please contact a system administrator.");
+               sendJSON($data);
+               return;
+       }
+       $obj = new Image();
+       $cdata = array('obj' => $obj,
+                      'requestid' => $requestid,
+                      'imageid' => $imageid,
+                      'baserevisionid' => 
$data['reservations'][0]['imagerevisionid'],
+                      'checkpoint' => $checkpoint,
+                      'add' => 1);
+       $cont = addContinuationsEntry('AJsaveResource', $cdata, SECINDAY, 0);
+       $arr = array('newcont' => $cont,
+                    'enableupdate' => 0,
+                    'connectmethods' => $imageData[$imageid]['connectmethods'],
+                    'owner' => "{$user['unityid']}@{$user['affiliation']}",
+                    'checkpoint' => $checkpoint);
+
+       $cdata = array('obj' => $obj,
+                      'imageid' => $imageid,
+                      'newimage' => 1,
+                      'curmethods' => $imageData[$imageid]['connectmethods']);
+       $cont = addContinuationsEntry('connectmethodDialogContent', $cdata);
+       $arr['connectmethodurl'] = BASEURL . SCRIPT . "?continuation=$cont";
+
+       if(! $disableUpdate) {
+               $revisions = getImageRevisions($imageid);
+               if(array_key_exists($revid, $revisions))
+                       $comments = $revisions[$revid]['comments'];
+               else {
+                       $keys = array_keys($revisions);
+                       if(count($keys)) {
+                               $key = array_pop($keys);
+                               $comments = $revisions[$key]['comments'];
+                       }
+                       else
+                               $comments = '';
+               }
+               if(preg_match('/\w/', $comments)) {
+                       $cmt  = "These are the comments from the previous 
revision ";
+                       $cmt .= "({$revisions[$revid]['revision']}):<br>";
+                       $cmt .= "{$revisions[$revid]['comments']}<br><br>";
+               }
+               else
+                       $cmt = "The previous revision did not have any 
comments.<br><br>";
+               $arr['comments'] = $cmt;
+               $cdata = array('obj' => $obj,
+                              'requestid' => $requestid,
+                              'imageid' => $imageid,
+                              'checkpoint' => $checkpoint,
+                              'revisionid' => $revid);
+               $cont = addContinuationsEntry('AJupdateImage', $cdata, 
SECINDAY, 0);
+               $arr['updatecont'] = $cont;
+               $arr['enableupdate'] = 1;
+       }
+       $arr['status'] = 'success';
+       sendJSON($arr);
+}
+
+?>

Added: vcl/trunk/web/.ht-inc/schedule.php
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/schedule.php?rev=1624325&view=auto
==============================================================================
--- vcl/trunk/web/.ht-inc/schedule.php (added)
+++ vcl/trunk/web/.ht-inc/schedule.php Thu Sep 11 16:01:48 2014
@@ -0,0 +1,464 @@
+<?php
+/*
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \class Schedule
+///
+/// \brief extends Resource class to add things specific to resources of the
+/// schedule type
+///
+////////////////////////////////////////////////////////////////////////////////
+class Schedule extends Resource {
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn __construct()
+       ///
+       /// \brief calls parent constructor; initializes things for Schedule 
class
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function __construct() {
+               parent::__construct();
+               $this->restype = 'schedule';
+               $this->restypename = 'Schedule';
+               $this->namefield = 'name';
+               $this->basecdata['obj'] = $this;
+               $this->deletable = 1;
+               $this->deletetoggled = 0;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn getData($args)
+       ///
+       /// \param $args - unused in this class
+       ///
+       /// \return array of data as returned from getSchedules
+       ///
+       /// \brief wrapper for calling getSchedules
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function getData($args) {
+               return getSchedules();
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn addEditDialogHTML()
+       ///
+       /// \param $add - unused for this class
+       ///
+       /// \brief generates HTML for dialog used to edit resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function addEditDialogHTML($add=0) {
+               global $user, $days;
+               # dialog for on page editing
+               $h = '';
+               $h .= "<div dojoType=dijit.Dialog\n";
+               $h .= "      id=\"addeditdlg\"\n";
+               $h .= "      title=\"Edit {$this->restypename}\"\n";
+               $h .= "      duration=250\n";
+               $h .= "      style=\"width: 70%;\"\n";
+               $h .= "      draggable=true>\n";
+               $h .= "<div id=\"addeditdlgcontent\">\n";
+               # id
+               $h .= "<input type=\"hidden\" id=\"editresid\">\n";
+
+               $h .= "<div style=\"text-align: center;\">\n";
+               # name
+               $errmsg = "Name cannot contain single (') or double (&quot;) 
quotes, "
+                       . "less than (&lt;), or greater than (&gt;) and can be 
from 2 to 30 "
+                       . "characters long";
+               $h .= labeledFormItem('name', 'Name', 'text', 
'^([A-Za-z0-9-!@#$%^&\*\(\)_=\+\[\]{}\\\|:;,\./\?~` ]){2,30}$',
+                                     1, '', $errmsg, '', '', '200px'); 
+               # owner
+               $extra = array('onKeyPress' => 'setOwnerChecking');
+               $h .= labeledFormItem('owner', 'Owner', 'text', '', 1,
+                                     
"{$user['unityid']}@{$user['affiliation']}", 'Unknown user',
+                                     'checkOwner', $extra, '200px');
+               #$h .= labeledFormItem('owner', 'Owner', 'text', 
'{$user['unityid']}@{$user['affiliation']}',
+               #                      1, '', 'Unknown user', 'checkOwner', 
'onKeyPress', 'setOwnerChecking');
+               $cont = addContinuationsEntry('AJvalidateUserid');
+               $h .= "<input type=\"hidden\" id=\"valuseridcont\" 
value=\"$cont\">\n";
+
+               # table of times
+               $h .= "<br>";
+               $h .= "<span style=\"text-align: center;\"><h3>Schedule 
Times</h3></span>\n";
+               $h .= "The start and end day/times are based on a week's time 
period with ";
+               $h .= "the start/end point being 'Sunday 12:00&nbsp;am'. i.e. 
The earliest ";
+               $h .= "start day/time is 'Sunday 12:00&nbsp;am' and the latest 
end day/";
+               $h .= "time is 'Sunday 12:00&nbsp;am'<br><br>\n";
+               $h .= "Start:";
+               $h .= selectInputAutoDijitHTML('startday', $days, 'startday');
+               $h .= "<input type=\"text\" id=\"starttime\" 
dojoType=\"dijit.form.TimeTextBox\" ";
+               $h .= "required=\"true\" value=\"T00:00:00\"/>\n";
+               $h .= "End:";
+               $h .= selectInputAutoDijitHTML('endday', $days, 'endday');
+               $h .= "<input type=\"text\" id=\"endtime\" 
dojoType=\"dijit.form.TimeTextBox\" ";
+               $h .= "required=\"true\" value=\"T00:00:00\" />\n";
+               $h .= dijitButton('addTimeBtn', "Add", "addTime();");
+               $h .= "</div>\n"; # text-align: center
+               $h .= "<div dojoType=\"dojo.data.ItemFileWriteStore\" 
jsId=\"scheduleStore\" ";
+               $h .= "data=\"scheduleTimeData\"></div>\n";
+               $h .= "<table dojoType=\"dojox.grid.DataGrid\" 
jsId=\"scheduleGrid\" sortInfo=1 ";
+               $h .= "store=\"scheduleStore\" style=\"width: 520px; height: 
165px;\">\n";
+               $h .= "<thead>\n";
+               $h .= "<tr>\n";
+               $h .= "<th field=\"startday\" width=\"94px\" 
formatter=\"formatDay\">Start Day</th>\n";
+               $h .= "<th field=\"startday\" width=\"94px\" 
formatter=\"formatTime\">Start Time</th>\n";
+               $h .= "<th field=\"endday\" width=\"94px\" 
formatter=\"formatDay\">End Day</th>\n";
+               $h .= "<th field=\"endday\" width=\"94px\" 
formatter=\"formatTime\">End Time</th>\n";
+               $h .= "<th field=\"remove\" width=\"80px\">Remove</th>\n";
+               $h .= "</tr>\n";
+               $h .= "</thead>\n";
+               $h .= "</table>\n";
+               $h .= "</div>\n"; # addeditdlgcontent
+
+               $h .= "<div id=\"addeditdlgerrmsg\" 
class=\"nperrormsg\"></div>\n";
+               $h .= "<div id=\"editdlgbtns\" align=\"center\">\n";
+               $h .= dijitButton('addeditbtn', "Confirm", "saveResource();");
+               $h .= dijitButton('', "Cancel", "addEditDlgHide();");
+               $h .= "</div>\n"; # editdlgbtns
+               $h .= "</div>\n"; # addeditdlg
+
+               $h .= "<div dojoType=dijit.Dialog\n";
+               $h .= "      id=\"groupingnote\"\n";
+               $h .= "      title=\"Schedule Grouping\"\n";
+               $h .= "      duration=250\n";
+               $h .= "      draggable=true>\n";
+               $h .= "Each schedule should be a member of a 
schedule<br>resource group. The following dialog will allow you<br>to add the 
new schedule to a group.<br><br>\n";
+               $h .= "<div align=\"center\">\n";
+               $h .= dijitButton('', "Close", 
"dijit.byId('groupingnote').hide();");
+               $h .= "</div>\n"; # btn div
+               $h .= "</div>\n"; # groupingnote
+
+               $h .= "<div dojoType=dijit.Dialog\n";
+               $h .= "      id=\"groupdlg\"\n";
+               $h .= "      title=\"Schedule Grouping\"\n";
+               $h .= "      duration=250\n";
+               $h .= "      draggable=true>\n";
+               $h .= "<div id=\"groupdlgcontent\"></div>\n";
+               $h .= "<div align=\"center\">\n";
+               $script  = "    dijit.byId('groupdlg').hide();\n";
+               $script .= "    checkFirstAdd();\n";
+               $h .= dijitButton('', "Close", $script);
+               $h .= "</div>\n"; # btn div
+               $h .= "</div>\n"; # groupdlg
+
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJsaveResource()
+       ///
+       /// \brief saves changes to resource
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function AJsaveResource() {
+               $add = getContinuationVar('add', 0);
+               $data = $this->validateResourceData();
+               if($data['error']) {
+                       $ret = array('status' => 'error', 'msg' => 
$data['errormsg']);
+                       sendJSON($ret);
+                       return;
+               }
+
+               if($add) {
+                       if(! $data['rscid'] = $this->addResource($data)) {
+                               sendJSON(array('status' => 'adderror',
+                                              'errormsg' => 'Error encountered 
while trying to create new schedule.<br>Please contact an admin for 
assistance.'));
+                               return;
+                       }
+               }
+               else {
+                       $ownerid = getUserlistID($data['owner']);
+                       $query = "UPDATE schedule "
+                              . "SET name = '{$data['name']}', "
+                              .     "ownerid = $ownerid "
+                              . "WHERE id = {$data['rscid']}";
+                       doQuery($query);
+               }
+
+               if(! $add) {
+                       $query = "DELETE FROM scheduletimes WHERE scheduleid = 
{$data['rscid']}";
+                       doQuery($query, 101);
+               }
+               $qvals = array();
+               foreach($data['times'] as $time)
+                       $qvals[] = "({$data['rscid']}, {$time['start']}, 
{$time['end']})";
+               $allvals = implode(',', $qvals);
+               $query = "INSERT INTO scheduletimes "
+                      .        "(scheduleid, start, end) "
+                                . "VALUES $allvals";
+               doQuery($query, 101);
+
+               # clear user resource cache for this type
+               $key = getKey(array(array($this->restype . "Admin"), 
array("administer"), 0, 1, 0));
+               unset($_SESSION['userresources'][$key]);
+               $key = getKey(array(array($this->restype . "Admin"), 
array("administer"), 0, 0, 0));
+               unset($_SESSION['userresources'][$key]);
+               $key = getKey(array(array($this->restype . "Admin"), 
array("manageGroup"), 0, 1, 0));
+               unset($_SESSION['userresources'][$key]);
+               $key = getKey(array(array($this->restype . "Admin"), 
array("manageGroup"), 0, 0, 0));
+               unset($_SESSION['userresources'][$key]);
+
+               $tmp = $this->getData(array('includedeleted' => 0, 'rscid' => 
$data['rscid']));
+               $data = $tmp[$data['rscid']];
+               $arr = array('status' => 'success');
+               if($add) {
+                       $arr['action'] = 'add';
+                       $arr['nogroups'] = 0;
+                       $groups = getUserResources(array($this->restype . 
'Admin'), array('manageGroup'), 1);
+                       if(count($groups[$this->restype]))
+                               $arr['groupingHTML'] = 
$this->groupByResourceHTML();
+                       else
+                               $arr['nogroups'] = 1;
+               }
+               else
+                       $arr['action'] = 'edit';
+               $arr['data'] = $data;
+               sendJSON($arr);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn addResource($data)
+       ///
+       /// \param $data - array of needed data for adding a new resource
+       ///
+       /// \return id of new resource
+       ///
+       /// \brief handles adding a new schedule and other associated data to 
the
+       /// database
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function addResource($data) {
+               global $user;
+
+               $ownerid = getUserlistID($data['owner']);
+               $query = "INSERT INTO schedule "
+                      .         "(name, "
+                      .         "ownerid) "
+                      . "VALUES ('{$data['name']}', "
+                      .         "$ownerid)";
+               doQuery($query);
+
+               $rscid = dbLastInsertID();
+               if($rscid == 0) {
+                       return 0;
+               }
+
+               $query = "INSERT INTO resource "
+                                .        "(resourcetypeid, "
+                                .        "subid) "
+                                . "VALUES (15, "
+                                .         "$rscid)";
+               doQuery($query, 223);
+       
+               return $rscid;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn validateResourceData()
+       ///
+       /// \return array with these fields:\n
+       /// \b rscid - id of resource (from schedule table)\n
+       /// \b name\n
+       /// \b owner\n
+       /// \b times - array of arrays, each having 2 keys: start and end, each 
in
+       ///    unix timestamp format\n
+       /// \b error - 0 if submitted data validates; 1 if anything is invalid\n
+       /// \b errormsg - if error = 1; string of error messages separated by 
html
+       ///    break tags
+       ///
+       /// \brief validates form input from editing or adding a schedule
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function validateResourceData() {
+               global $user;
+
+               $return = array('error' => 0);
+               $errormsg = array();
+
+               $return['rscid'] = getContinuationVar('rscid', 0);
+               $return["name"] = processInputVar("name", ARG_STRING);
+               $return["owner"] = processInputVar("owner", ARG_STRING, 
"{$user["unityid"]}@{$user['affiliation']}");
+               $times = processInputVar('times', ARG_STRING);
+
+               if(! 
preg_match("/^([A-Za-z0-9-!@#$%^&\*\(\)_=\+\[\]{}\\\|:;,\.\/\?~` ]){2,30}$/", 
$return['name'])) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Name cannot contain single (') or double 
(&quot;) quotes, "
+                                   . "less than (&lt;), or greater than (&gt;) 
and can be from 2 to 30 "
+                                   . "characters long";
+               }
+               elseif($this->checkForScheduleName($return['name'], 
$return['rscid'])) {
+                       $return['error'] = 1;
+                       $errormsg[] = "A schedule already exists with this 
name.";
+               }
+               if(! validateUserid($return['owner'])) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Submitted owner is not valid";
+               }
+               if(! preg_match('/^([0-9]+:[0-9]+,)*([0-9]+:[0-9]+){1}$/', 
$times)) {
+                       $return['error'] = 1;
+                       $errormsg[] = "Invalid time data submitted";
+               }
+
+               if(! $return['error']) {
+                       $times = explode(',', $times);
+                       $return['times'] = array();
+                       foreach($times as $pair) {
+                               list($start, $end) = explode(':', $pair);
+                               foreach($return['times'] as $check) {
+                                       if($start < $check['end'] && $end > 
$check['start']) {
+                                               $return['error'] = 1;
+                                               $errormsg[] = "Two sets of 
times are overlapping - please correct and save again";
+                                               break(2);
+                                       }
+                               }
+                               $return['times'][] = array('start' => $start, 
'end' => $end);
+                       }
+               }
+
+               if($return['error'])
+                       $return['errormsg'] = implode('<br>', $errormsg);
+
+               return $return;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn toggleDeleteResourceExtra()
+       ///
+       /// \return html
+       ///
+       /// \brief generates additional HTML to be included at the end of the 
confirm
+       /// toggle delete resource page
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function toggleDeleteResourceExtra() {
+               $rscid = processInputVar('rscid', ARG_NUMERIC);
+               $data = $this->getData('');
+               $h = '';
+               if(count($data[$rscid]["times"])) {
+                       $h .= "<br><TABLE>\n";
+                       $h .= "  <TR>\n";
+                       $h .= "    <TH>Start</TH>\n";
+                       $h .= "    <TD>&nbsp;</TD>\n";
+                       $h .= "    <TH>End</TH>\n";
+                       $h .= "  <TR>\n";
+                       foreach($data[$rscid]["times"] as $time) {
+                               $h .= "  <TR>\n";
+                               $h .= "    <TD>" . 
$this->minToDaytime($time["start"]) . "</TD>\n";
+                               $h .= "    <TD>&nbsp;</TD>\n";
+                               $h .= "    <TD>" . 
$this->minToDaytime($time["end"]) . "</TD>\n";
+                               $h .= "  </TR>\n";
+                       }
+                       $h .= "</TABLE><br>\n";
+               }
+               return $h;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn submitToggleDeleteResourceExtra($rscid, $deleted)
+       ///
+       /// \param $rscid - id of a resource (from schedule table)
+       /// \param $deleted - (optional, default=0) 1 if resource was previously
+       /// deleted; 0 if not
+       ///
+       /// \brief handles deleting associated entries from scheduletimes table
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function submitToggleDeleteResourceExtra($rscid, $deleted=0) {
+               $query = "DELETE FROM scheduletimes "
+                      . "WHERE scheduleid = $rscid";
+               doQuery($query);
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn checkForScheduleName($name, $id)
+       ///
+       /// \param $name - the name of a schedule
+       /// \param $id - id of a schedule to ignore
+       ///
+       /// \return 1 if $name is already in the schedule table, 0 if not
+       ///
+       /// \brief checks for $name being in the schedule table except for $id
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function checkForScheduleName($name, $id) {
+               $query = "SELECT id FROM schedule "
+                                . "WHERE name = '$name'";
+               
+               if(! empty($id))
+                       $query .= " AND id != $id";
+               $qh = doQuery($query, 101);
+               if(mysql_num_rows($qh))
+                       return 1;
+               return 0;
+       }
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn minToDaytime($min)
+       ///
+       /// \param $min - minute of the week
+       ///
+       /// \return day of week and time of day
+       ///
+       /// \brief calculates day of week and time of day from $min and returns 
a
+       /// nicely formatted string of "Weekday&nbsp;HH:MM am/pm"
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function minToDaytime($min) {
+               $days = array("Sunday", "Monday", "Tuesday", "Wednesday", 
"Thursday",
+                                                 "Friday", "Saturday");
+               $time = minuteToTime($min % 1440);
+               if((int)($min / 1440) == 0) {
+                       $day = 0;
+               }
+               elseif((int)($min / 1440) == 1) {
+                       $day = 1;
+               }
+               elseif((int)($min / 1440) == 2) {
+                       $day = 2;
+               }
+               elseif((int)($min / 1440) == 3) {
+                       $day = 3;
+               }
+               elseif((int)($min / 1440) == 4) {
+                       $day = 4;
+               }
+               elseif((int)($min / 1440) == 5) {
+                       $day = 5;
+               }
+               elseif((int)($min / 1440) == 6) {
+                       $day = 6;
+               }
+               elseif((int)($min / 1440) > 6) {
+                       $day = 0;
+               }
+               return $days[$day] . "&nbsp;$time";
+       }
+}
+?>


Reply via email to