diff --git a/.wp-env.json b/.wp-env.json new file mode 100644 index 0000000..9ddbbd1 --- /dev/null +++ b/.wp-env.json @@ -0,0 +1,12 @@ +{ + "core": "https://wordpress.org/wordpress-6.7.2.zip", + "plugins": [ + ".", + "C:/Users/acalog/bu/bu-slideshow", + "C:/Users/acalog/bu/wordpress/plugins/bu-navigation", + "C:/Users/acalog/bu/wordpress/plugins/plugin-check" + ], + "config": { + "WP_DEBUG": true + } + } \ No newline at end of file diff --git a/README.md b/README.md index e1ddf92..18936b9 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # BU Section Editing # **Contributors:** mgburns, gcorne, awbauer, inderpreet99, anton-kachurin **Tags:** permissions, section, access, acl, user management, custom roles, content editing, workflow, boston university, bu -**Requires at least:** 3.1 -**Tested up to:** 4.5.3 -**Stable tag:** 0.10.0 +**Requires at least:** 3.1 +**Tested up to:** 6.7.2 +**Stable tag:** 0.10.1 **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html @@ -82,6 +82,10 @@ For more information on creating roles for use with section editing groups, see ## Changelog +### 0.10.0 +* Conform to WP Coding Standards +* Tested for 6.7.2 compatibility + ### 0.9.9 * Allow to add/edit posts of custom types diff --git a/admin.groups.php b/admin.groups.php index 4f7911a..152c93b 100644 --- a/admin.groups.php +++ b/admin.groups.php @@ -59,7 +59,7 @@ public static function register_hooks() { */ public static function add_manage_users_column( $columns ) { - $columns[ self::MANAGE_USERS_COLUMN ] = __( 'Section Groups', BUSE_TEXTDOMAIN ); + $columns[ self::MANAGE_USERS_COLUMN ] = __( 'Section Groups', 'bu-section-editing' ); return $columns; } @@ -77,7 +77,7 @@ public static function manage_users_group_column( $content, $column, $user_id ) if ( empty( $groups ) ) { - $content = __( 'None', BUSE_TEXTDOMAIN ); + $content = __( 'None', 'bu-section-editing' ); } else { @@ -106,10 +106,10 @@ public static function manage_users_group_column( $content, $column, $user_id ) if ( $truncated_count > 0 ) { $content .= sprintf( ' %s %s %s', - __( 'and', BUSE_TEXTDOMAIN ), + __( 'and', 'bu-section-editing' ), admin_url( self::MANAGE_GROUPS_PAGE ), $truncated_count, - _n( 'other', 'others', $truncated_count, BUSE_TEXTDOMAIN ) + _n( 'other', 'others', $truncated_count, 'bu-section-editing' ) ); } } @@ -227,8 +227,9 @@ public static function add_edit_views() { // Most of these options don't do anything at this time, but we should keep an eye // on the ticket mentioned above as this could change in future releases $args = array( - 'label' => __( 'Editable', BUSE_TEXTDOMAIN ), - 'label_count' => _n_noop( 'Editable (%s)', 'Editable (%s)' ), + 'label' => __( 'Editable', 'bu-section-editing' ), + // translators: %s stands for number of labels. + 'label_count' => _n_noop( 'Editable (%s)', 'Editable (%s)', 'bu-section-editing' ), 'public' => true, 'show_in_admin_all' => true, 'publicly_queryable' => true, @@ -288,7 +289,7 @@ public static function add_editable_view( $views ) { $count = $groups->get_allowed_post_count( $args ); - $views[ self::EDITABLE_POST_STATUS ] = "" . __( 'Editable', BUSE_TEXTDOMAIN ) . " ($count)"; + $views[ self::EDITABLE_POST_STATUS ] = "" . __( 'Editable', 'bu-section-editing' ) . " ($count)"; return $views; @@ -409,8 +410,8 @@ public static function admin_scripts( $hook ) { 'showStatuses' => false, 'suppressUrls' => true, 'rpcUrl' => admin_url( 'admin-ajax.php?action=buse_render_post_list' ), - 'allowLabel' => __( 'Allow', BUSE_TEXTDOMAIN ), - 'denyLabel' => __( 'Deny', BUSE_TEXTDOMAIN ), + 'allowLabel' => __( 'Allow', 'bu-section-editing' ), + 'denyLabel' => __( 'Deny', 'bu-section-editing' ), ); // Let the tree view class handle enqueing @@ -426,9 +427,9 @@ public static function admin_scripts( $hook ) { // Enforce section editor restrictions for inline/bulk edit actions if ( 'edit.php' == $hook ) { $strings = array( - 'cantEditParentNotice' => __( 'You are not able to edit the parent.', BUSE_TEXTDOMAIN ), - 'cantMovePostNotice' => __( 'You are not able to edit the parent, so you cannot place this page under the parent.', BUSE_TEXTDOMAIN ), - 'publishLabel' => __( 'Published', BUSE_TEXTDOMAIN ), + 'cantEditParentNotice' => __( 'You are not able to edit the parent.', 'bu-section-editing' ), + 'cantMovePostNotice' => __( 'You are not able to edit the parent, so you cannot place this page under the parent.', 'bu-section-editing' ), + 'publishLabel' => __( 'Published', 'bu-section-editing' ), ); wp_enqueue_script( 'bu-section-editor-post', plugins_url( '/js/section-editor-post' . $suffix . '.js', __FILE__ ), array( 'jquery' ), $version, true ); wp_localize_script( 'bu-section-editor-post', 'buse_post', $strings ); @@ -441,39 +442,43 @@ public static function admin_scripts( $hook ) { */ public static function group_editor_i10n() { - $users_link = sprintf( '%s', admin_url( 'users.php' ), __( 'users page', BUSE_TEXTDOMAIN ) ); - $add_user_link = sprintf( '%s', admin_url( 'user-new.php' ), __( 'add them to your site', BUSE_TEXTDOMAIN ) ); - $nav_plugin_link = sprintf( '%s', BUSE_NAV_INSTALL_LINK, __( 'BU Navigation plugin', BUSE_TEXTDOMAIN ) ); + $users_link = sprintf( '%s', admin_url( 'users.php' ), __( 'users page', 'bu-section-editing' ) ); + $add_user_link = sprintf( '%s', admin_url( 'user-new.php' ), __( 'add them to your site', 'bu-section-editing' ) ); + $nav_plugin_link = sprintf( '%s', BUSE_NAV_INSTALL_LINK, __( 'BU Navigation plugin', 'bu-section-editing' ) ); return array( - 'bulkEditOpenText' => __( 'Bulk Edit', BUSE_TEXTDOMAIN ), - 'bulkEditCloseText' => __( 'Close Bulk Edit', BUSE_TEXTDOMAIN ), - 'bulkEditOpenTitle' => __( 'Enable bulk edit mode', BUSE_TEXTDOMAIN ), - 'bulkEditCloseTitle' => __( 'Disable bulk edit mode', BUSE_TEXTDOMAIN ), - 'confirmActionNotice' => __( 'Are you sure you want to do this?', BUSE_TEXTDOMAIN ), - 'deleteGroupNotice' => __( 'You are about to permanently delete this section editing group. This action is irreversible.', BUSE_TEXTDOMAIN ), - 'dirtyLeaverNotice' => __( 'Your group has pending edits. If you leave now, your changes will be lost.', BUSE_TEXTDOMAIN ), - 'loadingText' => __( 'Loading...', BUSE_TEXTDOMAIN ), - 'memberCountSingularLabel' => __( 'member', BUSE_TEXTDOMAIN ), - 'memberCountPluralLabel' => __( 'members', BUSE_TEXTDOMAIN ), - 'nameRequiredNotice' => __( 'Section editing groups require a name.', BUSE_TEXTDOMAIN ), + 'bulkEditOpenText' => __( 'Bulk Edit', 'bu-section-editing' ), + 'bulkEditCloseText' => __( 'Close Bulk Edit', 'bu-section-editing' ), + 'bulkEditOpenTitle' => __( 'Enable bulk edit mode', 'bu-section-editing' ), + 'bulkEditCloseTitle' => __( 'Disable bulk edit mode', 'bu-section-editing' ), + 'confirmActionNotice' => __( 'Are you sure you want to do this?', 'bu-section-editing' ), + 'deleteGroupNotice' => __( 'You are about to permanently delete this section editing group. This action is irreversible.', 'bu-section-editing' ), + 'dirtyLeaverNotice' => __( 'Your group has pending edits. If you leave now, your changes will be lost.', 'bu-section-editing' ), + 'loadingText' => __( 'Loading...', 'bu-section-editing' ), + 'memberCountSingularLabel' => __( 'member', 'bu-section-editing' ), + 'memberCountPluralLabel' => __( 'members', 'bu-section-editing' ), + 'nameRequiredNotice' => __( 'Section editing groups require a name.', 'bu-section-editing' ), 'navDepAlertText' => sprintf( - __( "In order to set permissions for hierarchical post types, the BU Navigation plugin must be activated.\n\nPlease install BU Navigation:\n%s", BUSE_TEXTDOMAIN ), + // translators: %s stands for the BU Navigation install link. + __( "In order to set permissions for hierarchical post types, the BU Navigation plugin must be activated.\n\nPlease install BU Navigation:\n%s", 'bu-section-editing' ), BUSE_NAV_INSTALL_LINK ), 'navDepEditorText' => sprintf( - __( 'Please install the %s in order to set permissions for this post type.', BUSE_TEXTDOMAIN ), + // translators: %s stands for an html anchor tag to the BU Navigation install link. + __( 'Please install the %s in order to set permissions for this post type.', 'bu-section-editing' ), $nav_plugin_link ), - 'permAllowLabel' => __( 'Allow', BUSE_TEXTDOMAIN ), - 'permDenyLabel' => __( 'Deny', BUSE_TEXTDOMAIN ), - 'permEditableLabel' => __( 'editable', BUSE_TEXTDOMAIN ), - 'permNonEditableLabel' => __( 'non-editable', BUSE_TEXTDOMAIN ), - 'permGlobalLabel' => __( 'All', BUSE_TEXTDOMAIN ), + 'permAllowLabel' => __( 'Allow', 'bu-section-editing' ), + 'permDenyLabel' => __( 'Deny', 'bu-section-editing' ), + 'permEditableLabel' => __( 'editable', 'bu-section-editing' ), + 'permNonEditableLabel' => __( 'non-editable', 'bu-section-editing' ), + 'permGlobalLabel' => __( 'All', 'bu-section-editing' ), 'userWrongRoleNotice' => sprintf( - __( 'is not a section editor. Before you can assign them to a group, you must change their role to "Section Editor" on the %s.', BUSE_TEXTDOMAIN ), + // translators: %s stands for a link to the users page. + __( 'is not a section editor. Before you can assign them to a group, you must change their role to "Section Editor" on the %s.', 'bu-section-editing' ), $users_link ), - 'userAlreadyMemberNotice' => __( 'is already a member of this group.', BUSE_TEXTDOMAIN ), + 'userAlreadyMemberNotice' => __( 'is already a member of this group.', 'bu-section-editing' ), 'userNotExistsNotice' => sprintf( - __( 'is not a member of this site. Please %s with the "Section Editor" role.', BUSE_TEXTDOMAIN ), + // translators: %s stands for a link to the add users page. + __( 'is not a member of this site. Please %s with the "Section Editor" role.', 'bu-section-editing' ), $add_user_link ), ); } @@ -492,8 +497,8 @@ public static function admin_menus() { } $groups_manage = add_menu_page( - __( 'Section Groups', BUSE_TEXTDOMAIN ), - __( 'Section Groups', BUSE_TEXTDOMAIN ), + __( 'Section Groups', 'bu-section-editing' ), + __( 'Section Groups', 'bu-section-editing' ), 'promote_users', self::MANAGE_GROUPS_SLUG, array( 'BU_Groups_Admin', 'manage_groups_screen' ), @@ -503,8 +508,8 @@ public static function admin_menus() { add_submenu_page( self::MANAGE_GROUPS_SLUG, - __( 'Section Groups', BUSE_TEXTDOMAIN ), - __( 'All Groups', BUSE_TEXTDOMAIN ), + __( 'Section Groups', 'bu-section-editing' ), + __( 'All Groups', 'bu-section-editing' ), 'promote_users', self::MANAGE_GROUPS_SLUG, array( 'BU_Groups_Admin', 'manage_groups_screen' ) @@ -512,8 +517,8 @@ public static function admin_menus() { $groups_edit = add_submenu_page( self::MANAGE_GROUPS_SLUG, - __( 'Edit Section Group', BUSE_TEXTDOMAIN ), - __( 'Add New', BUSE_TEXTDOMAIN ), + __( 'Edit Section Group', 'bu-section-editing' ), + __( 'Add New', 'bu-section-editing' ), 'promote_users', self::NEW_GROUP_SLUG, array( 'BU_Groups_Admin', 'manage_groups_screen' ) @@ -542,14 +547,14 @@ public static function admin_notices() { // List errors first if ( isset( $notices['error'] ) ) { foreach ( $notices['error'] as $msg ) { - printf( '
%s
', $msg ); + printf( '
%s
', wp_kses_post( $msg ) ); } } // List notices second if ( isset( $notices['update'] ) ) { foreach ( $notices['update'] as $msg ) { - printf( '
%s
', $msg ); + printf( '
%s
', wp_kses_post( $msg ) ); } } @@ -570,24 +575,24 @@ static function get_notices() { if ( isset( $_GET['status'] ) ) { $groups_url = admin_url( self::MANAGE_GROUPS_PAGE ); - $view_txt = __( 'View all groups', BUSE_TEXTDOMAIN ); + $view_txt = __( 'View all groups', 'bu-section-editing' ); switch ( $_GET['status'] ) { case 1: - $notices['error'][] = '

