%# BEGIN BPS TAGGED BLOCK {{{
%#
%# COPYRIGHT:
%#
%# This software is Copyright (c) 1996-2025 Best Practical Solutions, LLC
%#                                          <sales@bestpractical.com>
%#
%# (Except where explicitly superseded by other copyright notices)
%#
%#
%# LICENSE:
%#
%# This work is made available to you under the terms of Version 2 of
%# the GNU General Public License. A copy of that license should have
%# been provided with this software, but in any event can be snarfed
%# from www.gnu.org.
%#
%# This work is distributed in the hope that it will be useful, but
%# WITHOUT ANY WARRANTY; without even the implied warranty of
%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
%# General Public License for more details.
%#
%# You should have received a copy of the GNU General Public License
%# along with this program; if not, write to the Free Software
%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
%# 02110-1301 or visit their web page on the internet at
%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
%#
%#
%# CONTRIBUTION SUBMISSION POLICY:
%#
%# (The following paragraph is not intended to limit the rights granted
%# to you to modify and distribute this software under the terms of
%# the GNU General Public License and is only of importance to you if
%# you choose to contribute your changes and enhancements to the
%# community by submitting them to Best Practical Solutions, LLC.)
%#
%# By intentionally submitting any modifications, corrections or
%# derivatives to this work, or any other work intended for use with
%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
%# you are the copyright holder for those contributions and you grant
%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
%# royalty-free, perpetual, license to use, copy, create derivative
%# works based on those contributions, and sublicense and distribute
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
<%args>
$Context
$Principals
$AddPrincipal => undef
</%args>
<%init>
# Let callbacks get at principals and context before we do anything with them
$m->callback( Principals => $Principals, Context => $Context );

# Try to detect if we want to include an add user/group box
unless ( $AddPrincipal ) {
    my $last = $Principals->[-1];
    if ( $last->[0] =~ /Groups/i ) {
        $AddPrincipal = 'group'; # loc
    }
    elsif ( $last->[0] =~ /Users/i ) {
        $AddPrincipal = 'user'; # loc
    }
}

my $anchor = $DECODED_ARGS->{Anchor} || '';
if ($anchor =~ /AddPrincipal/) {
    for my $type ("group", "user") {
        my $record = _ParseACLNewPrincipal($DECODED_ARGS, $type)
            or next;
        if ($record->PrincipalId) {
            $anchor = '#' . $record->PrincipalId;
            last;
        }
    }
}
</%init>
%# Principals is an array of arrays, where the inner arrays are like:
%#      [ 'Category name' => $CollectionObj => 'DisplayColumn' => 1 ]
%# The last value is a boolean determining if the value of DisplayColumn
%# should be loc()-ed before display.

