Added preliminary support for ACL presets. Yay!
authorDan
Mon, 11 Aug 2008 19:52:41 -0400
changeset 679 80bf9b8fe6aa
parent 678 c5d4ce19e640
child 680 4cc27e7abd60
Added preliminary support for ACL presets. Yay!
includes/clientside/static/acl.js
includes/clientside/static/functions.js
includes/pageutils.php
language/english/admin.json
--- a/includes/clientside/static/acl.js	Mon Aug 11 19:52:00 2008 -0400
+++ b/includes/clientside/static/acl.js	Mon Aug 11 19:52:41 2008 -0400
@@ -538,6 +538,15 @@
   
   html = '<h2>'+act_desc+'</h2>';
   html += '<p>' + $lang.get('acl_lbl_editwin_body', { target_type: target_type_t, target: target_name_t, scope_type: scope_type }) + '</p>';
+  
+  // preset management
+  var load_flags = 'href="#" onclick="aclShowPresetLoader(); return false;"';
+  var save_flags = 'href="#" onclick="aclShowPresetSave(); return false;"';
+  html += '<div style="float: right;">';
+  html += $lang.get('acl_btn_edit_presets', { load_flags: load_flags, save_flags: save_flags });
+  html += '</div>';
+  html += '<div style="clear: both;"></div>';
+  
   parser = new templateParser(data.template.acl_field_begin);
   html += parser.run();
   
@@ -853,7 +862,7 @@
       var warned_everyone = false;
       for(var i in aclPermList)
       {
-        selections[aclPermList[i]] = getRadioState(form, aclPermList[i], [1, 2, 3, 4]);
+        selections[aclPermList[i]] = getRadioState(form, aclPermList[i], ['i', 1, 2, 3, 4]);
         // If we're editing permissions for everyone on the entire site and the
         // admin selected to deny privileges, give a stern warning about it.
         if ( selections[aclPermList[i]] == 1 && aclDataCache.target_type == 1 /* ACL_TYPE_GROUP */ && aclDataCache.target_id == 1 && !warned_everyone )
@@ -1060,6 +1069,285 @@
   }
 }
 
