Commit 3f01e768 authored by Cédric Anne's avatar Cédric Anne
Browse files

Merge branch '10.0/bugfixes' into main

parents 65b0b8da 7891b99a
......@@ -3,10 +3,9 @@
"description": "GLPI dependencies",
"license": "GPL-3.0-or-later",
"type": "project",
"homepage": "http://www.glpi-project.org/",
"homepage": "https://www.glpi-project.org/",
"support": {
"irc": "irc://irc.freenode.org/glpi",
"forum": "http://forum.glpi-project.org/",
"forum": "https://forum.glpi-project.org/",
"issues": "https://github.com/glpi-project/glpi/issues",
"docs": "https://github.com/glpi-project/doc"
},
......
......@@ -65,8 +65,11 @@ $timeline-task-bg: #ffe8b9 !default;
$timeline-task-fg: #38301f !default;
$timeline-task-border: #e5c88c !default;
$timeline-sol-bg: #9fd6ed !default;
$timeline-sol-fg: #425b64 !default;
$timeline-sol-fg: #27363b !default;
$timeline-sol-border: #90c2d8 !default;
$timeline-doc-bg: #80cead !default;
$timeline-doc-fg: #21352c !default;
$timeline-doc-border: #68b997 !default;
$timeline-log-bg: #cacaca21 !default;
$timeline-badge-bg: rgba(97, 97, 97, 15%) !default;
$timeline-badge-fg: rgba(43, 43, 43, 80%) !default;
......
......@@ -83,7 +83,8 @@
content: "\f204";
left: 0;
top: 0;
font: 15px var(--fa-font-solid);
font: var(--fa-font-solid);
font-size: 15px;
position: absolute;
}
......
......@@ -43,6 +43,12 @@
z-index: $zindex-fixed;
}
.answer-action {
&:hover {
font-weight: bold;
}
}
.action-task {
background-color: $timeline-task-bg;
color: $timeline-task-fg;
......@@ -53,6 +59,11 @@
color: $timeline-sol-fg;
}
.action-document {
background-color: $timeline-doc-bg;
color: $timeline-doc-fg;
}
#debugajax {
position: absolute;
top: 10px;
......
......@@ -269,6 +269,14 @@
border: 0;
box-shadow: none;
}
&#new-Document_Item-block {
.timeline-content {
border: 1px solid $timeline-doc-border;
box-shadow: inherit;
color: $timeline-doc-fg;
}
}
}
&.Log {
......
......@@ -77,7 +77,7 @@ if (array_key_exists('update', $_POST)) {
if ($user->update($input)) {
$success = true;
} else {
$error_messages = [__('An error occured during password update')];
$error_messages = [__('An error occurred during password update')];
}
} catch (\Glpi\Exception\PasswordTooWeakException $exception) {
$error_messages = $exception->getMessages();
......
......@@ -4193,9 +4193,9 @@ $empty_data_builder = new class
##IFticket.assigntousers## <span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.ticket.assigntousers##</span> : ##ticket.assigntousers## ##ENDIFticket.assigntousers##<br /> <span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;">##lang.ticket.status## </span> : ##ticket.status##<br /> ##IFticket.assigntogroups## <span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.ticket.assigntogroups##</span> : ##ticket.assigntogroups## ##ENDIFticket.assigntogroups##<br /> <span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.ticket.urgency##</span> : ##ticket.urgency##<br /> <span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.ticket.impact##</span> : ##ticket.impact##<br /> <span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.ticket.priority##</span> : ##ticket.priority## <br /> ##IFticket.user.email##<span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.ticket.user.email##</span> : ##ticket.user.email ##ENDIFticket.user.email## <br /> ##IFticket.category##<span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;">##lang.ticket.category## </span> :##ticket.category## ##ENDIFticket.category## ##ELSEticket.category## ##lang.ticket.nocategoryassigned## ##ENDELSEticket.category## <br /> <span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.ticket.content##</span> : ##ticket.content##</p>
<br />##IFticket.storestatus=6##<br /><span style="text-decoration: underline;"><strong><span style="color: #888888;">##lang.ticket.solvedate##</span></strong></span> : ##ticket.solvedate##<br /><span style="color: #888888;"><strong><span style="text-decoration: underline;">##lang.ticket.solution.type##</span></strong></span> : ##ticket.solution.type##<br /><span style="text-decoration: underline; color: #888888;"><strong>##lang.ticket.solution.description##</strong></span> : ##ticket.solution.description##<br />##ENDIFticket.storestatus##</p>
<p>##FOREACHtimelineitems##</p>
<div class="description b"><br /><strong> [##timelineitems.date##]</strong><br /><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.timelineitems.author## </span> ##<span style="color: #000000; font-weight: bold; text-decoration: underline; background-color: #ffffff;">timelineitems</span>.author##<br /><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.timelineitems.description## </span> ##<span style="color: #000000; font-weight: bold; text-decoration: underline;">timelineitems</span>.description##<br /><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.timelineitems.date## </span> ##<span style="color: #000000; font-weight: bold; text-decoration: underline;">timelineitems</span>.date##<br /><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;">##lang.timelineitems.position## </span><span style="color: #000000;"> ##<span style="font-weight: bold; text-decoration: underline;">timelineitems</span>.<span style="font-weight: bold; text-decoration: underline;">position</span>##</span></div>
<div class="description b"><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;">##lang.timelineitems.type## </span> ##<span style="color: #000000;"><span style="font-weight: bold; text-decoration: underline;">timelineitems</span>.<span style="font-weight: bold; text-decoration: underline;">type</span>##</span></div>
<div class="description b"><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;">##lang.timelineitems.typename## </span> #<span style="color: #000000;">#<span style="font-weight: bold; text-decoration: underline;">timelineitems</span>.<span style="font-weight: bold; text-decoration: underline;">typename</span>##</span></div>
<div class="description b"><br /><strong> [##timelineitems.date##]</strong><br /><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.timelineitems.author## </span> <span style="color: #000000; font-weight: bold; text-decoration: underline;">##timelineitems.author##</span><br /><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.timelineitems.description## </span> <span style="color: #000000; font-weight: bold; text-decoration: underline;">##timelineitems.description##</span><br /><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;"> ##lang.timelineitems.date## </span> <span style="color: #000000; font-weight: bold; text-decoration: underline;">##timelineitems.date##</span><br /><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;">##lang.timelineitems.position## </span><span style="color: #000000; font-weight: bold; text-decoration: underline;"> ##timelineitems.position##</span></div>
<div class="description b"><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;">##lang.timelineitems.type## </span><span style="color: #000000; font-weight: bold; text-decoration: underline;"> ##timelineitems.type##</span></div>
<div class="description b"><span style="color: #8b8c8f; font-weight: bold; text-decoration: underline;">##lang.timelineitems.typename## </span> <span style="color: #000000; font-weight: bold; text-decoration: underline;">##timelineitems.typename##</span></div>
<p>##ENDFOREACHtimelineitems##</p>
<div class="description b">##lang.ticket.numberoffollowups## : ##ticket.numberoffollowups##</div>
<div class="description b">##lang.ticket.numberoftasks## : ##ticket.numberoftasks##</div>',
......
......@@ -157,6 +157,61 @@ class Agent extends CommonDBTM
return $tab;
}
public static function rawSearchOptionsToAdd()
{
$tab = [];
// separator
$tab[] = [
'id' => 'agent',
'name' => self::getTypeName(1),
];
$baseopts = [
'table' => self::getTable(),
'joinparams' => [
'jointype' => 'itemtype_item',
],
];
$tab[] = [
'id' => 900,
'field' => 'name',
'name' => __('Name'),
'datatype' => 'itemlink',
] + $baseopts;
$tab[] = [
'id' => 901,
'field' => 'tag',
'name' => __('Tag'),
'datatype' => 'text',
] + $baseopts;
$tab[] = [
'id' => 902,
'field' => 'last_contact',
'name' => __('Last contact'),
'datatype' => 'datetime',
] + $baseopts;
$tab[] = [
'id' => 903,
'field' => 'version',
'name' => _n('Version', 'Versions', 1),
'datatype' => 'text',
] + $baseopts;
$tab[] = [
'id' => 904,
'field' => 'deviceid',
'name' => __('Device id'),
'datatype' => 'text',
] + $baseopts;
return $tab;
}
/**
* Define tabs to display on form page
*
......
......@@ -3150,6 +3150,11 @@ abstract class API
$actions = $this->getMassiveActionsForItem($item);
}
if (count($actions) === 0) {
// An error occurred
return;
}
// Build response array
$response = [];
foreach ($actions as $key => $label) {
......@@ -3173,7 +3178,16 @@ abstract class API
bool $is_deleted = false
): array {
// Return massive actions for a given itemtype
return MassiveAction::getAllMassiveActions($itemtype, $is_deleted);
$actions = MassiveAction::getAllMassiveActions($itemtype, $is_deleted);
if ($actions === false) {
$this->returnError(
"Unable to get massive actions for itemtype '$itemtype'. Please check that it is a valid itemtype.",
400,
"ERROR_MASSIVEACTION_NOT_FOUND"
);
return [];
}
return $actions;
}
/**
......@@ -3185,12 +3199,21 @@ abstract class API
public function getMassiveActionsForItem(CommonDBTM $item): array
{
// Return massive actions for a given item
return MassiveAction::getAllMassiveActions(
$actions = MassiveAction::getAllMassiveActions(
$item::getType(),
$item->isDeleted(),
$item,
$item->getID()
);
if ($actions === false) {
$this->returnError(
"Unable to get massive actions for item of type '{$item::getType()}'. Please check that it is a valid itemtype.",
400,
"ERROR_MASSIVEACTION_NOT_FOUND"
);
return [];
}
return $actions;
}
/**
......@@ -3223,6 +3246,15 @@ abstract class API
}
$actions = MassiveAction::getAllMassiveActions($itemtype, $is_deleted);
if ($actions === false) {
$this->returnError(
"Unable to get massive actions for itemtype '$itemtype'. Please check that it is a valid itemtype.",
400,
"ERROR_MASSIVEACTION_NOT_FOUND"
);
return;
}
if (!isset($actions[$action_key])) {
$this->returnError(
"Invalid action key parameter, run 'getMassiveActions' endpoint to see available keys",
......@@ -3231,7 +3263,7 @@ abstract class API
);
}
// Get massive action for the given key
// Get massive action for the given key
$ma = new MassiveAction([
'action' => $action_key,
'actions' => $actions,
......
......@@ -286,7 +286,7 @@ class ErrorHandler
/**
* Twig error handler.
*
* This handler is manually called by application when an error occured during Twig template rendering.
* This handler is manually called by application when an error occurred during Twig template rendering.
*
* @param \Twig\Error\Error $error
*
......@@ -316,7 +316,7 @@ class ErrorHandler
/**
* SQL error handler.
*
* This handler is manually called by application when a SQL error occured.
* This handler is manually called by application when a SQL error occurred.
*
* @param integer $error_code
* @param string $error_message
......
......@@ -379,6 +379,12 @@ abstract class CommonITILObject extends CommonDBTM
$canupdate = !$ID || (Session::getCurrentInterface() == "central" && $this->canUpdateItem());
if ($ID && in_array($this->fields['status'], $this->getClosedStatusArray())) {
$canupdate = false;
// No update for actors
$options['_noupdate'] = true;
}
if (!$this->isNewItem()) {
$options['formtitle'] = sprintf(
__('%1$s - ID %2$d'),
......@@ -408,6 +414,7 @@ abstract class CommonITILObject extends CommonDBTM
'timeline_itemtypes' => $this->getTimelineItemtypes(),
'legacy_timeline_actions' => $this->getLegacyTimelineActionsHTML(),
'params' => $options,
'entities_id' => $ID ? $this->fields['entities_id'] : $options['entities_id'],
'timeline' => $this->getTimelineItems(),
'itiltemplate_key' => static::getTemplateFormFieldName(),
'itiltemplate' => $tt,
......@@ -6891,6 +6898,15 @@ abstract class CommonITILObject extends CommonDBTM
'item' => new ITILSolution(),
'hide_in_menu' => !$canadd_solution
];
$itemtypes['document'] = [
'type' => 'Document_Item',
'class' => Document_Item::class,
'icon' => Document_Item::getIcon(),
'label' => _x('button', 'Add a document'),
'template' => 'components/itilobject/timeline/form_document_item.html.twig',
'item' => new Document_Item(),
'hide_in_menu' => !$canadd_document
];
if ($validation !== null) {
$itemtypes['validation'] = [
'type' => 'ITILValidation',
......@@ -6902,15 +6918,6 @@ abstract class CommonITILObject extends CommonDBTM
'hide_in_menu' => !$canadd_validation
];
}
$itemtypes['document'] = [
'type' => 'Document_Item',
'class' => Document_Item::class,
'icon' => Document_Item::getIcon(),
'label' => _x('button', 'Add a document'),
'template' => 'components/itilobject/timeline/form_document_item.html.twig',
'item' => new Document_Item(),
'hide_in_menu' => true
];
if (isset($PLUGIN_HOOKS[Hooks::TIMELINE_ANSWER_ACTIONS])) {
foreach ($PLUGIN_HOOKS[Hooks::TIMELINE_ANSWER_ACTIONS] as $plugin => $hook_itemtypes) {
......
......@@ -593,6 +593,8 @@ class Computer extends CommonDBTM
$tab = array_merge($tab, Socket::rawSearchOptionsToAdd(get_class($this)));
$tab = array_merge($tab, Agent::rawSearchOptionsToAdd());
return $tab;
}
......
......@@ -284,6 +284,11 @@ class Config extends CommonDBTM
);
}
// Automatically trim whitespaces around registration key.
if (array_key_exists('glpinetwork_registration_key', $input) && !empty($input['glpinetwork_registration_key'])) {
$input['glpinetwork_registration_key'] = trim($input['glpinetwork_registration_key']);
}
$this->setConfigurationValues('core', $input);
return false;
......@@ -2564,6 +2569,11 @@ HTML;
$CFG_GLPI['root_doc'] = parse_url($url_base, PHP_URL_PATH) ?? '';
}
}
// Path for icon of document type (web mode only)
if (isset($CFG_GLPI['root_doc'])) {
$CFG_GLPI['typedoc_icon_dir'] = $CFG_GLPI['root_doc'] . '/pics/icones';
}
}
......@@ -3003,7 +3013,7 @@ HTML;
/**
* Load legacy configuration into $CFG_GLPI global variable.
*
* @return boolean True for success, false if an error occured
* @return boolean True for success, false if an error occurred
*
* @since 10.0.0 Parameter $older_to_latest is not longer used.
*/
......@@ -3058,11 +3068,6 @@ HTML;
$CFG_GLPI['lock_lockprofile'] = $prof->fields;
}
// Path for icon of document type (web mode only)
if (isset($CFG_GLPI['root_doc'])) {
$CFG_GLPI['typedoc_icon_dir'] = $CFG_GLPI['root_doc'] . '/pics/icones';
}
if (isset($CFG_GLPI['planning_work_days'])) {
$CFG_GLPI['planning_work_days'] = importArrayFromDB($CFG_GLPI['planning_work_days']);
}
......
......@@ -179,7 +179,7 @@ class ConfigureCommand extends AbstractCommand
try {
$this->cache_manager->testConnection($dsn);
} catch (\Throwable $e) {
$error_msg = sprintf(__('An error occured during connection to cache system: "%s"'), $e->getMessage());
$error_msg = sprintf(__('An error occurred during connection to cache system: "%s"'), $e->getMessage());
throw new \Glpi\Console\Exception\EarlyExitException(
'<error>' . $error_msg . '</error>',
self::ERROR_UNABLE_TO_WRITE_CONFIG
......
......@@ -155,7 +155,7 @@ class DynamicRowFormatCommand extends AbstractCommand
if ($errors) {
throw new \Glpi\Console\Exception\EarlyExitException(
'<error>' . __('Errors occured during migration.') . '</error>',
'<error>' . __('Errors occurred during migration.') . '</error>',
self::ERROR_MIGRATION_FAILED_FOR_SOME_TABLES
);
}
......
......@@ -124,7 +124,7 @@ class MyIsamToInnoDbCommand extends AbstractCommand
if ($errors) {
throw new \Glpi\Console\Exception\EarlyExitException(
'<error>' . __('Errors occured during migration.') . '</error>',
'<error>' . __('Errors occurred during migration.') . '</error>',
self::ERROR_TABLE_MIGRATION_FAILED
);
}
......
......@@ -233,7 +233,7 @@ class TimestampsCommand extends AbstractCommand
if ($errors) {
throw new \Glpi\Console\Exception\EarlyExitException(
'<error>' . __('Errors occured during migration.') . '</error>',
'<error>' . __('Errors occurred during migration.') . '</error>',
self::ERROR_TABLE_MIGRATION_FAILED
);
}
......
......@@ -179,7 +179,7 @@ class UnsignedKeysCommand extends AbstractCommand
if ($errors) {
throw new \Glpi\Console\Exception\EarlyExitException(
'<error>' . __('Errors occured during migration.') . '</error>',
'<error>' . __('Errors occurred during migration.') . '</error>',
self::ERROR_COLUMN_MIGRATION_FAILED
);
}
......
......@@ -199,7 +199,7 @@ class Utf8mb4Command extends AbstractCommand
if ($errors) {
throw new \Glpi\Console\Exception\EarlyExitException(
'<error>' . __('Errors occured during migration.') . '</error>',
'<error>' . __('Errors occurred during migration.') . '</error>',
self::ERROR_MIGRATION_FAILED_FOR_SOME_TABLES
);
}
......
......@@ -1138,4 +1138,9 @@ class Document_Item extends CommonDBRelation
return $criteria;
}
public static function getIcon()
{
return Document::getIcon();
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment