Merge next into suite 8

This commit is contained in:
Jack Anderson 2024-01-24 09:41:06 +00:00
commit c9f078c3ff
54 changed files with 2385 additions and 2280 deletions

View file

@ -2,7 +2,7 @@
<img width="180px" height="41px" src="https://suitecrm.com/wp-content/uploads/2017/12/logo.png" align="right" />
</a>
# SuiteCRM 7.14.2
# SuiteCRM 7.14.3
[![Build Status](https://travis-ci.org/salesagility/SuiteCRM.svg?branch=hotfix)](https://travis-ci.org/salesagility/SuiteCRM)
[![codecov](https://codecov.io/gh/salesagility/SuiteCRM/branch/hotfix/graph/badge.svg)](https://codecov.io/gh/salesagility/SuiteCRM/branch/hotfix)

View file

@ -4451,7 +4451,7 @@ class SugarBean
$next_offset--;
$previous_offset++;
}
} elseif (!isset($rows_found)) {
} elseif ($rows_found == 0) {
$rows_found = $row_offset + count($list);
}

File diff suppressed because it is too large Load diff

View file

@ -1164,6 +1164,7 @@ class SearchForm
if ($type == 'datetime' || $type == 'datetimecombo') {
try {
$field_value = $timedate->to_db_date($field_value, false);
if ($operator == '=' || $operator == 'between') {
// FG - bug45287 - If User asked for a range, takes edges from it.
$placeholderPos = strpos($field_value, "<>");

View file

@ -13,5 +13,7 @@
*/
function smarty_function_diff_for_humans(array $params)
{
return \Carbon\Carbon::createFromTimeString($params['datetime'])->diffForHumans();
}
global $timedate;
return \Carbon\Carbon::createFromTimeString($timedate->to_db($params['datetime']))->diffForHumans();
}

View file

@ -10,7 +10,7 @@ r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" s
r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system
r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system
r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
@ -56,7 +56,7 @@ r14718 - 2006-07-17 17:39:10 -0700 (Mon, 17 Jul 2006) - wayne - format the curre
* Type: function<br>
* Name: sugar_currency_format<br>
* Purpose: formats a number
*
*
* @author Wayne Pan {wayne at sugarcrm.com}
* @param array
* @param Smarty
@ -66,19 +66,25 @@ function smarty_function_sugar_currency_format($params, &$smarty) {
// Bug #47406 : Currency field doesn't accept 0.00 as default value
if(!isset($params['var']) || $params['var'] === '') {
return '';
}
}
global $locale;
if(empty($params['currency_id'])){
$params['currency_id'] = $locale->getPrecedentPreference('currency');
if(!isset($params['convert'])) {
$params['convert'] = true;
}
if(!isset($params['currency_symbol'])) {
$params['currency_symbol'] = $locale->getPrecedentPreference('default_currency_symbol');
}
if ($_REQUEST['action'] === 'Popup' && $params['field_name'] !== 'amount_usdollar') {
$params['currency_id'] = getCurrencyId($_REQUEST['module'], $params['id']);
$params['currency_symbol'] = $locale->currencies[$params['currency_id']]['symbol'];
} else {
$params['currency_id'] = $locale->getPrecedentPreference('currency');
if(!isset($params['convert'])) {
$params['convert'] = true;
}
if(!isset($params['currency_symbol'])) {
$params['currency_symbol'] = $locale->getPrecedentPreference('default_currency_symbol');
}
}
}
$_contents = currency_format_number($params['var'], $params);
if (!empty($params['assign'])) {

View file

@ -46,7 +46,7 @@
{{if !empty($displayParams.accesskey)}} accesskey='{{$displayParams.accesskey}}' {{/if}} {{$displayParams.field}}
{{if isset($displayParams.javascript)}}{{$displayParams.javascript}}{{/if}}>
{if isset({{sugarvar key='value' string=true}}) && {{sugarvar key='value' string=true}} != ''}
{if isset({{sugarvar key='value' string=true}})}
{html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='value' string=true}}}
{else}
{html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='default' string=true}}}

View file

@ -51,7 +51,7 @@
accesskey='{{$displayParams.accesskey}}' {{/if}} {{$displayParams.field}}
{{if isset($displayParams.javascript)}}{{$displayParams.javascript}}{{/if}}>
{if isset({{sugarvar key='value' string=true}}) && {{sugarvar key='value' string=true}} != ''}
{if isset({{sugarvar key='value' string=true}})}
{html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='value' string=true}}}
{else}
{html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='default' string=true}}}

View file

@ -38,7 +38,7 @@
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
*/
*}
<span class="sugar_field" id="{{if empty($displayParams.idName)}}{{sugarvar key='name'}}{{else}}{{$displayParams.idName}}{{/if}}">{sugar_literal content={{sugar_varname key='value'}}}</span>
<span class="sugar_field" id="{{if empty($displayParams.idName)}}{{sugarvar key='name'}}{{else}}{{$displayParams.idName}}{{/if}}">{{$vardef.value}}</span>
{{if !empty($displayParams.enableConnectors)}}
{{sugarvar_connector view='DetailView'}}
{{/if}}
{{/if}}

View file

@ -5,7 +5,7 @@
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
*
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
* Copyright (C) 2011 - 2020 SalesAgility Ltd.
* Copyright (C) 2011 - 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
@ -37,12 +37,11 @@
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
*/
*}
<input type="hidden" id="{{if empty($displayParams.idName)}}{{sugarvar key='name'}}{{else}}{{$displayParams.idName}}{{/if}}_multiselect"
name="{{if empty($displayParams.idName)}}{{sugarvar key='name'}}{{else}}{{$displayParams.idName}}{{/if}}_multiselect" value="true">
name="{{if empty($displayParams.idName)}}{{sugarvar key='name'}}{{else}}{{$displayParams.idName}}{{/if}}_multiselect"
value="{{if !empty($displayParams.isWorkFlowCall)}}{{""}}{{else}}{{"true"}}{{/if}}">
{multienum_to_array string={{sugarvar key='value' string=true}} default={{sugarvar key='default' string=true}} assign="values"}
<select id="{{if empty($displayParams.idName)}}{{sugarvar key='name'}}{{else}}{{$displayParams.idName}}{{/if}}"
name="{{if empty($displayParams.idName)}}{{sugarvar key='name'}}{{else}}{{$displayParams.idName}}{{/if}}[]"

View file

@ -47,6 +47,10 @@ class SugarFieldMultienum extends SugarFieldEnum
if (!isset($vardef['options_list']) && isset($vardef['options']) && !is_array($vardef['options'])) {
$vardef['options_list'] = $GLOBALS['app_list_strings'][$vardef['options']];
}
if ($_REQUEST['module'] === 'AOW_WorkFlow') {
$displayParams['isWorkFlowCall'] = true;
}
return parent::setup($parentFieldArray, $vardef, $displayParams, $tabindex, $twopass);
}

View file

