Changeset 1425
- Timestamp:
- 03/19/2015 07:31:41 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/translate.wordpress.org/includes/gp-plugins/wporg-rosetta-roles/wporg-rosetta-roles.php
r909 r1425 3 3 * Tie roles on Rosetta sites directly into translate.wordpress.org. 4 4 * 5 * Anyone with the role of Validator, Contributor, Author, or Editor 6 * has the ability to validate strings for that language. 7 * 8 * Future improvements to this would make this more granular (i.e. per-project) 9 * with a UI in Rosetta to control those permissions. 10 * 11 * @author Nacin 5 * @author Nacin, ocean90 12 6 */ 13 7 class GP_WPorg_Rosetta_Roles extends GP_Plugin { 14 var $id = 'wporg-rosetta-roles'; 15 16 function __construct() { 8 /** 9 * Holds the plugin ID. 10 * 11 * @var string 12 */ 13 public $id = 'wporg-rosetta-roles'; 14 15 /** 16 * Holds the role of an approver. 17 * 18 * @var string 19 */ 20 public $approver_role = 'translation_editor'; 21 22 /** 23 * Holds the meta key of the project access list. 24 * 25 * @var string 26 */ 27 public $project_access_meta_key = 'translation_editor_project_access_list'; 28 29 /** 30 * Contructor. 31 */ 32 public function __construct() { 17 33 parent::__construct(); 18 34 $this->add_filter( 'pre_can_user', array( 'args' => 2, 'priority' => 9 ) ); 19 35 } 20 36 21 function pre_can_user( $verdict, $args ) { 22 if ( ! class_exists( 'BP_Roles' ) ) 37 /** 38 * Filter to check if the current user has permissions to approve strings, based 39 * on a role on the Rosetta site. 40 * 41 * @param string $verdict Verdict. 42 * @param array $args Array of arguments. 43 * @return bool True if user has permissions, false if not. 44 */ 45 public function pre_can_user( $verdict, $args ) { 46 if ( ! class_exists( 'BP_Roles' ) ) { 23 47 require_once( BACKPRESS_PATH . 'class.bp-roles.php' ); 24 if ( ! class_exists( 'BP_User' ) ) 48 } 49 if ( ! class_exists( 'BP_User' ) ) { 25 50 require_once( BACKPRESS_PATH . 'class.bp-user.php' ); 51 } 52 53 // Current user. 26 54 $user = new BP_User( $args['user_id'] ); 27 55 28 56 // 115 = global.wordpress.org. Administrators on this site are considered global admins in GlotPress. 29 if ( ! empty( $user->wporg_115_capabilities ) && is_array( $user->wporg_115_capabilities ) && ! empty( $user->wporg_115_capabilities['administrator'] ) ) 57 if ( ! empty( $user->wporg_115_capabilities ) && is_array( $user->wporg_115_capabilities ) && ! empty( $user->wporg_115_capabilities['administrator'] ) ) { 30 58 return true; 31 32 if ( $args['action'] !== 'approve' || ! in_array( $args['object_type'], array( 'project|locale|set-slug', 'translation-set' ) ) ) 33 return false; 34 35 if ( ! $locale_slug = $this->get_locale_slug( $args['object_type'], $args['object_id'] ) ) 36 return false; 37 38 if ( ! $maybe_cap_key = $this->get_cap_key( $locale_slug ) ) 39 return false; 40 41 $user->cap_key = $maybe_cap_key; 59 } 60 61 if ( $args['action'] !== 'approve' || ! in_array( $args['object_type'], array( 'project|locale|set-slug', 'translation-set' ) ) ) { 62 return false; 63 } 64 65 // Get locale and current project ID. 66 $locale_and_project_id = (object) $this->get_locale_and_project_id( $args['object_type'], $args['object_id'] ); 67 if ( ! $locale_and_project_id ) { 68 return false; 69 } 70 71 $locale_slug = $locale_and_project_id->locale; 72 $current_project_id = $locale_and_project_id->project_id; 73 74 // Get blog prefix of the associated Rosetta site. 75 if ( ! $blog_prefix = $this->get_blog_prefix( $locale_slug ) ) { 76 return false; 77 } 78 79 // Check if current user has the approver role. 80 $user->cap_key = $blog_prefix . 'capabilities'; 42 81 $user->caps = &$user->{$user->cap_key}; 43 if ( ! is_array( $user->caps ) ) 82 if ( ! is_array( $user->caps ) ) { 44 83 $user->caps = array(); 84 } 45 85 $user->get_role_caps(); 46 foreach ( array( 'administrator', 'editor', 'author', 'contributor', 'validator' ) as $role ) { 47 if ( $user->has_cap( $role ) ) 48 return true; 49 } 86 if ( ! $user->has_cap( $this->approver_role ) ) { 87 return false; 88 } 89 90 // Get IDs of projects which the user can approve. 91 $meta_key = $blog_prefix . $this->project_access_meta_key; 92 if ( empty( $user->$meta_key ) || ! is_array( $user->$meta_key ) ) { 93 return false; 94 } 95 96 $project_access_list = $user->$meta_key; 97 98 // Short circuit the check if user can approve all projects. 99 if ( in_array( 'all', $project_access_list ) ) { 100 return true; 101 } 102 103 // If current project is a parent ID. 104 if ( in_array( $current_project_id, $project_access_list ) ) { 105 return true; 106 } 107 108 // An user is allowed to approve potential sub projects as well. 109 $projects = $this->get_all_projects(); // Flat array 110 $project_tree = $this->get_project_tree( $projects ); 111 $allowed_sub_project_ids = array(); 112 foreach ( $project_access_list as $project_id ) { 113 $sub_project_ids = $this->get_sub_project_ids( $project_id, $project_tree ); 114 if ( $sub_project_ids ) { 115 $allowed_sub_project_ids = array_merge( $allowed_sub_project_ids, $sub_project_ids ); 116 } 117 } 118 $allowed_sub_project_ids = array_unique( $allowed_sub_project_ids ); 119 120 if ( in_array( $current_project_id, $allowed_sub_project_ids ) ) { 121 return true; 122 } 123 50 124 return false; 51 125 } 52 126 53 function get_locale_slug( $object_type, $object_id ) { 127 /** 128 * Fetches all projects from database. 129 * 130 * @return array List of projects with ID and parent ID. 131 */ 132 public function get_all_projects() { 133 global $gpdb; 134 static $projects; 135 136 if ( isset( $projects ) ) { 137 return $projects; 138 } 139 140 $table = GP::$project->table; 141 142 $_projects = $gpdb->get_results( " 143 SELECT 144 id, parent_project_id 145 FROM $table 146 ORDER BY id 147 " ); 148 149 $projects = array(); 150 foreach ( $_projects as $project ) { 151 $projects[ $project->id ] = $project; 152 } 153 154 return $projects; 155 } 156 157 /** 158 * Transforms a flat array to a hierarchy tree. 159 * 160 * @param array $projects The projects 161 * @param int $parent_id Optional. Parent ID. Default 0. 162 * @param int $max_depth Optional. Max depth to avoid endless recursion. Default 5. 163 * @return array The project tree. 164 */ 165 public function get_project_tree( $projects, $parent_id = 0, $max_depth = 5 ) { 166 if ( $max_depth < 0 ) { // Avoid an endless recursion. 167 return; 168 } 169 170 $tree = array(); 171 foreach ( $projects as $project ) { 172 if ( $project->parent_project_id == $parent_id ) { 173 $sub_projects = $this->get_project_tree( $projects, $project->id, $max_depth - 1 ); 174 if ( $sub_projects ) { 175 $project->sub_projects = $sub_projects; 176 } 177 178 $tree[ $project->id ] = $project; 179 unset( $projects[ $project->id ] ); 180 } 181 } 182 return $tree; 183 } 184 185 /** 186 * Returns all sub project IDs of a parent ID. 187 * 188 * @param int $project_id Parent ID. 189 * @param array $projects Hierarchy tree of projects. 190 * @return array IDs of the sub projects. 191 */ 192 public function get_sub_project_ids( $project_id, $projects ) { 193 $project_branch = $this->get_project_branch( $project_id, $projects ); 194 $project_ids = self::array_keys_multi( $project_branch->sub_projects, 'sub_projects' ); 195 return $project_ids; 196 } 197 198 /** 199 * Returns a specifc branch of a hierarchy tree. 200 * 201 * @param int $project_id Project ID. 202 * @param array $projects Hierarchy tree of projects. 203 * @return mixed False if project ID doesn't exist, project branch on success. 204 */ 205 public function get_project_branch( $project_id, $projects ) { 206 if ( ! is_array( $projects ) ) { 207 return false; 208 } 209 210 foreach ( $projects as $project ) { 211 if ( $project->id == $project_id ) { 212 return $project; 213 } 214 215 $sub = $this->get_project_branch( $project_id, $project->sub_projects ); 216 if ( $sub ) { 217 return $sub; 218 } 219 } 220 221 return false; 222 } 223 224 /** 225 * Extracts project ID and locale slug from object type and ID. 226 * 227 * @param string $object_type Current object type. 228 * @param string $object_id Current object ID. 229 * @return array Locale and project ID. 230 */ 231 public function get_locale_and_project_id( $object_type, $object_id ) { 54 232 switch ( $object_type ) { 55 233 case 'translation-set' : 56 return GP::$translation_set->get( $object_id )->locale; 57 break; 234 $set = GP::$translation_set->get( $object_id ); 235 return array( 'locale' => $set->locale, 'project_id' => (int) $set->project_id ); 236 58 237 case 'project|locale|set-slug' : 59 list( , $locale ) = explode( '|', $object_id ); 60 return $locale; 61 break; 238 list( $project_id, $locale ) = explode( '|', $object_id ); 239 return array( 'locale' => $locale, 'project_id' => (int) $project_id ); 62 240 } 63 241 return false; 64 242 } 65 243 66 function get_cap_key( $locale_slug ) { 244 /** 245 * Returns the blog prefix of a locale. 246 * 247 * @param string $locale_slug Slug of GlotPress locale. 248 * @return bool|string Blog prefix on success, false on failure. 249 */ 250 public function get_blog_prefix( $locale_slug ) { 67 251 global $gpdb; 68 252 static $ros_blogs, $ros_locale_assoc; 69 253 70 254 $gp_locale = GP_Locales::by_slug( $locale_slug ); 71 if ( ! $gp_locale || ! isset( $gp_locale->wp_locale ) ) 72 return false; 255 if ( ! $gp_locale || ! isset( $gp_locale->wp_locale ) ) { 256 return false; 257 } 73 258 74 259 $wp_locale = $gp_locale->wp_locale; 75 260 76 261 if ( ! isset( $ros_blogs ) ) { 77 $ros_locale_assoc = $gpdb->get_results( "SELECT locale, subdomain FROM locales", OBJECT_K );262 $ros_locale_assoc = $gpdb->get_results( 'SELECT locale, subdomain FROM locales', OBJECT_K ); 78 263 // 6 = Rosetta sites 79 $ros_blogs = $gpdb->get_results( "SELECT domain, blog_id FROM wporg_blogs WHERE site_id = 6", OBJECT_K );80 } 81 82 if ( isset( $ros_locale_assoc[ $wp_locale ] ) ) 264 $ros_blogs = $gpdb->get_results( 'SELECT domain, blog_id FROM wporg_blogs WHERE site_id = 6', OBJECT_K ); 265 } 266 267 if ( isset( $ros_locale_assoc[ $wp_locale ] ) ) { 83 268 $subdomain = $ros_locale_assoc[ $wp_locale ]->subdomain; 84 else 85 return false; 86 87 if ( isset( $ros_blogs[ "$subdomain.wordpress.org" ] ) ) 88 return 'wporg_' . $ros_blogs[ "$subdomain.wordpress.org" ]->blog_id . '_capabilities'; 269 } else { 270 return false; 271 } 272 273 if ( isset( $ros_blogs[ "$subdomain.wordpress.org" ] ) ) { 274 return 'wporg_' . $ros_blogs[ "$subdomain.wordpress.org" ]->blog_id . '_'; 275 } 89 276 90 277 return false; 91 278 } 279 280 /** 281 * Returns all keys of a multidimensional array. 282 * 283 * @param array $array Multidimensional array to extract keys from. 284 * @param string $childs_key Optional. Key of the child elements. Default 'childs'. 285 * @return array Array keys. 286 */ 287 public static function array_keys_multi( $array, $childs_key = 'childs' ) { 288 $keys = array(); 289 290 foreach ( $array as $key => $value ) { 291 $keys[] = $key; 292 293 if ( is_array( $value->$childs_key ) ) { 294 $keys = array_merge( $keys, self::array_keys_multi( $value->$childs_key ) ); 295 } 296 } 297 298 return $keys; 299 } 92 300 } 301 93 302 GP::$plugins->wporg_rosetta_roles = new GP_WPorg_Rosetta_Roles;
Note: See TracChangeset
for help on using the changeset viewer.