' . __( 'There was an error saving the group.', BUSE_TEXTDOMAIN ) . '

'; + $notices['error'][] = '

' . __( 'There was an error saving the group.', 'bu-section-editing' ) . '

'; break; case 2: - $notices['update'][] = '

' . __( 'Group added.', BUSE_TEXTDOMAIN ) . " $view_txt

"; + $notices['update'][] = '

' . __( 'Group added.', 'bu-section-editing' ) . " $view_txt

"; break; case 3: - $notices['update'][] = '

' . __( 'Group updated.', BUSE_TEXTDOMAIN ) . " $view_txt

"; + $notices['update'][] = '

' . __( 'Group updated.', 'bu-section-editing' ) . " $view_txt

"; break; case 4: - $notices['update'][] = '

' . __( 'Group deleted.', BUSE_TEXTDOMAIN ) . '

'; + $notices['update'][] = '

' . __( 'Group deleted.', 'bu-section-editing' ) . '

'; break; default: @@ -601,9 +606,11 @@ static function get_notices() { if ( $valid_user_count == 0 ) { $manage_users_url = admin_url( 'users.php' ); - $users_link = sprintf( '%s', $manage_users_url, __( 'users page', BUSE_TEXTDOMAIN ) ); - $no_users_warning = __( 'There are currently no users on your site that are capable of being assigned to section editing groups.', BUSE_TEXTDOMAIN ); - $role_notice = sprintf( __( 'To start using this plugin, visit the %s and change the role for any users you would like to add to a section editing group to "Section Editor".', BUSE_TEXTDOMAIN ), $users_link ); + // translators: %s stands for the manage users url. + $users_link = sprintf( '%s', $manage_users_url, __( 'users page', 'bu-section-editing' ) ); + $no_users_warning = __( 'There are currently no users on your site that are capable of being assigned to section editing groups.', 'bu-section-editing' ); + // translators: %s stands for the manage users url. + $role_notice = sprintf( __( 'To start using this plugin, visit the %s and change the role for any users you would like to add to a section editing group to "Section Editor".', 'bu-section-editing' ), $users_link ); $notices['error'][] = "

$no_users_warning

$role_notice

"; } @@ -693,10 +700,7 @@ static function load_manage_groups() { // Redirect if we have one if ( $redirect_url ) { - - // Use safe redirect as the redirect URL built with manage_groups_url() begins - // with admin_url and the final URL should be local. - wp_safe_redirect( $redirect_url ); + wp_redirect( $redirect_url ); die(); } @@ -706,7 +710,7 @@ static function load_manage_groups() { $group = $groups->get( $group_id ); if ( empty( $group ) ) { - wp_die( 'No section editing group exists with an ID of : ' . $group_id ); + wp_die( 'No section editing group exists with an ID of : ' . esc_html( $group_id ) ); } } @@ -717,7 +721,7 @@ static function load_manage_groups() { if ( self::NEW_GROUP_SLUG == $_GET['page'] || $group_id > 0 ) { add_screen_option( 'per_page', array( - 'label' => __( 'Posts per page', BUSE_TEXTDOMAIN ), + 'label' => __( 'Posts per page', 'bu-section-editing' ), 'default' => 10, 'option' => self::POSTS_PER_PAGE_OPTION, ) @@ -796,7 +800,7 @@ static function manage_groups_screen() { if ( $group_id > 0 ) { $group = $groups->get( $group_id ); - $page_title = __( 'Edit Section Group', BUSE_TEXTDOMAIN ); + $page_title = __( 'Edit Section Group', 'bu-section-editing' ); $template_path = 'interface/edit-group.php'; } else { @@ -810,7 +814,7 @@ static function manage_groups_screen() { // New group page case self::NEW_GROUP_SLUG: $group = new BU_Edit_Group(); - $page_title = __( 'Add Section Group', BUSE_TEXTDOMAIN ); + $page_title = __( 'Add Section Group', 'bu-section-editing' ); $template_path = 'interface/edit-group.php'; break; } @@ -917,7 +921,7 @@ static function group_permissions_string( $group, $args = array() ) { $counts[] = sprintf( '%s%s %s', $pt->name, $global_edit, - __('All', BUSE_TEXTDOMAIN), + __('All', 'bu-section-editing'), $count, $label ); diff --git a/bu-section-editing.php b/bu-section-editing.php index d883df7..4da4d2c 100644 --- a/bu-section-editing.php +++ b/bu-section-editing.php @@ -8,6 +8,8 @@ Version: 0.10.0 Text Domain: bu-section-editing Domain Path: /languages +License: GPLv2 or later +License URI: http://www.gnu.org/licenses/gpl-2.0.html */ /** @@ -73,7 +75,7 @@ public static function register_hooks() { public static function l10n() { - load_plugin_textdomain( BUSE_TEXTDOMAIN, false, plugin_basename( dirname( __FILE__ ) ) . '/languages/' ); + load_plugin_textdomain( 'bu-section-editing', false, plugin_basename( dirname( __FILE__ ) ) . '/languages/' ); } @@ -112,17 +114,19 @@ public static function on_activate() { $msg = ''; if ( ! class_exists( 'BU_Navigation_Plugin' ) ) { - $install_link = sprintf( '%s', BUSE_NAV_INSTALL_LINK, __( 'BU Navigation plugin', BUSE_TEXTDOMAIN ) ); - $msg = '

' . __( 'The BU Section Editing plugin relies on the BU Navigation plugin for displaying hierarchical permission editors.', BUSE_TEXTDOMAIN ) . '

'; + $install_link = sprintf( '%s', BUSE_NAV_INSTALL_LINK, __( 'BU Navigation plugin', 'bu-section-editing' ) ); + $msg = '

' . __( 'The BU Section Editing plugin relies on the BU Navigation plugin for displaying hierarchical permission editors.', 'bu-section-editing' ) . '

'; $msg .= '

' . sprintf( - __( 'Please install and activate the %s in order to set permissions for hierarchical post types.', BUSE_TEXTDOMAIN ), + // translators: %s stands for the BU Navigation install link. + __( 'Please install and activate the %s in order to set permissions for hierarchical post types.', 'bu-section-editing' ), $install_link ) . '

'; } else if ( version_compare( BU_Navigation_Plugin::VERSION, '1.1', '<' ) ) { - $upgrade_link = sprintf( '%s', BUSE_NAV_UPGRADE_LINK, __( 'upgrade your copy of BU Navigation', BUSE_TEXTDOMAIN ) ); - $msg = '

' . __( 'The BU Section Editing plugin relies on the BU Navigation plugin for displaying hierarchical permission editors.', BUSE_TEXTDOMAIN ) . '

'; - $msg .= '

' . __( 'This version of BU Section Editing requires at least version 1.1 of BU Navigation.', BUSE_TEXTDOMAIN ) . '

'; + $upgrade_link = sprintf( '%s', BUSE_NAV_UPGRADE_LINK, __( 'upgrade your copy of BU Navigation', 'bu-section-editing' ) ); + $msg = '

' . __( 'The BU Section Editing plugin relies on the BU Navigation plugin for displaying hierarchical permission editors.', 'bu-section-editing' ) . '

'; + $msg .= '

' . __( 'This version of BU Section Editing requires at least version 1.1 of BU Navigation.', 'bu-section-editing' ) . '

'; $msg .= '

' . sprintf( - __( 'Please %s to enable permissions for hierarchical post types.', BUSE_TEXTDOMAIN ), + // translators: %s stands for the BU Navigation upgrade link. + __( 'Please %s to enable permissions for hierarchical post types.', 'bu-section-editing' ), $upgrade_link ) . '

