Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add possibility to disable or restrict users mentions in RichText #18849

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions install/empty_data.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

use Glpi\Form\Form;
use Glpi\Inventory\Conf;
use Glpi\RichText\UserMention;
use Glpi\Socket;

// Use anonymous class so we can have constants that define special values without polluting the global table
Expand Down Expand Up @@ -8899,6 +8900,7 @@ public function getEmptyData(): array
'is_default' => '1',
'helpdesk_hardware' => '1',
'helpdesk_item_type' => '["Computer","Monitor","NetworkEquipment","Peripheral","Phone","Printer","Software", "DCRoom", "Rack", "Enclosure", "Database"]',
'use_mentions' => UserMention::USER_MENTION_FULL,
'ticket_status' => '{"1":{"2":0,"3":0,"4":0,"5":0,"6":0},"2":{"1":0,"3":0,"4":0,"5":0,"6":0},"3":{"1":0,"2":0,"4":0,"5":0,"6":0},"4":{"1":0,"2":0,"3":0,"5":0,"6":0},"5":{"1":0,"2":0,"3":0,"4":0},"6":{"1":0,"2":0,"3":0,"4":0,"5":0}}',
'comment' => '',
'problem_status' => '[]',
Expand All @@ -8913,6 +8915,7 @@ public function getEmptyData(): array
'is_default' => '0',
'helpdesk_hardware' => '1',
'helpdesk_item_type' => '["Computer","Monitor","NetworkEquipment","Peripheral","Phone","Printer","Software", "DCRoom", "Rack", "Enclosure", "Database"]',
'use_mentions' => UserMention::USER_MENTION_FULL,
'ticket_status' => '[]',
'comment' => '',
'problem_status' => '[]',
Expand All @@ -8927,6 +8930,7 @@ public function getEmptyData(): array
'is_default' => '0',
'helpdesk_hardware' => '3',
'helpdesk_item_type' => '["Computer","Monitor","NetworkEquipment","Peripheral","Phone","Printer","Software", "DCRoom", "Rack", "Enclosure", "Database"]',
'use_mentions' => UserMention::USER_MENTION_FULL,
'ticket_status' => '[]',
'comment' => '',
'problem_status' => '[]',
Expand All @@ -8941,6 +8945,7 @@ public function getEmptyData(): array
'is_default' => '0',
'helpdesk_hardware' => '3',
'helpdesk_item_type' => '["Computer","Monitor","NetworkEquipment","Peripheral","Phone","Printer","Software", "DCRoom", "Rack", "Enclosure", "Database"]',
'use_mentions' => UserMention::USER_MENTION_FULL,
'ticket_status' => '[]',
'comment' => '',
'problem_status' => '[]',
Expand All @@ -8955,6 +8960,7 @@ public function getEmptyData(): array
'is_default' => '0',
'helpdesk_hardware' => '3',
'helpdesk_item_type' => '["Computer","Monitor","NetworkEquipment","Peripheral","Phone","Printer","Software", "DCRoom", "Rack", "Enclosure", "Database"]',
'use_mentions' => UserMention::USER_MENTION_FULL,
'ticket_status' => '[]',
'comment' => '',
'problem_status' => '[]',
Expand All @@ -8969,6 +8975,7 @@ public function getEmptyData(): array
'is_default' => '0',
'helpdesk_hardware' => '3',
'helpdesk_item_type' => '["Computer","Monitor","NetworkEquipment","Peripheral","Phone","Printer","Software", "DCRoom", "Rack", "Enclosure", "Database"]',
'use_mentions' => UserMention::USER_MENTION_FULL,
'ticket_status' => '[]',
'comment' => '',
'problem_status' => '[]',
Expand All @@ -8983,6 +8990,7 @@ public function getEmptyData(): array
'is_default' => '0',
'helpdesk_hardware' => '3',
'helpdesk_item_type' => '["Computer","Monitor","NetworkEquipment","Peripheral","Phone","Printer","Software", "DCRoom", "Rack", "Enclosure", "Database"]',
'use_mentions' => UserMention::USER_MENTION_FULL,
'ticket_status' => '[]',
'comment' => '',
'problem_status' => '[]',
Expand All @@ -8997,6 +9005,7 @@ public function getEmptyData(): array
'is_default' => '0',
'helpdesk_hardware' => '0',
'helpdesk_item_type' => '[]',
'use_mentions' => UserMention::USER_MENTION_FULL,
'ticket_status' => '{"1":{"2":0,"3":0,"4":0,"5":0,"6":0},"2":{"1":0,"3":0,"4":0,"5":0,"6":0},"3":{"1":0,"2":0,"4":0,"5":0,"6":0},"4":{"1":0,"2":0,"3":0,"5":0,"6":0},"5":{"1":0,"2":0,"3":0,"4":0,"6":0},"6":{"1":0,"2":0,"3":0,"4":0,"5":0}}',
'comment' => 'This profile defines read-only access. It is used when objects are locked. It can also be used to give to users rights to unlock objects.',
'problem_status' => '{"1":{"7":0,"2":0,"3":0,"4":0,"5":0,"8":0,"6":0},"7":{"1":0,"2":0,"3":0,"4":0,"5":0,"8":0,"6":0},"2":{"1":0,"7":0,"3":0,"4":0,"5":0,"8":0,"6":0},"3":{"1":0,"7":0,"2":0,"4":0,"5":0,"8":0,"6":0},"4":{"1":0,"7":0,"2":0,"3":0,"5":0,"8":0,"6":0},"5":{"1":0,"7":0,"2":0,"3":0,"4":0,"8":0,"6":0},"8":{"1":0,"7":0,"2":0,"3":0,"4":0,"5":0,"6":0},"6":{"1":0,"7":0,"2":0,"3":0,"4":0,"5":0,"8":0}}',
Expand Down
13 changes: 13 additions & 0 deletions install/migrations/update_10.0.x_to_11.0.0/profiles.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
* ---------------------------------------------------------------------
*/

