Skip to content

Commit

Permalink
Fix FAQ/KB (#12922)
Browse files Browse the repository at this point in the history
* Fix FAQ/KB

* Fix tests (mariadb)

* Apply suggestions from code review

Co-authored-by: Cédric Anne <cedric.anne@gmail.com>

* Iterable

Co-authored-by: Cédric Anne <cedric.anne@gmail.com>
  • Loading branch information
AdrienClairembault and cedric-anne authored Oct 12, 2022
1 parent 9f6bba5 commit 9a4fda5
Show file tree
Hide file tree
Showing 2 changed files with 517 additions and 77 deletions.
278 changes: 201 additions & 77 deletions src/KnowbaseItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -572,22 +572,66 @@ public static function getVisibilityCriteria(bool $forceall = false): array
{
global $CFG_GLPI;

// Build common JOIN clause
$criteria = [
'LEFT JOIN' => self::getVisibilityCriteriaCommonJoin($forceall),
];

// Handle anonymous users
if (!Session::getLoginUserID()) {
if ($CFG_GLPI["use_public_faq"]) {
// Public FAQ is enabled; show FAQ
$criteria['WHERE'] = self::getVisibilityCriteriaFAQ();
return $criteria;
} else {
// Public FAQ is disabled; show nothing
$criteria['WHERE'] = [0];
return $criteria;
}
}

// Handle logged in users
if (Session::getCurrentInterface() == "helpdesk") {
// Show FAQ for helpdesk user
$criteria['WHERE'] = self::getVisibilityCriteriaFAQ();
return $criteria;
} else {
// Show knowledge base for central users
$criteria['WHERE'] = self::getVisibilityCriteriaKB();
return $criteria;
}
}

/**
* Common JOIN clause used by getVisibilityCriteria* methods
*
* @param bool $forceall Force all join ?
*
* @return array LEFT JOIN clause
*/
private static function getVisibilityCriteriaCommonJoin(bool $forceall = false)
{
global $CFG_GLPI;

$join = [];

// Context checks - avoid doing unnecessary join if possible
$is_public_faq_context = !Session::getLoginUserID() && $CFG_GLPI["use_public_faq"];
$has_session_groups = isset($_SESSION["glpigroups"]) && count($_SESSION["glpigroups"]);
$has_active_profile = isset($_SESSION["glpiactiveprofile"])
&& isset($_SESSION["glpiactiveprofile"]['id']);
$has_active_entity = isset($_SESSION["glpiactiveentities"])
&& count($_SESSION["glpiactiveentities"]);

$where = [];
$join = [
'glpi_knowbaseitems_users' => [
$has_session_groups = count(($_SESSION["glpigroups"] ?? []));
$has_active_profile = isset($_SESSION["glpiactiveprofile"]['id']);
$has_active_entity = count(($_SESSION["glpiactiveentities"] ?? []));

// Add user restriction data
if ($forceall || Session::getLoginUserID()) {
$join['glpi_knowbaseitems_users'] = [
'ON' => [
'glpi_knowbaseitems_users' => 'knowbaseitems_id',
'glpi_knowbaseitems' => 'id'
]
]
];
];
}

// Add group restriction data
if ($forceall || $has_session_groups) {
$join['glpi_groups_knowbaseitems'] = [
'ON' => [
Expand All @@ -596,6 +640,8 @@ public static function getVisibilityCriteria(bool $forceall = false): array
]
];
}

// Add profile restriction data
if ($forceall || $has_active_profile) {
$join['glpi_knowbaseitems_profiles'] = [
'ON' => [
Expand All @@ -604,6 +650,8 @@ public static function getVisibilityCriteria(bool $forceall = false): array
]
];
}

// Add entity restriction data
if ($forceall || $has_active_entity || $is_public_faq_context) {
$join['glpi_entities_knowbaseitems'] = [
'ON' => [
Expand All @@ -613,81 +661,157 @@ public static function getVisibilityCriteria(bool $forceall = false): array
];
}

if (Session::haveRight(self::$rightname, self::KNOWBASEADMIN)) {
return [
'LEFT JOIN' => $join,
'WHERE' => [],
];
}
return $join;
}

// Users
if (Session::getLoginUserID()) {
$where['OR'] = [
'glpi_knowbaseitems.users_id' => Session::getLoginUserID(),
'glpi_knowbaseitems_users.users_id' => Session::getLoginUserID(),
'glpi_knowbaseitems.is_faq' => 1,
];
} else if ($is_public_faq_context) {
$where = [
"glpi_knowbaseitems.is_faq" => 1,
];
if (Session::isMultiEntitiesMode()) {
$where += [
"glpi_entities_knowbaseitems.entities_id" => 0,
"glpi_entities_knowbaseitems.is_recursive" => 1,
];
}
} else {
$where = [
0
];
}
// Groups
if ($forceall || $has_session_groups) {
if (Session::getLoginUserID()) {
$restrict = getEntitiesRestrictCriteria('glpi_groups_knowbaseitems', '', '', true, true);
$where['OR'][] = [
'glpi_groups_knowbaseitems.groups_id' => count($_SESSION["glpigroups"])
? $_SESSION["glpigroups"]
: [-1],
'OR' => [
'glpi_groups_knowbaseitems.no_entity_restriction' => 1,
] + $restrict
];
}
/**
* Get visibility criteria for articles displayed in the FAQ (seen by
* helpdesk and anonymous users)
* This mean any KB article tagged as 'is_faq' should be displayed
*
* @return array WHERE clause
*/
private static function getVisibilityCriteriaFAQ(): array
{
$where = ['is_faq' => 1];

// Specific case for anonymous users + multi entities
if (!Session::getLoginUserID() && Session::isMultiEntitiesMode()) {
$where[Entity_KnowbaseItem::getTableField('entities_id')] = 0;
$where[Entity_KnowbaseItem::getTableField('is_recursive')] = 1;
}

// Profiles
if ($forceall || $has_active_profile) {
if (Session::getLoginUserID()) {
$where['OR'][] = [
'glpi_knowbaseitems_profiles.profiles_id' => $_SESSION["glpiactiveprofile"]['id'],
'OR' => [
'glpi_knowbaseitems_profiles.no_entity_restriction' => 1,
getEntitiesRestrictCriteria('glpi_knowbaseitems_profiles', '', '', true, true)
]
];
}
return $where;
}

/**
* Get visibility criteria for articles displayed in the knowledge base
* (seen by central users)
* This mean any KB article with valid visibility criteria for the current
* user should be displayed
*
* @return array WHERE clause
*/
private static function getVisibilityCriteriaKB(): array
{
// Special case for KB Admins
if (Session::haveRight(self::$rightname, self::KNOWBASEADMIN)) {
// See all articles
return [1];
}

// Entities
if ($forceall || $has_active_entity) {
if (Session::getLoginUserID()) {
$restrict = getEntitiesRestrictCriteria('glpi_entities_knowbaseitems', '', '', true, true);
if (count($restrict)) {
$where['OR'] = $where['OR'] + $restrict;
} else {
$where['glpi_entities_knowbaseitems.entities_id'] = null;
}
}
// Prepare criteria, which will use an OR statement (the user can read
// the article if any of the user/group/profile/entity criteria are
// validated)
$where = ['OR' => []];

// Special case: the user may be the article's author
$user = Session::getLoginUserID();
$author_check = [self::getTableField('users_id') => $user];
$where['OR'][] = $author_check;

// Filter on users
$where['OR'][] = self::getVisibilityCriteriaKB_User();

// Filter on groups (if the current user have any)
$groups = $_SESSION["glpigroups"] ?? [];
if (count($groups)) {
$where['OR'][] = self::getVisibilityCriteriaKB_Group();
}

$criteria = ['LEFT JOIN' => $join];
if (count($where)) {
$criteria['WHERE'] = $where;
// Filter on profiles
$where['OR'][] = self::getVisibilityCriteriaKB_Profile();

// Filter on entities
$where['OR'][] = self::getVisibilityCriteriaKB_Entity();

return $where;
}

/**
* Get criteria used to filter knowledge base articles on users
*
* @return array
*/
private static function getVisibilityCriteriaKB_User(): array
{
$user = Session::getLoginUserID();
return [
KnowbaseItem_User::getTableField('users_id') => $user,
];
}

/**
* Get criteria used to filter knowledge base articles on groups
*
* @return array
*/
private static function getVisibilityCriteriaKB_Group(): array
{
$groups = $_SESSION["glpigroups"] ?? [-1];
$entity_restriction = getEntitiesRestrictCriteria(
Group_KnowbaseItem::getTable(),
'',
'',
true,
true
);

return [
Group_KnowbaseItem::getTableField('groups_id') => $groups,
'OR' => [
Group_KnowbaseItem::getTableField('no_entity_restriction') => 1,
] + $entity_restriction,
];
}

/**
* Get criteria used to filter knowledge base articles on profiles
*
* @return array
*/
private static function getVisibilityCriteriaKB_Profile(): array
{
$profile = $_SESSION["glpiactiveprofile"]['id'] ?? -1;
$entity_restriction = getEntitiesRestrictCriteria(
KnowbaseItem_Profile::getTable(),
'',
'',
true,
true
);

return [
KnowbaseItem_Profile::getTableField('profiles_id') => $profile,
'OR' => [
KnowbaseItem_Profile::getTableField('no_entity_restriction') => 1,
] + $entity_restriction,
];
}

/**
* Get criteria used to filter knowledge base articles on entity
*
* @return array
*/
private static function getVisibilityCriteriaKB_Entity(): array
{
$entity_restriction = getEntitiesRestrictCriteria(
Entity_KnowbaseItem::getTable(),
'',
'',
true,
true
);

// All entities
if (!count($entity_restriction)) {
$entity_restriction = [
Entity_KnowbaseItem::getTableField('entities_id') => null
];
}

return $criteria;
return $entity_restriction;
}

public function prepareInputForAdd($input)
Expand Down
Loading

0 comments on commit 9a4fda5

Please sign in to comment.