From abace5a103cddbb0fdf7ae4f72816caa9932e6ee Mon Sep 17 00:00:00 2001 From: Brian Hogg Date: Mon, 17 Feb 2025 16:52:25 +0100 Subject: [PATCH 1/4] Add additional check for enrolling users into courses or memberships. --- includes/admin/class.llms.student.bulk.enroll.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/includes/admin/class.llms.student.bulk.enroll.php b/includes/admin/class.llms.student.bulk.enroll.php index f72c9720bf..4b968e4bc9 100644 --- a/includes/admin/class.llms.student.bulk.enroll.php +++ b/includes/admin/class.llms.student.bulk.enroll.php @@ -114,6 +114,12 @@ public function maybe_enroll_users_in_product() { return; } + if ( ! current_user_can( 'enroll', $this->product_id ) ) { + $message = __( 'You do not have permission to enroll users into this course or membership.', 'lifterlms' ); + $this->generate_notice( 'error', $message ); + return; + } + // Get the product title for notices. $this->product_title = get_the_title( $this->product_id ); From 0252f9c6219d236a78f31b53561ab2c8e4dea678 Mon Sep 17 00:00:00 2001 From: Brian Hogg Date: Mon, 17 Feb 2025 17:18:46 +0100 Subject: [PATCH 2/4] Filter to only return students for courses the instructor is an instructor for. --- includes/class.llms.user.permissions.php | 57 ++++++++++++++++++------ 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/includes/class.llms.user.permissions.php b/includes/class.llms.user.permissions.php index 95499acd74..ea7ec5a738 100644 --- a/includes/class.llms.user.permissions.php +++ b/includes/class.llms.user.permissions.php @@ -35,7 +35,7 @@ public function __construct() { add_filter( 'user_has_cap', array( $this, 'handle_caps' ), 10, 3 ); add_filter( 'editable_roles', array( $this, 'editable_roles' ) ); - + add_filter( 'rest_user_query', array( $this, 'filter_rest_user_query' ), 10, 2 ); } /** @@ -98,7 +98,45 @@ public function editable_roles( $all_roles ) { } return $all_roles; + } + + /** + * Filter the WP_User_Query args to ensure that instructors can only see their students + * + * @since [version] + * + * @param array $args WP_User_Query args. + * @param WP_REST_Request $request Request object. + * @return array + */ + public function filter_rest_user_query( $args, $request ) { + + $user = wp_get_current_user(); + + if ( ! $user ) { + return $args; + } + + if ( ! in_array( 'instructor', $user->roles, true ) ) { + return $args; + } + + $instructor = llms_get_instructor( $user ); + if ( ! $instructor ) { + return $args; + } + + $student_query = $instructor->get_students( array( 'statuses' => array( 'enrolled' ) ) ); + $students = $student_query->get_results(); + + if ( empty( $students ) ) { + $args['include'] = array( 0 ); + } else { + $args['include'] = wp_list_pluck( $students, 'id' ); + } + + return $args; } /** @@ -137,7 +175,6 @@ public function edit_others_lms_content( $allcaps, $cap, $args ) { } return $allcaps; - } /** @@ -165,7 +202,6 @@ public static function get_editable_roles() { ); return $roles; - } /** @@ -198,10 +234,10 @@ private function handle_cap_view_grades( $allcaps, $args ) { return $allcaps; } - $requested_cap = $args[0]; - $current_user_id = intval( $args[1] ); + $requested_cap = $args[0]; + $current_user_id = intval( $args[1] ); $requested_user_id = intval( $args[2] ); - $post_id = isset( $args[3] ) ? intval( $args[3] ) : false; + $post_id = isset( $args[3] ) ? intval( $args[3] ) : false; // Administrators and LMS managers explicitly have the cap so we don't need to perform any further checks. if ( ! empty( $allcaps[ $requested_cap ] ) ) { @@ -222,7 +258,6 @@ private function handle_cap_view_grades( $allcaps, $args ) { } return $allcaps; - } /** @@ -295,7 +330,6 @@ public function handle_caps( $allcaps, $cap, $args ) { } return $allcaps; - } /** @@ -308,7 +342,6 @@ public function handle_caps( $allcaps, $cap, $args ) { public static function is_current_user_instructor() { return ( current_user_can( 'lifterlms_instructor' ) && current_user_can( 'list_users' ) && ! current_user_can( 'manage_lifterlms' ) ); - } /** @@ -384,7 +417,6 @@ protected function user_can_manage_user( $user_id, $edit_id ) { } return false; - } /** @@ -396,14 +428,11 @@ protected function user_can_manage_user( $user_id, $edit_id ) { * @param int $requested_user_id WP User ID of the user the action will be performed on. * @return bool Returns true if the user has the student, false if it doesn't */ - protected function instructor_has_student( $current_user_id, $requested_user_id ) - { + protected function instructor_has_student( $current_user_id, $requested_user_id ) { $instructor = llms_get_instructor( $current_user_id ); return $instructor && $instructor->has_student( $requested_user_id ); - } - } return new LLMS_User_Permissions(); From 881b53ec8655c0a287be67a900c5dad7ba9b67a3 Mon Sep 17 00:00:00 2001 From: Brian Hogg Date: Tue, 18 Feb 2025 13:54:29 +0100 Subject: [PATCH 3/4] Changelog. --- .../limit-student-viewing-for-instructors-and-assistant.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .changelogs/limit-student-viewing-for-instructors-and-assistant.yml diff --git a/.changelogs/limit-student-viewing-for-instructors-and-assistant.yml b/.changelogs/limit-student-viewing-for-instructors-and-assistant.yml new file mode 100644 index 0000000000..4288ab54ba --- /dev/null +++ b/.changelogs/limit-student-viewing-for-instructors-and-assistant.yml @@ -0,0 +1,4 @@ +significance: patch +type: fixed +entry: Adds additional verifications on permission for bulk enrolls, and REST + API access for instructors. From cf5ae45b2b84372445a625be575f7701dbda7323 Mon Sep 17 00:00:00 2001 From: Brian Hogg Date: Tue, 18 Feb 2025 15:41:43 +0100 Subject: [PATCH 4/4] Only show bulk dropdown if they can manage lifterlms. --- includes/admin/class.llms.student.bulk.enroll.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/includes/admin/class.llms.student.bulk.enroll.php b/includes/admin/class.llms.student.bulk.enroll.php index 4b968e4bc9..1d55545da0 100644 --- a/includes/admin/class.llms.student.bulk.enroll.php +++ b/includes/admin/class.llms.student.bulk.enroll.php @@ -73,6 +73,10 @@ public function __construct() { */ public function display_product_selection_for_bulk_users( $which ) { + if ( ! current_user_can( 'manage_lifterlms' ) ) { + return; + } + // The attributes need to be different for top and bottom of the table. $id = 'bottom' === $which ? 'llms_bulk_enroll_product2' : 'llms_bulk_enroll_product'; $submit = 'bottom' === $which ? 'llms_bulk_enroll2' : 'llms_bulk_enroll';