+function aclShowPresetLoader()
+{
+  var prompt = miniPrompt(function(parent)
+    {
+      parent.innerHTML = '<img style="display: block; margin: 0 auto;" src="' + cdnPath + '/images/loading-big.gif" />';
+    });
+  var request = toJSONString({
+      mode: 'list_presets'
+    });
+  ajaxPost(stdAjaxPrefix + '&_mode=acljson', 'acl_params=' + ajaxEscape(request), function()
+    {
+      if ( ajax.readyState == 4 && ajax.status == 200 )
+      {
+        if ( !check_json_response(ajax.responseText) )
+        {
+          miniPromptDestroy(prompt);
+          return handle_invalid_json(ajax.responseText);
+        }
+        var response = parseJSON(ajax.responseText);
+        if ( response.mode == 'error' )
+        {
+          alert(response.error);
+          miniPromptDestroy(prompt);
+          return false;
+        }
+        prompt = prompt.firstChild.nextSibling;
+        prompt.style.textAlign = 'center';
+        prompt.innerHTML = '<h3>' + $lang.get('acl_lbl_preset_load_title') + '</h3>';
+        
+        if ( response.presets.length > 0 )
+        {
+          // selection box
+          var para = document.createElement('p');
+          var select = document.createElement('select');
+          
+          var option = document.createElement('option');
+          option.value = '0';
+          option.appendChild(document.createTextNode($lang.get('acl_lbl_preset_load')));
+          select.appendChild(option);
+          
+          for ( var i = 0; i < response.presets.length; i++ )
+          {
+            var preset = response.presets[i];
+            var option = document.createElement('option');
+            option.value = preset.rule_id;
+            option.preset_data = preset;
+            option.appendChild(document.createTextNode($lang.get(preset.preset_name)));
+            select.appendChild(option);
+          }
+          
+          para.appendChild(select);
+          prompt.appendChild(para);
+          
+          // buttons
+          var buttons = document.createElement('p');
+          
+          // load button
+          var btn_load = document.createElement('a');
+          btn_load.className = 'abutton abutton_green';
+          btn_load.style.fontWeight = 'bold';
+          btn_load.appendChild(document.createTextNode($lang.get('acl_btn_load_preset')));
+          btn_load.selectobj = select;
+          btn_load.onclick = function()
+          {
+            if ( this.selectobj.value == '0' )
+            {
+              alert($lang.get('acl_err_select_preset'));
+              return false;
+            }
+            // retrieve preset data
+            for ( var i = 0; i < this.selectobj.childNodes.length; i++ )
+            {
+              if ( this.selectobj.childNodes[i].tagName == 'OPTION' )
+              {
+                var node = this.selectobj.childNodes[i];
+                if ( node.value == this.selectobj.value )
+                {
+                  aclSetRulesAbsolute(node.preset_data.rules);
+                  break;
+                }
+              }
+            }
+            miniPromptDestroy(this);
+            return false;
+          }
+          btn_load.href = '#';
+          buttons.appendChild(btn_load);
+          
+          buttons.appendChild(document.createTextNode(' '));
+          
+          // cancel button
+          var btn_cancel = document.createElement('a');
+          btn_cancel.className = 'abutton';
+          btn_cancel.appendChild(document.createTextNode($lang.get('etc_cancel')));
+          btn_cancel.onclick = function()
+          {
+            miniPromptDestroy(this);
+            return false;
+          }
+          btn_cancel.href = '#';
+          buttons.appendChild(btn_cancel);
+          
+          prompt.appendChild(buttons);
+        }
+        else
+        {
+          // "no presets"
+          prompt.innerHTML += '<p>' + $lang.get('acl_msg_no_presets', { close_flags: 'href="#" onclick="miniPromptDestroy(this); return false;"' }) + '</p>';
+        }
+      }
+    });
+}
+
+function aclSetRulesAbsolute(rules)
+{
+  __aclSetAllRadios('i');
+  
+  var form = document.forms[aclManagerID + '_formobj'];
+  if (!form)
+  {
+    return false;
+  }
+  var inputs = form.getElementsByTagName('input');
+  var radios = new Array();
+  var dbg = '';
+  for(var i = 0; i < inputs.length; i++)
+  {
+    if(inputs[i].type == 'radio')
+      radios.push(inputs[i]);
+  }
+  for(var i in radios)
+  {
+    if ( typeof(rules[ radios[i]['name'] ]) == 'number' )
+    {
+      radios[i].checked = ( rules[radios[i]['name']] == radios[i].value );
+    }
+  }
+}
+
+function aclShowPresetSave()
+{
+  miniPrompt(function(parent)
+    {
+      parent.style.textAlign = 'center';
+      
+      parent.innerHTML = '<h3>' + $lang.get('acl_lbl_preset_save_title') + '</h3>';
+      var input = document.createElement('input');
+      input.id = aclManagerID + '_preset_save';
+      input.type = 'text';
+      input.size = '30';
+      input.onkeypress = function(e)
+      {
+        // javascript sucks. IE and several others throw myriad errors unless it's done this way.
+        if ( e )
+        if ( e.keyCode )
+        if ( e.keyCode == 13 )
+        {
+          if ( aclSavePreset() )
+          {
+            miniPromptDestroy(this);
+          }
+        }
+        else if ( e.keyCode == 27 )
+        {
+          miniPromptDestroy(this);
+        }
+      }
+      var para = document.createElement('p');
+      para.appendChild(input);
+      
+      parent.appendChild(para);
+      
+      // buttons
+      var buttons = document.createElement('p');
+      
+      // save button
+      var btn_save = document.createElement('a');
+      btn_save.className = 'abutton abutton_green';
+      btn_save.style.fontWeight = 'bold';
+      btn_save.appendChild(document.createTextNode($lang.get('acl_btn_save_preset')));
+      btn_save.selectobj = select;
+      btn_save.onclick = function()
+      {
+        if ( aclSavePreset() )
+        {
+          miniPromptDestroy(this);
+        }
+        return false;
+      }
+      btn_save.href = '#';
+      buttons.appendChild(btn_save);
+      
+      buttons.appendChild(document.createTextNode(' '));
+      
+      // cancel button
+      var btn_cancel = document.createElement('a');
+      btn_cancel.className = 'abutton';
+      btn_cancel.appendChild(document.createTextNode($lang.get('etc_cancel')));
+      btn_cancel.onclick = function()
+      {
+        miniPromptDestroy(this);
+        return false;
+      }
+      btn_cancel.href = '#';
+      buttons.appendChild(btn_cancel);
+      
+      parent.appendChild(buttons);
+      
+      var timeout = ( aclDisableTransitionFX ) ? 10 : 1000;
+      setTimeout(function()
+        {
+          input.focus();
+        }, timeout);
+    });
+}
+
+function aclSavePreset()
+{
+  var input = document.getElementById(aclManagerID + '_preset_save');
+  if ( trim(input.value) == '' )
+  {
+    alert($lang.get('acl_err_preset_name_empty'));
+    return false;
+  }
+  var form = document.forms[aclManagerID + '_formobj'], selections = {};
+  var dbg = '';
+  var warned_everyone = false;
+  for(var i in aclPermList)
+  {
+    selections[aclPermList[i]] = getRadioState(form, aclPermList[i], ['i', 1, 2, 3, 4]);
+    // If we're editing permissions for everyone on the entire site and the
+    // admin selected to deny privileges, give a stern warning about it.
+    if ( selections[aclPermList[i]] == 1 && aclDataCache.target_type == 1 /* ACL_TYPE_GROUP */ && aclDataCache.target_id == 1 && !warned_everyone )
+    {
+      warned_everyone = true;
+      if ( !confirm($lang.get('acl_msg_deny_everyone_confirm')) )
+      {
+        return false;
+      }
+    }
+    dbg += aclPermList[i] + ': ' + selections[aclPermList[i]] + "\n";
+    if(!selections[aclPermList[i]])
+    {
+      alert("Invalid return from getRadioState: "+i+": "+selections[i]+" ("+typeof(selections[i])+")");
+      return false;
+    }
+  }
+  
+  var packet = toJSONString({
+      mode: 'save_preset',
+      preset_name: input.value,
+      perms: selections
+    });
+  
+  var whitey = whiteOutElement(document.getElementById(aclManagerID));
+  
+  ajaxPost(stdAjaxPrefix + '&_mode=acljson', 'acl_params=' + ajaxEscape(packet), function()
+    {
+      if ( ajax.readyState == 4 && ajax.status == 200 )
+      {
+        if ( !check_json_response(ajax.responseText) )
+        {
+          whitey.parentNode.removeChild(whitey);
+          return handle_invalid_json(ajax.responseText);
+        }
+        var response = parseJSON(ajax.responseText);
+        if ( response.mode == 'error' )
+        {
+          whitey.parentNode.removeChild(whitey);
+          alert(response.error);
+          return false;
+        }
+        whiteOutReportSuccess(whitey);
+      }
+    });
+  
+  return true;
+}
+
 function array_keys(obj)
 {
   keys = new Array();
--- a/includes/clientside/static/functions.js	Mon Aug 11 19:52:00 2008 -0400
+++ b/includes/clientside/static/functions.js	Mon Aug 11 19:52:41 2008 -0400
@@ -359,6 +359,7 @@
             })).start();
         }, 1000);
     }
