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