-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Event capabilities #215
Merged
Merged
Event capabilities #215
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
1b1ff99
Add Event_Capabilities class
psrpinto 813c5e4
Implement create capability
psrpinto 02697e9
Add docblocks
psrpinto 20fd493
Pass event repository to Event_Capabilities
psrpinto f050551
Add edit_translation_event capability
psrpinto 14ca1bc
Add tests for edit capability
psrpinto 32287ab
Pass dependencies to Event_Capabilities
psrpinto dbc66e4
Implement edit event capability check
psrpinto 196745c
Implement delete capability
psrpinto ccc278f
Return 404 if event is not found
psrpinto 5f652d8
Use capabilities to check if user can view the edit page
psrpinto a785a4b
GlotPress admins can always edit
psrpinto d990113
Check for delete_post instead of manage_options
psrpinto 3260aea
Use current_user_can() to check for permissions
psrpinto 0a551ea
Move variables to where they are first needed
psrpinto 5c1583f
Implement view capability
psrpinto 0d42399
Use current_user_can() to check for permissions
psrpinto fab7ad1
Use edit capability to show edit button
psrpinto 5ce4d4b
Check for edit_translation_event when managing hosts
psrpinto a867505
Use edit capability to check for permissions
psrpinto 3d2bab7
Remove unneeded checks
psrpinto 5a63d8c
Simplify logic
psrpinto 91c8136
Declare properties
psrpinto a9fced4
Correctly call current_user_can()
psrpinto fcf31e1
Remove unneeded else conditions
psrpinto 22f933b
Allow passing event id as string
psrpinto File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
<?php | ||
|
||
namespace Wporg\TranslationEvents\Event; | ||
|
||
use GP; | ||
use WP_User; | ||
use Wporg\TranslationEvents\Attendee\Attendee; | ||
use Wporg\TranslationEvents\Attendee\Attendee_Repository; | ||
use Wporg\TranslationEvents\Stats\Stats_Calculator; | ||
|
||
class Event_Capabilities { | ||
private const CREATE = 'create_translation_event'; | ||
private const VIEW = 'view_translation_event'; | ||
private const EDIT = 'edit_translation_event'; | ||
private const DELETE = 'delete_translation_event'; | ||
|
||
/** | ||
* All the capabilities that concern an Event. | ||
*/ | ||
private const CAPS = array( | ||
self::CREATE, | ||
self::VIEW, | ||
self::EDIT, | ||
self::DELETE, | ||
); | ||
|
||
private Event_Repository_Interface $event_repository; | ||
private Attendee_Repository $attendee_repository; | ||
private Stats_Calculator $stats_calculator; | ||
|
||
public function __construct( | ||
Event_Repository_Interface $event_repository, | ||
Attendee_Repository $attendee_repository, | ||
Stats_Calculator $stats_calculator | ||
) { | ||
$this->event_repository = $event_repository; | ||
$this->attendee_repository = $attendee_repository; | ||
$this->stats_calculator = $stats_calculator; | ||
} | ||
|
||
/** | ||
* This function is automatically called whenever user_can() is called for one the capabilities in self::CAPS. | ||
* | ||
* @param string $cap Requested capability. | ||
* @param array $args Arguments that accompany the requested capability check. | ||
* @param WP_User $user User for which we're evaluating the capability. | ||
* @return bool | ||
*/ | ||
private function has_cap( string $cap, array $args, WP_User $user ): bool { | ||
switch ( $cap ) { | ||
case self::CREATE: | ||
return $this->has_create( $user ); | ||
case self::VIEW: | ||
case self::EDIT: | ||
case self::DELETE: | ||
if ( ! isset( $args[2] ) || ! is_numeric( $args[2] ) ) { | ||
return false; | ||
} | ||
$event = $this->event_repository->get_event( intval( $args[2] ) ); | ||
if ( ! $event ) { | ||
return false; | ||
} | ||
|
||
if ( self::VIEW === $cap ) { | ||
return $this->has_view( $user, $event ); | ||
} | ||
if ( self::EDIT === $cap ) { | ||
return $this->has_edit( $user, $event ); | ||
} | ||
if ( self::DELETE === $cap ) { | ||
return $this->has_delete( $user, $event ); | ||
} | ||
break; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Evaluate whether a user can create events. | ||
* | ||
* @param WP_User $user User for which we're evaluating the capability. | ||
* @return bool | ||
*/ | ||
private function has_create( WP_User $user ): bool { | ||
return $this->is_gp_admin( $user ); | ||
} | ||
|
||
/** | ||
* Evaluate whether a user can view a specific event. | ||
* | ||
* @param WP_User $user User for which we're evaluating the capability. | ||
* @param Event $event Event for which we're evaluating the capability. | ||
* @return bool | ||
*/ | ||
private function has_view( WP_User $user, Event $event ): bool { | ||
if ( $this->is_gp_admin( $user ) ) { | ||
return true; | ||
} | ||
|
||
return 'publish' === $event->status(); | ||
} | ||
|
||
/** | ||
* Evaluate whether a user can edit a specific event. | ||
* | ||
* @param WP_User $user User for which we're evaluating the capability. | ||
* @param Event $event Event for which we're evaluating the capability. | ||
* @return bool | ||
*/ | ||
private function has_edit( WP_User $user, Event $event ): bool { | ||
if ( $event->end()->is_in_the_past() ) { | ||
return false; | ||
} | ||
|
||
if ( $this->stats_calculator->event_has_stats( $event->id() ) ) { | ||
return false; | ||
} | ||
|
||
if ( $event->author_id() === $user->ID ) { | ||
return true; | ||
} | ||
|
||
if ( user_can( $user->ID, 'edit_post', $event->id() ) ) { | ||
return true; | ||
} | ||
|
||
$attendee = $this->attendee_repository->get_attendee( $event->id(), $user->ID ); | ||
if ( ( $attendee instanceof Attendee ) && $attendee->is_host() ) { | ||
return true; | ||
} | ||
|
||
if ( $this->is_gp_admin( $user ) ) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Evaluate whether a user can delete a specific event. | ||
* | ||
* @param WP_User $user User for which we're evaluating the capability. | ||
* @param Event $event Event for which we're evaluating the capability. | ||
* @return bool | ||
*/ | ||
private function has_delete( WP_User $user, Event $event ): bool { | ||
// Must be able to edit in order to delete. | ||
if ( ! $this->has_edit( $user, $event ) ) { | ||
return false; | ||
} | ||
|
||
if ( user_can( $user->ID, 'delete_post', $event->id() ) ) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Evaluate whether a user is a GlotPress admin. | ||
* | ||
* @param WP_User $user User for which we're evaluating the capability. | ||
* @return bool | ||
*/ | ||
private function is_gp_admin( WP_User $user ): bool { | ||
return apply_filters( 'gp_translation_events_can_crud_event', GP::$permission->user_can( $user, 'admin' ) ); | ||
} | ||
|
||
public function register_hooks(): void { | ||
add_action( | ||
'user_has_cap', | ||
function ( $allcaps, $caps, $args, $user ) { | ||
foreach ( $caps as $cap ) { | ||
if ( ! in_array( $cap, self::CAPS, true ) ) { | ||
continue; | ||
} | ||
if ( $this->has_cap( $cap, $args, $user ) ) { | ||
$allcaps[ $cap ] = true; | ||
} | ||
} | ||
return $allcaps; | ||
}, | ||
10, | ||
4, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this is too early and/or we need more fine grained controls (which is easy now!) But I think it should be possible to change at least the event description (and maybe the event end, if it should be extended) even when there are stats.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, more fine grained capabilities could make sense, e.g.
edit_translation_event_with_stats
. Also agree that it it should be possible to edit certain fields of a past event. I opened #227 to track that.