Commit 3417eb92 authored by John Punzalan's avatar John Punzalan

Add User Role Editor Plugin

parent 3486fc4f
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
*/
.ms-parent {
display: inline-block;
position: relative;
vertical-align: middle;
}
.ms-choice {
display: block;
height: 26px;
padding: 0;
overflow: hidden;
position: relative;
cursor: pointer;
border: 1px solid #aaa;
white-space: nowrap;
line-height: 26px;
color: #444;
text-decoration: none;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
background-color: #fff;
}
.ms-choice.disabled {
background-color: #f4f4f4;
background-image: none;
border: 1px solid #ddd;
cursor: default;
}
.ms-choice > span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
float: left;
padding-left: 8px;
}
.ms-choice > span.placeholder {
color: #999;
}
.ms-choice > div {
float: right;
width: 20px;
height: 25px;
background: url('multiple-select.png') right top no-repeat;
}
.ms-choice > div.open {
background: url('multiple-select.png') left top no-repeat;
}
.ms-drop {
overflow: hidden;
display: none;
margin-top: -1px;
padding: 0;
position: absolute;
z-index: 1000;
top: 100%;
background: #fff;
color: #000;
border: 1px solid #aaa;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
-moz-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
}
.ms-search {
display: inline-block;
margin: 0;
min-height: 26px;
padding: 4px;
position: relative;
white-space: nowrap;
width: 100%;
z-index: 10000;
}
.ms-search input {
width: 100%;
height: auto !important;
min-height: 24px;
padding: 0 20px 0 5px;
margin: 0;
outline: 0;
font-family: sans-serif;
font-size: 1em;
border: 1px solid #aaa;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
background: #fff url('multiple-select.png') no-repeat 100% -22px;
background: url('multiple-select.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee));
background: url('multiple-select.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%);
background: url('multiple-select.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%);
background: url('multiple-select.png') no-repeat 100% -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%);
background: url('multiple-select.png') no-repeat 100% -22px, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%);
background: url('multiple-select.png') no-repeat 100% -22px, linear-gradient(top, #ffffff 85%, #eeeeee 99%);
}
.ms-search, .ms-search input {
-webkit-box-sizing: border-box;
-khtml-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.ms-drop ul {
overflow: auto;
margin: 0;
padding: 5px 8px;
}
.ms-drop ul > li {
list-style: none;
display: list-item;
background-image: none;
position: static;
}
.ms-drop ul > li .disabled {
opacity: .35;
filter: Alpha(Opacity=35);
}
.ms-drop ul > li.multiple {
display: block;
float: left;
}
.ms-drop ul > li.group {
clear: both;
}
.ms-drop ul > li.multiple label {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ms-drop ul > li label.optgroup {
font-weight: bold;
}
.ms-drop input[type="checkbox"] {
vertical-align: middle;
}
/*
Document : ure_admin
Created on : 10.03.2010
Author : Vladimir Garagulya
Description:
User Role Editor plugin Admin Settings Page CSS
*/
/*
Syntax recommendation http://www.w3.org/TR/REC-CSS2/
*/
.txt_left {
text-align: left;
}
.txt_center {
text-align: center;
}
.txt_right {
text-align: right;
}
.nowrap {
white-space: nowrap;
}
img.input_radio {
vertical-align: middle;
}
a.ure_rsb_link {
padding:4px;
display:block;
padding-left:25px;
background-repeat:no-repeat;
background-position:5px 50%;
text-decoration:none;
border:none;
}
a.ure_rsb_link:hover {
border-bottom-width:1px;
}
input.warning:hover, a.warning:hover {
color: red;
}
#ure_container {
display: table;
width: 100%;
}
.ure-table {
display: table;
}
.ure-table-cell {
display: table-cell;
margin: 0;
padding: 0;
vertical-align: top;
}
#ure-sidebar {
width: 270px;
padding-left: 20px;
}
.hidden {
display: none;
}
#user_role_editor {
}
#ure_form_controls {
}
#ure_role_selector {
padding: 10px 0 0 10px;
}
#ure_user_caps_header {
padding: 10px 0 0 10px;
font-size: 16px;
}
#ure_user_caps_title {
font-weight: bold;
}
#ure_role_select_label {
font-size: 16px;
font-weight: bold;
}
.ure-caps-option {
padding-left: 20px;
}
#ure_caps_container {
width: 100%;
}
#ure_toolbar {
margin-top: 10px;
border: 1px solid #dfdfdf;
-webkit-box-shadow: inset 0 1px 0 #fff;
box-shadow: inset 0 1px 0 #fff;
-webkit-border-radius: 3px;
border-radius: 3px;
background: #f5f5f5;
padding: 5px;
}
.ure_toolbar_button {
width: 100%;
margin-bottom: 3px;
}
#ure_update {
width: 100%;
margin-top: 10px;
margin-bottom: 10px;
}
#ure_service_tools {
margin-top: 10px;
}
.ure-modal-dialog {
display: none;
padding: 10px;
}
.ure-label {
clear: left;
float: left;
display: block;
width: 150px;
}
.ure-input {
float: left;
display: inline;
width: 200px;
margin-bottom: 5px;
}
#ure_user_roles {
vertical-align: text-top;
padding-right: 10px;
padding-top: 5px;
font-size: 1.1em;
border-top: 1px solid #cccccc;
border-right: 1px solid #cccccc;
min-width: 200px;
width: 20%;
}
.ure-user-role-section-title {
margin-top: 5px;
margin-bottom: 5px;
font-weight: bold;
}
/* Multipe select */
.countLabel {
color:Gray;
font-style:italic;
}
.storageBox {
display:none;
}
.copiedOption {
background-color:Yellow;
}
.ure-caps-cell {
vertical-align:top;
padding-top: 5px;
}
.ure-cap-div {
white-space: nowrap;
}
#other_default_roles {
display: block;
margin: 10px;
}
.ure-dialog {
display: none;
}
#ure_admin_menu_access_table tr:hover {
background-color: #2ea2cc;
color: #ffffff;
}
#ure_caps_groups_td {
padding:0 10px 0 10px;
min-width:25%;
border-right: 1px solid #cccccc;
}
#ure_caps_td {
width:60%;
padding-left: 10px;
}
#ure_toolbar_td {
width: 15%;
min-width:200px;
padding-left: 10px;
}
#ure_editor_options {
margin-bottom: 10px;
}
#ure_caps_groups_title {
min-width: 250px;
vertical-align:middle;
border-bottom: 1px solid #cccccc;
border-right: 1px solid #cccccc;
}
#ure_caps_select {
vertical-align:middle;
border-bottom: 1px solid #cccccc;
padding: 5px 5px 5px 10px;
}
#ure_toolbar_title {
border-bottom: 1px solid #cccccc;
}
#ure_caps_groups_list .ui-selecting {
background: #DDDDDD;
}
#ure_caps_groups_list .ui-selected {
background: #CCCCCC;
color: #444444;
}
#ure_caps_groups_list li {
min-height: 20px;
line-height: 20px;
cursor: pointer;
}
.plugins {
color: #444444;
}
#ure_caps_list_container {
float: left;
width: 100%;
overflow: auto;
min-height: 600px;
max-height: 720px;
}
#ure_caps_list {
-moz-column-count: 1;
-webkit-column-count: 1;
column-count: 1;
column-width: auto;
display: inline-block;
min-width: 100%;
}
\ No newline at end of file
<?php
// Silence is golden.
?>
\ No newline at end of file
<?php
/*
* User Role Editor plugin: advertisement showing class
* Author: Vladimir Garagulya
* email: vladimir@shinephp.com
* site: http://shinephp.com
*
*/
class URE_Advertisement {
private $slots = array(0=>'');
function __construct() {
$used = array(-1);
//$index = $this->rand_unique( $used );
$index = 0;
$this->slots[$index] = $this->admin_menu_editor();
$used[] = $index;
}
// end of __construct
/**
* Returns random number not included into input array
*
* @param array $used - array of numbers used already
*
* @return int
*/
private function rand_unique( $used = array(-1) ) {
$index = rand(0, 2);
while (in_array($index, $used)) {
$index = rand(0, 2);
}
return $index;
}
// return rand_unique()
// content of Admin Menu Editor advertisement slot
private function admin_menu_editor() {
$output = '
<div style="text-align: center;">
<a href="http://w-shadow.com/admin-menu-editor-pro/?utm_source=UserRoleEditor&utm_medium=banner&utm_campaign=Plugins " target="_new" >
<img src="'. URE_PLUGIN_URL . 'images/admin-menu-editor-pro.jpg' .'" alt="Admin Menu Editor Pro" title="Move, rename, hide, add admin menu items, restrict access"/>
</a>
</div>
';
return $output;
}
// end of admin_menu_editor()
/**
* Output all existed ads slots
*/
public function display() {
?>
<div id="ure-sidebar" class="ure_table_cell" >
<?php
foreach ($this->slots as $slot) {
echo $slot . "\n";
}
?>
</div>
<?php
}
// end of display()
}
// end of ure_Advertisement
\ No newline at end of file
<?php
/*
* User Role Editor WordPress plugin
* Author: Vladimir Garagulya
* Email: support@role-editor.com
* License: GPLv2 or later
*/
/**
* Process AJAX requrest from User Role Editor
*
* @author vladimir
*/
class URE_Ajax_Processor {
protected $lib = null;
protected $action = null;
public function __construct($lib) {
$this->lib = $lib;
}
// end of __construct()
protected function get_action() {
$action = filter_input(INPUT_POST, 'sub_action', FILTER_SANITIZE_STRING);
if (empty($action)) {
$action = filter_input(INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING);
}
$this->action = $action;
return $action;
}
protected function ajax_check_permissions() {
if (!wp_verify_nonce($_REQUEST['wp_nonce'], 'user-role-editor')) {
echo json_encode(array('result'=>'error', 'message'=>'URE: Wrong or expired request'));
die;
}
$key_capability = URE_Own_Capabilities::get_key_capability();
if (!current_user_can($key_capability)) {
echo json_encode(array('result'=>'error', 'message'=>'URE: Insufficient permissions'));
die;
}
}
// end of ajax_check_permissions()
protected function get_caps_to_remove() {
$html = URE_Role_View::caps_to_remove_html();
$answer = array('result'=>'success', 'html'=>$html, 'message'=>'success');
return $answer;
}
// end of get_caps_to_remove()
protected function get_users_without_role() {
global $wp_roles;
$new_role = filter_input(INPUT_POST, 'new_role', FILTER_SANITIZE_STRING);
if (empty($new_role)) {
$answer = array('result'=>'failure', 'message'=>'Provide new role');
return $answer;
}
$assign_role = $this->lib->get_assign_role();
if ($new_role==='no_rights') {
$assign_role->create_no_rights_role();
}
if (!isset($wp_roles)) {
$wp_roles = new WP_Roles();
}
if (!isset($wp_roles->roles[$new_role])) {
$answer = array('result'=>'failure', 'message'=>'Selected new role does not exist');
return $answer;
}
$users = $assign_role->get_users_without_role($new_role);
$answer = array('result'=>'success', 'users'=>$users, 'new_role'=>$new_role, 'message'=>'success');
return $answer;
}
// end of get_users_without_role()
protected function _dispatch() {
switch ($this->action) {
case 'get_caps_to_remove':
$answer = $this->get_caps_to_remove();
break;
case 'get_users_without_role':
$answer = $this->get_users_without_role();
break;
default:
$answer = array('result' => 'error', 'message' => 'unknown action "' . $this->action . '"');
}
return $answer;
}
// end of _dispatch()
/**
* AJAX requests dispatcher
*/
public function dispatch() {
$this->get_action();
$this->ajax_check_permissions();
$answer = $this->_dispatch();
$json_answer = json_encode($answer);
echo $json_answer;
die;
}
}
// end of URE_Ajax_Processor
<?php
/**
* Project: User Role Editor plugin
* Author: Vladimir Garagulya
* Author email: support@role-editor.com
* Author URI: https://www.role-editor.com
* Greetings: some ideas and code samples for long runing cron job was taken from the "Broken Link Checker" plugin (Janis Elst).
* License: GPL v2+
*
* Assign role to the users without role stuff
*/
class URE_Assign_Role {
const MAX_USERS_TO_PROCESS = 50;
protected $lib = null;
function __construct($lib) {
$this->lib = $lib;
}
// end of __construct()
public function create_no_rights_role() {
global $wp_roles;
$role_id = 'no_rights';
$role_name = 'No rights';
if (!isset($wp_roles)) {
$wp_roles = new WP_Roles();
}
if (isset($wp_roles->roles[$role_id])) {
return;
}
add_role($role_id, $role_name, array());
}
// end of create_no_rights_role()
private function get_where_condition() {
global $wpdb;
$usermeta = $this->lib->get_usermeta_table_name();
$id = get_current_blog_id();
$blog_prefix = $wpdb->get_blog_prefix($id);
$where = "where not exists (select user_id from {$usermeta}
where user_id=users.ID and meta_key='{$blog_prefix}capabilities') or
exists (select user_id from {$usermeta}
where user_id=users.ID and meta_key='{$blog_prefix}capabilities' and meta_value='a:0:{}')";
return $where;
}
// end of get_where_condition()
public function count_users_without_role() {
global $wpdb;
$users_quant = get_transient('ure_users_without_role');
if (empty($users_quant)) {
$where = $this->get_where_condition();
$query = "select count(ID) from {$wpdb->users} users {$where}";
$users_quant = $wpdb->get_var($query);
set_transient('ure_users_without_role', $users_quant, 15);
}
return $users_quant;
}
// end of count_users_without_role()
public function get_users_without_role($new_role='') {
global $wpdb;
$top_limit = self::MAX_USERS_TO_PROCESS;
$where = $this->get_where_condition();
$query = "select ID from {$wpdb->users} users
{$where}
limit 0, {$top_limit}";
$users0 = $wpdb->get_col($query);
return $users0;
}
// end of get_users_without_role()
}
// end of URE_Assign_Role class
\ No newline at end of file
<?php
/*
* General stuff for usage at WordPress plugins
* Author: Vladimir Garagulya
* Author email: vladimir@shinephp.com
* Author URI: http://shinephp.com
*
*/
/**
* This class contains general stuff for usage at WordPress plugins and must be extended by child class
*/
class URE_Base_Lib {
protected static $instance = null; // object exemplar reference
protected $options_id = ''; // identifire to save/retrieve plugin options to/from wp_option DB table
protected $options = array(); // plugin options data
protected $multisite = false;
protected $active_for_network = false;
protected $blog_ids = null;
protected $main_blog_id = 0;
public static function get_instance($options_id = '') {
if (self::$instance===null) {
self::$instance = new URE_Base_Lib($options_id);
}
return self::$instance;
}
// end of get_instance()
/**
* class constructor
* @param string $options_id to save/retrieve plugin options to/from wp_option DB table
*/
protected function __construct($options_id) {
$this->multisite = function_exists('is_multisite') && is_multisite();
if ($this->multisite) {
$this->blog_ids = $this->get_blog_ids();
// get Id of 1st (main) blog
$this->main_blog_id = $this->get_main_site();
}
$this->init_options($options_id);
}
// end of __construct()
public function get($property_name) {
if (!property_exists($this, $property_name)) {
syslog(LOG_ERR, 'Lib class does not have such property '. $property_name);
}
return $this->$property_name;
}
// end of get_property()
public function set($property_name, $property_value) {
if (!property_exists($this, $property_name)) {
syslog(LOG_ERR, 'Lib class does not have such property '. $property_name);
}
$this->$property_name = $property_value;
}
// end of get_property()
public function get_main_site() {
global $current_site;
return $current_site->blog_id;
}
// end of get_main_site()
/**
* Returns the array of multisite WP blogs IDs
* @global wpdb $wpdb
* @return array
*/
protected function get_blog_ids() {
global $wpdb;
$blog_ids = $wpdb->get_col("select blog_id from $wpdb->blogs order by blog_id asc");
return $blog_ids;
}
// end of get_blog_ids()
/**
* get current options for this plugin
*/
protected function init_options($options_id) {
$this->options_id = $options_id;
$this->options = get_option($options_id);
}
// end of init_options()
/**
* Return HTML formatted message
*
* @param string $message message text
* @param string $error_style message div CSS style
*/
public function show_message($message, $error_style = false) {
if ($message) {
if ($error_style) {
echo '<div id="message" class="error" >';
} else {
echo '<div id="message" class="updated fade">';
}
echo $message . '</div>';
}
}
// end of show_message()
/**
* Returns value by name from GET/POST/REQUEST. Minimal type checking is provided
*
* @param string $var_name Variable name to return
* @param string $request_type type of request to process get/post/request (default)
* @param string $var_type variable type to provide value checking
* @return mix variable value from request
*/
public function get_request_var($var_name, $request_type = 'request', $var_type = 'string') {
$result = 0;
if ($request_type == 'get') {
if (isset($_GET[$var_name])) {
$result = filter_var($_GET[$var_name], FILTER_SANITIZE_STRING);
}
} else if ($request_type == 'post') {
if (isset($_POST[$var_name])) {
if ($var_type != 'checkbox') {
$result = filter_var($_POST[$var_name], FILTER_SANITIZE_STRING);;
} else {
$result = 1;
}
}
} else {
if (isset($_REQUEST[$var_name])) {
$result = filter_var($_REQUEST[$var_name], FILTER_SANITIZE_STRING);
}
}
if ($result) {
if ($var_type == 'int' && !is_numeric($result)) {
$result = 0;
}
if ($var_type != 'int') {
$result = esc_attr($result);
}
}
return $result;
}
// end of get_request_var()
/**
* returns option value for option with name in $option_name
*/
public function get_option($option_name, $default = false) {
if (isset($this->options[$option_name])) {
return $this->options[$option_name];
} else {
return $default;
}
}
// end of get_option()
/**
* puts option value according to $option_name option name into options array property
*/
public function put_option($option_name, $option_value, $flush_options = false) {
$this->options[$option_name] = $option_value;
if ($flush_options) {
$this->flush_options();
}
}
// end of put_option()
/**
* Delete URE option with name option_name
* @param string $option_name
* @param bool $flush_options
*/
public function delete_option($option_name, $flush_options = false) {
if (array_key_exists($option_name, $this->options)) {
unset($this->options[$option_name]);
if ($flush_options) {
$this->flush_options();
}
}
}
// end of delete_option()
/**
* saves options array into WordPress database wp_options table
*/
public function flush_options() {
update_option($this->options_id, $this->options);
}
// end of flush_options()
/**
* Check product versrion and stop execution if product version is not compatible
* @param type $must_have_version
* @param type $version_to_check
* @param type $error_message
* @return type
*/
public static function check_version($must_have_version, $version_to_check, $error_message, $plugin_file_name) {
if (version_compare($must_have_version, $version_to_check, '<')) {
if (is_admin() && (!defined('DOING_AJAX') || !DOING_AJAX )) {
require_once ABSPATH . '/wp-admin/includes/plugin.php';
deactivate_plugins($plugin_file_name);
wp_die($error_message);
} else {
return;
}
}
}
// end of check_version()
public function get_current_url() {
global $wp;
$current_url = esc_url_raw(add_query_arg($wp->query_string, '', home_url($wp->request)));
return $current_url;
}
// end of get_current_url()
/**
* Returns comma separated list from the first $items_count element of $full_list array
*
* @param array $full_list
* @param int $items_count
* @return string
*/
public function get_short_list_str($full_list, $items_count=3) {
$short_list = array(); $i = 0;
foreach($full_list as $key=>$item) {
if ($i>=$items_count) {
break;
}
$short_list[] = $item;
$i++;
}
$str = implode(', ', $short_list);
if ($items_count<count($full_list)) {
$str .= '...';
}
return $str;
}
// end of get_short_list_str()
/**
* Private clone method to prevent cloning of the instance of the
* *Singleton* instance.
*
* @return void
*/
private function __clone() {
}
// end of __clone()
/**
* Private unserialize method to prevent unserializing of the *Singleton*
* instance.
*
* @return void
*/
private function __wakeup() {
}
// end of __wakeup()
}
// end of Garvs_WP_Lib class
\ No newline at end of file
<?php
/**
* Support for bbPress user roles and capabilities
*
* Project: User Role Editor WordPress plugin
* Author: Vladimir Garagulya
* Author email: vladimir@shinephp.com
* Author URI: http://shinephp.com
*
**/
class URE_bbPress {
public static $instance = null;
protected $lib = null;
protected function __construct(Ure_Lib $lib) {
$this->lib = $lib;
}
// end of __construct()
static public function get_instance(Ure_Lib $lib) {
if (!function_exists('bbp_filter_blog_editable_roles')) { // bbPress plugin is not active
return null;
}
if (self::$instance!==null) {
return self::$instance;
}
if ($lib->is_pro()) {
self::$instance = new URE_bbPress_Pro($lib);
} else {
self::$instance = new URE_bbPress($lib);
}
return self::$instance;
}
// end of get_instance()
/**
* Exclude roles created by bbPress
*
* @global array $wp_roles
* @return array
*/
public function get_roles() {
global $wp_roles;
$roles = bbp_filter_blog_editable_roles($wp_roles->roles); // exclude bbPress roles
return $roles;
}
// end of get_roles()
/**
* Get full list user capabilities created by bbPress
*
* @return array
*/
public function get_caps() {
$caps = array_keys(bbp_get_caps_for_role(bbp_get_keymaster_role()));
return $caps;
}
// end of get_caps()
}
// end of URE_bbPress class
\ No newline at end of file
<?php
/**
* Class to work with user capability
*
* @package User-Role-Editor
* @subpackage Admin
* @author Vladimir Garagulya <support@role-editor.com>
* @copyright Copyright (c) 2010 - 2016, Vladimir Garagulya
**/
class URE_Capability {
const SPACE_REPLACER = '_URE-SR_';
const SLASH_REPLACER = '_URE-SLR_';
const VERT_LINE_REPLACER = '_URE-VLR_';
public static function escape($cap_id) {
$search = array(' ', '/', '|');
$replace = array(self::SPACE_REPLACER, self::SLASH_REPLACER, self::VERT_LINE_REPLACER);
$cap_id_esc = str_replace($search, $replace, $cap_id);
return $cap_id_esc;
}
// end escape()
// sanitize user input for security
public static function validate($cap_id_raw) {
$match = array();
$found = preg_match('/[A-Za-z0-9_\-]*/', $cap_id_raw, $match);
if ( !$found || ($found && ($match[0]!=$cap_id_raw)) ) { // some non-alphanumeric charactes found!
$result = false;
} else {
$result = true;
}
$data = array('result'=>$result, 'cap_id'=>strtolower($match[0]));
return $data;
}
// end of validate()
/**
* Add new user capability
*
* @global WP_Roles $wp_roles
* @return string
*/
public static function add() {
global $wp_roles;
if (!current_user_can('ure_create_capabilities')) {
return esc_html__('Insufficient permissions to work with User Role Editor','user-role-editor');
}
$mess = '';
if (!isset($_POST['capability_id']) || empty($_POST['capability_id'])) {
return 'Wrong Request';
}
$data = self::validate($_POST['capability_id']);
if (!$data['result']) {
return esc_html__('Error: Capability name must contain latin characters and digits only!', 'user-role-editor');
}
$cap_id = $data['cap_id'];
$lib = URE_Lib::get_instance();
$lib->get_user_roles();
$lib->init_full_capabilities();
$full_capabilities = $lib->get('full_capabilities');
if (!isset($full_capabilities[$cap_id])) {
$admin_role = $lib->get_admin_role();
$wp_roles->use_db = true;
$wp_roles->add_cap($admin_role, $cap_id);
$mess = sprintf(esc_html__('Capability %s is added successfully', 'user-role-editor'), $cap_id);
} else {
$mess = sprintf(esc_html__('Capability %s exists already', 'user-role-editor'), $cap_id);
}
return $mess;
}
// end of add()
/**
* Extract capabilities selected from deletion from the $_POST global
*
* @return array
*/
private static function get_caps_for_deletion_from_post($caps_allowed_to_remove) {
$caps = array();
foreach($_POST as $key=>$value) {
if (substr($key, 0, 3)!=='rm_') {
continue;
}
if (!isset($caps_allowed_to_remove[$value])) {
continue;
}
$caps[] = $value;
}
return $caps;
}
// end of get_caps_for_deletion_from_post()
private static function revoke_caps_from_user($user_id, $caps) {
$user = get_user_to_edit($user_id);
foreach($caps as $cap_id) {
if (isset($user->caps[$cap_id])) {
$user->remove_cap($cap_id);
}
}
}
// end of revoke_caps_from_user()
private static function revoke_caps_from_role($wp_role, $caps) {
foreach($caps as $cap_id) {
if ($wp_role->has_cap($cap_id)) {
$wp_role->remove_cap($cap_id);
}
}
}
// end of revoke_caps_from_role()
private static function revoke_caps($caps) {
global $wpdb, $wp_roles;
// remove caps from users
$users_ids = $wpdb->get_col("SELECT $wpdb->users.ID FROM $wpdb->users");
foreach ($users_ids as $user_id) {
self::revoke_caps_from_user($user_id, $caps);
}
// remove caps from roles
foreach ($wp_roles->role_objects as $wp_role) {
self::revoke_caps_from_role($wp_role, $caps);
}
}
// end of revoke_caps()
/**
* Delete capability
*
* @global wpdb $wpdb
* @global WP_Roles $wp_roles
* @return string - information message
*/
public static function delete() {
if (!isset($_POST['action']) || $_POST['action']!='delete-user-capability') {
return 'Wrong Request';
}
if (!current_user_can('ure_delete_capabilities')) {
return esc_html__('Insufficient permissions to work with User Role Editor','user-role-editor');
}
$lib = URE_Lib::get_instance();
$mess = '';
$caps_allowed_to_remove = $lib->get_caps_to_remove();
if (!is_array($caps_allowed_to_remove) || count($caps_allowed_to_remove) == 0) {
return esc_html__('There are no capabilities available for deletion!', 'user-role-editor');
}
$capabilities = self::get_caps_for_deletion_from_post($caps_allowed_to_remove);
if (empty($capabilities)) {
return esc_html__('There are no capabilities available for deletion!', 'user-role-editor');
}
self::revoke_caps($capabilities);
if (count($capabilities)==1) {
$mess = sprintf(esc_html__('Capability %s was removed successfully', 'user-role-editor'), $capabilities[0]);
} else {
$short_list_str = $lib->get_short_list_str($capabilities);
$mess = count($capabilities) .' '. esc_html__('capabilities were removed successfully', 'user-role-editor') .': '.
$short_list_str;
}
return $mess;
}
// end of delete()
}
// end of class URE_Capability
<?php
class URE_Known_JS_CSS_Compatibility_Issues {
public static function fix($hook_suffix, $ure_hook_suffixes) {
$ure_hook_suffixes[] = 'users.php';
$ure_hook_suffixes[] = 'profile.php';
if (!in_array($hook_suffix, $ure_hook_suffixes)) {
return;
}
self::unload_techgostore($hook_suffix);
self::unload_musicplay($hook_suffix);
self::unload_conflict_plugins_css($hook_suffix);
}
// end of fix()
/**
* Unload WP TechGoStore theme JS and CSS to exclude compatibility issues with URE
*/
private static function unload_techgostore($hook_suffix) {
if (!defined('THEME_SLUG') || THEME_SLUG !== 'techgo_') {
return;
}
wp_deregister_script('jqueryform');
wp_deregister_script('tab');
wp_deregister_script('shortcode_js');
wp_deregister_script('fancybox_js');
wp_deregister_script('bootstrap-colorpicker');
wp_deregister_script('logo_upload');
wp_deregister_script('js_wd_menu_backend');
wp_deregister_style('config_css');
wp_deregister_style('fancybox_css');
wp_deregister_style('colorpicker');
wp_deregister_style('font-awesome');
wp_deregister_style('css_wd_menu_backend');
}
// end of unload_techgostore()
/**
* Unload MusicPlay theme CSS to exclude compatibility issues with URE
*
*/
private static function unload_musicplay($hook_suffix) {
if (!in_array($hook_suffix, array('users.php', 'profile.php')) ) {
return;
}
if (defined('THEMENAME') && THEMENAME!=='MusicPlay') {
return;
}
wp_deregister_style('atpadmin');
wp_deregister_style('appointment-style');
wp_deregister_style('atp-chosen');
wp_deregister_style('atp_plupload');
wp_deregister_style('atp-jquery-timepicker-addon');
wp_deregister_style('atp-jquery-ui');
}
// end of unload_music_play()
private static function unload_conflict_plugins_css($hook_suffix) {
global $wp_styles;
if (!in_array($hook_suffix, array('users.php', 'profile.php')) ) {
return;
}
// remove conflict CSS from responsive-admin-maintenance-pro plugin
if (isset($wp_styles->registered['admin-page-css'])) {
wp_deregister_style('admin-page-css');
}
}
// end of unload_conflict_plugins_css()
}
// end of URE_Fix_Known_JS_CSS_Compatibility_Issues
\ No newline at end of file
<?php
/**
* Class to provide the routine for the own User Role Editor user capabilities list
*
* @package User-Role-Editor
* @subpackage Admin
* @author Vladimir Garagulya <support@role-editor.com>
* @copyright Copyright (c) 2010 - 2016, Vladimir Garagulya
**/
class URE_Own_Capabilities {
const URE_SETTINGS_CAP_TR = 'ure_settings_cap';
public static function get_caps() {
$lib = URE_Lib::get_instance();
$ure_caps = array(
'ure_edit_roles' => 1,
'ure_create_roles' => 1,
'ure_delete_roles' => 1,
'ure_create_capabilities' => 1,
'ure_delete_capabilities' => 1,
'ure_manage_options' => 1,
'ure_reset_roles' => 1
);
if ($lib->is_pro()) {
$ure_caps['ure_export_roles'] = 1;
$ure_caps['ure_import_roles'] = 1;
$ure_caps['ure_admin_menu_access'] = 1;
$ure_caps['ure_widgets_access'] = 1;
$ure_caps['ure_widgets_show_access'] = 1;
$ure_caps['ure_meta_boxes_access'] = 1;
$ure_caps['ure_other_roles_access'] = 1;
$ure_caps['ure_edit_posts_access'] = 1;
$ure_caps['ure_plugins_activation_access'] = 1;
$ure_caps['ure_view_posts_access'] = 1;
$ure_caps['ure_front_end_menu_access'] = 1;
$multisite = $lib->get('multisite');
if ($multisite) {
$ure_caps['ure_themes_access'] = 1;
}
}
return $ure_caps;
}
// end of get_caps()
/**
* return key capability to have access to User Role Editor Plugin
*/
public static function get_key_capability() {
$lib = URE_Lib::get_instance();
$key_cap = $lib->get('key_capability');
if (!empty($key_cap)) {
return $key_cap;
}
$multisite = $lib->get('multisite');
if (!$multisite) {
$key_cap = URE_KEY_CAPABILITY;
} else {
$enable_simple_admin_for_multisite = $lib->get_option('enable_simple_admin_for_multisite', 0);
if ( (defined('URE_ENABLE_SIMPLE_ADMIN_FOR_MULTISITE') && URE_ENABLE_SIMPLE_ADMIN_FOR_MULTISITE == 1) ||
$enable_simple_admin_for_multisite) {
$key_cap = URE_KEY_CAPABILITY;
} else {
$key_cap = 'manage_network_plugins';
}
}
$lib->set('key_capability', $key_cap);
return $key_cap;
}
// end of get_key_capability()
/**
* Return user capability for the User Role Editor Settings page
*
* @return string
*/
public static function get_settings_capability() {
$lib = URE_Lib::get_instance();
$settings_cap = $lib->get('settings_capability');
if (!empty($settings_cap)) {
return $settings_cap;
}
$multisite = $lib->get('multisite');
if (!$multisite) {
$settings_cap = 'ure_manage_options';
} else {
$enable_simple_admin_for_multisite = $lib->get_option('enable_simple_admin_for_multisite', 0);
if ((defined('URE_ENABLE_SIMPLE_ADMIN_FOR_MULTISITE') && URE_ENABLE_SIMPLE_ADMIN_FOR_MULTISITE == 1) ||
$enable_simple_admin_for_multisite) {
$settings_cap = 'ure_manage_options';
} else {
$settings_cap = self::get_key_capability();
}
}
$lib->set('settings_capability', $settings_cap);
return $settings_cap;
}
// end of get_settings_capability()
public static function init_caps() {
global $wp_roles;
if (!isset($wp_roles)) {
$wp_roles = new WP_Roles();
}
if (!isset($wp_roles->roles['administrator'])) {
return;
}
$lib = URE_Lib::get_instance();
$multisite = $lib->get('multisite');
// Do not turn on URE caps for local administrator by default under multisite, as there is a superadmin.
$turn_on = !$multisite;
$old_use_db = $wp_roles->use_db;
$wp_roles->use_db = true;
$administrator = $wp_roles->role_objects['administrator'];
$ure_caps = self::get_caps();
foreach(array_keys($ure_caps) as $cap) {
if (!$administrator->has_cap($cap)) {
$administrator->add_cap($cap, $turn_on);
}
}
$wp_roles->use_db = $old_use_db;
}
// end of init_caps()
/**
* Return list of URE capabilities with data about groups they were included
*
* @return array
*/
public static function get_caps_groups() {
$ure_caps = self::get_caps();
$caps = array();
foreach($ure_caps as $ure_cap=>$value) {
$caps[$ure_cap] = array('custom', 'user_role_editor');
}
return $caps;
}
// end of get_caps_groups()
}
// end of URE_Capabilities class
\ No newline at end of file
<?php
/*
* Main class of User Role Editor WordPress plugin
* Author: Vladimir Garagulya
* Author email: support@role-editor.com
* Author URI: https://www.role-editor.com
* License: GPL v2+
*
*/
class URE_Protect_Admin {
private $lib = null;
private $user_to_check = null; // cached list of user IDs, who has Administrator role
public function __construct($lib) {
$this->lib = $lib;
$this->user_to_check = array();
// Exclude administrator role from edit list.
add_filter('editable_roles', array($this, 'exclude_admin_role'));
// prohibit any actions with user who has Administrator role
add_filter('user_has_cap', array($this, 'not_edit_admin'), 10, 3);
// exclude users with 'Administrator' role from users list
add_action('pre_user_query', array($this, 'exclude_administrators'));
// do not show 'Administrator (s)' view above users list
add_filter('views_users', array($this, 'exclude_admins_view'));
}
// end of __construct()
// apply protection to the user edit pages only
protected function is_protection_applicable() {
$result = false;
$links_to_block = array('profile.php', 'users.php', 'user-new.php');
foreach ($links_to_block as $key => $value) {
$result = stripos($_SERVER['REQUEST_URI'], $value);
if ($result !== false) {
break;
}
}
return $result;
}
// end of is_protection_applicable()
/**
* exclude administrator role from the roles list
*
* @param string $roles
* @return array
*/
public function exclude_admin_role($roles) {
if ($this->is_protection_applicable() && isset($roles['administrator'])) {
unset($roles['administrator']);
}
return $roles;
}
// end of exclude_admin_role()
/**
* Check if user has "Administrator" role assigned
*
* @global wpdb $wpdb
* @param int $user_id
* @return boolean returns true is user has Role "Administrator"
*/
private function has_administrator_role($user_id) {
global $wpdb;
if (empty($user_id) || !is_numeric($user_id)) {
return false;
}
$table_name = $this->lib->get_usermeta_table_name();
$meta_key = $wpdb->prefix . 'capabilities';
$query = "SELECT count(*)
FROM $table_name
WHERE user_id=$user_id AND meta_key='$meta_key' AND meta_value like '%administrator%'";
$has_admin_role = $wpdb->get_var($query);
if ($has_admin_role > 0) {
$result = true;
} else {
$result = false;
}
// cache checking result for the future use
$this->user_to_check[$user_id] = $result;
return $result;
}
// end of has_administrator_role()
/**
* We have two vulnerable queries with user id at admin interface, which should be processed
* 1st: http://blogdomain.com/wp-admin/user-edit.php?user_id=ID&wp_http_referer=%2Fwp-admin%2Fusers.php
* 2nd: http://blogdomain.com/wp-admin/users.php?action=delete&user=ID&_wpnonce=ab34225a78
* If put Administrator user ID into such request, user with lower capabilities (if he has 'edit_users')
* can edit, delete admin record
* This function removes 'edit_users' capability from current user capabilities
* if request has admin user ID in it
*
* @param array $allcaps
* @param type $caps
* @param string $name
* @return array
*/
public function not_edit_admin($allcaps, $caps, $name) {
$user_keys = array('user_id', 'user');
foreach ($user_keys as $user_key) {
$access_deny = false;
$user_id = $this->lib->get_request_var($user_key, 'get');
if (empty($user_id)) {
break;
}
if ($user_id == 1) { // built-in WordPress Admin
$access_deny = true;
} else {
if (!isset($this->user_to_check[$user_id])) {
// check if user_id has Administrator role
$access_deny = $this->has_administrator_role($user_id);
} else {
// user_id was checked already, get result from cash
$access_deny = $this->user_to_check[$user_id];
}
}
if ($access_deny) {
unset($allcaps['edit_users']);
}
break;
}
return $allcaps;
}
// end of not_edit_admin()
/**
* add where criteria to exclude users with 'Administrator' role from users list
*
* @global wpdb $wpdb
* @param type $user_query
*/
public function exclude_administrators($user_query) {
global $wpdb;
if (!$this->is_protection_applicable()) { // block the user edit stuff only
return;
}
// get user_id of users with 'Administrator' role
$tableName = $this->lib->get_usermeta_table_name();
$meta_key = $wpdb->prefix . 'capabilities';
$admin_role_key = '%"administrator"%';
$query = "select user_id
from $tableName
where meta_key='$meta_key' and meta_value like '$admin_role_key'";
$ids_arr = $wpdb->get_col($query);
if (is_array($ids_arr) && count($ids_arr) > 0) {
$ids = implode(',', $ids_arr);
$user_query->query_where .= " AND ( $wpdb->users.ID NOT IN ( $ids ) )";
}
}
// end of exclude_administrators()
/*
* Exclude view of users with Administrator role
*
*/
public function exclude_admins_view($views) {
unset($views['administrator']);
return $views;
}
// end of exclude_admins_view()
}
// end of URE_Protect_Admin class
<?php
class URE_Role_Additional_Options {
private static $instance = null;
private $lib = null;
private $items = null;
private $active_items = null;
const STORAGE_ID = 'ure_role_additional_options_values';
public function __construct($lib) {
$this->lib = $lib;
$this->init();
}
// end of __construct()
public static function get_instance($lib) {
if (self::$instance===null) {
self::$instance = new URE_Role_Additional_Options($lib);
}
return self::$instance;
}
// end of get_instance()
public static function create_item($id, $label, $hook, $routine) {
$item = new stdClass();
$item->id = $id;
$item->label = $label;
$item->hook = $hook;
$item->routine = $routine;
return $item;
}
// end of create_item()
public static function get_active_items() {
$data = get_option(self::STORAGE_ID, array());
/*
// It's enough to update the role via URE to achieve this, that why this code is commented:
// remove deactivated options
$modified = false;
foreach($data as $role=>$items) {
foreach($items as $item_id) {
if (!isset($this->items[$item_id])) {
$modified = true;
unset($data[$role][$item_id]);
}
}
}
if ($modified) {
put_option(self::STORAGE_ID, $data);
}
*/
return $data;
}
private function init() {
$this->items = array();
$item = self::create_item('hide_admin_bar', esc_html__('Hide admin bar', 'user-role-editor'), 'init', 'ure_hide_admin_bar');
$this->items[$item->id] = $item;
// Allow other developers to modify the list of role's additonal options
$this->items = apply_filters('ure_role_additional_options', $this->items);
$this->active_items = self::get_active_items();
}
// end of init()
public function set_active_items_hooks() {
global $current_user;
if (current_user_can('ure_edit_roles')) {
return;
}
foreach($current_user->roles as $role) {
if (!isset($this->active_items[$role])) {
continue;
}
foreach(array_keys($this->active_items[$role]) as $item_id) {
if (isset($this->items[$item_id])) {
add_action($this->items[$item_id]->hook, $this->items[$item_id]->routine, 99);
}
}
}
}
// end of set_active_items_hooks()
public function save($current_role) {
$this->active_items = self::get_active_items();
$this->active_items[$current_role] = array();
foreach($this->items as $item) {
if (isset($_POST[$item->id])) {
$this->active_items[$current_role][$item->id] = 1;
}
}
update_option(self::STORAGE_ID, $this->active_items);
}
// end of save()
public function show($current_role) {
?>
<hr />
<?php echo esc_html__('Additional Options', 'user-role-editor');?>:
<table class="form-table" style="clear:none;" cellpadding="0" cellspacing="0">
<tr>
<td>
<?php
$first_time = true;
foreach($this->items as $item) {
$checked = (isset($this->active_items[$current_role]) &&
isset($this->active_items[$current_role][$item->id])) ? 'checked="checked"' : '';
if (!$first_time) {
?>
<br/>
<?php
}
?>
<input type="checkbox" name="<?php echo $item->id;?>" id="<?php echo $item->id;?>" value="<?php echo $item->id;?>" <?php echo $checked;?> >
<label for="<?php echo $item->id;?>"><?php echo $item->label;?></label>
<?php
$first_time = false;
}
?>
</td>
<td></td>
</tr>
</table>
<?php
}
// end of show()
}
// end of URE_Role_Additional_Options class
\ No newline at end of file
<?php
/*
* User Role Editor On Screen Help class
*
*/
class URE_Screen_Help {
protected function get_general_tab() {
$text = '<h2>'. esc_html__('User Role Editor Options page help', 'user-role-editor') .'</h2>
<p>
<ul>
<li><strong>' . esc_html__('Show Administrator role at User Role Editor', 'user-role-editor').'</strong> - ' .
esc_html__('turn this option on in order to make the "Administrator" role available at the User Role Editor '
. 'roles selection drop-down list. It is hidden by default for security reasons.','user-role-editor') . '</li>
<li><strong>' . esc_html__('Show capabilities in the human readable form','user-role-editor').'</strong> - ' .
esc_html__('automatically converts capability names from the technical form for internal use like '
. '"edit_others_posts" to more user friendly form, e.g. "Edit others posts".','user-role-editor') . '</li>
<li><strong>' . esc_html__('Show deprecated capabilities','user-role-editor').'</strong> - '.
esc_html__('Capabilities like "level_0", "level_1" are deprecated and are not used by WordPress. '
. 'They are left at the user roles for the compatibility purpose with the old themes and plugins code. '
. 'Turning on this option will show those deprecated capabilities.', 'user-role-editor') . '</li>
<li><strong>' . esc_html__('Edit user capabilities','user-role-editor').'</strong> - '.
esc_html__('If turned off - capabilities section of selected user is shown in readonly mode. '
. 'Administrator can not assign capabilities to the user directly. '
. 'He should make it using roles only.', 'user-role-editor') . '</li>';
$text = apply_filters('ure_get_settings_general_tab_help', $text);
$text .='
</ul>
</p>';
return $text;
}
// end of get_general_tab()
protected function get_additional_modules_tab() {
$text = '<h2>'. esc_html__('User Role Editor Options page help', 'user-role-editor') .'</h2>
<p>
<ul>';
if (!is_multisite()) {
$text .= '<li><strong>' . esc_html__('Count users without role', 'user-role-editor').'</strong> - ' .
esc_html__('Show at the "Users" page a quant of users without role. Module allows to assign all of them '.
'an empty role "No rights", in order to look on the users list with role "No rights" at the separate tab then.','user-role-editor') . '</li>';
}
$text = apply_filters('ure_get_settings_additional_modules_tab_help', $text);
$text .='
</ul>
</p>';
return $text;
}
// end of get_additional_modules_tab()
protected function get_default_roles_tab() {
$text = '<h2>'. esc_html__('User Role Editor Options page help', 'user-role-editor') .'</h2>
<p>
<ul>
<li><strong>' . esc_html__('Other default roles for new registered user', 'user-role-editor').'</strong> - ' .
esc_html__('select roles below to assign them to the new user automatically as an addition to the primary role. '.
'Note for multisite environment: take into account that other default roles should exist at the site, '.
'in order to be assigned to the new registered users.','user-role-editor') . '</li>';
$text = apply_filters('ure_get_settings_default_roles_tab_help', $text);
$text .='
</ul>
</p>';
return $text;
}
// end of get_default_roles_tab()
protected function get_multisite_tab() {
$text = '<h2>'. esc_html__('User Role Editor Options page help', 'user-role-editor') .'</h2>
<p>
<ul>
<li><strong>' . esc_html__('Allow non super-admininstrators to create, edit and delete users', 'user-role-editor').'</strong> - ' .
esc_html__('Super administrator only may create, edit and delete users under WordPress multi-site by default. '
. 'Turn this option on in order to remove this limitation.','user-role-editor') . '</li>';
$text = apply_filters('ure_get_settings_multisite_tab_help', $text);
$text .='
</ul>
</p>';
return $text;
}
// end of get_multisite_tab()
public function get_settings_help($tab_name) {
switch ($tab_name) {
case 'general':{
$text = $this->get_general_tab();
break;
}
case 'additional_modules':{
$text = $this->get_additional_modules_tab();
break;
}
case 'default_roles':{
$text = $this->get_default_roles_tab();
break;
}
case 'multisite':{
$text = $this->get_multisite_tab();
break;
}
default:
}
return $text;
}
// end of get_settings_help()
}
// end of URE_Screen_Help
<?php
/*
* User Role Editor Pro WordPress plugin
* Author: Vladimir Garagulya
* Author email: support@role-editor.com
* Author URI: https://www.role-editor.com
* License: GPL v3
*
*/
/*
* User Role Editor's internal tasks queue
* Usage: on URE plugin activation URE adds 'on_activation' task to this queue, which fires 'ure_on_activation' action
* on the next WordPress call. It's useful when some action is needed unavailable at standard plugin activation point,
* like 'admin_menu', which is used for the admin menu access data conversion - class URE_Admin_Menu_Hashes.
* Class User_Role_Editor_Pro adds execute_once method for the 'ure_on_activation' action, where
* URE_Admin_Menu_Hashes::require_data_conversion(); method is called which registers tasks for data coversion, including
* individual tasks for every site of the multisite network
*
*/
class URE_Task_Queue {
private static $instance = null; // object exemplar reference according to singleton patern
const OPTION_NAME = 'ure_tasks_queue';
private $queue = null;
public static function get_instance() {
if (self::$instance===null) {
self::$instance = new URE_Task_Queue();
}
return self::$instance;
}
// end of get_instance()
protected function __construct() {
$this->init();
}
// end of __construct()
private function init() {
$this->queue = get_option(self::OPTION_NAME, array());
}
// end of init()
public function reinit() {
$this->init();
}
// end of reinit()
/**
*
* @param string $task_id
* @param array $args=array('action'=>'action_name', 'routine'=>'routine_name', 'priority'=>99)
*/
public function add($task_id, $args=array()) {
$this->queue[$task_id] = $args;
update_option(self::OPTION_NAME, $this->queue);
}
// end of add_task()
public function remove($task_id) {
if (isset($this->queue[$task_id])) {
unset($this->queue[$task_id]);
update_option(self::OPTION_NAME, $this->queue);
}
}
// end of remove_task()
/**
* Returns true in case a queue is empty
*
* @return boolean
*/
public function is_empty() {
return count($this->queue)==0;
}
// end of is_empty()
/**
* Consumers should add there tasks with add_method and add 'ure_fulfil_task' action routine to work on it.
* Do not forget remove task after it was fulfilled.
*
* @return void
*/
public function process() {
if ($this->is_empty()) {
return;
}
foreach($this->queue as $task_id=>$task) {
if ($task_id=='on_activation') {
do_action('ure_on_activation');
$this->remove('on_activation'); // remove this task after execution if it was defined
} elseif (!empty($task['action'])) {
$priority = empty($task['priority']) ? 10: $task['priority'];
add_action($task['action'], $task['routine'], $priority);
} else {
add_action('init', $task['routine']);
}
}
}
// end of process();
/**
* Private clone method to prevent cloning of the instance of the
* *Singleton* instance.
*
* @return void
*/
private function __clone() {
}
// end of __clone()
/**
* Private unserialize method to prevent unserializing of the *Singleton*
* instance.
*
* @return void
*/
private function __wakeup() {
}
// end of __wakeup()
}
// end of class URE_On_Activation
\ No newline at end of file
<?php
/*
* Project: User Role Editor WordPress plugin
* Class for Assigning to a user multiple roles
* Author: Vladimir Garagulya
* Author email: support@role-editor.com
* Author URI: https://www.role-editor.com
* License: GPL v2+
*
*/
class URE_User_Other_Roles {
protected $lib = null;
function __construct() {
$this->lib = URE_Lib::get_instance();
$this->set_hooks();
}
// end of $lib
public function set_hooks() {
if (is_admin()) {
add_filter( 'additional_capabilities_display', array($this, 'additional_capabilities_display'), 10, 1);
add_action( 'admin_print_styles-user-edit.php', array($this, 'load_css') );
add_action( 'admin_print_styles-user-new.php', array($this, 'load_css') );
add_action( 'admin_enqueue_scripts', array($this, 'load_js' ) );
add_action( 'edit_user_profile', array($this, 'edit_user_profile_html'), 10, 1 );
add_action( 'user_new_form', array($this, 'user_new_form'), 10, 1 );
add_action( 'profile_update', array($this, 'update'), 10 );
}
$multisite = $this->lib->get('multisite');
if ($multisite) {
add_action( 'wpmu_activate_user', array($this, 'add_other_roles'), 10, 1 );
}
add_action( 'user_register', array($this, 'add_other_roles'), 10, 1 );
}
// end of set_hooks()
public function additional_capabilities_display($display) {
$display = false;
return $display;
}
// end of additional_capabilities_display()
/*
* Load CSS for the user profile edit page
*/
public function load_css() {
wp_enqueue_style('wp-jquery-ui-dialog');
wp_enqueue_style('ure-jquery-multiple-select', plugins_url('/css/multiple-select.css', URE_PLUGIN_FULL_PATH), array(), false, 'screen');
}
// end of load_css()
public function load_js($hook_suffix) {
if (!in_array($hook_suffix, array('user-edit.php', 'user-new.php'))) {
return;
}
wp_enqueue_script('jquery-ui-dialog', false, array('jquery-ui-core', 'jquery-ui-button', 'jquery'));
wp_register_script('ure-jquery-multiple-select', plugins_url('/js/jquery.multiple.select.js', URE_PLUGIN_FULL_PATH));
wp_enqueue_script('ure-jquery-multiple-select');
wp_register_script('ure-user-profile-other-roles', plugins_url('/js/ure-user-profile-other-roles.js', URE_PLUGIN_FULL_PATH));
wp_enqueue_script('ure-user-profile-other-roles');
wp_localize_script('ure-user-profile-other-roles', 'ure_data_user_profile_other_roles', array(
'wp_nonce' => wp_create_nonce('user-role-editor'),
'other_roles' => esc_html__('Other Roles', 'user-role-editor'),
'select_roles' => esc_html__('Select additional roles for this user', 'user-role-editor')
));
}
// end of load_js()
/**
* Returns list of user roles, except 1st one, and bbPress assigned as they are shown by WordPress and bbPress theirselves.
*
* @param type $user WP_User from wp-includes/capabilities.php
* @return array
*/
public function get_roles_array($user) {
if (!is_array($user->roles) || count($user->roles) <= 1) {
return array();
}
// get bbPress assigned user role
if (function_exists('bbp_filter_blog_editable_roles')) {
$bb_press_role = bbp_get_user_role($user->ID);
} else {
$bb_press_role = '';
}
$roles = array();
foreach ($user->roles as $key => $value) {
if (!empty($bb_press_role) && $bb_press_role === $value) {
// exclude bbPress assigned role
continue;
}
$roles[] = $value;
}
array_shift($roles); // exclude primary role which is shown by WordPress itself
return $roles;
}
// end of get_roles_array()
private function roles_select_html($user) {
global $wp_roles;
$user_roles = $user->roles;
$primary_role = array_shift($user_roles);
$roles = apply_filters('editable_roles', $wp_roles->roles); // exclude restricted roles if any
if (isset($roles[$primary_role])) { // exclude role assigned to the user as a primary role
unset($roles[$primary_role]);
}
$other_roles = $this->get_roles_array($user);
echo '<select multiple="multiple" id="ure_select_other_roles" name="ure_select_other_roles" style="width: 500px;" >'."\n";
foreach($roles as $key=>$role) {
echo '<option value="'.$key.'" >'.$role['name'].'</option>'."\n";
} // foreach()
echo '</select><br>'."\n";
if (is_array($other_roles) && count($other_roles) > 0) {
$other_roles_str = implode(',', $other_roles);
} else {
$other_roles_str = '';
}
echo '<input type="hidden" name="ure_other_roles" id="ure_other_roles" value="' . $other_roles_str . '" />';
$output = $this->lib->roles_text($other_roles);
echo '<span id="ure_other_roles_list">'. $output .'</span>';
}
// end of roles_select()
private function user_profile_capabilities($user) {
global $current_user;
$user_caps = $this->lib->get_edited_user_caps($user);
?>
<tr>
<th>
<?php esc_html_e('Capabilities', 'user-role-editor'); ?>
</th>
<td>
<?php
echo $user_caps .'<br/>';
if ($this->lib->user_is_admin($current_user->ID)) {
echo '<a href="' . wp_nonce_url("users.php?page=users-".URE_PLUGIN_FILE."&object=user&amp;user_id={$user->ID}", "ure_user_{$user->ID}") . '">' .
esc_html__('Edit', 'user-role-editor') . '</a>';
}
?>
</td>
</tr>
<?php
}
// end of user_profile_capabilities()
private function display($user, $context) {
?>
<table class="form-table">
<tr>
<th scope="row"><?php esc_html_e('Other Roles', 'user-role-editor'); ?></th>
<td>
<?php
$this->roles_select_html($user);
?>
</td>
</tr>
<?php
if ($context=='user-edit') {
$this->user_profile_capabilities($user);
}
?>
</table>
<?php
}
// end of display()
/**
* Add URE stuff to the edit user profile page
*
* @global object $current_user
* @param object $user
* @return void
*/
public function edit_user_profile_html($user) {
if (!$this->lib->is_user_profile_extention_allowed()) {
return;
}
$show = apply_filters('ure_show_additional_capabilities_section', true);
if (empty($show)) {
return;
}
?>
<h3><?php esc_html_e('Additional Capabilities', 'user-role-editor'); ?></h3>
<?php
$this->display($user, 'user-edit');
}
// end of edit_user_profile()
public function user_new_form($context) {
$show = apply_filters('ure_show_additional_capabilities_section', true);
if (empty($show)) {
return;
}
$user = new WP_User();
?>
<table>
<?php
$this->display($user, $context);
?>
</table>
<?php
}
// end of edit_user_profile_html()
// save additional user roles when user profile is updated, as WordPress itself doesn't know about them
public function update($user_id) {
global $wp_roles;
if (!current_user_can('edit_users')) {
return false;
}
if (!current_user_can('edit_user', $user_id)) {
return false;
}
$user = get_userdata($user_id);
if (empty($_POST['ure_other_roles'])) {
return false;
}
$data = explode(',', str_replace(' ', '', $_POST['ure_other_roles']));
$ure_other_roles = array();
foreach($data as $role_id) {
if (!isset($wp_roles->roles[$role_id])) { // skip unexisted roles
continue;
}
if (is_array($user->roles) && !in_array($role_id, $user->roles)) {
$ure_other_roles[] = $role_id;
}
}
foreach ($ure_other_roles as $role) {
$user->add_role($role);
}
return true;
}
// end of update()
private function add_default_other_roles($user_id) {
$user = get_user_by('id', $user_id);
if (empty($user->ID)) {
return;
}
// Get default roles if any
$other_default_roles = $this->lib->get_option('other_default_roles', array());
if (count($other_default_roles) == 0) {
return;
}
foreach ($other_default_roles as $role) {
if (!isset($user->caps[$role])) {
$user->add_role($role);
}
}
}
// end of add_default_other_roles()
public function add_other_roles($user_id) {
if (empty($user_id)) {
return;
}
$result = $this->update($user_id);
if ($result) { // roles were assigned manually
return;
}
$this->add_default_other_roles($user_id);
}
// end of add_other_roles()
}
// end of URE_User_Other_Roles class
<?php
/**
* User capabilities View class to output HTML with capabilities assigne to the user
*
* @package User-Role-Editor
* @subpackage Admin
* @author Vladimir Garagulya <support@role-editor.com>
* @copyright Copyright (c) 2010 - 2016, Vladimir Garagulya
**/
class URE_User_View extends URE_View {
private $lib = null;
private $user_to_edit = null;
public function __construct() {
parent::__construct();
$this->lib = URE_Lib::get_instance();
$this->user_to_edit = $this->lib->get('user_to_edit');
}
// end of __construct()
public function display_edit_dialogs() {
}
// end of display_edit_dialogs()
/**
* output HTML code to create URE toolbar
*
* @param boolean $role_delete
* @param boolean $capability_remove
*/
public function toolbar() {
?>
<div id="ure_toolbar" >
<div id="ure_update">
<button id="ure_update_role" class="ure_toolbar_button button-primary">Update</button>
<?php
do_action('ure_user_edit_toolbar_update');
?>
</div>
</div>
<?php
}
// end of toolbar()
private function get_user_info() {
$switch_to_user = '';
if (!is_multisite() || current_user_can('manage_network_users')) {
$anchor_start = '<a href="' . wp_nonce_url("user-edit.php?user_id={$this->user_to_edit->ID}", "ure_user_{$this->user_to_edit->ID}") . '" >';
$anchor_end = '</a>';
if (class_exists('user_switching') && current_user_can('switch_to_user', $this->user_to_edit->ID)) {
$switch_to_user_link = user_switching::switch_to_url($this->user_to_edit);
$switch_to_user = '<a href="' . esc_url($switch_to_user_link) . '">' . esc_html__('Switch&nbsp;To', 'user-switching') . '</a>';
}
} else {
$anchor_start = '';
$anchor_end = '';
}
$user_info = ' <span style="font-weight: bold;">' . $anchor_start . $this->user_to_edit->user_login;
if ($this->user_to_edit->display_name !== $this->user_to_edit->user_login) {
$user_info .= ' (' . $this->user_to_edit->display_name . ')';
}
$user_info .= $anchor_end . '</span>';
if (is_multisite() && $this->lib->is_super_admin($this->user_to_edit->ID)) {
$user_info .= ' <span style="font-weight: bold; color:red;">' . esc_html__('Network Super Admin', 'user-role-editor') . '</span>';
}
if (!empty($switch_to_user)) {
$user_info .= '&nbsp;&nbsp;&nbsp;&nbsp;' . $switch_to_user;
}
return $user_info;
}
// end of get_user_info()
private function show_primary_role_dropdown_list($user_roles) {
?>
<select name="primary_role" id="primary_role">
<?php
// Compare user role against currently editable roles
$user_roles = array_intersect( array_values( $user_roles ), array_keys( get_editable_roles() ) );
$user_primary_role = array_shift( $user_roles );
// print the full list of roles with the primary one selected.
wp_dropdown_roles($user_primary_role);
// print the 'no role' option. Make it selected if the user has no role yet.
$selected = ( empty($user_primary_role) ) ? 'selected="selected"' : '';
echo '<option value="" '. $selected.'>' . esc_html__('&mdash; No role for this site &mdash;') . '</option>';
?>
</select>
<?php
}
// end of show_primary_role_dropdown_list()
private function show_secondary_roles() {
$show_admin_role = $this->lib->show_admin_role_allowed();
$values = array_values($this->user_to_edit->roles);
$primary_role = array_shift($values); // get 1st element from roles array
$roles = $this->lib->get('roles');
foreach ($roles as $role_id => $role) {
if (($show_admin_role || $role_id != 'administrator') && ($role_id !== $primary_role)) {
if ($this->lib->user_can($role_id)) {
$checked = 'checked="checked"';
} else {
$checked = '';
}
echo '<label for="wp_role_' . $role_id . '"><input type="checkbox" id="wp_role_' . $role_id .
'" name="wp_role_' . $role_id . '" value="' . $role_id . '"' . $checked . ' />&nbsp;' .
esc_html__($role['name'], 'user-role-editor') . '</label><br />';
}
}
}
// end of show_secondary_roles()
public function display() {
$caps_readable = $this->lib->get('caps_readable');
$show_deprecated_caps = $this->lib->get('show_deprecated_caps');
$edit_user_caps_mode = $this->lib->get_edit_user_caps_mode();
$caps_access_restrict_for_simple_admin = $this->lib->get_option('caps_access_restrict_for_simple_admin', 0);
$user_info = $this->get_user_info();
?>
<div class="postbox" style="float:left;min-width:1000px;width: 100%;">
<div id="ure_user_caps_header">
<span id="ure_user_caps_title"><?php esc_html_e('Change capabilities for user', 'user-role-editor')?></span> <?php echo $user_info;?>
</div>
<div class="inside">
<table cellpadding="0" cellspacing="0" style="width: 100%;">
<tr>
<td>&nbsp;</td>
<td style="padding-left: 10px; padding-bottom: 5px;">
<?php
if ($this->lib->is_super_admin() || !$this->multisite || !class_exists('User_Role_Editor_Pro') || !$caps_access_restrict_for_simple_admin) {
if ($caps_readable) {
$checked = 'checked="checked"';
} else {
$checked = '';
}
?>
<input type="checkbox" name="ure_caps_readable" id="ure_caps_readable" value="1"
<?php echo $checked; ?> onclick="ure_turn_caps_readable(<?php echo $this->user_to_edit->ID; ?>);" />
<label for="ure_caps_readable"><?php esc_html_e('Show capabilities in human readable form', 'user-role-editor'); ?></label>&nbsp;&nbsp;&nbsp;
<?php
if ($show_deprecated_caps) {
$checked = 'checked="checked"';
} else {
$checked = '';
}
?>
<input type="checkbox" name="ure_show_deprecated_caps" id="ure_show_deprecated_caps" value="1"
<?php echo $checked; ?> onclick="ure_turn_deprecated_caps(<?php echo $this->user_to_edit->ID; ?>);"/>
<label for="ure_show_deprecated_caps"><?php esc_html_e('Show deprecated capabilities', 'user-role-editor'); ?></label>
<?php
}
?>
</td>
</tr>
<tr>
<td id="ure_user_roles">
<div class="ure-user-role-section-title"><?php esc_html_e('Primary Role:', 'user-role-editor'); ?></div>
<?php
$this->show_primary_role_dropdown_list($this->user_to_edit->roles);
if (function_exists('bbp_filter_blog_editable_roles') ) { // bbPress plugin is active
?>
<div class="ure-user-role-section-title" style="margin-top: 5px;"><?php esc_html_e('bbPress Role:', 'user-role-editor'); ?></div>
<?php
$dynamic_roles = bbp_get_dynamic_roles();
$bbp_user_role = bbp_get_user_role($this->user_to_edit->ID);
if (!empty($bbp_user_role)) {
echo $dynamic_roles[$bbp_user_role]['name'];
}
}
?>
<div style="margin-top: 5px;margin-bottom: 5px; font-weight: bold;"><?php esc_html_e('Other Roles:', 'user-role-editor'); ?></div>
<?php
$this->show_secondary_roles();
?>
</td>
<td style="padding-left: 5px; padding-top: 5px; border-top: 1px solid #ccc;">
<?php $this->display_caps(false, $edit_user_caps_mode ); ?>
</td>
</tr>
</table>
<input type="hidden" name="object" value="user" />
<input type="hidden" name="user_id" value="<?php echo $this->user_to_edit->ID; ?>" />
</div>
</div>
<?php
}
// end of display()
}
// end of class URE_User_View
\ No newline at end of file
This diff is collapsed.
<?php
/**
* Class to provide the list of WooCommerce plugin user capabilities
*
* @package User-Role-Editor
* @subpackage Admin
* @author Vladimir Garagulya <support@role-editor.com>
* @copyright Copyright (c) 2010 - 2016, Vladimir Garagulya
**/
class URE_Woocommerce_Capabilities {
public static $post_types = array('product', 'shop_order', 'shop_coupon', 'shop_webhook', 'product_variation', 'shop_order_refund');
private static $capability_types = array('product', 'shop_order', 'shop_coupon', 'shop_webhook');
public static function add_group_to_caps(&$caps, $post_type, $group) {
$post_types = $post_type .'s';
$caps['edit_'. $post_types][] = $group;
$caps['edit_others_'. $post_types][] = $group;
$caps['publish_'. $post_types][] = $group;
$caps['read_private_'. $post_types][] = $group;
$caps['delete_'. $post_types][] = $group;
$caps['delete_private_'. $post_types][] = $group;
$caps['delete_published_'. $post_types][] = $group;
$caps['delete_others_'. $post_types][] = $group;
$caps['edit_private_'. $post_types][] = $group;
$caps['edit_published_'. $post_types][] = $group;
}
// end of add_group_to_caps()
private static function add_base_caps(&$caps, $group, $subgroup, $cap_type) {
$cap_types = $cap_type .'s';
$caps['edit_'. $cap_type] = array('custom', $group, $subgroup, $cap_type);
$caps['read_'. $cap_type] = array('custom', $group, $subgroup, $cap_type);
$caps['delete_'. $cap_type] = array('custom', $group, $subgroup, $cap_type);
$caps['edit_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
$caps['edit_others_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
$caps['publish_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
$caps['read_private_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
$caps['delete_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
$caps['delete_private_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
$caps['delete_published_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
$caps['delete_others_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
$caps['edit_private_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
$caps['edit_published_'. $cap_types] = array('custom', $group, $subgroup, $cap_type);
}
// end of add_caps()
/**
* Returns full list of WooCommerce plugin user capabilities
*/
public static function get_caps_groups() {
$caps = array(
'manage_woocommerce'=>array('custom', 'woocommerce', 'woocommerce_core'),
'view_woocommerce_reports'=>array('custom', 'woocommerce', 'woocommerce_core'),
'view_admin_dashboard'=>array('custom', 'woocommerce', 'woocommerce_core')
);
// code was built on the base of woocommerce/includes/class-wc-install.php method WC_Install::get_core_capabilities()
$group = 'woocommerce';
foreach (self::$capability_types as $cap_type) {
$subgroup = $group .'_'. $cap_type;
self::add_base_caps($caps, $group, $subgroup, $cap_type);
$caps['manage_'. $cap_type .'_terms'] = array('custom', $group, $subgroup, $cap_type);
$caps['edit_'. $cap_type .'_terms'] = array('custom', $group, $subgroup, $cap_type);
$caps['delete_'. $cap_type .'_terms'] = array('custom', $group, $subgroup, $cap_type);
$caps['assign_'. $cap_type .'_terms'] = array('custom', $group, $subgroup, $cap_type);
}
$pto1 = get_post_type_object('product_variation');
if (empty($pto1) || $pto1->capability_type === 'product') { // default, not redefined by some plugin
// add capabilities group for the product_variation custom post type
self::add_group_to_caps($caps, 'product', 'woocommerce_product_variation');
self::add_group_to_caps($caps, 'product', 'product_variation');
} else {
$cap_type = 'product_variation';
$subgroup = $group .'_'. $cap_type;
self::add_base_caps($caps, $group, $subgroup, $cap_type);
}
$pto2 = get_post_type_object('shop_order_refund');
if (empty($pto2) || $pto2->capability_type === 'shop_order') { // default, not redefined by some plugin
// add capabilities group for the shop_order_refund custom post type
self::add_group_to_caps($caps, 'shop_order', 'woocommerce_shop_order_refund');
self::add_group_to_caps($caps, 'shop_order', 'shop_order_refund');
} else {
$cap_type = 'shop_order_variant';
$subgroup = $group .'_'. $cap_type;
self::add_base_caps($caps, $group, $subgroup, $cap_type);
}
return $caps;
}
// end of get()
/**
* This custom post types use capabilities from the other custom post types
* So we should define capabilities set for theme manually
* @return array()
*/
public static function get_post_types_without_caps() {
$pt_without_caps = array();
$pto1 = get_post_type_object('product_variation');
if (!empty($pto1) && $pto1->capability_type === 'product') {
$pt_without_caps[] = $pto1->name;
}
$pto2 = get_post_type_object('shop_order_refund');
if (!empty($pto2) && $pto2->capability_type === 'shop_order') {
$pt_without_caps[] = $pto2->name;
}
return $pt_without_caps;
}
// end of get_post_types_without_caps()
}
// end of URE_Woocommerce_Capabilities class
\ No newline at end of file
<?php
/*
* Constant definitions for use in User Role Editor WordPress plugin
* Author: Vladimir Garagulya
* Author email: vladimir@shinephp.com
* Author URI: http://shinephp.com
*
*/
define('URE_WP_ADMIN_URL', admin_url());
define('URE_ERROR', 'Error is encountered');
define('URE_PARENT', is_network_admin() ? 'network/users.php':'users.php');
define('URE_KEY_CAPABILITY', 'ure_manage_options');
\ No newline at end of file
<?php
/**
* Load related files
* Project: User Role Editor WordPress plugin
*
* Author: Vladimir Garagulya
* email: support@role-editor.com
*
**/
require_once(URE_PLUGIN_DIR .'includes/define-constants.php');
require_once(URE_PLUGIN_DIR .'includes/misc-support-stuff.php');
require_once(URE_PLUGIN_DIR .'includes/classes/task-queue.php');
require_once(URE_PLUGIN_DIR .'includes/classes/own-capabilities.php');
require_once(URE_PLUGIN_DIR .'includes/classes/bbpress.php');
require_once(URE_PLUGIN_DIR .'includes/classes/assign-role.php');
require_once(URE_PLUGIN_DIR .'includes/classes/user-other-roles.php');
require_once(URE_PLUGIN_DIR .'includes/classes/protect-admin.php');
require_once(URE_PLUGIN_DIR .'includes/classes/ajax-processor.php');
require_once(URE_PLUGIN_DIR .'includes/classes/screen-help.php');
require_once(URE_PLUGIN_DIR .'includes/classes/known-js-css-compatibility-issues.php');
require_once(URE_PLUGIN_DIR .'includes/classes/role-additional-options.php');
require_once(URE_PLUGIN_DIR .'includes/classes/capability.php');
require_once(URE_PLUGIN_DIR .'includes/classes/woocommerce-capabilities.php');
require_once(URE_PLUGIN_DIR .'includes/classes/capabilities-groups-manager.php');
require_once(URE_PLUGIN_DIR .'includes/classes/view.php');
require_once(URE_PLUGIN_DIR .'includes/classes/role-view.php');
require_once(URE_PLUGIN_DIR .'includes/classes/user-view.php');
require_once(URE_PLUGIN_DIR .'includes/classes/user-role-editor.php');
<?php
/*
* Miscellaneous support stuff, which should still be defined beyond of classes
*
* Author: Vladimir Garagulya
* Author email: vladimir@shinephp.com
* Author URI: http://shinephp.com
* License: GPL v3
*
*/
if (class_exists('GFForms') ) { // if Gravity Forms is installed
// Support for Gravity Forms capabilities
// As Gravity Form has integrated support for the Members plugin - let's imitate its presense,
// so GF code, like
// self::has_members_plugin())
// considers that it is has_members_plugin()
if (!function_exists('members_get_capabilities')) {
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
if (!is_plugin_active('members/members.php')) {
// define stub function to say "Gravity Forms" plugin: 'Hey! While I'm not the "Members" plugin, but I'm "User Role Editor" and
// I'm capable to manage your roles and capabilities too
function members_get_capabilities() {
}
}
}
}
if (!function_exists('ure_get_post_view_access_users')) {
function ure_get_post_view_access_users($post_id) {
if (!$GLOBALS['user_role_editor']->is_pro()) {
return false;
}
$result = $GLOBALS['user_role_editor']->get_post_view_access_users($post_id);
return $result;
}
// end of ure_get_post_view_users()
}
if (!function_exists('ure_hide_admin_bar')) {
function ure_hide_admin_bar() {
show_admin_bar(false);
}
// end of hide_admin_bar()
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment