Skip to content

Commit

Permalink
Filters Doc permalinks for more reliable Admin linkage. Replaces Rece…
Browse files Browse the repository at this point in the history
…nt Comments dashboard widget to protect non-public Doc comments from being visible to certain members. Fixes #115

git-svn-id: http://plugins.svn.wordpress.org/buddypress-docs/trunk@412207 b8457f37-d9ea-0310-8a92-e5e31aec5664
  • Loading branch information
boonebgorges committed Jul 19, 2011
1 parent f4fdf57 commit 8bb4820
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 12 deletions.
9 changes: 8 additions & 1 deletion bp-docs.php
Expand Up @@ -127,6 +127,10 @@ function load_constants() {
// The slug used when deleting a doc
if ( !defined( 'BP_DOCS_DELETE_SLUG' ) )
define( 'BP_DOCS_DELETE_SLUG', 'delete' );

// By default, BP Docs will replace the Recent Comments WP Dashboard Widget
if ( !defined( 'BP_DOCS_REPLACE_RECENT_COMMENTS_DASHBOARD_WIDGET' ) )
define( 'BP_DOCS_REPLACE_RECENT_COMMENTS_DASHBOARD_WIDGET', true );
}

/**
Expand Down Expand Up @@ -203,7 +207,6 @@ function register_post_type() {
'hierarchical' => false,
'supports' => array( 'title', 'editor', 'revisions', 'excerpt', 'comments' ),
'query_var' => true,
//'rewrite' => false
'rewrite' => false // Todo: This bites
) );

Expand Down Expand Up @@ -277,6 +280,10 @@ function includes() {

// formatting.php contains filters and functions used to modify appearance only
require_once( BP_DOCS_INCLUDES_PATH . 'formatting.php' );

// Dashboard-specific functions
if ( is_admin() )
require_once( BP_DOCS_INCLUDES_PATH . 'admin.php' );
}

/**
Expand Down
146 changes: 146 additions & 0 deletions includes/admin.php
@@ -0,0 +1,146 @@
<?php

/**
* Dashboard functions for BuddyPress Docs
*
* @package BuddyPress Docs
* @since 1.1.8
*/

class BP_Docs_Admin {
/**
* PHP 4 constructor
*
* @package BuddyPress Docs
* @since 1.1.8
*/
function bp_docs_admin() {
$this->__construct();
}

/**
* PHP 5 constructor
*
* @package BuddyPress Docs
* @since 1.1.8
*/
function __construct() {
// Replace the Dashboard widget
if ( !defined( BP_DOCS_REPLACE_RECENT_COMMENTS_DASHBOARD_WIDGET ) || !BP_DOCS_REPLACE_RECENT_COMMENTS_DASHBOARD_WIDGET ) {
add_action( 'wp_dashboard_setup', array( $this, 'replace_recent_comments_dashboard_widget' ) );
}
}

function replace_recent_comments_dashboard_widget() {
global $wp_meta_boxes;

// Find the recent comments widget
foreach ( $wp_meta_boxes['dashboard'] as $context => $widgets ) {
if ( array_key_exists( 'dashboard_recent_comments', $widgets['core'] ) ) {
// Take note of the context for when we add our widget
$drc_widget_context = $context;

// Store the widget so that we have access to its information
$drc_widget = $widgets['core']['dashboard_recent_comments'];

// Store the array keys, so that we can reorder things later
$widget_order = array_keys( $widgets['core'] );

// Remove the core widget
remove_meta_box( 'dashboard_recent_comments', 'dashboard', $drc_widget_context );

// No need to continue the loop
break;
}
}

// If we couldn't find the recent comments widget, it must have been removed. We'll
// assume this means we shouldn't add our own
if ( empty( $drc_widget ) )
return;

// Set up and add our widget
$recent_comments_title = __( 'Recent Comments' );

// Add our widget in the same location
wp_add_dashboard_widget( 'dashboard_recent_comments_bp_docs', $recent_comments_title, array( $this, 'wp_dashboard_recent_comments' ), 'wp_dashboard_recent_comments_control' );

// Restore the previous widget order. File this under "good citizenship"
$wp_meta_boxes['dashboard'][$context]['core']['dashboard_recent_comments'] = $wp_meta_boxes['dashboard'][$context]['core']['dashboard_recent_comments_bp_docs'];

unset( $wp_meta_boxes['dashboard'][$context]['core']['dashboard_recent_comments_bp_docs'] );

// In order to inherit the styles, we're going to spoof the widget ID. Sadness
$wp_meta_boxes['dashboard'][$context]['core']['dashboard_recent_comments']['id'] = 'dashboard_recent_comments';
}

/**
* Replicates WP's native recent comments dashboard widget.
*
* @package BuddyPress Docs
* @since 1.1.8
*/
function wp_dashboard_recent_comments() {
global $wpdb, $bp;

if ( current_user_can('edit_posts') )
$allowed_states = array('0', '1');
else
$allowed_states = array('1');

// Select all comment types and filter out spam later for better query performance.
$comments = array();
$start = 0;

$widgets = get_option( 'dashboard_widget_options' );
$total_items = isset( $widgets['dashboard_recent_comments'] ) && isset( $widgets['dashboard_recent_comments']['items'] )
? absint( $widgets['dashboard_recent_comments']['items'] ) : 5;

while ( count( $comments ) < $total_items && $possible = $wpdb->get_results( "SELECT c.*, p.post_type AS comment_post_post_type FROM $wpdb->comments c LEFT JOIN $wpdb->posts p ON c.comment_post_ID = p.ID WHERE p.post_status != 'trash' ORDER BY c.comment_date_gmt DESC LIMIT $start, 50" ) ) {

foreach ( $possible as $comment ) {
if ( count( $comments ) >= $total_items )
break;

// Is the user allowed to read this doc?
if ( $bp->bp_docs->post_type_name == $comment->comment_post_post_type && !bp_docs_user_can( 'read', get_current_user_ID(), $comment->comment_post_ID ) )
continue;

if ( in_array( $comment->comment_approved, $allowed_states ) && current_user_can( 'read_post', $comment->comment_post_ID ) )
$comments[] = $comment;
}

$start = $start + 50;
}

if ( $comments ) :
?>

<div id="the-comment-list" class="list:comment">
<?php
foreach ( $comments as $comment )
_wp_dashboard_recent_comments_row( $comment );
?>

</div>

<?php
if ( current_user_can('edit_posts') ) { ?>
<?php _get_list_table('WP_Comments_List_Table')->views(); ?>
<?php }

wp_comment_reply( -1, false, 'dashboard', false );
wp_comment_trashnotice();

else :
?>

<p><?php _e( 'No comments yet.' ); ?></p>

<?php
endif; // $comments;
}
}
$bp_docs_admin = new BP_Docs_Admin;

