From 559de3d38f3556ae45e7853c3813a6383ba7e906 Mon Sep 17 00:00:00 2001 From: Romain Quetiez Date: Thu, 15 Sep 2011 10:06:46 +0000 Subject: [PATCH] Portal reworked (code factorization, allowing for paginated lists) + added the list of closed tickets (+search) SVN:trunk[1577] --- portal/index.php | 1111 ++++++++++++++++++--------------------------- portal/portal.css | 259 +++++++---- 2 files changed, 600 insertions(+), 770 deletions(-) diff --git a/portal/index.php b/portal/index.php index 7462dfaaa1..fa3326c719 100644 --- a/portal/index.php +++ b/portal/index.php @@ -27,54 +27,16 @@ require_once(APPROOT.'/application/application.inc.php'); require_once(APPROOT.'/application/nicewebpage.class.inc.php'); require_once(APPROOT.'/application/wizardhelper.class.inc.php'); -/** - * Get the list of parameters (i.e. attribute codes) to be handled while creating a new UserRequest object - * @return Array The list of attribute codes - */ -function GetParamsList() -{ - return array('org_id', 'caller_id', 'service_id', 'servicesubcategory_id', 'request_type', 'title', 'description', 'impact', 'urgency', 'workgroup_id'); -} -/** - * Outputs a list of parameters as hidden field into the current page - * (must be called when inside a form) - * @param WebPage $oP The current web page - * @param Array $aInteractive The list of parameters that are handled intractively and thus should not be output as hidden fields - * @param Hash $aParameters Array name => value for the parameters - * @return void - */ -function DumpHiddenParams($oP, $aInteractive, $aParameters) -{ - foreach($aParameters as $sAttCode => $value) - { - if (!in_array($sAttCode, $aInteractive)) - { - $oP->Add(""); - } - } -} -/** - * Read all the parameters of the page for building a UserRequest - * Parameters that were absent from the page's parameters are not set in the resulting hash array - * @input string $sMethod Either get or post - * @return Hash Array of name => value corresponding to the parameters that were passed to the page - */ -function ReadAllParams() -{ - $aParams = GetParamsList(); - $aValues = array(); - foreach($aParams as $sName) - { - $value = utils::ReadParam('attr_'.$sName, null, false, 'raw_data'); - if (!is_null($value)) - { - $aValues[$sName] = $value; - } - } - return $aValues; -} +define('SERVICECATEGORY_QUERY', 'SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id = :org_id'); +define('SERVICE_SUBCATEGORY_QUERY', 'SELECT ServiceSubcategory WHERE service_id = :svc_id'); + +define('VALIDATE_SERVICECATEGORY_QUERY', 'SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id = :org_id AND s.id = :id'); +define('VALIDATE_SERVICESUBCATEGORY_QUERY', 'SELECT ServiceSubcategory AS Sub JOIN Service AS Svc ON Sub.service_id = Svc.id WHERE Svc.org_id=:org_id AND Sub.id=:id'); + +define('ALL_PARAMS', 'from_service_id,org_id,caller_id,service_id,servicesubcategory_id,title,description,impact,urgency,workgroup_id,moreinfo,caller_id,start_date,end_date,duration,impact_duration'); + /** * Displays the portal main menu @@ -83,14 +45,24 @@ function ReadAllParams() */ function DisplayMainMenu(WebPage $oP) { - $oP->AddMenuButton('refresh', 'Portal:Refresh', './index.php?operation=welcome'); - $oP->AddMenuButton('create', 'Portal:CreateNewRequest', './index.php?operation=create_request'); + $oP->AddMenuButton('showongoing', 'Portal:ShowOngoing', './index.php?operation=show_ongoing'); + $oP->AddMenuButton('newrequest', 'Portal:CreateNewRequest', './index.php?operation=create_request'); + $oP->AddMenuButton('showclosed', 'Portal:ShowClosed', './index.php?operation=show_closed'); $oP->AddMenuButton('change_pwd', 'Portal:ChangeMyPassword', './index.php?loginop=change_pwd'); +} - $oP->add("
\n"); - $oP->add("

".Dict::S('Portal:OpenRequests')."

\n"); +/** + * Displays the current tickets + * @param WebPage $oP The current web page + * @return void + */ +function ShowOngoingTickets(WebPage $oP) +{ + $oP->add("
\n"); + $oP->add("

".Dict::S('Portal:OpenRequests')."

\n"); ListOpenRequests($oP); $oP->add("
\n"); + $oP->add("
\n"); $oP->add("

".Dict::S('Portal:ResolvedRequests')."

\n"); ListResolvedRequests($oP); @@ -98,22 +70,35 @@ function DisplayMainMenu(WebPage $oP) } /** - * Displays the form to select a Service Id (among the valid ones for the specified user Organization) + * Displays the closed tickets + * @param WebPage $oP The current web page + * @return void + */ +function ShowClosedTickets(WebPage $oP) +{ + $oP->add("
\n"); + //$oP->add("

".Dict::S('Portal:ListClosedTickets')."

\n"); + ListClosedTickets($oP); + $oP->add("
\n"); +} + +/** + * Displays the form to select a Service Category Id (among the valid ones for the specified user Organization) * @param WebPage $oP Web page for the form output * @param Organization $oUserOrg The organization of the current user * @return void */ -function SelectService($oP, $oUserOrg) +function SelectServiceCategory($oP, $oUserOrg) { - // Init forms parameters - $aParameters = ReadAllParams(); + $aParameters = $oP->ReadAllParams(ALL_PARAMS); - $oSearch = DBObjectSearch::FromOQL('SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id = :org_id'); - $oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey())); $oP->add("
\n"); - $oP->add("

".Dict::S('Portal:SelectService')."

\n"); - $oP->add("
\n"); + $oP->WizardFormStart('request_wizard', 1); + + $oP->add("

".Dict::S('Portal:SelectService')."

\n"); $oP->add("\n"); + $oSearch = DBObjectSearch::FromOQL(SERVICECATEGORY_QUERY); + $oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey())); while($oService = $oSet->Fetch()) { $id = $oService->GetKey(); @@ -122,24 +107,17 @@ function SelectService($oP, $oUserOrg) { $sChecked = "checked"; } - $oP->p(""); + $oP->p(""); } $oP->add("

"); - $oP->p("

".htmlentities($oService->Get('description'), ENT_QUOTES, 'UTF-8')."

"); + $oP->p("

".$oService->GetAsHTML('description')."

\n"); - DumpHiddenParams($oP, array('service_id'), $aParameters); - $oP->add(""); + + $oP->DumpHiddenParams($aParameters, array('service_id')); $oP->add(""); - $oP->p(""); - $oP->add("
"); - $oP->add("
\n"); - $sMessage = Dict::S('Portal:PleaseSelectOneService'); - $oP->add_ready_script( -<<WizardFormButtons(BUTTON_BACK | BUTTON_NEXT | BUTTON_CANCEL); + $oP->WizardFormEnd(); + $oP->WizardCheckSelectionOnSubmit(Dict::S('Portal:PleaseSelectOneService')); + $oP->add("
\n"); } /** @@ -150,21 +128,23 @@ EOF * @return void */ -function SelectSubService($oP, $oUserOrg) +function SelectServiceSubCategory($oP, $oUserOrg) { - // Init forms parameters - $aParameters = ReadAllParams(); + $aParameters = $oP->ReadAllParams(ALL_PARAMS); + $iSvcId = $aParameters['service_id']; $iDefaultSubSvcId = isset($aParameters['servicesubcategory_id']) ? $aParameters['servicesubcategory_id'] : 0; - $oSearch = DBObjectSearch::FromOQL('SELECT ServiceSubcategory AS ss WHERE ss.service_id = :svc_id'); - $oSet = new CMDBObjectSet($oSearch, array(), array('svc_id' => $iSvcId)); - $oService = MetaModel::GetObject('Service', $iSvcId, false); - if (is_object($oService)) + $iDefaultWizNext = 2; + + $oSearch = DBObjectSearch::FromOQL(SERVICE_SUBCATEGORY_QUERY); + $oSet = new CMDBObjectSet($oSearch, array(), array('svc_id' => $iSvcId, 'org_id' => $oUserOrg->GetKey())); + $oServiceCategory = MetaModel::GetObject('Service', $iSvcId, false); + if (is_object($oServiceCategory)) { $oP->add("
\n"); - $oP->add("

".Dict::Format('Portal:SelectSubcategoryFrom_Service', htmlentities($oService->GetName(), ENT_QUOTES, 'UTF-8'))."

\n"); - $oP->add("
\n"); + $oP->add("

".Dict::Format('Portal:SelectSubcategoryFrom_Service', htmlentities($oServiceCategory->GetName(), ENT_QUOTES, 'UTF-8'))."

\n"); + $oP->WizardFormStart('request_wizard', $iDefaultWizNext); $oP->add("\n"); while($oSubService = $oSet->Fetch()) { @@ -174,23 +154,25 @@ function SelectSubService($oP, $oUserOrg) { $sChecked = "checked"; } - $oP->p(""); + + $oP->add(""); + + $oP->add(""); + + $oP->add(""); + $oP->add(""); } - $sMessage = Dict::S('Portal:PleaseSelectAServiceSubCategory'); - $oP->add_ready_script( -<<add("

"); - $oP->p("

".htmlentities($oSubService->Get('description'), ENT_QUOTES, 'UTF-8')."

"); + $oP->add("

"); + $oP->add("
"); + $oP->add("

"); + $oP->add("

".$oSubService->GetAsHTML('description')."

"); + $oP->add("
\n"); - DumpHiddenParams($oP, array('servicesubcategory_id'), $aParameters); - $oP->add(""); + $oP->DumpHiddenParams($aParameters, array('servicesubcategory_id')); $oP->add(""); - $oP->p(" "); - $oP->add("
"); + $oP->WizardFormButtons(BUTTON_BACK | BUTTON_NEXT | BUTTON_CANCEL); + $oP->WizardFormEnd(); + $oP->WizardCheckSelectionOnSubmit(Dict::S('Portal:PleaseSelectAServiceSubCategory')); $oP->add("
\n"); } else @@ -198,6 +180,7 @@ EOF $oP->p("Error: Invalid Service: id = $iSvcId"); } } + /** * Displays the form for the final step of the UserRequest creation * @param WebPage $oP The current web page for the form output @@ -206,12 +189,29 @@ EOF */ function RequestCreationForm($oP, $oUserOrg) { - $aList = array('request_type', 'title', 'description', 'impact', 'urgency', 'workgroup_id'); - $aParameters = ReadAllParams(); + $oP->add_ready_script( +<<ReadAllParams(ALL_PARAMS); - $oService = MetaModel::GetObject('Service', $aParameters['service_id'], false); - $oSubService = MetaModel::GetObject('ServiceSubcategory', $aParameters['servicesubcategory_id'], false); - if (is_object($oService) && is_object($oSubService)) + $aList = array('title', 'description', 'impact', 'urgency', 'workgroup_id'); + + $sDescription = ''; + if (isset($aParameters['template_id'])) + { + $oTemplate = MetaModel::GetObject('Template', $aParameters['template_id'], false); + if (is_object($oTemplate)) + { + $sDescription = htmlentities($oTemplate->Get('template'), ENT_QUOTES, 'UTF-8'); + } + } + + $oServiceCategory = MetaModel::GetObject('Service', $aParameters['service_id'], false); + $oServiceSubCategory = MetaModel::GetObject('ServiceSubcategory', $aParameters['servicesubcategory_id'], false); + if (is_object($oServiceCategory) && is_object($oServiceSubCategory)) { $oRequest = new UserRequest(); $oRequest->Set('org_id', $oUserOrg->GetKey()); @@ -220,9 +220,10 @@ function RequestCreationForm($oP, $oUserOrg) $oRequest->Set('servicesubcategory_id', $aParameters['servicesubcategory_id']); $oAttDef = MetaModel::GetAttributeDef('UserRequest', 'service_id'); - $aDetails[] = array('label' => ''.$oAttDef->GetLabel().'', 'value' => htmlentities($oService->GetName(), ENT_QUOTES, 'UTF-8')); + $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => htmlentities($oServiceCategory->GetName(), ENT_QUOTES, 'UTF-8')); $oAttDef = MetaModel::GetAttributeDef('UserRequest', 'servicesubcategory_id'); - $aDetails[] = array('label' => ''.$oAttDef->GetLabel().'', 'value' => htmlentities($oSubService->GetName(), ENT_QUOTES, 'UTF-8')); + $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => htmlentities($oServiceSubCategory->GetName(), ENT_QUOTES, 'UTF-8')); + $iFlags = 0; foreach($aList as $sAttCode) { @@ -247,14 +248,10 @@ function RequestCreationForm($oP, $oUserOrg) $aFieldsMap[$sAttCode] = 'attr_'.$sAttCode; $sValue = $oRequest->GetFormElementForField($oP, get_class($oRequest), $sAttCode, $oAttDef, $value, '', 'attr_'.$sAttCode, '', $iFlags, $aArgs); - $aDetails[] = array('label' => ''.$oAttDef->GetLabel().'', 'value' => $sValue); - } - if (!class_exists('AttachmentPlugIn')) - { - // the Attachement plug-ins is not installed, do it the old way - $aDetails[] = array('label' => ''.Dict::S('Portal:Attachments').'', 'value' => ' '); - $aDetails[] = array('label' => ' ', 'value' => '

'); + $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sValue); } + $aDetails[] = array('label' => Dict::S('Class:Ticket/Attribute:ticket_log'), 'value' => ''); + $oP->add_linked_script("../js/json.js"); $oP->add_linked_script("../js/forms-json-utils.js"); $oP->add_linked_script("../js/wizardhelper.js"); @@ -264,35 +261,23 @@ function RequestCreationForm($oP, $oUserOrg) $oP->add_linked_script("../js/jquery.blockUI.js"); $oP->add("
\n"); $oP->add("

".Dict::S('Portal:DescriptionOfTheRequest')."

\n"); - $oP->add("
\n"); - $oP->add("
\n"); + $oP->WizardFormStart('request_form', 3); + //$oP->add("\n"); $oP->details($aDetails); - $sTransactionId = utils::GetNewTransactionId(); - $oP->SetTransactionId($sTransactionId); // Must be set before calling the plug-in - if (class_exists('AttachmentPlugIn')) - { - $oAttPlugin = new AttachmentPlugIn(); - // depending on the plug-in's configuration, the attachments are displayed either in the 'properties' or in the 'relations' - // in the portal, both are handled the same way... it does not matter - $oAttPlugin->OnDisplayProperties($oRequest, $oP, true /* edit */); - $oAttPlugin->OnDisplayRelations($oRequest, $oP, true /* edit */); - } + $oAttPlugin = new AttachmentPlugIn(); + $oAttPlugin->OnDisplayRelations($oRequest, $oP, true /* edit */); - $oP->add("
\n"); - DumpHiddenParams($oP, $aList, $aParameters); - $oP->add(""); + $oP->DumpHiddenParams($aParameters, $aList); $oP->add(""); - $oP->add("\n"); - $oP->p(" "); - $oP->add(""); + $oP->WizardFormButtons(BUTTON_BACK | BUTTON_FINISH | BUTTON_CANCEL); + $oP->WizardFormEnd(); $oP->add("\n"); $iFieldsCount = count($aFieldsMap); $sJsonFieldsMap = json_encode($aFieldsMap); + $oP->add_ready_script( << new - var oWizardHelper = new WizardHelper('UserRequest', ''); oWizardHelper.SetFieldsMap($sJsonFieldsMap); oWizardHelper.SetFieldsCount($iFieldsCount); @@ -301,29 +286,13 @@ function RequestCreationForm($oP, $oUserOrg) $('#request_form').submit( function() { return OnSubmit('request_form'); }); - $(window).unload(function() { OnUnload('$sTransactionId') } ); -EOF -); - $sBtnLabel = Dict::S('Portal:RemoveAttachment'); - $oP->add_script( -<< 

'); - index++; - } - function RemoveAttachment(id_attachment) - { - $('#attachment_'+id_attachment).remove(); - } EOF ); } else { // User not authorized to use this service ? - DisplayMainMenu($oP); + //ShowOngoingTickets($oP); } } @@ -335,43 +304,51 @@ EOF */ function DoCreateRequest($oP, $oUserOrg) { - $aParameters = ReadAllParams(); + $aParameters = $oP->ReadAllParams(ALL_PARAMS); $sTransactionId = utils::ReadPostedParam('transaction_id', ''); if (!utils::IsTransactionValid($sTransactionId)) { $oP->add("

".Dict::S('UI:Error:ObjectAlreadyCreated')."

\n"); - DisplayMainMenu($oP); + //ShowOngoingTickets($oP); return; } // Validate the parameters - // 1) Service - $oSearch = DBObjectSearch::FromOQL('SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id = :org_id AND s.id = :svc_id'); - $oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey(), 'svc_id' => $aParameters['service_id'])); + // 1) ServiceCategory + $oSearch = DBObjectSearch::FromOQL(VALIDATE_SERVICECATEGORY_QUERY); + $oSet = new CMDBObjectSet($oSearch, array(), array('id' => $aParameters['service_id'], 'org_id' => $oUserOrg->GetKey())); if ($oSet->Count() != 1) { // Invalid service for the current user ! - throw new Exception("Invalid Service: id={$aParameters['servicesubcategory_id']} for the current user (org_id=".$oUserOrg->GetKey().")."); + throw new Exception("Invalid Service Category: id={$aParameters['service_id']} - count: ".$oSet->Count()); } - $oService = $oSet->Fetch(); + $oServiceCategory = $oSet->Fetch(); + // 2) Service Subcategory - $oSearch = DBObjectSearch::FromOQL('SELECT ServiceSubcategory AS sc WHERE sc.id = :subcategory_id AND sc.service_id = :svc_id'); - $oSet = new CMDBObjectSet($oSearch, array(), array('svc_id' => $aParameters['service_id'], 'subcategory_id' =>$aParameters['servicesubcategory_id'] )); + $oSearch = DBObjectSearch::FromOQL(VALIDATE_SERVICESUBCATEGORY_QUERY); + $oSet = new CMDBObjectSet($oSearch, array(), array('service_id' => $aParameters['service_id'], 'id' =>$aParameters['servicesubcategory_id'],'org_id' => $oUserOrg->GetKey() )); if ($oSet->Count() != 1) { // Invalid subcategory - throw new Exception("Invalid ServiceSubcategory: id={$aParameters['servicesubcategory_id']} for service ".$oService->GetName()."({$aParameters['service_id']})"); + throw new Exception("Invalid ServiceSubcategory: id={$aParameters['servicesubcategory_id']} for service category ".$oServiceCategory->GetName()."({$aParameters['service_id']}) - count: ".$oSet->Count()); } - + $oServiceSubCategory = $oSet->Fetch(); + $oRequest = new UserRequest(); $oRequest->Set('org_id', $oUserOrg->GetKey()); $oRequest->Set('caller_id', UserRights::GetContactId()); - $aList = array('service_id', 'servicesubcategory_id', 'request_type', 'title', 'description', 'impact', 'urgency', 'workgroup_id'); - foreach($aList as $sAttCode) + $aList = array('service_id', 'servicesubcategory_id', 'title', 'description', 'impact'); + $oRequest->UpdateObjectFromPostedForm(); + if (isset($aParameters['moreinfo'])) { - $oRequest->Set($sAttCode, $aParameters[$sAttCode]); + // There is a template, insert it into the description + $oRequest->Set('ticket_log', $aParameters['moreinfo']); } - + + /////$oP->DoUpdateObjectFromPostedForm($oObj); + $oAttPlugin = new AttachmentPlugIn(); + $oAttPlugin->OnFormSubmit($oRequest); + list($bRes, $aIssues) = $oRequest->CheckToWrite(); if ($bRes) { @@ -382,39 +359,9 @@ function DoCreateRequest($oP, $oUserOrg) $iChangeId = $oMyChange->DBInsert(); $oRequest->DBInsertTracked($oMyChange); $oP->add("

".Dict::Format('UI:Title:Object_Of_Class_Created', $oRequest->GetName(), MetaModel::GetName(get_class($oRequest)))."

\n"); - - if (class_exists('AttachmentPlugIn')) - { - // New way: use the plug-in - $oAttPlugin = new AttachmentPlugIn(); - $oAttPlugin->OnFormSubmit($oRequest); - } - else - { - // Old way: create linked documents - $index = 0; - foreach($_FILES as $sName => $void) - { - $oAttachment = utils::ReadPostedDocument($sName); - if (!$oAttachment->IsEmpty()) - { - $index++; - // Create a document and attach it to the created ticket - $oDoc = new FileDoc(); - $oDoc->Set('name', Dict::Format('Portal:Attachment_No_To_Ticket_Name', $index, $oRequest->GetName(), $oAttachment->GetFileName())); - $oDoc->Set('org_id', $oUserOrg->GetKey()); - $oDoc->Set('description', $oAttachment->GetFileName()); - $oDoc->Set('contents', $oAttachment); - $oDoc->DBInsertTracked($oMyChange); - // Link the document to the ticket - $oLink = new lnkTicketToDoc(); - $oLink->Set('ticket_id', $oRequest->GetKey()); - $oLink->Set('document_id', $oDoc->GetKey()); - $oLink->DBInsertTracked($oMyChange); - } - } - } - DisplayMainMenu($oP); + + //DisplayObject($oP, $oRequest, $oUserOrg); + ShowOngoingTickets($oP); } else { @@ -431,24 +378,19 @@ function DoCreateRequest($oP, $oUserOrg) */ function CreateRequest(WebPage $oP, Organization $oUserOrg) { - $iStep = utils::ReadParam('step', 0); - - switch($iStep) + switch($oP->GetWizardStep()) { case 0: default: - $oP->AddMenuButton('cancel', 'UI:Button:Cancel', './index.php?operation=welcome'); - SelectService($oP, $oUserOrg); + SelectServiceCategory($oP, $oUserOrg); break; case 1: - $oP->AddMenuButton('cancel', 'UI:Button:Cancel', './index.php?operation=welcome'); - SelectSubService($oP, $oUserOrg); + SelectServiceSubCategory($oP, $oUserOrg); break; case 2: - $oP->AddMenuButton('cancel', 'UI:Button:Cancel', './index.php?operation=welcome'); - RequestCreationForm($oP, $oUserOrg); + RequestCreationForm($oP, $oUserOrg); break; case 3: @@ -457,86 +399,6 @@ function CreateRequest(WebPage $oP, Organization $oUserOrg) } } -/** - * Displays the value of the given field, in HTML, without any hyperlink to other objects - * @param DBObject $oObj The object to use - * @param string $sAttCode Code of the attribute to display - * @return string HTML text representing the value of this field - */ -function GetFieldAsHtml($oObj, $sAttCode) -{ - $sValue = ''; - $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); - if ($oAttDef->IsExternalKey()) - { - // Special processing for external keys: don't display any hyperlink - $oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $oObj->Get($sAttCode), false); - if (is_object($oTargetObj)) - { - $sValue = $oTargetObj->GetName(); - } - else - { - $sValue = Dict::S('UI:UndefinedObject'); - } - } - else - { - $sValue = $oObj->GetAsHTML($sAttCode); - } - return $sValue; -} - -/** - * Displays a list of objects, without any hyperlink (except for the object's details) - * @param WebPage $oP The web page for the output - * @param DBObjectSet $oSet The set of objects to display - * @param Array $aZList The ZList (list of field codes) to use for the tabular display - * @return string The HTML text representing the list - */ - function DisplaySet($oP, $oSet, $aZList) - { - if ($oSet->Count() > 0) - { - $aAttribs = array(); - $aValues = array(); - $oAttDef = MetaModel::GetAttributeDef('UserRequest', 'ref'); - $aAttribs['key'] = array('label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription()); - foreach($aZList as $sAttCode) - { - $oAttDef = MetaModel::GetAttributeDef('UserRequest', $sAttCode); - $aAttribs[$sAttCode] = array('label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription()); - } - while($oRequest = $oSet->Fetch()) - { - $aRow = array(); - - $aRow['key'] = ''.$oRequest->Get('ref').''; - $sHilightClass = $oRequest->GetHilightClass(); - if ($sHilightClass != '') - { - $aRow['@class'] = $sHilightClass; - } - foreach($aZList as $sAttCode) - { - $aRow[$sAttCode] = GetFieldAsHtml($oRequest, $sAttCode); - } - $aValues[$oRequest->GetKey()] = $aRow; - } - $oP->Table($aAttribs, $aValues); - // Temprory until we merge re-use the paginated tables: - $oP->add_ready_script( -<<add(Dict::S('Portal:NoOpenRequest')); - } -} - /** * Lists all the currently opened User Requests for the current user * @param WebPage $oP The current web page @@ -544,453 +406,303 @@ EOF */ function ListOpenRequests(WebPage $oP) { - $iContactId = UserRights::GetContactId(); - $oContact = MetaModel::GetObject('Contact', $iContactId, false); // false => Can fail - if (is_object($oContact)) + $oUserOrg = GetUserOrg(); + + $sOQL = 'SELECT UserRequest WHERE org_id = :org_id AND status NOT IN ("closed")'; + $oSearch = DBObjectSearch::FromOQL($sOQL); + $iUser = UserRights::GetUserId(); + if ($iUser > 0) { - $sOQL = 'SELECT UserRequest WHERE caller_id = :contact_id AND status NOT IN ("resolved", "closed")'; - $oSearch = DBObjectSearch::FromOQL($sOQL); - $oSet = new CMDBObjectSet($oSearch, array(), array('contact_id' => $iContactId)); - $aZList = array('title', 'start_date', 'status', 'service_id', 'priority', 'workgroup_id', 'agent_id'); - DisplaySet($oP, $oSet, $aZList); - } + $oSearch->AddCondition('caller_id', $iUser); + } + $oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey())); + $aZList = array('finalclass', 'title', 'start_date', 'status', 'servicesubcategory_id', 'priority', 'caller_id'); + $oP->DisplaySet($oSet, $aZList, Dict::S('Portal:NoOpenRequest')); } /** - * Lists all the currently Resolved (not "Closed")User Requests for the current user + * Lists all the currently resolved (not yet closed) User Requests for the current user * @param WebPage $oP The current web page * @return void */ function ListResolvedRequests(WebPage $oP) { - $iContactId = UserRights::GetContactId(); - $oContact = MetaModel::GetObject('Contact', $iContactId, false); // false => Can fail - if (is_object($oContact)) - { - $sOQL = 'SELECT UserRequest WHERE caller_id = :contact_id AND status ="resolved"'; - $oSearch = DBObjectSearch::FromOQL($sOQL); - $oSet = new CMDBObjectSet($oSearch, array(), array('contact_id' => $iContactId)); - $aZList = array('title', 'start_date', 'status', 'service_id', 'priority', 'workgroup_id', 'agent_id'); - DisplaySet($oP, $oSet, $aZList); - } -} -/** - * Displays the details of the specified UserRequest object - * @param WebPage $oP The current web page for the output - * @param UserRequest $oRequest The object to display - * @return void - */ -function DisplayRequestDetails($oP, UserRequest $oRequest, $bEditMode = true) -{ - // Identical to the standard 'details' ZList of UserRequest, except that the field 'org_id' has been removed - $aList = array( - 'col:col1' => array( - 'fieldset:Ticket:baseinfo' => array('ref','title','request_type','status','priority','service_id','servicesubcategory_id','product' ), - 'fieldset:Ticket:moreinfo' => array('impact','urgency','description','resolution_code', 'solution', 'user_satisfaction', 'user_commment','freeze_reason'), - ), - 'col:col2' => array( - 'fieldset:Ticket:date' => array('start_date','last_update','assignment_date','tto_escalation_deadline', 'ttr_escalation_deadline', 'close_date', 'closure_deadline',), - 'fieldset:Ticket:contact' => array('caller_id','workgroup_id','agent_id',), - 'fieldset:Ticket:relation' => array('related_problem_id', 'related_change_id'), - ) + $oUserOrg = GetUserOrg(); - ); - - // Similar to CMDBAbstractObject::GetBareProperties except that: multiple tabs are not supported and GetFieldAsHtml is customized - // in order to NOT display any hyperlink - $aDetails = array(); - $oP->add('
'); - - $aDetailsStruct = CMDBAbstractObject::ProcessZlist($aList, array('UI:PropertiesTab' => array()), 'UI:PropertiesTab', 'col1', ''); - // Compute the list of properties to display, first the attributes in the 'details' list, then - // all the remaining attributes that are not external fields - $aDetails = array(); - $iInputId = 0; - foreach($aDetailsStruct as $sTab => $aCols ) + $sOQL = 'SELECT UserRequest WHERE org_id = :org_id AND status = "resolved"'; + $oSearch = DBObjectSearch::FromOQL($sOQL); + $iUser = UserRights::GetUserId(); + if ($iUser > 0) { - $aDetails[$sTab] = array(); - ksort($aCols); - $oP->add(''); - foreach($aCols as $sColIndex => $aFieldsets) - { - $oP->add(''); - } - $oP->add('
'); - //$aDetails[$sTab][$sColIndex] = array(); - $sLabel = ''; - $sPreviousLabel = ''; - $aDetails[$sTab][$sColIndex] = array(); - foreach($aFieldsets as $sFieldsetName => $aFields) - { - if (!empty($sFieldsetName) && ($sFieldsetName[0] != '_')) - { - $sLabel = $sFieldsetName; - } - else - { - $sLabel = ''; - } - if ($sLabel != $sPreviousLabel) - { - if (!empty($sPreviousLabel)) - { - $oP->add('
'); - $oP->add(''.Dict::S($sPreviousLabel).''); - } - $oP->Details($aDetails[$sTab][$sColIndex]); - if (!empty($sPreviousLabel)) - { - $oP->add('
'); - } - $aDetails[$sTab][$sColIndex] = array(); - $sPreviousLabel = $sLabel; - } - foreach($aFields as $sAttCode) - { - if (MetaModel::IsValidAttCode(get_class($oRequest), $sAttCode)) - { - $iFlags = $oRequest->GetAttributeFlags($sAttCode); - if ( ($iFlags & OPT_ATT_HIDDEN) == 0) - { - // The field is visible, add it to the current column - $val = GetFieldAsHtml($oRequest, $sAttCode); - $aDetails[$sTab][$sColIndex][] = array( 'label' => ''.MetaModel::GetLabel('UserRequest', $sAttCode).'', 'value' => $val); - $iInputId++; - } - } - } - } - if (!empty($sPreviousLabel)) - { - $oP->add('
'); - $oP->add(''.Dict::S($sFieldsetName).''); - } - $oP->Details($aDetails[$sTab][$sColIndex]); - if (!empty($sPreviousLabel)) - { - $oP->add('
'); - } - $oP->add('
'); + $oSearch->AddCondition('caller_id', $iUser); } - - if (!class_exists('AttachmentPlugIn')) - { - // Attachments, the old way - $sOQL = 'SELECT FileDoc AS Doc JOIN lnkTicketToDoc AS L ON L.document_id = Doc.id WHERE L.ticket_id = :request_id'; - $oSearch = DBObjectSearch::FromOQL($sOQL); - $oSet = new CMDBObjectSet($oSearch, array(), array('request_id' => $oRequest->GetKey())); - $aDetails = array(); - if ($oSet->Count() > 0) - { - $sAttachements = ''; - while($oDoc = $oSet->Fetch()) - { - $sAttachements .= ''; - } - $sAttachements .= '
'.$oDoc->GetAsHtml('contents').'
'; - $aDetails[] = array('label' => Dict::S('Portal:Attachments'), 'value' => $sAttachements); - } - $oP->Details($aDetails); - } - - // Case log... editable so that users can post comments - if ($bEditMode) - { - $oP->add("
\n"); - $oP->add("GetKey()."\">"); - $oP->add(""); - $sTransactionId = utils::GetNewTransactionId(); - $oP->SetTransactionId($sTransactionId); - $oP->add("\n"); - $oP->add(""); - $oP->add('
'.MetaModel::GetLabel('UserRequest', 'ticket_log').''); - $oAttDef = MetaModel::GetAttributeDef(get_class($oRequest), 'ticket_log'); - $oValue = $oRequest->Get('ticket_log'); - $oP->add($oRequest->GetFormElementForField($oP, get_class($oRequest), 'ticket_log', $oAttDef, $oValue, $sDisplayValue = '', $iId = 'att_ticket_log')); - //$oP->add(GetFieldAsHtml($oRequest, 'ticket_log')); - $oP->add('
'); - if (class_exists('AttachmentPlugIn')) - { - $oAttPlugin = new AttachmentPlugIn(); - // depending on the plug-in's configuration, the attachments are displayed either in the 'properties' or in the 'relations' - // in the portal, both are handled the same way... it does not matter - $oAttPlugin->OnDisplayProperties($oRequest, $oP, true /* edit */); - $oAttPlugin->OnDisplayRelations($oRequest, $oP, true /* edit */); - } - $oP->p(''); - $oP->add('
'); - $oP->add_ready_script( -<<add('
'.MetaModel::GetLabel('UserRequest', 'ticket_log').''); - $oP->add(GetFieldAsHtml($oRequest, 'ticket_log')); - $oP->add('
'); - if (class_exists('AttachmentPlugIn')) - { - $oAttPlugin = new AttachmentPlugIn(); - // depending on the plug-in's configuration, the attachments are displayed either in the 'properties' or in the 'relations' - // in the portal, both are handled the same way... it does not matter - $oAttPlugin->OnDisplayProperties($oRequest, $oP, false /* edit */); - $oAttPlugin->OnDisplayRelations($oRequest, $oP, false /* edit */); - } - } - $oP->add('
'); + $oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey())); + $aZList = array('finalclass', 'title', 'start_date', 'status', 'servicesubcategory_id', 'priority', 'caller_id'); + $oP->DisplaySet($oSet, $aZList, Dict::S('Portal:NoOpenRequest')); } /** - * Displays a form for the user to provide feedback about a 'resolved' UserRequest and then close the request + * Lists all the currently closed tickets * @param WebPage $oP The current web page - * @param UserRequest $oRequest The object to display * @return void */ -function DisplayResolvedRequestForm($oP, UserRequest $oRequest) +function ListClosedTickets(WebPage $oP) { - $oP->add("
\n"); - $oP->add("
\n"); - $aArgs = array('this' => $oRequest); - $sClass = get_class($oRequest); + $aAttSpecs = array('ref', 'start_date', 'close_date', 'service_id', 'caller_id'); + $aZList = array('title', 'start_date', 'close_date', 'servicesubcategory_id'); - $aDetails = array(); - $aTargetStates = MetaModel::EnumStates($sClass); - $aTargetState = $aTargetStates['closed']; - $aExpectedAttributes = $aTargetState['attribute_list']; - $iFieldIndex = 0; - - foreach($aExpectedAttributes as $sAttCode => $iExpectCode) + $oP->DisplaySearchForm('UserRequest', $aAttSpecs, array('operation' => 'show_closed'), 'search_', false /* => not closed */); + + $oUserOrg = GetUserOrg(); + + // UserRequest + $oSearch = $oP->PostedParamsToFilter('UserRequest', $aAttSpecs, 'search_'); + if(is_null($oSearch)) { - // Prompt for an attribute if - // - the attribute must be changed or must be displayed to the user for confirmation - // - or the field is mandatory and currently empty - if ( ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) || - (($iExpectCode & OPT_ATT_MANDATORY) && ($oRequest->Get($sAttCode) == '')) ) - { - $aAttributesDef = MetaModel::ListAttributeDefs($sClass); - $oAttDef = $aAttributesDef[$sAttCode]; - $aArgs = array('this' => $oRequest); - $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $oRequest->Get($sAttCode), $oRequest->GetEditValue($sAttCode), 'att_'.$iFieldIndex, '', $iExpectCode, $aArgs); - $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => "$sHTMLValue"); - $aFieldsMap[$sAttCode] = 'att_'.$iFieldIndex; - $iFieldIndex++; - } + $oSearch = new DBObjectSearch('UserRequest'); } - $aStimuli = MetaModel::EnumStimuli($sClass); - $oP->add("

".Dict::S('Portal:EnterYourCommentsOnTicket')."

"); - $oP->details($aDetails); - $oP->add("GetKey()."\">"); - $oP->add(""); - $oP->add("\n"); - $oP->add(""); - $oP->p(""); - $oP->add("
"); - $oP->add("
\n"); - $oP->add("

".Dict::Format('Portal:TitleRequestDetailsFor_Request', $oRequest->GetName())."

\n"); - DisplayRequestDetails($oP, $oRequest, false /* bEditMode */); - - $oP->add_ready_script( -<<AddCondition('org_id', $oUserOrg->GetKey()); + $oSearch->AddCondition('status', 'closed'); + $iUser = UserRights::GetUserId(); + if ($iUser > 0) + { + $oSearch->AddCondition('caller_id', $iUser + 12345); + } + $oSet1 = new CMDBObjectSet($oSearch); + $oP->add("

\n"); + $oP->add("

".Dict::S('Portal:ClosedRequests')."

\n"); + $oP->DisplaySet($oSet1, $aZList, Dict::S('Portal:NoClosedRequest')); + $oP->add("

\n"); } + /** - * Actually close the request and saves the user's feedback + * Display an object - to be customized * @param WebPage $oP The current web page - * @param UserRequest $oRequest The object to close + * @param Object $oObj Any kind of object + * @param Object $oUserOrg The organization of the logged in user * @return void */ -function DoCloseRequest($oP, UserRequest $oRequest) +function DisplayObject($oP, $oObj, $oUserOrg) { - $sTransactionId = utils::ReadPostedParam('transaction_id', ''); - if (!utils::IsTransactionValid($sTransactionId)) + switch(get_class($oObj)) { - $oP->add("

".Dict::S('UI:Error:ObjectAlreadyCreated')."

\n"); - DisplayMainMenu($oP); - return; - } - - $sClass = get_class($oRequest); - $aDetails = array(); - $aTargetStates = MetaModel::EnumStates($sClass); - $aTargetState = $aTargetStates['closed']; - $aExpectedAttributes = $aTargetState['attribute_list']; - $iFieldIndex = 0; - - foreach($aExpectedAttributes as $sAttCode => $iExpectCode) - { - // Prompt for an attribute if - // - the attribute must be changed or must be displayed to the user for confirmation - // - or the field is mandatory and currently empty - if ( ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) || - (($iExpectCode & OPT_ATT_MANDATORY) && ($oRequest->Get($sAttCode) == '')) ) - { - $value = utils::ReadPostedParam('attr_'.$sAttCode, null, 'raw_data'); - if (!is_null($value)) - { - $oRequest->Set($sAttCode, $value); - } - } - } - if ($oRequest->ApplyStimulus('ev_close')) - { - $oMyChange = MetaModel::NewObject("CMDBChange"); - $oMyChange->Set("date", time()); - $sUserString = CMDBChange::GetCurrentUserName(); - $oMyChange->Set("userinfo", $sUserString); - $iChangeId = $oMyChange->DBInsert(); - $oRequest->DBUpdateTracked($oMyChange); - $oP->p("

".Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oRequest)), $oRequest->GetName())."

\n"); - DisplayMainMenu($oP); - } - else - { - $oP->AddMenuButton('back', 'Portal:Back', './index.php?operation=welcome'); - $oP->add('Error: cannot close the request - '.$oRequest->GetName()); + case 'UserRequest': + ShowDetailsRequest($oP, $oObj); + break; + + default: + throw new Exception("The class ".get_class($oObj)." is not handled through the portal"); } } -/** - * Find the UserRequest object of the specified ID. Make sure that it the caller is the current user - * @param integer $id The ID of the request to find - * @return UserRequert The found object, or null in case of failure (object does not exist, user has no rights to see it...) - */ -function FindRequest($id) -{ - $oRequest = null; - $iContactId = UserRights::GetContactId(); - $oContact = MetaModel::GetObject('Contact', $iContactId, false); // false => Can fail - if (is_object($oContact)) - { - $sOQL = "SELECT UserRequest WHERE caller_id = :contact_id AND id = :request_id"; - $oSearch = DBObjectSearch::FromOQL($sOQL); - $oSet = new CMDBObjectSet($oSearch, array(), array('contact_id' => $iContactId, 'request_id' => $id)); - if ($oSet->Count() > 0) - { - $oRequest = $oSet->Fetch(); - } - } - else - { - $oP->AddMenuButton('back', 'Portal:Back', './index.php?operation=welcome'); - $oP->add("

".Dict::S('Portal:ErrorNoContactForThisUser')."

"); - } - return $oRequest; -} /** * Displays the details of a request * @param WebPage $oP The current web page + * @param Object $oObj The target object * @return void */ -function RequestDetails(WebPage $oP, $id) +function ShowDetailsRequest(WebPage $oP, $oObj) { - $oRequest = FindRequest($id); - if (!is_object($oRequest)) - { - DisplayMainMenu($oP); - return; - } - $iDefaultStep = 0; - if ($oRequest->GetState() == 'resolved') - { - // The current ticket is in 'resolved' state, prompt to close it - $iDefaultStep = 1; - } + $sClass = get_class($oObj); - $iStep = utils::ReadParam('step', $iDefaultStep); - - switch($iStep) + $bIsEscalateButton = false; + $bIsCloseButton = false; + $bEditAttachments = false; + switch($oObj->GetState()) { - case 0: - $oP->AddMenuButton('back', 'Portal:Back', './index.php?operation=welcome'); - $oP->add("

".$oRequest->GetIcon()." ".Dict::Format('Portal:TitleRequestDetailsFor_Request', $oRequest->GetName())."

\n"); - DisplayRequestDetails($oP, $oRequest); - break; - - case 1: - $oP->AddMenuButton('cancel', 'UI:Button:Cancel', './index.php?operation=welcome'); - DisplayResolvedRequestForm($oP, $oRequest); - break; - - case 2: - DoCloseRequest($oP, $oRequest); + case 'new': + case 'assigned': + case 'frozen': + $aEditAtt = array( + 'ticket_log' => '????' + ); + $bEditAttachments = true; + // disabled - $bIsEscalateButton = true; break; - case 3: - AddComment($oP, $oRequest); + case 'escalated_tto': + case 'escalated_ttr': + $aEditAtt = array( + 'ticket_log' => '????' + ); + $bEditAttachments = true; break; - + + case 'resolved': + $aEditAtt = array( + // non, read-only dans cet etat - 'ticket_log' => '????', + 'user_satisfaction' => '????', + 'user_commment' => '????', + ); + $bIsCloseButton = true; + break; + + case 'closed': + case 'closure_requested': default: - // Should never happen - DisplayMainMenu($oP); + $aEditAtt = array(); + break; } -} -/** - * Adds a comment to the specified UserRequest and displays the main menu - * @param WebPage $oP The current web page for the output - * @param $id ID of the object to update - * @return void - */ -function AddComment($oP, $id) -{ - $oRequest = FindRequest($id); - if (!is_object($oRequest)) +// REFACTORISER LA MISE EN FORME + $oP->add("

".$oObj->GetIcon()." ".Dict::Format('Portal:TitleRequestDetailsFor_Request', $oObj->GetName())."

\n"); + + switch($sClass) { - DisplayMainMenu($oP); - return; + case 'UserIssue': + //$aAttList = array('ref', 'status', 'title', 'description', 'start_date', 'caller_id', 'servicesubcategory_id', 'impact', 'priority', 'agent_id', 'close_date', 'last_update', 'assignment_date', 'resolution_code', 'solution', 'origin', 'time_spent', 'respected_gtr', 'gtr_overdue', 'user_satisfaction', 'user_commment', 'freeze_reason', 'ticket_log'); + $aAttList = array('col:0'=> array('ref','caller_id','impact','perimeter','servicesubcategory_id','title'),'col:1'=> array('status','priority','start_date','resolution_date','last_update','agent_id')); + break; + + case 'UserRequest': + //$aAttList = array('ref', 'status', 'title', 'description', 'requesttype', 'start_date', 'caller_id', 'servicesubcategory_id', 'priority', 'agent_id', 'close_date', 'last_update', 'assignment_date', 'user_satisfaction', 'user_commment', 'freeze_reason', 'ticket_log'); + $aAttList = array('col:0'=> array('ref','caller_id','servicesubcategory_id','title'),'col:1'=> array('status','priority','start_date','resolution_date','last_update','agent_id')); + break; + + default: + //$aAttList = array('ref'); + array('col:0'=> array('ref','service_id','servicesubcategory_id','title'),'col:1'=> array('status','start_date')); + break; } - $sTransactionId = utils::ReadPostedParam('transaction_id', ''); - if (!utils::IsTransactionValid($sTransactionId)) + + // Remove the edited attribute from the shown attributes + // + foreach($aEditAtt as $sAttCode => $foo) { - $oP->add("

".Dict::S('UI:Error:ObjectAlreadyUpdated')."

\n"); - DisplayMainMenu($oP); - return; - } - $sComment = trim(utils::ReadPostedParam('attr_ticket_log', '', 'raw_data')); - if (!empty($sComment)) - { - $oRequest->Set('ticket_log', $sComment); - } - if (class_exists('AttachmentPlugIn')) - { - $oAttPlugin = new AttachmentPlugIn(); - $oAttPlugin->OnFormSubmit($oRequest, ''); - } - if ($oRequest->IsModified()) - { - $oMyChange = MetaModel::NewObject("CMDBChange"); - $oMyChange->Set("date", time()); - $sUserString = CMDBChange::GetCurrentUserName(); - $oMyChange->Set("userinfo", $sUserString); - $iChangeId = $oMyChange->DBInsert(); - $oRequest->DBUpdateTracked($oMyChange); - $oP->p("

".Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oRequest)), $oRequest->GetName())."

\n"); - - // If there is any trigger for the Portal Update, then activate them - $aClasses = MetaModel::EnumParentClasses(get_class($oRequest), ENUM_PARENT_CLASSES_ALL); - $aClasses = CMDBSource::Quote($aClasses); - $sOQL = "SELECT TriggerOnPortalUpdate WHERE target_class IN (".implode(',', $aClasses).")"; - $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL)); - while($oTrigger = $oSet->Fetch()) + foreach($aAttList as $col => $aColumn) { - $oTrigger->DoActivate($oRequest->ToArgs('this')); + if (in_array($sAttCode, $aColumn)) + { + if(($index = array_search($sAttCode, $aColumn)) !== false) + { + unset($aAttList[$col][$index]); + } + } } } + + $oP->add("
\n"); + $oP->WizardFormStart('request_form', null); + + $oP->add('
'); + $oP->add(''); + + $oP->add(''); + $oP->add(''); + $oP->add(''); + $oP->add(''); + +// REFACTORISER + $oP->add(''); + $oP->add(''); + $oP->add(''); + + if (count($aEditAtt) > 0) + { + $oP->add(''); + $oP->add('
'); + $oP->DisplayObjectDetails($oObj, $aAttList['col:0']); + $oP->add(''); + $oP->DisplayObjectDetails($oObj, $aAttList['col:1']); + $oP->add('
'); + $oAttPlugin = new AttachmentPlugIn(); + if ($bEditAttachments) + { + $oAttPlugin->EnableDelete(false); + $oAttPlugin->OnDisplayRelations($oObj, $oP, true /* edit */); + } else { - $oP->p("

".Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oRequest)), $oRequest->GetName())."

\n"); + $oAttPlugin->OnDisplayRelations($oObj, $oP, false /* read */); } - DisplayMainMenu($oP); + $oP->add('
'); + + //$oP->add("
\n"); + //$oP->add(''); + $oP->add(''); + } + + $oP->add(''); + $oP->add(''); + $oP->add(''); + + $oP->add('
'); + //$oP->add("

".Dict::Format('Portal:CommentsFor_Request', $oObj->GetName())."

\n"); + $oP->add(""); + $oP->add("GetKey()."\">"); + $oP->add(""); + $oP->add("\n"); + $oP->add_script( +<< $foo) + { + $sValue = $oObj->Get($sAttCode); + $sDisplayValue = $oObj->GetEditValue($sAttCode); + $aArgs = array('this' => $oObj, 'formPrefix' => ''); + $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); + $sInputId = 'input_'.$sAttCode; + $sHTMLValue = "".cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', 0 /*$iFlags*/, $aArgs).''; + + $aEditFields[$sAttCode] = array( + 'label' => MetaModel::GetLabel($sClass, $sAttCode), + 'value' => $sHTMLValue + ); + } + foreach($aEditFields as $sAttCode => $aFieldSpec) + { + if ($sAttCode == 'ticket_log') + { + // Skip, the public log will be displayed below the buttons + continue; + } + $oP->add("
"); + $oP->add('