use Glpi\RichText\UserMention;

RomainLvr marked this conversation as resolved.
Show resolved Hide resolved
/**
* @var \Migration $migration
*/
Expand All @@ -47,3 +49,14 @@
]
);
$migration->addKey('glpi_profiles', 'last_rights_update');

$migration->addField(
'glpi_profiles',
'use_mentions',
'int',
[
'null' => false,
'value' => UserMention::USER_MENTION_FULL,
RomainLvr marked this conversation as resolved.
Show resolved Hide resolved
'after' => 'helpdesk_item_type'
]
);
1 change: 1 addition & 0 deletions install/mysql/glpi-empty.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5824,6 +5824,7 @@ CREATE TABLE `glpi_profiles` (
`is_default` tinyint NOT NULL DEFAULT '0',
`helpdesk_hardware` int NOT NULL DEFAULT '0',
`helpdesk_item_type` text,
`use_mentions` int NOT NULL DEFAULT '1',
`ticket_status` text COMMENT 'json encoded array of from/dest allowed status change',
`date_mod` timestamp NULL DEFAULT NULL,
`comment` text,
Expand Down
13 changes: 11 additions & 2 deletions js/RichText/UserMention.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ window.GLPI.RichText.UserMention = class {
* @param {Editor} editor
* @param {number} activeEntity
* @param {string} idorToken
* @param {Array} mentions_options
RomainLvr marked this conversation as resolved.
Show resolved Hide resolved
*/
constructor(editor, activeEntity, idorToken) {
constructor(editor, activeEntity, idorToken, mentions_options) {
RomainLvr marked this conversation as resolved.
Show resolved Hide resolved
this.editor = editor;
this.activeEntity = activeEntity;
this.idorToken = idorToken;
this.mentionsOptions = mentions_options;
RomainLvr marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down Expand Up @@ -99,7 +101,14 @@ window.GLPI.RichText.UserMention = class {
}
).done(
(data) => {
const items = data.results.map(
let results = data.results;

if (!this.mentionsOptions.full) {
const allowedIds = this.mentionsOptions.users;
results = results.filter(user => allowedIds.includes(user.id));
}

const items = results.map(
(user) => {
return {
type: 'autocompleteitem',
Expand Down
18 changes: 13 additions & 5 deletions src/CommonITILObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
use Glpi\Form\Destination\AnswersSet_FormDestinationItem;
use Glpi\Plugin\Hooks;
use Glpi\RichText\RichText;
use Glpi\RichText\UserMention;
use Glpi\Team\Team;

/**
Expand Down Expand Up @@ -7358,6 +7359,8 @@ public function getTimelineItemtypes(): array

$itemtypes = [];

$use_mentions = UserMention::getRestrictedUsers($this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to read the code multiple times to figure out what this variable contains. I guess the naming can be improved here.

use_mentions => mentions_options
UserMention::getRestrictedUsers() => UserMention::getMentionOptions()


$itemtypes['answer'] = [
'type' => 'ITILFollowup',
'class' => 'ITILFollowup',
Expand All @@ -7366,7 +7369,8 @@ public function getTimelineItemtypes(): array
'short_label' => _x('button', 'Answer'),
'template' => 'components/itilobject/timeline/form_followup.html.twig',
'item' => $fup,
'hide_in_menu' => !$canadd_fup
'hide_in_menu' => !$canadd_fup,
'use_mentions' => $use_mentions,
];
$itemtypes['task'] = [
'type' => 'ITILTask',
Expand All @@ -7376,7 +7380,8 @@ public function getTimelineItemtypes(): array
'short_label' => _x('button', 'Task'),
'template' => 'components/itilobject/timeline/form_task.html.twig',
'item' => $task,
'hide_in_menu' => !$canadd_task
'hide_in_menu' => !$canadd_task,
'use_mentions' => $use_mentions,
];
$itemtypes['solution'] = [
'type' => 'ITILSolution',
Expand All @@ -7386,7 +7391,8 @@ public function getTimelineItemtypes(): array
'short_label' => _x('button', 'Solution'),
'template' => 'components/itilobject/timeline/form_solution.html.twig',
'item' => new ITILSolution(),
'hide_in_menu' => !$canadd_solution
'hide_in_menu' => !$canadd_solution,
'use_mentions' => $use_mentions,
];
$itemtypes['document'] = [
'type' => 'Document_Item',
Expand All @@ -7396,7 +7402,8 @@ public function getTimelineItemtypes(): array
'short_label' => _x('button', 'Document'),
'template' => 'components/itilobject/timeline/form_document_item.html.twig',
'item' => new Document_Item(),
'hide_in_menu' => !$canadd_document
'hide_in_menu' => !$canadd_document,
'use_mentions' => $use_mentions,
];
if ($validation !== null) {
$itemtypes['validation'] = [
Expand All @@ -7407,7 +7414,8 @@ public function getTimelineItemtypes(): array
'short_label' => _x('button', 'Validation'),
'template' => 'components/itilobject/timeline/form_validation.html.twig',
'item' => $validation,
'hide_in_menu' => !$canadd_validation
'hide_in_menu' => !$canadd_validation,
'use_mentions' => $use_mentions,
];
}

Expand Down
47 changes: 47 additions & 0 deletions src/Glpi/RichText/UserMention.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,15 @@
use ITILFollowup;
use ITILSolution;
use NotificationEvent;
use Profile;
use User;

final class UserMention
{
const USER_MENTION_DISABLED = 0;
const USER_MENTION_FULL = 1;
const USER_MENTION_RESTRICTED = 2;
RomainLvr marked this conversation as resolved.
Show resolved Hide resolved

/**
* Handle user mentions.
* Add newly mention users to observers and send them a notification.
Expand Down Expand Up @@ -261,4 +266,46 @@ public static function refreshUserMentionsHtmlToDisplay(string $content): string

return $content;
}

public static function isEnabled(): bool
{
$pro = Profile::getById($_SESSION['glpiactiveprofile']['id']);
return $pro->fields['use_mentions'] !== self::USER_MENTION_DISABLED;
}

public static function isMentionsRestricted(): bool
{
$pro = Profile::getById($_SESSION['glpiactiveprofile']['id']);
return $pro->fields['use_mentions'] === self::USER_MENTION_RESTRICTED;
}
RomainLvr marked this conversation as resolved.
Show resolved Hide resolved

public static function getRestrictedUsers(CommonITILObject $item): array
{
$data = [
'enabled' => self::isEnabled(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is preferable to always return the same keys in a JSON object. Also, defining them at only one place is easier to read.

Suggested change
'enabled' => self::isEnabled(),
'enabled' => self::isEnabled(),
'full' => !self::isMentionsRestricted(),
'user' => [],

];

if (!self::isMentionsRestricted()) {
$data['full'] = true;
return $data;
} else {
$data['full'] = false;
}

$items_id = $item->getID();

//get actors from item
$userlink = new $item->userlinkclass();
$actors = $userlink->getActors($items_id);

$data['users'] = [];

foreach ($actors as $actor) {
foreach ($actor as $a) {
$data['users'][] = $a['users_id'];
}
}

return $data;
}
}
87 changes: 87 additions & 0 deletions src/Profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
use Glpi\Form\Form;
use Glpi\Helpdesk\DefaultDataManager;
use Glpi\Helpdesk\Tile\TilesManager;
use Glpi\RichText\UserMention;
use Glpi\Session\SessionInfo;
use Glpi\Toolbox\ArrayNormalizer;

Expand Down Expand Up @@ -68,6 +69,7 @@ class Profile extends CommonDBTM
'reservation',
'rssfeed_public',
'show_group_hardware',
'use_mentions',
'task',
'ticket',
'ticket_cost',
Expand Down Expand Up @@ -1538,6 +1540,10 @@ public function showFormTools($openform = true, $closeform = true)
**/
public function showFormTracking($openform = true, $closeform = true)
{
/** @var array $CFG_GLPI */

global $CFG_GLPI;

if (!self::canView()) {
return false;
}
Expand Down Expand Up @@ -1597,6 +1603,60 @@ public function showFormTracking($openform = true, $closeform = true)
$matrix_options['title'] = _n('Followup', 'Followups', Session::getPluralNumber()) . " / " . _n('Task', 'Tasks', Session::getPluralNumber());
$this->displayRightsChoiceMatrix(self::getRightsForForm('central', 'tracking', 'followups_tasks'), $matrix_options);

echo "<div class='mt-n2 mx-n2 mb-4'>";
echo "<table class='table table-hover card-table'>";
echo "<thead>";
echo "<tr><th colspan='2'><h4>" . __s('Users mentions') . "<h4></th></tr>";

echo "</thead>";

echo "<tbody>";

$description = __s('Enables or disables the ability to mention users within the application.') . "<br><br>";
$description .= "<b>" . __s('Disabled') . "</b> : " . __('User mentions are disabled for this profile.') . "<br><br>";
$description .= "<b>" . __s('Full') . "</b> : " . __('Displays all users. Mentioned users will be added as observers if they are not already actors.') . "<br><br>";
$description .= "<b>" . __s('Restricted') . "</b> : " . __('Limits the display to actors directly involved in the ticket.') . "<br><br><br>";

$disabled = false;

if ($CFG_GLPI['use_notifications'] == '0') {
$disabled = true;
}

echo "<tr>";
echo "<td>" . __s('Mentions configuration');
echo "<span class='ms-2 form-help'
data-bs-toggle='popover'
data-bs-placement='top'
data-bs-html='true'
data-bs-content='" . htmlspecialchars($description) . "'>
?
</span>";
echo "</td><td>";

echo Dropdown::showFromArray(
'use_mentions',
self::getMentionsLists($disabled),
[
'value' => $this->fields['use_mentions'],
'display' => false,
'disabled' => $disabled
]
);

if ($disabled) {
$warning = __('Notifications must be enabled to activate mentions.');
RomainLvr marked this conversation as resolved.
Show resolved Hide resolved
echo "<span class='form-help ms-2' data-bs-toggle='popover' data-bs-placement='top' data-bs-html='true' data-bs-content='" . $warning . "'>";
echo "<i class='fas fa-exclamation-triangle text-danger'></i>";
echo "</span>";
}

echo "</td></tr>";

echo "</tbody>";
echo "</table>";
echo "</div>";

$matrix_options['title'] = _n('Validation', 'Validations', Session::getPluralNumber());
$this->displayRightsChoiceMatrix(self::getRightsForForm('central', 'tracking', 'validations'), $matrix_options);

Expand Down Expand Up @@ -4015,6 +4075,33 @@ public static function dropdownHelpdeskItemtypes($options)
return Dropdown::showFromArray($p['name'], $values, $p);
}

/**
* @return array<int, string>
**/
public static function getMentionsLists(bool $disabled): array
RomainLvr marked this conversation as resolved.
Show resolved Hide resolved
{
if ($disabled) {
return [
UserMention::USER_MENTION_DISABLED => __('Disabled'),
];
}

return [
UserMention::USER_MENTION_DISABLED => __('Disabled'),
UserMention::USER_MENTION_FULL => __('Full'),
UserMention::USER_MENTION_RESTRICTED => __('Restricted'),
];
}

/**
* @param $value
* @return string
*/
public static function getMentionsListName($value): string
RomainLvr marked this conversation as resolved.
Show resolved Hide resolved
{
return self::getMentionsLists(false)[$value] ?? NOT_AVAILABLE;
}

/**
* Check if user has given right.
*
Expand Down
Loading