<script type="text/javascript">
  jQuery(function() {
      function sync_anchor(hash) {
          if (!hash.length) return;
          window.location.hash = hash;
          jQuery(".rights-editor input[name=Anchor]").val(hash);
      }
      sync_anchor(<% $anchor |n,j %>);

      jQuery('.rights-editor .principal-tabs a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
          var anchor = jQuery(this).attr('href').replace('#acl-', '#');
          sync_anchor(anchor);
          jQuery('.rights-editor .category-tabs a[data-toggle="tab"]:visible:first').tab('show');
          if ( anchor == '#AddPrincipal' ) {
              jQuery('.rights-editor li.add-principal input').focus();
          }
      });

      jQuery('li.add-principal input').focus(function() {
          jQuery('.rights-editor .principal-tabs a[data-toggle="tab"][href="#acl-AddPrincipal"]').tab('show');
      });

      var anchor = jQuery(".rights-editor input[name=Anchor]").val();
      if ( anchor && jQuery('.rights-editor .principal-tabs a[data-toggle="tab"][href="' + anchor.replace('#', '#acl-') + '"]' ).length ) {
          jQuery('.rights-editor .principal-tabs a[data-toggle="tab"][href="' + anchor.replace('#', '#acl-') + '"]' ).tab('show');
      }
      else {
          jQuery('.rights-editor .principal-tabs a[data-toggle="tab"]:first').tab('show');
      }

      jQuery('.rights-editor .category-tabs a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
          jQuery.cookie('rights-category-tab', jQuery(this).attr('href'));
      });

      var category_tab = jQuery.cookie('rights-category-tab');
      if ( category_tab && jQuery(category_tab).length ) {
          jQuery('.rights-editor .category-tabs a[data-toggle="tab"][href="' + category_tab + '"]' ).tab('show');
      }
      else {
          jQuery('.rights-editor .category-tabs a[data-toggle="tab"]:visible:first').tab('show');
      };

      // "rights" checkbox state cache...
      var check_counts = {};

      // Before page loads we need to initialize our "rights" checkbox state
      // cache.
      jQuery("div.category-tabs input[type=checkbox]").each(function(index, element) {
          // Evaluating each checkbox and its current check state is the same
          // as evaluating a check event once the page is loaded. However, we
          // must indicate to the process_check_event that we are initializing
          // the cache. That is, we musn't decrement values from count
          // totals for checkboxes that aren't checked. That only happens when
          // a user actually unchecks a box, not when we are initially counting
          // checked or unchecked boxes.
          process_check_event(element, true);
      });

      jQuery("div.category-tabs input[type=checkbox]").change(function() {
          process_check_event(this, false);
      });

      // parameters:
      //   checkbox           - DOM checkbox element that was checked
      //   initializing_cache - a boolean that defines whether or not this
      //                        function was called with the purpose of
      //                        initializing the contents of the check_counts
      //                        cache.
      function process_check_event(checkbox, initializing_cache) {
          var category_tab  = checkbox.getAttribute('data-category-tab');
          var principal_tab = checkbox.getAttribute('data-principal-tab');

          classify_tab(checkbox.checked, category_tab, initializing_cache);
          classify_tab(checkbox.checked, principal_tab, initializing_cache);
      }

      function classify_tab(checked, tab_id, initializing_cache) {
          if (typeof check_counts[tab_id] == 'undefined') {
              check_counts[tab_id] = 0;
          }

          if (checked) {
              check_counts[tab_id]++;
              if (check_counts[tab_id] == 1) {
                  // Then this is the first check and we need to add a class
                  // to the tab.
                  jQuery('#' + tab_id).addClass("tab-aggregates-checked-rights");
              }
          }
          else if (! initializing_cache) {
              check_counts[tab_id]--;
              if (check_counts[tab_id] == 0) {
                  // Then this is the last uncheck and we need to remove a
                  // class from the tab.
                  jQuery('#' + tab_id).removeClass("tab-aggregates-checked-rights");
              }
          }
      }

    var auto_set_own_dashboards;
    jQuery('input[value="ModifySelf"]').change(function() {
        var form = jQuery(this).closest('form');
        if ( jQuery(this).is(':checked') ) {
            if ( form.find('input[value$="OwnDashboard"]:visible:not(:checked)').length ) {
                jQuery('#grant-own-dashboard-rights-modal').modal('show');
            }
        }
        else {
            if ( auto_set_own_dashboards ) {
                form.find('input[value$="OwnDashboard"]:visible:checked').prop('checked', false);
                auto_set_own_dashboards = false;
            }
        }
    });

    jQuery('#grant-own-dashboard-rights-confirm').click(function() {
        var form = jQuery(this).closest('form');
        form.find('input[value$="OwnDashboard"]:visible:not(:checked)').prop('checked', true);
        jQuery('#grant-own-dashboard-rights-modal').modal('hide');
        auto_set_own_dashboards = true;
    });
  });
</script>

<div class="rights-editor">
  <input type="hidden" value="" name="Anchor" />
  <div class="form-row">
    <div class="col-3">
      <div class="principal-tabs">
        <ul class="nav nav-tabs flex-column nav-pills" role="tablist" aria-orientation="vertical">
