├── admin ├── sql │ ├── updates │ │ ├── mysql │ │ │ ├── 0.0.1.sql │ │ │ ├── 1.sql │ │ │ ├── index.html │ │ │ └── 2.0.0.sql │ │ └── index.html │ ├── index.html │ ├── uninstall.mysql.utf8.sql │ └── install.mysql.utf8.sql ├── index.html ├── models │ ├── index.html │ ├── fields │ │ ├── index.html │ │ └── advancedopenportal.php │ └── advancedopenportals.php ├── tables │ ├── index.html │ └── advancedopenportal.php ├── views │ ├── index.html │ └── advancedopenportals │ │ ├── index.html │ │ ├── tmpl │ │ ├── index.html │ │ ├── default_head.php │ │ ├── default_foot.php │ │ ├── default.php │ │ └── default_body.php │ │ └── view.html.php ├── language │ └── en-GB │ │ ├── en-GB.com_advancedopenportal.ini │ │ └── en-GB.com_advancedopenportal.sys.ini ├── advancedopenportal.php └── controller.php ├── site ├── index.html ├── models │ ├── index.html │ ├── SugarContact.php │ ├── SugarAccount.php │ ├── SugarUpdate.php │ ├── SugarCase.php │ ├── SugarObject.php │ ├── advancedopenportal.php │ └── SugarCasesConnection.php ├── views │ ├── index.html │ ├── newcase │ │ ├── index.html │ │ ├── tmpl │ │ │ ├── index.html │ │ │ ├── default.xml │ │ │ └── default.php │ │ └── view.html.php │ ├── listcases │ │ ├── index.html │ │ ├── tmpl │ │ │ ├── index.html │ │ │ ├── default.xml │ │ │ └── default.php │ │ └── view.html.php │ ├── showcase │ │ ├── index.html │ │ ├── tmpl │ │ │ ├── index.html │ │ │ └── default.php │ │ └── view.html.php │ ├── attachment │ │ ├── index.html │ │ └── view.html.php │ └── advancedopenportal │ │ ├── index.html │ │ ├── tmpl │ │ ├── index.html │ │ ├── default.xml │ │ └── default.php │ │ └── view.html.php ├── advancedopenportal.php ├── css │ └── portal.css ├── js │ ├── jquery.prettydate.js │ ├── jquery.form.min.js │ └── jquery.dataTables.1.9.4.min.js ├── sugarRestClient.php └── controller.php ├── .gitignore ├── README.md ├── language └── en-GB │ └── en-GB.com_advancedopenportal.ini ├── advancedopenportal.xml └── LICENSE /admin/sql/updates/mysql/0.0.1.sql: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /admin/sql/updates/mysql/1.sql: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /admin/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/models/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/sql/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/tables/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/models/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/sql/updates/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/views/newcase/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/models/fields/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/sql/updates/mysql/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/views/listcases/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/views/newcase/tmpl/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/views/showcase/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/sql/uninstall.mysql.utf8.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `#__advancedopenportal`; 2 | -------------------------------------------------------------------------------- /site/views/attachment/index.html: -------------------------------------------------------------------------------- 1 | vie 2 | -------------------------------------------------------------------------------- /site/views/listcases/tmpl/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/views/showcase/tmpl/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/views/advancedopenportals/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/views/advancedopenportal/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/views/advancedopenportals/tmpl/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /site/views/advancedopenportal/tmpl/index.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /admin/views/advancedopenportals/tmpl/default_head.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /admin/language/en-GB/en-GB.com_advancedopenportal.ini: -------------------------------------------------------------------------------- 1 | COM_ADVANCEDOPENPORTAL="Advanced OpenPortal" 2 | COM_ADVANCEDOPENPORTAL_MANAGER_ADVANCEDOPENPORTALS="Advanced OpenPortal Settings" 3 | COM_ADVANCEDOPENPORTAL_SETTINGS_SAVED='Settings saved' 4 | -------------------------------------------------------------------------------- /admin/sql/updates/mysql/2.0.0.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `#__advancedopenportal` 2 | ADD COLUMN allow_case_reopen BOOLEAN, 3 | ADD COLUMN allow_case_closing BOOLEAN, 4 | ADD COLUMN allow_priority BOOLEAN, 5 | ADD COLUMN allow_type BOOLEAN; 6 | 7 | -------------------------------------------------------------------------------- /site/models/SugarContact.php: -------------------------------------------------------------------------------- 1 | id = $id; 9 | } 10 | 11 | public function fetch(){ 12 | 13 | } 14 | 15 | 16 | 17 | } -------------------------------------------------------------------------------- /site/views/advancedopenportal/view.html.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 |   8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /site/views/advancedopenportal/tmpl/default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | COM_ADVANCEDOPENPORTAL_HOME_VIEW_DEFAULT_DESC 5 | 6 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /site/views/newcase/tmpl/default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | COM_ADVANCEDOPENPORTAL_NEW_CASE_VIEW_DEFAULT_DESC 5 | 6 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /site/models/SugarAccount.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | COM_ADVANCEDOPENPORTAL_LIST_CASE_VIEW_DEFAULT_DESC 5 | 6 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /admin/sql/install.mysql.utf8.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `#__advancedopenportal`; 2 | 3 | CREATE TABLE `#__advancedopenportal` ( 4 | `id` int(11) NOT NULL AUTO_INCREMENT, 5 | `sugar_url` varchar(200) DEFAULT NULL, 6 | `sugar_user` varchar(60) DEFAULT NULL, 7 | `sugar_pass` varchar(32) DEFAULT NULL, 8 | `allow_case_reopen` BOOLEAN, 9 | `allow_case_closing` BOOLEAN, 10 | `allow_priority` BOOLEAN, 11 | `allow_type` BOOLEAN, 12 | PRIMARY KEY (`id`) 13 | ) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8; 14 | -------------------------------------------------------------------------------- /admin/views/advancedopenportals/tmpl/default.php: -------------------------------------------------------------------------------- 1 | 9 |
10 | loadTemplate('head');?> 11 | loadTemplate('body');?> 12 | loadTemplate('foot');?> 13 |
14 | -------------------------------------------------------------------------------- /site/advancedopenportal.php: -------------------------------------------------------------------------------- 1 | execute(JRequest::getCmd('task')); 13 | 14 | // Redirect if set by the controller 15 | $controller->redirect(); 16 | -------------------------------------------------------------------------------- /admin/tables/advancedopenportal.php: -------------------------------------------------------------------------------- 1 | execute(JRequest::getCmd('task')); 16 | 17 | // Redirect if set by the controller 18 | $controller->redirect(); 19 | -------------------------------------------------------------------------------- /site/models/SugarUpdate.php: -------------------------------------------------------------------------------- 1 | description = nl2br(html_entity_decode($this->description)); 8 | if(isset($this->contact)){ 9 | $this->poster = $this->contact[0]; 10 | $this->poster->type = "contact"; 11 | }elseif($this->assigned_user_link){ 12 | $this->poster = $this->assigned_user_link[0]; 13 | $this->poster->type = "user"; 14 | } 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /site/models/SugarCase.php: -------------------------------------------------------------------------------- 1 | description = nl2br($this->description); 16 | include_once 'components/com_advancedopenportal/models/SugarCasesConnection.php'; 17 | $caseConnection = SugarCasesConnection::getInstance(); 18 | $this->status_display = $caseConnection->getCaseStatusDisplay($this->status); 19 | } 20 | } -------------------------------------------------------------------------------- /site/views/advancedopenportal/tmpl/default.php: -------------------------------------------------------------------------------- 1 | addStyleSheet('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'css'.DIRECTORY_SEPARATOR.'portal.css'); 7 | $user =& JFactory::getUser(); 8 | if($user->id){ 9 | ?>

