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