+  return false;
 }
 
 /**
@@ -611,11 +612,18 @@
 {
   // fade the status indicator in and then out
   whitey.style.backgroundImage = 'url(' + scriptPath + '/images/check.png)';
-  domOpacity(whitey, 60, 80, 500);
-  setTimeout(function()
-    {
-      domOpacity(whitey, 60, 0, 500);
-    }, 750);
+  if ( aclDisableTransitionFX )
+  {
+    domObjChangeOpac(80, whitey);
+  }
+  else
+  {
+    domOpacity(whitey, 60, 80, 500);
+    setTimeout(function()
+      {
+        domOpacity(whitey, 60, 0, 500);
+      }, 750);
+  }
   setTimeout(function()
     {
       whitey.parentNode.removeChild(whitey);
--- a/includes/pageutils.php	Mon Aug 11 19:52:00 2008 -0400
+++ b/includes/pageutils.php	Mon Aug 11 19:52:41 2008 -0400
@@ -1965,6 +1965,55 @@
           }
           
           break;
+        case 'list_presets':
+          $presets = array();
+          $q = $db->sql_query('SELECT page_id AS preset_name, rule_id, rules FROM ' . table_prefix . "acl WHERE target_type = " . ACL_TYPE_PRESET . ";");
+          if ( !$q )
+            $db->die_json();
+          
+          while ( $row = $db->fetchrow() )
+          {
+            $row['rules'] = $session->string_to_perm($row['rules']);
+            $presets[] = $row;
+          }
+          
+          return array(
+            'mode' => 'list_existing',
+            'presets' => $presets
+          );
+          break;
+        case 'save_preset':
+          if ( empty($parms['preset_name']) )
+          {
+            return array(
+              'mode' => 'error',
+              'error' => $lang->get('acl_err_preset_name_empty')
+            );
+          }
+          $preset_name = $db->escape($parms['preset_name']);
+          $q = $db->sql_query('DELETE FROM ' . table_prefix . "acl WHERE target_type = " . ACL_TYPE_PRESET . " AND page_id = '$preset_name';");
+          if ( !$q )
+            $db->die_json();
+          
+          $perms = $session->perm_to_string($parms['perms']);
+          if ( !$perms )
+          {
+            return array(
+              'mode' => 'error',
+              'error' => $lang->get('acl_err_preset_is_blank')
+            );
+          }
+          
+          $perms = $db->escape($perms);
+          $q = $db->sql_query('INSERT INTO ' . table_prefix . "acl(page_id, target_type, rules) VALUES\n"
+                            . "  ( '$preset_name', " . ACL_TYPE_PRESET . ", '$perms' );");
+          if ( !$q )
+            $db->die_json();
+          
+          return array(
+              'mode' => 'success'
+            );
+          break;
         default:
           return Array('mode'=>'error','error'=>'Hacking attempt');
           break;
--- a/language/english/admin.json	Mon Aug 11 19:52:00 2008 -0400
+++ b/language/english/admin.json	Mon Aug 11 19:52:41 2008 -0400
@@ -94,6 +94,9 @@
       err_zero_list: 'Supplied rule list has a length of zero',
       err_pleaseselect_targettype: 'Please select a target type.',
       err_pleaseselect_username: 'Please enter a username.',
+      err_select_preset: 'Please select a preset to load.',
+      err_preset_name_empty: 'Please enter a name for this preset.',
+      err_preset_is_blank: 'The preset you entered seems completely empty (i.e. all permissions set to "inherit")',
       
       radio_usergroup: 'A usergroup',
       radio_user: 'A specific user',
@@ -112,6 +115,9 @@
       lbl_save_success_body: 'The permissions for %target_name% on this page have been updated successfully. If you changed permissions that affect your user account, you may not see changes until you reload the page.',
       lbl_delete_success_title: 'Rule deleted',
       lbl_delete_success_body: 'The access rules for %target_name% on this page have been deleted.',
+      lbl_preset_load_title: 'Load a preset',
+      lbl_preset_load: 'Select a preset...',
+      lbl_preset_save_title: 'Enter a name for this preset',
       lbl_field_inherit: 'Inherit',
       lbl_field_deny: 'Deny',
       lbl_field_disallow: 'Disallow',
@@ -160,6 +166,8 @@
       
       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>',
+      
       btn_success_dismiss: 'dismiss',
       btn_success_close: 'close manager',
       btn_deleterule: 'Delete rule',
@@ -168,6 +176,9 @@
       btn_returnto_userscope: 'Return to user/scope selection',
       btn_show_existing: '&raquo; View existing rules',
       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',
       
       inherit_enano_default: 'Enano defaults',
       inherit_global_everyone: 'Rule for everyone on the entire site',
@@ -210,7 +221,7 @@
       field_site_desc: 'Site description:',
       field_main_page: 'Main page:',
       field_copyright: 'Copyright notice shown on pages:',
-      field_copyright_hint: 'Hint: If you\'re using Windows, you can make a "&copy;" symbol by holding ALT and pressing 0169 on the numeric keypad.',
+      field_copyright_hint: 'Hint: To make a copyright symbol (&copy;), type <tt>&amp;copy;</tt>.',
       field_contactemail: 'Contact e-mail',
       field_contactemail_hint: 'All e-mail sent from this site will appear to have come from the address shown here.',
       
@@ -564,7 +575,7 @@
       btn_clear_all: 'Clear all caches',
       hint_clear_all: 'To force all caches (except image thumbnails) on the site to empty, click this button. Certain caches, such as language data, must be regenerated in order to fully refresh the cache. It is recommended that you use "%this.acpcm_btn_refresh_all%" below to clear all caches and then regenerate them.',
       btn_refresh_all: 'Refresh all caches',
-      hint_refresh_all: 'This will clear all caches (except image thumbnails) on the site to empty and then regenerate, except templates, which are cached on demand.',
+      hint_refresh_all: 'This will clear all caches (except image thumbnails) on the site to empty and then regenerate, except certain components that are cached on demand.',
       
       th_individual_caches: 'Individual caches',
       btn_clear: 'Clear',