'; } @@ -149,7 +153,7 @@ public static function plugin_dependency_nag() { $notice = get_transient( 'buse_nav_dep_nag' ); if ( $notice ) { - echo "
$notice
\n"; + echo esc_html("
$notice
\n", 'bu-section-editing'); delete_transient( 'buse_nav_dep_nag' ); } @@ -173,7 +177,7 @@ public static function plugin_settings_link( $links, $file ) { } $groups_url = admin_url( BU_Groups_Admin::MANAGE_GROUPS_PAGE ); - array_unshift( $links, "" . __( 'Manage Groups', BUSE_TEXTDOMAIN ) . '' ); + array_unshift( $links, "" . __( 'Manage Groups', 'bu-section-editing' ) . '' ); return $links; } diff --git a/classes.groups.php b/classes.groups.php index bf3a545..ccd3fea 100644 --- a/classes.groups.php +++ b/classes.groups.php @@ -51,8 +51,8 @@ static public function register_hooks() { static public function register_post_type() { $labels = array( - 'name' => _x( 'Section Groups', 'Post Type General Name', BUSE_TEXTDOMAIN ), - 'singular_name' => _x( 'Section Group', 'Post Type Singular Name', BUSE_TEXTDOMAIN ), + 'name' => _x( 'Section Groups', 'Post Type General Name', 'bu-section-editing' ), + 'singular_name' => _x( 'Section Group', 'Post Type Singular Name', 'bu-section-editing' ), ); $args = array( @@ -68,7 +68,7 @@ static public function register_post_type() { 'menu_icon' => '', 'can_export' => true, 'has_archive' => false, - 'exclude_from_search' => true, + 'exclude_from_search' => false, 'publicly_queryable' => false, 'rewrite' => false, 'capability_type' => 'post', @@ -309,105 +309,111 @@ public function has_user( $groups, $user_id ) { * * @return array post ids for the given post type, group or user */ - public function get_allowed_posts( $args = array() ) { - global $wpdb, $bu_navigation_plugin; - - $defaults = array( - 'user_id' => null, - 'group' => null, - 'post_type' => null, - 'include_unpublished' => false, - 'include_links' => true, - ); + /** + * Get allowed post ids, optionally filtered by user ID, group or post_type + * + * @param $args array optional args + * @return array post ids for the given post type, group or user + */ + public function get_allowed_posts( $args = array() ) { + global $wpdb, $bu_navigation_plugin; - extract( wp_parse_args( $args, $defaults ) ); + $defaults = array( + 'user_id' => null, + 'group' => null, + 'post_type' => null, + 'include_unpublished' => false, + 'include_links' => true, + ); - $group_ids = array(); + extract( wp_parse_args( $args, $defaults ) ); - // If user_id is passed, populate group ID's from their memberships - if ( $user_id ) { + $group_ids = array(); - if ( is_null( get_userdata( $user_id ) ) ) { - error_log( 'No user found for ID: ' . $user_id ); - return array(); - } + // If user_id is passed, populate group ID's from their memberships + if ( $user_id ) { - // Get groups for users - $group_ids = $this->find_groups_for_user( $user_id, 'ids' ); + if ( is_null( get_userdata( $user_id ) ) ) { + error_log( 'No user found for ID: ' . $user_id ); + return array(); + } - } + // Get groups for users + $group_ids = $this->find_groups_for_user( $user_id, 'ids' ); - // If no user ID is passed, but a group is, convert to array - if ( is_null( $user_id ) && $group ) { + } - if ( is_array( $group ) ) { - $group_ids = $group; - } + // If no user ID is passed, but a group is, convert to array + if ( is_null( $user_id ) && $group ) { - if ( is_numeric( $group ) && $group > 0 ) { - $group_ids = array( $group ); - } - } + if ( is_array( $group ) ) { + $group_ids = $group; + } - // Bail if we don't have any valid groups by now - if ( empty( $group_ids ) ) { - return array(); - } + if ( is_numeric( $group ) && $group > 0 ) { + $group_ids = array( $group ); + } + } - // Generate query - $post_type_clause = $post_status_clause = ''; + // Bail if we don't have any valid groups by now + if ( empty( $group_ids ) ) { + return array(); + } - // Maybe filter by post type and status - if ( ! is_null( $post_type ) && ! is_null( $pto = get_post_type_object( $post_type ) ) ) { + // Generate query + $post_type_clause = $post_status_clause = ''; - // Only a single post type is expected, so it should be prepared as a string. - $post_type_clause = $wpdb->prepare( "AND post_type = %s", $post_type ); + // Maybe filter by post type and status + if ( ! is_null( $post_type ) && ! is_null( $pto = get_post_type_object( $post_type ) ) ) { - if ( $include_links && $post_type == 'page' && isset( $bu_navigation_plugin ) ) { - if ( $bu_navigation_plugin->supports( 'links' ) ) { - $link_post_type = defined( 'BU_NAVIGATION_LINK_POST_TYPE' ) ? BU_NAVIGATION_LINK_POST_TYPE : 'bu_link'; + $post_type_clause = "AND post_type = '" . esc_sql( $post_type ) . "' "; - // Only a single post type string is passed, so it can be prepared as normal. - $post_type_clause = $wpdb->prepare( "AND post_type IN ('page', %s) ", $link_post_type ); - } - } - } + if ( $include_links && $post_type == 'page' && isset( $bu_navigation_plugin ) ) { + if ( $bu_navigation_plugin->supports( 'links' ) ) { + $link_post_type = defined( 'BU_NAVIGATION_LINK_POST_TYPE' ) ? BU_NAVIGATION_LINK_POST_TYPE : 'bu_link'; + $post_type_clause = "AND post_type IN ('page','" . esc_sql( $link_post_type ) . "') "; + } + } + } - // Include unpublished should only work for hierarchical post types - if ( $include_unpublished ) { + // Include unpublished should only work for hierarchical post types + if ( $include_unpublished ) { - // Flat post types are not allowed to include unpublished, as perms can be set for drafts - if ( $post_type ) { + // Flat post types are not allowed to include unpublished, as perms can be set for drafts + if ( $post_type ) { - $pto = get_post_type_object( $post_type ); + $pto = get_post_type_object( $post_type ); - if ( $pto->hierarchical ) { + if ( $pto->hierarchical ) { - // The `$post_type_clause` statement is prepared above and can be considered safe here. - $post_status_clause = "OR (post_status IN ('draft','pending') $post_type_clause)"; + $post_status_clause = "OR (post_status IN ('draft','pending') $post_type_clause)"; - } - } else { + } + } else { - $post_status_clause = "OR post_status IN ('draft','pending')"; + $post_status_clause = "OR post_status IN ('draft','pending')"; - } - } + } + } - // Prepare the first section of the SQL statement. - $count_query = $wpdb->prepare( - "SELECT ID FROM {$wpdb->posts} WHERE ( ID IN ( SELECT post_ID FROM {$wpdb->postmeta} WHERE meta_key = %s", - BU_Group_Permissions::META_KEY - ); + // Build group_id IN clause safely + $group_ids = array_map( 'intval', $group_ids ); + $group_in = implode( ',', $group_ids ); - // Build the remaining SQL from previously prepared statements. The `group_ids` array is forced to integer values for safety. - $count_query .= " AND meta_value IN (" . implode( ',', array_map( 'intval', $group_ids ) ) . ') ) ' . $post_type_clause . ') ' . $post_status_clause; + // Final query: find posts whose ID appears in postmeta entries for our group IDs + $sql = "SELECT ID FROM {$wpdb->posts} WHERE ID IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s AND meta_value IN ({$group_in}) ) {$post_type_clause}"; - // Execute query - $ids = $wpdb->get_col( $count_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + if ( $post_status_clause ) { + $sql .= " {$post_status_clause} "; + } - return $ids; - } + // Use prepare for the meta_key substitution + $prepared = $wpdb->prepare( $sql, BU_Group_Permissions::META_KEY ); + + $ids = $wpdb->get_col( $prepared ); + + return $ids; + } /** * Get allowed post count, optionally filtered by user ID, group or post_type diff --git a/classes.permissions.php b/classes.permissions.php index 6c75368..7024e6a 100644 --- a/classes.permissions.php +++ b/classes.permissions.php @@ -70,82 +70,91 @@ public static function can_edit_section( WP_User $user, $post_id ) { } /** - * Update permissions for a group - * - * @param int $group_id ID of group to modify ACL for - * @param array $permissions Permissions, as an associative array indexed by post type - */ - public static function update_group_permissions( $group_id, $permissions ) { - global $wpdb; - - if ( ! is_array( $permissions ) ) { - return false; - } - - foreach ( $permissions as $post_type => $ids_by_status ) { - - if ( ! is_array( $ids_by_status ) ) { - error_log( "Unexpected value found while updating permissions: $ids_by_status" ); - continue; - } - - // Incoming allowed posts - $allowed_ids = isset( $ids_by_status['allowed'] ) ? $ids_by_status['allowed'] : array(); - - if ( ! empty( $allowed_ids ) ) { - - // Make sure we don't add allowed meta twice - $previously_allowed = $wpdb->get_col( - $wpdb->prepare( - "SELECT post_id FROM {$wpdb->postmeta} WHERE post_id IN (%s) AND meta_key = %s AND meta_value = %s", - implode( ',', $allowed_ids ), - self::META_KEY, - $group_id - ) - ); - $additions = array_merge( array_diff( $allowed_ids, $previously_allowed ) ); - - foreach ( $additions as $post_id ) { - - add_post_meta( $post_id, self::META_KEY, $group_id ); - } - } - - // Incoming restricted posts - $denied_ids = isset( $ids_by_status['denied'] ) ? $ids_by_status['denied'] : array(); - - if ( ! empty( $denied_ids ) ) { - - // Sanitize the list of IDs for direct use in the query. - $denied_ids = implode( ',', array_map( 'intval', $denied_ids ) ); - - // Select meta_id's for removal based on incoming posts - $denied_meta_ids = $wpdb->get_col( - $wpdb->prepare( - "SELECT meta_id FROM {$wpdb->postmeta} WHERE post_id IN ({$denied_ids}) AND meta_key = %s AND meta_value = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared - self::META_KEY, - $group_id - ) - ); - - // Bulk deletion - if ( ! empty( $denied_meta_ids ) ) { - - // Sanitize the list of IDs for direct use in the query. - $denied_meta_ids = implode( ',', array_map( 'intval', $denied_meta_ids ) ); - - // Remove allowed status in one query - $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_id IN ({$denied_meta_ids})" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared - - // Purge cache - foreach ( $denied_ids as $post_id ) { - wp_cache_delete( $post_id, 'post_meta' ); - } - } - } - } - - } + * Update permissions for a group + * + * @param int $group_id ID of group to modify ACL for + * @param array $permissions Permissions, as an associative array indexed by post type + */ + public static function update_group_permissions( $group_id, $permissions ) { + global $wpdb; + + if ( ! is_array( $permissions ) ) { + return false; + } + + foreach ( $permissions as $post_type => $ids_by_status ) { + + if ( ! is_array( $ids_by_status ) ) { + error_log( "Unexpected value found while updating permissions: $ids_by_status" ); + continue; + } + + // + // Handle allowed IDs + // + $allowed_ids = isset( $ids_by_status['allowed'] ) ? $ids_by_status['allowed'] : array(); + $allowed_ids = array_map( 'intval', (array) $allowed_ids ); + + if ( ! empty( $allowed_ids ) ) { + + // Build safe IN list from ints + $in = implode( ',', $allowed_ids ); + + // Find which of these are already present + $previously_allowed = $wpdb->get_col( + "SELECT post_id FROM {$wpdb->postmeta} WHERE post_id IN ({$in}) AND meta_key = '" + . esc_sql( self::META_KEY ) . "' AND meta_value = '" . esc_sql( $group_id ) . "'" + ); + + $additions = array_diff( $allowed_ids, (array) $previously_allowed ); + + foreach ( $additions as $post_id ) { + add_post_meta( $post_id, self::META_KEY, $group_id ); + // Purge cache for this post's post_meta + wp_cache_delete( $post_id, 'post_meta' ); + } + } + + // + // Handle denied IDs (remove meta rows) + // + $denied_ids = isset( $ids_by_status['denied'] ) ? $ids_by_status['denied'] : array(); + $denied_ids = array_map( 'intval', (array) $denied_ids ); + + if ( ! empty( $denied_ids ) ) { + + $in = implode( ',', $denied_ids ); + + // Get meta rows so we can delete them and purge relevant post caches + $rows = $wpdb->get_results( + "SELECT meta_id, post_id FROM {$wpdb->postmeta} WHERE post_id IN ({$in}) AND meta_key = '" + . esc_sql( self::META_KEY ) . "' AND meta_value = '" . esc_sql( $group_id ) . "'", + OBJECT + ); + + if ( ! empty( $rows ) ) { + + $meta_ids = array(); + $post_ids = array(); + + foreach ( $rows as $r ) { + $meta_ids[] = intval( $r->meta_id ); + $post_ids[] = intval( $r->post_id ); + } + + // Execute deletion of postmeta rows + $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE meta_id IN (" . implode( ',', $meta_ids ) . ")" ); + + // Purge post_meta cache for affected posts + foreach ( array_unique( $post_ids ) as $pid ) { + wp_cache_delete( $pid, 'post_meta' ); + } + } + } + } + + return true; + } public static function delete_group_permissions( $group_id ) { @@ -333,7 +342,7 @@ public function display() { break; case 'html':default: - echo $this->get_posts(); + echo esc_html( $this->get_posts(), 'bu-section-editing' ); break; } @@ -411,8 +420,8 @@ public function get_post_markup( $p ) { // Publish information $meta = ''; - $published_label = __( 'Published on', BUSE_TEXTDOMAIN ); - $draft_label = __( 'Draft', BUSE_TEXTDOMAIN ); + $published_label = __( 'Published on', 'bu-section-editing' ); + $draft_label = __( 'Draft', 'bu-section-editing' ); switch ( $p['metadata']['post_status'] ) { @@ -434,7 +443,7 @@ public function get_post_markup( $p ) { // Perm actions button $perm_state = $p['metadata']['editable'] ? 'denied' : 'allowed'; - $perm_label = $perm_state == 'allowed' ? __( 'Allow', BUSE_TEXTDOMAIN ) : __( 'Deny', BUSE_TEXTDOMAIN ); + $perm_label = $perm_state == 'allowed' ? __( 'Allow', 'bu-section-editing' ) : __( 'Deny', 'bu-section-editing' ); $button = sprintf( '', $perm_state, $perm_label ); // Anchor @@ -472,7 +481,7 @@ public function format_post( $post, $has_children = false ) { $editable = BU_Group_Permissions::group_can_edit( $this->group->id, $post->ID, 'ignore_global' ); $perm = $editable ? 'allowed' : 'denied'; - $post->post_title = empty( $post->post_title ) ? __( '(no title)', BUSE_TEXTDOMAIN ) : $post->post_title; + $post->post_title = empty( $post->post_title ) ? __( '(no title)', 'bu-section-editing' ) : $post->post_title; $p = array( 'attr' => array( @@ -486,7 +495,7 @@ public function format_post( $post, $has_children = false ) { ), 'metadata' => array( 'post_id' => $post->ID, - 'post_date' => date( get_option( 'date_format' ), strtotime( $post->post_date ) ), + 'post_date' => gmdate( get_option( 'date_format' ), strtotime( $post->post_date ) ), 'post_status' => $post->post_status, 'editable' => $editable, 'editable-original' => $editable, @@ -593,7 +602,7 @@ public function display() { break; case 'html': default: - echo $this->get_posts( $this->child_of ); + echo esc_html($this->get_posts( $this->child_of ), 'bu-section-editing'); break; } @@ -737,45 +746,41 @@ protected function format_post( $post, $has_children = false ) { * Add custom section editable properties to the post objects returned by bu_navigation_get_pages() */ public function filter_posts( $posts ) { - global $wpdb; + global $wpdb; - if ( ( is_array( $posts ) ) && ( count( $posts ) > 0 ) ) { + if ( ( is_array( $posts ) ) && ( count( $posts ) > 0 ) ) { - /* Gather all group post meta in one shot */ - $ids = array_keys( $posts ); + /* Gather all group post meta in one shot */ + $ids = array_keys( $posts ); + $ids = array_map( 'intval', $ids ); + $in = implode( ',', $ids ); - // Sanitize the list of IDs for direct use in the query. - $ids = implode( ',', array_map( 'intval', $ids ) ); + $group_meta = $wpdb->get_results( + "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = '" + . esc_sql( BU_Group_Permissions::META_KEY ) . "' AND post_id IN ({$in}) AND meta_value = '" + . esc_sql( $this->group->id ) . "'", + OBJECT_K + ); - $group_meta = $wpdb->get_results( - $wpdb->prepare( - "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s AND post_id IN ({$ids}) AND meta_value = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared - BU_Group_Permissions::META_KEY, - $this->group->id - ), - OBJECT_K - ); // get results as objects in an array keyed on post_id + if ( ! is_array( $group_meta ) ) { + $group_meta = array(); + } - if ( ! is_array( $group_meta ) ) { - $group_meta = array(); - } + // Append permissions to post object + foreach ( $posts as $post ) { - // Append permissions to post object - foreach ( $posts as $post ) { + $post->editable = false; - $post->editable = false; + if ( array_key_exists( $post->ID, $group_meta ) ) { + $perm = $group_meta[ $post->ID ]; - if ( array_key_exists( $post->ID, $group_meta ) ) { - $perm = $group_meta[ $post->ID ]; + if ( $perm->meta_value === (string) $this->group->id ) { + $post->editable = true; + } + } + } + } - if ( $perm->meta_value === (string) $this->group->id ) { - $post->editable = true; - } - } - } - } - - return $posts; - - } + return $posts; + } } diff --git a/classes.upgrade.php b/classes.upgrade.php index 2ff389c..8ea8dcc 100644 --- a/classes.upgrade.php +++ b/classes.upgrade.php @@ -120,7 +120,7 @@ private function upgrade_03() { BU_Group_Permissions::META_KEY, '%:allowed' ) - ); + ); foreach ( $allowed_posts as $post ) { $new_meta_value = preg_replace( $patterns, $replacements, $post->meta_value ); @@ -133,8 +133,7 @@ private function upgrade_03() { "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s AND meta_value LIKE %s", BU_Group_Permissions::META_KEY, '%denied' - ) - ); + )); // Loop through and update foreach ( $denied_posts as $post ) { @@ -183,7 +182,6 @@ private function upgrade_04() { // Convert to new structure $group = $gc->add_group( $groupdata ); - // Grab all post IDS that have permissions set for this group $posts_to_update = $wpdb->get_col( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s", diff --git a/interface/edit-group.php b/interface/edit-group.php index ce71682..2b170ab 100644 --- a/interface/edit-group.php +++ b/interface/edit-group.php @@ -1,21 +1,21 @@
-

+

- + - - + +
diff --git a/interface/group-members.php b/interface/group-members.php index 0f731a1..31c5c82 100644 --- a/interface/group-members.php +++ b/interface/group-members.php @@ -1,13 +1,13 @@
-

+

- + - +
@@ -15,9 +15,9 @@
- users ); ?> users ), BUSE_TEXTDOMAIN ); ?> + users ), 'bu-section-editing'); ?> users ), 'bu-section-editing' ); ?>
-