'.$aFieldSpec['label'].'

'); + $oP->add($aFieldSpec['value']); + $oP->add('
'); + } + // $oP->p(''); + if($bIsCloseButton) + { + $sStimulusCode = 'ev_close'; + $oP->p(''); + } + else + { + $oP->p(''); + } + + if ($bIsEscalateButton) + { + $sStimulusCode = 'ev_timeout'; + $oP->p(''); + } + + $oP->add('
'); + if (isset($aEditFields['ticket_log'])) + { + $oP->add("
"); + $oP->add('

'.$aEditFields['ticket_log']['label'].'

'); + $oP->add($aEditFields['ticket_log']['value']); + $oP->add('
'); + } + else + { + $oP->add('

'.MetaModel::GetLabel($sClass, 'ticket_log').'

'); + $oP->add($oObj->GetAsHTML('ticket_log')); + } + $oP->add('
'); + $oP->add(''); + + $oP->WizardFormEnd(); + $oP->add(''); } /** @@ -1014,6 +726,12 @@ function GetUserOrg() return $oOrg; } +/////////////////////////////////////////////////////////////////////////////// +// +// Main program +// +/////////////////////////////////////////////////////////////////////////////// + try { require_once(APPROOT.'/application/startup.inc.php'); @@ -1024,6 +742,8 @@ try require_once(APPROOT.'/application/loginwebpage.class.inc.php'); LoginWebPage::DoLogin(false /* bMustBeAdmin */, true /* IsAllowedToPortalUsers */); // Check user rights and prompt if needed + ApplicationContext::SetUrlMakerClass('PortalURLMaker'); + $oUserOrg = GetUserOrg(); $sCode = $oUserOrg->Get('code'); @@ -1034,24 +754,57 @@ try } $oP = new PortalWebPage(Dict::S('Portal:Title'), $sAlternateStylesheet); - $oP->add($sAlternateStylesheet); + + $oP->EnableDisconnectButton(true); + $oP->SetWelcomeMessage(Dict::Format('Portal:WelcomeUserOrg', UserRights::GetUserFriendlyName(), $oUserOrg->GetName())); if (is_object($oUserOrg)) { switch($sOperation) { + case 'show_closed': + DisplayMainMenu($oP); + ShowClosedTickets($oP); + break; + case 'create_request': + DisplayMainMenu($oP); CreateRequest($oP, $oUserOrg); break; case 'details': - $iRequestId = utils::ReadParam('id', 0); - RequestDetails($oP, $iRequestId); + DisplayMainMenu($oP); + $oObj = $oP->FindObjectFromArgs(array('UserRequest')); + DisplayObject($oP, $oObj, $oUserOrg); break; - case 'welcome': + case 'update_request': + DisplayMainMenu($oP); + $oObj = $oP->FindObjectFromArgs(array('UserRequest')); + switch(get_class($oObj)) + { + case 'UserRequest': + $aAttList = array('ticket_log', 'user_satisfaction', 'user_commment'); + break; + + default: + throw new Exception("Implementation issue: unexpected class '".get_class($oObj)."'"); + } + try + { + $oP->DoUpdateObjectFromPostedForm($oObj, $aAttList); + } + catch(TransactionException $e) + { + $oP->add("