?>
32 changes: 32 additions & 0 deletions includes/integration-bp.php
Expand Up @@ -60,6 +60,9 @@ function __construct() {
// Keep comment notifications from being sent
add_filter( 'comment_post', array( $this, 'check_comment_type' ) );

// Make sure that comment links are correct. Can't use $wp_rewrite bc of assoc items
add_filter( 'post_type_link', array( $this, 'filter_permalinks' ), 10, 4 );

// AJAX handler for removing the edit lock when a user clicks away from Edit mode
add_action( 'wp_ajax_remove_edit_lock', array( $this, 'remove_edit_lock' ) );

Expand Down Expand Up @@ -596,6 +599,35 @@ function check_comment_type( $comment_id ) {
}
}

/**
* Display the proper permalink for Docs
*
* This function filters 'post_type_link', which in turn powers get_permalink() and related
* functions.
*
* In brief, the purpose is to make sure that Doc permalinks point to the proper place.
* Ideally I would use a rewrite rule to accomplish this, but it's impossible to write
* regex that will be able to tell which group/user a Doc should be associated with.
*
* @package BuddyPress Docs
* @since 1.1.8
*
* @param str $link The permalink
* @param obj $post The post object
* @param bool $leavename
* @param bool $sample See get_post_permalink() for an explanation of these two params
* @return str $link The filtered permalink
*/
function filter_permalinks( $link, $post, $leavename, $sample ) {
global $bp;

if ( $bp->bp_docs->post_type_name == $post->post_type ) {
$link = bp_docs_get_doc_link( $post->ID );
}

return $link;
}