+

    @@ -25,9 +25,9 @@ has_user( $user->ID ) ? 'checked="checked"' : ''; ?>
  • - - /> - + + /> +
diff --git a/interface/group-permissions.php b/interface/group-permissions.php index 27d0ac0..87c31cf 100644 --- a/interface/group-permissions.php +++ b/interface/group-permissions.php @@ -4,7 +4,7 @@
$pt ) : ?> name ? ' nav-tab-active' : ''; ?> - label; ?> + label, 'bu-section-editing'); ?>
@@ -16,30 +16,31 @@ $is_post = 'post' === $pt->name; $editable = $groups->get_allowed_posts( array( 'group' => $group_id, 'post_type' => $pt->name ) ); ?> -
+
- post_is_globally_editable_by_group( $pt->name, $group_id ) ? 'checked' : ''; ?> > -
-
+

- | - + | +

- - + + +

- +

@@ -48,37 +49,37 @@
- +
- -
+ +
-
- +
+ - « - + « + - of 1 + of 1 - - » + + »
-
+
diff --git a/interface/group-properties.php b/interface/group-properties.php index 2916122..2776867 100644 --- a/interface/group-properties.php +++ b/interface/group-properties.php @@ -1,10 +1,10 @@
- +
- +
diff --git a/interface/group-stats.php b/interface/group-stats.php index cf308d7..c2d3fdc 100644 --- a/interface/group-stats.php +++ b/interface/group-stats.php @@ -1,24 +1,24 @@
-

+

"\n" ) ); ?>
    -
  • : name; ?>
  • -
  • : users ); ?>
  • -
  • :
  • +
  • : name, 'bu-section-editing'); ?>
  • +
  • : users ); ?>
  • +
  • :
- +
$group_id ) ); ?>
- +
- +
diff --git a/interface/groups.php b/interface/groups.php index 9d8e6a8..5f2cd50 100644 --- a/interface/groups.php +++ b/interface/groups.php @@ -1,24 +1,24 @@
-

-

+

+

- - - - - + + + + + - - - - - + + + + + @@ -27,17 +27,17 @@ have_groups() ) : $group = $group_list->the_group(); ?> $group->id ) ); + $edit_url = esc_url( BU_Groups_Admin::manage_groups_url( 'edit', array( 'id' => $group->id ) ), 'bu-section-editing' ); $description = (strlen( $group->description ) > 60) ? substr( $group->description, 0, 60 ) . ' [...]' : $group->description; ?> - > - - + > + + - + @@ -45,5 +45,5 @@
name; ?>
name, 'bu-section-editing' ); ?> users ); ?> - - <?php esc_attr_e( 'Delete', BUSE_TEXTDOMAIN ); ?> + + <?php esc_attr_e( 'Delete', 'bu-section-editing' ); ?>
-

+

