From 3e2f1b46bb33c1720b4373f324f6126ca26d2ac7 Mon Sep 17 00:00:00 2001 From: Janusz Dobrowolski Date: Wed, 19 Aug 2009 22:37:40 +0000 Subject: [PATCH] Partial changes for new access control system. --- admin/db/security_db.inc | 65 ++++++++++++ admin/security_roles.php | 203 +++++++++++++++++++++++++++++++++++ includes/access_levels.inc | 209 ++++++++++++++++++++----------------- includes/ui/ui_lists.inc | 38 +++++++ sql/alter2.2.sql | 11 ++ sql/en_US-demo.sql | 20 ++++ 6 files changed, 453 insertions(+), 93 deletions(-) create mode 100644 admin/db/security_db.inc create mode 100644 admin/security_roles.php diff --git a/admin/db/security_db.inc b/admin/db/security_db.inc new file mode 100644 index 00000000..55e56b55 --- /dev/null +++ b/admin/db/security_db.inc @@ -0,0 +1,65 @@ +. +***********************************************************************/ +//-------------------------------------------------------------------------------------------------- + +function get_security_role($id) +{ + $sql = "SELECT * FROM ".TB_PREF."security_roles WHERE id='$id'"; + $ret = db_query($sql, "could not retrieve security roles"); + $row = db_fetch($ret); + $row['areas'] = explode(';', $row['areas']); + $row['modules'] = explode(';', $row['modules']); + return $row; +} + +//-------------------------------------------------------------------------------------------------- + +function add_security_role($name, $description, $modules, $areas) +{ + $sql = "INSERT INTO ".TB_PREF."security_roles (role, description, modules, areas) + VALUES (" + .db_escape($name)."," + .db_escape($description)."," + .db_escape(implode(';',$modules))."," + .db_escape(implode(';',$areas)).")"; + + db_query($sql, "could not add new security role"); +} + +//-------------------------------------------------------------------------------------------------- + +function update_security_role($id, $name, $description, $modules, $areas) +{ + $sql = "UPDATE ".TB_PREF."security_roles SET role=".db_escape($name) + .",description=".db_escape($description) + .",modules=".db_escape(implode(';',$modules)) + .",areas=".db_escape(implode(';',$areas)) + ." WHERE id=$id"; + db_query($sql, "could not update role"); +} +//-------------------------------------------------------------------------------------------------- + +function delete_security_role($id) +{ + $sql = "DELETE FROM ".TB_PREF."security_roles WHERE id=$id"; + + db_query($sql, "could not delete role"); +} +//-------------------------------------------------------------------------------------------------- + +function check_role_used($id) { + $sql = "SELECT count(*) FROM ".TB_PREF."users WHERE full_access=$id"; + $ret = db_query($sql, 'cannot check role usage'); + $row = db_fetch($ret); + return $row[0]; +} +?> \ No newline at end of file diff --git a/admin/security_roles.php b/admin/security_roles.php new file mode 100644 index 00000000..e0aaab9a --- /dev/null +++ b/admin/security_roles.php @@ -0,0 +1,203 @@ +. +***********************************************************************/ +$page_security = 20; +$path_to_root=".."; +include_once($path_to_root . "/includes/session.inc"); + +page(_("Access setup")); + +include_once($path_to_root . "/includes/ui.inc"); +include_once($path_to_root . "/includes/access_levels.inc"); +include_once($path_to_root . "/admin/db/security_db.inc"); + +$new_role = get_post('role')=='' || get_post('cancel') || get_post('clone'); +//-------------------------------------------------------------------------------------------------- +if (list_updated('role')) { + $Ajax->activate('details'); + $Ajax->activate('controls'); +} + +function clear_data() +{ + unset($_POST); +} + +if (get_post('addupdate')) +{ + $input_error = 0; + if ($_POST['description'] == '') + { + $input_error = 1; + display_error( _("Role description cannot be empty.")); + set_focus('description'); + } + elseif ($_POST['name'] == '') + { + $input_error = 1; + display_error( _("Role name cannot be empty.")); + set_focus('name'); + } + + if ($input_error == 0) + { + $modules = array(); + $areas = array(); + foreach($_POST as $p =>$val) { + if (substr($p,0,4) == 'Area') + $areas[] = substr($p, 4); + if (substr($p,0,6) == 'Module') + $modules[] = substr($p, 6); + } + sort($areas); + sort($modules); + if ($new_role) + { + add_security_role($_POST['name'], $_POST['description'], $modules, $areas); + display_notification(_("New security role has been added.")); + } else + { + update_security_role($_POST['role'], $_POST['name'], $_POST['description'], + $modules, $areas); + update_record_status($_POST['role'], get_post('inactive'), + 'security_roles', 'id'); + + display_notification(_("Security role has been updated.")); + } + $new_role = true; + clear_data(); + $Ajax->activate('_page_body'); + } +} + +//-------------------------------------------------------------------------------------------------- + +if (get_post('delete')) +{ + if (check_role_used(get_post('role'))) { + display_error(_("This role is currently assigned to some users and cannot be deleted")); + } else { + delete_security_role(get_post('role')); + display_notification(_("Security role has been sucessfully deleted.")); + unset($_POST['role']); + } + $Ajax->activate('_page_body'); +} + +if (get_post('cancel')) +{ + unset($_POST['role']); + $Ajax->activate('_page_body'); +} + +if (!isset($_POST['role']) || get_post('clone') || list_updated('role')) { + $id = get_post('role'); + $clone = get_post('clone'); + clear_data(); + if ($id) { + $row = get_security_role($id); + $_POST['description'] = $row['description']; + $_POST['name'] = $row['role']; +// if ($row['inactive'] +// $_POST['inactive'] = 1; + + $_POST['inactive'] = $row['inactive']; + $access = $row['areas']; + $modules = $row['modules']; + } + else { + $_POST['description'] = $_POST['name'] = ''; + unset($_POST['inactive']); + $access = $modules = array(); + } + foreach($access as $a) $_POST['Area'.$a] = 1; + foreach($modules as $m) $_POST['Module'.$m] = 1; + + if($clone) { + set_focus('name'); + $Ajax->activate('_page_body'); + } else + $_POST['role'] = $id; +} + +//-------------------------------------------------------------------------------------------------- + +start_form(); + +start_table("class='tablestyle_noborder'"); +start_row(); +security_roles_list_cells(_("Role:"). " ", 'role', null, true, true, check_value('show_inactive')); +//$new_role = get_post('role')==''; +check_cells(_("Show inactive:"), 'show_inactive', null, true); +end_row(); +end_table(); +echo "
"; + +if (get_post('_show_inactive_update')) { + $Ajax->activate('role'); + set_focus('role'); +} +if (find_submit('_Module')) { + $Ajax->activate('details'); +// set_focus(''); +} +//----------------------------------------------------------------------------------------------- +div_start('details'); +start_table($table_style2); + text_row(_("Role name:"), 'name', null, 20, 22); + text_row(_("Role description:"), 'description', null, 50, 52); + record_status_list_row(_("Current status:"), 'inactive'); +end_table(1); + + start_table("$table_style width=50%"); + + $k = $j = 0; //row colour counter + $m = 0; + foreach($security_areas as $area =>$descr ) { + if (($area&~0xff) != $m) + { // features set selection + $m = $area & ~0xff; + label_row(sprintf(_("%s features:"), $security_modules[$m]), + checkbox( null, 'Module'.$m, null, true, + _("Set access to security features area")), + "class='tableheader2'", "class='tableheader'"); + } + if (check_value('Module'.$m)) { + alt_table_row_color($k); + check_cells($descr, 'Area'.$area, null, + false, '', "align='center'"); + end_row(); + } else { + hidden('Area'.$area); + } + } + end_table(1); +div_end(); + +div_start('controls'); +if ($new_role) +{ + submit_center('addupdate', _("Insert New Role"), true, '', 'default'); +} +else +{ + submit_center_first('addupdate', _("Update Role"), '', 'default'); + submit('clone', _("Clone This Role"), true, '', true); + submit('delete', _("Delete This Role"), true, '', true); + submit_center_last('cancel', _("Cancel"), _("Cancel Edition"), 'cancel'); +} + +div_end(); + +end_form(); +end_page(); + +?> diff --git a/includes/access_levels.inc b/includes/access_levels.inc index 5e807ecd..5067b6ec 100644 --- a/includes/access_levels.inc +++ b/includes/access_levels.inc @@ -10,6 +10,29 @@ See the License here . ***********************************************************************/ // +/* + This table is introduced only for additional grouping of sales areas, + and should be consistent with convention used above. +*/ + +define('SM_SALES', 1<<8); +define('SM_PURCH', 2<<8); +define('SM_ITEMS', 3<<8); +define('SM_MANUF', 4<<8); +define('SM_DIM', 5<<8); +define('SM_GL', 6<<8); +define('SM_SETUP', 7<<8); + +$security_modules = array( + SM_SALES => _("Sales"), + SM_PURCH => _("Purchases"), + SM_ITEMS => _("Items and Inventory"), + SM_MANUF => _("Manufacturing"), + SM_DIM => _("Dimensions"), + SM_GL => _("Banking & General Ledger"), + SM_SETUP => _("Setup") +); + // Access areas used in FrontAccounting. // Constants defined below should be used wherever access rights for current // user are checked. Set of allowed access areas is retrieved during login from @@ -19,135 +42,135 @@ //---------------------------------------------------------------------------------- // Sales module // -define('SA_CUSTOMER', 101); -define('SA_SALESGROUP', 102); -define('SA_PRICE', 103); -define('SA_SALESMAN', 104); -define('SA_SALESAREA', 105); -define('SA_STATUS', 106); -define('SA_STEMPLATE', 107); -define('SA_SRECCURENT', 108); +define('SA_CUSTOMER', SM_SALES|1); +define('SA_SALESGROUP', SM_SALES|2); +define('SA_PRICE', SM_SALES|3); +define('SA_SALESMAN', SM_SALES|4); +define('SA_SALESAREA', SM_SALES|5); +define('SA_STATUS', SM_SALES|6); +define('SA_STEMPLATE', SM_SALES|7); +define('SA_SRECURRENT', SM_SALES|8); -define('SA_SALESORDER', 111); -define('SA_SALESDELIVERY', 112); -define('SA_SALESINVOICE', 113); -define('SA_SALESCREDITINV', 114); -define('SA_SALESCREDIT', 115); -define('SA_SALESPAYMNT', 116); +define('SA_SALESORDER', SM_SALES|11); +define('SA_SALESDELIVERY', SM_SALES|12); +define('SA_SALESINVOICE', SM_SALES|13); +define('SA_SALESCREDITINV', SM_SALES|14); +define('SA_SALESCREDIT', SM_SALES|15); +define('SA_SALESPAYMNT', SM_SALES|16); -define('SA_SALESALLOC', 121); -define('SA_SALESANALYTIC', 122); -define('SA_SALESMANREP', 123); -define('SA_SALESVARREP', 124); +define('SA_SALESALLOC', SM_SALES|21); +define('SA_SALESANALYTIC', SM_SALES|22); +define('SA_SALESMANREP', SM_SALES|23); +define('SA_SALESVARREP', SM_SALES|24); // // Purchasing module // -define('SA_SUPPLIER', 201); +define('SA_SUPPLIER', SM_PURCH|1); -define('SA_PURCHASEORDER', 211); -define('SA_GRN', 212); -define('SA_SUPPLIERINVOICE', 213); -define('SA_SUPPLIERCREDIT', 214); -define('SA_SUPPLIERPAYMNT', 215); +define('SA_PURCHASEORDER', SM_PURCH|11); +define('SA_GRN', SM_PURCH|12); +define('SA_SUPPLIERINVOICE', SM_PURCH|13); +define('SA_SUPPLIERCREDIT', SM_PURCH|14); +define('SA_SUPPLIERPAYMNT', SM_PURCH|15); -define('SA_SUPPLIERALLOC', 221); -define('SA_SUPPLIERANALYTIC', 222); -define('SA_SUPPLIERMANREP', 223); -define('SA_SUPPLIERVARREP', 224); +define('SA_SUPPLIERALLOC', SM_PURCH|21); +define('SA_SUPPLIERANALYTIC', SM_PURCH|22); +define('SA_SUPPLIERMANREP', SM_PURCH|23); +define('SA_SUPPLIERVARREP', SM_PURCH|24); // // Inventory module // -define('SA_ITEM', 301); -define('SA_FORITEMCODE', 302); -define('SA_SALESKIT', 303); -define('SA_ITEMCATEGORY', 304); -define('SA_INVENTORYLOCATION', 305); -define('SA_INVENTORYMOVETYPE', 306); -define('SA_ITEMTAXTYPE', 307); -define('SA_UOM', 308); -define('SA_REORDER', 309); +define('SA_ITEM', SM_ITEMS|1); +define('SA_FORITEMCODE', SM_ITEMS|2); +define('SA_SALESKIT', SM_ITEMS|3); +define('SA_ITEMCATEGORY', SM_ITEMS|4); +define('SA_INVENTORYLOCATION', SM_ITEMS|5); +define('SA_INVENTORYMOVETYPE', SM_ITEMS|6); +define('SA_ITEMTAXTYPE', SM_ITEMS|7); +define('SA_UOM', SM_ITEMS|8); +define('SA_REORDER', SM_ITEMS|9); -define('SA_LOCATIONTRANSFER', 311); -define('SA_INVENTORYADJUSTMENT', 312); +define('SA_LOCATIONTRANSFER', SM_ITEMS|11); +define('SA_INVENTORYADJUSTMENT', SM_ITEMS|12); -define('SA_ITEMSANALYTIC', 321); -define('SA_ITEMSMANREP', 322); -define('SA_ITEMSVARREP', 323); +define('SA_ITEMSANALYTIC', SM_ITEMS|21); +define('SA_ITEMSMANREP', SM_ITEMS|22); +define('SA_ITEMSVARREP', SM_ITEMS|23); -define('SA_SALESPRICING', 331); -define('SA_PURCHASEPRICING', 332); -define('SA_STANDARDCOST', 333); +define('SA_SALESPRICING', SM_ITEMS|31); +define('SA_PURCHASEPRICING', SM_ITEMS|32); +define('SA_STANDARDCOST', SM_ITEMS|33); // // Manufacturing module // -define('SA_BOM', 401); -define('SA_WORKCENTRE', 402); +define('SA_BOM', SM_MANUF|1); +define('SA_WORKCENTRE', SM_MANUF|2); -define('SA_WORKORDERENTRY', 411); -define('SA_WORKORDEROPERATION', 412); +define('SA_WORKORDERENTRY', SM_MANUF|11); +define('SA_WORKORDEROPERATION', SM_MANUF|12); -define('SA_WORKORDERANALYTIC', 421); -define('SA_WORKORDERMANREP', 422); -define('SA_WORKORDERVARREP', 423); +define('SA_WORKORDERANALYTIC', SM_MANUF|21); +define('SA_WORKORDERMANREP', SM_MANUF|22); +define('SA_WORKORDERVARREP', SM_MANUF|23); // // Dimension module // -define('SA_DIMENSION', 501); +define('SA_DIMENSION', SM_DIM|1); -define('SA_DIMENTIONOPERATION', 511); +define('SA_DIMENSIONOPERATION', SM_DIM|11); -define('SA_DIMENSIONANALYTIC', 521); -define('SA_DIMENSIONMANREP', 522); -define('SA_DIMENSIONVARREP', 523); +define('SA_DIMENSIONANALYTIC', SM_DIM|21); +define('SA_DIMENSIONMANREP', SM_DIM|22); +define('SA_DIMENSIONVARREP', SM_DIM|23); // // Banking and General Ledger module // -define('SA_BANKACCOUNT', 601); -define('SA_QUICKENTRY', 602); -define('SA_CURRENCY', 603); -define('SA_EXCHANGERATE', 604); -define('SA_GLACCOUNT', 605); -define('SA_GLACCOUNTGROUP', 606); -define('SA_GLACCOUNTCLASS', 607); +define('SA_BANKACCOUNT', SM_GL|1); +define('SA_QUICKENTRY', SM_GL|2); +define('SA_CURRENCY', SM_GL|3); +define('SA_EXCHANGERATE', SM_GL|4); +define('SA_GLACCOUNT', SM_GL|5); +define('SA_GLACCOUNTGROUP', SM_GL|6); +define('SA_GLACCOUNTCLASS', SM_GL|7); -define('SA_PAYMENT', 611); -define('SA_DEPOSIT', 612); -define('SA_BANKACCOUNTTRANSFER', 613); -define('SA_JOURNALENTRY', 614); -define('SA_BUDGETENTRY', 615); -define('SA_RECONCILE', 616); +define('SA_PAYMENT', SM_GL|11); +define('SA_DEPOSIT', SM_GL|12); +define('SA_BANKACCOUNTTRANSFER', SM_GL|13); +define('SA_JOURNALENTRY', SM_GL|14); +define('SA_BUDGETENTRY', SM_GL|15); +define('SA_RECONCILE', SM_GL|16); -define('SA_GLANALYTIC', 621); -define('SA_GLMANREP', 622); -define('SA_GLVARREP', 623); +define('SA_GLANALYTIC', SM_GL|21); +define('SA_GLMANREP', SM_GL|22); +define('SA_GLVARREP', SM_GL|23); // // Setup module // -define('SA_SETUPCOMPANY', 701); -define('SA_SETUPUSER', 702); -define('SA_SETUPFORM', 703); -define('SA_SETUPTAX', 704); -define('SA_SETUPFISCALYEAR', 705); -define('SA_PRINTPROFILE', 706); -define('SA_PAYMENTTERM', 707); -define('SA_SHIPPING', 708); -define('SA_SETUPPOS', 709); -define('SA_SETUPPRINTER', 710); +define('SA_SETUPCOMPANY', SM_SETUP|1); +define('SA_SETUPUSER', SM_SETUP|2); +define('SA_SETUPFORM', SM_SETUP|3); +define('SA_SETUPTAX', SM_SETUP|4); +define('SA_SETUPFISCALYEAR', SM_SETUP|5); +define('SA_PRINTPROFILE', SM_SETUP|6); +define('SA_PAYMENTTERM', SM_SETUP|7); +define('SA_SHIPPING', SM_SETUP|8); +define('SA_SETUPPOS', SM_SETUP|9); +define('SA_SETUPPRINTER', SM_SETUP|10); -define('SA_VOIDTRANSACTION', 711); -define('SA_VIEWPRINTTRANSACTION', 712); -define('SA_ATTACHDOCUMENT', 713); -define('SA_BACKUP', 714); -define('SA_CREATECOMPANY', 715); -define('SA_CREATELANGUAGE', 716); -define('SA_CREATEMODULES', 717); -define('SA_SORTWAREUPGRADE', 718); +define('SA_VOIDTRANSACTION', SM_SETUP|11); +define('SA_VIEWPRINTTRANSACTION', SM_SETUP|12); +define('SA_ATTACHDOCUMENT', SM_SETUP|13); +define('SA_BACKUP', SM_SETUP|14); +define('SA_CREATECOMPANY', SM_SETUP|15); +define('SA_CREATELANGUAGE', SM_SETUP|16); +define('SA_CREATEMODULES', SM_SETUP|17); +define('SA_SOFTWAREUPGRADE', SM_SETUP|18); /* This table stores security area ranges. It is used by security_role @@ -222,7 +245,7 @@ $security_areas = array( // database table crud operations and administrative areas SA_DIMENSION => _("Dimensions"), // documents, transactions entry - SA_DIMENSiONOPERATION => _("Dimension Operations"), + SA_DIMENSIONOPERATION => _("Dimension Operations"), // maintenance and analytics SA_DIMENSIONANALYTIC => _("Dimension analytical reports and inquiries"), _("Dimension Reports"), @@ -265,6 +288,6 @@ $security_areas = array( _("Install/Update Companies"), _("Install/Update Languages"), _("Install/Upgrade Modules"), - _("Software Upgrades"), + _("Software Upgrades") ); ?> \ No newline at end of file diff --git a/includes/ui/ui_lists.inc b/includes/ui/ui_lists.inc index e409ce63..320e13cf 100644 --- a/includes/ui/ui_lists.inc +++ b/includes/ui/ui_lists.inc @@ -2096,5 +2096,43 @@ function class_types_list_row($label, $name, $selected_id=null, $submit_on_chang echo "\n"; } +//------------------------------------------------------------------------------------------------ + +function security_roles_list($name, $selected_id=null, $new_item=false, $submit_on_change=false, + $show_inactive = false) +{ + global $all_items; + + $sql = "SELECT id, role, inactive FROM ".TB_PREF."security_roles"; + +return combo_input($name, $selected_id, $sql, 'id', 'description', + array( + 'spec_option'=>$new_item ? _("New role") : false, + 'spec_id' => '', + 'select_submit'=> $submit_on_change, + 'show_inactive' => $show_inactive + ) ); +} + +function security_roles_list_cells($label, $name, $selected_id=null, $new_item=false, $submit_on_change=false, + $show_inactive = false) +{ + if ($label != null) + echo "$label\n"; + echo ""; + $str = security_roles_list($name, $selected_id, $new_item, $submit_on_change, $show_inactive); + echo "\n"; + return $str; +} + +function security_roles_list_row($label, $name, $selected_id=null, $new_item=false, $submit_on_change=false, + $show_inactive = false) +{ + echo ""; + $str = security_roles_list_cells($label, $name, $selected_id, $new_item, $submit_on_change, $show_inactive); + echo "\n"; + return $str; +} + ?> \ No newline at end of file diff --git a/sql/alter2.2.sql b/sql/alter2.2.sql index 3ea59ce2..f8848998 100644 --- a/sql/alter2.2.sql +++ b/sql/alter2.2.sql @@ -81,3 +81,14 @@ ALTER TABLE `0_suppliers` ADD COLUMN `supp_ref` varchar(30) NOT NULL; UPDATE `0_suppliers` SET `supp_ref`=`supp_name` WHERE 1; ALTER TABLE `0_cust_branch` ADD COLUMN `branch_ref` varchar(30) NOT NULL; UPDATE `0_cust_branch` SET `branch_ref`=`br_name` WHERE 1; + +CREATE TABLE `0_security_roles` ( + `id` int(11) NOT NULL auto_increment, + `role` varchar(20) NOT NULL, + `description` varchar(50) default NULL, + `modules` text, + `areas` text, + `inactive` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`id`), + UNIQUE KEY `role` (`role`) +) TYPE=MyISAM AUTO_INCREMENT=8 AUTO_INCREMENT=8 ; diff --git a/sql/en_US-demo.sql b/sql/en_US-demo.sql index 88dba3ab..2f159948 100644 --- a/sql/en_US-demo.sql +++ b/sql/en_US-demo.sql @@ -2026,3 +2026,23 @@ INSERT INTO `0_workorders` VALUES ('4', '4', 'DEF', '4', '3400', '2009-06-21', ' INSERT INTO `0_workorders` VALUES ('5', '5', 'DEF', '5', '3400', '2009-06-21', '0', '2009-06-21', '2009-06-21', '5', '1', '1', '10'); INSERT INTO `0_workorders` VALUES ('6', '6', 'DEF', '-5', '3400', '2009-06-21', '1', '2009-06-21', '2009-06-21', '-5', '1', '1', '0'); INSERT INTO `0_workorders` VALUES ('7', '7', 'DEF', '-2', '3400', '2009-06-21', '1', '2009-06-21', '2009-06-21', '-2', '1', '1', '10'); + +DROP TABLE IF EXISTS `0_security_roles`; + +CREATE TABLE `0_security_roles` ( + `id` int(11) NOT NULL auto_increment, + `role` varchar(20) NOT NULL, + `description` varchar(50) default NULL, + `modules` text, + `areas` text, + `inactive` tinyint(1) NOT NULL default '0', + PRIMARY KEY (`id`), + UNIQUE KEY `role` (`role`) +) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ; + + +### Data of table `0_security_roles` ### + +INSERT INTO `0_security_roles` VALUES ('2', 'System Admin', 'Full system access', '256;512;768;1024;1280;1536;1792', '257;258;259;260;261;262;263;264;267;268;269;270;271;272;277;278;279;280;513;523;524;525;526;527;533;534;535;536;769;770;771;772;773;774;775;776;777;779;780;789;790;791;799;800;801;1025;1026;1035;1036;1045;1046;1047;1281;1291;1301;1302;1303;1537;1538;1539;1540;1541;1542;1543;1547;1548;1549;1550;1551;1552;1557;1558;1559;1793;1794;1795;1796;1797;1798;1799;1800;1801;1802;1803;1804;1805;1806;1807;1808;1809;1810', '0'); +INSERT INTO `0_security_roles` VALUES ('7', 'Accountant', 'Accounting features and most non-admin options', '256;512;768;1024;1280;1536;1792', '257;258;263;264;267;268;269;270;271;272;277;278;279;280;513;523;524;525;526;527;533;534;535;536;769;770;771;772;773;774;775;776;777;779;780;789;790;791;799;800;801;1026;1045;1046;1047;1291;1301;1302;1538;1547;1548;1549;1550;1552;1557;1558;1559;1796;1804;1805', '0'); +INSERT INTO `0_security_roles` VALUES ('6', 'Sub Admin', 'Near full system access', '256;512;768;1024;1280;1536;1792', '257;258;263;264;267;268;269;270;271;272;277;278;279;280;513;523;524;525;526;527;533;534;535;536;769;770;771;772;773;774;775;776;777;779;780;789;790;791;799;800;801;1026;1045;1046;1047;1291;1301;1302;1538;1547;1548;1549;1550;1552;1557;1558;1559;1796;1804;1805', '0'); -- 2.30.2