".Dict::S('UI:Error:ObjectAlreadyUpdated')."

\n"); + } + DisplayObject($oP, $oObj, $oUserOrg); + break; + + case 'show_ongoing': default: DisplayMainMenu($oP); + ShowOngoingTickets($oP); } } $oP->output(); diff --git a/portal/portal.css b/portal/portal.css index 922d85000c..d5b10b2702 100644 --- a/portal/portal.css +++ b/portal/portal.css @@ -7,72 +7,98 @@ html, body { height: 100%; } #content { - margin: 10px; + margin: auto; padding-left: 10px; padding-right: 10px; text-align: center; overflow-y: auto; + no.max-width: 90%; + min-width: 960px; + position: relative; display: block; + clear: both; +} +div#portal #welcome { + display: none; + background: url("./images/dockbar_bg.png") repeat-x scroll 0 0 #97A1AE; + border-bottom: 1px solid #636364; + font-size: 13px; + padding: 1px 5px; + position: relative; + z-index: 300; + text-align:right; + color: #2C2F34; + font-weight: bold; + text-shadow: 1px 1px #FFFFFF; } div#portal #banner { - width: 100%; - height: 60px; + background-color: #F6F6F1; display: block; - vertical-align:middle; - background-color: #f6f6f1; + height: 60px; + vertical-align: middle; + width: 100%; +} +div#portal #logo { + background: url("../images/itop-logo.png") no-repeat scroll 0 0 transparent; + border: 0 none; + display: inline-block; + height: 116px; + line-height: 48px; + margin-left: 20px; + margin-right: 20px; + padding-right: 50px; + text-align: center; + vertical-align: middle; + width: 240px; } -div#portal #logo { - width: 126px; - background: url(../images/itop-logo.png) 0 0 no-repeat; - margin-left:20px; - margin-right:20px; - height: 60px; - border: 0; - vertical-align: middle; - text-align: center; - display: inline-block; - line-height: 48px; - padding-right:50px; -} div#menu { display: block; - width: auto; - position: absolute; - top: 0; - left: 200px; - right: 0px; - line-height: 48px; height: 48px; + left: 200px; + line-height: 48px; + position: absolute; + right: 0; + top: 0; + width: auto; } + #portal_menu { height: 60px; } -div.button { - margin-left:20px; - margin-right:20px; - height: 60px; - border: 0; - vertical-align: middle; - text-align: center; - display: inline-block; - line-height: 48px; +#change_pwd { + background: url("../images/password.png") no-repeat scroll 0 0 transparent; + display: block; + float: right; } -a.button , a.button:visited { +#logoff { + background: url("../images/logoff.png") no-repeat scroll 0 0 transparent; + display: block; + float: right; +} +#logoff span { +} + +div.button { + font-size: 1.1em; + font-weight: bold; + text-decoration: none; +} +a.button, a.button:visited { color: #1C94C4; - text-decoration: none; - vertical-align: middle; + display: inline-block; height: 48px; line-height: 48px; - display: inline-block; + text-decoration: none; + vertical-align: middle; } a.button span { - vertical-align:middle; - margin-right: 20px; margin-left: 50px; + margin-right: 20px; + vertical-align: middle; } #close_form_table { @@ -80,66 +106,117 @@ a.button span { padding: 20px; } -#logoff { - display: block; - float: right; - background: url(../images/logoff.png) right center no-repeat; +#request_details td { + text-align:left; } -#logoff span { - margin-right: 50px; - margin-left: 20px; +#request_details td fieldset{ + xxxheight:100%; } -#cancel { - background: url(../images/stop-mid.png) 0 0 no-repeat; -} - -#create { - background: url(../modules/itop-request-mgmt-1.0.0/images/user-request.png) 0 0 no-repeat; -} -#user_info { - background: url(../images/clean-mid.png) 0 0 no-repeat; -} - -#change_pwd { - background: url(../images/password.png) 0 0 no-repeat; -} -#back { - background: url(../images/back.png) 0 0 no-repeat; -} -#back span { - margin-left: 54px; -} -#refresh { - background: url(../images/refresh.png) 0 0 no-repeat; - margin-right: 40px; -} -#refresh span { - margin-left: 54px; - margin-right: 20px; -} -#request_details { - display: inline-block; - width:800px; - text-align: left; -} -#form_close_request { - display: inline-block; - width:800px; - text-align: left; -} -#request_details_log { - width:774px; -} -#request_details table { - border: #f1f1f6 2px solid; - text-align: left; -} #form_details { display: inline-block; } + .wizContainer table { display: inline-block; text-align: left; } + +#user_request_comment { + width: 30em; + height: 20em; +} + +#buttons { + margin-top: 1em; +} +div#buttons #btn_cancel { + margin-right: 50px; +} + +div#buttons #btn_back { + margin-left: 50px; + margin-right: 5px; +} + +div#buttons #btn_next { + margin-left: 5px; +} + +div#buttons #btn_finish { + margin-left: 5px; +} +table.listContainer { + clear: both; + width: 100%; +} +h1 { + font-weight: bold; + font-weight: bold; + padding: 5px; + margin-top: 5px; +} + +div.DrawerHandle { + display:none; +} +div.HRDrawer { + background: transparent; + border: 0; + height: 0.5em; +} + +.SearchDrawer { + background-color: #F9EDBF; + border: 0; + -moz-border-radius: 4px 4px 4px 4px; +} +.SearchDrawer label { + background: transparent; +} +#open_incidents, #open_requests, #open_changes, #request_details { + margin-bottom: 1em; +} +legend { + background: url("./images/header_bg.png") repeat-x scroll 0 0 #D4D4D4; + border-color: #C8C9CA #9E9E9E #9E9E9E #C8C9CA; + border-style: solid; + border-width: 1px; + font-size: 1.1em; + font-weight: bold; + color: #222222; + font-weight: bold; + text-shadow: 1px 1px #FFFFFF; + padding: 5px; + -moz-border-radius: 4px 4px 4px 4px; + margin-top:0; +} +table.details > tbody > tr > td { + padding-bottom: 5px; + padding-top: 3px; + padding-right: 5px; + border: 0; +} +.label { + font-weight: bold; +} +.caselog { + display:block; + width: 100%; +} +.caselog textarea { + resize: none; +} +.edit_item { + margin-bottom: 1em; +} +div.edit_item span div table { + width: 100%; +} +div.edit_item span div table tbody tr td textarea{ + width: 99%; +} +div#ticket_shortcuts form { + display: inline-block; +} \ No newline at end of file