Merging in the past three months' work on ACL tracing tools.
authorDan
Sat, 08 Nov 2008 22:37:59 -0500
changeset 729 ebac7eeb89eb
parent 728 067a6173820c
child 730 b09cb1dab505
Merging in the past three months' work on ACL tracing tools.
includes/clientside/css/enano-shared.css
includes/clientside/static/acl.js
includes/clientside/static/enano-lib-basic.js
includes/pageutils.php
language/english/admin.json
--- a/includes/clientside/css/enano-shared.css	Sat Nov 08 22:37:40 2008 -0500
+++ b/includes/clientside/css/enano-shared.css	Sat Nov 08 22:37:59 2008 -0500
@@ -887,3 +887,26 @@
   padding: 10px;
 }
 
+/*
+ * ACL tracing tools
+ */
+
+div.acl_inherit {
+  padding: 5px;
+  margin-bottom: 1px;
+}
+
+td.acl_inherit_key {
+  width: 15px;
+}
+
+.acl_enano_default   { background-color: #FFFFC6; }
+.acl_global_everyone { background-color: #D6D6FF; }
+.acl_global_group    { background-color: #C6C6FF; }
+.acl_global_user     { background-color: #B6B6FF; }
+.acl_pg_everyone     { background-color: #D6FFD6; }
+.acl_pg_group        { background-color: #C6FFC6; }
+.acl_pg_user         { background-color: #B6FFB6; }
+.acl_local_everyone  { background-color: #FFD6D6; }
+.acl_local_group     { background-color: #FFC6C6; }
+.acl_local_user      { background-color: #FFB6B6; }
--- a/includes/clientside/static/acl.js	Sat Nov 08 22:37:40 2008 -0500
+++ b/includes/clientside/static/acl.js	Sat Nov 08 22:37:59 2008 -0500
@@ -165,6 +165,14 @@
   editbtn.href = '#';
   editbtn.innerHTML = $lang.get('acl_btn_show_existing');
   editbtn_wrapper.appendChild(editbtn);
+  
+  // tracer button
+  var tracebtn = document.createElement('a');
+  tracebtn.href = '#';
+  tracebtn.innerHTML = $lang.get('acl_btn_view_effective');
+  editbtn_wrapper.appendChild(document.createElement('br'));
+  editbtn_wrapper.appendChild(tracebtn);
+  
   main.appendChild(editbtn_wrapper);
   
   editbtn.onclick = function()
@@ -173,6 +181,12 @@
     return false;
   }
   
+  tracebtn.onclick = function()
+  {
+    aclSetViewDebugTools();
+    return false;
+  }
+  
   selector = document.createElement('div');
   
   grpsel = __aclBuildGroupsHTML(groups);
@@ -525,6 +539,9 @@
           case 'list_existing':
             aclSetViewListExistingRespond(data);
             break;
+          case 'trace':
+            aclDrawTraceWrapper(data);
+            break;
           default:
             handle_invalid_json(ajax.responseText);
             break;
@@ -658,7 +675,7 @@
 
 function __aclBuildWizardWindow()
 {
-  darken(aclDisableTransitionFX);
+  darken(aclDisableTransitionFX, 70, 'acldarkener');
   box = document.createElement('div');
   box.style.width = '640px'
   box.style.height = '440px';
@@ -781,13 +798,13 @@
   {
     if ( aclDisableTransitionFX )
     {
-      enlighten(true);
+      enlighten(true, 'acldarkener');
       el.parentNode.removeChild(el);
     }
     else
     {
       opacity(aclManagerID, 100, 0, 500);
-      setTimeout('var el = document.getElementById(aclManagerID); el.parentNode.removeChild(el); enlighten();', 750);
+      setTimeout('var el = document.getElementById(aclManagerID); el.parentNode.removeChild(el); enlighten(false, "acldarkener");', 750);
     }
   }
 }
@@ -896,6 +913,14 @@
       obj['namespace'] = aclDataCache.namespace;
       __aclJSONSubmitAjaxHandler(obj);
       break;
+    case 'trace':
+      var params = {
+        mode: 'trace',
+        user: document.getElementById(aclManagerID + 'trace_user').value,
+        page: document.getElementById(aclManagerID + 'trace_page').value
+      };
+      __aclJSONSubmitAjaxHandler(params);
+      break;
     default:
       alert("JSON form submit: invalid mode string "+mode+", stopping execution");
       return false;
@@ -1075,6 +1100,361 @@
   }
 }
 
+function aclSetViewDebugTools()
+{
+  // selection window for viewing effective permissions
+  var main = document.getElementById(aclManagerID + '_main');
+  main.innerHTML = '';
+ 
+  // set the submission handler to trace
+  var thefrm = document.forms[form.name];
+  var modeobj = form_fetch_field(thefrm, 'mode');
+  modeobj.value = 'trace';
+  
+  // show the back button
+  document.getElementById(aclManagerID + '_back').style.display = 'inline';
+  
+  //
+  // start building
+  //
+  
+  // selection interface
+  var selector = document.createElement('div');
+  
+    var table = document.createElement('table');
+    
+    // username
+    var tr_user = document.createElement('tr');
+    var td_user_l = document.createElement('td');
+    var lbl_user = document.createElement('label');
+    lbl_user.setAttribute('for', aclManagerID + 'trace_user');
+    lbl_user.appendChild(document.createTextNode($lang.get('acl_lbl_trace_user')));
+    td_user_l.appendChild(lbl_user);
+    tr_user.appendChild(td_user_l);
+    
+    var td_user_i = document.createElement('td');
+    var i_user = document.createElement('input');
+    i_user.type = 'text';
+    i_user.id = aclManagerID + 'trace_user';
+    i_user.onkeyup = function() { new AutofillUsername(this); };
+    i_user.size = '20';
+    td_user_i.appendChild(i_user);
+    tr_user.appendChild(td_user_i);
+    
+    table.appendChild(tr_user);
+    
+    // page
+    var tr_page = document.createElement('tr');
+    var td_page_l = document.createElement('td');
+    var lbl_page = document.createElement('label');
+    lbl_page.setAttribute('for', aclManagerID + 'trace_page');
+    lbl_page.appendChild(document.createTextNode($lang.get('acl_lbl_trace_page')));
+    td_page_l.appendChild(lbl_page);
+    tr_page.appendChild(td_page_l);
+    
+    var td_page_i = document.createElement('td');
+    var i_page = document.createElement('input');
+    i_page.type = 'text';
+    i_page.id = aclManagerID + 'trace_page';
+    i_page.onkeyup = function() { new AutofillPage(this); };
+    i_page.size = '20';
+    td_page_i.appendChild(i_page);
+    tr_page.appendChild(td_page_i);
+    
+    table.appendChild(tr_page);
+    
+    selector.appendChild(table);
+  
+  // wrapper
+  
+  var container = document.createElement('div');
+  
+    container.style.margin = 'auto';
+    container.style.width = '360px';
+    container.style.paddingTop = '90px';
+    
+    var head = document.createElement('h2');
+    head.appendChild(document.createTextNode($lang.get('acl_lbl_trace_title')));
+    
+    var desc = document.createElement('p');
+    desc.innerHTML = $lang.get('acl_lbl_trace_body');
+    
+    container.appendChild(head);
+    container.appendChild(desc);
+    container.appendChild(selector);
+  
+  main.appendChild(container);
+}
+
+function aclTraceKey()
+{
+  var div = document.createElement('div');
+  $(div).addClass('tblholder');
+  var table = document.createElement('table');
+  $(table).attr('cellspacing', '1').attr('cellpadding', '4');
+  
+  var inherit_list = ['enano_default', 'global_everyone', 'global_group', 'global_user', 'pg_everyone', 'pg_group', 'pg_user', 'local_everyone', 'local_group', 'local_user'];
+  for ( var i = 0; i < inherit_list.length; i++ )
+  {
+    var t = inherit_list[i];
+    var tr = document.createElement('tr');
+    var td_key = document.createElement('td');
+    $(td_key).addClass('acl_' + t).addClass('acl_inherit_key');
+    tr.appendChild(td_key);
+    var td_explain = document.createElement('td');
+    $(td_explain).addClass(i % 2 == 0 ? 'row1' : 'row2');
+    td_explain.appendChild(document.createTextNode($lang.get('acl_inherit_key_' + t)));
+    tr.appendChild(td_explain);
+    table.appendChild(tr);
+  }
+  div.appendChild(table);
+  return div;
+}
+
+function aclTraceModalKey()
+{
+  load_component('messagebox');
+  miniPrompt(function(parent)
+    {
+      // heading
+      var h3 = document.createElement('h3');
+      h3.appendChild(document.createTextNode($lang.get('acl_msg_trace_key')));
+      parent.appendChild(h3);
+      
+      var key = aclTraceKey();
+      parent.appendChild(key);
+      
+      var p = document.createElement('p');
+      $(p).css('text-align', 'center');
+      
+      var closer = document.createElement('a');
+      $(closer).addClass('abutton').addClass('abutton_red').css('font-weight', 'bold');
+      closer.appendChild(document.createTextNode($lang.get('etc_close')));
+      closer.href = '#';
+      $(closer).click(function(e)
+        {
+          miniPromptDestroy(this);
+          return false;
+        });
+      
+      p.appendChild(closer);
+      parent.appendChild(p);
+    });
+}
+
+function aclDrawTraceWrapper(data)
+{
+  var trace_by_perm = aclDrawTraceByPerm(data);
+  var trace_by_rule = aclDrawTraceByRule(data);
+  
+  trace_by_perm.id = 'aclDebugTraceViewPerm';
+  trace_by_rule.id = 'aclDebugTraceViewRule';
+  
+  var start_with_rule = ( readCookie('acl_trace_view') == 'rule' );
+  
+  if ( start_with_rule )
+  {
+    trace_by_perm.style.display = 'none';
+  }
+  else
+  {
+    trace_by_rule.style.display = 'none';
+  }
+  
+  // selection window for viewing effective permissions
+  var main = document.getElementById(aclManagerID + '_main');
+  main.innerHTML = '';
+  
+  var wrapper = document.createElement('div');
+  $(wrapper).css('padding-bottom', '20px');
+  
+  var floatlink = document.createElement('div');
+  $(floatlink).css('float', 'right').css('margin-left', '20px').css('margin-bottom', '20px').css('text-align', 'right');
+  var a_toggle = document.createElement('a');
+  $(a_toggle).attr('id', 'aclDebugTraceViewToggle');
+  a_toggle.innerHTML = '&raquo; ';
+  a_toggle.innerHTML += start_with_rule ? $lang.get('acl_btn_sort_perm') : $lang.get('acl_btn_sort_rule');
+  a_toggle.href = '#';
+  floatlink.appendChild(a_toggle);
+  floatlink.appendChild(document.createElement('br'));
+  var a_key = document.createElement('a');
+  $(a_key).css('font-size', 'smaller');
+  a_key.innerHTML = '&raquo; ';
+  a_key.innerHTML += $lang.get('acl_btn_view_key');
+  a_key.href = '#';
+  floatlink.appendChild(a_key);
+  wrapper.appendChild(floatlink);
+  
+  var h3 = document.createElement('h3');
+  h3.appendChild(document.createTextNode($lang.get('acl_msg_debug_main_title')));
+  wrapper.appendChild(h3);
+  var p = document.createElement('p');
+  p.appendChild(document.createTextNode($lang.get('acl_msg_debug_main_body')));
+  wrapper.appendChild(p);
+  
+  wrapper.appendChild(trace_by_perm);
+  wrapper.appendChild(trace_by_rule);
+  
+  main.appendChild(wrapper);
+  
+  $(a_toggle).click(function(e)
+    {
+      aclTraceToggleViews();
+      return false;
+    });
+  
+  $(a_key).click(function(e)
+    {
+      aclTraceModalKey();
+      return false;
+    });
+}
+
+function aclTraceToggleViews()
+{
+  var trace_by_perm = document.getElementById('aclDebugTraceViewPerm');
+  var trace_by_rule = document.getElementById('aclDebugTraceViewRule');
+  
+  var toggler = document.getElementById('aclDebugTraceViewToggle');
+  var newtext;
+  
+  if ( trace_by_perm.style.display == 'none' )
+  {
+    newtext = $lang.get('acl_btn_sort_rule');
+    $(trace_by_rule).hide('blind', {}, 750, function()
+      {
+        $(trace_by_perm).show('blind', {}, 750);
+      });
+    createCookie('acl_trace_view', 'perm');
+  }
+  else
+  {
+    newtext = $lang.get('acl_btn_sort_perm');
+    $(trace_by_perm).hide('blind', {}, 750, function()
+      {
+        $(trace_by_rule).show('blind', {}, 750);
+      });
+    createCookie('acl_trace_view', 'rule');
+  }
+  $(toggler).fadeOut(500, function()
+    {
+      this.innerHTML = '&raquo; ' + newtext;
+      $(this).fadeIn(500);
+    });
+}
+
+function aclDrawTraceByPerm(data)
+{
+  var wrapper = document.createElement('div');
+  // wrapper.style.display = 'none';
+  
+  // temporarily append wrapper to body to allow onclick to work
+  // var body = document.getElementsByTagName('body')[0];
+  // body.appendChild(wrapper);  
+  
+  for ( var i in data.perms )
+  {
+    var perm = data.perms[i];
+    var item = document.createElement('div');
+    item.className = perm.divclass;
+    
+    // first row - permission name + current setting
+    // use innerHTML here to allow for HTML in localized permission types
+    item.innerHTML += '<b>' + perm.perm_name + ' - ' + perm.perm_value + '</b>';
+    item.appendChild(document.createElement('br'));
+    
+    // second row - permission localized name + rule ID
+    var sm = document.createElement('small');
+    sm.innerHTML = perm.perm_src;
+    
+    item.appendChild(sm);
+    
+    wrapper.appendChild(item);
+    
+    // whole row is now in the document
+    if ( perm.rule_id != -1 )
+    {
+      sm.innerHTML += ' [';
+      // rule is editable
+      var editlink = document.createElement('a');
+      editlink.href = 'javascript:ajaxOpenDirectACLRule(' + perm.rule_id + ');';
+      editlink.appendChild(document.createTextNode($lang.get('acl_btn_edit_rule')));
+      sm.appendChild(editlink);
+      sm.innerHTML += ']';
+    }
+  }
+  
+  // var ret = wrapper.cloneNode(true);
+  // body.removeChild(wrapper);
+  // wrapper = false;
+  // ret.style.display = 'block';
+  // console.debug(ret);
+  // return ret;
+  return wrapper;
+}
+
+function aclDrawTraceByRule(data)
+{
+  var wrapper = document.createElement('div');
+  var groupdata = {};
+  
+  for ( var i in data.perms )
+  {
+    var perm = data.perms[i];
+    if ( !groupdata[perm['rule_id']] )
+    {
+      groupdata[perm['rule_id']] = {
+        meta: {
+          divclass: perm.divclass,
+          perm_src: perm.perm_src,
+          rule_id: perm.rule_id
+        },
+        rules: {}
+      };
+    }
+    groupdata[perm['rule_id']]['rules'][i] = perm;
+  }
+  
+  console.debug('draw by rule - group data: ', groupdata);
+  
+  for ( var i in groupdata )
+  {
+    var group = groupdata[i];
+    var grp = document.createElement('div');
+    var head = document.createElement('div');
+    head.className = group.meta.divclass;
+    var span = document.createElement('span');
+    span.style.fontSize = 'larger';
+    span.appendChild(document.createTextNode(group.meta.perm_src));
+    head.appendChild(span);
+    if ( group.meta.rule_id != -1 )
+    {
+      head.innerHTML += ' [';
+      // rule is editable
+      var editlink = document.createElement('a');
+      editlink.href = 'javascript:ajaxOpenDirectACLRule(' + group.meta.rule_id + ');';
+      editlink.appendChild(document.createTextNode($lang.get('acl_btn_edit_rule')));
+      head.appendChild(editlink);
+      head.innerHTML += ']';
+    }
+    grp.appendChild(head);
+    for ( var i in group.rules )
+    {
+      var rule = group.rules[i];
+      var rulediv = document.createElement('div');
+      rulediv.style.padding = '3px 12px';
+      rulediv.innerHTML += rule.perm_name + ': ';
+      var b = document.createElement('strong');
+      b.appendChild(document.createTextNode(rule.perm_value));
+      rulediv.appendChild(b);
+      grp.appendChild(rulediv);
+    }
+    wrapper.appendChild(grp);
+  }
+  
+  return wrapper;
+}
+
 function aclShowPresetLoader()
 {
   var prompt = miniPrompt(function(parent)
--- a/includes/clientside/static/enano-lib-basic.js	Sat Nov 08 22:37:40 2008 -0500
+++ b/includes/clientside/static/enano-lib-basic.js	Sat Nov 08 22:37:59 2008 -0500
@@ -447,6 +447,9 @@
       case 'rename':
         ajaxRename();
         break;
+      case 'aclmanager':
+        ajaxOpenACLManager();
+        break;
     }
   }
 });
--- a/includes/pageutils.php	Sat Nov 08 22:37:40 2008 -0500
+++ b/includes/pageutils.php	Sat Nov 08 22:37:59 2008 -0500
@@ -2028,6 +2028,53 @@
               'mode' => 'success'
             );
           break;
+        case 'trace':
+          list($targetpid, $targetns) = RenderMan::strToPageID($parms['page']);
+          $perms = $session->fetch_page_acl_user($parms['user'], $targetpid, $targetns);
+          $perm_table = array(
+              AUTH_ALLOW => 'acl_lbl_field_allow',
+              AUTH_WIKIMODE => 'acl_lbl_field_wikimode',
+              AUTH_DISALLOW => 'acl_lbl_field_disallow',
+              AUTH_DENY => 'acl_lbl_field_deny'
+            );
+          
+          $return = array(
+            'mode' => 'trace',
+            'perms' => array()
+          );
+          
+          foreach ( $perms->perm_resolve_table as $perm_type => $lookup_data )
+          {
+            if ( !$session->check_acl_scope($perm_type, $targetns) )
+              continue;
+            
+            $src_l10n = $lang->get($session->acl_inherit_lang_table[$lookup_data['src']], $lookup_data);
+            $divclass = preg_replace('/^acl_inherit_/', '', $session->acl_inherit_lang_table[$lookup_data['src']]);
+            $perm_string = $lang->get($perm_table[$perms->perms[$perm_type]]);
+            $perm_name = $lang->get($session->acl_descs[$perm_type]);
+            
+            $return['perms'][$perm_type] = array(
+                'divclass' => "acl_inherit acl_$divclass",
+                'perm_type' => $perm_type,
+                'perm_name' => $perm_name,
+                'perm_value' => $perm_string,
+                'perm_src' => $src_l10n,
+                'rule_id' => intval($lookup_data['rule_id'])
+              );
+          }
+          
+          // group rules if possible
+          $return['groups'] = array();
+          foreach ( $return['perms'] as $rule )
+          {
+            if ( !isset($return['groups'][$rule['rule_id']]) )
+            {
+              $return['groups'][$rule['rule_id']] = array();
+            }
+            $return['groups'][$rule['rule_id']][] = $rule['perm_type'];
+          }
+          
+          break;
         default:
           return Array('mode'=>'error','error'=>'Hacking attempt');
           break;
--- a/language/english/admin.json	Sat Nov 08 22:37:40 2008 -0500
+++ b/language/english/admin.json	Sat Nov 08 22:37:59 2008 -0500
@@ -107,6 +107,8 @@
       lbl_scope: 'What should this access rule control?',
       lbl_welcome_title: 'Manage page access',
       lbl_welcome_body: 'Please select who should be affected by this access rule.',
+      lbl_trace_title: 'View effective permissions',
+      lbl_trace_body: 'See what permissions are effective and where. <a href="http://docs.enanocms.org/Help:4.2" onclick="window.open(this.href); return false;">Learn about precedence and scope</a>',
       lbl_editwin_title_create: 'Create access rule',
       lbl_editwin_title_edit: 'Editing permissions',
       lbl_editwin_body: 'This panel allows you to edit what the %target_type% "<b>%target%</b>" can do on <b>%scope_type%</b>. Unless you set a permission to "Deny", these permissions may be overridden by other rules.',
@@ -133,6 +135,8 @@
                    <li><b>Deny</b> means that the user is denied access to the item. This setting overrides all other permissions.</li>
                    <li><b>Inherit</b> forces the permission to be unset and thus inherited from the defaults. Setting every permission to Inherit is the same as deleting the rule.</li>
                  </ul>',
+      lbl_trace_user: 'See permissions for:',
+      lbl_trace_page: 'On page:',
       
       scope_type_wholesite: 'this entire site',
       scope_type_thispage: 'this page',
@@ -163,10 +167,11 @@
       msg_list_on_page: ' on page: %page_name%',
       msg_list_on_page_group: ' for page group: %page_group%',
       msg_list_entire_site: ' for the entire site',
-      
       msg_list_score: 'Score: %score% (%desc%) %info%',
-      
       msg_no_presets: 'No presets are defined. Define a preset by setting all the ACL settings to what you want, and then hitting Save. <a %close_flags%>Close</a>',
+      msg_debug_main_title: 'View effective permissions',
+      msg_debug_main_body: 'This tool allows you to see what actual permissions are in use. It can be helpful if you are struggling to determine why a certain action is being allowed or denied. There are two views available for this window: you can either view the information sorted by individual actions, or group actions by which rule sets them.',
+      msg_trace_key: 'Color guide',
       
       btn_success_dismiss: 'dismiss',
       btn_success_close: 'close manager',
@@ -175,10 +180,15 @@
       btn_returnto_editor: 'Return to ACL editor',
       btn_returnto_userscope: 'Return to user/scope selection',
       btn_show_existing: '&raquo; View existing rules',
+      btn_view_effective: '&raquo; Show diagnostic tools',
       btn_close: 'Close ACL wizard',
       btn_edit_presets: 'Presets: <a %load_flags%>Load</a> | <a %save_flags%>Save</a>',
       btn_load_preset: 'Load preset',
       btn_save_preset: 'Save preset',
+      btn_edit_rule: 'edit',
+      btn_view_key: 'View color key',
+      btn_sort_perm: 'Sort individually',
+      btn_sort_rule: 'Sort by rule',
       
       inherit_enano_default: 'Enano defaults',
       inherit_global_everyone: 'Rule for everyone on the entire site',
@@ -190,6 +200,17 @@
       inherit_local_everyone: 'Rule for everyone on this page',
       inherit_local_group: 'Rule for the group "%group_name%" on this page',
       inherit_local_user: 'Rule for this user on this page',
+      
+      inherit_key_enano_default: '%this.acl_inherit_enano_default% (most broad)',
+      inherit_key_global_everyone: '%this.acl_inherit_global_everyone%',
+      inherit_key_global_group: 'Rule for a user group on the entire site',
+      inherit_key_global_user: '%this.acl_inherit_global_user%',
+      inherit_key_pg_everyone: 'Rule for everyone in a specific page group',
+      inherit_key_pg_group: 'Rule for a usergroup on a specific page group',
+      inherit_key_pg_user: 'Rule for this user in a specific page group',
+      inherit_key_local_everyone: '%this.acl_inherit_local_everyone%',
+      inherit_key_local_group: 'Rule for a specific usergroup on this page',
+      inherit_key_local_user: '%this.acl_inherit_local_user% (most specific)',
     },
     acphome: {
       heading_main: 'Welcome to Runt, the Enano administration panel.',
@@ -396,7 +417,7 @@
       // Section Defective By Design link
       heading_dbd: 'Defective By Design Anti-DRM button',
       dbd_intro: 'The Enano project is strongly against Digital Restrictions Management.',
-      dbd_explain: 'DRM infringes on consumer rights by using technical locks to prevent you from using your Fair Use rights granted by copyright law. This means that consumers are harmed when they can\'t copy purchased digital media to their own devices. Furthermore, since most DRM schemes are proprietary and designed to prevent interoperability, you can be locked you into a specific brand or product. You can help spread consumer awareness and show your opposition to DRM through this button. It\'s as easy as checking the box below to place a link to <a href="http://www.defectivebydesign.org">DefectiveByDesign.org</a> on your sidebar.',
+      dbd_explain: 'DRM infringes on consumer rights by using technical locks to prevent you from using your Fair Use rights granted by copyright law. This means that consumers are harmed in many ways, for example when they can\'t copy purchased digital media to their own devices. Furthermore, since most DRM schemes are proprietary and designed to prevent interoperability, you can be locked you into a specific brand or product. You can help spread consumer awareness and show your opposition to DRM through this button. It\'s as easy as checking the box below to place a link to <a href="http://www.defectivebydesign.org">DefectiveByDesign.org</a> on your sidebar.',
       field_stopdrm: 'Help stop DRM by placing a link to DBD on the sidebar!',
       
       // Save button