Article#
NAME#
Kernel::System::Ticket::Article - functions to manage ticket articles
DESCRIPTION#
Since OTRS 6, article data is split in a neutral part for all articles (in the article
database table),
and back end specific data in custom tables (such as article_data_mime
for the MIME
based back ends).
This class only manages back end neutral article data, like listing articles with ArticleList() or manipulating article metadata like ArticleFlagSet().
For all operations involving back end specific article data (like ArticleCreate
and ArticleGet
),
please call BackendForArticle() or BackendForChannel() to get to the correct article back end.
See ArticleList() for an example of looping over all article data of a ticket.
See Kernel::System::Ticket::Article::Backend::Base for the definition of the basic interface of all article back ends.
PUBLIC INTERFACE#
new()#
Don’t use the constructor directly, use the ObjectManager instead:
my $ArticleObject = $Kernel::OM->Get('Kernel::System::Ticket::Article');
BackendForArticle()#
Returns the correct back end for a given article, or the Invalid back end, so that you can always expect a back end object instance that can be used for chain-calling.
my $ArticleBackendObject = $ArticleObject->BackendForArticle( TicketID => 42, ArticleID => 123 );
Alternatively, you can pass in a hash with base article data as returned by ArticleList(), this will avoid the
lookup for the CommunicationChannelID
of the article:
my $ArticleBackendObject = $ArticleObject->BackendForArticle( %BaseArticle );
See Kernel::System::Ticket::Article::Backend::Base for the definition of the basic interface of all article back ends.
BackendForChannel()#
Returns the correct back end for a given communication channel, or the Invalid
back end, so that you can always expect
a back end object instance that can be used for chain-calling.
my $ArticleBackendObject = $ArticleObject->BackendForChannel( ChannelName => 'Email' );
See Kernel::System::Ticket::Article::Backend::Base for the definition of the basic interface of all article back ends.
ArticleList()#
Returns an filtered array of base article data for a ticket.
my @Articles = $ArticleObject->ArticleList(
TicketID => 123,
# Optional filters, these can be combined:
ArticleID => 234, # optional, limit to one article (if present on a ticket)
CommunicationChannel => 'Email', # optional, to limit to a certain CommunicationChannel
CommunicationChannelID => 2, # optional, to limit to a certain CommunicationChannelID
SenderType => 'customer', # optional, to limit to a certain article SenderType
SenderTypeID => 2, # optional, to limit to a certain article SenderTypeID
IsVisibleForCustomer => 0, # optional, to limit to a certain visibility
# After filtering, you can also limit to first or last found article only:
OnlyFirst => 0, # optional, only return first match
OnlyLast => 0, # optional, only return last match
);
Returns a list with base article data (no back end related data included):
(
{
ArticleID => 1,
TicketID => 2,
ArticleNumber => 1, # sequential number of article in the ticket
CommunicationChannelID => 1,
SenderTypeID => 1,
IsVisibleForCustomer => 0,
CreateBy => 1,
CreateTime => '2017-03-01 00:00:00',
ChangeBy => 1,
ChangeTime => '2017-03-01 00:00:00',
},
{ ... }
)
Please note that you need to use ArticleGet() via the article backend objects to access the full backend-specific article data hash for each article.
for my $MetaArticle (@Articles) {
my %Article = $ArticleObject->BackendForArticle( %{$MetaArticle} )->ArticleGet( %{$MetaArticle} );
}
TicketIDLookup()#
Get a ticket ID for supplied article ID.
my $TicketID = $ArticleObject->TicketIDLookup(
ArticleID => 123, # required
);
Returns ID of a ticket that article belongs to:
$TicketID = 123;
NOTE: Usage of this lookup function is strongly discouraged, since its result is not cached.
Where possible, use ArticleList()
instead.
ArticleFlagSet()#
Set article flags.
my $Success = $ArticleObject->ArticleFlagSet(
TicketID => 123,
ArticleID => 123,
Key => 'Seen',
Value => 1,
UserID => 123,
);
- Events:
ArticleFlagSet
ArticleFlagDelete()#
Delete an article flag.
my $Success = $ArticleObject->ArticleFlagDelete(
TicketID => 123,
ArticleID => 123,
Key => 'seen',
UserID => 123,
);
my $Success = $ArticleObject->ArticleFlagDelete(
TicketID => 123,
ArticleID => 123,
Key => 'seen',
AllUsers => 1, # delete for all users
);
- Events:
ArticleFlagDelete
ArticleFlagGet()#
Get article flags.
my %Flags = $ArticleObject->ArticleFlagGet(
ArticleID => 123,
UserID => 123,
);
ArticleFlagsOfTicketGet()#
Get all article flags of a ticket.
my %Flags = $ArticleObject->ArticleFlagsOfTicketGet(
TicketID => 123,
UserID => 123,
);
returns (
123 => { # ArticleID
'Seen' => 1,
'Other' => 'something',
},
)
ArticleAccountedTimeGet()#
Returns the accounted time of a article.
my $AccountedTime = $ArticleObject->ArticleAccountedTimeGet(
ArticleID => $ArticleID,
);
ArticleAccountedTimeDelete()#
Delete accounted time of an article.
my $Success = $ArticleObject->ArticleAccountedTimeDelete(
ArticleID => $ArticleID,
);
ArticleSenderTypeList()#
List all article sender types.
my %ArticleSenderTypeList = $ArticleObject->ArticleSenderTypeList();
Returns:
(
1 => 'agent',
2 => 'customer',
3 => 'system',
)
ArticleSenderTypeLookup()#
Lookup an article sender type id or name.
my $SenderTypeID = $ArticleObject->ArticleSenderTypeLookup(
SenderType => 'customer', # customer|system|agent
);
my $SenderType = $ArticleObject->ArticleSenderTypeLookup(
SenderTypeID => 1,
);
ArticleSearchIndexRebuildFlagSet()#
Set the article flags to indicate if the article search index needs to be rebuilt.
my $Success = $ArticleObject->ArticleSearchIndexRebuildFlagSet(
ArticleIDs => [ 123, 234, 345 ] # (Either 'ArticleIDs' or 'All' must be provided) The ArticleIDs to be updated.
All => 1, # (Either 'ArticleIDs' or 'All' must be provided) Set all articles to $Value. Default: 0,
Value => 1, # 0/1 default 0
);
ArticleSearchIndexRebuildFlagList()#
Get a list of ArticleIDs and TicketIDs for a given flag (either needs rebuild or not)
my %ArticleTicketIDs = $ArticleObject->ArticleSearchIndexRebuildFlagList(
Value => 1, # (optional) 0/1 default 0
Limit => 10000, # (optional) default: 20000
);
Returns:
%ArticleIDs = (
1 => 2, # ArticleID => TicketID
3 => 4,
5 => 6,
# ...
);
ArticleSearchIndexStatus()#
gets an article indexing status hash.
my %Status = $ArticleObject->ArticleSearchIndexStatus();
Returns:
%Status = (
ArticlesTotal => 443,
ArticlesIndexed => 420,
ArticlesNotIndexed => 23,
);
ArticleSearchIndexBuild()#
Rebuilds the current article search index table content. Existing article entries will be replaced.
my $Success = $ArticleObject->ArticleSearchIndexBuild(
TicketID => 123,
ArticleID => 123,
UserID => 1,
);
Returns:
True if indexing process was successfully finished, False if not.
ArticleSearchIndexDelete()#
Deletes entries from the article search index table base on supplied ArticleID
or TicketID
.
my $Success = $ArticleObject->ArticleSearchIndexDelete(
ArticleID => 123, # required, deletes search index for single article
# or
TicketID => 123, # required, deletes search index for all ticket articles
UserID => 1, # required
);
Returns:
True if delete process was successfully finished, False if not.
ArticleSearchIndexSQLJoinNeeded()#
Checks the given search parameters for used article backend fields.
my $Needed = $ArticleObject->ArticleSearchIndexSQLJoinNeeded(
SearchParams => {
# ...
ConditionInline => 1,
ContentSearchPrefix => '*',
ContentSearchSuffix => '*',
MIMEBase_From => '%spam@example.com%',
MIMEBase_To => '%service@example.com%',
MIMEBase_Cc => '%client@example.com%',
MIMEBase_Subject => '%VIRUS 32%',
MIMEBase_Body => '%VIRUS 32%',
MIMEBase_AttachmentName => '%anyfile.txt%',
# ...
},
);
Returns:
True if article search index usage is needed, False if not.
ArticleSearchIndexSQLJoin()#
Generates SQL string extensions, including the needed table joins for the article index search.
my $SQLExtenion = $ArticleObject->ArticleSearchIndexSQLJoin(
SearchParams => {
# ...
ConditionInline => 1,
ContentSearchPrefix => '*',
ContentSearchSuffix => '*',
MIMEBase_From => '%spam@example.com%',
MIMEBase_To => '%service@example.com%',
MIMEBase_Cc => '%client@example.com%',
MIMEBase_Subject => '%VIRUS 32%',
MIMEBase_Body => '%VIRUS 32%',
MIMEBase_AttachmentName => '%anyfile.txt%',
# ...
},
);
Returns:
$SQLExtension = 'LEFT JOIN article_search_index ArticleFulltext ON art.id = ArticleFulltext.article_id ';
ArticleSearchIndexWhereCondition()#
Generates SQL query conditions for the used article fields, that may be used in the WHERE clauses of main SQL queries to the database.
my $SQLExtenion = $ArticleObject->ArticleSearchIndexWhereCondition(
SearchParams => {
# ...
ConditionInline => 1,
ContentSearchPrefix => '*',
ContentSearchSuffix => '*',
MIMEBase_From => '%spam@example.com%',
MIMEBase_To => '%service@example.com%',
MIMEBase_Cc => '%client@example.com%',
MIMEBase_Subject => '%VIRUS 32%',
MIMEBase_Body => '%VIRUS 32%',
MIMEBase_AttachmentName => '%anyfile.txt%',
# ...
},
);
Returns:
$SQLConditions = " AND (MIMEBase_From.article_value LIKE '%spam@example.com%') ";
SearchStringStopWordsFind()#
Find stop words within given search string.
my $StopWords = $ArticleObject->SearchStringStopWordsFind(
SearchStrings => {
'Fulltext' => '(this AND is) OR test',
'MIMEBase_From' => 'myself',
},
);
Returns Hashref with found stop words.
SearchStringStopWordsUsageWarningActive()#
Checks if warnings for stop words in search strings are active or not.
my $WarningActive = $ArticleObject->SearchStringStopWordsUsageWarningActive();
ArticleSearchableFieldsList()#
Get list of searchable fields across all article backends.
my %SearchableFields = $ArticleObject->ArticleSearchableFieldsList();
Returns:
%SearchableFields = (
'MIMEBase_Body' => {
Filterable => 1,
Key => 'MIMEBase_Body',
Label => 'Body',
Type => 'Text',
},
'MIMEBase_Subject' => {
Filterable => 1,
Key => 'MIMEBase_Subject',
Label => 'Subject',
Type => 'Text',
},
# ...
);
PRIVATE FUNCTIONS#
_MetaArticleList()#
Returns an array-hash with the meta articles of the current ticket.
my @MetaArticles = $ArticleObject->_MetaArticleList(
TicketID => 123,
);
Returns:
(
{
ArticleID => 1,
TicketID => 2,
ArticleNumber => 1, # sequential number of article in the ticket
CommunicationChannelID => 1,
SenderTypeID => 1,
IsVisibleForCustomer => 0,
CreateBy => 1,
CreateTime => '2017-03-01 00:00:00',
ChangeBy => 1,
ChangeTime => '2017-03-01 00:00:00',
},
{ ... },
)
_ArticleCacheClear()#
Removes all article caches related to specified ticket.
my $Success = $ArticleObject->_ArticleCacheClear(
TicketID => 123,
);
ArticleIndex()#
returns an array with article IDs
my @ArticleIDs = $ArticleObject->ArticleIndex(
TicketID => 123,
);
my @ArticleIDs = $ArticleObject->ArticleIndex(
SenderType => 'customer', # optional, to limit to a certain sender type
TicketID => 123,
);
ArticleAttachmentIndex()#
returns an array with article IDs
my %AttachmentIndex = $ArticleObject->ArticleAttachmentIndex(
TicketID => 123,
ArticleID => 123,
ExcludePlainText => 1, # (optional) Exclude plain text attachment
ExcludeHTMLBody => 1, # (optional) Exclude HTML body attachment
ExcludeInline => 1, # (optional) Exclude inline attachments
OnlyHTMLBody => 1, # (optional) Return only HTML body attachment, return nothing if not found
);
Returns:
my %AttachmentIndex = (
'1' => {
'FilesizeRaw' => '804764',
'Disposition' => 'attachment',
'ContentType' => 'image/jpeg',
'ContentAlternative' => '',
'Filename' => 'blub.jpg',
'ContentID' => ''
},
# ...
);
ArticleAttachment()#
Get article attachment from storage. This is a delegate method from active backend.
my %Attachment = $ArticleObject->ArticleAttachment(
TicketID => 123,
ArticleID => 123,
FileID => 1, # as returned by ArticleAttachmentIndex
);
Returns:
%Attachment = (
Content => 'xxxx', # actual attachment contents
ContentAlternative => '',
ContentID => '',
ContentType => 'application/pdf',
Filename => 'StdAttachment-Test1.pdf',
FilesizeRaw => 4722,
Disposition => 'attachment',
);
ArticleWriteAttachment()#
Write an article attachment to storage.
my $Success = $ArticleBackendObject->ArticleWriteAttachment(
TicketID => 503,
Content => $ContentAsString,
ContentType => 'text/html; charset="iso-8859-15"',
Filename => 'lala.html',
ContentID => 'cid-1234', # optional
ContentAlternative => 0, # optional, alternative content to shown as body
Disposition => 'attachment', # or 'inline'
ArticleID => 123,
UserID => 123,
);
ArticleCount()#
Returns count of article.
my $Count = $ArticleObject->ArticleCount(
TicketID => 123,
);
Returns:
my $Count = 1;
ArticleAttachmentCount()#
Returns count of article attachment.
my $Count = $ArticleObject->ArticleAttachmentCount(
TicketID => 123,
ArticleID => 123,
);
Returns:
my $Count = 1;
ArticleContentPathGet()#
Get the stored content path of an article.
my $Path = $BackendObject->ArticleContentPathGet(
ArticleID => 123,
);