10 | 14 | Home'; 17 | 18 | echo JText::_('COM_ADVANCEDOPENPORTAL_LOGIN_REQUIRED'); 19 | } 20 | -------------------------------------------------------------------------------- /site/views/attachment/view.html.php: -------------------------------------------------------------------------------- 1 | errors = array(); 19 | $note_id = JRequest::getVar('id'); 20 | $caseConnection = new SugarCasesConnection(); 21 | $this->attachment = $caseConnection->getNoteAttachment($note_id); 22 | $finfo = finfo_open(FILEINFO_MIME_TYPE); 23 | $file = base64_decode($this->attachment['file']); 24 | $mime = finfo_buffer($finfo, $file); 25 | header("Content-type: ".$mime); 26 | header("Content-Disposition: attachment;filename=".$this->attachment['filename']); 27 | echo $file; 28 | jexit(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /site/views/listcases/view.html.php: -------------------------------------------------------------------------------- 1 | errors = array(); 19 | 20 | $contact_id = $user->getParam('sugarid'); 21 | $caseConnection = SugarCasesConnection::getInstance(); 22 | $this->cases = $caseConnection->getCases($contact_id); 23 | $this->states = $caseConnection->getStates(); 24 | $this->validPortalUser = SugarCasesConnection::isValidPortalUser($user); 25 | $this->userBlocked = SugarCasesConnection::isUserBlocked($user); 26 | $this->contact = $caseConnection->getContact($contact_id); 27 | // Display the view 28 | parent::display($tpl); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /site/models/SugarObject.php: -------------------------------------------------------------------------------- 1 | date_fields)){ 13 | $disp_name = $name . "_display"; 14 | $this->$disp_name = date($this->format, strtotime($value)); 15 | } 16 | 17 | $this->$name = $value; 18 | } 19 | foreach($relations as $relation){ 20 | $relationname = $relation['name']; 21 | $newrecords = array(); 22 | foreach($relation['records'] as $record){ 23 | $new_record = new stdClass(); 24 | foreach($record as $name_value){ 25 | $name = $name_value['name']; 26 | $value = $name_value['value']; 27 | $new_record->$name = $value; 28 | } 29 | 30 | $newrecords[] = $new_record; 31 | } 32 | $this->$relationname = $newrecords; 33 | 34 | } 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /site/views/showcase/view.html.php: -------------------------------------------------------------------------------- 1 | errors = array(); 19 | $case_id = JRequest::getVar('id'); 20 | $caseConnection = SugarCasesConnection::getInstance(); 21 | 22 | require_once 'components/com_advancedopenportal/models/advancedopenportal.php'; 23 | $settings = AdvancedOpenPortalModelAdvancedOpenPortal::getSettings(); 24 | $this->allow_case_reopen = $settings->allow_case_reopen; 25 | $this->allow_case_closing = $settings->allow_case_closing; 26 | $this->case = $caseConnection->getCase($case_id,$user->getParam("sugarid")); 27 | if(!$this->case){ 28 | JFactory::getApplication()->redirect(JURI::base()."?option=com_advancedopenportal"); 29 | } 30 | parent::display($tpl); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /admin/models/fields/advancedopenportal.php: -------------------------------------------------------------------------------- 1 | getQuery(true); 30 | $query->select('id,sugar_url,sugar_user,sugar_pass'); 31 | $query->from('#__advancedopenportal'); 32 | $db->setQuery((string)$query); 33 | $sagilitysugars = $db->loadObjectList(); 34 | $options = array(); 35 | if ($sagilitysugars) 36 | { 37 | foreach($sagilitysugars as $sagilitysugar) 38 | { 39 | $options[] = JHtml::_('select.option', $sagilitysugar->id, $sagilitysugar->sugar_url, $sagilitysugar->sugar_user,$sagilitysugar->sugar_pass); 40 | } 41 | } 42 | $options = array_merge(parent::getOptions(), $options); 43 | return $options; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /site/views/newcase/view.html.php: -------------------------------------------------------------------------------- 1 | errors = array(); 19 | $caseConnection = SugarCasesConnection::getInstance(); 20 | require_once 'components/com_advancedopenportal/models/advancedopenportal.php'; 21 | $settings = AdvancedOpenPortalModelAdvancedOpenPortal::getSettings(); 22 | $this->allow_priority = $settings->allow_priority; 23 | if($this->allow_priority){ 24 | $this->priorities = $caseConnection->getPriorities(); 25 | }else{ 26 | $this->priorities = array(); 27 | } 28 | $this->allow_type = $settings->allow_type; 29 | if($this->allow_type) { 30 | $this->types = $caseConnection->getTypes(); 31 | }else{ 32 | $this->types = array(); 33 | } 34 | // Display the view 35 | parent::display($tpl); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /admin/controller.php: -------------------------------------------------------------------------------- 1 | enqueueMessage(JText::_('COM_ADVANCEDOPENPORTAL_SETTINGS_SAVED')); 30 | 31 | } 32 | // set default view if not set 33 | JRequest::setVar('view', JRequest::getCmd('view', 'AdvancedOpenPortals')); 34 | 35 | // call parent behavior 36 | parent::display($cachable); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /admin/views/advancedopenportals/view.html.php: -------------------------------------------------------------------------------- 1 | get('Items'); 21 | $pagination = $this->get('Pagination'); 22 | 23 | // Check for errors. 24 | if (count($errors = $this->get('Errors'))) 25 | { 26 | JError::raiseError(500, implode('
', $errors)); 27 | return false; 28 | } 29 | // Assign data to the view 30 | $this->items = $items[0]; 31 | $this->pagination = $pagination; 32 | 33 | // Set the toolbar 34 | $this->addToolBar(); 35 | 36 | // Display the template 37 | parent::display($tpl); 38 | 39 | // Set the document 40 | $this->setDocument(); 41 | } 42 | 43 | /** 44 | * Setting the toolbar 45 | */ 46 | protected function addToolBar() 47 | { 48 | JToolBarHelper::title(JText::_('COM_ADVANCEDOPENPORTAL_MANAGER_ADVANCEDOPENPORTALS')); 49 | } 50 | 51 | protected function setDocument() 52 | { 53 | $document = JFactory::getDocument(); 54 | $document->setTitle(JText::_('Advanced OpenPortal Settings')); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SuiteCRM-Portal-Joomla 2.0.3 2 | Joomla Plugin for the SuiteCRM Portal 3 | 4 | 5 | ### What's in this repository ### 6 | 7 | This is the git repository for the SuiteCRM Portal project 8 | 9 | This repository has been created to allow community members to collaborate and contribute to the project, helping to develop the SuiteCRM Portal. 10 | 11 | ### Contributing to the project ### 12 | 13 | #####Important: Please read before developing code intended for inclusion in the SuiteCRM project.##### 14 | 15 | Please read and sign the following [contributor agreement][cont_agrmt] 16 | 17 | [cont_agrmt]: https://cla.suitecrm.com/salesagility/SuiteCRM 18 | 19 | The Contributor Agreement only needs to be signed once for all pull requests and contributions. 20 | 21 | Once signed and confirmed, any pull requests will be considered for inclusion in the SuiteCRM Portal project. 22 | 23 | ### Helpful links for the community### 24 | 25 | The following links offer various ways to view, contribute and collaborate to the SuiteCRM Portal project: 26 | 27 | 28 | + [SuiteCRM Demo - A fully working SuiteCRM demo available for people to try before downloading the full SuiteCRM package][suitecrm_demo] 29 | + [SuiteCRM Forums - Forums dedicated to discussions about SuiteCRM with various topics and subjects about SuiteCRM][suitecrm_forums] 30 | + [SuiteCRM Documentation - A wiki containing relevant documentation to SuiteCRM including portal, constantly being added to][suitecrm_portal_docs] 31 | 32 | [suitecrm_demo]: https://suitecrm.com/demo 33 | [suitecrm_forums]: https://community.suitecrm.com/ 34 | [suitecrm_Portal_docs]: https://docs.suitecrm.com/user/advanced-modules/cases-with-portal/ 35 | 36 | -------------------------------------------------------------------------------- /site/css/portal.css: -------------------------------------------------------------------------------- 1 | .case_update{ 2 | -webkit-border-radius: 5px; 3 | -moz-border-radius: 5px; 4 | border-radius: 5px; 5 | border: solid 1px; 6 | margin-top: 5px; 7 | padding: 5px; 8 | } 9 | 10 | .case_description{ 11 | -webkit-border-radius: 5px; 12 | -moz-border-radius: 5px; 13 | border-radius: 5px; 14 | border: solid 1px; 15 | margin-top: 5px; 16 | padding: 5px; 17 | min-height: 50px; 18 | } 19 | 20 | .user_update{ 21 | margin-right: 50px; 22 | } 23 | 24 | .contact_update{ 25 | margin-left: 50px; 26 | } 27 | 28 | .show_case_table{ 29 | width: 100%; 30 | } 31 | #case_table{ 32 | width: 100%; 33 | } 34 | 35 | .portal_form textarea { 36 | height: 125px; 37 | width: 375px; 38 | } 39 | 40 | h2 span{ 41 | font-size: 0.7em; 42 | } 43 | 44 | /* 45 | * List view 46 | * 47 | */ 48 | 49 | .paginate_enabled_previous{ 50 | text-decoration: underline; 51 | } 52 | .paginate_enabled_next{ 53 | text-decoration: underline; 54 | margin-left: 10px; 55 | } 56 | .paginate_disabled_previous{ 57 | display: none; 58 | } 59 | 60 | .paginate_disabled_next{ 61 | display: none; 62 | } 63 | 64 | #case_table_info{ 65 | text-align: center; 66 | } 67 | 68 | #case_table_paginate{ 69 | text-align: center; 70 | } 71 | 72 | .table_controls{ 73 | display: inline; 74 | } 75 | #case_table_filter{ 76 | display: inline; 77 | } 78 | #case_table_filter label{ 79 | display: inline; 80 | } 81 | #case_table_length{ 82 | display: inline; 83 | } 84 | #case_table_length label{ 85 | display: inline; 86 | } 87 | #select_controls{ 88 | display: inline; 89 | } 90 | #select_controls label{ 91 | display: inline; 92 | } -------------------------------------------------------------------------------- /site/models/advancedopenportal.php: -------------------------------------------------------------------------------- 1 | getQuery(true); 21 | $query->select(array('*')); 22 | $query->from('#__advancedopenportal'); 23 | $db->setQuery($query); 24 | $list = $db->loadObjectList(); 25 | if(count($list)>0){ 26 | return $list[0]; 27 | } 28 | return array(); 29 | } 30 | 31 | /** 32 | * Returns a reference to the a Table object, always creating it. 33 | * 34 | * @param type The table type to instantiate 35 | * @param string A prefix for the table class name. Optional. 36 | * @param array Configuration array for model. Optional. 37 | * @return JTable A database object 38 | * @since 1.6 39 | */ 40 | public function getTable($type = 'AdvancedOpenPortal', $prefix = 'AdvancedOpenPortalTable', $config = array()) 41 | { 42 | return JTable::getInstance($type, $prefix, $config); 43 | } 44 | /** 45 | * Get the message 46 | * @return string The message to be displayed to the user 47 | */ 48 | public function getMsg() 49 | { 50 | if (!isset($this->msg)) 51 | { 52 | $id = JRequest::getInt('id'); 53 | // Get a TableHelloWorld instance 54 | $table = $this->getTable(); 55 | 56 | // Load the message 57 | $table->load($id); 58 | 59 | // Assign the message 60 | $this->msg = $table->sugar_user; 61 | } 62 | return $this->msg; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /language/en-GB/en-GB.com_advancedopenportal.ini: -------------------------------------------------------------------------------- 1 | COM_ADVANCEDOPENPORTAL_PORTAL_NAME="Advanced OpenPortal" 2 | COM_ADVANCEDOPENPORTAL_CREATE_CASE="Create a new case" 3 | COM_ADVANCEDOPENPORTAL_LIST_CASES="List cases" 4 | COM_ADVANCEDOPENPORTAL_LOGIN_REQUIRED="You must be logged in to use the portal" 5 | COM_ADVANCEDOPENPORTAL_NO_PORTAL_ACCOUNT="This account does not have portal access" 6 | COM_ADVANCEDOPENPORTAL_PORTAL_USER_BLOCKED="This portal account has been disabled" 7 | COM_ADVANCEDOPENPORTAL_CASE_STATUS="Status" 8 | COM_ADVANCEDOPENPORTAL_CASE_STATUS_ALL="All" 9 | COM_ADVANCEDOPENPORTAL_CASE_STATUS_OPEN="Open" 10 | COM_ADVANCEDOPENPORTAL_CASE_STATUS_CLOSED="Closed" 11 | COM_ADVANCEDOPENPORTAL_CASE_STATE="State" 12 | COM_ADVANCEDOPENPORTAL_CASE_NUMBER="Number" 13 | COM_ADVANCEDOPENPORTAL_CASE_SUBJECT="Subject" 14 | COM_ADVANCEDOPENPORTAL_CASE_CREATED="Created" 15 | COM_ADVANCEDOPENPORTAL_CASE_LAST_UPDATE="Last Update" 16 | COM_ADVANCEDOPENPORTAL_CASE_TYPE="Type" 17 | COM_ADVANCEDOPENPORTAL_CASE_PRIORITY="Priority" 18 | COM_ADVANCEDOPENPORTAL_CASE_DESCRIPTION="Description" 19 | COM_ADVANCEDOPENPORTAL_CASE_ADD_FILE="Add file" 20 | COM_ADVANCEDOPENPORTAL_CASE_ADD_ANOTHER_FILE="Add another file" 21 | COM_ADVANCEDOPENPORTAL_CASE_REMOVE_FILE="X" 22 | COM_ADVANCEDOPENPORTAL_CASE_FILES="Files" 23 | COM_ADVANCEDOPENPORTAL_CASE_UPDATE_ON="On" 24 | COM_ADVANCEDOPENPORTAL_CASE_UPDATE_SAID="said" 25 | COM_ADVANCEDOPENPORTAL_CASE_UPDATE_PLACEHOLDER="Reply here..." 26 | COM_ADVANCEDOPENPORTAL_CASE_UPDATE_SEND_REPLY="Send reply" 27 | COM_ADVANCEDOPENPORTAL_CASE_UPDATE_SENDING="Sending..." 28 | COM_ADVANCEDOPENPORTAL_SAVE="Save" 29 | COM_ADVANCEDOPENPORTAL_CLOSE="Close" 30 | COM_ADVANCEDOPENPORTAL_REOPEN="Reopen" 31 | COM_ADVANCEDOPENPORTAL_CASE_CREATED_BY='Raised by' 32 | COM_ADVANCEDOPENPORTAL_RAISED='Raised by' 33 | COM_ADVANCEDOPENPORTAL_RAISED_ON='on' 34 | COM_ADVANCEDOPENPORTAL_OWN_CASES='My cases' 35 | COM_ADVANCEDOPENPORTAL_SEARCH='Search' -------------------------------------------------------------------------------- /admin/views/advancedopenportals/tmpl/default_body.php: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 | Portal Settings 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
Sugar URL
Sugar Username
Sugar Password
items->allow_case_reopen ? 'checked="checked"' : '';?> name="allow_case_reopen" id="allow_case_reopen">
items->allow_case_closing ? 'checked="checked"' : '';?> name="allow_case_closing" id="allow_case_closing">
items->allow_priority ? 'checked="checked"' : '';?> name="allow_priority" id="allow_priority">
items->allow_type ? 'checked="checked"' : '';?> name="allow_type" id="allow_type">
33 |
-------------------------------------------------------------------------------- /advancedopenportal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Advanced OpenPortal 4 | February 2023 5 | SalesAgility 6 | info@salesagility.com 7 | https://www.salesagility.com 8 | 2.0.3 9 | Joomla integration for the Advanced OpenPortal SuiteCRM case management module 10 | 11 | 12 | 13 | sql/install.mysql.utf8.sql 14 | 15 | 16 | 17 | 18 | sql/uninstall.mysql.utf8.sql 19 | 20 | 21 | 22 | 23 | sql/updates/mysql 24 | 25 | 26 | 27 | language/en-GB/en-GB.com_advancedopenportal.ini 28 | 29 | 30 | css 31 | js 32 | models 33 | views 34 | controller.php 35 | index.html 36 | advancedopenportal.php 37 | sugarRestClient.php 38 | 39 | 40 | 41 | Advanced OpenPortal 42 | 43 | models 44 | sql 45 | tables 46 | views 47 | controller.php 48 | index.html 49 | advancedopenportal.php 50 | 51 | 52 | 53 | language/en-GB/en-GB.com_advancedopenportal.ini 54 | language/en-GB/en-GB.com_advancedopenportal.sys.ini 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /admin/models/advancedopenportals.php: -------------------------------------------------------------------------------- 1 | getQuery(true); 16 | $ob = new stdClass(); 17 | $ob->id = 1; 18 | $ob->sugar_url = $url; 19 | $ob->sugar_user= $user; 20 | $ob->allow_case_reopen = $reopen; 21 | $ob->allow_case_closing = $close; 22 | $ob->allow_priority = $priority; 23 | $ob->allow_type = $type; 24 | try { 25 | $db->updateObject('#__advancedopenportal',$ob,'id'); 26 | if($db->getAffectedRows() == 0){ 27 | $db->insertObject('#__advancedopenportal', $ob); 28 | } 29 | } catch (Exception $e) { 30 | return false; 31 | } 32 | //Do pass as a separate query since they may have left the md5'd pass unchanged 33 | //TODO: Find a nicer way to do this 34 | $fields = array("sugar_pass='" . md5($pass) . "'"); 35 | $conditions = array("sugar_pass!='" . $pass . "' OR sugar_pass IS NULL"); 36 | $query->update($db->quoteName('#__advancedopenportal'))->set($fields)->where($conditions); 37 | $db->setQuery($query); 38 | try { 39 | $db->query(); 40 | } catch (Exception $e) { 41 | return false; 42 | } 43 | return true; 44 | } 45 | 46 | /** 47 | * Method to build an SQL query to load the list data. 48 | * 49 | * @return string An SQL query 50 | */ 51 | protected function getListQuery() 52 | { 53 | // Create a new query object. 54 | $db = JFactory::getDBO(); 55 | $query = $db->getQuery(true); 56 | // Select some fields 57 | $query->select('*'); 58 | // From the hello table 59 | $query->from('#__advancedopenportal'); 60 | return $query; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /site/views/newcase/tmpl/default.php: -------------------------------------------------------------------------------- 1 | addStyleSheet('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'css'.DIRECTORY_SEPARATOR.'portal.css'); 9 | $document->addScript('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR.'jquery.2.0.0.min.js'); 10 | 11 | $editor =& JFactory::getEditor(); 12 | $params = array(); 13 | $descField = $editor->display( 'description', '', '', '', '20', '20', false, null, null, null, $params ); 14 | 15 | JHTML::_('behavior.formvalidation'); 16 | ?> 17 |

