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 & 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;\"> </th>\n"; + $h .= "<th field=\"id\" width=\"{$w[1]}\" formatter=\"resource.EditBtn\" styles=\"text-align: center;\"> </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;\"><-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-></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;\"><-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-></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;\"><-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-></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;\"><-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-></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 (") quotes, " + . "less than (<), or greater than (>) 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 am'. i.e. The earliest "; + $h .= "start day/time is 'Sunday 12:00 am' and the latest end day/"; + $h .= "time is 'Sunday 12:00 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 (") quotes, " + . "less than (<), or greater than (>) 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> </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> </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 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] . " $time"; + } +} +?>