/**
* AJAX handler for remove_edit_lock option
*
Expand Down
103 changes: 93 additions & 10 deletions includes/integration-groups.php
Expand Up @@ -53,7 +53,7 @@ function __construct() {
add_action( 'bp_docs_taxonomy_save_item_terms', array( $this, 'save_group_terms' ) );

// Filter the core user_can_edit function for group-specific functionality
add_filter( 'bp_docs_user_can', array( $this, 'user_can' ), 10, 3 );
add_filter( 'bp_docs_user_can', array( $this, 'user_can' ), 10, 4 );

// Add group-specific settings to the doc settings box
add_filter( 'bp_docs_doc_settings_markup', array( $this, 'doc_settings_markup' ) );
Expand Down Expand Up @@ -208,29 +208,39 @@ function save_group_terms( $terms ) {
}

/**
* Determine whether a user can edit the group doc is question
* Determine whether a user can edit the group doc in question
*
* @package BuddyPress Docs
* @since 1.0-beta
*
* @param bool $user_can The default perms passed from bp_docs_user_can_edit()
* @param str $action At the moment, 'edit', 'manage', 'create'
* @param str $action At the moment, 'edit', 'manage', 'create', 'read'
* @param int $user_id The user id whose perms are being tested
* @param int $doc_id Optional. The id of the doc being checked. Defaults to current
*/
function user_can( $user_can, $action, $user_id ) {
function user_can( $user_can, $action, $user_id, $doc_id = false ) {
global $bp, $post;

$user_can = false;

// If a doc_id is provided, check it against the current post before querying
if ( $doc_id && isset( $post->ID ) && $doc_id == $post->ID ) {
$doc = $post;
}

if ( empty( $post->ID ) )
$post = !empty( $bp->bp_docs->current_post ) ? $bp->bp_docs->current_post : false;
$doc = !empty( $bp->bp_docs->current_post ) ? $bp->bp_docs->current_post : false;

// Keep on trying to set up a post
if ( empty( $post->ID ) )
$post = bp_docs_get_current_doc();
if ( empty( $doc ) )
$doc = bp_docs_get_current_doc();

// If we still haven't got a post by now, query based on doc id
if ( empty( $doc ) )
$doc = get_post( $doc_id );

if ( !empty( $post->ID ) ) {
$doc_settings = get_post_meta( $post->ID, 'bp_docs_settings', true );
if ( !empty( $doc ) ) {
$doc_settings = get_post_meta( $doc->ID, 'bp_docs_settings', true );

// Manage settings don't always get set on doc creation, so we need a default
if ( empty( $doc_settings['manage'] ) )
Expand All @@ -245,9 +255,33 @@ function user_can( $user_can, $action, $user_id ) {
$doc_settings['read_comments'] = 'anyone';
}

$group_id = $bp->groups->current_group->id;
// Default to the current group, but get the associated doc if not
if ( isset( $bp->groups->current_group->id ) ) {
$group_id = $bp->groups->current_group->id;
$group = $bp->groups->current_group;
} else {
$group_id = bp_docs_get_associated_group_id( $doc->ID, $doc );

if ( is_array( $group_id ) ) {
$group_id = $group_id[0]; // todo: make this a loop
$group = new BP_Groups_Group( $group_id );
}
}

switch ( $action ) {
case 'read' :
// At the moment, read permissions are entirely based on group
// membership and privacy level
if ( 'public' != $group->status ) {
if ( groups_is_user_member( $user_id, $group_id ) ) {
$user_can = true;
}
} else {
$user_can = true;
}

break;

case 'create' :
$group_settings = groups_get_groupmeta( $group_id, 'bp-docs' );

Expand Down Expand Up @@ -1090,4 +1124,53 @@ function bp_docs_is_docs_enabled_for_group( $group_id = false ) {
return apply_filters( 'bp_docs_is_docs_enabled_for_group', $docs_is_enabled, $group_id );
}

/**
* Get the group associated with a Doc
*
* In order to be forward-compatible, this function will return an array when more than one group
* is found.
*
* @package BuddyPress Docs
* @since 1.1.8
*
* @param int $doc_id The id of the Doc
* @param obj $doc The Doc post object. If you've already got this, send it along to avoid another
* query
* @param bool $single_array This is a funky one. If only a single group_id is found, should it be
* returned as a singleton array, or as an int? Defaults to the latter.
* @return mixed $group_id Either an array or a string of the group id(s)
*/
function bp_docs_get_associated_group_id( $doc_id, $doc = false, $single_array = false ) {
global $bp;

if ( !$doc ) {
$doc = get_post( $doc_id );
}

if ( !$doc ) {
return false;
}

$post_terms = wp_get_post_terms( $doc_id, $bp->bp_docs->associated_item_tax_name );

$group_ids = array();

foreach( $post_terms as $post_term ) {
// Make sure this is a group term
$parent_term = get_term( $post_term->parent, $bp->bp_docs->associated_item_tax_name );

if ( 'group' == $parent_term->slug ) {
$group_ids[] = $post_term->name;
}
}

if ( !$single_array && ( count( $group_ids ) <= 1 ) ) {
$return = implode( ',', $group_ids );
} else {
$return = $group_ids;
}

return apply_filters( 'bp_docs_get_associated_group_id', $group_ids, $doc_id, $doc, $single_array );
}

?>
2 changes: 1 addition & 1 deletion includes/templatetags.php
Expand Up @@ -400,7 +400,7 @@ function bp_docs_user_can( $action = 'edit', $user_id = false, $doc_id = false )
$user_id = bp_loggedin_user_id();

// Only certain actions are checked against doc_ids
$need_doc_ids_actions = apply_filters( 'bp_docs_need_doc_ids_actions', array( 'edit', 'manage', 'view_history' ) );
$need_doc_ids_actions = apply_filters( 'bp_docs_need_doc_ids_actions', array( 'edit', 'manage', 'view_history', 'read' ) );

if ( in_array( $action, $need_doc_ids_actions ) ) {
if ( !$doc_id ) {
Expand Down
2 changes: 2 additions & 0 deletions readme.txt
Expand Up @@ -36,6 +36,8 @@ This plugin is in active development. For feature requests and bug reports, visi
== Changelog ==

= 1.1.8 =
* Filters get_post_permalink() so that Doc permalinks in the Admin point to the proper place
* Modifies Recent Comments dashboard widget in order to prevent non-allowed people from seeing certain Doc comments
* Adds Print button to TinyMCE
* Adds Brazilian Portuguese localization.

Expand Down

0 comments on commit 8bb4820

Please sign in to comment.