18 |
19 |
20 |

21 | allow_type) { 23 | ?> 24 |

35 | allow_priority) { 38 | ?> 39 |

48 | 51 |

52 | 53 | 54 | 55 |
56 | 57 | 58 |
59 | 60 | 82 | -------------------------------------------------------------------------------- /site/views/listcases/tmpl/default.php: -------------------------------------------------------------------------------- 1 | addStyleSheet('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'css'.DIRECTORY_SEPARATOR.'portal.css'); 7 | $document->addScript('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR.'jquery.2.0.0.min.js'); 8 | $document->addScript('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR.'jquery.dataTables.1.9.4.min.js'); 9 | 10 | $user =& JFactory::getUser(); 11 | 12 | if(!$this->validPortalUser || $this->userBlocked){ 13 | return; 14 | } 15 | 16 | ?> 17 |
18 | 19 | 20 | 21 |
22 |
23 | 33 | contact->portal_user_type === 'Account'){ 35 | ?> 36 | 37 | 40 | 41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | cases as $case){ 58 | ?> 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 72 | 73 |
case_number;?>name;?>status_display;?>state;?>contact_created_by_name;?>contact_created_by_id;?>date_entered_display;?>date_modified_display;?>
74 | 75 | 76 | 127 | -------------------------------------------------------------------------------- /site/js/jquery.prettydate.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery prettyDate v1.1.0 3 | * 4 | * @author John Resig (ejohn.org) 5 | * @author Jörn Zaefferer 6 | * @author Timo Tijhof 7 | * 8 | * Based on http://ejohn.org/blog/javascript-pretty-date 9 | * Documentation: http://bassistance.de/jquery-plugins/jquery-plugin-prettydate/ 10 | * 11 | * Dual licensed under the MIT and GPL licenses: 12 | * http://www.opensource.org/licenses/mit-license.php 13 | * http://www.gnu.org/licenses/gpl.html 14 | */ 15 | 16 | (function ($) { 17 | 'use strict'; 18 | 19 | var slice = Array.prototype.slice, 20 | rES5ts = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?: (\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/, 21 | // Indexes in a rES5ts match list that are required for Date.UTC, 22 | // Use in a loop to replace undefined with 0 (otherwise Date.UTC would give NaN) 23 | dateUrcReqIndx = [1, 4, 5, 6, 7, 10, 11]; 24 | 25 | $.prettyDate = { 26 | 27 | /** 28 | * Replace numerial placeholders ({0}, {1}, ..) with the value 29 | * at that index in the array or variadic list of arugments. 30 | * When called with only a source, a function is returned that calls itself 31 | * again, that time with the arguments passed to apply the template. 32 | * 33 | * @param {string} source Text containing {#} placeholders where 34 | * '#' is a number referring to an index in `params`. 35 | * @param {string|Array} [params...] List of replacement values or a 36 | * varadic argument list starting where this argument is the first one. 37 | */ 38 | template: function (source, params) { 39 | if (arguments.length === 1) { 40 | return function () { 41 | var args = slice.call(arguments); 42 | args.unshift(source); 43 | return $.prettyDate.template.apply(this, args); 44 | }; 45 | } 46 | // Detect different call patterns: 47 | // * template(source, [1, 2, 3]) 48 | // * template(source, 1, 2, 3) 49 | if (!$.isArray(params)) { 50 | params = slice.call(arguments, 1); 51 | } 52 | $.each(params, function (i, n) { 53 | source = source.replace(new RegExp('\\{' + i + '\\}', 'g'), n); 54 | }); 55 | return source; 56 | }, 57 | 58 | /** 59 | * Offset from which the relative date will be generated. 60 | * @return {Date} 61 | */ 62 | now: function () { 63 | return new Date(); 64 | }, 65 | 66 | parse: function (timestamp) { 67 | var i, k, minutesOffset, 68 | m = rES5ts.exec(timestamp); 69 | if (!m) { 70 | return NaN; 71 | } 72 | for (i = 0; (k = dateUrcReqIndx[i]); i += 1) { 73 | m[k] = +m[k] || 0; 74 | } 75 | // Undefined days and months are allowed 76 | m[2] = +m[2] || 1; 77 | m[3] = +m[3] || 1; 78 | 79 | if (m[8] !== 'Z' && m[9] !== undefined) { 80 | minutesOffset = m[10] * 60 + m[11]; 81 | 82 | if (m[9] === '+') { 83 | minutesOffset = 0 - minutesOffset; 84 | } 85 | } else { 86 | minutesOffset = 0; 87 | } 88 | 89 | return Date.UTC( 90 | // Year 91 | m[1], 92 | // Month 93 | m[2] - 1, 94 | // Day 95 | m[3], 96 | // Hour 97 | m[4], 98 | // Minutes 99 | // Date.UTC allows values higher than 59 here, 100 | // it increments hours, days etc. if needed. 101 | m[5] + minutesOffset, 102 | // Seconds 103 | m[6], 104 | // Milliseconds 105 | m[7] 106 | ); 107 | }, 108 | 109 | /** 110 | * Takes an ISO time and returns a string representing how 111 | * long ago the date represents. 112 | * @param {string} targetTs Timestamp in ISO 8601 format. 113 | * @return {string} 114 | */ 115 | format: function (target) { 116 | 117 | var messages, 118 | targetTime = $.prettyDate.parse(target), 119 | nowTime = $.prettyDate.now().getTime(), 120 | diff = (nowTime - targetTime) / 1000, 121 | dayDiff = Math.floor(diff / 86400); 122 | 123 | if (isNaN(dayDiff) || dayDiff < 0) { 124 | return; 125 | } 126 | 127 | messages = $.prettyDate.messages; 128 | return dayDiff === 0 && ( 129 | diff < 60 && messages.now || 130 | diff < 120 && messages.minute || 131 | diff < 3600 && messages.minutes(Math.floor(diff / 60)) || 132 | diff < 7200 && messages.hour || 133 | diff < 86400 && messages.hours(Math.floor(diff / 3600))) || 134 | dayDiff === 1 && messages.yesterday || 135 | dayDiff < 7 && messages.days(dayDiff) || 136 | dayDiff < 8 && messages.week || 137 | dayDiff < 14 && messages.days(dayDiff) || 138 | dayDiff < 30 && messages.weeks(Math.ceil(dayDiff / 7)) || 139 | dayDiff < 32 && messages.month || 140 | dayDiff < 363 && messages.months(Math.ceil(dayDiff / 31)) || 141 | dayDiff <= 380 && messages.year || 142 | dayDiff > 380 && messages.years(Math.ceil(dayDiff / 365)); 143 | } 144 | 145 | }; 146 | 147 | $.prettyDate.messages = { 148 | now: 'just now', 149 | minute: '1 minute ago', 150 | minutes: $.prettyDate.template('{0} minutes ago'), 151 | hour: '1 hour ago', 152 | hours: $.prettyDate.template('{0} hours ago'), 153 | yesterday: 'Yesterday', 154 | days: $.prettyDate.template('{0} days ago'), 155 | week: '1 week ago', 156 | weeks: $.prettyDate.template('{0} weeks ago'), 157 | month: '1 month ago', 158 | months: $.prettyDate.template('{0} months ago'), 159 | year: '1 year ago', 160 | years: $.prettyDate.template('{0} years ago') 161 | }; 162 | 163 | /** 164 | * @context {jQuery} 165 | * @param {Object} options 166 | * - {number|false} interval Time in milliseconds between updates, 167 | * or set to false to disable auto updating interval. 168 | * - {string} attribute Name of attribute where the timestamp should 169 | * be accessed from. 170 | * - {Function} value Overrides 'attribute', a custom function to get the 171 | * timestamp. 'this' context is set to the HTMLElement. 172 | */ 173 | $.fn.prettyDate = function (options) { 174 | options = $.extend({ 175 | interval: 10000, 176 | attribute: 'title', 177 | value: function () { 178 | return $(this).attr(options.attribute); 179 | } 180 | }, options); 181 | var elements = this; 182 | function format() { 183 | 184 | elements.each(function () { 185 | var date = $.prettyDate.format(options.value.apply(this)); 186 | if (date && $(this).text() !== date) { 187 | $(this).text(date); 188 | } 189 | }); 190 | } 191 | format(); 192 | if (options.interval) { 193 | setInterval(format, options.interval); 194 | } 195 | return this; 196 | }; 197 | 198 | }(jQuery)); 199 | -------------------------------------------------------------------------------- /site/views/showcase/tmpl/default.php: -------------------------------------------------------------------------------- 1 | addStyleSheet('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'css'.DIRECTORY_SEPARATOR.'portal.css'); 5 | $document->addScript('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR.'jquery.2.0.0.min.js'); 6 | $document->addScript('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR.'jquery-ui.1.10.3.min.js'); 7 | $document->addScript('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR.'jquery.prettydate.js'); 8 | $document->addScript('components'.DIRECTORY_SEPARATOR.'com_advancedopenportal'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR.'jquery.form.min.js'); 9 | $user =& JFactory::getUser(); 10 | 11 | $editor =& JFactory::getEditor(); 12 | $params = array(); 13 | $updateField = $editor->display( 'update_text', '', '', '', '40', '12', false, null, null, null, $params ); 14 | 15 | function displayNotes($parent){ 16 | if(isset($parent->notes)){ 17 | ?> 18 |

19 |
20 | 21 | 24 | 25 | notes as $note){ 27 | if(!$note->id || !$note->filename){ 28 | continue; 29 | } 30 | ?> 31 | filename?> 32 | 36 | allow_case_reopen && strpos($this->case->status, 'Closed') === 0){ 41 | $closeButtonText = JText::_('COM_ADVANCEDOPENPORTAL_REOPEN'); 42 | }elseif($this->allow_case_closing && strpos($this->case->status, 'Open') === 0){ 43 | $closeButtonText = JText::_('COM_ADVANCEDOPENPORTAL_CLOSE'); 44 | }else{ 45 | $closeButtonText = ''; 46 | } 47 | 48 | ?> 49 | 50 |
51 |

case->name;?> (#case->case_number;?>) case->contact_created_by_name .' '.JText::_('COM_ADVANCEDOPENPORTAL_RAISED_ON').' ' .$this->case->date_entered;?> case->status_display;?> 52 | 55 |
56 | 57 | 58 | 59 |
60 | 63 | 64 |

65 |
66 | case->description); 68 | displayNotes($this->case); 69 | ?> 70 |
71 |
72 |
73 |
74 | case->aop_case_updates)){ 76 | foreach($this->case->aop_case_updates as $update){ 77 | ?> 78 |
79 | date_entered_display;?> poster->first_name . " " . $update->poster->last_name;?> : 80 |

description;?>

81 | 82 | 83 | 84 |
85 | 89 |
90 |

91 |
92 |
93 | 94 |
95 | 96 | 97 |
98 | 99 | 100 |
101 | 189 | -------------------------------------------------------------------------------- /site/sugarRestClient.php: -------------------------------------------------------------------------------- 1 | $value) { 13 | $return[] = array('name' => $key, 'value' => $value); 14 | } 15 | 16 | return $return; 17 | } 18 | 19 | /** 20 | * Converts a SugarCRM-REST compatible name_value_list to an Array 21 | * 22 | * @param array $data 23 | * @return array 24 | */ 25 | function convertNVLToArray($data) 26 | { 27 | $return = array(); 28 | foreach ($data as $row) { 29 | $return[$row['name']] = $row['value']; 30 | } 31 | 32 | return $return; 33 | } 34 | 35 | class sugarRestClient 36 | { 37 | 38 | /** 39 | * SugarCRM Session ID 40 | * 41 | * @var string 42 | */ 43 | protected $sid; 44 | /** 45 | * Rest object 46 | * 47 | * @var string 48 | */ 49 | private $rest_url; 50 | /** 51 | * SugarCRM User 52 | * 53 | * @var string 54 | */ 55 | private $rest_user; 56 | /** 57 | * SugarCRM Pass 58 | * 59 | * @var string 60 | */ 61 | private $rest_pass; 62 | 63 | public function __construct() 64 | { 65 | include_once 'components/com_advancedopenportal/models/advancedopenportal.php'; 66 | $settings = AdvancedOpenPortalModelAdvancedOpenPortal::getSettings(); 67 | $this->rest_url = $settings->sugar_url . "/service/v4_1/rest.php"; 68 | $this->base_url = $settings->sugar_url; 69 | $this->rest_user = $settings->sugar_user; 70 | $this->rest_pass = $settings->sugar_pass; 71 | } 72 | 73 | /** 74 | * Login with user credentials 75 | * 76 | * @return boolean 77 | */ 78 | public function login() 79 | { 80 | $login_params = array( 81 | 'user_name' => $this->rest_user, 82 | 'password' => $this->rest_pass, 83 | ); 84 | 85 | $result = $this->rest_request('login', array( 86 | 'user_auth' => $login_params, 87 | "application_name" => "", 88 | 'name_value_list' => array(array('name' => 'notifyonsave', 'value' => 'true')) 89 | )); 90 | 91 | if (isset($result['id'])) { 92 | $this->sid = $result['id']; 93 | 94 | return $result['id']; 95 | } 96 | 97 | if (isset($result['name'])) { 98 | return false; 99 | } 100 | 101 | return false; 102 | } 103 | 104 | /** 105 | * convert to rest request and return decoded array 106 | * 107 | * @param $call_name 108 | * @param $call_arguments 109 | * @return array 110 | */ 111 | private function rest_request($call_name, $call_arguments) 112 | { 113 | 114 | ob_start(); 115 | $ch = curl_init(); 116 | 117 | $post_data = array( 118 | 'method' => $call_name, 119 | 'input_type' => 'JSON', 120 | 'response_type' => 'JSON', 121 | 'rest_data' => json_encode($call_arguments) 122 | ); 123 | 124 | curl_setopt($ch, CURLOPT_URL, $this->rest_url); 125 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 126 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 127 | curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); 128 | curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); 129 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 130 | $output = curl_exec($ch); 131 | 132 | $response_data = json_decode($output, true); 133 | 134 | curl_close($ch); 135 | ob_end_flush(); 136 | 137 | return $response_data; 138 | } 139 | 140 | /** 141 | * Logout 142 | */ 143 | public function logout() 144 | { 145 | $this->rest_request('logout', array( 146 | 'session' => $this->sid, 147 | )); 148 | 149 | $this->sid = null; 150 | } 151 | 152 | /** 153 | * Retrieves a list of entries 154 | * 155 | * @param string $module 156 | * @param string $query 157 | * @param string $order_by 158 | * @param integer $offset 159 | * @param array $select_fields 160 | * @param array $related_fields 161 | * @param string $max_results 162 | * @param boolean $deleted 163 | * @return bool|array 164 | */ 165 | public function getEntryList( 166 | $module, 167 | $query = '', 168 | $order_by = '', 169 | $offset = 0, 170 | $select_fields = array(), 171 | $related_fields = array(), 172 | $max_results = '0', 173 | $deleted = false 174 | ) { 175 | if (!$this->sid) { 176 | return false; 177 | } 178 | 179 | $result = $this->rest_request('get_entry_list', array( 180 | 'session' => $this->sid, 181 | 'module_name' => $module, 182 | 'query' => $query, 183 | 'order_by' => $order_by, 184 | 'offset' => $offset, 185 | 'select_fields' => $select_fields, 186 | 'link_name_to_fields_array' => $related_fields, 187 | 'max_results' => $max_results, 188 | 'deleted' => $deleted, 189 | )); 190 | 191 | if ($result['result_count'] > 0) { 192 | return $result; 193 | } 194 | 195 | return false; 196 | } 197 | 198 | /** 199 | * @param $module 200 | * @param $id 201 | * @param array $select_fields 202 | * @param array $related_fields 203 | * @return array|bool 204 | */ 205 | public function getEntry($module, $id, $select_fields = array(), $related_fields = array()) 206 | { 207 | if (!$this->sid) { 208 | return false; 209 | } 210 | 211 | $result = $this->rest_request('get_entry', array( 212 | 'session' => $this->sid, 213 | 'module_name' => $module, 214 | 'id' => $id, 215 | 'select_fields' => $select_fields, 216 | 'link_name_to_fields_array' => $related_fields, 217 | )); 218 | 219 | if (!isset($result['result_count']) || $result['result_count'] > 0) { 220 | return $result; 221 | } 222 | 223 | return false; 224 | } 225 | 226 | /** 227 | * Adds or changes an entry 228 | * 229 | * @param string $module 230 | * @param array $data 231 | * @return bool|array 232 | */ 233 | public function setEntry($module, $data) 234 | { 235 | if (!$this->sid) { 236 | return false; 237 | } 238 | 239 | return $this->rest_request('set_entry', array( 240 | 'session' => $this->sid, 241 | 'module_name' => $module, 242 | 'name_value_list' => convertArrayToNVL(str_replace("&", "%26", $data)), 243 | )); 244 | } 245 | 246 | /** 247 | * Creates a new relationship-entry 248 | * 249 | * @param string $module1 250 | * @param string $module1_id 251 | * @param string $module2 252 | * @param string $module2_id 253 | * @return bool|array 254 | */ 255 | public function setRelationship($module1, $module1_id, $module2, $module2_id) 256 | { 257 | if (!$this->sid) { 258 | return false; 259 | } 260 | 261 | $data = array( 262 | 'session' => $this->sid, 263 | 'module_name' => $module1, 264 | 'module_id' => $module1_id, 265 | 'link_field_name' => $module2, 266 | '$related_ids' => array($module2_id), 267 | ); 268 | 269 | return $this->rest_request('set_relationship', $data); 270 | } 271 | 272 | /** 273 | * Retrieves relationship data 274 | * 275 | * @param string $module_name 276 | * @param string $module_id 277 | * @param string $related_module 278 | * @param string $related_module_query 279 | * @param array $related_fields 280 | * @param array $related_module_link_name_to_fields_array 281 | * @param bool $deleted 282 | * @param string $order_by 283 | * @param int $offset 284 | * @param bool $limit 285 | * @return bool|array 286 | */ 287 | public function getRelationships( 288 | $module_name, 289 | $module_id, 290 | $related_module, 291 | $related_module_query = '', 292 | $related_fields = array(), 293 | $related_module_link_name_to_fields_array = array(), 294 | $deleted = false, 295 | $order_by = '', 296 | $offset = 0, 297 | $limit = false 298 | ) { 299 | $result = $this->rest_request('get_relationships', array( 300 | 'session' => $this->sid, 301 | 'module_name' => $module_name, 302 | 'module_id' => $module_id, 303 | 'link_field_name' => $related_module, 304 | 'related_module_query' => $related_module_query, 305 | 'related_fields' => $related_fields, 306 | 'related_module_link_name_to_fields_array' => $related_module_link_name_to_fields_array, 307 | 'deleted' => $deleted, 308 | 'order_by' => $order_by, 309 | 'offset' => $offset, 310 | 'limit' => $limit, 311 | )); 312 | 313 | if (!isset($result['error']['number']) || $result['error']['number'] == 0) { 314 | return $result; 315 | } 316 | 317 | return false; 318 | } 319 | 320 | /** 321 | * Retrieves a module field 322 | * 323 | * @param string $module 324 | * @param string $field 325 | * @return bool|array 326 | */ 327 | public function getModuleFields($module, $field) 328 | { 329 | if (!$this->sid) { 330 | return false; 331 | } 332 | 333 | $result = $this->rest_request('get_module_fields', array( 334 | 'session' => $this->sid, 335 | 'module_name' => $module, 336 | )); 337 | 338 | if ($result > 0) { 339 | return $result['module_fields'][$field]; 340 | } 341 | 342 | return false; 343 | } 344 | 345 | /** 346 | * @param $module 347 | * @return bool|array 348 | */ 349 | public function getAllModuleFields($module) 350 | { 351 | if (!$this->sid) { 352 | return false; 353 | } 354 | 355 | $result = $this->rest_request('get_module_fields', array( 356 | 'session' => $this->sid, 357 | 'module_name' => $module, 358 | )); 359 | 360 | if ($result > 0) { 361 | return $result['module_fields']; 362 | } 363 | 364 | return false; 365 | } 366 | 367 | /** 368 | * @param $note_id 369 | * @return array|bool 370 | */ 371 | public function get_note_attachment($note_id) 372 | { 373 | if (!$this->sid) { 374 | return false; 375 | } 376 | 377 | $call_arguments = array( 378 | 'session' => $this->sid, 379 | 'id' => $note_id 380 | ); 381 | 382 | return $this->rest_request('get_note_attachment', 383 | $call_arguments 384 | ); 385 | } 386 | 387 | /** 388 | * @param $note_id 389 | * @param $file_name 390 | * @param $file_location 391 | * @return array|bool 392 | */ 393 | public function set_note_attachment($note_id, $file_name, $file_location) 394 | { 395 | if (!$this->sid) { 396 | return false; 397 | } 398 | 399 | return $this->rest_request('set_note_attachment', array( 400 | 'session' => $this->sid, 401 | 'note' => array( 402 | 'id' => $note_id, 403 | 'filename' => $file_name, 404 | 'file' => base64_encode(file_get_contents($file_location)), 405 | ), 406 | )); 407 | } 408 | 409 | /** 410 | * @param $id 411 | * @return array|bool 412 | */ 413 | public function get_document_revision($id) 414 | { 415 | if (!$this->sid) { 416 | return false; 417 | } 418 | 419 | return $this->rest_request('get_document_revision', array( 420 | 'session' => $this->sid, 421 | 'id' => $id, 422 | )); 423 | } 424 | 425 | /** 426 | * @param $document_id 427 | * @param $file_name 428 | * @param $file_location 429 | * @param int $revision_number 430 | * @return array|bool 431 | */ 432 | public function set_document_revision($document_id, $file_name, $file_location, $revision_number = 1) 433 | { 434 | if (!$this->sid) { 435 | return false; 436 | } 437 | 438 | return $this->rest_request('set_document_revision', array( 439 | 'session' => $this->sid, 440 | 'document_revision' => array( 441 | 'id' => $document_id, 442 | 'revision' => $revision_number, 443 | 'filename' => $file_name, 444 | 'file' => base64_encode(file_get_contents($file_location)), 445 | ), 446 | )); 447 | 448 | 449 | } 450 | } 451 | -------------------------------------------------------------------------------- /site/controller.php: -------------------------------------------------------------------------------- 1 | id){ 24 | $msg = JText::_('COM_ADVANCEDOPENPORTAL_LOGIN_REQUIRED'); 25 | }elseif(SugarCasesConnection::isUserBlocked($user)){ 26 | $msg = JText::_('COM_ADVANCEDOPENPORTAL_PORTAL_USER_BLOCKED'); 27 | }else{ 28 | $msg = JText::_('COM_ADVANCEDOPENPORTAL_NO_PORTAL_ACCOUNT'); 29 | } 30 | if($view != 'listcases'){ 31 | JFactory::getApplication()->redirect(JURI::base(), $msg, 'error'); 32 | }else{ 33 | JFactory::getApplication()->enqueueMessage($msg, 'error'); 34 | parent::display($cachable,$url_params); 35 | } 36 | } 37 | } 38 | 39 | private function getToggletatus($status){ 40 | if(strpos($status, 'Closed') === 0){ 41 | return "Open_New"; 42 | }elseif(strpos($status, 'Open') === 0){ 43 | return "Closed_Closed"; 44 | } 45 | return null; 46 | } 47 | 48 | public function toggleCaseStatus(){ 49 | $con = SugarCasesConnection::getInstance(); 50 | require_once 'components/com_advancedopenportal/models/advancedopenportal.php'; 51 | $settings = AdvancedOpenPortalModelAdvancedOpenPortal::getSettings(); 52 | $settings->allow_case_reopen; 53 | $settings->allow_case_closing; 54 | 55 | $newStatus = $this->getToggletatus($_REQUEST['case_status']); 56 | if(($newStatus == 'Open_New' && !$settings->allow_case_reopen) || $newStatus == 'Closed_Closed' && !$settings->allow_case_closing){ 57 | JFactory::getApplication()->redirect(JURI::base()."?option=com_advancedopenportal&view=showcase&id=".$_REQUEST['case_id']); 58 | return; 59 | } 60 | $user =& JFactory::getUser(); 61 | $case = $con->getCase($_REQUEST['case_id'],$user->getParam("sugarid")); 62 | if(!$case){ 63 | JFactory::getApplication()->redirect(JURI::base()."?option=com_advancedopenportal"); 64 | return; 65 | } 66 | 67 | $con->setCaseStatus($_REQUEST['case_id'],$newStatus); 68 | JFactory::getApplication()->redirect(JURI::base()."?option=com_advancedopenportal&view=showcase&id=".$_REQUEST['case_id']); 69 | } 70 | 71 | 72 | function newcase(){ 73 | $errors = array(); 74 | $subject = JRequest::getVar("subject"); 75 | $description = JRequest::getVar("description",null, 'default', 'html',4); 76 | $type = JRequest::getVar("type"); 77 | $priority = JRequest::getVar("priority"); 78 | $file_count = JRequest::getVar("file_count"); 79 | $files = array(); 80 | for($count = 1; $count <= $file_count; $count++){ 81 | if(!array_key_exists("file".$count,$_FILES)){ 82 | continue; 83 | } 84 | $fileError = $_FILES["file".$count]['error']; 85 | if ($fileError > 0){ 86 | switch ($fileError){ 87 | case 1: 88 | case 2: 89 | $errors["file".$count] = "File too large"; 90 | break; 91 | case 3: 92 | $errors["file".$count] = "Partial upload"; 93 | break; 94 | } 95 | continue; 96 | } 97 | $files[$_FILES["file".$count]['name']] = $_FILES["file".$count]['tmp_name']; 98 | } 99 | $user = JFactory::getUser(); 100 | $contact_id = $user->getParam("sugarid"); 101 | $casesConnection = SugarCasesConnection::getInstance(); 102 | $new_case = $casesConnection->newCase($contact_id, $subject, $description, $type, $priority, $files); 103 | JFactory::getApplication()->redirect(JURI::base()."?option=com_advancedopenportal&view=showcase&id=".$new_case); 104 | } 105 | 106 | function addupdate(){ 107 | $case_id = JRequest::getVar("case_id"); 108 | $description = JRequest::getVar("update_text",null, 'default', 'html',4); 109 | if(!$case_id){ 110 | echo json_encode(array('Case Id is required')); 111 | return; 112 | } 113 | if(!$description){ 114 | echo json_encode(array('Update Text is required')); 115 | return; 116 | } 117 | $user = JFactory::getUser(); 118 | $contact_id = $user->getParam("sugarid"); 119 | $casesConnection = SugarCasesConnection::getInstance(); 120 | $case_update = $casesConnection->postUpdate($case_id,$description,$contact_id); 121 | $file_count = JRequest::getVar("file_count"); 122 | 123 | if($file_count){ 124 | $case_update->notes = array(); 125 | $files = array(); 126 | for($count = 1; $count <= $file_count; $count++){ 127 | if(!array_key_exists("file".$count,$_FILES)){ 128 | continue; 129 | } 130 | $fileError = $_FILES["file".$count]['error']; 131 | if ($fileError > 0){ 132 | switch ($fileError){ 133 | case 1: 134 | case 2: 135 | $errors["file".$count] = "File too large"; 136 | break; 137 | case 3: 138 | $errors["file".$count] = "Partial upload"; 139 | break; 140 | } 141 | continue; 142 | } 143 | $files[$_FILES["file".$count]['name']] = $_FILES["file".$count]['tmp_name']; 144 | } 145 | $response = $casesConnection->addFiles($case_id, $case_update->id, $contact_id, $files); 146 | foreach($response as $res){ 147 | $case_update->notes[] = $res; 148 | } 149 | } 150 | 151 | 152 | echo json_encode($case_update); 153 | } 154 | 155 | function create() { 156 | // Get the document object. 157 | $document =& JFactory::getDocument(); 158 | 159 | // Set the MIME type for JSON output. 160 | $document->setMimeEncoding('application/json'); 161 | //Connect to Sugar via Rest interface 162 | include_once 'components/com_advancedopenportal/sugarRestClient.php'; 163 | $restClient = new sugarRestClient(); 164 | $restClient->login(); 165 | 166 | if(isset($_REQUEST['sug']) && $_REQUEST['sug'] != ''){ 167 | 168 | $contacts = $restClient->getEntry('Contacts',$_REQUEST['sug'],array('name','email1')); 169 | if(!empty($contacts['entry_list'])){ 170 | 171 | $contact = $contacts['entry_list'][0]['name_value_list']; 172 | 173 | $pass = JUserHelper::genRandomPassword(); 174 | $pass_c = JUserHelper::getCryptedPassword($pass); 175 | 176 | $data = array(); 177 | $data['fullname'] = $contact['name']['value']; 178 | $data['email'] = $contact['email1']['value']; 179 | $data['password'] = $pass_c; 180 | $data['username'] = $contact['email1']['value']; 181 | 182 | $user = JUser::getInstance(); 183 | 184 | jimport('joomla.application.component.helper'); 185 | 186 | $config = JFactory::getConfig(); 187 | $params = JComponentHelper::getParams('com_users'); 188 | // Default to Registered. 189 | $defaultUserGroup = $params->get('new_usertype', 2); 190 | 191 | $acl = JFactory::getACL(); 192 | 193 | $user->set('id' , 0); 194 | $user->set('name' , $data['fullname']); 195 | $user->set('username' , $data['username']); 196 | $user->set('password' , $data['password']); 197 | $user->set('email' , $data['email']); // Result should contain an email (check) 198 | $user->set('usertype' , 'deprecated'); 199 | $user->set('groups' , array($defaultUserGroup)); 200 | $user->setParam('sugarid', $_REQUEST['sug']); 201 | 202 | //If autoregister is set let's register the user 203 | $autoregister = isset($options['autoregister']) ? $options['autoregister'] : $params->get('autoregister', 1); 204 | 205 | if ($autoregister) { 206 | if (!$user->save()) { 207 | echo json_encode(array("error"=>"Failed to save user ".implode(" ",$user->getErrors()))); 208 | JFactory::getApplication()->close(); 209 | return JError::raiseWarning('SOME_ERROR_CODE', $user->getError()); 210 | } 211 | } 212 | else { 213 | // No existing user and autoregister off, this is a temporary user. 214 | $user->set('tmp_user', true); 215 | } 216 | 217 | $restClient->setEntry('Contacts',array('id'=>$_REQUEST['sug'], 'joomla_account_id' => $user->id,'joomla_account_access' => $pass, )); 218 | echo json_encode(array("success"=>true)); 219 | } 220 | }else{ 221 | echo json_encode(array("error"=>"ID Not specified")); 222 | } 223 | JFactory::getApplication()->close(); 224 | } 225 | 226 | function update_e(){ 227 | //Connect to Sugar via Rest interface 228 | include_once 'components/com_advancedopenportal/sugarRestClient.php'; 229 | $restClient = new sugarRestClient(); 230 | $restClient->login(); 231 | 232 | if(isset($_REQUEST['sug']) && $_REQUEST['sug'] != ''){ 233 | 234 | $contacts = $restClient->getEntry('Contacts',$_REQUEST['sug'],array('name','email1','joomla_account_id')); 235 | 236 | if(!empty($contacts['entry_list'])){ 237 | $contact = $contacts['entry_list'][0]['name_value_list']; 238 | 239 | $userId = (int) $_REQUEST['uid']; 240 | 241 | // Check for a valid user id. 242 | if (!$userId) { 243 | $this->setError(JText::_('COM_USERS_ACTIVATION_TOKEN_NOT_FOUND')); 244 | return false; 245 | } 246 | 247 | // Load the users plugin group. 248 | JPluginHelper::importPlugin('user'); 249 | 250 | // Activate the user. 251 | $user = JFactory::getUser($userId); 252 | 253 | $user->set('name', $contact['name']['value']); 254 | $user->set('email', $contact['email1']['value']); 255 | $user->set('username', $contact['email1']['value']); 256 | 257 | $user->save(); 258 | } 259 | } 260 | 261 | } 262 | 263 | function disable_user(){ 264 | $this->setUserDisabled(1); 265 | } 266 | 267 | function enable_user(){ 268 | $this->setUserDisabled(0); 269 | } 270 | 271 | private function setUserDisabled($disable){ 272 | if(isset($_REQUEST['sug']) && $_REQUEST['sug'] != ''){ 273 | include_once 'components/com_advancedopenportal/sugarRestClient.php'; 274 | $restClient = new sugarRestClient(); 275 | $restClient->login(); 276 | $contacts = $restClient->getEntry('Contacts',$_REQUEST['sug'],array('joomla_account_id')); 277 | if(!empty($contacts['entry_list'])){ 278 | $contact = $contacts['entry_list'][0]['name_value_list']; 279 | $userId = (int) $_REQUEST['uid']; 280 | if (!$userId) { 281 | echo json_encode(array("error"=>JText::_('COM_USERS_ACTIVATION_TOKEN_NOT_FOUND'))); 282 | 283 | }else{ 284 | JPluginHelper::importPlugin('user'); 285 | $user = JFactory::getUser($userId); 286 | $user->setParam('aop_block', $disable); 287 | $user->save(); 288 | echo json_encode(array("success"=>true)); 289 | } 290 | } 291 | } 292 | JFactory::getApplication()->close(); 293 | } 294 | 295 | 296 | } 297 | -------------------------------------------------------------------------------- /site/models/SugarCasesConnection.php: -------------------------------------------------------------------------------- 1 | 23 | */ 24 | include_once 'components/com_advancedopenportal/sugarRestClient.php'; 25 | include_once 'components/com_advancedopenportal/models/SugarCase.php'; 26 | include_once 'components/com_advancedopenportal/models/SugarUpdate.php'; 27 | 28 | 29 | class SugarCasesConnection { 30 | 31 | private $case_fields = array('id','name','date_entered','date_modified','description','case_number','type','status','state','priority','contact_created_by_id', 'contact_created_by_name'); 32 | private $case_update_fields = array('id','name','date_entered','date_modified','description','contact','contact_id', 'internal', 'assigned_user_id'); 33 | private $contact_fields = array('id','first_name','last_name','date_entered','date_modified','description','portal_user_type','account_id'); 34 | private $user_fields = array('id','first_name', 'last_name', 'date_entered','date_modified','description'); 35 | private $note_fields = array('id','name', 'date_entered','date_modified','description','filename','file_url'); 36 | 37 | private static $singleton; 38 | 39 | public function __construct() { 40 | 41 | $this->restClient = new sugarRestClient(); 42 | $this->cache = & JFactory::getCache(); 43 | $this->cache->setCaching( 1 ); 44 | if(!$this->restClient->login()){ 45 | throw new Exception("Failed to connect to sugar. Please check your settings."); 46 | } 47 | } 48 | 49 | public static function getInstance(){ 50 | if(!self::$singleton){ 51 | self::$singleton = new SugarCasesConnection(); 52 | } 53 | return self::$singleton; 54 | } 55 | 56 | private function getCaseFields(){ 57 | return $this->cache->call(array($this->restClient,'getAllModuleFields'),'Cases'); 58 | } 59 | 60 | public function getTypes(){ 61 | $fields = $this->getCaseFields(); 62 | return $fields['type']; 63 | } 64 | 65 | public function getPriorities(){ 66 | $fields = $this->getCaseFields(); 67 | return $fields['priority']; 68 | } 69 | 70 | public function getStatuses(){ 71 | $fields = $this->getCaseFields(); 72 | return $fields['status']; 73 | } 74 | 75 | public function getStates(){ 76 | $fields = $this->getCaseFields(); 77 | return $fields['state']; 78 | } 79 | 80 | public function getCaseStatusDisplay($status){ 81 | $statuses = $this->getStatuses(); 82 | foreach($statuses['options'] as $option){ 83 | if($option['name'] == $status){ 84 | return $option['value']; 85 | } 86 | } 87 | return $status; 88 | } 89 | 90 | public function addFiles($caseId, $caseUpdateId, $contactId, $files){ 91 | $results = array(); 92 | //For every file, create a new note. Add an attachment and link the note to the 93 | foreach($files as $file_name => $file_location){ 94 | $note_data = array( 95 | 'name' => "Case Attachment: $file_name", 96 | 'parent_id' => $caseUpdateId, 97 | 'parent_type' => 'AOP_Case_Updates', 98 | ); 99 | $new_note = $this->restClient->setEntry('Notes',$note_data); 100 | $note_id = $new_note['id']; 101 | $this->restClient->set_note_attachment($note_id, $file_name, $file_location); 102 | $this->restClient->setRelationship("Notes",$note_id,"contact",$contactId); 103 | $results[] = array('id'=>$note_id,'file_name'=>$file_name); 104 | } 105 | return $results; 106 | } 107 | 108 | public function newCase($contact_id,$subject, $description,$type,$priority,$files){ 109 | 110 | $data = array("contact_id"=>$contact_id, 111 | "contact_created_by_id"=>$contact_id, 112 | "name" => $subject, 113 | "status" => 'New', 114 | "description" => $description, 115 | "type" => $type, 116 | "priority" => $priority, 117 | 'update_date_entered' => true, 118 | ); 119 | //TODO: Check call results 120 | //Create the actual case. 121 | $response = $this->restClient->setEntry('Cases',$data); 122 | $this->restClient->setRelationship("Cases",$response['id'],"contacts",$contact_id); 123 | //For every file, create a new note. Add an attachment and link the note to the 124 | foreach($files as $file_name => $file_location){ 125 | $note_data = array( 126 | 'name' => "Case Attachment: $file_name", 127 | ); 128 | $new_note = $this->restClient->setEntry('Notes',$note_data); 129 | $note_id = $new_note['id']; 130 | $this->restClient->set_note_attachment($note_id, $file_name, $file_location); 131 | $this->restClient->setRelationship("Notes",$note_id,"cases",$response['id']); 132 | $this->restClient->setRelationship("Notes",$note_id,"contact",$contact_id); 133 | } 134 | return $response['id']; 135 | } 136 | 137 | public function postUpdate($case_id,$update_text, $contact_id){ 138 | $data = array(); 139 | //TODO: Add validation that this user can update this case. 140 | $data['name'] = $update_text; 141 | $data['description'] = nl2br($update_text); 142 | $data['description'] = str_replace("\n", "", $data['description']); 143 | $data['contact_id'] = $contact_id; 144 | $data['case_id'] = $case_id; 145 | $response = $this->restClient->setEntry('AOP_Case_Updates',$data); 146 | return $this->getUpdate($response['id']); 147 | 148 | } 149 | 150 | public function getUpdate($update_id){ 151 | $sugarupdate = $this->restClient->getEntry("AOP_Case_Updates",$update_id,$this->case_update_fields, 152 | array( 153 | array('name'=>'contact', 154 | 'value' => 155 | $this->contact_fields 156 | ), 157 | array('name'=>'assigned_user_link', 158 | 'value' => 159 | $this->user_fields 160 | ))); 161 | //TODO: Check exists 162 | $update = new SugarUpdate($sugarupdate['entry_list'][0],$sugarupdate['relationship_list'][0]); 163 | return $update; 164 | } 165 | 166 | public function getNoteAttachment($note_id){ 167 | $attachment = $this->restClient->get_note_attachment($note_id); 168 | return $attachment['note_attachment']; 169 | } 170 | 171 | public function setCaseStatus($caseId,$newStatus){ 172 | $state = explode('_',$newStatus,2); 173 | $state = array_shift($state); 174 | $caseData = array( 175 | 'id' => $caseId, 176 | 'status' => $newStatus, 177 | 'state' => $state, 178 | ); 179 | return $this->restClient->setEntry('Cases',$caseData); 180 | } 181 | 182 | public function getCase($case_id, $contact_id) 183 | { 184 | $sugarcase = $this->restClient->getEntry("Cases", $case_id, $this->case_fields, 185 | array( 186 | array( 187 | 'name' => 'aop_case_updates', 188 | 'value' => $this->case_update_fields 189 | ), 190 | array( 191 | 'name' => 'notes', 192 | 'value' => $this->note_fields 193 | ), 194 | array( 195 | 'name' => 'accounts', 196 | 'value' => array('id') 197 | ), 198 | array( 199 | 'name' => 'contacts', 200 | 'value' => array('id') 201 | ), 202 | )); 203 | 204 | $case = new SugarCase($sugarcase['entry_list'][0], $sugarcase['relationship_list'][0]); 205 | 206 | $contact = $this->getContact($contact_id); 207 | $access = false; 208 | 209 | if ($contact->portal_user_type === 'Account' && !empty($contact->account_id)) { 210 | foreach ($case->accounts as $account) { 211 | if ($contact->account_id === $account->id) { 212 | $access = true; 213 | break; 214 | } 215 | } 216 | } else { 217 | foreach ($case->contacts as $caseContact) { 218 | if ($contact->id === $caseContact->id) { 219 | $access = true; 220 | break; 221 | } 222 | } 223 | } 224 | 225 | if (!$access) { 226 | return null; 227 | } 228 | 229 | //Grab all updates and related contacts in one go 230 | $sugarupdates = $this->restClient->getRelationships('Cases', $case_id, 'aop_case_updates', '', 231 | $this->case_update_fields, 232 | array( 233 | array( 234 | 'name' => 'contact', 235 | 'value' => $this->contact_fields 236 | ), 237 | array( 238 | 'name' => 'assigned_user_link', 239 | 'value' => $this->user_fields 240 | ), 241 | array( 242 | 'name' => 'notes', 243 | 'value' => $this->note_fields 244 | ) 245 | ) 246 | ); 247 | 248 | $newupdates = array(); 249 | foreach ($sugarupdates['entry_list'] as $index => $sugarupdate) { 250 | $update = new SugarUpdate($sugarupdate, $sugarupdates['relationship_list'][$index]); 251 | if ($update->internal) { 252 | continue; 253 | } 254 | $newupdates[] = $update; 255 | } 256 | usort($newupdates, function ($a, $b) { 257 | return strtotime($a->date_entered) - (strtotime($b->date_entered)); 258 | }); 259 | 260 | $case->aop_case_updates = $newupdates; 261 | 262 | return $case; 263 | } 264 | 265 | public function getContact($contactId){ 266 | $sugarcontact = $this->restClient->getEntry("Contacts",$contactId,$this->contact_fields); 267 | $contact = new SugarUpdate($sugarcontact['entry_list'][0],$sugarcontact['relationship_list'][0]); 268 | return $contact; 269 | } 270 | 271 | public function getCases($contact_id) 272 | { 273 | $contact = $this->getContact($contact_id); 274 | if ($contact->portal_user_type === 'Account' && !empty($contact->account_id)) { 275 | $cases = $this->restClient->getRelationships('Accounts', $contact->account_id, 'cases', '', $this->case_fields); 276 | } else { 277 | $cases = $this->restClient->getRelationships('Contacts', $contact_id, 'cases', '', $this->case_fields); 278 | } 279 | 280 | return $this->fromSugarCases($cases); 281 | } 282 | 283 | private function fromSugarCases($sugarcases){ 284 | $cases = array(); 285 | foreach($sugarcases['entry_list'] as $sugarcase){ 286 | $cases[] = new SugarCase($sugarcase, array()); 287 | } 288 | return $cases; 289 | } 290 | 291 | public static function isValidPortalUser($user){ 292 | return !empty($user->id) && $user->getParam("sugarid"); 293 | } 294 | 295 | public static function isUserBlocked($user){ 296 | return $user->getParam("aop_block"); 297 | } 298 | 299 | private function getContactData($sugarId,$user){ 300 | $data = array(); 301 | if($sugarId){ 302 | $data['id'] = $sugarId; 303 | } 304 | $name = explode(' ',$user['name'],2); 305 | 306 | $data['first_name'] = empty($name[0]) ? '' : $name[0]; 307 | $data['last_name'] = empty($name[1]) ? '' : $name[1]; 308 | $data['email'] = $user['email']; 309 | $data['email1'] = $user['email']; 310 | $data['joomla_account_id'] = $user['id']; 311 | return $data; 312 | } 313 | 314 | public function updateOrCreateContact($sugarId,$user){ 315 | $contactData = $this->getContactData($sugarId, $user); 316 | $res = $this->restClient->setEntry('Contacts',$contactData); 317 | return $res; 318 | } 319 | 320 | } 321 | -------------------------------------------------------------------------------- /site/js/jquery.form.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Form Plugin; v20130616 3 | * http://jquery.malsup.com/form/ 4 | * Copyright (c) 2013 M. Alsup; Dual licensed: MIT/GPL 5 | * https://github.com/malsup/form#copyright-and-license 6 | */ 7 | ;(function(e){"use strict";function t(t){var r=t.data;t.isDefaultPrevented()||(t.preventDefault(),e(this).ajaxSubmit(r))}function r(t){var r=t.target,a=e(r);if(!a.is("[type=submit],[type=image]")){var n=a.closest("[type=submit]");if(0===n.length)return;r=n[0]}var i=this;if(i.clk=r,"image"==r.type)if(void 0!==t.offsetX)i.clk_x=t.offsetX,i.clk_y=t.offsetY;else if("function"==typeof e.fn.offset){var o=a.offset();i.clk_x=t.pageX-o.left,i.clk_y=t.pageY-o.top}else i.clk_x=t.pageX-r.offsetLeft,i.clk_y=t.pageY-r.offsetTop;setTimeout(function(){i.clk=i.clk_x=i.clk_y=null},100)}function a(){if(e.fn.ajaxSubmit.debug){var t="[jquery.form] "+Array.prototype.join.call(arguments,"");window.console&&window.console.log?window.console.log(t):window.opera&&window.opera.postError&&window.opera.postError(t)}}var n={};n.fileapi=void 0!==e("").get(0).files,n.formdata=void 0!==window.FormData;var i=!!e.fn.prop;e.fn.attr2=function(){if(!i)return this.attr.apply(this,arguments);var e=this.prop.apply(this,arguments);return e&&e.jquery||"string"==typeof e?e:this.attr.apply(this,arguments)},e.fn.ajaxSubmit=function(t){function r(r){var a,n,i=e.param(r,t.traditional).split("&"),o=i.length,s=[];for(a=0;o>a;a++)i[a]=i[a].replace(/\+/g," "),n=i[a].split("="),s.push([decodeURIComponent(n[0]),decodeURIComponent(n[1])]);return s}function o(a){for(var n=new FormData,i=0;a.length>i;i++)n.append(a[i].name,a[i].value);if(t.extraData){var o=r(t.extraData);for(i=0;o.length>i;i++)o[i]&&n.append(o[i][0],o[i][1])}t.data=null;var s=e.extend(!0,{},e.ajaxSettings,t,{contentType:!1,processData:!1,cache:!1,type:u||"POST"});t.uploadProgress&&(s.xhr=function(){var r=e.ajaxSettings.xhr();return r.upload&&r.upload.addEventListener("progress",function(e){var r=0,a=e.loaded||e.position,n=e.total;e.lengthComputable&&(r=Math.ceil(100*(a/n))),t.uploadProgress(e,a,n,r)},!1),r}),s.data=null;var l=s.beforeSend;return s.beforeSend=function(e,t){t.data=n,l&&l.call(this,e,t)},e.ajax(s)}function s(r){function n(e){var t=null;try{e.contentWindow&&(t=e.contentWindow.document)}catch(r){a("cannot get iframe.contentWindow document: "+r)}if(t)return t;try{t=e.contentDocument?e.contentDocument:e.document}catch(r){a("cannot get iframe.contentDocument: "+r),t=e.document}return t}function o(){function t(){try{var e=n(g).readyState;a("state = "+e),e&&"uninitialized"==e.toLowerCase()&&setTimeout(t,50)}catch(r){a("Server abort: ",r," (",r.name,")"),s(D),j&&clearTimeout(j),j=void 0}}var r=f.attr2("target"),i=f.attr2("action");w.setAttribute("target",d),u||w.setAttribute("method","POST"),i!=m.url&&w.setAttribute("action",m.url),m.skipEncodingOverride||u&&!/post/i.test(u)||f.attr({encoding:"multipart/form-data",enctype:"multipart/form-data"}),m.timeout&&(j=setTimeout(function(){T=!0,s(k)},m.timeout));var o=[];try{if(m.extraData)for(var l in m.extraData)m.extraData.hasOwnProperty(l)&&(e.isPlainObject(m.extraData[l])&&m.extraData[l].hasOwnProperty("name")&&m.extraData[l].hasOwnProperty("value")?o.push(e('').val(m.extraData[l].value).appendTo(w)[0]):o.push(e('').val(m.extraData[l]).appendTo(w)[0]));m.iframeTarget||(v.appendTo("body"),g.attachEvent?g.attachEvent("onload",s):g.addEventListener("load",s,!1)),setTimeout(t,15);try{w.submit()}catch(c){var p=document.createElement("form").submit;p.apply(w)}}finally{w.setAttribute("action",i),r?w.setAttribute("target",r):f.removeAttr("target"),e(o).remove()}}function s(t){if(!x.aborted&&!F){if(M=n(g),M||(a("cannot access response document"),t=D),t===k&&x)return x.abort("timeout"),S.reject(x,"timeout"),void 0;if(t==D&&x)return x.abort("server abort"),S.reject(x,"error","server abort"),void 0;if(M&&M.location.href!=m.iframeSrc||T){g.detachEvent?g.detachEvent("onload",s):g.removeEventListener("load",s,!1);var r,i="success";try{if(T)throw"timeout";var o="xml"==m.dataType||M.XMLDocument||e.isXMLDoc(M);if(a("isXml="+o),!o&&window.opera&&(null===M.body||!M.body.innerHTML)&&--O)return a("requeing onLoad callback, DOM not available"),setTimeout(s,250),void 0;var u=M.body?M.body:M.documentElement;x.responseText=u?u.innerHTML:null,x.responseXML=M.XMLDocument?M.XMLDocument:M,o&&(m.dataType="xml"),x.getResponseHeader=function(e){var t={"content-type":m.dataType};return t[e]},u&&(x.status=Number(u.getAttribute("status"))||x.status,x.statusText=u.getAttribute("statusText")||x.statusText);var l=(m.dataType||"").toLowerCase(),c=/(json|script|text)/.test(l);if(c||m.textarea){var f=M.getElementsByTagName("textarea")[0];if(f)x.responseText=f.value,x.status=Number(f.getAttribute("status"))||x.status,x.statusText=f.getAttribute("statusText")||x.statusText;else if(c){var d=M.getElementsByTagName("pre")[0],h=M.getElementsByTagName("body")[0];d?x.responseText=d.textContent?d.textContent:d.innerText:h&&(x.responseText=h.textContent?h.textContent:h.innerText)}}else"xml"==l&&!x.responseXML&&x.responseText&&(x.responseXML=X(x.responseText));try{L=_(x,l,m)}catch(b){i="parsererror",x.error=r=b||i}}catch(b){a("error caught: ",b),i="error",x.error=r=b||i}x.aborted&&(a("upload aborted"),i=null),x.status&&(i=x.status>=200&&300>x.status||304===x.status?"success":"error"),"success"===i?(m.success&&m.success.call(m.context,L,"success",x),S.resolve(x.responseText,"success",x),p&&e.event.trigger("ajaxSuccess",[x,m])):i&&(void 0===r&&(r=x.statusText),m.error&&m.error.call(m.context,x,i,r),S.reject(x,"error",r),p&&e.event.trigger("ajaxError",[x,m,r])),p&&e.event.trigger("ajaxComplete",[x,m]),p&&!--e.active&&e.event.trigger("ajaxStop"),m.complete&&m.complete.call(m.context,x,i),F=!0,m.timeout&&clearTimeout(j),setTimeout(function(){m.iframeTarget||v.remove(),x.responseXML=null},100)}}}var l,c,m,p,d,v,g,x,b,y,T,j,w=f[0],S=e.Deferred();if(r)for(c=0;h.length>c;c++)l=e(h[c]),i?l.prop("disabled",!1):l.removeAttr("disabled");if(m=e.extend(!0,{},e.ajaxSettings,t),m.context=m.context||m,d="jqFormIO"+(new Date).getTime(),m.iframeTarget?(v=e(m.iframeTarget),y=v.attr2("name"),y?d=y:v.attr2("name",d)):(v=e('