@ -40,7 +40,7 @@
*}
<select name='{{$vardef.type_name}}' {{if !empty($tabindex)}} tabindex="{{$tabindex}}" {{/if}} id='{{$vardef.type_name}}' title='{{$vardef.help}}'
onchange='document.{{$form_name}}.{{sugarvar key='name'}}.value="";document.{{$form_name}}.parent_id.value="";
onchange='document.{{$form_name}}.{{sugarvar key='name'}}.value="";document.{{$form_name}}.parent_id.value="";
changeParentQSSearchView("{{sugarvar key='name'}}"); checkParentType(document.{{$form_name}}.{{$vardef.type_name}}.value, document.{{$form_name}}.btn_{{sugarvar key='name'}});'>
{html_options options={{sugarvar key='options' string=true}} selected=$fields.{{$vardef.type_name}}.value}
</select>
@ -66,6 +66,7 @@ onchange='document.{{$form_name}}.{{sugarvar key='name'}}.value="";document.{{$f
if (typeof(changeParentQSSearchView) == 'undefined'){
function changeParentQSSearchView(field) {
field = YAHOO.util.Dom.get(field);
var sqs_objects = {};
var form = field.form;
var sqsId = form.id + "_" + field.id;
var typeField = form.elements["{{$vardef.type_name}}"];

View file

@ -172,12 +172,9 @@ class TemplateHandler
$contents = $this->ss->fetch($tpl);
// Insert validation and quick search stuff here
if ($view === 'EditView' || $ajaxSave || $view === 'ConvertLead' || $view === 'ComposeView' || strpos($view, 'QuickCreate')) {
global $dictionary, $beanList, $app_strings, $mod_strings;
$mod = $beanList[$module];
global $dictionary, $app_strings, $mod_strings;
if ($mod === 'aCase') {
$mod = 'Case';
}
$mod = BeanFactory::getObjectName($module);
$defs = isset($dictionary[$mod]['fields']) ? $dictionary[$mod]['fields'] : [];
$defs2 = array();

View file

@ -6341,3 +6341,15 @@ function isSelfRequest($endpoint) : bool {
return stripos((string) $endpoint, (string) $domain) !== false || stripos((string) $endpoint, (string) $siteUrl) !== false;
}
/**
* Get currency ID directly from the record, if property is empty -> use default currency ID
* @param $module
* @param $id
* @return string
*/
function getCurrencyId($module, $id)
{
global $locale;
return BeanFactory::getBean($module, $id)->currency_id ?? $locale->getPrecedentPreference('currency');
}

View file

@ -382,7 +382,7 @@ class ElasticSearchIndexer extends AbstractIndexer
return null;
}
return $results[$lowercaseModule]['mappings']['_meta'];
return $results[$lowercaseModule]['mappings']['_meta'] ?? array();
}
/**

View file

@ -70,9 +70,7 @@ trait IndexingSchedulerTrait
$indexer = new self();
$indexer->getLogger()->debug('Starting scheduled job');
$indexer->setDifferentialIndexing(
isset($options['partial']) ? $options['partial'] : true
);
$indexer->setDifferentialIndexing($options['partial'] ?? true);
try {
$indexer->index();

View file

@ -44,6 +44,7 @@ if (!defined('sugarEntry') || !sugarEntry) {
}
use Elasticsearch\Common\Exceptions\NoNodesAvailableException;
use Elasticsearch\Common\Exceptions\Missing404Exception;
use Exception;
use SuiteCRM\Search\Exceptions\SearchEngineNotFoundException;
use SuiteCRM\Search\Exceptions\SearchException;
@ -131,6 +132,9 @@ class SearchThrowableHandler
case SearchException::class:
$message = $mod_strings['LBL_ELASTIC_SEARCH_EXCEPTION_SEARCH'];
break;
case Missing404Exception::class:
$message = $mod_strings['LBL_ELASTIC_SEARCH_EXCEPTION_MISSING_INDEX'];
break;
default:
$message = $mod_strings['LBL_ELASTIC_SEARCH_EXCEPTION_DEFAULT'];
}

View file

@ -5,7 +5,7 @@
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
*
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
* Copyright (C) 2011 - 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
@ -50,9 +50,7 @@ function getAOPAssignField($assignField, $value)
$roles = get_bean_select_array(true, 'ACLRole', 'name', '', 'name', true);
$securityGroups = get_bean_select_array(true, 'SecurityGroup', 'name', '', 'name', true);
$field = '';
$field .= "<select type='text' name='$assignField" . '[0]' . "' id='$assignField" . '[0]' . "' onchange='assign_field_change(\"$assignField\")' title='' tabindex='116'>" . get_select_options_with_id($app_list_strings['aow_assign_options'], isset($value[0]) ? $value[0] : null) . '</select>&nbsp;&nbsp;';
$field = "<select type='text' name='$assignField" . '[0]' . "' id='$assignField" . '[0]' . "' onchange='assign_field_change(\"$assignField\")' title='' tabindex='116'>" . get_select_options_with_id($app_list_strings['aow_assign_options'], $value[0] ?? null) . '</select>&nbsp;&nbsp;';
if (!file_exists('modules/SecurityGroups/SecurityGroup.php')) {
$field .= "<input type='hidden' name='$assignField" . '[1]' . "' id='$assignField" . '[1]' . "' value='' />";
} else {
@ -60,13 +58,13 @@ function getAOPAssignField($assignField, $value)
if (isset($value[0]) && $value[0] === 'security_group') {
$display = '';
}
$field .= "<select type='text' style='display:$display' name='$assignField" . '[1]' . "' id='$assignField" . '[1]' . "' title='' tabindex='116'>" . get_select_options_with_id($securityGroups, isset($value[1]) ? $value[1] : null) . '</select>&nbsp;&nbsp;';
$field .= "<select type='text' style='display:$display' name='$assignField" . '[1]' . "' id='$assignField" . '[1]' . "' title='' tabindex='116'>" . get_select_options_with_id($securityGroups, $value[0][1] ?? null) . '</select>&nbsp;&nbsp;';
}
$display = 'none';
if (isset($value[0]) && ($value[0] === 'role' || $value[0] === 'security_group')) {
$display = '';
}
$field .= "<select type='text' style='display:$display' name='$assignField" . '[2]' . "' id='$assignField" . '[2]' . "' title='' tabindex='116'>" . get_select_options_with_id($roles, isset($value[2]) ? $value[2] : null) . '</select>&nbsp;&nbsp;';
$field .= "<select type='text' style='display:$display' name='$assignField" . '[2]' . "' id='$assignField" . '[2]' . "' title='' tabindex='116'>" . get_select_options_with_id($roles, $value[0][2] ?? null) . '</select>&nbsp;&nbsp;';
return $field;
}

View file

@ -97,8 +97,8 @@ $dictionary['AOW_Processed'] = array(
array(
'name'=> 'parent_name',
'parent_type'=>'record_type_display' ,
'type_name'=>'bean_module',
'id_name'=>'bean_id',
'type_name'=>'parent_type',
'id_name'=>'parent_id',
'vname'=>'LBL_BEAN',
'type'=>'parent',
'group'=>'parent_name',

View file

@ -5,7 +5,7 @@
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
*
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
* Copyright (C) 2011 - 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
@ -68,6 +68,7 @@ class AOW_WorkFlow extends Basic
public $run_when;
public $flow_run_on;
public $multiple_runs;
public static $doNotRunInSaveLogic = false;
/**
* return an SQL operator
@ -205,6 +206,7 @@ class AOW_WorkFlow extends Basic
*/
public function run_flow()
{
AOW_WorkFlow::$doNotRunInSaveLogic = true;
$beans = $this->get_flow_beans();
if (!empty($beans)) {
foreach ($beans as $bean) {
@ -212,6 +214,7 @@ class AOW_WorkFlow extends Basic
$this->run_actions($bean);
}
}
AOW_WorkFlow::$doNotRunInSaveLogic = false;
}
/**
@ -219,6 +222,10 @@ class AOW_WorkFlow extends Basic
*/
public function run_bean_flows(SugarBean $bean)
{
if (AOW_WorkFlow::$doNotRunInSaveLogic) {
return;
}
$query = "SELECT id FROM aow_workflow WHERE aow_workflow.flow_module = '" . $bean->module_dir . "' AND aow_workflow.status = 'Active' AND (aow_workflow.run_when = 'Always' OR aow_workflow.run_when = 'On_Save' OR aow_workflow.run_when = 'Create') AND aow_workflow.deleted = 0 ";
$result = $this->db->query($query, false);
@ -880,6 +887,18 @@ class AOW_WorkFlow extends Basic
$value = strtotime($value);
} elseif ($data['type'] == 'bool' && (!(bool)$value || strtolower($value) == 'false')) {
$value = 0;
} elseif($data['type'] == 'multienum') {
$value = unencodeMultienum($value);
$field = unencodeMultienum($field);
switch ($condition->operator) {
case 'Not_Equal_To':
$condition->operator = 'Not_One_of';
break;
case 'Equal_To':
default:
$condition->operator = 'One_of';
break;
}
}
$type = $data['dbType'] ?? $data['type'];
if ((strpos((string) $type, 'char') !== false || strpos((string) $type, 'text') !== false) && !empty($field)) {

View file

@ -158,7 +158,8 @@ $closureEmailTemplateDropdown =
$joomlaEmailTemplateDropdown =
get_select_options_with_id($emailTemplateList, $cfg->config['aop']['joomla_account_creation_email_template_id']);
$inboundEmailCaseMacro = $cfg->config['inbound_email_case_subject_macro'] ?? '';
$case = BeanFactory::newBean('Cases');
$inboundEmailCaseMacro = $cfg->config['inbound_email_case_subject_macro'] ?? $case->getEmailSubjectMacro();
$sugar_smarty->assign('inbound_email_case_macro', $inboundEmailCaseMacro);
$sugar_smarty->assign('USER_EMAIL_TEMPLATES', $userEmailTemplateDropdown);
@ -374,7 +375,7 @@ function getStatusRowTemplate($mod_strings, $ifDropdown, $thenDropdown)
<td width="100">
<select id='then_status_select[]' name='then_status[]'>{$thenDropdown}</select>
</td>
<td><button class="removeStatusButton" type="button">{$mod_strings['LBL_AOP_REMOVE_STATUS']}</button></td>
<td><button class="removeStatusButton button" type="button">{$mod_strings['LBL_AOP_REMOVE_STATUS']}</button></td>
</tr>
EOF;

View file

@ -187,7 +187,7 @@
<th align="left" scope="row" colspan="6"><h4>{$MOD.LBL_AOP_CASE_STATUS_SETTINGS}</h4></th>
</tr>
{$currentStatuses}
<tr><td><button type='button' id="addStatusButton">{$MOD.LBL_AOP_ADD_STATUS}</button></td></tr>
<tr><td><button class="button" type='button' id="addStatusButton">{$MOD.LBL_AOP_ADD_STATUS}</button></td></tr>
</table>
<table id='email_settings' width="100%" border="0" cellspacing="1" cellpadding="0" class="edit view">
<tr>
@ -211,7 +211,6 @@
<input type="text" name="inbound_email_case_macro" id="inbound_email_case_macro" value="{$inbound_email_case_macro}">
<span>
{$MOD.LBL_CASE_MACRO_DESC}
<br />
<i>{$MOD.LBL_CASE_MACRO_DESC2}</i>
</span>
</td>

View file

@ -96,7 +96,6 @@ if (is_admin($current_user)) {
$class_names[] = $GLOBALS['beanList'][$module];
}
$repairClass->module_list[] = $module;
foreach ($views as $view) {
try {
$parser = ParserFactory::getParser($view, $module);

View file

@ -186,6 +186,11 @@ class Controller extends AbstractController
/** @var Scheduler[]|null $schedulers */
$schedulers = BeanFactory::getBean('Schedulers')->get_full_list(null, $where);
foreach ($schedulers as &$scheduler) {
$scheduler->check_date_relationships_load();
}
unset($scheduler);
return $schedulers;
}

View file

@ -72,8 +72,13 @@ $("#es-test-connection").click(function () {
$("#es-full-index").click(function () {
var url = "index.php?module=Administration&action=ElasticSearchSettings&do=FullIndex";
$.ajax(url).done(function () {
alert(SUGAR.language.get("Administration", "LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_FULL_SUCCESS"));
$.ajax(url).done(function (data) {
if (data.status === "success") {
alert(SUGAR.language.get("Administration", "LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_FULL_SUCCESS"));
}
else {
alert(SUGAR.language.get("Administration", "LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_FULL_FAIL_NO_SUCCESS"));
}
}).error(function () {
alert(SUGAR.language.get("Administration", "LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_FULL_FAIL"));
});
@ -82,8 +87,13 @@ $("#es-full-index").click(function () {
$("#es-partial-index").click(function () {
var url = "index.php?module=Administration&action=ElasticSearchSettings&do=PartialIndex";
$.ajax(url).done(function () {
alert(SUGAR.language.get("Administration", "LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_PART_SUCCESS"));
$.ajax(url).done(function (data) {
if (data.status === "success") {
alert(SUGAR.language.get("Administration", "LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_PART_SUCCESS"));
}
else {
alert(SUGAR.language.get("Administration", "LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_PART_FAIL_NO_SUCCESS"));
}
}).error(function () {
alert(SUGAR.language.get("Administration", "LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_PART_FAIL"));
});

View file

@ -147,5 +147,4 @@
{$JAVASCRIPT}
</form>
<script src="modules/Administration/Search/ElasticSearch/scripts.js"></script>
<script src="modules/Administration/Search/ajaxSubmit.js"></script>
<script src="modules/Administration/Search/ElasticSearch/scripts.js"></script>

View file

@ -77,11 +77,19 @@ class AdministrationController extends SugarController
public function action_savelanguages()
{
global $sugar_config, $current_language;
global $sugar_config, $current_language, $mod_strings;
$toDecode = html_entity_decode((string) $_REQUEST['disabled_langs'], ENT_QUOTES);
$disabled_langs = json_decode($toDecode);
$toDecode = html_entity_decode((string) $_REQUEST['enabled_langs'], ENT_QUOTES);
$enabled_langs = json_decode($toDecode);
if (in_array($current_language, $disabled_langs)){
$GLOBALS['log']->fatal($mod_strings['LBL_CANNOT_DISABLE_CURRENT_LANGUAGE']);
displayAdminError(translate('LBL_CANNOT_DISABLE_CURRENT_LANGUAGE', 'Administration'));
SugarApplication::redirect('index.php?module=Administration&action=Languages');
return;
}
$cfg = new Configurator();
$cfg->config['disabled_languages'] = implode(',', $disabled_langs);
// TODO: find way to enforce order

View file

@ -627,8 +627,8 @@ $mod_strings = array(
'LBL_QUICK_REPAIR_TITLE' => 'Please select Module(s) to repair:',
'LBL_QUICK_REPAIR_AND_REBUILD_DESC' => 'Repairs and rebuilds DB, Extensions, Vardefs, SuiteCRM Dashlets etc.',
'LBL_ALL_MODULES' => 'All Modules',
'LBL_REPAIR_ELASTICSEARCH_INDEX' => 'Repair ElasticSearch Index',
'LBL_REPAIR_ELASTICSEARCH_INDEX_DONE' => 'ElasticSearch Indexing has been repaired',
'LBL_REPAIR_ELASTICSEARCH_INDEX' => 'Repair Elasticsearch Index',
'LBL_REPAIR_ELASTICSEARCH_INDEX_DONE' => 'Elasticsearch Indexing has been repaired',
'LBL_CAMPAIGN_CONFIG_TITLE' => 'Campaign Email Settings',
'LBL_CAMPAIGN_CONFIG_DESC' => 'Configure email settings for campaigns',
'LBL_REPAIR_ORACLE_FULLTEXT' => 'Rebuild fulltext indices',
@ -785,6 +785,8 @@ $mod_strings = array(
'LBL_SPRITES_ADDED' => 'Added sprite {0}',
'LBL_SPRITES_EXCLUDING_FILE' => 'Excluding file: {0}',
'LBL_CANNOT_DISABLE_CURRENT_LANGUAGE' => 'The language being actively used cannot be disabled. Please change to another language in order to disable it.',
//FTS
'LBL_DELETE_FTS_DATA' => 'Delete existing data when index is performed. Only data in the selected modules will be indexed.',
'LBL_SAVE_SCHED_BUTTON' => 'Save and Schedule System Index',
@ -950,26 +952,28 @@ $mod_strings = array(
'LBL_ELASTIC_SEARCH_TEST_CONNECTION' => 'Test connection',
'LBL_ELASTIC_SEARCH_TEST_CONNECTION_SUCCESS' => 'Connection successful.',
'LBL_ELASTIC_SEARCH_TEST_CONNECTION_FAIL' => 'Connection failed.',
'LBL_SETUP_ELASTICSEARCH' => 'Please enable ElasticSearch before repairing Indexes',
'LBL_SETUP_ELASTICSEARCH' => 'Please enable Elasticsearch before repairing Indexes',
'LBL_ELASTIC_SEARCH_TEST_CONNECTION_ERROR' => 'Failed perform ping request.',
'LBL_ELASTIC_SEARCH_SERVER' => 'Server',
'LBL_ELASTIC_SEARCH_HOST' => 'Host',
'LBL_ELASTIC_SEARCH_USER' => 'Username',
'LBL_ELASTIC_SEARCH_PASS' => 'Password',
'LBL_ELASTIC_SEARCH_SCHEDULERS' => 'Schedulers',
'LBL_ELASTIC_SEARCH_SCHEDULERS_HELP' => 'The following ElasticSearch schedulers were detected:',
'LBL_ELASTIC_SEARCH_SCHEDULERS_HELP' => 'The following Elasticsearch schedulers were detected:',
'LBL_ELASTIC_SEARCH_SCHEDULERS_LAST_RUN' => 'last run:',
'LBL_ELASTIC_SEARCH_SCHEDULERS_NEVER_RUN' => 'This job has never run',
'LBL_ELASTIC_SEARCH_SCHEDULERS_NOT_FOUND' => 'No schedulers found. Consider creating one.',
'LBL_ELASTIC_SEARCH_SCHEDULERS_DESC' => 'The ElasticSearch module uses schedulers to keep the database and the indexing engine synchronised.',
'LBL_ELASTIC_SEARCH_SCHEDULERS_DESC' => 'The Elasticsearch module uses schedulers to keep the database and the indexing engine synchronised.',
'LBL_ELASTIC_SEARCH_INDEX' => 'Index',
'LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_HELP' => 'Schedule an indexing',
'LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_FULL' => 'Schedule full indexing',
'LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_PART' => 'Schedule partial indexing',
'LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_FULL_SUCCESS' => 'A full indexing has been scheduled and will start in the next 60 seconds. Search results might be inconsistent until the process is complete.',
'LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_FULL_FAIL' => 'Failed to start full index.',
'LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_FULL_FAIL_NO_SUCCESS' => 'Full indexing was not scheduled. Are you still logged in?',
'LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_PART_SUCCESS' => 'A partial indexing has been scheduled and will start in the next 60 seconds.',
'LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_PART_FAIL' => 'Failed to start partial index.',
'LBL_ELASTIC_SEARCH_INDEX_SCHEDULE_PART_FAIL_NO_SUCCESS' => 'Partial indexing was not scheduled. Are you still logged in?',
// SearchWrapper Settings
'LBL_SEARCH_INTERFACE' => 'Search Interface',

View file

@ -131,6 +131,7 @@ class TemplateHTML extends TemplateField
$def['display'] = 'readonly';
$def['readonly'] = true;
$def['dbType'] = isset($this->ext3) ? $this->ext3 : 'text' ;
$def['resetFieldInStudio'] = 'true';
return array_merge($def, $this->get_additional_defs());
}
}

View file

@ -49,7 +49,7 @@ class TemplateParent extends TemplateEnum
{
public $max_size = 25;
public $type='parent';
public function get_field_def()
{
$def = parent::get_field_def();
@ -58,9 +58,10 @@ class TemplateParent extends TemplateEnum
$def['parent_type'] = 'record_type_display';
$def['source'] = 'non-db';
$def['studio'] = 'visible';
$def['resetFieldInStudio'] = 'true';
return $def;
}
public function delete($df)
{
parent::delete($df);
@ -68,19 +69,19 @@ class TemplateParent extends TemplateEnum
$parent_type = new TemplateText();
$parent_type->name = 'parent_type';
$parent_type->delete($df);
$parent_id = new TemplateId();
$parent_id->name = 'parent_id';
$parent_id->delete($df);
}
public function save($df)
{
$this->ext1 = 'parent_type_display';
$this->name = 'parent_name';
$this->default_value = '';
parent::save($df); // always save because we may have updates
//save parent_type
$parent_type = new TemplateParentType();
$parent_type->name = 'parent_type';
@ -89,7 +90,7 @@ class TemplateParent extends TemplateEnum
$parent_type->len = 255;
$parent_type->importable = $this->importable;
$parent_type->save($df);
//save parent_name
$parent_id = new TemplateId();
$parent_id->name = 'parent_id';
@ -99,7 +100,7 @@ class TemplateParent extends TemplateEnum
$parent_id->importable = $this->importable;
$parent_id->save($df);
}
public function get_db_add_alter_table($table)
{
return '';

View file

@ -218,6 +218,7 @@ class TemplateRelatedTextField extends TemplateText
$def['quicksearch'] = 'enabled';
$def['studio'] = 'visible';
$def['source'] = 'non-db';
$def['resetFieldInStudio'] = 'true';
return $def;
}

View file

@ -47,12 +47,12 @@ class ExternalOAuthConnectionController extends SugarController
public function action_EditView() {
$this->view = 'edit';
if (empty($_REQUEST['type'])){
$_REQUEST['type'] = 'personal';
if (isset($this->bean->type)){
$_REQUEST['type'] = $this->bean->type;
}
if (!empty($this->bean)) {
$this->bean->type = $_REQUEST['type'];
if (empty($_REQUEST['type'])){
$_REQUEST['type'] = 'personal';
}
if (empty($_REQUEST['record']) && $_REQUEST['type'] === 'personal') {

View file

@ -47,11 +47,14 @@ class ExternalOAuthProviderController extends SugarController
public function action_EditView() {
$this->view = 'edit';
if (isset($this->bean->type)){
$_REQUEST['type'] = $this->bean->type;
}
if (empty($_REQUEST['type'])){
$_REQUEST['type'] = 'personal';
}
if (!empty($this->bean)) {
$this->bean->type = $_REQUEST['type'];
}

View file

@ -247,6 +247,7 @@ $mod_strings = array(
'LBL_ELASTIC_SEARCH_EXCEPTION_SEARCH' => 'An error internal to the Search has occurred.',
'LBL_ELASTIC_SEARCH_EXCEPTION_DEFAULT' => 'An unknown error has occurred while performing the search.',
'LBL_ELASTIC_SEARCH_EXCEPTION_END_MESSAGE' => 'Contact an administrator if the problem persists. More information available in the logs.',
'LBL_ELASTIC_SEARCH_EXCEPTION_MISSING_INDEX' => 'The search index for one or more modules could not be found. Please make sure that crontab is configured and running, open the Elasticsearch configuration and click "Schedule full indexing" and consider creating a Scheduler job "Elasticsearch Indexer" when not existent.',
'LBL_ELASTIC_SEARCH_DEFAULT' => 'No results matching your search criteria. Try broadening your search.',

View file

@ -1,4 +1,4 @@
<?php
<?php
/**
*
* SugarCRM Community Edition is a customer relationship management program developed by
@ -172,7 +172,19 @@ $viewdefs ['InboundEmail'] = [
],
'lbl_outbound_configuration' => [
[
'outbound_email_name',
[
'name' => 'outbound_email_name',
'displayParams' => [
'field_to_name_array'=> [
'name' => 'outbound_email_name',
'id' => 'outbound_email_id',
'smtp_from_name' => 'from_name',
'reply_to_name' => 'reply_to_name',
'smtp_from_addr' => 'from_addr',
'reply_to_addr' => 'reply_to_addr',
]
]
],
'account_signature_id'
],
[

View file

@ -50,10 +50,10 @@
<li>
<input type="checkbox" name="{$action.name}" value="{$action.name}" checked="checked" />
{$action.label}
</li>
</li>
{/foreach}
</ul>
</form>
<button id="execute_repair" onclick="this.disabled = true;
<button class="button primary" id="execute_repair" onclick="this.disabled = true;
ajaxStatus.showStatus(SUGAR.language.get('ModuleBuilder', 'LBL_AJAX_LOADING'));
ModuleBuilder.submitForm('remove_custom')">{sugar_translate label="LBL_RESET"}</button>

View file

@ -49,13 +49,19 @@ require_once 'modules/ModuleBuilder/parsers/views/DeployedMetaDataImplementation
#[\AllowDynamicProperties]
class ViewResetmodule extends SugarView
{
public static array $exceptionFields = [
'jjwg_maps_geocode_status_c',
'jjwg_maps_address_c',
'jjwg_maps_lng_c',
'jjwg_maps_lat_c'
];
/**
* @see SugarView::_getModuleTitleParams()
*/
protected function _getModuleTitleParams($browserTitle = false)
{
global $mod_strings;
return array(
translate('LBL_MODULE_NAME', 'Administration'),
ModuleBuilderController::getModuleTitle(),
@ -68,12 +74,12 @@ class ViewResetmodule extends SugarView
if (isset($_REQUEST['handle']) && $_REQUEST['handle'] == "execute") {
return $this->handleSave();
}
$ajax = new AjaxCompose() ;
$ajax->addCrumb(translate('LBL_STUDIO'), 'ModuleBuilder.main("studio")') ;
$ajax->addCrumb(translate($moduleName), 'ModuleBuilder.getContent("module=ModuleBuilder&action=wizard&view_module=' . $moduleName . '")') ;
$ajax->addCrumb(translate('LBL_RESET') . " " . translate($moduleName), '') ;
$smarty = new Sugar_Smarty() ;
$smarty->assign("module", $moduleName);
$smarty->assign("actions", array(
@ -83,59 +89,59 @@ class ViewResetmodule extends SugarView
array("name" => "labels", "label" => translate("LBL_RESET_LABELS")),
array("name" => "extensions", "label" => translate("LBL_CLEAR_EXTENSIONS")),
));
$ajax->addSection(
'center',
"Reset ". translate($moduleName),
$smarty->fetch('modules/ModuleBuilder/tpls/resetModule.tpl') //"This works now"
) ;
echo $ajax->getJavascript() ;
}
public function handleSave()
{
$out = "<script>ajaxStatus.flashStatus(SUGAR.language.get('app_strings', 'LBL_REQUEST_PROCESSED'), 2000);</script>";
if (!empty($_REQUEST['relationships'])) {
$out .= $this->removeCustomRelationships();
}
if (!empty($_REQUEST['fields'])) {
$out .= $this->removeCustomFields();
}
if (!empty($_REQUEST['layouts'])) {
$out .= $this->removeCustomLayouts();
}
if (!empty($_REQUEST['labels'])) {
$out .= $this->removeCustomLabels();
}
if (!empty($_REQUEST['extensions'])) {
$out .= $this->removeCustomExtensions();
}
$out .= "Complete!";
$ajax = new AjaxCompose() ;
$ajax->addCrumb(translate('LBL_STUDIO'), 'ModuleBuilder.main("studio")') ;
$ajax->addCrumb(translate($this->module), 'ModuleBuilder.getContent("module=ModuleBuilder&action=wizard&view_module=' . $this->module . '")') ;
$ajax->addCrumb("Reset ". translate($this->module), '') ;
$ajax->addSection(
'center',
"Reset ". translate($this->module),
$out
) ;
echo $ajax->getJavascript() ;
}
/**
* Removes all custom fields created in studio
*
@ -149,15 +155,17 @@ class ViewResetmodule extends SugarView
$seed = new $class_name() ;
$df = new DynamicField($moduleName) ;
$df->setup($seed) ;
$module = StudioModuleFactory::getStudioModule($moduleName) ;
$customFields = array();
foreach ($seed->field_defs as $def) {
if (isset($def['source']) && $def['source'] == 'custom_fields') {
if (isset($def['source']) && $def['source'] == 'custom_fields'
&& (!in_array($def['name'], ViewResetmodule::$exceptionFields))
|| (isTrue($def['resetFieldInStudio'] ?? false))) {
$field = $df->getFieldWidget($moduleName, $def['name']);
$field->delete($df) ;
$module->removeFieldFromLayouts($def['name']);
$customFields[] = $def['name'];
}
@ -168,7 +176,7 @@ class ViewResetmodule extends SugarView
}
return ($out);
}
/**
* Removes the metadata files for all known studio layouts.
*
@ -188,14 +196,14 @@ class ViewResetmodule extends SugarView
$out .= "Removed layout {$view['type']}.php<br/>";
}
}
// now clear the cache
include_once('include/TemplateHandler/TemplateHandler.php') ;
TemplateHandler::clearCache($this->module) ;
return $out;
}
/**
* Removes all custom relationships containing this module
*
@ -207,7 +215,7 @@ class ViewResetmodule extends SugarView
$out = "";
$madeChanges = false;
$relationships = new DeployedRelationships($this->module) ;
foreach ($relationships->getRelationshipList() as $relationshipName) {
$rel = $relationships->get($relationshipName)->getDefinition() ;
if ($rel [ 'is_custom' ] || (isset($rel [ 'from_studio' ]) && $rel [ 'from_studio' ])) {
@ -218,10 +226,10 @@ class ViewResetmodule extends SugarView
if ($madeChanges) {
$relationships->save() ;
}
return $out;
}
public function removeCustomLabels()
{
$out = "";
@ -234,15 +242,15 @@ class ViewResetmodule extends SugarView
}
$language = substr((string) $langFile, 0, strlen((string) $langFile) - 9);
unlink($languageDir . "/" . $langFile);
LanguageManager::clearLanguageCache($this->module, $language) ;
$out .= "Removed language file $langFile<br/>";
}
}
return $out;
}
public function removeCustomExtensions()
{
$out = "";
@ -255,7 +263,7 @@ class ViewResetmodule extends SugarView
$rac->rebuildExtensions();
$out .= "Cleared extensions for {$this->module}<br/>";
}
return $out;
}
}

View file

@ -266,6 +266,7 @@ class ProjectTaskViewList extends ViewList
$lv->searchColumns = $searchForm->searchColumns;
if (empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false) {
$lv->ss->assign('savedSearchData', $searchForm->getSavedSearchData());
//Bug 58841 - mass update form was not displayed for non-admin users that should have access
if (ACLController::checkAccess($module, 'massupdate') || ACLController::checkAccess($module, 'export')) {
$lv->setup($seed, 'include/ListView/ListViewGeneric.tpl', $where, $params);

View file

@ -1,14 +1,12 @@
<?php
if (!defined('sugarEntry') || !sugarEntry) {
die('Not A Valid Entry Point');
}
/**
*
* SugarCRM Community Edition is a customer relationship management program developed by
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
*
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
* Copyright (C) 2011 - 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
@ -41,11 +39,9 @@ if (!defined('sugarEntry') || !sugarEntry) {
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
*/
if (!defined('sugarEntry') || !sugarEntry) {
die('Not A Valid Entry Point');
}
$focus = BeanFactory::newBean('ProspectLists');
@ -59,4 +55,5 @@ if (!$focus->ACLAccess('Delete')) {
}
$focus->mark_deleted($_REQUEST['record']);
header("Location: index.php?module=".$_REQUEST['return_module']."&action=".$_REQUEST['return_action']."&record=".$_REQUEST['return_id']);
require_once('include/formbase.php');
handleRedirect($_REQUEST['return_id'], $_REQUEST['return_module']);

View file

@ -964,6 +964,18 @@ class Scheduler extends SugarBean
$sched16->modified_user_id = '1';
$sched16->catch_up = '0';
$sched16->save();
$sched17 = new Scheduler;
$sched17->name = $mod_strings['LBL_OOTB_ELASTIC_INDEX'];
$sched17->job = 'function::runElasticSearchIndexerScheduler';
$sched17->date_time_start = create_date(2015, 1, 1) . ' ' . create_time(0, 0, 1);
$sched17->date_time_end = null;
$sched17->job_interval = '30::4::*::*::*';
$sched17->status = 'Active';
$sched17->created_by = '1';
$sched17->modified_user_id = '1';
$sched17->catch_up = '0';
$sched17->save();
}
//// END SCHEDULER HELPER FUNCTIONS

View file

@ -833,9 +833,9 @@ EOF;
}
}
function runElasticSearchIndexerScheduler($data)
function runElasticSearchIndexerScheduler($job, $data = '{}')
{
return \SuiteCRM\Search\ElasticSearch\ElasticSearchIndexer::schedulerJob(json_decode((string) $data));
return \SuiteCRM\Search\ElasticSearch\ElasticSearchIndexer::schedulerJob(json_decode(html_entity_decode($data), true));
}
if (file_exists('custom/modules/Schedulers/_AddJobsHere.php')) {

View file

@ -56,6 +56,7 @@ $mod_strings = array(
'LBL_OOTB_CLEANUP_QUEUE' => 'Clean Jobs Queue',
'LBL_OOTB_REMOVE_DOCUMENTS_FROM_FS' => 'Removal of documents from filesystem',
'LBL_OOTB_GOOGLE_CAL_SYNC' => 'Google Calendar Sync',
'LBL_OOTB_ELASTIC_INDEX' => 'Perform Elasticsearch Index',
// List Labels
'LBL_LIST_JOB_INTERVAL' => 'Interval:',

View file

@ -180,87 +180,92 @@ EOQ;
$mass_assign = <<<EOQ
<script type="text/javascript" language="javascript">
function confirm_massassign(del,start_string, end_string) {
if (del == 1) {
return confirm( start_string + sugarListView.get_num_selected_string() + end_string);
}
else {
return confirm( start_string + sugarListView.get_num_selected_string() + end_string);
}
function confirm_massassign(del, start_string, end_string) {
if (del == 1) {
return confirm(start_string + sugarListView.get_num_selected_string() + end_string);
} else {
return confirm(start_string + sugarListView.get_num_selected_string() + end_string);
}
}
function send_massassign(mode, no_record_txt, start_string, end_string, del) {
if(!sugarListView.confirm_action(del, start_string, end_string))
return false;
if (!sugarListView.confirm_action(del, start_string, end_string))
return false;
if(document.MassAssign_SecurityGroups.massassign_group.selectedIndex == 0) {
alert("{$current_module_strings['LBL_SELECT_GROUP_ERROR']}");
return false;
}
if (document.MassAssign_SecurityGroups.massassign_group.selectedIndex == 0) {
alert("{$current_module_strings['LBL_SELECT_GROUP_ERROR']}");
return false;
}
if (document.MassUpdate.select_entire_list &&
document.MassUpdate.select_entire_list.value == 1)
mode = 'entire';
else if (document.MassUpdate.massall.checked == true)
mode = 'page';
else
mode = 'selected';
if (document.MassUpdate.select_entire_list &&
document.MassUpdate.select_entire_list.value == 1)
mode = 'entire';
else if (document.MassUpdate.massall.checked == true)
mode = 'page';
else
mode = 'selected';
var ar = new Array();
if(del == 1) {
var deleteInput = document.createElement('input');
deleteInput.name = 'Delete';
deleteInput.type = 'hidden';
deleteInput.value = true;
document.MassAssign_SecurityGroups.appendChild(deleteInput);
}
var ar = new Array();
if (del == 1) {
var deleteInput = document.createElement('input');
deleteInput.name = 'Delete';
deleteInput.type = 'hidden';
deleteInput.value = true;
document.MassAssign_SecurityGroups.appendChild(deleteInput);
}
switch(mode) {
case 'page':
document.MassAssign_SecurityGroups.uid.value = '';
for(wp = 0; wp < document.MassUpdate.elements.length; wp++) {
if(typeof document.MassUpdate.elements[wp].name != 'undefined'
&& document.MassUpdate.elements[wp].name == 'mass[]' && document.MassUpdate.elements[wp].checked) {
ar.push(document.MassUpdate.elements[wp].value);
}
}
document.MassAssign_SecurityGroups.uid.value = ar.join(',');
if(document.MassAssign_SecurityGroups.uid.value == '') {
alert(no_record_txt);
return false;
}
break;
case 'selected':
for(wp = 0; wp < document.MassUpdate.elements.length; wp++) {
if(typeof document.MassUpdate.elements[wp].name != 'undefined'
&& document.MassUpdate.elements[wp].name == 'mass[]'
&& document.MassUpdate.elements[wp].checked) {
ar.push(document.MassUpdate.elements[wp].value);
}
}
if(document.MassUpdate.uid.value != '') {
switch (mode) {
case 'page':
document.MassAssign_SecurityGroups.uid.value = '';
for (wp = 0; wp < document.MassUpdate.elements.length; wp++) {
if (typeof document.MassUpdate.elements[wp].name != 'undefined'
&& document.MassUpdate.elements[wp].name == 'mass[]' && document.MassUpdate.elements[wp].checked) {
ar.push(document.MassUpdate.elements[wp].value);
}
}
document.MassAssign_SecurityGroups.uid.value = ar.join(',');
if (document.MassAssign_SecurityGroups.uid.value == '') {
alert(no_record_txt);
return false;
}
break;
case 'selected':
for (wp = 0; wp < document.MassUpdate.elements.length; wp++) {
if (typeof document.MassUpdate.elements[wp].name != 'undefined'
&& document.MassUpdate.elements[wp].name == 'mass[]'
&& document.MassUpdate.elements[wp].checked) {
ar.push(document.MassUpdate.elements[wp].value);
}
}
if (document.MassUpdate.uid.value != '') {
document.MassUpdate.uid.value += ',';
document.MassUpdate.uid.value += ar.join(',');
document.MassAssign_SecurityGroups.uid.value = document.MassUpdate.uid.value;
if(document.MassAssign_SecurityGroups.uid.value == '') {
alert(no_record_txt);
return false;
if (document.MassAssign_SecurityGroups.uid.value == '') {
alert(no_record_txt);
return false;
}
} else {
document.MassAssign_SecurityGroups.uid.value += ar.join(',');
if (document.MassAssign_SecurityGroups.uid.value == '') {
alert(no_record_txt);
return false;
}
}
break;
case 'entire':
var entireInput = document.createElement('input');
entireInput.name = 'entire';
entireInput.type = 'hidden';
entireInput.value = 'index';
document.MassAssign_SecurityGroups.appendChild(entireInput);
//confirm(no_record_txt);
break;
}
break;
case 'entire':
var entireInput = document.createElement('input');
entireInput.name = 'entire';
entireInput.type = 'hidden';
entireInput.value = 'index';
document.MassAssign_SecurityGroups.appendChild(entireInput);
break;
}
document.MassAssign_SecurityGroups.submit();
return false;
document.MassAssign_SecurityGroups.submit();
return false;
}
</script>

View file

@ -10,7 +10,7 @@
</tr>
{/foreach}
</table>
<canvas width="600" height="300" id='{$question.id}Chart' class=''></canvas>
<canvas width="750" height="400" id='{$question.id}Chart' class=''></canvas>
<script>
{literal}
$(document).ready(function () {
@ -21,8 +21,11 @@
data: chartData,
options: {
title: '{/literal}{$question.name}{literal}',
radius: 140,
gutterTop: 60,
textSize: 10,
titleSize: 10,
titleSize: 16,
titleFont: 'Lato',
colors: ['#f08377', '#534d64', '#778591', '#bfcad3', '#d8f5ee'],
tooltips: function (ind) {
return chartLabels[ind] + " - " + chartData[ind];
@ -33,4 +36,4 @@
}).draw();
});
{/literal}
</script>
</script>

View file

@ -12,7 +12,7 @@
</tr>
{/foreach}
</table>
<canvas width="600" height="400" id='{$responseId}Chart' class=''></canvas>
<canvas width="750" height="400" id='{$responseId}Chart' class=''></canvas>
<script>
{literal}
$(document).ready(function () {
@ -25,10 +25,13 @@
options: {
title: '{/literal}{$question.name} - {$response.label}{literal}',
textSize: 10,
titleSize: 10,
titleSize: 16,
titleFont: 'Lato',
titleY: 10,
textAngle: 30,
colorsSequential: true,
colors: ['#f08377', '#534d64', '#778591', '#bfcad3', '#d8f5ee'],
gutterTop: 60,
gutterBottom: 110,
gutterLeft: 50,
tooltips: function (ind) {
@ -48,4 +51,4 @@
});
{/literal}
</script>
{/foreach}
{/foreach}

View file

@ -10,7 +10,7 @@
</tr>
{/foreach}
</table>
<canvas width="600" height="300" id='{$question.id}Chart' class=''></canvas>
<canvas width="750" height="400" id='{$question.id}Chart' class=''></canvas>
<script>
{literal}
$(document).ready(function () {
@ -23,8 +23,14 @@
options: {
title: '{/literal}{$question.name}{literal}',
textSize: 10,
titleSize: 10,
textAngle: 40,
titleSize: 16,
titleFont: 'Lato',
titleY: 10,
colors: ['#f08377', '#534d64', '#778591', '#bfcad3', '#d8f5ee'],
gutterBottom: 110,
gutterTop: 60,
gutterLeft: 50,
tooltips: function (ind) {
return chartLabels[ind] + " - " + chartData[ind];
},
@ -41,4 +47,4 @@
}).draw();
});
{/literal}
</script>
</script>

View file

@ -2,35 +2,49 @@
<table>
<tr>
<th>{$MOD.LBL_SURVEY_RESPONSES}</th>
<td>{$responsesCount}</td>
<td class="survey-report-summary">{$responsesCount}</td>
</tr>
<tr>
<th>{$MOD.LBL_SURVEYS_SENT}</th>
<td>{$surveysSent}</td>
<td class="survey-report-summary">{$surveysSent}</td>
</tr>
<tr>
<th>{$MOD.LBL_SURVEY_DISTINCT}</th>
<td>{$surveysSentDistinct}</td>
<td class="survey-report-summary">{$surveysSentDistinct}</td>
</tr>
</table>
<style>
{literal}
.survey-report-summary
{
padding-left: 2em;
}
{/literal}
</style>
{foreach from=$data item=question}
{foreach from=$data key=i item=question}
<hr>
<div class="panel panel-default">
<div class="panel-heading">
<div>{$question.name}</div>
<a class="" role="button" data-toggle="collapse" href="#top-panel-{$i}" aria-expanded="false">
<div class="col-xs-10 col-sm-11 col-md-11">
<h4>{$question.name}</h4>
</div>
</a>
</div>
<div class="panel-body" style="padding: 50px;">
{if $question.type == 'Checkbox'}
{include file='modules/Surveys/tpls/Reports/checkbox.tpl'}
{elseif $question.type == 'Dropdown' || $question.type == 'Multiselect' || $question.type == 'Radio' || $question.type == 'Rating' || $question.type == 'Scale'}
{include file='modules/Surveys/tpls/Reports/option.tpl'}
{elseif $question.type == 'Matrix'}
{include file='modules/Surveys/tpls/Reports/matrix.tpl'}
{else}
{include file='modules/Surveys/tpls/Reports/other.tpl'}
{/if}
<div class="panel-body panel-collapse collapse in" id="top-panel-{$i}" style="padding: 50px;">
<div class="tab-content">
{if $question.type == 'Checkbox'}
{include file='modules/Surveys/tpls/Reports/checkbox.tpl'}
{elseif $question.type == 'Dropdown' || $question.type == 'Multiselect' || $question.type == 'Radio' || $question.type == 'Rating' || $question.type == 'Scale'}
{include file='modules/Surveys/tpls/Reports/option.tpl'}
{elseif $question.type == 'Matrix'}
{include file='modules/Surveys/tpls/Reports/matrix.tpl'}
{else}
{include file='modules/Surveys/tpls/Reports/other.tpl'}
{/if}
</div>
</div>
</div>
{/foreach}

View file

@ -5,7 +5,7 @@
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
*
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
* Copyright (C) 2011 - 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
@ -67,18 +67,24 @@ class UsersController extends SugarController
}
}
private function currentUserEqualsRecordUser() {
return $_REQUEST['record'] === $GLOBALS['current_user']->id;
}
protected function action_delete()
{
if ($_REQUEST['record'] != $GLOBALS['current_user']->id && (
global $app_strings, $mod_strings;
if (!$this->currentUserEqualsRecordUser() && (
$GLOBALS['current_user']->isAdminForModule('Users')
)
) {
$u = BeanFactory::newBean('Users');
$u->retrieve($_REQUEST['record']);
$u->status = 'Inactive';
$u->employee_status = 'Terminated';
$u->save();
$u->mark_deleted($u->id);
$user = BeanFactory::newBean('Users');
$user->retrieve($_REQUEST['record']);
$user->status = 'Inactive';
$user->employee_status = 'Terminated';
$user->save();
$user->mark_deleted($user->id);
$GLOBALS['log']->info("User id: {$GLOBALS['current_user']->id} deleted user record: {$_REQUEST['record']}");
$eapm = loadBean('EAPM');
@ -87,7 +93,11 @@ class UsersController extends SugarController
SugarApplication::redirect("index.php?module=Users&action=index");
} else {
sugar_die("Unauthorized access to administration.");
if ($this->currentUserEqualsRecordUser()) {
sugar_die($mod_strings['ERR_DELETE_USER']);
} else {
sugar_die($app_strings['ERR_NOT_ADMIN']);
}
}
}

View file

@ -85,6 +85,7 @@ $mod_strings = array(
'ERR_RECIPIENT_EMAIL' => 'Recipient Email Address',
'ERR_SERVER_STATUS' => 'Your server status',
'ERR_SERVER_SMTP_EMPTY' => 'The system is unable to send an email to the user. Please check the Outgoing Mail Configuration in <a href="index.php?module=EmailMan&action=config">Email Settings</a>.',
'ERR_DELETE_USER' => 'It is not allowed to delete logged in user.',
'LBL_ADDRESS_CITY' => 'Address City',
'LBL_ADDRESS_COUNTRY' => 'Address Country',
'LBL_ADDRESS_INFORMATION' => 'Address Information',

View file

@ -533,7 +533,7 @@
<slot>Current API Token is: <span style="color:{$GOOGLE_API_TOKEN_COLOR}">{$GOOGLE_API_TOKEN}</span>
&nbsp;&nbsp;<input style="display:{$GOOGLE_API_TOKEN_ENABLE_NEW}" class="btn btn-primary btn-sm"
id="google_gettoken" type="button" value="{$GOOGLE_API_TOKEN_BTN}"
onclick="window.open('{$GOOGLE_API_TOKEN_NEW_URL}', '_self')"/></slot>
onclick="window.open('{$GOOGLE_API_TOKEN_NEW_URL}', '_blank')"/></slot>
</td>
<td width="63%">
<slot>&nbsp;</slot>

View file

@ -5,7 +5,7 @@
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
*
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
* Copyright (C) 2011 - 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
@ -102,6 +102,8 @@ class UsersViewDetail extends ViewDetail
);
$buttons = array();
$this->ss->assign("CURRENT_USER_ID", $GLOBALS['current_user']->id);
if ((
is_admin($current_user) || $_REQUEST['record'] == $current_user->id
)
@ -120,9 +122,7 @@ class UsersViewDetail extends ViewDetail
if (!$current_user->is_group) {
$this->dv->defs['templateMeta']['form']['buttons'][] = array('customCode' => "<input id='duplicate_button' title='" . $app_strings['LBL_DUPLICATE_BUTTON_TITLE'] . "' accessKey='" . $app_strings['LBL_DUPLICATE_BUTTON_KEY'] . "' class='button' onclick=\"this.form.return_module.value='Users'; this.form.return_action.value='DetailView'; this.form.isDuplicate.value=true; this.form.action.value='EditView'\" type='submit' name='Duplicate' value='" . $app_strings['LBL_DUPLICATE_BUTTON_LABEL'] . "'>");
if ($this->bean->id != $current_user->id) {
$this->dv->defs['templateMeta']['form']['buttons'][] = array('customCode' => "<input id='delete_button' title='" . $app_strings['LBL_DELETE_BUTTON_LABEL'] . "' type='button' class='button' onclick='confirmDelete();' value='" . $app_strings['LBL_DELETE_BUTTON_LABEL'] . "' />");
}
$this->dv->defs['templateMeta']['form']['buttons'][] = array('customCode' => "<input name='delete' id='delete_button' title='" . $app_strings['LBL_DELETE_BUTTON_LABEL'] . "' type='button' class='button' onclick='confirmDelete();' value='" . $app_strings['LBL_DELETE_BUTTON_LABEL'] . "'>");
if (!$this->bean->portal_only && !$this->bean->is_group && !$this->bean->external_auth_only
&& isset($sugar_config['passwordsetting']['SystemGeneratedPasswordON']) && $sugar_config['passwordsetting']['SystemGeneratedPasswordON']) {

View file

@ -4,5 +4,5 @@ if (!defined('sugarEntry') || !sugarEntry) {
}
$suitecrm_version = '8.5.0';
$suitecrm_timestamp = '2023-12-13 12:00:00';
$suitecrm_legacy = '7.14.2';
$suitecrm_timestamp = '2024-01-29 12:00:00';
$suitecrm_legacy = '7.14.3';

View file

@ -170,7 +170,9 @@
{sugar_evalcolumn_old var=$params.customCode rowData=$rowData}
{elseif $params.currency_format}
{sugar_currency_format
var=$rowData.$col
id=$rowData.ID
var=$rowData.$col
field_name=$params.name
round=$params.currency_format.round
decimals=$params.currency_format.decimals
symbol=$params.currency_format.symbol

View file

@ -5,7 +5,7 @@
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
*
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
* Copyright (C) 2011 - 2023 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
@ -44,6 +44,7 @@
<form action="index.php" method="post" name="DetailView" id="formDetailView">
<input type="hidden" name="module" value="{$module}">
<input type="hidden" name="record" value="{$fields.id.value}">
<input type="hidden" name="current_user_id" value="{$CURRENT_USER_ID}">
<input type="hidden" name="return_action">
<input type="hidden" name="return_module">
<input type="hidden" name="return_id">
@ -271,5 +272,13 @@
});
});
var $record = $("#formDetailView [name='record']").val();
var $currentUser = $("#formDetailView [name='current_user_id']").val();
var $deleteButton = $("#delete_button");
if ($currentUser === $record) {
$deleteButton.closest('li').remove();
$deleteButton.remove();
}
</script>
{/literal}