<%perl>
for my $category (@$Principals) {
    my ($name, $collection, $col, $loc) = @$category;
</%perl>
          <li class="category"><% loc($name) %></li>
<%perl>
    while ( my $obj = $collection->Next ) {
        next
          if $obj->isa( 'RT::Group' )
          && $obj->_CustomRoleObj
          && ( $obj->_CustomRoleObj->Disabled
            || ( $Context->isa( 'RT::Queue' ) && !$obj->_CustomRoleObj->IsAdded( $Context->id ) ) );
        my $display = ref $col eq 'CODE' ? $col->($obj) : $obj->$col;
        my $id = "acl-" . $obj->PrincipalId;
</%perl>
          <li class="nav-item">
            <a href="#<% $id %>" class="nav-link" id="<% "principal-tab-$id" %>" data-toggle="tab" role="tab" aria-controls="<% $id %>" aria-selected="false">
              <% $loc ? loc($display) : $display %>
            </a>
          </li>
<%perl>
    }
}
</%perl>
% if ( $AddPrincipal ) {

<script type="text/javascript">
jQuery(function() {
    jQuery("#AddPrincipalForRights-"+<% lc $AddPrincipal |n,j%>).keyup(function(){
        toggle_addprincipal_validity(this, true);
    }).keydown(function(event){
        event.stopPropagation() // Disable tabs keyboard nav
    });

    jQuery("#AddPrincipalForRights-"+<% lc $AddPrincipal |n,j%>).on("autocompleteselect", addprincipal_onselect);
    jQuery("#AddPrincipalForRights-"+<% lc $AddPrincipal |n,j%>).on("autocompletechange", addprincipal_onchange);
});
</script>

          <li class="add-principal nav-item">
            <a href="#acl-AddPrincipal" class="nav-link" id="principal-tab-acl-AddPrincipal" data-toggle="tab" role="tab" aria-controls="acl-AddPrincipal">
              <input placeholder="<&|/l, loc($AddPrincipal) &>Add [_1]</&>" type="text" value="" class="form-control" data-autocomplete="<% lc $AddPrincipal eq 'user' ? 'Users' : 'Groups' %>"
% if ( lc $AddPrincipal eq 'user' ) {
                data-autocomplete-return="Name"
                data-autocomplete-privileged="1"
% }
                name="AddPrincipalForRights-<% lc $AddPrincipal %>"
                id="AddPrincipalForRights-<% lc $AddPrincipal %>" />

% my $type = lc $AddPrincipal eq 'user' ? loc('username') : loc($AddPrincipal);
              <div class="invalid-feedback hidden"><&|/l, $type &>Invalid [_1]</&></div>
            </a>
          </li>
% }
        </ul>
      </div>
    </div>
    <div class="col-9">
      <div class="tab-content">
<%perl>
# Now generate our rights panels for each principal
for my $category (@$Principals) {
    my ($name, $collection, $col, $loc) = @$category;
    while ( my $obj = $collection->Next ) {
        next
          if $obj->isa( 'RT::Group' )
          && $obj->_CustomRoleObj
          && ( $obj->_CustomRoleObj->Disabled
            || ( $Context->isa( 'RT::Queue' ) && !$obj->_CustomRoleObj->IsAdded( $Context->id ) ) );
        my $display = ref $col eq 'CODE' ? $col->($obj) : $obj->$col;
        my $id = "acl-" . $obj->PrincipalId;
</%perl>

        <div id="<% $id %>" class="tab-pane fade" role="tabpanel" aria-labelledby="<% $id %>-tab">
          <h3>
            <% $loc ? loc($display) : $display %>
<%perl>
if ($obj->isa('RT::Group') and $obj->Domain eq 'UserDefined') {
    my $subgroups = $obj->GroupMembersObj( Recursively => 1 );
    $subgroups->LimitToUserDefinedGroups;
    $subgroups->Limit( FIELD => 'Name', OPERATOR => '!=', VALUE => $obj->Name, CASESENSITIVE => 0 );

    if ( $subgroups->Count ) {
        my $inc = join ", ", map $_->Name, @{$subgroups->ItemsArrayRef};
</%perl>
            <span class="subgroups"><&|/l, $inc &>includes [_1]</&></span>\
<%perl>
    }
}
</%perl>
          </h3>
          <& EditRightsCategoryTabs, Context => $Context, Principal => $obj, id => $id &>
        </div>
<%perl>
    }
}

if ( $AddPrincipal ) {
</%perl>
        <div id="acl-AddPrincipal" class="tab-pane fade" role="tabpanel" aria-labelledby="acl-AddPrincipal-tab">
          <h3><&|/l, loc($AddPrincipal) &>Add rights for this [_1]</&></h3>
          <& EditRightsCategoryTabs, Context => $Context, id => 'acl-AddPrincipal' &>
        </div>
% }
      </div>
    </div>
  </div>
</div>

<div class="modal fade" id="grant-own-dashboard-rights-modal">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title"><&|/l&>Grant Dashboard Rights</&></h5>
        <a href="javascript:void(0)" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </a>
      </div>
      <div class="modal-body">
        <p>
          <&|/l&>Users need these additional rights to fully customize their own "RT at a glance":</&>
        </p>
        <ul class="list-group-compact">
%       for my $item ( qw/Create Delete Modify See/ ) {
          <li class="list-group-item"><% $item %>OwnDashboard</li>
%       }
        </ul>
        <p>
          <&|/l&>Grant these rights also? (Make sure to Save Changes)</&>
        </p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-primary button form-control" data-dismiss="modal"><&|/l&>No</&></button>
        <button type="button" class="btn btn-primary button form-control" id="grant-own-dashboard-rights-confirm"><&|/l&>Yes</&></button>
      </div>
    </div>
  </div>
</div>