diff --git a/js/group-editor.js b/js/group-editor.js index 132fd55..c4f6858 100644 --- a/js/group-editor.js +++ b/js/group-editor.js @@ -59,7 +59,7 @@ jQuery(document).ready(function($){ $('.member:not(.active)').appendTo('#inactive-members'); // Remove a member from the editor group list - $members_list.delegate( 'a.remove_member', 'click', function(e){ + $members_list.on( 'a.remove_member', 'click', function(e){ e.preventDefault(); $(this).parent('.member').removeClass('active').slideUp( 'fast', function() { @@ -67,7 +67,7 @@ jQuery(document).ready(function($){ // Move to #inactive-members bucket $(this) .appendTo('#inactive-members') - .find('input[type="checkbox"]').removeAttr('checked'); + .find('input[type="checkbox"]').prop('checked', false); // Update member count updateMemberCount(); @@ -183,7 +183,7 @@ jQuery(document).ready(function($){ /* Add Members */ - $('#add_member').bind( 'click', function(e){ + $('#add_member').on( 'click', function(e){ e.preventDefault(); handle_member_add(); @@ -266,7 +266,7 @@ jQuery(document).ready(function($){ var add_member = function( user ) { // Add member - $('#member_' + user.id ).attr('checked','checked') + $('#member_' + user.id ).prop('checked',false) .parent('.member') .addClass('active') .appendTo($members_list) @@ -323,7 +323,7 @@ jQuery(document).ready(function($){ loadToolbars( $panel, $editor ); // Handle permission actions - $editor.delegate('.edit-perms', 'click', function (e) { + $editor.on('.edit-perms', 'click', function (e) { var $button = $(e.currentTarget), $post = $button.closest('li'), classes = $button.attr('class'), @@ -348,7 +348,7 @@ jQuery(document).ready(function($){ }); // Deselect all on click outside active perm panel - $(document).bind('click', function (e) { + $(document).on('click', function (e) { var $active_perm_panel = $('.perm-panel.active'); var $editor = $('.perm-editor', $active_perm_panel); @@ -370,7 +370,7 @@ jQuery(document).ready(function($){ /** * Permissions editor loading on post type tab click */ - $('#perm-tab-container').delegate( 'a', 'click', function(e) { + $('#perm-tab-container').on( 'a', 'click', function(e) { var $panel = $($(this).attr('href')); @@ -390,7 +390,7 @@ jQuery(document).ready(function($){ var loadToolbars = function( $panel, $editor ) { // Search - $panel.delegate( 'button.perm-search', 'click', function(e){ + $panel.on( 'button.perm-search', 'click', function(e){ e.preventDefault(); var post_type = $editor.data('post-type'); @@ -410,7 +410,7 @@ jQuery(document).ready(function($){ /* Pagination */ // Pagination using links - $panel.find('.pagination-links').delegate( 'a', 'click', function(e){ + $panel.find('.pagination-links').on( 'a', 'click', function(e){ e.preventDefault(); if( $(this).hasClass('disabled') ) @@ -444,7 +444,7 @@ jQuery(document).ready(function($){ }); // Manually advanced page using current page text input - $panel.delegate( 'input.current-page', 'keypress', function(e) { + $panel.on( 'input.current-page', 'keypress', function(e) { if( e.keyCode == '13' ) { e.preventDefault(); @@ -465,7 +465,7 @@ jQuery(document).ready(function($){ }); // Search - $panel.delegate( 'input.perm-search', 'keypress', function(e) { + $panel.on( 'input.perm-search', 'keypress', function(e) { if( e.keyCode == 13 ) { e.preventDefault(); $(this).siblings('button').first().click(); @@ -475,7 +475,7 @@ jQuery(document).ready(function($){ /* Bulk editor */ // Toggle bulk edit mode - $panel.delegate( 'a.perm-editor-bulk-edit', 'click', function(e) { + $panel.on( 'a.perm-editor-bulk-edit', 'click', function(e) { e.preventDefault(); var $a = $(this); @@ -489,19 +489,19 @@ jQuery(document).ready(function($){ // Reset selections & bulk editor state $editor.find('.perm-item-selected').removeClass('perm-item-selected'); - $panel.find('input[type="checkbox"]').attr('checked', false); + $panel.find('input[type="checkbox"]').prop('checked', false); $('.bulk-edit-actions select').val('none'); }); // Select all behavior toolbar checkbox - $panel.delegate('.bulk-edit-select-all', 'click', function(e) { + $panel.on('.bulk-edit-select-all', 'click', function(e) { var $allposts = $editor.find('li'); - $allposts.children('input[type="checkbox"]').attr( 'checked', this.checked ); + $allposts.children('input[type="checkbox"]').prop( 'checked', this.checked ); }); // Apply bulk actions - $panel.delegate('.bulk-edit-actions button', 'click', function(e) { + $panel.on('.bulk-edit-actions button', 'click', function(e) { e.preventDefault(); var $selector = $(this).siblings('select'); @@ -524,16 +524,16 @@ jQuery(document).ready(function($){ // Reset bulk actions to default state - $panel.find('.bulk-edit-select-all').attr('checked', false); + $panel.find('.bulk-edit-select-all').prop('checked', false); $selector.val('none'); - selections.attr('checked', false); + selections.prop('checked', false); }); /* Hierarchical editor */ // Expand all - $panel.delegate('a.perm-tree-expand', 'click', function(e) { + $panel.on('a.perm-tree-expand', 'click', function(e) { e.preventDefault(); if(typeof $.jstree !== 'undefined') { $.jstree._reference($editor).open_all(); @@ -541,7 +541,7 @@ jQuery(document).ready(function($){ }); // Collapse all - $panel.delegate('a.perm-tree-collapse', 'click', function(e) { + $panel.on('a.perm-tree-collapse', 'click', function(e) { e.preventDefault(); if(typeof $.jstree !== 'undefined') { $.jstree._reference($editor).close_all(); @@ -572,7 +572,7 @@ jQuery(document).ready(function($){ args['query']['s'] = term; // Reset bulk edit toolbar - $panel.find('.bulk-edit-select-all').attr('checked',false ); + $panel.find('.bulk-edit-select-all').prop('checked',false ); $panel.find('.bulk-edit-actions select').val('none'); // Render post list @@ -639,7 +639,7 @@ jQuery(document).ready(function($){ // Event binding $editor - .bind('posts_loaded.buse', function (e, data) { + .on('posts_loaded.buse', function (e, data) { // Merge incoming server state with pending edits var edits = $editor.data('perm-edits') || {"allowed":[], "denied": []}, @@ -674,7 +674,7 @@ jQuery(document).ready(function($){ var attachFlatEditorHandlers = function( $editor ) { // Post selection - $editor.delegate( 'a', 'click', function (e) { + $editor.on( 'a', 'click', function (e) { e.preventDefault(); e.stopPropagation(); @@ -690,7 +690,7 @@ jQuery(document).ready(function($){ }); - $editor.bind('perm_updated', function (e, data ) { + $editor.on('perm_updated', function (e, data ) { // Deselect data.post.removeClass('perm-item-selected'); @@ -718,7 +718,7 @@ jQuery(document).ready(function($){ // Attach handlers and instantiate $editor - .bind('load_node.jstree', function( event, data ) { + .on('load_node.jstree', function( event, data ) { // Correct state post-load for all non-root nodes if( data.rslt.obj != -1 ) { @@ -726,7 +726,7 @@ jQuery(document).ready(function($){ } }) - .bind('perm_updated', function (e, data) { + .on('perm_updated', function (e, data) { var $post = data.post; if ($post.hasClass('jstree-closed')) { diff --git a/js/group-editor.min.js b/js/group-editor.min.js index dbf9631..3325cc8 100644 --- a/js/group-editor.min.js +++ b/js/group-editor.min.js @@ -1 +1 @@ -jQuery(document).ready(function(a){var b;"undefined"!=typeof bu&&void 0!==bu.plugins.navigation&&void 0!==bu.plugins.navigation.tree&&(b=bu.plugins.navigation);var c=a("#group-member-list");a("a.nav-link").click(function(b){b.preventDefault();var c=a('a.nav-tab[href="'+this.hash+'"]'),d=a(this.hash);$input=a(d.hasClass("group-panel")?"#tab":"#perm_panel"),$input.val(c.data("target")),c.addClass("nav-tab-active").siblings().removeClass("nav-tab-active"),d.addClass("active").siblings().removeClass("active")});var d=60;a("#edit-group-name").blur(function(b){var c=a.trim(a(this).val());if(c.length>d&&(c=c.slice(0,d-1),a(this).val(c)),c.length<1)return D(buse_group_editor_settings.nameRequiredNotice),!1;E(),a("#group-stats-name").html(c)}),a(".member:not(.active)").appendTo("#inactive-members"),c.delegate("a.remove_member","click",function(b){b.preventDefault(),a(this).parent(".member").removeClass("active").slideUp("fast",function(){a(this).appendTo("#inactive-members").find('input[type="checkbox"]').removeAttr("checked"),m()})});var e=function(){return a.map(a('li.member.active input[type="checkbox"]'),function(a){return parseInt(a.value,10)})},f=function(b,c){return a.grep(b,function(a,b){return c=c.toLowerCase(),a.user.is_section_editor&&(-1!=a.user.display_name.toLowerCase().indexOf(c)||-1!=a.user.login.toLowerCase().indexOf(c)||-1!=a.user.nicename.toLowerCase().indexOf(c)||-1!=a.user.email.toLowerCase().indexOf(c))})},g=function(b){return a.grep(b,function(a,b){return!h(a.user)})},h=function(b){var c=e();return a.inArray(b.id,c)>-1},i=function(b){var c=a.grep(buse_site_users,function(a,c){var d=b.toLowerCase();return a.user.display_name.toLowerCase()==d||a.user.login.toLowerCase()==d||a.user.nicename.toLowerCase()==d||a.user.email.toLowerCase()==d});return!(c.length>1||0==c.length)&&c[0].user},j=a(".buse-suggest-user").autocomplete({source:function(b,c){var d=f(buse_site_users,b.term),d=g(d);c(a.map(d,function(a){return a.autocomplete}))},delay:500,minLength:2,position:"undefined"!=typeof isRtl&&isRtl?{my:"right top",at:"right bottom",offset:"0, -1"}:{offset:"0, -1"},open:function(){a(this).addClass("open")},close:function(){a(this).removeClass("open")}});a("#add_member").bind("click",function(a){a.preventDefault(),k()}),a("#user_login").keypress(function(a){"13"==a.keyCode&&(a.preventDefault(),k())});var k=function(){var b=a.trim(a("#user_login").val());if(b){j.autocomplete("search","");var c=i(b);if(c)if(c.is_section_editor)if(h(c)){var d=""+c.display_name+" "+a("

").html(buse_group_editor_settings.userAlreadyMemberNotice).text();D(d,"members-message")}else E("members-message"),l(c);else{var d=""+c.display_name+" "+a("

").html(buse_group_editor_settings.userWrongRoleNotice).text();D(d,"members-message")}else{var d=""+b+" "+a("

").html(buse_group_editor_settings.userNotExistsNotice).text();D(d,"members-message")}}a("#user_login").val("").focus()},l=function(b){a("#member_"+b.id).attr("checked","checked").parent(".member").addClass("active").appendTo(c).slideDown("fast"),m()},m=function(){var b,d;b=c.children(".member").length,d=1==b?buse_group_editor_settings.memberCountSingularLabel:buse_group_editor_settings.memberCountPluralLabel,a(".member-count").html(b),a(".member-count-label").text(d)},n=function(c){var d=c.find(".perm-editor").first();d.hasClass("hierarchical")?void 0===b?(alert(buse_group_editor_settings.navDepAlertText),d.html(buse_group_editor_settings.navDepEditorText)):v(d):t(d),q(c,d),d.delegate(".edit-perms","click",function(b){var c,e,f=a(b.currentTarget),g=f.closest("li"),h=f.attr("class");b.stopPropagation(),b.preventDefault(),h.indexOf("allowed")>-1?c="allowed":h.indexOf("denied")>-1&&(c="denied"),e="allowed"==c,y(g,e,d),d.trigger("perm_updated",[{post:g,action:c}])}),a(document).bind("click",function(b){var c=a(".perm-panel.active"),d=a(".perm-editor",c);a.contains(c[0],b.target)||(d.hasClass("hierarchical")&&void 0!==d.jstree?d.jstree("deselect_all"):d.find(".perm-item-selected").removeClass("perm-item-selected"))}),c.addClass("loaded")};a("#perm-tab-container").delegate("a","click",function(b){var c=a(a(this).attr("href"));c.hasClass("loaded")||n(c)});var o,p,q=function(b,c){b.delegate("button.perm-search","click",function(b){b.preventDefault();var d=c.data("post-type"),e=a("#perm-search-"+d).val(),f={post_type:c.data("post-type"),query:{s:e}};w(c,f)}),b.find(".pagination-links").delegate("a","click",function(b){if(b.preventDefault(),!a(this).hasClass("disabled")){var d=a(this).attr("class"),e=parseInt(a(this).parent().find(".current-page").val()),f=parseInt(a(this).parent().find(".total-pages").text()),g=1;switch(d){case"first-page":g=1;break;case"prev-page":g=e-1;break;case"next-page":g=e+1;break;case"last-page":g=f}r(g,c)}}),b.delegate("input.current-page","keypress",function(b){if("13"==b.keyCode){b.preventDefault();var d=a(this).val(),e=parseInt(a(this).parent().find(".total-pages").text());d<1?a(this).val(1):d>e&&a(this).val(e),d=a(this).val(),r(d,c)}}),b.delegate("input.perm-search","keypress",function(b){13==b.keyCode&&(b.preventDefault(),a(this).siblings("button").first().click())}),b.delegate("a.perm-editor-bulk-edit","click",function(d){d.preventDefault();var e=a(this);b.hasClass("bulk-edit")?(e.removeClass("bulk-edit-close").attr("title",buse_group_editor_settings.bulkEditOpenTitle).text(buse_group_editor_settings.bulkEditOpenText),b.removeClass("bulk-edit")):(e.addClass("bulk-edit-close").attr("title",buse_group_editor_settings.bulkEditCloseTitle).text(buse_group_editor_settings.bulkEditCloseText),b.addClass("bulk-edit")),c.find(".perm-item-selected").removeClass("perm-item-selected"),b.find('input[type="checkbox"]').attr("checked",!1),a(".bulk-edit-actions select").val("none")}),b.delegate(".bulk-edit-select-all","click",function(a){c.find("li").children('input[type="checkbox"]').attr("checked",this.checked)}),b.delegate(".bulk-edit-actions button","click",function(d){d.preventDefault();var e=a(this).siblings("select"),f=e.val(),g=c.find('input[type="checkbox"]:checked');g.length>0&&("allowed"!=f&&"denied"!=f||g.each(function(){var b=a(this).parents("li");y(b,"allowed"==f,c)})),b.find(".bulk-edit-select-all").attr("checked",!1),e.val("none"),g.attr("checked",!1)}),b.delegate("a.perm-tree-expand","click",function(b){b.preventDefault(),void 0!==a.jstree&&a.jstree._reference(c).open_all()}),b.delegate("a.perm-tree-collapse","click",function(b){b.preventDefault(),void 0!==a.jstree&&a.jstree._reference(c).close_all()})},r=function(b,c){var d=c.closest(".perm-panel"),e=c.data("post-type"),f={post_type:e,query:{paged:b}},g=a("#perm-search-"+e).val();g.length>0&&(f.query.s=g),d.find(".bulk-edit-select-all").attr("checked",!1),d.find(".bulk-edit-actions select").val("none"),w(c,f)},s=function(a){var b=a.hasClass("allowed")?"allowed":"denied",c="allowed"==b?"denied":"allowed",d="";d="allowed"==c?buse_group_editor_settings.permAllowLabel:buse_group_editor_settings.permDenyLabel,a.removeClass(b).addClass(c).text(d)},t=function(a){var b=a.data("post-type"),c=a.data("original-global-edit"),d=jQuery("#perm-panel-"+b),e=(jQuery("#"+b+"-stats"),[]);a.data("global-edit",c),c&&(d.addClass("global-edit"),d.data("editable-original")&&(e=(d.data("editable-original")+"").split(","))),a.data("editable-original",e),jQuery("#perm-global-edit-"+b).change(function(){this.checked?(a.data("global-edit",!0),d.addClass("global-edit")):(a.data("global-edit",!1),d.removeClass("global-edit")),C(b)}),a.data("loaded",!0),u(a),a.bind("posts_loaded.buse",function(b,c){var d,e,f,g=a.data("perm-edits")||{allowed:[],denied:[]};for(d=0;d'+buse_group_editor_settings.loadingText+""):b.html('

  • '+buse_group_editor_settings.loadingText+"
"),a.ajax({url:ajaxurl,type:"GET",data:d,cache:!1,success:function(a){d.query.offset?b.append(a.posts):b.html(a.posts);var c={page:a.page,found_posts:a.found_posts,post_count:a.post_count,max_num_pages:a.max_num_pages};x(c,b),b.trigger("posts_loaded.buse",{posts:a.posts}),b.removeClass("loading")},error:function(a){}})},x=function(b,c){var d=c.data("post-type");a("#group_id").val();if($pagination=a("#perm-editor-pagination-"+d),$total_items=$pagination.find(".displaying-num"),$current_page=$pagination.find(".current-page"),$total_pages=$pagination.find(".total-pages"),$first_page=$pagination.find(".first-page"),$prev_page=$pagination.find(".prev-page"),$next_page=$pagination.find(".next-page"),$last_page=$pagination.find(".last-page"),b.max_num_pages>1){var e=1==parseInt(b.found_posts)?" item":" items";$total_items.text(b.found_posts+e),$current_page.val(b.page),$total_pages.text(b.max_num_pages),1==b.page?($first_page.addClass("disabled"),$prev_page.addClass("disabled")):($first_page.removeClass("disabled"),$prev_page.removeClass("disabled")),b.page==b.max_num_pages?($next_page.addClass("disabled"),$last_page.addClass("disabled")):($next_page.removeClass("disabled"),$last_page.removeClass("disabled")),$pagination.show()}else $pagination.hide()},y=function(a,b,c){var d,e=c.data("post-type"),f=c.data("perm-edits")||{allowed:[],denied:[]};z(a,b,f),c.hasClass("hierarchical")&&(d=a.parent("ul").parent("div").attr("id")!=c.attr("id")?a.parents("li:last"):a,A(d)),c.data("perm-edits",f),C(e)},z=function(b,c,d){var e=b.attr("id").substr(1),f=b.find(".edit-perms").first();c!=b.data("editable")&&s(f);var g,h=c?"allowed":"denied",i=b.data("editable-original");b.data("editable",c),b.attr("rel",h),i!=c?-1===(g=a.inArray(e,d[h]))&&d[h].push(e):(g=a.inArray(e,d.allowed),g>-1&&d.allowed.splice(g,1),(g=a.inArray(e,d.denied))>-1&&d.denied.splice(g,1)),b.find("> ul > li").each(function(){z(a(this),c,d)})},A=function(b){$sections=b.find("ul"),$sections.each(function(){var b=a(this).parents("li").first();if(b.length){var c=b.attr("rel"),d=!1;switch(c){case"allowed":case"allowed-desc-denied":case"allowed-desc-unknown":d=a(this).find('li[rel="denied"],li[rel="denied-desc-allowed"],li[rel="denied-desc-unknown"]').length,d?b.attr("rel","allowed-desc-denied"):b.attr("rel","allowed"),B(b,d);break;case"denied":case"denied-desc-allowed":case"denied-desc-unknown":d=a(this).find('li[rel="allowed"],li[rel="allowed-desc-denied"],li[rel="allowed-desc-unknown"]').length,d?b.attr("rel","denied-desc-allowed"):b.attr("rel","denied"),B(b,d)}}})},B=function(b,c){var d=b.find("> a > .perm-stats"),e=b.data("editable");0===d.length&&(d=a('  '),b.find("> a > .title-count").after(d)),d.removeClass("allowed denied").children(".label").text(""),c&&(e?d.addClass("denied").children(".label").text(c+" "+buse_group_editor_settings.permNonEditableLabel):d.addClass("allowed").children(".label").text(c+" "+buse_group_editor_settings.permEditableLabel))},C=function(b){var c=a("#perm-editor-"+b),d=a("#"+b+"-stats"),e=a(".perm-stats-diff",d),f=c.data("perm-edits")||{allowed:[],denied:[]};0===e.length&&(e=a(''),d.append(e));var g=[];if(!!c.data("original-global-edit")!=!!c.data("global-edit"))if(c.data("global-edit"))g.push('+'+buse_group_editor_settings.permGlobalLabel+"");else{g.push('-'+buse_group_editor_settings.permGlobalLabel+""),f=a.extend(!0,{},f);var h=c.data("editable-original"),i=a(h).not(f.denied).get(),j=a(f.denied).not(h).get();f.denied=j,a.merge(f.allowed,i)}var k,l;if(!c.data("global-edit"))for(k in f)f[k].length&&(l="allowed"===k?"+":"-",g.push(''+l+f[k].length+""));var m=g.join(", ");m?e.html(" ("+m+")"):e.html("")},D=function(b,c,d){var e={classes:"error",before_msg:"

",after_msg:"

"};d&&"object"==typeof d&&a.extend(e,d),a("#"+(c||"message")).attr("class",e.classes).html(e.before_msg+b+e.after_msg).fadeIn()},E=function(b){a("#"+(b||"message")).fadeOut("fast",function(b){a(this).attr("class","").html("")})};o=a("#edit-group-name").val();var F=function(){var b=[];return a("#group-member-list").children("li.member.active").each(function(c,d){b.push(a(d).children("input").first().val())}),b};p=F(),window.onbeforeunload=function(){if(G())return buse_group_editor_settings.dirtyLeaverNotice};var G=function(){var b,c,d,e,f=!1;if(b=a("#edit-group-name").val(),o!=b&&(f=!0),c=F(),p.length!=c.length)f=!0;else for(e=0;e"+t.display_name+" "+d("

").html(buse_group_editor_settings.userAlreadyMemberNotice).text(),x(e,"members-message")):($("members-message"),p(t)):(e=""+t.display_name+" "+d("

").html(buse_group_editor_settings.userWrongRoleNotice).text(),x(e,"members-message")):(e=""+a+" "+d("

").html(buse_group_editor_settings.userNotExistsNotice).text(),x(e,"members-message"))),d("#user_login").val("").focus()}),p=function(e){d("#member_"+e.id).prop("checked",!1).parent(".member").addClass("active").appendTo(i).slideDown("fast"),u()},u=function(){var e=i.children(".member").length,t=1==e?buse_group_editor_settings.memberCountSingularLabel:buse_group_editor_settings.memberCountPluralLabel;d(".member-count").html(e),d(".member-count-label").text(t)},c=(d("#perm-tab-container").on("a","click",function(e){var t=d(d(this).attr("href"));t.hasClass("loaded")||a(t)}),function(i,s){i.on("button.perm-search","click",function(e){e.preventDefault();e=s.data("post-type"),e=d("#perm-search-"+e).val(),e={post_type:s.data("post-type"),query:{s:e}};_(s,e)}),i.find(".pagination-links").on("a","click",function(e){if(e.preventDefault(),!d(this).hasClass("disabled")){var e=d(this).attr("class"),t=parseInt(d(this).parent().find(".current-page").val()),a=parseInt(d(this).parent().find(".total-pages").text()),i=1;switch(e){case"first-page":i=1;break;case"prev-page":i=t-1;break;case"next-page":i=t+1;break;case"last-page":i=a}g(i,s)}}),i.on("input.current-page","keypress",function(e){var t;"13"==e.keyCode&&(e.preventDefault(),e=d(this).val(),t=parseInt(d(this).parent().find(".total-pages").text()),e<1?d(this).val(1):t'+buse_group_editor_settings.loadingText+""):a.html('

  • '+buse_group_editor_settings.loadingText+"
"),d.ajax({url:ajaxurl,type:"GET",data:i,cache:!1,success:function(e){i.query.offset?a.append(e.posts):a.html(e.posts);var t={page:e.page,found_posts:e.found_posts,post_count:e.post_count,max_num_pages:e.max_num_pages};h(t,a),a.trigger("posts_loaded.buse",{posts:e.posts}),a.removeClass("loading")},error:function(e){}})},h=function(e,t){var t=t.data("post-type");d("#group_id").val();$pagination=d("#perm-editor-pagination-"+t),$total_items=$pagination.find(".displaying-num"),$current_page=$pagination.find(".current-page"),$total_pages=$pagination.find(".total-pages"),$first_page=$pagination.find(".first-page"),$prev_page=$pagination.find(".prev-page"),$next_page=$pagination.find(".next-page"),$last_page=$pagination.find(".last-page"),1 ul > li").each(function(){w(d(this),t,a)})},k=function(e){($sections=e.find("ul")).each(function(){var e=d(this).parents("li").first();if(e.length){var t=!1;switch(e.attr("rel")){case"allowed":case"allowed-desc-denied":case"allowed-desc-unknown":(t=d(this).find('li[rel="denied"],li[rel="denied-desc-allowed"],li[rel="denied-desc-unknown"]').length)?e.attr("rel","allowed-desc-denied"):e.attr("rel","allowed"),C(e,t);break;case"denied":case"denied-desc-allowed":case"denied-desc-unknown":(t=d(this).find('li[rel="allowed"],li[rel="allowed-desc-denied"],li[rel="allowed-desc-unknown"]').length)?e.attr("rel","denied-desc-allowed"):e.attr("rel","denied"),C(e,t)}}})},C=function(e,t){var a=e.find("> a > .perm-stats"),i=e.data("editable");0===a.length&&(a=d('  '),e.find("> a > .title-count").after(a)),a.removeClass("allowed denied").children(".label").text(""),t&&(i?a.addClass("denied").children(".label").text(t+" "+buse_group_editor_settings.permNonEditableLabel):a.addClass("allowed").children(".label").text(t+" "+buse_group_editor_settings.permEditableLabel))},y=function(e){var t,a,i=d("#perm-editor-"+e),e=d("#"+e+"-stats"),s=d(".perm-stats-diff",e),n=i.data("perm-edits")||{allowed:[],denied:[]},l=(0===s.length&&(s=d(''),e.append(s)),[]);if(!!i.data("original-global-edit")!=!!i.data("global-edit")&&(i.data("global-edit")?l.push('+'+buse_group_editor_settings.permGlobalLabel+""):(l.push('-'+buse_group_editor_settings.permGlobalLabel+""),n=d.extend(!0,{},n),e=i.data("editable-original"),t=d(e).not(n.denied).get(),e=d(n.denied).not(e).get(),n.denied=e,d.merge(n.allowed,t))),!i.data("global-edit"))for(a in n)n[a].length&&l.push(''+("allowed"===a?"+":"-")+n[a].length+"");e=l.join(", ");e?s.html(" ("+e+")"):s.html("")},x=function(e,t,a){var i={classes:"error",before_msg:"

",after_msg:"

"},a=(a&&"object"==typeof a&&d.extend(i,a),t||"message");d("#"+a).attr("class",i.classes).html(i.before_msg+e+i.after_msg).fadeIn()},$=function(e){d("#"+(e||"message")).fadeOut("fast",function(e){d(this).attr("class","").html("")})},j=d("#edit-group-name").val(),D=n(),L=(window.onbeforeunload=function(){if(L())return buse_group_editor_settings.dirtyLeaverNotice},function(){var e,t,a,i=!1,s=d("#edit-group-name").val();if(j!=s&&(i=!0),e=n(),D.length!=e.length)i=!0;else for(a=0;a'+buse_post.publishLabel+"")):a(c+' [name="_status"] [value="publish"]').remove(),a(c+' [name="_status"] [value="'+b.status+'"]').attr("selected","selected")},error:function(a){}})},inlineEditPost.post_edit=inlineEditPost.edit,inlineEditPost.edit=function(a){inlineEditPost.pre_edit(a)})}); \ No newline at end of file +jQuery(function(n){n("#bulk-edit #post_parent").on("change",function(t){var e=n("#post_parent option:selected").val();-1!=e&&n.ajax({url:ajaxurl,data:{action:"buse_can_edit",post_id:e},type:"POST",success:function(t){0==t.can_edit&&(alert(buse_post.cantEditParentNotice),n('#bulk-edit #post_parent [value="-1"]').prop("selected",!0))},error:function(t){}})}),n("#inline-edit #post_parent").on("change",function(t){var e=n("#post_parent option:selected").val(),i=n(this).closest("tr").attr("id").split("-"),i=i[i.length-1];"publish"==n("#edit-"+i+' [name="_status"] option:selected').val()&&n.ajax({url:ajaxurl,data:{action:"buse_can_move",post_id:i,parent_id:e},type:"POST",success:function(t){0==t.can_edit&&(alert(buse_post.cantMovePostNotice),n('#post_parent [value="'+t.original_parent+'"]').prop("selected",!0))},error:function(t){}})}),void 0!==window.inlineEditPost&&(inlineEditPost.pre_edit=function(t){var e={action:"buse_can_edit",post_id:e="object"==typeof t?this.getId(t):e};n.ajax({url:ajaxurl,data:e,type:"POST",id:t,success:function(t){inlineEditPost.post_edit(this.id);var e="#edit-"+t.post_id;1==t.can_edit?0==n(e+' [name="_status"] [value="publish"]').length&&(console.log(buse_post),n(e+' [name="_status"]').prepend('")):n(e+' [name="_status"] [value="publish"]').remove(),n(e+' [name="_status"] [value="'+t.status+'"]').prop("selected",!0)},error:function(t){}})},inlineEditPost.post_edit=inlineEditPost.edit,inlineEditPost.edit=function(t){inlineEditPost.pre_edit(t)})}); \ No newline at end of file diff --git a/js/tree-perm-editor.js b/js/tree-perm-editor.js index 9f63fbc..40c57fe 100644 --- a/js/tree-perm-editor.js +++ b/js/tree-perm-editor.js @@ -99,7 +99,7 @@ node.each(function () { $li = $(this); - $li.find("li").andSelf().each(function () { + $li.find("li").addBack().each(function () { action_class = $(this).data('editable') ? 'denied' : 'allowed'; if (action_class == 'allowed') { @@ -116,11 +116,11 @@ }; // Add perm actions button to each node as needed - $tree.bind("open_node.jstree create_node.jstree clean_node.jstree refresh.jstree", function (e, data) { + $tree.on("open_node.jstree create_node.jstree clean_node.jstree refresh.jstree", function (e, data) { _prepare_perm_actions(data.rslt.obj); }); - $tree.bind("loaded.jstree", function (e) { + $tree.on("loaded.jstree", function (e) { _prepare_perm_actions(); }); diff --git a/js/tree-perm-editor.min.js b/js/tree-perm-editor.min.js index f521090..fab8c71 100644 --- a/js/tree-perm-editor.min.js +++ b/js/tree-perm-editor.min.js @@ -1 +1 @@ -!function(a){if("undefined"!=typeof bu&&void 0!==bu.plugins.navigation&&void 0!==bu.plugins.navigation.tree){var b=bu.plugins.navigation;b.trees.buse_perm_editor=function(c,d){d=d||{};var e=b.trees.base(c,d),f=e.data,g=a.extend(e.config,c||{}),h=e.$el,i=a.inArray("crrm",f.treeConfig.plugins);i>-1&&(f.treeConfig.plugins.splice(i,1),void 0!==f.treeConfig.crrm&&delete f.treeConfig.crrm);var j=a.inArray("dnd",f.treeConfig.plugins);j>-1&&(f.treeConfig.plugins.splice(j,1),void 0!==f.treeConfig.dnd&&delete f.treeConfig.dnd),f.treeConfig.types={types:{default:{},denied:{},"denied-desc-allowed":{},"denied-desc-unknown":{},allowed:{},"allowed-desc-denied":{},"allowed-desc-unknown":{}}},f.treeConfig.ui={select_limit:1},f.treeConfig.json_data.ajax={url:g.rpcUrl,type:"GET",cache:!1,data:function(a){return{group_id:g.groupID,node_prefix:g.nodePrefix,post_type:g.postType,query:{child_of:a.attr?d.stripNodePrefix(a.attr("id")):0}}},success:function(a){return a.posts},error:function(a){}},f.treeConfig.json_data.progressive_render=!1;var k=function(b){b=b&&-1!=b?a.jstree._reference(h)._get_node(b):h.find("> ul > li");var c,d,e,f;b.each(function(){c=a(this),c.find("li").andSelf().each(function(){e=a(this).data("editable")?"denied":"allowed",f="allowed"==e?g.allowLabel:g.denyLabel,d=a('').text(f),a(this).children("a").not(":has(.edit-perms)").append(d)})})};return h.bind("open_node.jstree create_node.jstree clean_node.jstree refresh.jstree",function(a,b){k(b.rslt.obj)}),h.bind("loaded.jstree",function(a){k()}),h.addClass("buse-perm-editor"),e}}}(jQuery); \ No newline at end of file +!function(a){var s;"undefined"!=typeof bu&&void 0!==bu.plugins.navigation&&void 0!==bu.plugins.navigation.tree&&((s=bu.plugins.navigation).trees.buse_perm_editor=function(e,n){n=n||{};function t(e){var n,t;(e=e&&-1!=e?a.jstree._reference(o)._get_node(e):o.find("> ul > li")).each(function(){a(this).find("li").addBack().each(function(){n=a(this).data("editable")?"denied":"allowed",t="allowed"==n?d.allowLabel:d.denyLabel,n=a('').text(t),a(this).children("a").not(":has(.edit-perms)").append(n)})})}var i=s.trees.base(e,n),r=i.data,d=a.extend(i.config,e||{}),o=i.$el,e=a.inArray("crrm",r.treeConfig.plugins),e=(-1factory->group = new WP_UnitTest_Factory_For_Group( $this->factory ); - - // Create global state programmatically - $this->factory->user->create(array('role'=>'section_editor')); - - } - - public function pre_test_setup() { - $this->timeouts()->implicitWait(5000); - $this->wp->login( $this->settings['login'], $this->settings['password'] ); - } - - // _______________________ TAB/PANEL SWITCHING _______________________ - - /** - * Switching group panels via nav tabs - */ - public function test_load_panels() { - $this->pre_test_setup(); - - $edit_page = new BUSE_EditGroupPage( $this ); - - $edit_page->loadPanel( 'properties' ); - $this->assertTrue( $edit_page->isActivePanel( 'properties' ) ); - - $edit_page->loadPanel( 'members' ); - $this->assertTrue( $edit_page->isActivePanel( 'members' ) ); - - $edit_page->loadPanel( 'permissions' ); - $this->assertTrue( $edit_page->isActivePanel( 'permissions' ) ); - - } - - // _______________________ GROUP CRUD _______________________ - - /* - @todo more tests - - update group - - delete group - - -- NEED TO CONFIRM STATE POST GROUP SAVE/UPDATE - */ - - public function test_create_group() { - $this->pre_test_setup(); - - $group_data = array( - 'name' => 'Test Group - Create Group', - ); - - $edit_page = new BUSE_EditGroupPage( $this ); - $edit_page->setName( $group_data['name'] ); - $edit_page->saveGroup(); - - // Verify via browser - $group_id = self::findGroupIdByName($group_data['name']); - $this->assertNotNull( $group_id ); - - // Verify against plugin API - $groups = BU_Edit_Groups::get_instance(); - $group = $groups->get( $group_id ); - $this->assertEquals( $group_data['name'], $group->name ); - - } - - // _______________________ PROPERTY TESTS _______________________ - - /* - @todo more tests - - attempt to save group with no name - */ - - public function test_group_property_description() { - $this->pre_test_setup(); - - $group = $this->factory->group->create(array('name' => 'Test Group - Property - Description','description' => '')); - $test_description = 'A test description for the group property description test'; - - $edit_page = new BUSE_EditGroupPage( $this, $group->id ); - $edit_page->setDescription( $test_description ); - $edit_page->saveGroup(); - - $this->assertEquals( $test_description, $edit_page->getDescription() ); - - } - - // _______________________ MEMBER TESTS _______________________ - - /* - @todo more tests - - attempt to add non-existant user - - remove member - */ - - /** - * Tests adding user to group - */ - public function test_add_member() { - $this->pre_test_setup(); - - // Add a group first - $group = $this->factory->group->create(array('name' => 'Test Group - Add Member')); - $user_id = $this->factory->user->create(array('user_login' => 'test_editor','role'=>'section_editor')); - - $members_panel = new BUSE_EditGroupMembers( $this, $group->id ); - - $members_panel->addMember( 'test_editor' ); - - // Save group (reloads page as well) - $members_panel->saveGroup(); - - // == Issue == - // Selenium works through the browser session. - // Meanwhile, this code runs in a separate session, so the group fetched during the factory - // creation is cached -- in both the 'option' and 'alloptions' groups. - - // When we change things through Selenium and then attempt to load from the DB, - // we get the cached value (either from memory if we don't reload BU_Edit_Groups, - // or from the options/alloptions object cache if we do). - - // Need to figure out the best way to work around this - // Could be not using the API for verification at all -- stick to markup and keep - // all tests firmly in the selenium browser session and only use plugin API for state generation - // Or maybe there is a better solution. - - // Verify against plugin API -- DOES NOT WORK - // $groups = BU_Edit_Groups::get_instance(); - // $groups->load(); - // $group_after = $groups->get( $group->id ); - // $this->assertContains( $user_id, $group->users ); - - $this->assertTrue( $members_panel->hasMember( 'test_editor' ) ); - - } - - // _______________________ PERMISSION TESTS _______________________ - - /* - @todo Other needed test cases - - pending edits that will be committed on save (hidden input) - - saving group permissions - - perm stats counters - - overlay behavior & text - */ - - /** - * Excercises the Javascript responsible for propogating icon permissions on toggled state - * - * Page tree for testing: - * - * - 1. Parent Post - * `-- 2. Child post - * `-- 3. Grand child post 1 - * `-- 4. Grand child post 2 - */ - public function test_hierarchical_permission_propogation() { - $this->pre_test_setup(); - - $group = $this->factory->group->create( array('name' => 'Test Group - Hierarchical Permissions Propogation' ) ); - - // Generate posts - $pid_one = $this->factory->post->create(array('post_title' => 'Parent page', 'post_type' => 'page' ) ); - $pid_two = $this->factory->post->create(array('post_title' => 'Child page', 'post_parent' => $pid_one, 'post_type' => 'page' ) ); - $pid_three = $this->factory->post->create(array('post_title' => 'Grand child page 1', 'post_parent' => $pid_two, 'post_type' => 'page' ) ); - $pid_four = $this->factory->post->create(array('post_title' => 'Grand child page 2', 'post_parent' => $pid_two, 'post_type' => 'page' ) ); - - $perms_panel = new BUSE_EditGroupPermissions( $this, $group->id ); - - // Switch to page tab and load all pages - $perms_panel->loadPostTypeEditor( 'page' ); - $perms_panel->expandAll(); - - sleep(2); - - // Verify initial state - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); - - // Action: Allow "Parent page" (allow 1) - // Expected Result: 1,2,3,4 should be allowed - $perms_panel->togglePostState( $pid_one ); - - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_four ) ); - - // Action: Deny "Child page" (deny 2) - // Expected Result: 1 should be allowed w/ denied children, 2,3,4 should be denied - $perms_panel->togglePostState( $pid_two ); - - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); - - // Action: Allow "Grand child page 1" - // Expected Result: 1 should be allowed w/ denied children, 2 should be denied w/allowed children, 3 should be allowed, 4 should be denied - $perms_panel->togglePostState( $pid_three ); - - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED_DESC_ALLOWED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); - - // Action: Allow "Grand child post 2" - // Expected Result: 1 should be allowed w/ denied children, 2 should be denied w/ allowed children, 3 and 4 should be allowed - $perms_panel->togglePostState( $pid_four ); - - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED_DESC_ALLOWED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_four ) ); - - // Action: Allow "Child post" - // Expected Result: 1, 2, 3, 4 should be allowed - $perms_panel->togglePostState( $pid_two ); - - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_four ) ); - - // Action: Deny "Grand child page 1" - // Expected Result: 1,2 should be allowed w/ denied children, 3 should be denied, 4 should be allowed - $perms_panel->togglePostState( $pid_three ); - - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_four ) ); - - // Action: Deny "Grand child page 2" - // Expected Result: 1,2 should be allowed w/ denied children, 3,4 should be denied - $perms_panel->togglePostState( $pid_four ); - - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); - - // Action: Deny "Child page" - // Expected Result: 1 should be allowed w/ denied children, 2,3,4 should be denied - $perms_panel->togglePostState( $pid_two ); - - $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); - - // Action: Deny "Parent page" - // Expected Result: 1,2,3,4 should be denied - $perms_panel->togglePostState( $pid_one ); - - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_one ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_two ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); - $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); - - } - - // _____________________HELPERS_______________________ - - /** - * Find group ID by looking at the edit group link found on the section groups page - */ - protected function findGroupIdByName( $name) { - $this->pre_test_setup(); - - $group_id = null; - - // Fetch group ID from edit link URL - $groups_page = new BUSE_GroupsPage( $this ); - - $edit_link = $this->byLinkText( $name ); - - if( isset( $edit_link ) ) { - $url = $edit_link->attribute('href'); - $parts = parse_url( $url ); - $args = wp_parse_args( $parts['query'] ); - $group_id = $args['id']; - - } - - return $group_id; - - } - -} - -/** - * Page objects for group editor interface - * - * @todo - * - better isolate markup/url dependencies in to constants - */ - -/** - * Section groups list page - */ -class BUSE_GroupsPage { - - private $webdriver = null; - - const MANAGE_GROUPS_URL = '/wp-admin/admin.php?page=buse_edit_groups'; - - function __construct( $webdriver ) { - $this->webdriver = $webdriver; - - $this->webdriver->url( self::MANAGE_GROUPS_URL ); - - $page_title = $this->webdriver->title(); - - if( strpos( $this->webdriver->title(), 'Section Group' ) === false ) - throw new Exception('Section Groups page failed to load -- unable to load URL: ' . $request_url ); - } - -} - -/** - * Add/Edit section group page - */ -class BUSE_EditGroupPage { - - protected $webdriver = null; - protected $group_form = null; - - /* Markup constants */ - - const ADD_GROUP_URL = '/wp-admin/admin.php?page=buse_new_group'; - - // Forms - const GROUP_EDIT_FORM = 'group-edit-form'; - const GROUP_NAME_INPUT = 'group[name]'; - const GROUP_DESC_INPUT = 'group[description]'; - const GROUP_ADD_MEMBER_INPUT = 'user_login'; - const GROUP_ADD_MEMBER_BTN = 'add_member'; - - // Tabs & panels - const NAV_TAB_CLASS = 'nav-tab'; - const PANEL_CLASS = 'group-panel'; - - const ACTIVE_TAB_CLASS = 'nav-tab-active'; - const ACTIVE_PANEL_CLASS = 'active'; - - const PROPERTIES_TAB = 'nav-tab-properties'; - const MEMBERS_TAB = 'nav-tab-members'; - const PERMISSIONS_TAB = 'nav-tab-permissions'; - - const PROPERTIES_PANEL = 'group-properties-panel'; - const MEMBERS_PANEL = 'group-members-panel'; - const PERMISSIONS_PANEL = 'group-permissions-panel'; - - /** - * Loads the add or edit group page, depending on group ID arg - * - * @todo make URL generation more flexible - */ - function __construct( $webdriver, $group_id = null ) { - $this->webdriver = $webdriver; - - // Generate request URL - $action_str = $group_str =''; - - if( is_null( $group_id ) ) { - $request_url = self::ADD_GROUP_URL; - } else { - $request_url = BUSE_GroupsPage::MANAGE_GROUPS_URL . '&id=' . $group_id; - } - - $this->webdriver->url( $request_url ); - - $page_title = $this->webdriver->title(); - - if( strpos( $page_title, 'Section Group' ) === false ) - throw new Exception('Edit Group Page failed to load -- Unable to load URL: ' . $request_url ); - - $this->group_form = new SeleniumFormHelper( $this->webdriver, self::GROUP_EDIT_FORM ); - - } - - function loadPanel( $name ) { - - $tab_id = self::PROPERTIES_TAB; - - switch( strtolower( $name ) ) { - case 'members': - $tab_id = self::MEMBERS_TAB; - break; - case 'permissions': - $tab_id = self::PERMISSIONS_TAB; - break; - case 'properties': default: - $tab_id = self::PROPERTIES_TAB; - break; - } - - $tab = $this->webdriver->byId( $tab_id ); - $tab->click(); - - } - - function isActivePanel( $name ) { - - $panel_id = null; - - switch( strtolower( $name ) ) { - case 'members': - $panel_id = self::MEMBERS_PANEL; - break; - case 'permissions': - $panel_id = self::PERMISSIONS_PANEL; - break; - case 'properties': - $panel_id = self::PROPERTIES_PANEL; - break; - } - - if( is_null( $panel_id ) ) - return false; - - $panel = $this->webdriver->byId( $panel_id ); - - if( isset( $panel ) && strpos( $panel->attribute('class'), self::ACTIVE_PANEL_CLASS ) !== false ) - return true; - - return false; - - } - - function setName( $name ) { - - $this->loadPanel( 'properties' ); - $this->group_form->populateFields( array( self::GROUP_NAME_INPUT => array( 'type' => 'text', 'value' => $name ) ) ); - - } - - function setDescription( $description ) { - - $this->loadPanel( 'properties' ); - $this->group_form->populateFields( array( self::GROUP_DESC_INPUT => array( 'type' => 'textarea', 'value' => $description ) ) ); - - } - - function getName() { - - $this->loadPanel( 'properties' ); - $name_input = $this->webdriver->byName( self::GROUP_NAME_INPUT ); - - if( isset( $name_input ) ) - return $name_input->attribute('value'); - - return false; - - } - - function getDescription() { - - $this->loadPanel( 'properties' ); - $desc_input = $this->webdriver->byName( self::GROUP_DESC_INPUT ); - - if( isset( $desc_input ) ) - return $desc_input->attribute('value'); - - return false; - - } - - function saveGroup() { - - $this->group_form->submit(); - - } - -} - -/** - * Add/Edit section group page, members panel - */ -class BUSE_EditGroupMembers extends BUSE_EditGroupPage { - - const ACTIVE_MEMBER_XPATH = "//li[contains(@class,'member') and contains(@class,'active')]//label[text()='%s']"; - - function __construct( $webdriver, $group_id = null ) { - - parent::__construct( $webdriver, $group_id ); - - $this->loadPanel( 'members' ); - - } - - function addMember( $login ) { - - $this->group_form->populateFields( array( self::GROUP_ADD_MEMBER_INPUT => array( 'type' => 'text', 'value' => $login ) ) ); - - $add_btn = $this->webdriver->byId( self::GROUP_ADD_MEMBER_BTN ); - $add_btn->click(); - - // Verify member has been added before continuing (AJAX call is utilized) - $xpath = sprintf(self::ACTIVE_MEMBER_XPATH,$login); - $this->webdriver->byXpath( $xpath ); - - } - - // @todo allow for either login or ID - function removeMember( $id ) { - - if( is_numeric($id) ) { - // @todo don't hard code remove_member - $remove_btn = $this->webdriver->byId( '#remove_member_' . $id ); - $remove_btn->click(); - } else { - // @todo find remove link based on display name label (xpath) - } - - } - - function hasMember( $login ) { - - $xpath = sprintf(self::ACTIVE_MEMBER_XPATH,$login); - $member_row = $this->webdriver->byXpath( $xpath ); - - if( isset( $member_row ) ) - return true; - - return false; - - } - -} - -/** - * Add/Edit group page, permissions panel - */ -class BUSE_EditGroupPermissions extends BUSE_EditGroupPage { - - const STATE_ALLOWED = 'allowed'; - const STATE_DENIED = 'denied'; - const STATE_ALLOWED_DESC_DENIED = 'allowed-desc-denied'; - const STATE_DENIED_DESC_ALLOWED = 'denied-desc-allowed'; - - function __construct( $webdriver, $group_id = null ) { - - parent::__construct( $webdriver, $group_id ); - - $this->loadPanel( 'permissions' ); - - } - - function loadPostTypeEditor( $name ) { - - $tab = $this->webdriver->byId( 'perm-panel-' . $name ); - $tab->click(); - - } - - function expandAll() { - - $link = $this->webdriver->byCssSelector( '.group-panel.active .perm-tree-expand' ); - $link->click(); - - } - - function togglePostState( $id ) { - - // Select post - $post_link = $this->webdriver->byCssSelector( '#p' . $id . ' > a' ); - $post_link->click(); - - // Click action button - $action_link = $this->webdriver->byCssSelector( '#p' . $id . ' .edit-perms' ); - $action_link->click(); - - } - - function getPostState( $id ) { - - $post_link = $this->webdriver->byId( 'p' . $id ); - return $post_link->attribute('rel'); - - } - -} - +factory->group = new WP_UnitTest_Factory_For_Group( $this->factory ); + + // Create global state programmatically + $this->factory->user->create(array('role'=>'section_editor')); + + } + + public function pre_test_setup() { + $this->timeouts()->implicitWait(5000); + $this->wp->login( $this->settings['login'], $this->settings['password'] ); + } + + // _______________________ TAB/PANEL SWITCHING _______________________ + + /** + * Switching group panels via nav tabs + */ + public function test_load_panels() { + $this->pre_test_setup(); + + $edit_page = new BUSE_EditGroupPage( $this ); + + $edit_page->loadPanel( 'properties' ); + $this->assertTrue( $edit_page->isActivePanel( 'properties' ) ); + + $edit_page->loadPanel( 'members' ); + $this->assertTrue( $edit_page->isActivePanel( 'members' ) ); + + $edit_page->loadPanel( 'permissions' ); + $this->assertTrue( $edit_page->isActivePanel( 'permissions' ) ); + + } + + // _______________________ GROUP CRUD _______________________ + + /* + @todo more tests + - update group + - delete group + + -- NEED TO CONFIRM STATE POST GROUP SAVE/UPDATE + */ + + public function test_create_group() { + $this->pre_test_setup(); + + $group_data = array( + 'name' => 'Test Group - Create Group', + ); + + $edit_page = new BUSE_EditGroupPage( $this ); + $edit_page->setName( $group_data['name'] ); + $edit_page->saveGroup(); + + // Verify via browser + $group_id = self::findGroupIdByName($group_data['name']); + $this->assertNotNull( $group_id ); + + // Verify against plugin API + $groups = BU_Edit_Groups::get_instance(); + $group = $groups->get( $group_id ); + $this->assertEquals( $group_data['name'], $group->name ); + + } + + // _______________________ PROPERTY TESTS _______________________ + + /* + @todo more tests + - attempt to save group with no name + */ + + public function test_group_property_description() { + $this->pre_test_setup(); + + $group = $this->factory->group->create(array('name' => 'Test Group - Property - Description','description' => '')); + $test_description = 'A test description for the group property description test'; + + $edit_page = new BUSE_EditGroupPage( $this, $group->id ); + $edit_page->setDescription( $test_description ); + $edit_page->saveGroup(); + + $this->assertEquals( $test_description, $edit_page->getDescription() ); + + } + + // _______________________ MEMBER TESTS _______________________ + + /* + @todo more tests + - attempt to add non-existant user + - remove member + */ + + /** + * Tests adding user to group + */ + public function test_add_member() { + $this->pre_test_setup(); + + // Add a group first + $group = $this->factory->group->create(array('name' => 'Test Group - Add Member')); + $user_id = $this->factory->user->create(array('user_login' => 'test_editor','role'=>'section_editor')); + + $members_panel = new BUSE_EditGroupMembers( $this, $group->id ); + + $members_panel->addMember( 'test_editor' ); + + // Save group (reloads page as well) + $members_panel->saveGroup(); + + // == Issue == + // Selenium works through the browser session. + // Meanwhile, this code runs in a separate session, so the group fetched during the factory + // creation is cached -- in both the 'option' and 'alloptions' groups. + + // When we change things through Selenium and then attempt to load from the DB, + // we get the cached value (either from memory if we don't reload BU_Edit_Groups, + // or from the options/alloptions object cache if we do). + + // Need to figure out the best way to work around this + // Could be not using the API for verification at all -- stick to markup and keep + // all tests firmly in the selenium browser session and only use plugin API for state generation + // Or maybe there is a better solution. + + // Verify against plugin API -- DOES NOT WORK + // $groups = BU_Edit_Groups::get_instance(); + // $groups->load(); + // $group_after = $groups->get( $group->id ); + // $this->assertContains( $user_id, $group->users ); + + $this->assertTrue( $members_panel->hasMember( 'test_editor' ) ); + + } + + // _______________________ PERMISSION TESTS _______________________ + + /* + @todo Other needed test cases + - pending edits that will be committed on save (hidden input) + - saving group permissions + - perm stats counters + - overlay behavior & text + */ + + /** + * Excercises the Javascript responsible for propogating icon permissions on toggled state + * + * Page tree for testing: + * + * - 1. Parent Post + * `-- 2. Child post + * `-- 3. Grand child post 1 + * `-- 4. Grand child post 2 + */ + public function test_hierarchical_permission_propogation() { + $this->pre_test_setup(); + + $group = $this->factory->group->create( array('name' => 'Test Group - Hierarchical Permissions Propogation' ) ); + + // Generate posts + $pid_one = $this->factory->post->create(array('post_title' => 'Parent page', 'post_type' => 'page' ) ); + $pid_two = $this->factory->post->create(array('post_title' => 'Child page', 'post_parent' => $pid_one, 'post_type' => 'page' ) ); + $pid_three = $this->factory->post->create(array('post_title' => 'Grand child page 1', 'post_parent' => $pid_two, 'post_type' => 'page' ) ); + $pid_four = $this->factory->post->create(array('post_title' => 'Grand child page 2', 'post_parent' => $pid_two, 'post_type' => 'page' ) ); + + $perms_panel = new BUSE_EditGroupPermissions( $this, $group->id ); + + // Switch to page tab and load all pages + $perms_panel->loadPostTypeEditor( 'page' ); + $perms_panel->expandAll(); + + sleep(2); + + // Verify initial state + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); + + // Action: Allow "Parent page" (allow 1) + // Expected Result: 1,2,3,4 should be allowed + $perms_panel->togglePostState( $pid_one ); + + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_four ) ); + + // Action: Deny "Child page" (deny 2) + // Expected Result: 1 should be allowed w/ denied children, 2,3,4 should be denied + $perms_panel->togglePostState( $pid_two ); + + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); + + // Action: Allow "Grand child page 1" + // Expected Result: 1 should be allowed w/ denied children, 2 should be denied w/allowed children, 3 should be allowed, 4 should be denied + $perms_panel->togglePostState( $pid_three ); + + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED_DESC_ALLOWED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); + + // Action: Allow "Grand child post 2" + // Expected Result: 1 should be allowed w/ denied children, 2 should be denied w/ allowed children, 3 and 4 should be allowed + $perms_panel->togglePostState( $pid_four ); + + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED_DESC_ALLOWED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_four ) ); + + // Action: Allow "Child post" + // Expected Result: 1, 2, 3, 4 should be allowed + $perms_panel->togglePostState( $pid_two ); + + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_four ) ); + + // Action: Deny "Grand child page 1" + // Expected Result: 1,2 should be allowed w/ denied children, 3 should be denied, 4 should be allowed + $perms_panel->togglePostState( $pid_three ); + + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED, $perms_panel->getPostState( $pid_four ) ); + + // Action: Deny "Grand child page 2" + // Expected Result: 1,2 should be allowed w/ denied children, 3,4 should be denied + $perms_panel->togglePostState( $pid_four ); + + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); + + // Action: Deny "Child page" + // Expected Result: 1 should be allowed w/ denied children, 2,3,4 should be denied + $perms_panel->togglePostState( $pid_two ); + + $this->assertEquals( BUSE_EditGroupPermissions::STATE_ALLOWED_DESC_DENIED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); + + // Action: Deny "Parent page" + // Expected Result: 1,2,3,4 should be denied + $perms_panel->togglePostState( $pid_one ); + + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_one ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_two ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_three ) ); + $this->assertEquals( BUSE_EditGroupPermissions::STATE_DENIED, $perms_panel->getPostState( $pid_four ) ); + + } + + // _____________________HELPERS_______________________ + + /** + * Find group ID by looking at the edit group link found on the section groups page + */ + protected function findGroupIdByName( $name) { + $this->pre_test_setup(); + + $group_id = null; + + // Fetch group ID from edit link URL + $groups_page = new BUSE_GroupsPage( $this ); + + $edit_link = $this->byLinkText( $name ); + + if( isset( $edit_link ) ) { + $url = $edit_link->attribute('href'); + $parts = parse_url( $url ); + $args = wp_parse_args( $parts['query'] ); + $group_id = $args['id']; + + } + + return $group_id; + + } + +} + +/** + * Page objects for group editor interface + * + * @todo + * - better isolate markup/url dependencies in to constants + */ + +/** + * Section groups list page + */ +class BUSE_GroupsPage { + + private $webdriver = null; + + const MANAGE_GROUPS_URL = '/wp-admin/admin.php?page=buse_edit_groups'; + + function __construct( $webdriver ) { + $this->webdriver = $webdriver; + + $this->webdriver->url( self::MANAGE_GROUPS_URL ); + + $page_title = $this->webdriver->title(); + + if( strpos( $this->webdriver->title(), 'Section Group' ) === false ) + throw new Exception('Section Groups page failed to load -- unable to load URL: ' . esc_html($request_url, 'bu-section-editing') ); + } + +} + +/** + * Add/Edit section group page + */ +class BUSE_EditGroupPage { + + protected $webdriver = null; + protected $group_form = null; + + /* Markup constants */ + + const ADD_GROUP_URL = '/wp-admin/admin.php?page=buse_new_group'; + + // Forms + const GROUP_EDIT_FORM = 'group-edit-form'; + const GROUP_NAME_INPUT = 'group[name]'; + const GROUP_DESC_INPUT = 'group[description]'; + const GROUP_ADD_MEMBER_INPUT = 'user_login'; + const GROUP_ADD_MEMBER_BTN = 'add_member'; + + // Tabs & panels + const NAV_TAB_CLASS = 'nav-tab'; + const PANEL_CLASS = 'group-panel'; + + const ACTIVE_TAB_CLASS = 'nav-tab-active'; + const ACTIVE_PANEL_CLASS = 'active'; + + const PROPERTIES_TAB = 'nav-tab-properties'; + const MEMBERS_TAB = 'nav-tab-members'; + const PERMISSIONS_TAB = 'nav-tab-permissions'; + + const PROPERTIES_PANEL = 'group-properties-panel'; + const MEMBERS_PANEL = 'group-members-panel'; + const PERMISSIONS_PANEL = 'group-permissions-panel'; + + /** + * Loads the add or edit group page, depending on group ID arg + * + * @todo make URL generation more flexible + */ + function __construct( $webdriver, $group_id = null ) { + $this->webdriver = $webdriver; + + // Generate request URL + $action_str = $group_str =''; + + if( is_null( $group_id ) ) { + $request_url = self::ADD_GROUP_URL; + } else { + $request_url = BUSE_GroupsPage::MANAGE_GROUPS_URL . '&id=' . $group_id; + } + + $this->webdriver->url( $request_url ); + + $page_title = $this->webdriver->title(); + + if( strpos( $page_title, 'Section Group' ) === false ) + throw new Exception('Edit Group Page failed to load -- Unable to load URL: ' . esc_html($request_url, 'bu-section-editing') ); + + $this->group_form = new SeleniumFormHelper( $this->webdriver, self::GROUP_EDIT_FORM ); + + } + + function loadPanel( $name ) { + + $tab_id = self::PROPERTIES_TAB; + + switch( strtolower( $name ) ) { + case 'members': + $tab_id = self::MEMBERS_TAB; + break; + case 'permissions': + $tab_id = self::PERMISSIONS_TAB; + break; + case 'properties': default: + $tab_id = self::PROPERTIES_TAB; + break; + } + + $tab = $this->webdriver->byId( $tab_id ); + $tab->click(); + + } + + function isActivePanel( $name ) { + + $panel_id = null; + + switch( strtolower( $name ) ) { + case 'members': + $panel_id = self::MEMBERS_PANEL; + break; + case 'permissions': + $panel_id = self::PERMISSIONS_PANEL; + break; + case 'properties': + $panel_id = self::PROPERTIES_PANEL; + break; + } + + if( is_null( $panel_id ) ) + return false; + + $panel = $this->webdriver->byId( $panel_id ); + + if( isset( $panel ) && strpos( $panel->attribute('class'), self::ACTIVE_PANEL_CLASS ) !== false ) + return true; + + return false; + + } + + function setName( $name ) { + + $this->loadPanel( 'properties' ); + $this->group_form->populateFields( array( self::GROUP_NAME_INPUT => array( 'type' => 'text', 'value' => $name ) ) ); + + } + + function setDescription( $description ) { + + $this->loadPanel( 'properties' ); + $this->group_form->populateFields( array( self::GROUP_DESC_INPUT => array( 'type' => 'textarea', 'value' => $description ) ) ); + + } + + function getName() { + + $this->loadPanel( 'properties' ); + $name_input = $this->webdriver->byName( self::GROUP_NAME_INPUT ); + + if( isset( $name_input ) ) + return $name_input->attribute('value'); + + return false; + + } + + function getDescription() { + + $this->loadPanel( 'properties' ); + $desc_input = $this->webdriver->byName( self::GROUP_DESC_INPUT ); + + if( isset( $desc_input ) ) + return $desc_input->attribute('value'); + + return false; + + } + + function saveGroup() { + + $this->group_form->submit(); + + } + +} + +/** + * Add/Edit section group page, members panel + */ +class BUSE_EditGroupMembers extends BUSE_EditGroupPage { + + const ACTIVE_MEMBER_XPATH = "//li[contains(@class,'member') and contains(@class,'active')]//label[text()='%s']"; + + function __construct( $webdriver, $group_id = null ) { + + parent::__construct( $webdriver, $group_id ); + + $this->loadPanel( 'members' ); + + } + + function addMember( $login ) { + + $this->group_form->populateFields( array( self::GROUP_ADD_MEMBER_INPUT => array( 'type' => 'text', 'value' => $login ) ) ); + + $add_btn = $this->webdriver->byId( self::GROUP_ADD_MEMBER_BTN ); + $add_btn->click(); + + // Verify member has been added before continuing (AJAX call is utilized) + $xpath = sprintf(self::ACTIVE_MEMBER_XPATH,$login); + $this->webdriver->byXpath( $xpath ); + + } + + // @todo allow for either login or ID + function removeMember( $id ) { + + if( is_numeric($id) ) { + // @todo don't hard code remove_member + $remove_btn = $this->webdriver->byId( '#remove_member_' . $id ); + $remove_btn->click(); + } else { + // @todo find remove link based on display name label (xpath) + } + + } + + function hasMember( $login ) { + + $xpath = sprintf(self::ACTIVE_MEMBER_XPATH,$login); + $member_row = $this->webdriver->byXpath( $xpath ); + + if( isset( $member_row ) ) + return true; + + return false; + + } + +} + +/** + * Add/Edit group page, permissions panel + */ +class BUSE_EditGroupPermissions extends BUSE_EditGroupPage { + + const STATE_ALLOWED = 'allowed'; + const STATE_DENIED = 'denied'; + const STATE_ALLOWED_DESC_DENIED = 'allowed-desc-denied'; + const STATE_DENIED_DESC_ALLOWED = 'denied-desc-allowed'; + + function __construct( $webdriver, $group_id = null ) { + + parent::__construct( $webdriver, $group_id ); + + $this->loadPanel( 'permissions' ); + + } + + function loadPostTypeEditor( $name ) { + + $tab = $this->webdriver->byId( 'perm-panel-' . $name ); + $tab->click(); + + } + + function expandAll() { + + $link = $this->webdriver->byCssSelector( '.group-panel.active .perm-tree-expand' ); + $link->click(); + + } + + function togglePostState( $id ) { + + // Select post + $post_link = $this->webdriver->byCssSelector( '#p' . $id . ' > a' ); + $post_link->click(); + + // Click action button + $action_link = $this->webdriver->byCssSelector( '#p' . $id . ' .edit-perms' ); + $action_link->click(); + + } + + function getPostState( $id ) { + + $post_link = $this->webdriver->byId( 'p' . $id ); + return $post_link->attribute('rel'); + + } + +} + ?> \ No newline at end of file