# --
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --
package Kernel::System::FAQ::Category;
use strict;
use warnings;
use Kernel::System::VariableCheck qw(:all);
our @ObjectDependencies = (
'Kernel::System::Cache',
'Kernel::System::CustomerGroup',
'Kernel::System::DB',
'Kernel::System::Group',
'Kernel::System::Log',
'Kernel::System::Valid'
);
=head1 NAME
Kernel::System::FAQ::Category - sub module of Kernel::System::FAQ
=head1 DESCRIPTION
All FAQ category functions.
=head1 PUBLIC INTERFACE
=head2 CategoryAdd()
add a category
my $CategoryID = $FAQObject->CategoryAdd(
Name => 'CategoryA',
Comment => 'Some comment', # Optional
ParentID => 2, # Mandatory, but could be 0
ValidID => 1,
UserID => 1,
);
Returns:
$CategoryID = 34; # or undef if category could not be added
=cut
sub CategoryAdd {
my ( $Self, %Param ) = @_;
for my $Argument (qw(Name UserID ValidID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
if ( !defined $Param{ParentID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need ParentID!",
);
return;
}
# check that ParentID is not an empty string but number 0 is allowed
if ( $Param{ParentID} eq '' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "ParentID cannot be empty!",
);
return;
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# insert record
return if !$DBObject->Do(
SQL => '
INSERT INTO faq_category (name, parent_id, comments, valid_id, created, created_by,
changed, changed_by)
VALUES ( ?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)',
Bind => [
\$Param{Name}, \$Param{ParentID}, \$Param{Comment}, \$Param{ValidID},
\$Param{UserID}, \$Param{UserID},
],
);
# get new category id
return if !$DBObject->Prepare(
SQL => '
SELECT id
FROM faq_category
WHERE name = ? AND parent_id = ?',
Bind => [ \$Param{Name}, \$Param{ParentID} ],
Limit => 1,
);
my $CategoryID;
while ( my @Row = $DBObject->FetchrowArray() ) {
$CategoryID = $Row[0];
}
# log notice
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'notice',
Message => "FAQCategory: '$Param{Name}' CategoryID: '$CategoryID' "
. "created successfully ($Param{UserID})!",
);
return $CategoryID;
}
=head2 CategoryCount()
Count the number of categories.
my $CategoryCount = $FAQObject->CategoryCount(
ParentIDs => [ 1, 2, 3, 4 ],
UserID => 1,
);
Returns:
$CategoryCount = 6;
=cut
sub CategoryCount {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need UserID!',
);
return;
}
if ( !defined $Param{ParentIDs} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need ParentIDs!',
);
return;
}
# build SQL
my $SQL = '
SELECT COUNT(*)
FROM faq_category
WHERE valid_id IN ('
. join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet()
. ')';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# parent ids are given
if ( defined $Param{ParentIDs} ) {
# integer quote the parent ids
for my $ParentID ( @{ $Param{ParentIDs} } ) {
$ParentID = $DBObject->Quote( $ParentID, 'Integer' );
}
# create string
my $InString = join ', ', @{ $Param{ParentIDs} };
$SQL .= ' AND parent_id IN (' . $InString . ')';
}
# add group by
$SQL .= ' GROUP BY parent_id';
return if !$DBObject->Prepare(
SQL => $SQL,
Limit => 200,
);
my $Count = 0;
while ( my @Row = $DBObject->FetchrowArray() ) {
$Count = $Row[0];
}
return $Count;
}
=head2 CategoryDelete()
Delete a category.
my $DeleteSuccess = $FAQObject->CategoryDelete(
CategoryID => 123,
UserID => 1,
);
Returns:
DeleteSuccess = 1; # or undef if category could not be deleted
=cut
sub CategoryDelete {
my ( $Self, %Param ) = @_;
for my $Attribute (qw(CategoryID UserID)) {
if ( !$Param{$Attribute} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Attribute!",
);
return;
}
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# delete the category
return if !$DBObject->Do(
SQL => '
DELETE FROM faq_category
WHERE id = ?',
Bind => [ \$Param{CategoryID} ],
);
# delete the category groups
return if !$DBObject->Do(
SQL => '
DELETE FROM faq_category_group
WHERE category_id = ?',
Bind => [ \$Param{CategoryID} ],
);
return 1;
}
=head2 CategoryDuplicateCheck()
check a category for duplicate name under the same parent
my $Exists = $FAQObject->CategoryDuplicateCheck(
CategoryID => 1,
Name => 'Some Name',
ParentID => 1,
UserID => 1,
);
Returns:
$Exists = 1; # if category name already exists with the same parent
# or 0 if the name does not exists with the same parent
=cut
sub CategoryDuplicateCheck {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need UserID!",
);
return;
}
# set defaults
$Param{Name} //= '';
$Param{ParentID} ||= 0;
my @Values;
push @Values, \$Param{Name};
push @Values, \$Param{ParentID};
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# db quote
$Param{ParentID} = $DBObject->Quote( $Param{ParentID}, 'Integer' );
# build SQL
my $SQL = '
SELECT id
FROM faq_category
WHERE name = ?
AND parent_id = ?
';
if ( defined $Param{CategoryID} ) {
$SQL .= " AND id != ?";
push @Values, \$Param{CategoryID};
}
# prepare SQL statement
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => \@Values,
Limit => 1,
);
# fetch the result
my $Exists;
while ( my @Row = $DBObject->FetchrowArray() ) {
$Exists = 1;
}
return $Exists;
}
=head2 CategoryGet()
get a category as hash
my %Category = $FAQObject->CategoryGet(
CategoryID => 1,
UserID => 1,
);
Returns:
%Category = (,
CategoryID => 2,
ParentID => 0,
Name => 'My Category',
Comment => 'This is my first category.',
ValidID => 1,
);
=cut
sub CategoryGet {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need UserID!",
);
return;
}
if ( !defined $Param{CategoryID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need CategoryID!',
);
return;
}
# check cache
my $CacheKey = 'CategoryGet::' . $Param{CategoryID};
# get cache object
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
my $Cache = $CacheObject->Get(
Type => 'FAQ',
Key => $CacheKey,
);
return %{$Cache} if $Cache;
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# SQL
return if !$DBObject->Prepare(
SQL => '
SELECT id, parent_id, name, comments, valid_id
FROM faq_category
WHERE id = ?',
Bind => [ \$Param{CategoryID} ],
Limit => 1,
);
my %Data;
while ( my @Row = $DBObject->FetchrowArray() ) {
%Data = (
CategoryID => $Row[0],
ParentID => $Row[1],
Name => $Row[2],
Comment => $Row[3],
ValidID => $Row[4],
);
}
# cache result
$CacheObject->Set(
Type => 'FAQ',
Key => $CacheKey,
Value => \%Data,
TTL => 60 * 60 * 24 * 2,
);
return %Data;
}
=head2 CategoryGroupGet()
get groups of a category
my $GroupArrayRef = $FAQObject->CategoryGroupGet(
CategoryID => 3,
UserID => 1,
);
Returns:
$GroupArrayRef = [
2,
9,
10,
];
=cut
sub CategoryGroupGet {
my ( $Self, %Param ) = @_;
for my $Argument (qw(CategoryID UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# get groups
return if !$DBObject->Prepare(
SQL => '
SELECT group_id
FROM faq_category_group
WHERE category_id = ?',
Bind => [ \$Param{CategoryID} ],
);
my @Groups;
while ( my @Row = $DBObject->FetchrowArray() ) {
push @Groups, $Row[0];
}
return \@Groups;
}
=head2 CategoryGroupGetAll()
get all category-groups
my $AllCategoryGroupHashRef = $FAQObject->CategoryGroupGetAll(
UserID => 1,
);
Returns:
$AllCategoryGroupHashRef = {
1 => {
2 => 1,
},
2 => {
2 => 1,
9 => 1,
10 => 1,
},
3 => {
2 => 1,
9 => 1,
10 => 1,
},
4 => {
1 => 1,
2 => 1,
3 => 1,
4 => 1,
5 => 1,
9 => 1,
10 => 1,
},
};
=cut
sub CategoryGroupGetAll {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need UserID!",
);
return;
}
# check cache
if ( $Self->{Cache}->{CategoryGroupGetAll} ) {
return $Self->{Cache}->{CategoryGroupGetAll};
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# get groups
return if !$DBObject->Prepare(
SQL => '
SELECT group_id, category_id
FROM faq_category_group',
);
my %Groups;
while ( my @Row = $DBObject->FetchrowArray() ) {
$Groups{ $Row[1] }->{ $Row[0] } = 1;
}
# cache
$Self->{Cache}->{CategoryGroupGetAll} = \%Groups;
return \%Groups;
}
=head2 CategoryList()
get the category list as hash
my $CategoryHashRef = $FAQObject->CategoryList(
Valid => 1, # (optional)
UserID => 1,
);
Returns:
$CategoryHashRef = {
0 => {
1 => 'Misc',
2 => 'My Category',
},
2 => {
3 => 'Sub Category A',
4 => 'Sub Category B',
},
};
=cut
sub CategoryList {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need UserID!",
);
return;
}
# set default
my $Valid = 0;
if ( defined $Param{Valid} ) {
$Valid = $Param{Valid};
}
# check cache
if ( $Self->{Cache}->{CategoryList}->{$Valid} ) {
return $Self->{Cache}->{CategoryList}->{$Valid};
}
# build SQL
my $SQL = '
SELECT id, parent_id, name
FROM faq_category';
if ($Valid) {
# get the valid ids
$SQL .= ' WHERE valid_id IN ('
. join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet()
. ')';
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# prepare SQL statement
return if !$DBObject->Prepare( SQL => $SQL );
# fetch the result
my %Data;
while ( my @Row = $DBObject->FetchrowArray() ) {
$Data{ $Row[1] }->{ $Row[0] } = $Row[2];
}
# cache
$Self->{Cache}->{CategoryList}->{$Valid} = \%Data;
return \%Data;
}
=head2 CategorySearch()
get the category search as an array ref
my $CategoryIDArrayRef = $FAQObject->CategorySearch(
Name => 'Test',
ParentID => 3,
ParentIDs => [ 1, 3, 8 ],
CategoryIDs => [ 2, 5, 7 ],
OrderBy => 'Name',
SortBy => 'down',
UserID => 1,
);
Returns:
$CategoryIDArrayRef = [
2,
];
=cut
sub CategorySearch {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need UserID!",
);
return;
}
# SQL
my $SQL = '
SELECT id
FROM faq_category
WHERE valid_id IN ('
. join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet()
. ')';
my $Ext = '';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# search for name
if ( defined $Param{Name} ) {
# db like quote
$Param{Name} = $DBObject->Quote( $Param{Name}, 'Like' );
$Ext .= " AND name LIKE '%" . $Param{Name} . "%' $Self->{LikeEscapeString}";
}
# search for parent id
elsif ( defined $Param{ParentID} ) {
# db integer quote
$Param{ParentID} = $DBObject->Quote( $Param{ParentID}, 'Integer' );
$Ext .= ' AND parent_id = ' . $Param{ParentID};
}
# search for parent ids
elsif (
defined $Param{ParentIDs}
&& ref $Param{ParentIDs} eq 'ARRAY'
&& @{ $Param{ParentIDs} }
)
{
# integer quote the parent ids
for my $ParentID ( @{ $Param{ParentIDs} } ) {
$ParentID = $DBObject->Quote( $ParentID, 'Integer' );
}
# create string
my $InString = join ', ', @{ $Param{ParentIDs} };
$Ext = ' AND parent_id IN (' . $InString . ')';
}
# search for category ids
elsif (
defined $Param{CategoryIDs}
&& ref $Param{CategoryIDs} eq 'ARRAY'
&& @{ $Param{CategoryIDs} }
)
{
# integer quote the category ids
for my $CategoryID ( @{ $Param{CategoryIDs} } ) {
$CategoryID = $DBObject->Quote( $CategoryID, 'Integer' );
}
# create string
my $InString = join ', ', @{ $Param{CategoryIDs} };
$Ext = ' AND id IN (' . $InString . ')';
}
# ORDER BY
if ( $Param{OrderBy} ) {
$Ext .= " ORDER BY name";
# set the default sort order
$Param{SortBy} ||= 'up';
# SORT
if ( $Param{SortBy} ) {
if ( $Param{SortBy} eq 'up' ) {
$Ext .= " ASC";
}
elsif ( $Param{SortBy} eq 'down' ) {
$Ext .= " DESC";
}
}
}
# SQL STATEMENT
$SQL .= $Ext;
return if !$DBObject->Prepare(
SQL => $SQL,
Limit => 500,
);
my @List;
while ( my @Row = $DBObject->FetchrowArray() ) {
push @List, $Row[0];
}
return \@List;
}
=head2 CategorySubCategoryIDList()
get all subcategory ids of a category
my $SubCategoryIDArrayRef = $FAQObject->CategorySubCategoryIDList(
ParentID => 1,
Mode => 'Public', # (Agent, Customer, Public)
CustomerUser => 'tt',
UserID => 1,
);
Returns:
$SubCategoryIDArrayRef = [
3,
4,
5,
6,
];
=cut
sub CategorySubCategoryIDList {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need UserID!",
);
return;
}
if ( !defined $Param{ParentID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need ParentID!',
);
return;
}
my $Categories = {};
if ( $Param{Mode} && $Param{Mode} eq 'Agent' ) {
# get agents categories
$Categories = $Self->GetUserCategories(
Type => 'ro',
UserID => $Param{UserID},
);
}
elsif ( $Param{Mode} && $Param{Mode} eq 'Customer' ) {
# get customer categories
$Categories = $Self->GetCustomerCategories(
Type => 'ro',
CustomerUser => $Param{CustomerUser},
UserID => $Param{UserID},
);
}
else {
# get all categories
$Categories = $Self->CategoryList(
Valid => 1,
UserID => $Param{UserID},
);
}
my @SubCategoryIDs;
my @TempSubCategoryIDs = keys %{ $Categories->{ $Param{ParentID} } };
SUBCATEGORYID:
while (@TempSubCategoryIDs) {
# get next subcategory id
my $SubCategoryID = shift @TempSubCategoryIDs;
# add to result
push @SubCategoryIDs, $SubCategoryID;
# check if subcategory has own subcategories
next SUBCATEGORYID if !$Categories->{$SubCategoryID};
# add new subcategories
push @TempSubCategoryIDs, keys %{ $Categories->{$SubCategoryID} };
}
# sort subcategories numerically
@SubCategoryIDs = sort { $a <=> $b } @SubCategoryIDs;
return \@SubCategoryIDs;
}
=head2 CategoryTreeList()
get all categories as tree (with their long names)
my $CategoryTree = $FAQObject->CategoryTreeList(
Valid => 0, # (0|1, optional)
UserID => 1,
);
Returns:
$CategoryTree = {
1 => 'Misc',
2 => 'My Category',
3 => 'My Category::Sub Category A',
4 => 'My Category::Sub Category B',
};
=cut
sub CategoryTreeList {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need UserID!",
);
return;
}
# set default
my $Valid = 0;
if ( $Param{Valid} ) {
$Valid = $Param{Valid};
}
# check cache
if ( $Self->{Cache}->{GetCategoryTree}->{$Valid} ) {
return $Self->{Cache}->{GetCategoryTree}->{$Valid};
}
# build SQL
my $SQL = '
SELECT id, parent_id, name
FROM faq_category';
# add where clause for valid categories
if ($Valid) {
$SQL .= ' WHERE valid_id IN ('
. join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet()
. ')';
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# prepare SQL
return if !$DBObject->Prepare(
SQL => $SQL,
);
# fetch result
my %CategoryMap;
my %CategoryNameLookup;
my %ParentIDLookup;
while ( my @Row = $DBObject->FetchrowArray() ) {
$CategoryMap{ $Row[1] }->{ $Row[0] } = $Row[2];
$CategoryNameLookup{ $Row[0] } = $Row[2];
$ParentIDLookup{ $Row[0] } = $Row[1];
}
# to store the category tree
my %CategoryTree;
# check all parent IDs
for my $ParentID ( sort { $a <=> $b } keys %CategoryMap ) {
# get subcategories and names for this parent id
while ( my ( $CategoryID, $CategoryName ) = each %{ $CategoryMap{$ParentID} } ) {
# lookup the parents name
my $NewParentID = $ParentID;
while ($NewParentID) {
# pre-append parents category name
if ( $CategoryNameLookup{$NewParentID} ) {
$CategoryName = $CategoryNameLookup{$NewParentID} . '::' . $CategoryName;
}
# get up one parent level
$NewParentID = $ParentIDLookup{$NewParentID} || 0;
}
# add category to tree
$CategoryTree{$CategoryID} = $CategoryName;
}
}
# cache
$Self->{Cache}->{GetCategoryTree}->{$Valid} = \%CategoryTree;
return \%CategoryTree;
}
=head2 CategoryUpdate()
update a category
my $Success = $FAQObject->CategoryUpdate(
CategoryID => 2,
ParentID => 1,
Name => 'Some Category',
Comment => 'some comment',
UserID => 1,
);
Returns:
$Success = 1; # or undef if category could not be updated
=cut
sub CategoryUpdate {
my ( $Self, %Param ) = @_;
for my $Argument (qw(Name UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
for my $Argument (qw(CategoryID ParentID)) {
if ( !defined $Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
# check that ParentID is not an empty string but number 0 is allowed
if ( $Param{ParentID} eq '' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "ParentID cannot be empty!",
);
return;
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# SQL
return if !$DBObject->Do(
SQL => '
UPDATE faq_category
SET parent_id = ?, name = ?, comments = ?, valid_id = ?, changed = current_timestamp,
changed_by = ?
WHERE id = ?',
Bind => [
\$Param{ParentID}, \$Param{Name},
\$Param{Comment}, \$Param{ValidID},
\$Param{UserID}, \$Param{CategoryID},
],
);
# log notice
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'notice',
Message => "FAQCategory: '$Param{Name}' "
. "ID: '$Param{CategoryID}' updated successfully ($Param{UserID})!",
);
# delete all cache, as FAQGet() will be also affected.
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
Type => 'FAQ',
);
return 1;
}
=head2 AgentCategorySearch()
get the category search as array ref
my $CategoryIDArrayRef = $FAQObject->AgentCategorySearch(
ParentID => 3, # (optional, default 0)
GetSubCategories => 1, # (optional, default 0)
UserID => 1,
);
Returns:
$CategoryIDArrayRef = [
'4',
'8',
];
=cut
sub AgentCategorySearch {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need UserID!',
);
return;
}
# set default parent id
my $ParentID = $Param{ParentID} ? $Param{ParentID} : 0;
my $Categories = $Self->GetUserCategories(
Type => 'ro',
UserID => $Param{UserID},
);
return [] if !IsHashRefWithData($Categories);
my %Category = %{ $Categories->{$ParentID} };
my @CategoryIDs = sort { $Category{$a} cmp $Category{$b} } ( keys %Category );
return \@CategoryIDs if !$Param{GetSubCategories};
# Check if some IDs have a subcategory and add this also to the list.
for my $CategoryID (@CategoryIDs) {
# get all subcategory ids for this category
my $SubCategoryIDs = $Self->CategorySubCategoryIDList(
ParentID => $CategoryID,
Mode => 'Agent',
UserID => $Param{UserID},
);
# Add the sub categories to the category ids.
push @CategoryIDs, @{$SubCategoryIDs};
}
# Remove any duplicate IDs from the lest
my %Seen;
@CategoryIDs = grep { !$Seen{$_}++ } @CategoryIDs;
return \@CategoryIDs;
}
=head2 CustomerCategorySearch()
get the category search as hash
my $CategoryIDArrayRef = @{$FAQObject->CustomerCategorySearch(
CustomerUser => 'tt',
ParentID => 3, # (optional, default 0)
GetSubCategories => 1, # (optional, default 0)
Mode => 'Customer',
UserID => 1,
)};
Returns:
$CategoryIDArrayRef = [
'4',
'8',
];
=cut
sub CustomerCategorySearch {
my ( $Self, %Param ) = @_;
for my $Argument (qw(CustomerUser Mode UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
# set default parent id
my $ParentID = $Param{ParentID} ? $Param{ParentID} : 0;
my $Categories = $Self->GetCustomerCategories(
CustomerUser => $Param{CustomerUser},
Type => 'ro',
UserID => $Param{UserID},
);
my %Category = %{ $Categories->{$ParentID} };
my @CategoryIDs = sort { $Category{$a} cmp $Category{$b} } ( keys %Category );
my @AllowedCategoryIDs;
my %Articles;
# check cache
my $CacheKey = 'CustomerCategorySearch::Articles';
if ( $Self->{Cache}->{$CacheKey} ) {
%Articles = %{ $Self->{Cache}->{$CacheKey} };
}
else {
# build valid id string
my $ValidIDsString = join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
my $SQL = "
SELECT faq_item.id, faq_item.category_id
FROM faq_item, faq_state_type, faq_state
WHERE faq_state.id = faq_item.state_id
AND faq_state.type_id = faq_state_type.id
AND faq_state_type.name != 'internal'
AND faq_item.valid_id IN ($ValidIDsString)
AND faq_item.approved = 1";
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
return if !$DBObject->Prepare(
SQL => $SQL,
);
while ( my @Row = $DBObject->FetchrowArray() ) {
$Articles{ $Row[1] }++;
}
# cache
$Self->{Cache}->{$CacheKey} = \%Articles;
}
return \@CategoryIDs if !$Param{GetSubCategories};
for my $CategoryID (@CategoryIDs) {
# get all subcategory ids for this category
my $SubCategoryIDs = $Self->CategorySubCategoryIDList(
ParentID => $CategoryID,
Mode => $Param{Mode},
CustomerUser => $Param{CustomerUser},
UserID => $Param{UserID},
);
# add this category id
my @IDs = ( $CategoryID, @{$SubCategoryIDs} );
# check if category contains articles with state external or public
ID:
for my $ID (@IDs) {
next ID if !$Articles{$ID};
push @AllowedCategoryIDs, $ID;
}
}
return \@AllowedCategoryIDs;
}
=head2 PublicCategorySearch()
get the category search as hash
my $CategoryIDArrayRef = $FAQObject->PublicCategorySearch(
ParentID => 3, # (optional, default 0)
Mode => 'Public',
UserID => 1,
);
Returns:
$CategoryIDArrayRef = [
'4',
'8',
];
=cut
sub PublicCategorySearch {
my ( $Self, %Param ) = @_;
for my $Argument (qw(Mode UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
if ( !defined $Param{ParentID} ) {
$Param{ParentID} = 0;
}
my $CategoryListCategories = $Self->CategoryList(
Valid => 1,
UserID => $Param{UserID},
);
return [] if !$CategoryListCategories->{ $Param{ParentID} };
my %Category = %{ $CategoryListCategories->{ $Param{ParentID} } };
my @CategoryIDs = sort { $Category{$a} cmp $Category{$b} } ( keys %Category );
my @AllowedCategoryIDs;
# build valid id string
my $ValidIDsString = join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
for my $CategoryID (@CategoryIDs) {
# get all subcategory ids for this category
my $SubCategoryIDs = $Self->CategorySubCategoryIDList(
ParentID => $CategoryID,
Mode => $Param{Mode},
CustomerUser => $Param{CustomerUser},
UserID => $Param{UserID},
);
# add this category id
my @IDs = ( $CategoryID, @{$SubCategoryIDs} );
# check if category contains articles with state public
my $FoundArticle = 0;
my $SQL = "
SELECT faq_item.id
FROM faq_item, faq_state_type, faq_state
WHERE faq_item.category_id = ?
AND faq_item.valid_id IN ($ValidIDsString)
AND faq_state.id = faq_item.state_id
AND faq_state.type_id = faq_state_type.id
AND faq_state_type.name = 'public'
AND faq_item.approved = 1";
ID:
for my $ID (@IDs) {
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => [ \$ID ],
Limit => 1,
);
while ( my @Row = $DBObject->FetchrowArray() ) {
$FoundArticle = $Row[0];
}
last ID if $FoundArticle;
}
# an article was found
if ($FoundArticle) {
push @AllowedCategoryIDs, $CategoryID;
}
}
return \@AllowedCategoryIDs;
}
=head2 GetUserCategories()
get user category-groups
my $UserCategoryGroupHashRef = $FAQObject->GetUserCategories(
Type => 'rw',
UserID => 1,
);
Returns:
$UserCategoryGroupHashRef = {
1 => {},
0 => {
1 => 'Misc',
2 => 'My Category',
},
2 => {
3 => 'Sub Category A',
4 => 'Sub Category B',
},
3 => {},
4 => {},
};
=cut
sub GetUserCategories {
my ( $Self, %Param ) = @_;
for my $Argument (qw(Type UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
my $Categories = $Self->CategoryList(
Valid => 1,
UserID => $Param{UserID},
);
my $CategoryGroups = $Self->CategoryGroupGetAll(
UserID => $Param{UserID},
);
my %UserGroups = $Kernel::OM->Get('Kernel::System::Group')->GroupMemberList(
UserID => $Param{UserID},
Type => $Param{Type},
Result => 'HASH',
);
my $UserCategories = $Self->_UserCategories(
Categories => $Categories,
CategoryGroups => $CategoryGroups,
UserGroups => \%UserGroups,
UserID => $Param{UserID},
);
return $UserCategories;
}
=head2 GetUserCategoriesLongNames()
get user category-groups (show category long names)
my $UserCategoryGroupHashRef = $FAQObject->GetUserCategoriesLongNames(
Type => 'rw',
UserID => 1,
);
Returns:
$UserCategoryGroupHashRef = {
1 => 'Misc',
2 => 'My Category',
3 => 'My Category::Sub Category A',
4 => 'My Category::Sub Category A',
};
=cut
sub GetUserCategoriesLongNames {
my ( $Self, %Param ) = @_;
for my $Argument (qw(Type UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
# get categories where user has rights
my $UserCategories = $Self->GetUserCategories(
Type => $Param{Type},
UserID => $Param{UserID},
);
# get all categories with their long names
my $CategoryTree = $Self->CategoryTreeList(
Valid => 1,
UserID => $Param{UserID},
);
# to store the user categories with their long names
my %UserCategoriesLongNames;
# get the long names of the categories where user has rights
PARENTID:
for my $ParentID ( sort keys %{$UserCategories} ) {
next PARENTID if !$UserCategories->{$ParentID};
next PARENTID if ref $UserCategories->{$ParentID} ne 'HASH';
next PARENTID if !%{ $UserCategories->{$ParentID} };
for my $CategoryID ( sort keys %{ $UserCategories->{$ParentID} } ) {
$UserCategoriesLongNames{$CategoryID} = $CategoryTree->{$CategoryID};
}
}
return \%UserCategoriesLongNames;
}
=head2 GetCustomerCategories()
get customer user categories
my $CustomerUserCategoryHashRef = $FAQObject->GetCustomerCategories(
CustomerUser => 'hans',
Type => 'rw',
UserID => 1,
);
Returns:
$CustomerUserCategoryHashRef = {
1 => {},
0 => {
1 => 'Misc',
2 => 'My Category',
},
2 => {
3 => 'Sub Category A',
4 => 'Sub Category B',
},
3 => {},
4 => {},
};
=cut
sub GetCustomerCategories {
my ( $Self, %Param ) = @_;
for my $Argument (qw(CustomerUser Type UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
# check cache
my $CacheKey = 'GetCustomerCategories::CustomerUser::' . $Param{CustomerUser};
if ( defined $Self->{Cache}->{$CacheKey} ) {
return $Self->{Cache}->{$CacheKey};
}
# get all valid categories
my $Categories = $Self->CategoryList(
Valid => 1,
UserID => $Param{UserID},
);
my $CategoryGroups = $Self->CategoryGroupGetAll(
UserID => $Param{UserID},
);
my %UserGroups = $Kernel::OM->Get('Kernel::System::CustomerGroup')->GroupMemberList(
UserID => $Param{CustomerUser},
Type => 'ro',
Result => 'HASH',
);
my $CustomerCategories = $Self->_UserCategories(
Categories => $Categories,
CategoryGroups => $CategoryGroups,
UserGroups => \%UserGroups,
UserID => $Param{UserID},
);
# cache
$Self->{Cache}->{$CacheKey} = $CustomerCategories;
return $CustomerCategories;
}
=head2 GetCustomerCategoriesLongNames()
get customer category-groups (show category long names)
my $CustomerCategoryGroupHashRef = $FAQObject->GetCustomerCategoriesLongNames(
CustomerUser => 'hans',
Type => 'rw',
UserID => 1,
);
Returns:
$CustomerCategoryGroupHashRef = {
1 => 'Misc',
2 => 'My Category',
3 => 'My Category::Sub Category A',
4 => 'My Category::Sub Category A',
};
=cut
sub GetCustomerCategoriesLongNames {
my ( $Self, %Param ) = @_;
for my $Argument (qw(CustomerUser Type UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
# get categories where user has rights
my $CustomerCategories = $Self->GetCustomerCategories(
CustomerUser => $Param{CustomerUser},
Type => $Param{Type},
UserID => $Param{UserID},
);
# extract category ids
my %AllCategoryIDs;
for my $ParentID ( sort keys %{$CustomerCategories} ) {
for my $CategoryID ( sort keys %{ $CustomerCategories->{$ParentID} } ) {
$AllCategoryIDs{$CategoryID} = 1;
}
}
# get all customer category ids
my @CustomerCategoryIDs;
for my $CategoryID ( 0, keys %AllCategoryIDs ) {
push @CustomerCategoryIDs, @{
$Self->CustomerCategorySearch(
ParentID => $CategoryID,
CustomerUser => $Param{CustomerUser},
Mode => 'Customer',
UserID => $Param{UserID},
)
};
}
# build customer category hash
$CustomerCategories = {};
for my $CategoryID (@CustomerCategoryIDs) {
my %Category = $Self->CategoryGet(
CategoryID => $CategoryID,
UserID => $Param{UserID},
);
$CustomerCategories->{ $Category{ParentID} }->{ $Category{CategoryID} } = $Category{Name};
}
# get all categories with their long names
my $CategoryTree = $Self->CategoryTreeList(
Valid => 1,
UserID => $Param{UserID},
);
# to store the user categories with their long names
my %CustomerCategoriesLongNames;
# get the long names of the categories where user has rights
PARENTID:
for my $ParentID ( sort keys %{$CustomerCategories} ) {
next PARENTID if !$CustomerCategories->{$ParentID};
next PARENTID if ref $CustomerCategories->{$ParentID} ne 'HASH';
next PARENTID if !%{ $CustomerCategories->{$ParentID} };
for my $CategoryID ( sort keys %{ $CustomerCategories->{$ParentID} } ) {
$CustomerCategoriesLongNames{$CategoryID} = $CategoryTree->{$CategoryID};
}
}
return \%CustomerCategoriesLongNames;
}
=head2 GetPublicCategoriesLongNames()
get public category-groups (show category long names)
my $PublicCategoryGroupHashRef = $FAQObject->GetPublicCategoriesLongNames(
Type => 'rw',
UserID => 1,
);
Returns:
$PublicCategoryGroupHashRef = {
1 => 'Misc',
2 => 'My Category',
3 => 'My Category::Sub Category A',
4 => 'My Category::Sub Category A',
};
=cut
sub GetPublicCategoriesLongNames {
my ( $Self, %Param ) = @_;
for my $Argument (qw(Type UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
# get all categories
my $PublicCategories = $Self->CategoryList( UserID => $Param{UserID} );
# extract category ids
my %AllCategoryIDs;
for my $ParentID ( sort keys %{$PublicCategories} ) {
for my $CategoryID ( sort keys %{ $PublicCategories->{$ParentID} } ) {
$AllCategoryIDs{$CategoryID} = 1;
}
}
# get all public category ids
my @PublicCategoryIDs;
for my $CategoryID ( 0, keys %AllCategoryIDs ) {
push @PublicCategoryIDs, @{
$Self->PublicCategorySearch(
ParentID => $CategoryID,
Mode => 'Public',
UserID => $Param{UserID},
)
};
}
# build public category hash
$PublicCategories = {};
for my $CategoryID (@PublicCategoryIDs) {
my %Category = $Self->CategoryGet(
CategoryID => $CategoryID,
UserID => $Param{UserID},
);
$PublicCategories->{ $Category{ParentID} }->{ $Category{CategoryID} } = $Category{Name};
}
# get all categories with their long names
my $CategoryTree = $Self->CategoryTreeList(
Valid => 1,
UserID => $Param{UserID},
);
# to store the user categories with their long names
my %PublicCategoriesLongNames;
# get the long names of the categories where user has rights
PARENTID:
for my $ParentID ( sort keys %{$PublicCategories} ) {
next PARENTID if !$PublicCategories->{$ParentID};
next PARENTID if ref $PublicCategories->{$ParentID} ne 'HASH';
next PARENTID if !%{ $PublicCategories->{$ParentID} };
for my $CategoryID ( sort keys %{ $PublicCategories->{$ParentID} } ) {
$PublicCategoriesLongNames{$CategoryID} = $CategoryTree->{$CategoryID};
}
}
return \%PublicCategoriesLongNames;
}
=head2 CheckCategoryUserPermission()
get user permission for a category
my $PermissionString = $FAQObject->CheckCategoryUserPermission(
CategoryID => '123',
Type => 'rw', # (optional) rw or ro, default ro
UserID => 1,
);
Returns:
$PermissionString = 'rw'; # or 'ro' or ''
=cut
sub CheckCategoryUserPermission {
my ( $Self, %Param ) = @_;
for my $Argument (qw(CategoryID UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
if ( !$Param{Type} ) {
$Param{Type} = 'ro';
}
$Param{Type} = lc $Param{Type};
if ( $Param{Type} ne 'rw' && $Param{Type} ne 'ro' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Type is invalid!",
);
}
my $UserCategories = $Self->GetUserCategories(
Type => $Param{Type},
UserID => $Param{UserID},
);
for my $ParentID ( sort keys %{$UserCategories} ) {
my $Categories = $UserCategories->{$ParentID};
for my $CategoryID ( sort keys %{$Categories} ) {
if ( $CategoryID == $Param{CategoryID} ) {
return $Param{Type};
}
}
}
return '';
}
=head2 CheckCategoryCustomerPermission()
get customer user permission for a category
my $PermissionString $FAQObject->CheckCategoryCustomerPermission(
CustomerUser => 'mm',
CategoryID => '123',
UserID => 1,
);
Returns:
$PermissionString = 'rw'; # or 'ro' or ''
=cut
sub CheckCategoryCustomerPermission {
my ( $Self, %Param ) = @_;
for my $Argument (qw(CustomerUser CategoryID UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
for my $Permission (qw(rw ro)) {
my $CustomerCategories = $Self->GetCustomerCategories(
CustomerUser => $Param{CustomerUser},
Type => 'ro',
UserID => $Param{UserID},
);
for my $ParentID ( sort keys %{$CustomerCategories} ) {
my $Categories = $CustomerCategories->{$ParentID};
for my $CategoryID ( sort keys %{$Categories} ) {
if ( $CategoryID == $Param{CategoryID} ) {
return $Permission;
}
}
}
}
return '';
}
=head2 SetCategoryGroup()
set groups to a category
my $Success = $FAQObject->SetCategoryGroup(
CategoryID => 3,
GroupIDs => [ 2,4,1,5,77 ],
UserID => 1,
);
Returns:
$Success = 1; # or undef if groups could not be set to a category
=cut
sub SetCategoryGroup {
my ( $Self, %Param ) = @_;
for my $Argument (qw(CategoryID GroupIDs UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# delete old groups
return if !$DBObject->Do(
SQL => '
DELETE FROM faq_category_group
WHERE category_id = ?',
Bind => [ \$Param{CategoryID} ],
);
# insert groups
$Param{CategoryID} = $DBObject->Quote( $Param{CategoryID}, 'Integer' );
for my $GroupID ( @{ $Param{GroupIDs} } ) {
# db quote
$GroupID = $DBObject->Quote( $GroupID, 'Integer' );
my $SQL = "
INSERT INTO faq_category_group (category_id, group_id, changed, changed_by, created,
created_by)
VALUES ($Param{CategoryID}, $GroupID, current_timestamp, $Param{UserID},
current_timestamp, $Param{UserID})";
# write attachment to db
return if !$DBObject->Do( SQL => $SQL );
}
return 1;
}
=head1 PRIVATE FUNCTIONS
=head2 _UserCategories()
reduces the categories ( from CategoryList() ) to only the ones where the user has privileges.
my $UserCategories = $FAQObject->_UserCategories(
Categories => $CategoryHashRef, # as returned form CategoryList()
CategoryGroups => $CategoryGroupHashRef, # as returned from CategoryGroupGetAll
UserGroups => $UserGroupsHashRef,
UserID => 123,
);
Returns:
$UserCategoies = {
0 => {
1 => 'Misc',
2 => 'My Category',
},
2 => {
3 => 'Sub Category A',
},
};
=cut
sub _UserCategories {
my ( $Self, %Param ) = @_;
for my $Argument (qw(Categories UserID)) {
if ( !$Param{$Argument} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Argument!",
);
return;
}
}
my %UserCategories;
PARENTID:
for my $ParentID ( sort { $a <=> $b } keys %{ $Param{Categories} } ) {
my %SubCategories;
CATEGORYID:
for my $CategoryID ( sort keys %{ $Param{Categories}->{$ParentID} } ) {
# check category groups
next CATEGORYID if !defined $Param{CategoryGroups}->{$CategoryID};
# check user groups
GROUPID:
for my $GroupID ( sort keys %{ $Param{CategoryGroups}->{$CategoryID} } ) {
next GROUPID if !defined $Param{UserGroups}->{$GroupID};
# add category
$SubCategories{$CategoryID} = $Param{Categories}->{$ParentID}->{$CategoryID};
# add empty hash if category has no subcategories
if ( !$UserCategories{$CategoryID} ) {
$UserCategories{$CategoryID} = {};
}
last GROUPID;
}
}
$UserCategories{$ParentID} = \%SubCategories;
}
return \%UserCategories;
}
1;
=head1 TERMS AND CONDITIONS
This software is part of the OTRS project (L).
This software comes with ABSOLUTELY NO WARRANTY. For details, see
the enclosed file COPYING for license information (GPL). If you
did not receive this file, see L.
=cut