/Kernel/Output/HTML/DashboardTicketGeneric.pm

https://github.com/tobixen/otrs · Perl · 421 lines · 322 code · 51 blank · 48 comment · 46 complexity · cd911977ef9a4e4792ab0e6135ed7bc6 MD5 · raw file

  1. # --
  2. # Kernel/Output/HTML/DashboardTicketGeneric.pm
  3. # Copyright (C) 2001-2013 OTRS AG, http://otrs.com/
  4. # --
  5. # This software comes with ABSOLUTELY NO WARRANTY. For details, see
  6. # the enclosed file COPYING for license information (AGPL). If you
  7. # did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
  8. # --
  9. package Kernel::Output::HTML::DashboardTicketGeneric;
  10. use strict;
  11. use warnings;
  12. sub new {
  13. my ( $Type, %Param ) = @_;
  14. # allocate new hash for object
  15. my $Self = {%Param};
  16. bless( $Self, $Type );
  17. # get needed objects
  18. for (
  19. qw(Config Name ConfigObject LogObject DBObject LayoutObject ParamObject TicketObject UserID)
  20. )
  21. {
  22. die "Got no $_!" if ( !$Self->{$_} );
  23. }
  24. # get current filter
  25. my $Name = $Self->{ParamObject}->GetParam( Param => 'Name' ) || '';
  26. my $PreferencesKey = 'UserDashboardTicketGenericFilter' . $Self->{Name};
  27. if ( $Self->{Name} eq $Name ) {
  28. $Self->{Filter} = $Self->{ParamObject}->GetParam( Param => 'Filter' ) || '';
  29. }
  30. # remember filter
  31. if ( $Self->{Filter} ) {
  32. # update session
  33. $Self->{SessionObject}->UpdateSessionID(
  34. SessionID => $Self->{SessionID},
  35. Key => $PreferencesKey,
  36. Value => $Self->{Filter},
  37. );
  38. # update preferences
  39. if ( !$Self->{ConfigObject}->Get('DemoSystem') ) {
  40. $Self->{UserObject}->SetPreferences(
  41. UserID => $Self->{UserID},
  42. Key => $PreferencesKey,
  43. Value => $Self->{Filter},
  44. );
  45. }
  46. }
  47. if ( !$Self->{Filter} ) {
  48. $Self->{Filter} = $Self->{$PreferencesKey} || $Self->{Config}->{Filter} || 'All';
  49. }
  50. $Self->{PrefKey} = 'UserDashboardPref' . $Self->{Name} . '-Shown';
  51. $Self->{PageShown} = $Self->{LayoutObject}->{ $Self->{PrefKey} } || $Self->{Config}->{Limit};
  52. $Self->{StartHit} = int( $Self->{ParamObject}->GetParam( Param => 'StartHit' ) || 1 );
  53. return $Self;
  54. }
  55. sub Preferences {
  56. my ( $Self, %Param ) = @_;
  57. my @Params = (
  58. {
  59. Desc => 'Shown Tickets',
  60. Name => $Self->{PrefKey},
  61. Block => 'Option',
  62. # Block => 'Input',
  63. Data => {
  64. 5 => ' 5',
  65. 10 => '10',
  66. 15 => '15',
  67. 20 => '20',
  68. 25 => '25',
  69. },
  70. SelectedID => $Self->{PageShown},
  71. Translation => 0,
  72. },
  73. );
  74. return @Params;
  75. }
  76. sub Config {
  77. my ( $Self, %Param ) = @_;
  78. # check if frontend module of link is used
  79. if ( $Self->{Config}->{Link} && $Self->{Config}->{Link} =~ /Action=(.+?)([&;].+?|)$/ ) {
  80. my $Action = $1;
  81. if ( !$Self->{ConfigObject}->Get('Frontend::Module')->{$Action} ) {
  82. $Self->{Config}->{Link} = '';
  83. }
  84. }
  85. return (
  86. %{ $Self->{Config} },
  87. # remember, do not allow to use page cache
  88. # (it's not working because of internal filter)
  89. CacheTTL => undef,
  90. CacheKey => undef,
  91. );
  92. }
  93. sub Run {
  94. my ( $Self, %Param ) = @_;
  95. my $CacheKey = $Self->{Name} . '-'
  96. . $Self->{PageShown} . '-'
  97. . $Self->{StartHit} . '-'
  98. . $Self->{UserID};
  99. # get all search base attributes
  100. my %TicketSearch;
  101. my %DynamicFieldsParameters;
  102. my @Params = split /;/, $Self->{Config}->{Attributes};
  103. for my $String (@Params) {
  104. next if !$String;
  105. my ( $Key, $Value ) = split /=/, $String;
  106. # push ARRAYREF attributes directly in an ARRAYREF
  107. if (
  108. $Key
  109. =~ /^(StateType|StateTypeIDs|Queues|QueueIDs|Types|TypeIDs|States|StateIDs|Priorities|PriorityIDs|Services|ServiceIDs|SLAs|SLAIDs|Locks|LockIDs|OwnerIDs|ResponsibleIDs|WatchUserIDs|ArchiveFlags)$/
  110. )
  111. {
  112. push @{ $TicketSearch{$Key} }, $Value;
  113. }
  114. # check if parameter is a dynamic field and capture dynamic field name (with DynamicField_)
  115. # in $1 and the Operator in $2
  116. # possible Dynamic Fields options include:
  117. # DynamicField_NameX_Equals=123;
  118. # DynamicField_NameX_Like=value*;
  119. # DynamicField_NameX_GreaterThan=2001-01-01 01:01:01;
  120. # DynamicField_NameX_GreaterThanEquals=2001-01-01 01:01:01;
  121. # DynamicField_NameX_SmallerThan=2002-02-02 02:02:02;
  122. # DynamicField_NameX_SmallerThanEquals=2002-02-02 02:02:02;
  123. elsif ( $Key =~ m{\A (DynamicField_.+?) _ (.+?) \z}sxm ) {
  124. $DynamicFieldsParameters{$1}->{$2} = $Value;
  125. }
  126. elsif ( !defined $TicketSearch{$Key} ) {
  127. $TicketSearch{$Key} = $Value;
  128. }
  129. elsif ( !ref $TicketSearch{$Key} ) {
  130. my $ValueTmp = $TicketSearch{$Key};
  131. $TicketSearch{$Key} = [$ValueTmp];
  132. push @{ $TicketSearch{$Key} }, $Value;
  133. }
  134. else {
  135. push @{ $TicketSearch{$Key} }, $Value;
  136. }
  137. }
  138. %TicketSearch = (
  139. %TicketSearch,
  140. %DynamicFieldsParameters,
  141. Permission => $Self->{Config}->{Permission} || 'ro',
  142. UserID => $Self->{UserID},
  143. );
  144. # CustomerInformationCenter shows data per CustomerID
  145. if ( $Param{CustomerID} ) {
  146. $TicketSearch{CustomerID} = $Param{CustomerID};
  147. $CacheKey .= '-' . $Param{CustomerID};
  148. }
  149. # define filter attributes
  150. my @MyQueues = $Self->{QueueObject}->GetAllCustomQueues(
  151. UserID => $Self->{UserID},
  152. );
  153. if ( !@MyQueues ) {
  154. @MyQueues = (999_999);
  155. }
  156. my %TicketSearchSummary = (
  157. Locked => {
  158. OwnerIDs => [ $Self->{UserID}, ],
  159. Locks => [ 'lock', 'tmp_lock' ],
  160. },
  161. Watcher => {
  162. WatchUserIDs => [ $Self->{UserID}, ],
  163. Locks => undef,
  164. },
  165. Responsible => {
  166. ResponsibleIDs => [ $Self->{UserID}, ],
  167. Locks => undef,
  168. },
  169. MyQueues => {
  170. QueueIDs => \@MyQueues,
  171. Locks => undef,
  172. },
  173. All => {
  174. OwnerIDs => undef,
  175. Locks => undef,
  176. },
  177. );
  178. if ( defined $TicketSearch{QueueIDs} || defined $TicketSearch{Queues} ) {
  179. delete $TicketSearchSummary{MyQueues};
  180. }
  181. # check cache
  182. my $TicketIDs = $Self->{CacheObject}->Get(
  183. Type => 'Dashboard',
  184. Key => $CacheKey . '-' . $Self->{Filter} . '-List',
  185. );
  186. # find and show ticket list
  187. my $CacheUsed = 1;
  188. if ( !$TicketIDs ) {
  189. $CacheUsed = 0;
  190. my @TicketIDsArray = $Self->{TicketObject}->TicketSearch(
  191. Result => 'ARRAY',
  192. %TicketSearch,
  193. %{ $TicketSearchSummary{ $Self->{Filter} } },
  194. Limit => $Self->{PageShown} + $Self->{StartHit} - 1,
  195. );
  196. $TicketIDs = \@TicketIDsArray;
  197. }
  198. # check cache
  199. my $Summary = $Self->{CacheObject}->Get(
  200. Type => 'Dashboard',
  201. Key => $CacheKey . '-Summary',
  202. );
  203. # if no cache or new list result, do count lookup
  204. if ( !$Summary || !$CacheUsed ) {
  205. for my $Type ( sort keys %TicketSearchSummary ) {
  206. next if !$TicketSearchSummary{$Type};
  207. $Summary->{$Type} = $Self->{TicketObject}->TicketSearch(
  208. Result => 'COUNT',
  209. %TicketSearch,
  210. %{ $TicketSearchSummary{$Type} },
  211. );
  212. }
  213. }
  214. # set cache
  215. if ( !$CacheUsed && $Self->{Config}->{CacheTTLLocal} ) {
  216. $Self->{CacheObject}->Set(
  217. Type => 'Dashboard',
  218. Key => $CacheKey . '-Summary',
  219. Value => $Summary,
  220. TTL => $Self->{Config}->{CacheTTLLocal} * 60,
  221. );
  222. $Self->{CacheObject}->Set(
  223. Type => 'Dashboard',
  224. Key => $CacheKey . '-' . $Self->{Filter} . '-List',
  225. Value => $TicketIDs,
  226. TTL => $Self->{Config}->{CacheTTLLocal} * 60,
  227. );
  228. }
  229. # set css class
  230. $Summary->{ $Self->{Filter} . '::Selected' } = 'Selected';
  231. # get filter ticket counts
  232. $Self->{LayoutObject}->Block(
  233. Name => 'ContentLargeTicketGenericFilter',
  234. Data => {
  235. %Param,
  236. %{ $Self->{Config} },
  237. Name => $Self->{Name},
  238. %{$Summary},
  239. },
  240. );
  241. # show also watcher if feature is enabled
  242. if ( $Self->{ConfigObject}->Get('Ticket::Watcher') ) {
  243. $Self->{LayoutObject}->Block(
  244. Name => 'ContentLargeTicketGenericFilterWatcher',
  245. Data => {
  246. %Param,
  247. %{ $Self->{Config} },
  248. Name => $Self->{Name},
  249. %{$Summary},
  250. },
  251. );
  252. }
  253. # show also responsible if feature is enabled
  254. if ( $Self->{ConfigObject}->Get('Ticket::Responsible') ) {
  255. $Self->{LayoutObject}->Block(
  256. Name => 'ContentLargeTicketGenericFilterResponsible',
  257. Data => {
  258. %Param,
  259. %{ $Self->{Config} },
  260. Name => $Self->{Name},
  261. %{$Summary},
  262. },
  263. );
  264. }
  265. # show only myqueues if we have the filter
  266. if ( $TicketSearchSummary{MyQueues} ) {
  267. $Self->{LayoutObject}->Block(
  268. Name => 'ContentLargeTicketGenericFilterMyQueues',
  269. Data => {
  270. %Param,
  271. %{ $Self->{Config} },
  272. Name => $Self->{Name},
  273. %{$Summary},
  274. },
  275. );
  276. }
  277. # add page nav bar
  278. my $Total = $Summary->{ $Self->{Filter} } || 0;
  279. my $LinkPage = 'Subaction=Element;Name=' . $Self->{Name} . ';Filter=' . $Self->{Filter} . ';';
  280. if ( $Param{CustomerID} ) {
  281. $LinkPage .= "CustomerID=$Param{CustomerID};";
  282. }
  283. my %PageNav = $Self->{LayoutObject}->PageNavBar(
  284. StartHit => $Self->{StartHit},
  285. PageShown => $Self->{PageShown},
  286. AllHits => $Total || 1,
  287. Action => 'Action=' . $Self->{LayoutObject}->{Action},
  288. Link => $LinkPage,
  289. AJAXReplace => 'Dashboard' . $Self->{Name},
  290. IDPrefix => 'Dashboard' . $Self->{Name},
  291. KeepScriptTags => $Param{AJAX},
  292. );
  293. $Self->{LayoutObject}->Block(
  294. Name => 'ContentLargeTicketGenericFilterNavBar',
  295. Data => {
  296. %{ $Self->{Config} },
  297. Name => $Self->{Name},
  298. %PageNav,
  299. },
  300. );
  301. # show tickets
  302. my $Count = 0;
  303. for my $TicketID ( @{$TicketIDs} ) {
  304. $Count++;
  305. next if $Count < $Self->{StartHit};
  306. my %Ticket = $Self->{TicketObject}->TicketGet(
  307. TicketID => $TicketID,
  308. UserID => $Self->{UserID},
  309. DynamicFields => 0,
  310. );
  311. # set a default title if ticket has no title
  312. if ( !$Ticket{Title} ) {
  313. $Ticket{Title} = $Self->{LayoutObject}->{LanguageObject}->Get(
  314. 'This ticket has no title or subject'
  315. );
  316. }
  317. # create human age
  318. if ( $Self->{Config}->{Time} ne 'Age' ) {
  319. $Ticket{Time} = $Self->{LayoutObject}->CustomerAgeInHours(
  320. Age => $Ticket{ $Self->{Config}->{Time} },
  321. Space => ' ',
  322. );
  323. }
  324. else {
  325. $Ticket{Time} = $Self->{LayoutObject}->CustomerAge(
  326. Age => $Ticket{ $Self->{Config}->{Time} },
  327. Space => ' ',
  328. );
  329. }
  330. # show ticket
  331. $Self->{LayoutObject}->Block(
  332. Name => 'ContentLargeTicketGenericRow',
  333. Data => \%Ticket,
  334. );
  335. # show ticket flags
  336. my @TicketMetaItems = $Self->{LayoutObject}->TicketMetaItems(
  337. Ticket => \%Ticket,
  338. );
  339. for my $Item (@TicketMetaItems) {
  340. $Self->{LayoutObject}->Block(
  341. Name => 'ContentLargeTicketGenericRowMeta',
  342. Data => {},
  343. );
  344. if ($Item) {
  345. $Self->{LayoutObject}->Block(
  346. Name => 'ContentLargeTicketGenericRowMetaImage',
  347. Data => $Item,
  348. );
  349. }
  350. }
  351. }
  352. # show "none" if no ticket is available
  353. if ( !$TicketIDs || !@{$TicketIDs} ) {
  354. $Self->{LayoutObject}->Block(
  355. Name => 'ContentLargeTicketGenericNone',
  356. Data => {},
  357. );
  358. }
  359. my $Content = $Self->{LayoutObject}->Output(
  360. TemplateFile => 'AgentDashboardTicketGeneric',
  361. Data => {
  362. %{ $Self->{Config} },
  363. Name => $Self->{Name},
  364. %{$Summary},
  365. },
  366. KeepScriptTags => $Param{AJAX},
  367. );
  368. return $Content;
  369. }
  370. 1;