Making WordPress.org


Ignore:
Timestamp:
08/19/2015 04:32:23 AM (11 years ago)
Author:
dd32
Message:

Translate: Introduce the backend for multiple project sorting options, this still lacks a UI to switch between these sort priorities.
The default sort priority of untranslated favourites, followed by untranslated items, followed by fully translated items applies now.
The Waiting tab will be visible for Translation Editors shortly.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/translate.wordpress.org/includes/gp-plugins/wporg-routes/routes/locale.php

    r1780 r1835  
    1414         * @param string $project_path     Path of a project.
    1515         */
    16         public function get_locale_projects( $locale_slug, $set_slug = 'default', $project_path = 'wp' ) {
     16        public function get_locale_projects( $locale_slug, $set_slug = 'default', $project_path = 'waiting' ) {
    1717                global $gpdb;
    1818
     
    2020                $page = (int) gp_get( 'page', 1 );
    2121                $search = gp_get( 's', '' );
     22                $filter = gp_get( 'filter', 'default' );
    2223
    2324                $locale = GP_Locales::by_slug( $locale_slug );
     
    2627                }
    2728
     29                // Grab the top level projects to show in the menu first, so as to be able to handle the default Waiting / WP tab selection
     30                $top_level_projects = $this->get_active_top_level_projects();
     31                usort( $top_level_projects, array( $this, '_sort_reverse_name_callback' ) );
     32
     33                // Filter out the Waiting Tab if the current user cannot validate strings
     34                $user = GP::$user->current();
     35                if (
     36                        ! $user->id || // Not logged in
     37                        ! isset( GP::$plugins->wporg_rosetta_roles ) || // Rosetta Roles plugin is not enabled
     38                        ! (
     39                                GP::$plugins->wporg_rosetta_roles->is_global_administrator( $user->id ) || // Not a global admin
     40                                GP::$plugins->wporg_rosetta_roles->is_approver_for_locale( $user->id, $locale_slug ) // Doesn't have project-level access either
     41                        ) ) { // Add check to see if there are any waiting translations for this locale?
     42                        foreach ( $top_level_projects as $i => $project ) {
     43                                if ( 'waiting' == $project->slug ) {
     44                                        unset( $top_level_projects[ $i ] );
     45                                        break;
     46                                }
     47                        }
     48
     49                        // Reset to default path of wp if the Waiting tab shouldn't be shown for this user.
     50                        $project_path = 'wp';
     51                }
     52
    2853                $project = GP::$project->by_path( $project_path );
    2954                if ( ! $project ) {
    3055                        return $this->die_with_404();
    3156                }
     57
    3258
    3359                $paged_sub_projects = $this->get_paged_active_sub_projects(
     
    3662                                'page' => $page,
    3763                                'per_page' => $per_page,
    38                                 'orderby' => 'name',
    3964                                'search' => $search,
     65                                'filter' => $filter,
    4066                                'set_slug' => $set_slug,
    4167                                'locale' => $locale_slug,
     
    4773                }
    4874
    49                 $sub_projects   = $paged_sub_projects['projects'];
    50                 $pages          = $paged_sub_projects['pages'];
     75                $sub_projects = $paged_sub_projects['projects'];
     76                $pages        = $paged_sub_projects['pages'];
    5177                unset( $paged_sub_projects );
    5278
     
    6995                }
    7096
    71                 $top_level_projects = $this->get_active_top_level_projects();
    72                 usort( $top_level_projects, array( $this, '_sort_reverse_name_callback' ) );
    73 
    7497                $variants = $this->get_locale_variants( $locale_slug, $project_ids );
    7598                // If there were no results for the current variant in the current project branch, it should still show it.
     
    141164         */
    142165        private function get_project_icon( $project, $sub_project, $size = 128 ) {
     166
     167                // The Waiting tab will have $sub_project's which are not sub-projects of $project
     168                if ( $sub_project->parent_project_id !== $project->id ) {
     169                        $project = GP::$project->get( $sub_project->parent_project_id );
     170                        // In the case of Plugins, we may need to go up another level yet
     171                        if ( $project->parent_project_id ) {
     172                                $sub_project = $project;
     173                                $project = GP::$project->get( $sub_project->parent_project_id );
     174                        }
     175                }
     176
    143177                switch( $project->slug ) {
    144178                        case 'wp':
     
    201235                $project_ids = implode( ',', $project_ids );
    202236                $slugs = $gpdb->get_col( $gpdb->prepare( "
    203                         SELECT DISTINCT(slug), name
     237                        SELECT DISTINCT slug
    204238                        FROM {$gpdb->translation_sets}
    205239                        WHERE
     
    337371                        'per_page' => 20,
    338372                        'page'     => 1,
    339                         'orderby'  => 'id',
    340                         'order'    => 'ASC',
    341373                        'search'   => false,
    342374                        'set_slug' => '',
    343375                        'locale'   => '',
     376                        'filter'     => 'default',
    344377                );
    345378                $r = wp_parse_args( $args, $defaults );
    346379                extract( $r, EXTR_SKIP );
    347380
    348                 $order = ( 'ASC' === $order ) ? 'ASC' : 'DESC';
    349                 $orderby = ( in_array( $orderby, array( 'id', 'name' ) ) ? $orderby : 'id' );
    350 
    351381                $limit_sql = '';
    352382                if ( $per_page ) {
    353383                        $limit_sql = $gpdb->prepare( 'LIMIT %d, %d', ( $page - 1 ) * $per_page, $per_page );
    354384                }
     385
     386                $parent_project_sql = $gpdb->prepare( 'AND tp.parent_project_id = %d', $project->id );
     387
    355388                $search_sql = '';
    356389                if ( $search ) {
    357390                        $esc_search = '%%' . like_escape( $search ) . '%%';
    358391                        $search_sql = $gpdb->prepare( 'AND ( tp.name LIKE %s OR tp.slug LIKE %s )', $esc_search, $esc_search );
     392                }
     393
     394                // Special Waiting Project Tab
     395                // This removes the parent_project_id restriction and replaces it with all-translation-editer-projects
     396                if ( 'waiting' == $project->slug && GP::$user->current()->id && isset( GP::$plugins->wporg_rosetta_roles ) ) {
     397
     398                        if ( 'default' === $filter ) {
     399                                $filter = 'strings-waiting';
     400                        }
     401
     402                        $user_id = GP::$user->current()->id;
     403
     404                        // Global Admin or Locale-specific admin
     405                        $can_approve_for_all = GP::$plugins->wporg_rosetta_roles->is_global_administrator( $user_id );
     406
     407                        // Check to see if they have any special approval permissions
     408                        $allowed_projects = array();
     409                        if ( ! $can_approve_for_all && GP::$plugins->wporg_rosetta_roles->is_approver_for_locale( $user_id, $locale ) ) {
     410                                $allowed_projects = GP::$plugins->wporg_rosetta_roles->get_project_id_access_list( $user_id, $locale, true );
     411
     412                                // Check to see if they can approve for all projects in this locale.
     413                                if ( in_array( 'all', $allowed_projects ) ) {
     414                                        $can_approve_for_all = true;
     415                                        $allowed_projects = array();
     416                                }
     417                        }
     418
     419                        $parent_project_sql = '';
     420                        if ( $can_approve_for_all ) {
     421                                // The current user can approve for all projects, so just grab all with any waiting strings.
     422                                $parent_project_sql = 'AND stats.waiting > 0';
     423
     424                        } elseif ( $allowed_projects ) {
     425                                // The current user can approve for a small set of projects.
     426                                // We only need to check against tp.id and not tp_sub.id in this case as we've overriding the parent_project_id check
     427                                $ids = implode( ', ', array_map( 'intval', $allowed_projects ) );
     428                                $parent_project_sql = "AND tp_sub.id IN( $ids ) AND stats.waiting > 0";
     429
     430                        } else {
     431                                // The current user can't approve for any locale projects, or is logged out.
     432                                $parent_project_sql = 'AND 0=1';
     433
     434                        }
     435
     436                }
     437
     438                $filter_order_by = $filter_where = '';
     439                switch ( $filter ) {
     440                        default:
     441                        case 'default':
     442                                // Float favorites to the start, but only if they have untranslated strings
     443                                $user_fav_projects = array_map( array( $gpdb, 'escape' ), $this->get_user_favorites( $project->slug ) );
     444
     445                                // Float Favorites to the start, float fully translated to the bottom, order the rest by name
     446                                if ( $user_fav_projects ) {
     447                                        $filter_order_by = 'FIELD( tp.path, "' . implode( '", "', $user_fav_projects ) . '" ) > 0 AND stats.untranslated > 0 DESC, stats.untranslated > 0 DESC, tp.name ASC';
     448                                } else {
     449                                        $filter_order_by = 'stats.untranslated > 0 DESC, tp.name ASC';
     450                                }
     451                                break;
     452
     453                        case 'favorites':
     454                                // Only list favorites
     455                                $user_fav_projects = array_map( array( $gpdb, 'escape' ), $this->get_user_favorites( $project->slug ) );
     456
     457                                if ( $user_fav_projects ) {
     458                                        $filter_where = 'AND tp.path IN( "' . implode( '", "', $user_fav_projects ) . '" )';
     459                                } else {
     460                                        $filter_where = 'AND 0=1';
     461                                }
     462                                $filter_order_by = 'stats.untranslated > 0 DESC, tp.name ASC';
     463
     464                                break;
     465
     466                        case 'strings-remaining':
     467                                $filter_where = 'AND stats.untranslated > 0';
     468                                $filter_order_by = 'stats.untranslated DESC, tp.name ASC';
     469                                break;
     470
     471                        case 'strings-waiting':
     472                                $filter_where = 'AND stats.waiting > 0';
     473                                $filter_order_by = 'stats.waiting DESC, tp.name ASC';
     474                                break;
     475
     476                        case 'strings-fuzzy-and-warnings':
     477                                $filter_where = 'AND ( stats.fuzzy > 0 OR stats.warnings > 0 )';
     478                                $filter_order_by = '(stats.fuzzy+stats.warnings) DESC, tp.name ASC';
     479                                break;
     480
     481                        case 'percent-completed':
     482                                $filter_where = 'AND stats.untranslated > 0';
     483                                $filter_order_by = ' ( stats.current / stats.all ) DESC, tp.name ASC';
     484                                break;
    359485                }
    360486
     
    374500                                LEFT JOIN {$gpdb->translation_sets} sets ON sets.project_id = tp.id AND sets.locale = %s AND sets.slug = %s
    375501                                LEFT JOIN {$gpdb->translation_sets} sets_sub ON sets_sub.project_id = tp_sub.id AND sets_sub.locale = %s AND sets_sub.slug = %s
     502                                LEFT JOIN {$gpdb->project_translation_status} stats ON stats.project_id = tp.id AND stats.translation_set_id = sets.id
    376503                        WHERE
    377                                 tp.parent_project_id = %d
    378                                 AND tp.active = 1
     504                                tp.active = 1
    379505                                AND ( sets.id IS NOT NULL OR sets_sub.id IS NOT NULL )
     506                                $parent_project_sql
    380507                                $search_sql
     508                                $filter_where
    381509                        GROUP BY tp.id
    382                         ORDER BY tp.$orderby $order
     510                        ORDER BY $filter_order_by
    383511                        $limit_sql
    384                 ", $locale, $set_slug, $locale, $set_slug, $project->id );
     512                ", $locale, $set_slug, $locale, $set_slug );
    385513
    386514                $results = (int) $project->found_rows();
     
    396524                        'projects' => $projects,
    397525                );
     526        }
     527
     528        /**
     529         * Retrieves a list of projects which the current user has favorited.
     530         *
     531         * @return array List of favorited items, eg [ 'wp-themes/twentyten', 'wp-themes/twentyeleven' ]
     532         */
     533        function get_user_favorites( $project_slug = false ) {
     534                global $gpdb;
     535                $user = GP::$user->current();
     536
     537                if ( ! $user->id ) {
     538                        return array();
     539                }
     540
     541                switch ( $project_slug ) {
     542                        default:
     543                                // Fall through to include both Themes and Plugins
     544                        case 'wp-themes':
     545                                // Theme favorites are stored as theme slugs, these map 1:1 to GlotPress projects
     546                                $theme_favorites = array_map( function( $slug ) {
     547                                        return "wp-themes/$slug";
     548                                }, (array) $user->get_meta( 'theme_favorites' ) );
     549
     550                                if ( 'wp-themes' === $project_slug ) {
     551                                        return $theme_favorites;
     552                                }
     553
     554                        case 'wp-plugins':
     555                                // Plugin favorites are stored as topic ID's
     556                                $plugin_fav_ids = array_keys( (array)$user->get_meta( PLUGINS_TABLE_PREFIX . 'plugin_favorite' ) );
     557                                $plugin_fav_slugs = array();
     558                                if ( $plugin_fav_ids ) {
     559                                        $plugin_fav_ids = implode( ',', array_map( 'intval', $plugin_fav_ids ) );
     560                                        $plugin_fav_slugs = $gpdb->get_col( "SELECT topic_slug FROM " . PLUGINS_TABLE_PREFIX . "topics WHERE topic_id IN( $plugin_fav_ids )" );
     561                                }
     562
     563                                $plugin_favorites = array_map( function( $slug ) {
     564                                        return "wp-plugins/$slug";
     565                                }, $plugin_fav_slugs );
     566
     567                                if ( 'wp-plugins' === $project_slug ) {
     568                                        return $plugin_favorites;
     569                                }
     570                }
     571
     572                // Return all favorites, for uses in things like the Waiting tab
     573                return array_merge( $theme_favorites, $plugin_favorites );
    398574        }
    399575
     
    417593
    418594        private function _sort_reverse_name_callback( $a, $b ) {
     595                // The Waiting project should always be first.
     596                if ( $a->slug == 'waiting' ) {
     597                        return -1;
     598                }
    419599                return - strcasecmp( $a->name, $b->name );
    420600        }
Note: See TracChangeset for help on using the changeset viewer.