1%# BEGIN BPS TAGGED BLOCK {{{
2%#
3%# COPYRIGHT:
4%#
5%# This software is Copyright (c) 1996-2021 Best Practical Solutions, LLC
6%#                                          <sales@bestpractical.com>
7%#
8%# (Except where explicitly superseded by other copyright notices)
9%#
10%#
11%# LICENSE:
12%#
13%# This work is made available to you under the terms of Version 2 of
14%# the GNU General Public License. A copy of that license should have
15%# been provided with this software, but in any event can be snarfed
16%# from www.gnu.org.
17%#
18%# This work is distributed in the hope that it will be useful, but
19%# WITHOUT ANY WARRANTY; without even the implied warranty of
20%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21%# General Public License for more details.
22%#
23%# You should have received a copy of the GNU General Public License
24%# along with this program; if not, write to the Free Software
25%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26%# 02110-1301 or visit their web page on the internet at
27%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28%#
29%#
30%# CONTRIBUTION SUBMISSION POLICY:
31%#
32%# (The following paragraph is not intended to limit the rights granted
33%# to you to modify and distribute this software under the terms of
34%# the GNU General Public License and is only of importance to you if
35%# you choose to contribute your changes and enhancements to the
36%# community by submitting them to Best Practical Solutions, LLC.)
37%#
38%# By intentionally submitting any modifications, corrections or
39%# derivatives to this work, or any other work intended for use with
40%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41%# you are the copyright holder for those contributions and you grant
42%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43%# royalty-free, perpetual, license to use, copy, create derivative
44%# works based on those contributions, and sublicense and distribute
45%# those contributions and any derivatives thereof.
46%#
47%# END BPS TAGGED BLOCK }}}
48<& /Elements/PageLayout, show_menu => $show_menu &>
49<a name="skipnav" id="skipnav" accesskey="8"></a>
50<%INIT>
51
52my $request_path = $HTML::Mason::Commands::r->path_info;
53$request_path =~ s!/{2,}!/!g;
54
55my $query_string = sub {
56    my %args = @_;
57    my $u    = URI->new();
58    $u->query_form(map { $_ => $args{$_} } sort keys %args);
59    return $u->query;
60};
61
62my $build_admin_menu = sub {
63    my $top = shift;
64    my $admin = $top->child( admin => title => loc('Admin'), path => '/Admin/' );
65    if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminUsers' ) ) {
66        my $users = $admin->child( users =>
67            title       => loc('Users'),
68            description => loc('Manage users and passwords'),
69            path        => '/Admin/Users/',
70        );
71        $users->child( select => title => loc('Select'), path => "/Admin/Users/" );
72        $users->child( create => title => loc('Create'), path => "/Admin/Users/Modify.html?Create=1" );
73    }
74    my $groups = $admin->child( groups =>
75        title       => loc('Groups'),
76        description => loc('Manage groups and group membership'),
77        path        => '/Admin/Groups/',
78    );
79    $groups->child( select => title => loc('Select'), path => "/Admin/Groups/" );
80    $groups->child( create => title => loc('Create'), path => "/Admin/Groups/Modify.html?Create=1" );
81
82    my $queues = $admin->child( queues =>
83        title       => loc('Queues'),
84        description => loc('Manage queues and queue-specific properties'),
85        path        => '/Admin/Queues/',
86    );
87    $queues->child( select => title => loc('Select'), path => "/Admin/Queues/" );
88    $queues->child( create => title => loc('Create'), path => "/Admin/Queues/Modify.html?Create=1" );
89
90    if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminCustomField' ) ) {
91        my $cfs = $admin->child( 'custom-fields' =>
92            title       => loc('Custom Fields'),
93            description => loc('Manage custom fields and custom field values'),
94            path        => '/Admin/CustomFields/',
95        );
96        $cfs->child( select => title => loc('Select'), path => "/Admin/CustomFields/" );
97        $cfs->child( create => title => loc('Create'), path => "/Admin/CustomFields/Modify.html?Create=1" );
98    }
99
100    if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminCustomRoles' ) ) {
101        my $roles = $admin->child( 'custom-roles' =>
102            title       => loc('Custom Roles'),
103            description => loc('Manage custom roles'),
104            path        => '/Admin/CustomRoles/',
105        );
106        $roles->child( select => title => loc('Select'), path => "/Admin/CustomRoles/" );
107        $roles->child( create => title => loc('Create'), path => "/Admin/CustomRoles/Modify.html?Create=1" );
108    }
109
110    if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'ModifyScrips' ) ) {
111        my $scrips = $admin->child( 'scrips' =>
112            title       => loc('Scrips'),
113            description => loc('Manage scrips'),
114            path        => '/Admin/Scrips/',
115        );
116        $scrips->child( select => title => loc('Select'), path => "/Admin/Scrips/" );
117        $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html" );
118    }
119
120    my $admin_global = $admin->child( global =>
121        title       => loc('Global'),
122        description => loc('Manage properties and configuration which apply to all queues'),
123        path        => '/Admin/Global/',
124    );
125
126    my $scrips = $admin_global->child( scrips =>
127        title       => loc('Scrips'),
128        description => loc('Modify scrips which apply to all queues'),
129        path        => '/Admin/Global/Scrips.html',
130    );
131    $scrips->child( select => title => loc('Select'), path => "/Admin/Global/Scrips.html" );
132    $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html?Global=1" );
133
134    my $conditions = $admin_global->child( conditions =>
135        title => loc('Conditions'),
136        description => loc('Edit system conditions'),
137        path        => '/Admin/Global/Conditions.html',
138    );
139    $conditions->child( select => title => loc('Select'), path => "/Admin/Global/Conditions.html" );
140    $conditions->child( create => title => loc('Create'), path => "/Admin/Conditions/Create.html" );
141
142    my $actions   = $admin_global->child( actions =>
143        title => loc('Actions'),
144        description => loc('Edit system actions'),
145        path        => '/Admin/Global/Actions.html',
146    );
147    $actions->child( select => title => loc('Select'), path => "/Admin/Global/Actions.html" );
148    $actions->child( create => title => loc('Create'), path => "/Admin/Actions/Create.html" );
149
150    my $templates = $admin_global->child( templates =>
151        title       => loc('Templates'),
152        description => loc('Edit system templates'),
153        path        => '/Admin/Global/Templates.html',
154    );
155    $templates->child( select => title => loc('Select'), path => "/Admin/Global/Templates.html" );
156    $templates->child( create => title => loc('Create'), path => "/Admin/Global/Template.html?Create=1" );
157
158    my $cfadmin = $admin_global->child( 'custom-fields' =>
159        title       => loc('Custom Fields'),
160        description => loc('Modify global custom fields'),
161        path        => '/Admin/Global/CustomFields/index.html',
162    );
163    $cfadmin->child( users =>
164        title       => loc('Users'),
165        description => loc('Select custom fields for all users'),
166        path        => '/Admin/Global/CustomFields/Users.html',
167    );
168    $cfadmin->child( groups =>
169        title       => loc('Groups'),
170        description => loc('Select custom fields for all user groups'),
171        path        => '/Admin/Global/CustomFields/Groups.html',
172    );
173    $cfadmin->child( queues =>
174        title       => loc('Queues'),
175        description => loc('Select custom fields for all queues'),
176        path        => '/Admin/Global/CustomFields/Queues.html',
177    );
178    $cfadmin->child( tickets =>
179        title       => loc('Tickets'),
180        description => loc('Select custom fields for tickets in all queues'),
181        path        => '/Admin/Global/CustomFields/Queue-Tickets.html',
182    );
183    $cfadmin->child( transactions =>
184        title       => loc('Ticket Transactions'),
185        description => loc('Select custom fields for transactions on tickets in all queues'),
186        path        => '/Admin/Global/CustomFields/Queue-Transactions.html',
187    );
188    $cfadmin->child( 'custom-fields' =>
189        title       => loc('Articles'),
190        description => loc('Select Custom Fields for Articles in all Classes'),
191        path        => '/Admin/Global/CustomFields/Class-Article.html',
192    );
193    $cfadmin->child( 'assets' =>
194        title       => loc('Assets'),
195        description => loc('Select Custom Fields for Assets in all Catalogs'),
196        path        => '/Admin/Global/CustomFields/Catalog-Assets.html',
197    );
198
199    my $article_admin = $admin->child( articles => title => loc('Articles'), path => "/Admin/Articles/index.html" );
200    my $class_admin = $article_admin->child(classes => title => loc('Classes'), path => '/Admin/Articles/Classes/' );
201    $class_admin->child( select =>
202        title       => loc('Select'),
203        description => loc('Modify and Create Classes'),
204        path        => '/Admin/Articles/Classes/',
205    );
206    $class_admin->child( create =>
207        title       => loc('Create'),
208        description => loc('Modify and Create Custom Fields for Articles'),
209        path        => '/Admin/Articles/Classes/Modify.html?Create=1',
210    );
211
212
213    my $cfs = $article_admin->child( 'custom-fields' =>
214        title => loc('Custom Fields'),
215        path  => '/Admin/CustomFields/index.html?'.$m->comp('/Elements/QueryString', Type => 'RT::Class-RT::Article'),
216    );
217    $cfs->child( select =>
218        title => loc('Select'),
219        path => '/Admin/CustomFields/index.html?'.$m->comp('/Elements/QueryString', Type => 'RT::Class-RT::Article'),
220    );
221    $cfs->child( create =>
222        title => loc('Create'),
223        path => '/Admin/CustomFields/Modify.html?'.$m->comp("/Elements/QueryString", Create=>1, LookupType=> "RT::Class-RT::Article" ),
224    );
225
226    my $assets_admin = $admin->child( assets => title => loc("Assets"), path => '/Admin/Assets/' );
227    my $catalog_admin = $assets_admin->child( catalogs =>
228        title       => loc("Catalogs"),
229        description => loc("Modify asset catalogs"),
230        path        => "/Admin/Assets/Catalogs/"
231    );
232    $catalog_admin->child( "select", title => loc("Select"), path => $catalog_admin->path );
233    $catalog_admin->child( "create", title => loc("Create"), path => "Create.html" );
234
235
236    my $assets_cfs = $assets_admin->child( "cfs",
237        title => loc("Custom Fields"),
238        description => loc("Modify asset custom fields"),
239        path => "/Admin/CustomFields/?Type=" . RT::Asset->CustomFieldLookupType
240    );
241    $assets_cfs->child( "select", title => loc("Select"), path => $assets_cfs->path );
242    $assets_cfs->child( "create", title => loc("Create"), path => "/Admin/CustomFields/Modify.html?Create=1&LookupType=" . RT::Asset->CustomFieldLookupType);
243
244    $admin_global->child( 'group-rights' =>
245        title       => loc('Group Rights'),
246        description => loc('Modify global group rights'),
247        path        => '/Admin/Global/GroupRights.html',
248    );
249    $admin_global->child( 'user-rights' =>
250        title       => loc('User Rights'),
251        description => loc('Modify global user rights'),
252        path        => '/Admin/Global/UserRights.html',
253    );
254    $admin_global->child( 'my-rt' =>
255        title       => loc('RT at a glance'),
256        description => loc('Modify the default "RT at a glance" view'),
257        path        => '/Admin/Global/MyRT.html',
258    );
259    $admin_global->child( 'dashboards-in-menu' =>
260        title       => loc('Dashboards in menu'),
261        description => loc('Customize dashboards in menu'),
262        path        => '/Admin/Global/DashboardsInMenu.html',
263    );
264    $admin_global->child( 'topics' =>
265        title       => loc('Topics'),
266        description => loc('Modify global article topics'),
267        path        => '/Admin/Global/Topics.html',
268    );
269
270    my $admin_tools = $admin->child( tools =>
271        title       => loc('Tools'),
272        description => loc('Use other RT administrative tools'),
273        path        => '/Admin/Tools/',
274    );
275    $admin_tools->child( configuration =>
276        title       => loc('System Configuration'),
277        description => loc('Detailed information about your RT setup'),
278        path        => '/Admin/Tools/Configuration.html',
279    );
280    $admin_tools->child( theme =>
281        title       => loc('Theme'),
282        description => loc('Customize the look of your RT'),
283        path        => '/Admin/Tools/Theme.html',
284    );
285    if (RT->Config->Get('StatementLog')
286        && $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => RT->System )) {
287       $admin_tools->child( 'sql-queries' =>
288           title       => loc('SQL Queries'),
289           description => loc('Browse the SQL queries made in this process'),
290           path        => '/Admin/Tools/Queries.html',
291       );
292    }
293    $admin_tools->child( shredder =>
294        title       => loc('Shredder'),
295        description => loc('Permanently wipeout data from RT'),
296        path        => '/Admin/Tools/Shredder',
297    );
298
299    if ( RT->Config->Get('GnuPG')->{'Enable'}
300        && $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => RT->System ) )
301    {
302        $admin_tools->child(
303            'gnupg'     => title => loc('Manage GnuPG Keys'),
304            description => loc('Manage GnuPG keys'),
305            path        => '/Admin/Tools/GnuPG.html',
306        );
307    }
308
309    if ( $request_path =~ m{^/Admin/(Queues|Users|Groups|CustomFields|CustomRoles)} ) {
310        my $type = $1;
311        my $tabs = PageMenu();
312
313        my %labels = (
314            Queues       => loc("Queues"),
315            Users        => loc("Users"),
316            Groups       => loc("Groups"),
317            CustomFields => loc("Custom Fields"),
318            CustomRoles  => loc("Custom Roles"),
319        );
320
321        my $section;
322        if ( $request_path =~ m|^/Admin/$type/?(?:index.html)?$|
323             || (    $request_path =~ m|^/Admin/$type/(?:Modify.html)$|
324                  && $DECODED_ARGS->{'Create'} )
325           )
326        {
327            $section = $tabs;
328
329        } else {
330            $section = $tabs->child( select => title => $labels{$type},
331                                     path => "/Admin/$type/" );
332        }
333
334        $section->child( select => title => loc('Select'), path => "/Admin/$type/" );
335        $section->child( create => title => loc('Create'), path => "/Admin/$type/Modify.html?Create=1" );
336    }
337
338    if ( $request_path =~ m{^/Admin/Queues} ) {
339        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/
340                ||
341              $DECODED_ARGS->{'Queue'} && $DECODED_ARGS->{'Queue'} =~ /^\d+$/
342                ) {
343            my $id = $DECODED_ARGS->{'Queue'} || $DECODED_ARGS->{'id'};
344            my $queue_obj = RT::Queue->new( $session{'CurrentUser'} );
345            $queue_obj->Load($id);
346
347            if ( $queue_obj and $queue_obj->id ) {
348                my $queue = PageMenu();
349                $queue->child( basics => title => loc('Basics'),   path => "/Admin/Queues/Modify.html?id=" . $id );
350                $queue->child( people => title => loc('Watchers'), path => "/Admin/Queues/People.html?id=" . $id );
351
352                my $templates = $queue->child(templates => title => loc('Templates'), path => "/Admin/Queues/Templates.html?id=" . $id);
353                $templates->child( select => title => loc('Select'), path => "/Admin/Queues/Templates.html?id=".$id);
354                $templates->child( create => title => loc('Create'), path => "/Admin/Queues/Template.html?Create=1;Queue=".$id);
355
356                my $scrips = $queue->child( scrips => title => loc('Scrips'), path => "/Admin/Queues/Scrips.html?id=" . $id);
357                $scrips->child( select => title => loc('Select'), path => "/Admin/Queues/Scrips.html?id=" . $id );
358                $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html?Queue=" . $id);
359
360                my $cfs = $queue->child( 'custom-fields' => title => loc('Custom Fields') );
361                my $ticket_cfs = $cfs->child( 'tickets' => title => loc('Tickets'),
362                    path => '/Admin/Queues/CustomFields.html?SubType=RT::Ticket&id=' . $id );
363
364                my $txn_cfs = $cfs->child( 'transactions' => title => loc('Transactions'),
365                    path => '/Admin/Queues/CustomFields.html?SubType=RT::Ticket-RT::Transaction&id='.$id );
366
367                $queue->child( 'custom-roles' => title => loc('Custom Roles'), path => "/Admin/Queues/CustomRoles.html?id=".$id );
368                $queue->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/Queues/GroupRights.html?id=".$id );
369                $queue->child( 'user-rights' => title => loc('User Rights'), path => "/Admin/Queues/UserRights.html?id=" . $id );
370                $queue->child( 'history' => title => loc('History'), path => "/Admin/Queues/History.html?id=" . $id );
371                $queue->child( 'default-values' => title => loc('Default Values'), path => "/Admin/Queues/DefaultValues.html?id=" . $id );
372
373                $m->callback( CallbackName => 'PrivilegedQueue', queue_id => $id, page_menu => $queue);
374            }
375        }
376    }
377    if ( $request_path =~ m{^(/Admin/Users|/User/(Summary|History)\.html)} and $admin->child("users") ) {
378        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
379            my $id = $DECODED_ARGS->{'id'};
380            my $obj = RT::User->new( $session{'CurrentUser'} );
381            $obj->Load($id);
382
383            if ( $obj and $obj->id ) {
384                my $tabs = PageMenu();
385                $tabs->child( basics      => title => loc('Basics'),         path => "/Admin/Users/Modify.html?id=" . $id );
386                $tabs->child( memberships => title => loc('Memberships'),    path => "/Admin/Users/Memberships.html?id=" . $id );
387                $tabs->child( history     => title => loc('History'),        path => "/Admin/Users/History.html?id=" . $id );
388                $tabs->child( 'my-rt'     => title => loc('RT at a glance'), path => "/Admin/Users/MyRT.html?id=" . $id );
389                $tabs->child( 'dashboards-in-menu' =>
390                    title => loc('Dashboards in menu'),
391                    path  => '/Admin/Users/DashboardsInMenu.html?id=' . $id,
392                );
393                if ( RT->Config->Get('Crypt')->{'Enable'} ) {
394                    $tabs->child( keys    => title => loc('Private keys'),   path => "/Admin/Users/Keys.html?id=" . $id );
395                }
396                $tabs->child( 'summary'   => title => loc('User Summary'),   path => "/User/Summary.html?id=" . $id );
397            }
398        }
399
400    }
401
402    if ( $request_path =~ m{^/Admin/Groups} ) {
403        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
404            my $id = $DECODED_ARGS->{'id'};
405            my $obj = RT::Group->new( $session{'CurrentUser'} );
406            $obj->Load($id);
407
408            if ( $obj and $obj->id ) {
409                my $tabs = PageMenu();
410                $tabs->child( basics         => title => loc('Basics'),       path => "/Admin/Groups/Modify.html?id=" . $obj->id );
411                $tabs->child( members        => title => loc('Members'),      path => "/Admin/Groups/Members.html?id=" . $obj->id );
412                $tabs->child( memberships    => title => loc('Memberships'),  path => "/Admin/Groups/Memberships.html?id=" . $obj->id );
413                $tabs->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/Groups/GroupRights.html?id=" . $obj->id );
414                $tabs->child( 'user-rights'  => title => loc('User Rights'),  path => "/Admin/Groups/UserRights.html?id=" . $obj->id );
415                $tabs->child( history        => title => loc('History'),      path => "/Admin/Groups/History.html?id=" . $obj->id );
416            }
417        }
418    }
419
420    if ( $request_path =~ m{^/Admin/CustomFields/} ) {
421        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
422            my $id = $DECODED_ARGS->{'id'};
423            my $obj = RT::CustomField->new( $session{'CurrentUser'} );
424            $obj->Load($id);
425
426            if ( $obj and $obj->id ) {
427                my $tabs = PageMenu();
428                $tabs->child( basics           => title => loc('Basics'),       path => "/Admin/CustomFields/Modify.html?id=".$id );
429                $tabs->child( 'group-rights'   => title => loc('Group Rights'), path => "/Admin/CustomFields/GroupRights.html?id=" . $id );
430                $tabs->child( 'user-rights'    => title => loc('User Rights'),  path => "/Admin/CustomFields/UserRights.html?id=" . $id );
431                unless ( $obj->IsOnlyGlobal ) {
432                    $tabs->child( 'applies-to' => title => loc('Applies to'),   path => "/Admin/CustomFields/Objects.html?id=" . $id );
433                }
434            }
435        }
436    }
437
438    if ( $request_path =~ m{^/Admin/CustomRoles} ) {
439        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
440            my $id = $DECODED_ARGS->{'id'};
441            my $obj = RT::CustomRole->new( $session{'CurrentUser'} );
442            $obj->Load($id);
443
444            if ( $obj and $obj->id ) {
445                my $tabs = PageMenu();
446                $tabs->child( basics       => title => loc('Basics'),       path => "/Admin/CustomRoles/Modify.html?id=".$id );
447                $tabs->child( 'applies-to' => title => loc('Applies to'),   path => "/Admin/CustomRoles/Objects.html?id=" . $id );
448            }
449        }
450    }
451
452    if ( $request_path =~ m{^/Admin/Scrips/} ) {
453        if ( $m->request_args->{'id'} && $m->request_args->{'id'} =~ /^\d+$/ ) {
454            my $id = $m->request_args->{'id'};
455            my $obj = RT::Scrip->new( $session{'CurrentUser'} );
456            $obj->Load($id);
457
458            my $tabs = PageMenu();
459
460            my ( $admin_cat, $create_path_arg, $from_query_param );
461            my $from_arg = $DECODED_ARGS->{'From'} || q{};
462            my ($from_queue) = $from_arg =~ /^(\d+)$/;
463            if ( $from_queue ) {
464                $admin_cat = "Queues/Scrips.html?id=$from_queue";
465                $create_path_arg = "?Queue=$from_queue";
466                $from_query_param = "&From=$from_queue";
467            }
468            elsif ( $from_arg eq 'Global' ) {
469                $admin_cat = 'Global/Scrips.html';
470                $create_path_arg = '?Global=1';
471                $from_query_param = '&From=Global';
472            }
473            else {
474                $admin_cat = 'Scrips';
475                $from_query_param = $create_path_arg = q{};
476            }
477            my $scrips = $tabs->child( scrips => title => loc('Scrips'), path => "/Admin/${admin_cat}" );
478            $scrips->child( select => title => loc('Select'), path => "/Admin/${admin_cat}" );
479            $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html${create_path_arg}" );
480
481            $tabs->child( basics => title => loc('Basics') => path => "/Admin/Scrips/Modify.html?id=" . $id . $from_query_param );
482            $tabs->child( 'applies-to' => title => loc('Applies to'), path => "/Admin/Scrips/Objects.html?id=" . $id . $from_query_param );
483        }
484        elsif ( $request_path =~ m{^/Admin/Scrips/(index\.html)?$} ) {
485            PageMenu->child( select => title => loc('Select') => path => "/Admin/Scrips/" );
486            PageMenu->child( create => title => loc('Create') => path => "/Admin/Scrips/Create.html" );
487        }
488        elsif ( $request_path =~ m{^/Admin/Scrips/Create\.html$} ) {
489            my ($queue) = $DECODED_ARGS->{'Queue'} && $DECODED_ARGS->{'Queue'} =~ /^(\d+)$/;
490            my $global_arg = $DECODED_ARGS->{'Global'};
491            if ($queue) {
492                PageMenu->child( select => title => loc('Select') => path => "/Admin/Queues/Scrips.html?id=$queue" );
493                PageMenu->child( create => title => loc('Create') => path => "/Admin/Scrips/Create.html?Queue=$queue" );
494            } elsif ($global_arg) {
495                PageMenu->child( select => title => loc('Select') => path => "/Admin/Global/Scrips.html" );
496                PageMenu->child( create => title => loc('Create') => path => "/Admin/Scrips/Create.html?Global=1" );
497            } else {
498                PageMenu->child( select => title => loc('Select') => path => "/Admin/Scrips" );
499                PageMenu->child( create => title => loc('Create') => path => "/Admin/Scrips/Create.html" );
500            }
501        }
502    }
503
504    if ( $request_path =~ m{^/Admin/Global/Scrips\.html} ) {
505        my $tabs = PageMenu();
506        $tabs->child( select => title => loc('Select'), path => "/Admin/Global/Scrips.html" );
507        $tabs->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html?Global=1" );
508    }
509
510    if ( $request_path =~ m{^/Admin(?:/Global)?/Conditions} ) {
511        my $tabs = PageMenu();
512        $tabs->child( select => title => loc('Select'), path => "/Admin/Global/Conditions.html" );
513        $tabs->child( create => title => loc('Create'), path => "/Admin/Conditions/Create.html" );
514    }
515
516    if ( $request_path =~ m{^/Admin(?:/Global)?/Actions} ) {
517        my $tabs = PageMenu();
518        $tabs->child( select => title => loc('Select'), path => "/Admin/Global/Actions.html" );
519        $tabs->child( create => title => loc('Create'), path => "/Admin/Actions/Create.html" );
520    }
521
522    if ( $request_path =~ m{^/Admin/Global/Templates?\.html} ) {
523        my $tabs = PageMenu();
524        $tabs->child( select => title => loc('Select'), path => "/Admin/Global/Templates.html" );
525        $tabs->child( create => title => loc('Create'), path => "/Admin/Global/Template.html?Create=1" );
526    }
527
528    if ( $request_path =~ m{^/Admin/Articles/Classes/} ) {
529        my $tabs = PageMenu();
530        if ( my $id = $DECODED_ARGS->{'id'} ) {
531            my $obj = RT::Class->new( $session{'CurrentUser'} );
532            $obj->Load($id);
533
534            if ( $obj and $obj->id ) {
535                my $section = $tabs->child( select => title => loc("Classes"), path => "/Admin/Articles/Classes/" );
536                $section->child( select => title => loc('Select'), path => "/Admin/Articles/Classes/" );
537                $section->child( create => title => loc('Create'), path => "/Admin/Articles/Classes/Modify.html?Create=1" );
538
539                $tabs->child( basics          => title => loc('Basics'),        path => "/Admin/Articles/Classes/Modify.html?id=".$id );
540                $tabs->child( topics          => title => loc('Topics'),        path => "/Admin/Articles/Classes/Topics.html?id=".$id );
541                $tabs->child( 'custom-fields' => title => loc('Custom Fields'), path => "/Admin/Articles/Classes/CustomFields.html?id=".$id );
542                $tabs->child( 'group-rights'  => title => loc('Group Rights'),  path => "/Admin/Articles/Classes/GroupRights.html?id=".$id );
543                $tabs->child( 'user-rights'   => title => loc('User Rights'),   path => "/Admin/Articles/Classes/UserRights.html?id=".$id );
544                $tabs->child( 'applies-to'    => title => loc('Applies to'),    path => "/Admin/Articles/Classes/Objects.html?id=$id" );
545            }
546        } else {
547            $tabs->child( select => title => loc('Select'), path => "/Admin/Articles/Classes/" );
548            $tabs->child( create => title => loc('Create'), path => "/Admin/Articles/Classes/Modify.html?Create=1" );
549        }
550    }
551};
552
553my $build_main_nav = sub {
554
555    if ($request_path =~ m{^/Asset/}) {
556        PageWidgets()->child( asset_search => raw_html => $m->scomp('/Asset/Elements/Search') );
557    } else {
558        PageWidgets()->child( simple_search => raw_html => $m->scomp('SimpleSearch') );
559        PageWidgets()->child( create_ticket => raw_html => $m->scomp('CreateTicket') );
560    }
561
562    my $home = Menu->child( home => title => loc('Homepage'), path => '/' );
563    unless ($session{'dashboards_in_menu'}) {
564        my $dashboards_in_menu = $session{CurrentUser}->UserObj->Preferences(
565            'DashboardsInMenu',
566            {},
567        );
568
569        unless ($dashboards_in_menu->{dashboards}) {
570            my ($default_dashboards) =
571                RT::System->new( $session{'CurrentUser'} )
572                    ->Attributes
573                    ->Named('DashboardsInMenu');
574            if ($default_dashboards) {
575                $dashboards_in_menu = $default_dashboards->Content;
576            }
577        }
578
579        $session{'dashboards_in_menu'} = $dashboards_in_menu->{dashboards} || [];
580    }
581
582    my @dashboards;
583    for my $id ( @{$session{'dashboards_in_menu'}} ) {
584        my $dash = RT::Dashboard->new( $session{CurrentUser} );
585        my ( $status, $msg ) = $dash->LoadById($id);
586        if ( $status ) {
587            push @dashboards, $dash;
588        } else {
589            $RT::Logger->debug( "Failed to load dashboard $id: $msg, removing from menu" );
590            $home->RemoveDashboardMenuItem( DashboardId => $id, CurrentUser => $session{CurrentUser}->UserObj );
591            @{$session{'dashboards_in_menu'}} = grep { $_ != $id } @{$session{'dashboards_in_menu'}};
592        }
593    }
594
595    my $dashes = Menu()->child('home');
596    if (@dashboards) {
597        for my $dash (@dashboards) {
598            $home->child( 'dashboard-' . $dash->id,
599                title => $dash->Name,
600                path  => '/Dashboards/' . $dash->id . '/' . $dash->Name
601            );
602        }
603    }
604    $dashes->child( edit => title => loc('Update This Menu'), path => 'Prefs/DashboardsInMenu.html' );
605    $dashes->child( more => title => loc('All Dashboards'),   path => 'Dashboards/index.html' );
606    my $dashboard = RT::Dashboard->new( $session{CurrentUser} );
607    if ( $dashboard->CurrentUserCanCreateAny ) {
608        $dashes->child('dashboard_create' => title => loc('New Dashboard'), path => "/Dashboards/Modify.html?Create=1" );
609    }
610
611    my $search = Menu->child( search => title => loc('Search'), path => '/Search/Simple.html' );
612
613    my $tickets = $search->child( tickets => title => loc('Tickets'), path => '/Search/Build.html' );
614    $tickets->child( simple => title => loc('Simple Search'), path => "/Search/Simple.html" );
615    $tickets->child( new    => title => loc('New Search'),    path => "/Search/Build.html?NewQuery=1" );
616
617    my $recents = $tickets->child( recent => title => loc('Recently Viewed'));
618    for my $ticket ( $session{CurrentUser}->RecentlyViewedTickets ) {
619        my $title = $ticket->{subject} || loc( "(No subject)" );
620        if ( length $title > 50 ) {
621            $title = substr($title, 0, 47);
622            $title =~ s/\s+$//;
623            $title .= "...";
624        }
625        $title = "#$ticket->{id}: " . $title;
626        $recents->child( "$ticket->{id}" => title => $title, path => "/Ticket/Display.html?id=" . $ticket->{id} );
627    }
628
629    $search->child( articles => title => loc('Articles'),   path => "/Articles/Article/Search.html" )
630        if $session{CurrentUser}->HasRight( Right => 'ShowArticlesMenu', Object => RT->System );
631
632    $search->child( users => title => loc('Users'),   path => "/User/Search.html" );
633
634    $search->child( assets => title => loc("Assets"), path => "/Asset/Search/" )
635        if $session{CurrentUser}->HasRight( Right => 'ShowAssetsMenu', Object => RT->System );
636
637    my $reports = Menu->child( reports =>
638        title       => loc('Reports'),
639        description => loc('Reports summarizing ticket resolution and status'),
640        path        => loc('/Reports'),
641    );
642    $reports->child( resolvedbyowner =>
643        title       => loc('Resolved by owner'),
644        path        => '/Reports/ResolvedByOwner.html',
645        description => loc('Examine tickets resolved in a queue, grouped by owner'),
646    );
647    $reports->child( resolvedindaterange =>
648        title       => loc('Resolved in date range'),
649        path        => '/Reports/ResolvedByDates.html',
650        description => loc('Examine tickets resolved in a queue between two dates'),
651    );
652    $reports->child( createdindaterange =>
653        title       => loc('Created in a date range'),
654        path        => '/Reports/CreatedByDates.html',
655        description => loc('Examine tickets created in a queue between two dates'),
656    );
657    $reports->child( user_time =>
658        title       => loc('User time worked'),
659        description => loc('User time worked'),
660        path        => '/Reports/TimeWorkedReport.html',
661    );
662
663    if ($session{CurrentUser}->HasRight( Right => 'ShowArticlesMenu', Object => RT->System )) {
664        my $articles = Menu->child( articles => title => loc('Articles'), path => "/Articles/index.html");
665        $articles->child( articles => title => loc('Overview'), path => "/Articles/index.html" );
666        $articles->child( topics   => title => loc('Topics'),   path => "/Articles/Topics.html" );
667        $articles->child( create   => title => loc('Create'),   path => "/Articles/Article/PreCreate.html" );
668        $articles->child( search   => title => loc('Search'),   path => "/Articles/Article/Search.html" );
669    }
670
671    if ($session{CurrentUser}->HasRight( Right => 'ShowAssetsMenu', Object => RT->System )) {
672        my $assets = Menu->child( "assets", title => loc("Assets"), path => "/Asset/Search/" );
673        $assets->child( "create", title => loc("Create"), path => "/Asset/CreateInCatalog.html" );
674        $assets->child( "search", title => loc("Search"), path => "/Asset/Search/" );
675    }
676
677    my $tools = Menu->child( tools => title => loc('Tools'), path => '/Tools/index.html' );
678
679    $tools->child( my_day =>
680        title       => loc('My Day'),
681        description => loc('Easy updating of your open tickets'),
682        path        => '/Tools/MyDay.html',
683    );
684
685    if ( RT->Config->Get('EnableReminders') ) {
686        $tools->child( my_reminders =>
687            title       => loc('My Reminders'),
688            description => loc('Easy viewing of your reminders'),
689            path        => '/Tools/MyReminders.html',
690        );
691    }
692
693    if ( $session{'CurrentUser'}->HasRight( Right => 'ShowApprovalsTab', Object => RT->System ) ) {
694        $tools->child( approval =>
695            title       => loc('Approval'),
696            description => loc('My Approvals'),
697            path        => '/Approvals/',
698        );
699    }
700
701    if ( $session{'CurrentUser'}->HasRight( Right => 'ShowConfigTab', Object => RT->System ) )
702    {
703        $build_admin_menu->(Menu());
704    }
705
706    my $username = '<span class="current-user">'
707                 . $m->interp->apply_escapes($session{'CurrentUser'}->Name, 'h')
708                 . '</span>';
709    my $about_me = Menu->child( 'preferences' =>
710        title        => loc('Logged in as [_1]', $username),
711        escape_title => 0,
712        path         => '/User/Summary.html?id=' . $session{CurrentUser}->id,
713        sort_order   => 99,
714    );
715
716
717    if ( $session{'CurrentUser'}->UserObj
718         && $session{'CurrentUser'}->HasRight( Right => 'ModifySelf', Object => RT->System )) {
719        my $settings = $about_me->child( settings => title => loc('Settings'), path => '/Prefs/Other.html' );
720        $settings->child( options        => title => loc('Preferences'),        path => '/Prefs/Other.html' );
721        $settings->child( about_me       => title => loc('About me'),       path => '/Prefs/AboutMe.html' );
722        $settings->child( search_options => title => loc('Search options'), path => '/Prefs/SearchOptions.html' );
723        $settings->child( myrt           => title => loc('RT at a glance'), path => '/Prefs/MyRT.html' );
724        $settings->child( dashboards_in_menu =>
725            title => loc('Dashboards in menu'),
726            path  => '/Prefs/DashboardsInMenu.html',
727        );
728        $settings->child( queue_list    => title => loc('Queue list'),   path => '/Prefs/QueueList.html' );
729
730        my $search_menu = $settings->child( 'saved-searches' => title => loc('Saved Searches') );
731        my $searches = [ $m->comp( "/Search/Elements/SearchesForObject",
732                          Object => RT::System->new( $session{'CurrentUser'} )) ];
733        my $i = 0;
734
735        for my $search (@$searches) {
736            $search_menu->child( "search-" . $i++ =>
737                title => $search->[1],
738                path  => "/Prefs/Search.html?"
739                       . $query_string->( name => ref( $search->[2] ) . '-' . $search->[2]->Id ),
740            );
741
742        }
743    }
744    if ( $session{'CurrentUser'}->Name
745         && (   !RT->Config->Get('WebRemoteUserAuth')
746              || RT->Config->Get('WebFallbackToRTLogin') )) {
747        $about_me->child( logout => title => loc('Logout'), path => '/NoAuth/Logout.html' );
748    }
749    if ( $request_path =~ m{^/Dashboards/(\d+)?}) {
750        if ( my $id = ( $1 || $DECODED_ARGS->{'id'} ) ) {
751            my $obj = RT::Dashboard->new( $session{'CurrentUser'} );
752            $obj->LoadById($id);
753            if ( $obj and $obj->id ) {
754                my $tabs = PageMenu;
755                $tabs->child( basics       => title => loc('Basics'),       path => "/Dashboards/Modify.html?id=" . $obj->id);
756                $tabs->child( content      => title => loc('Content'),      path => "/Dashboards/Queries.html?id=" . $obj->id);
757                $tabs->child( subscription => title => loc('Subscription'), path => "/Dashboards/Subscription.html?id=" . $obj->id)
758                    if $obj->CurrentUserCanSubscribe;
759                $tabs->child( show         => title => loc('Show'),         path => "/Dashboards/" . $obj->id . "/" . $obj->Name)
760            }
761        }
762    }
763
764
765    if ( $request_path =~ m{^/Ticket/} ) {
766        if ( ( $DECODED_ARGS->{'id'} || '' ) =~ /^(\d+)$/ ) {
767            my $id  = $1;
768            my $obj = RT::Ticket->new( $session{'CurrentUser'} );
769            $obj->Load($id);
770
771            if ( $obj and $obj->id ) {
772                my $actions = PageMenu()->child( actions => title => loc('Actions'), sort_order  => 95 );
773
774                my %can = %{ $obj->CurrentUser->PrincipalObj->HasRights( Object => $obj ) };
775                # since CurrentUserCanSetOwner returns ($ok, $msg), the parens ensure that $can{} gets $ok
776                ( $can{'_ModifyOwner'} ) = $obj->CurrentUserCanSetOwner();
777                my $can = sub {
778                    unless ($_[0] eq 'ExecuteCode') {
779                        return $can{$_[0]} || $can{'SuperUser'};
780                    } else {
781                        return !RT->Config->Get('DisallowExecuteCode')
782                            && ( $can{'ExecuteCode'} || $can{'SuperUser'} );
783                    }
784                };
785
786                my $tabs = PageMenu();
787                $tabs->child( bookmark => raw_html => $m->scomp( '/Ticket/Elements/Bookmark', id => $id ), sort_order => 98 );
788
789                if ($can->('ModifyTicket')) {
790                    $tabs->child( timer => raw_html => $m->scomp( '/Ticket/Elements/PopupTimerLink', id => $id ), sort_order => 99 );
791                }
792
793                $tabs->child( display => title => loc('Display'), path => "/Ticket/Display.html?id=" . $id );
794                $tabs->child( history => title => loc('History'), path => "/Ticket/History.html?id=" . $id );
795
796                # comment out until we can do it for an individual custom field
797                #if ( $can->('ModifyTicket') || $can->('ModifyCustomField') ) {
798                $tabs->child( basics => title => loc('Basics'), path => "/Ticket/Modify.html?id=" . $id );
799
800                #}
801
802                if ( $can->('ModifyTicket') || $can->('_ModifyOwner') || $can->('Watch') || $can->('WatchAsAdminCc') ) {
803                    $tabs->child( people => title => loc('People'), path => "/Ticket/ModifyPeople.html?id=" . $id );
804                }
805
806                if ( $can->('ModifyTicket') ) {
807                    $tabs->child( dates => title => loc('Dates'), path => "/Ticket/ModifyDates.html?id=" . $id );
808                    $tabs->child( links => title => loc('Links'), path => "/Ticket/ModifyLinks.html?id=" . $id );
809                }
810
811                #if ( $can->('ModifyTicket') || $can->('ModifyCustomField') || $can->('_ModifyOwner') ) {
812                $tabs->child( jumbo => title => loc('Jumbo'), path => "/Ticket/ModifyAll.html?id=" . $id );
813                #}
814
815                if ( RT->Config->Get('EnableReminders') ) {
816                    $tabs->child( reminders => title => loc('Reminders'), path => "/Ticket/Reminders.html?id=" . $id );
817                }
818
819                if ( $can->('ModifyTicket') or $can->('ReplyToTicket') ) {
820                    $actions->child( reply => title => loc('Reply'), path => "/Ticket/Update.html?Action=Respond;id=" . $id );
821                }
822
823                if ( $can->('ModifyTicket') or $can->('CommentOnTicket') ) {
824                    $actions->child( comment => title => loc('Comment'), path => "/Ticket/Update.html?Action=Comment;id=" . $id );
825                }
826
827                if ( $can->('ForwardMessage') ) {
828                    $actions->child( forward => title => loc('Forward'), path => "/Ticket/Forward.html?id=" . $id );
829                }
830
831                my $hide_resolve_with_deps = RT->Config->Get('HideResolveActionsWithDependencies')
832                    && $obj->HasUnresolvedDependencies;
833
834                my $current   = $obj->Status;
835                my $lifecycle = $obj->LifecycleObj;
836                my $i         = 1;
837                foreach my $info ( $lifecycle->Actions($current) ) {
838                    my $next = $info->{'to'};
839                    next unless $lifecycle->IsTransition( $current => $next );
840
841                    my $check = $lifecycle->CheckRight( $current => $next );
842                    next unless $can->($check);
843
844                    next if $hide_resolve_with_deps
845                        && $lifecycle->IsInactive($next)
846                        && !$lifecycle->IsInactive($current);
847
848                    my $action = $info->{'update'} || '';
849                    my $url = '/Ticket/';
850                    $url .= "Update.html?". $query_string->(
851                        $action
852                            ? (Action        => $action)
853                            : (SubmitTicket  => 1, Status => $next),
854                        DefaultStatus => $next,
855                        id            => $id,
856                    );
857                    my $key = $info->{'label'} || ucfirst($next);
858                    $actions->child( $key => title => loc( $key ), path => $url);
859                }
860
861                my ($can_take, $tmsg) = $obj->CurrentUserCanSetOwner( Type => 'Take' );
862                my ($can_steal, $smsg) = $obj->CurrentUserCanSetOwner( Type => 'Steal' );
863                my ($can_untake, $umsg) = $obj->CurrentUserCanSetOwner( Type => 'Untake' );
864                if ( $can_take ){
865                    $actions->child( take => title => loc('Take'), path => "/Ticket/Display.html?Action=Take;id=" . $id );
866                }
867                elsif ( $can_steal ){
868                    $actions->child( steal => title => loc('Steal'), path => "/Ticket/Display.html?Action=Steal;id=" . $id );
869                }
870                elsif ( $can_untake ){
871                       $actions->child( untake => title => loc('Untake'), path => "/Ticket/Display.html?Action=Untake;id=" . $id );
872                }
873
874                # TODO needs a "Can extract article into a class applied to this queue" check
875                $actions->child( 'extract-article' =>
876                    title => loc('Extract Article'),
877                    path  => "/Articles/Article/ExtractIntoClass.html?Ticket=".$obj->id,
878                ) if $session{CurrentUser}->HasRight( Right => 'ShowArticlesMenu', Object => RT->System );
879
880                if ( RT::Config->Get( 'ShowSearchNavigation', $session{'CurrentUser'} ) ) {
881                    if ( defined $session{"tickets"} ) {
882                        # we have to update session data if we get new ItemMap
883                        my $updatesession;
884                        $updatesession = 1 unless ( $session{"tickets"}->{'item_map'} );
885
886                        my $item_map = $session{"tickets"}->ItemMap;
887
888                        if ($updatesession) {
889                            $session{"tickets"}->PrepForSerialization();
890                        }
891
892                        my $search = Menu()->child('search')->child('tickets');
893                        # Don't display prev links if we're on the first ticket
894                        if ( $item_map->{$id}->{prev} ) {
895                            $search->child( first =>
896                                title => '<< ' . loc('First'), class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{first});
897                            $search->child( prev =>
898                                title => '< ' . loc('Prev'),   class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{$id}->{prev});
899                        }
900                        # Don't display next links if we're on the last ticket
901                        if ( $item_map->{$id}->{next} ) {
902                            $search->child( next =>
903                                title => loc('Next') . ' >',  class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{$id}->{next});
904                            if ( $item_map->{last} ) {
905                                $search->child( last =>
906                                    title => loc('Last') . ' >>', class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{last});
907                            }
908                        }
909                    }
910                }
911            }
912        }
913    }
914
915    # Scope here so we can share in the Privileged callback
916    my $args      = '';
917    my $has_query = '';
918    if (
919        (
920               $request_path =~ m{^/(?:Ticket|Search)/}
921            && $request_path !~ m{^/Search/Simple\.html}
922        )
923        || (   $request_path =~ m{^/Search/Simple\.html}
924            && $DECODED_ARGS->{'q'} )
925      )
926    {
927        my $search = Menu()->child('search')->child('tickets');
928        my $current_search = $session{"CurrentSearchHash"} || {};
929        my $search_id = $DECODED_ARGS->{'SavedSearchLoad'} || $DECODED_ARGS->{'SavedSearchId'} || $current_search->{'SearchId'} || '';
930        my $chart_id = $DECODED_ARGS->{'SavedChartSearchId'} || $current_search->{SavedChartSearchId};
931
932        $has_query = 1 if ( $DECODED_ARGS->{'Query'} or $current_search->{'Query'} );
933
934        my %query_args;
935        my %fallback_query_args = (
936            SavedSearchId => ( $search_id eq 'new' ) ? undef : $search_id,
937            SavedChartSearchId => $chart_id,
938            (
939                map {
940                    my $p = $_;
941                    $p => $DECODED_ARGS->{$p} || $current_search->{$p}
942                } qw(Query Format OrderBy Order Page)
943            ),
944        );
945
946        if ( defined ( my $rows = $DECODED_ARGS->{'RowsPerPage'} // $current_search->{'RowsPerPage'} ) ) {
947            $fallback_query_args{RowsPerPage} = $rows;
948        }
949
950        if ($QueryString) {
951            $args = '?' . $QueryString;
952        }
953        else {
954            my %final_query_args = ();
955            # key => callback to avoid unnecessary work
956
957            for my $param (keys %fallback_query_args) {
958                $final_query_args{$param} = defined($QueryArgs->{$param})
959                                          ? $QueryArgs->{$param}
960                                          : $fallback_query_args{$param};
961            }
962
963            for my $field (qw(Order OrderBy)) {
964                if ( ref( $final_query_args{$field} ) eq 'ARRAY' ) {
965                    $final_query_args{$field} = join( "|", @{ $final_query_args{$field} } );
966                } elsif (not defined $final_query_args{$field}) {
967                    delete $final_query_args{$field};
968                }
969                else {
970                    $final_query_args{$field} ||= '';
971                }
972            }
973
974            $args = '?' . $query_string->(%final_query_args);
975        }
976
977        my $current_search_menu;
978        if ( $request_path =~ m{^/Ticket} ) {
979            $current_search_menu = $search->child( current_search => title => loc('Current Search') );
980            $current_search_menu->path("/Search/Results.html$args") if $has_query;
981        } else {
982            $current_search_menu = PageMenu();
983        }
984
985        $current_search_menu->child( edit_search =>
986            title => loc('Edit Search'), path => "/Search/Build.html" . ( ($has_query) ? $args : '' ) );
987        $current_search_menu->child( advanced =>
988            title => loc('Advanced'),    path => "/Search/Edit.html$args" );
989        if ($has_query) {
990            $current_search_menu->child( results => title => loc('Show Results'), path => "/Search/Results.html$args" );
991        }
992
993        if ( $has_query ) {
994            $current_search_menu->child( bulk  => title => loc('Bulk Update'), path => "/Search/Bulk.html$args" );
995            $current_search_menu->child( chart => title => loc('Chart'),       path => "/Search/Chart.html$args" );
996
997            my $more = $current_search_menu->child( more => title => loc('Feeds') );
998
999            $more->child( spreadsheet => title => loc('Spreadsheet'), path => "/Search/Results.tsv$args" );
1000
1001            my %rss_data = map {
1002                $_ => $QueryArgs->{$_} || $fallback_query_args{$_} || '' }
1003                    qw(Query Order OrderBy);
1004            my $RSSQueryString = "?"
1005                . $query_string->( Query   => $rss_data{Query},
1006                                   Order   => $rss_data{Order},
1007                                   OrderBy => $rss_data{OrderBy}
1008                                 );
1009            my $RSSPath = join '/', map $m->interp->apply_escapes( $_, 'u' ),
1010                $session{'CurrentUser'}->UserObj->Name,
1011                $session{'CurrentUser'}
1012                ->UserObj->GenerateAuthString(   $rss_data{Query}
1013                                               . $rss_data{Order}
1014                                               . $rss_data{OrderBy} );
1015
1016            $more->child( rss => title => loc('RSS'), path => "/NoAuth/rss/$RSSPath/$RSSQueryString");
1017            my $ical_path = join '/', map $m->interp->apply_escapes($_, 'u'),
1018                $session{'CurrentUser'}->UserObj->Name,
1019                $session{'CurrentUser'}->UserObj->GenerateAuthString( $rss_data{Query} ),
1020                $rss_data{Query};
1021            $more->child( ical => title => loc('iCal'), path => '/NoAuth/iCal/'.$ical_path);
1022
1023            if ($request_path =~ m{^/Search/Results.html}
1024                &&                        #XXX TODO better abstraction
1025                $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => RT->System )) {
1026                my $shred_args = $query_string->(
1027                    Search          => 1,
1028                    Plugin          => 'Tickets',
1029                    'Tickets:query' => $rss_data{'Query'},
1030                    'Tickets:limit' => $QueryArgs->{'Rows'},
1031                );
1032
1033                $more->child( shredder => title => loc('Shredder'), path => '/Admin/Tools/Shredder/?' . $shred_args);
1034            }
1035
1036        }
1037    }
1038
1039    if ( $request_path =~ m{^/Article/} ) {
1040        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
1041            my $id = $DECODED_ARGS->{'id'};
1042            my $tabs = PageMenu();
1043
1044            $tabs->child( display => title => loc('Display'), path => "/Articles/Article/Display.html?id=".$id );
1045            $tabs->child( history => title => loc('History'), path => "/Articles/Article/History.html?id=".$id );
1046            $tabs->child( modify  => title => loc('Modify'),  path => "/Articles/Article/Edit.html?id=".$id );
1047        }
1048    }
1049
1050    if ( $request_path =~ m{^/Articles/} ) {
1051        PageWidgets()->child( article_search => raw_html => $m->scomp('/Articles/Elements/GotoArticle') );
1052        PageWidgets()->delete('create_ticket');
1053        PageWidgets()->delete('simple_search');
1054
1055        my $tabs = PageMenu();
1056        $tabs->child( search => title => loc("Search"),       path => "/Articles/Article/Search.html" );
1057        $tabs->child( create => title => loc("New Article" ), path => "/Articles/Article/PreCreate.html" );
1058        if ( $request_path =~ m{^/Articles/Article/} and ( $DECODED_ARGS->{'id'} || '' ) =~ /^(\d+)$/ ) {
1059            my $id  = $1;
1060            my $obj = RT::Article->new( $session{'CurrentUser'} );
1061            $obj->Load($id);
1062
1063            if ( $obj and $obj->id ) {
1064                $tabs->child( display => title => loc("Display"), path => "/Articles/Article/Display.html?id=" . $id );
1065                $tabs->child( history => title => loc('History'), path => '/Articles/Article/History.html?id=' . $id );
1066
1067                if ( $obj->CurrentUserHasRight('ModifyArticle') ) {
1068                    $tabs->child(modify => title => loc('Modify'), path => '/Articles/Article/Edit.html?id=' . $id );
1069                }
1070            }
1071        }
1072
1073    }
1074
1075    if ($request_path =~ m{^/Asset/} and $DECODED_ARGS->{id} and $DECODED_ARGS->{id} !~ /\D/) {
1076        my $page  = PageMenu();
1077        my $id    = $DECODED_ARGS->{id};
1078        my $asset = RT::Asset->new( $session{CurrentUser} );
1079        $asset->Load($id);
1080
1081        if ($asset->id) {
1082            $page->child("display",     title => loc("Display"),        path => "/Asset/Display.html?id=$id");
1083            $page->child("history",     title => loc("History"),        path => "/Asset/History.html?id=$id");
1084            $page->child("basics",      title => loc("Basics"),         path => "/Asset/Modify.html?id=$id");
1085            $page->child("links",       title => loc("Links"),          path => "/Asset/ModifyLinks.html?id=$id");
1086            $page->child("people",      title => loc("People"),         path => "/Asset/ModifyPeople.html?id=$id");
1087            $page->child("dates",       title => loc("Dates"),          path => "/Asset/ModifyDates.html?id=$id");
1088
1089            for my $grouping (RT::CustomField->CustomGroupings($asset)) {
1090                my $cfs = $asset->CustomFields;
1091                $cfs->LimitToGrouping( $asset => $grouping );
1092                next unless $cfs->Count;
1093                $page->child(
1094                    "cf-grouping-$grouping",
1095                    title   => loc($grouping),
1096                    path    => "/Asset/ModifyCFs.html?id=$id;Grouping=" . $m->interp->apply_escapes($grouping, 'u'),
1097                );
1098            }
1099
1100            my $actions = $page->child("actions", title => loc("Actions"));
1101            $actions->child("create-linked-ticket", title => loc("Create linked ticket"), path => "/Asset/CreateLinkedTicket.html?Asset=$id");
1102
1103            my $status    = $asset->Status;
1104            my $lifecycle = $asset->LifecycleObj;
1105            for my $action ( $lifecycle->Actions($status) ) {
1106                my $next = $action->{'to'};
1107                next unless $lifecycle->IsTransition( $status => $next );
1108
1109                my $check = $lifecycle->CheckRight( $status => $next );
1110                next unless $asset->CurrentUserHasRight($check);
1111
1112                my $label = $action->{'label'} || ucfirst($next);
1113                $actions->child(
1114                    $label,
1115                    title   => loc($label),
1116                    path    => "/Asset/Modify.html?id=$id;Update=1;DisplayAfter=1;Status="
1117                                . $m->interp->apply_escapes($next, 'u'),
1118
1119                    class       => "asset-lifecycle-action",
1120                    attributes  => {
1121                        'data-current-status'   => $status,
1122                        'data-next-status'      => $next,
1123                    },
1124                );
1125            }
1126        }
1127    } elsif ($request_path =~ m{^/Asset/Search/}) {
1128        my $page  = PageMenu();
1129        my %search = map @{$_},
1130            grep defined $_->[1] && length $_->[1],
1131            map {ref $DECODED_ARGS->{$_} ? [$_, $DECODED_ARGS->{$_}[0]] : [$_, $DECODED_ARGS->{$_}] }
1132            grep /^(?:q|SearchAssets|!?(Name|Description|Catalog|Status|Role\..+|CF\..+)|Order(?:By)?|Page)$/,
1133            keys %$DECODED_ARGS;
1134        if ( $request_path =~ /Bulk/) {
1135            $page->child('search',
1136                title => loc('Show Results'),
1137                path => '/Asset/Search/?' . (keys %search ? $query_string->(%search) : ''),
1138            );
1139        } else {
1140            $page->child('bulk',
1141                title => loc('Bulk Update'),
1142                path => '/Asset/Search/Bulk.html?' . (keys %search ? $query_string->(%search) : ''),
1143            );
1144        }
1145        $page->child('csv',
1146            title => loc('Download Spreadsheet'),
1147            path  => '/Asset/Search/Results.tsv?' . (keys %search ? $query_string->(%search) : ''),
1148        );
1149    } elsif ($request_path =~ m{^/Admin/Global/CustomFields/Catalog-Assets\.html$}) {
1150        my $page  = PageMenu();
1151        $page->child("create", title => loc("Create New"), path => "/Admin/CustomFields/Modify.html?Create=1;LookupType=" . RT::Asset->CustomFieldLookupType);
1152    } elsif ($request_path =~ m{^/Admin/CustomFields(/|/index\.html)?$}
1153            and $DECODED_ARGS->{'Type'} and $DECODED_ARGS->{'Type'} eq RT::Asset->CustomFieldLookupType) {
1154        my $page  = PageMenu();
1155        $page->child("create")->path( $page->child("create")->path . "&LookupType=" . RT::Asset->CustomFieldLookupType );
1156    } elsif ($request_path =~ m{^/Admin/Assets/Catalogs/}) {
1157        my $page  = PageMenu();
1158        my $actions = $request_path =~ m{/((index|Create)\.html)?$}
1159            ? $page
1160            : $page->child("catalogs", title => loc("Catalogs"), path => "/Admin/Assets/Catalogs/");
1161
1162        $actions->child("select", title => loc("Select"), path => "/Admin/Assets/Catalogs/");
1163        $actions->child("create", title => loc("Create"), path => "/Admin/Assets/Catalogs/Create.html");
1164
1165        my $catalog = RT::Catalog->new( $session{CurrentUser} );
1166        $catalog->Load($DECODED_ARGS->{id}) if $DECODED_ARGS->{id};
1167
1168        if ($catalog->id and $catalog->CurrentUserCanSee) {
1169            my $query = "id=" . $catalog->id;
1170            $page->child("modify", title => loc("Basics"), path => "/Admin/Assets/Catalogs/Modify.html?$query");
1171            $page->child("people", title => loc("Roles"),  path => "/Admin/Assets/Catalogs/Roles.html?$query");
1172
1173            $page->child("cfs", title => loc("Asset Custom Fields"), path => "/Admin/Assets/Catalogs/CustomFields.html?$query");
1174
1175            $page->child("group-rights", title => loc("Group Rights"), path => "/Admin/Assets/Catalogs/GroupRights.html?$query");
1176            $page->child("user-rights",  title => loc("User Rights"),  path => "/Admin/Assets/Catalogs/UserRights.html?$query");
1177
1178            $page->child("default-values", title => loc('Default Values'), path => "/Admin/Assets/Catalogs/DefaultValues.html?$query");
1179        }
1180    }
1181
1182    if ( $request_path =~ m{^/User/(Summary|History)\.html} ) {
1183        if (PageMenu()->child('summary')) {
1184            # Already set up from having AdminUser and ShowConfigTab;
1185            # but rename "Basics" to "Edit" in this context
1186            PageMenu()->child( 'basics' )->title( loc('Edit') );
1187        } elsif ( $session{'CurrentUser'}->HasRight( Object => $RT::System, Right => 'ShowUserHistory' ) ) {
1188            PageMenu()->child( display => title => loc('Summary'), path => '/User/Summary.html?id=' . $DECODED_ARGS->{'id'} );
1189            PageMenu()->child( history => title => loc('History'), path => '/User/History.html?id=' . $DECODED_ARGS->{'id'} );
1190        }
1191    }
1192
1193    if ( $request_path =~ /^\/(?:index.html|$)/ ) {
1194        PageMenu()->child( edit => title => loc('Edit'), path => '/Prefs/MyRT.html' );
1195    }
1196
1197    $m->callback( CallbackName => 'Privileged', Path => $request_path, Search_Args => $args, Has_Query => $has_query, ARGSRef => \%ARGS );
1198};
1199
1200my $build_selfservice_nav = sub {
1201    my $queues = RT::Queues->new( $session{'CurrentUser'} );
1202    $queues->UnLimit;
1203
1204    my $queue_count = 0;
1205    my $queue_id;
1206
1207    while ( my $queue = $queues->Next ) {
1208        next unless $queue->CurrentUserHasRight('CreateTicket');
1209        $queue_id = $queue->id;
1210        $queue_count++;
1211        last if ( $queue_count > 1 );
1212    }
1213
1214
1215    if ( $queue_count > 1 ) {
1216        Menu->child( new => title => loc('New ticket'), path => '/SelfService/CreateTicketInQueue.html' );
1217    } elsif ( $queue_id ) {
1218        Menu->child( new => title => loc('New ticket'), path => '/SelfService/Create.html?Queue=' . $queue_id );
1219    }
1220    my $tickets = Menu->child( tickets => title => loc('Tickets'), path => '/SelfService/' );
1221    $tickets->child( open   => title => loc('Open tickets'),   path => '/SelfService/' );
1222    $tickets->child( closed => title => loc('Closed tickets'), path => '/SelfService/Closed.html' );
1223
1224    Menu->child( "assets", title => loc("Assets"), path => "/SelfService/Asset/" )
1225        if $session{CurrentUser}->HasRight( Right => 'ShowAssetsMenu', Object => RT->System );
1226
1227    my $username = '<span class="current-user">'
1228                 . $m->interp->apply_escapes($session{'CurrentUser'}->Name, 'h')
1229                 . '</span>';
1230    my $about_me = Menu->child( preferences =>
1231        title        => loc('Logged in as [_1]', $username),
1232        escape_title => 0,
1233        sort_order   => 99,
1234    );
1235
1236    if ( ( RT->Config->Get('SelfServiceUserPrefs') || '' ) eq 'view-info' ||
1237       $session{'CurrentUser'}->HasRight( Right => 'ModifySelf', Object => RT->System ) ) {
1238        $about_me->child( prefs => title => loc('Preferences'), path => '/SelfService/Prefs.html' );
1239    }
1240
1241    if ( $session{'CurrentUser'}->Name
1242         && (   !RT->Config->Get('WebRemoteUserAuth')
1243              || RT->Config->Get('WebFallbackToRTLogin') )) {
1244        $about_me->child( logout => title => loc('Logout'), path => '/NoAuth/Logout.html' );
1245    }
1246
1247    if ($session{'CurrentUser'}->HasRight( Right => 'ShowArticle', Object => RT->System )) {
1248        PageWidgets->child( 'goto-article' => raw_html => $m->scomp('/SelfService/Elements/SearchArticle') );
1249    }
1250
1251    PageWidgets->child( goto => raw_html => $m->scomp('/SelfService/Elements/GotoTicket') );
1252
1253    if ($request_path =~ m{^/SelfService/Asset/} and $DECODED_ARGS->{id}) {
1254        my $page = PageMenu();
1255        my $id   = $DECODED_ARGS->{id};
1256        $page->child("display",     title => loc("Display"),        path => "/SelfService/Asset/Display.html?id=$id");
1257        $page->child("history",     title => loc("History"),        path => "/SelfService/Asset/History.html?id=$id");
1258
1259        if (Menu->child("new")) {
1260            my $actions = $page->child("actions", title => loc("Actions"));
1261            $actions->child("create-linked-ticket", title => loc("Create linked ticket"), path => "/SelfService/Asset/CreateLinkedTicket.html?Asset=$id");
1262        }
1263    }
1264
1265    $m->callback( CallbackName => 'SelfService', Path => $request_path, ARGSRef => \%ARGS );
1266};
1267
1268
1269
1270if ( $request_path !~ m{^/SelfService/} ) {
1271    $build_main_nav->();
1272} else {
1273    $build_selfservice_nav->();
1274}
1275
1276
1277
1278
1279</%INIT>
1280<%ARGS>
1281$show_menu => 1
1282$QueryString => ''
1283$QueryArgs => {}
1284</%ARGS>
1285