diff --git a/includes/event/event-form-handler.php b/includes/event/event-form-handler.php index 9e1aad09..20c5e979 100644 --- a/includes/event/event-form-handler.php +++ b/includes/event/event-form-handler.php @@ -21,26 +21,35 @@ public function __construct( DateTimeImmutable $now, Event_Repository $event_rep } public function handle( array $form_data ): void { + $response = $this->process_form( $form_data ); + if ( is_wp_error( $response ) ) { + $status_code = $response->get_error_data( 'status' ); + wp_send_json_error( $response->get_error_message(), $status_code ); + } + wp_send_json_success( $response ); + } + + public function process_form( array $form_data ) { if ( ! is_user_logged_in() ) { - wp_send_json_error( esc_html__( 'The user must be logged in.', 'gp-translation-events' ), 403 ); + return new WP_Error( 'not_logged_in', esc_html__( 'The user must be logged in.', 'gp-translation-events' ), array( 'status' => 403 ) ); } $action = isset( $form_data['form_name'] ) ? sanitize_text_field( wp_unslash( $form_data['form_name'] ) ) : ''; if ( ! in_array( $action, array( 'create_event', 'edit_event', 'trash_event' ), true ) ) { - wp_send_json_error( esc_html__( 'Invalid form name.', 'gp-translation-events' ), 403 ); + return new WP_Error( 'form_name_error', esc_html__( 'Invalid form name.', 'gp-translation-events' ), array( 'status' => 403 ) ); } $event_id = isset( $form_data['event_id'] ) ? intval( sanitize_text_field( wp_unslash( $form_data['event_id'] ) ) ) : 0; $event = null; if ( 'create_event' === $action && ( ! current_user_can( 'create_translation_event' ) ) ) { - wp_send_json_error( esc_html__( 'You do not have permissions to create events.', 'gp-translation-events' ), 403 ); + return new WP_Error( 'permission_error', esc_html__( 'You do not have permissions to create events.', 'gp-translation-events' ), array( 'status' => 403 ) ); } if ( 'edit_event' === $action && ( ! current_user_can( 'edit_translation_event', $event_id ) ) ) { - wp_send_json_error( esc_html__( 'You do not have permissions to edit this event.', 'gp-translation-events' ), 403 ); + return new WP_Error( 'permission_error', esc_html__( 'You do not have permissions to edit this event.', 'gp-translation-events' ), array( 'status' => 403 ) ); } if ( 'trash_event' === $action && ( ! current_user_can( 'trash_translation_event', $event_id ) ) ) { - wp_send_json_error( esc_html__( 'You do not have permissions to delete this event.', 'gp-translation-events' ), 403 ); + return new WP_Error( 'permission_error', esc_html__( 'You do not have permissions to delete this event.', 'gp-translation-events' ), array( 'status' => 403 ) ); } $is_nonce_valid = false; @@ -52,7 +61,7 @@ public function handle( array $form_data ): void { } } if ( ! $is_nonce_valid ) { - wp_send_json_error( esc_html__( 'Nonce verification failed.', 'gp-translation-events' ), 403 ); + return new WP_Error( 'invalid_nonce', esc_html__( 'Nonce verification failed.', 'gp-translation-events' ), array( 'status' => 403 ) ); } $response_message = ''; @@ -63,17 +72,17 @@ public function handle( array $form_data ): void { if ( 'trash_event' === $action ) { // Trash event. if ( ! $event ) { - wp_send_json_error( esc_html__( 'Event does not exist.', 'gp-translation-events' ), 404 ); + return new WP_Error( 'inexistent_event', esc_html__( 'Event does not exist.', 'gp-translation-events' ), array( 'status' => 404 ) ); } $stats_calculator = new Stats_Calculator(); try { $event_stats = $stats_calculator->for_event( $event->id() ); } catch ( Exception $e ) { - wp_send_json_error( esc_html__( 'Failed to calculate event stats.', 'gp-translation-events' ), 500 ); + return new WP_Error( 'stats_calculation_error', esc_html__( 'Failed to calculate event stats.', 'gp-translation-events' ), array( 'status' => 500 ) ); } if ( ! empty( $event_stats->rows() ) ) { - wp_send_json_error( esc_html__( 'Event has stats so it cannot be deleted.', 'gp-translation-events' ), 422 ); + return new WP_Error( 'cannot_delete_event', esc_html__( 'Event has stats so it cannot be deleted.', 'gp-translation-events' ), array( 'status' => 422 ) ); } if ( false === $this->event_repository->trash_event( $event ) ) { @@ -90,35 +99,30 @@ public function handle( array $form_data ): void { try { $new_event = $this->parse_form_data( $form_data ); } catch ( InvalidTimeZone $e ) { - wp_send_json_error( esc_html__( 'Invalid time zone.', 'gp-translation-events' ), 422 ); - return; + return new WP_Error( 'invalid_timezone', esc_html__( 'Invalid time zone.', 'gp-translation-events' ), array( 'status' => 422 ) ); } catch ( InvalidStart $e ) { - wp_send_json_error( esc_html__( 'Invalid start date.', 'gp-translation-events' ), 422 ); - return; + return new WP_Error( 'invalid_start_date', esc_html__( 'Invalid start date.', 'gp-translation-events' ), array( 'status' => 422 ) ); } catch ( InvalidEnd $e ) { - wp_send_json_error( esc_html__( 'Invalid end date.', 'gp-translation-events' ), 422 ); - return; + return new WP_Error( 'invalid_end_date', esc_html__( 'Invalid end date.', 'gp-translation-events' ), array( 'status' => 422 ) ); } catch ( InvalidStatus $e ) { - wp_send_json_error( esc_html__( 'Invalid status.', 'gp-translation-events' ), 422 ); - return; + return new WP_Error( 'invalid_status', esc_html__( 'Invalid status.', 'gp-translation-events' ), array( 'status' => 422 ) ); } if ( empty( $new_event->title() ) ) { - wp_send_json_error( esc_html__( 'Invalid title.', 'gp-translation-events' ), 422 ); - return; + return new WP_Error( 'invalid_title', esc_html__( 'Invalid title.', 'gp-translation-events' ), array( 'status' => 422 ) ); } // This is a list of slugs that are not allowed, as they conflict with the event URLs. $invalid_slugs = array( 'new', 'edit', 'attend', 'my-events' ); if ( in_array( sanitize_title( $new_event->title() ), $invalid_slugs, true ) ) { - wp_send_json_error( esc_html__( 'Invalid slug.', 'gp-translation-events' ), 422 ); + return new WP_Error( 'invalid_slug', esc_html__( 'Invalid slug.', 'gp-translation-events' ), array( 'status' => 422 ) ); } if ( 'create_event' === $action ) { $result = $this->event_repository->insert_event( $new_event ); if ( $result instanceof WP_Error ) { - wp_send_json_error( esc_html__( 'Failed to create event.', 'gp-translation-events' ), 422 ); - return; + return new WP_Error( 'cannot_create_event', esc_html__( 'Failed to create event.', 'gp-translation-events' ), array( 'status' => 422 ) ); + } $response_message = esc_html__( 'Event created successfully.', 'gp-translation-events' ); $this->notifications_schedule->schedule_emails( $result ); @@ -126,7 +130,7 @@ public function handle( array $form_data ): void { if ( 'edit_event' === $action ) { $event = $this->event_repository->get_event( $new_event->id() ); if ( ! $event ) { - wp_send_json_error( esc_html__( 'Event does not exist.', 'gp-translation-events' ), 404 ); + return new WP_Error( 'inexistent_event', esc_html__( 'Event does not exist.', 'gp-translation-events' ), array( 'status' => 404 ) ); } try { @@ -153,14 +157,14 @@ public function handle( array $form_data ): void { $event->set_attendance_mode( $new_event->attendance_mode() ); } } catch ( Exception $e ) { - wp_send_json_error( esc_html__( 'Failed to update event.', 'gp-translation-events' ), 422 ); - return; + return new WP_Error( 'cannot_update_event', esc_html__( 'Failed to update event.', 'gp-translation-events' ), array( 'status' => 422 ) ); + } $result = $this->event_repository->update_event( $event ); if ( $result instanceof WP_Error ) { - wp_send_json_error( esc_html__( 'Failed to update event.', 'gp-translation-events' ), 422 ); - return; + return new WP_Error( 'cannot_update_event', esc_html__( 'Failed to update event.', 'gp-translation-events' ), array( 'status' => 422 ) ); + } $response_message = esc_html__( 'Event updated successfully', 'gp-translation-events' ); $this->notifications_schedule->schedule_emails( $result ); @@ -170,7 +174,7 @@ public function handle( array $form_data ): void { $event_status = $new_event->status(); } - wp_send_json_success( + return( array( 'message' => $response_message, 'eventId' => $event_id, diff --git a/tests/event/event-form-handler.php b/tests/event/event-form-handler.php new file mode 100644 index 00000000..0519a8b4 --- /dev/null +++ b/tests/event/event-form-handler.php @@ -0,0 +1,103 @@ +attendee_repository = new Attendee_Repository(); + $this->event_repository = new Event_Repository( $this->now, $this->attendee_repository ); + $this->event_form_handler = new Event_Form_Handler( $this->now, $this->event_repository ); + $this->event_form_handler_factory = new Event_Form_Handler_Factory(); + $this->set_normal_user_as_current(); + } + + /** + * Test that the user must be logged in to create an event. + * + * @return void + */ + public function test_user_is_not_logged_in() { + wp_set_current_user( 0 ); + $form_data = $this->event_form_handler_factory->future_inactive_event_form_data( 'create_event', $this->now ); + $response = $this->event_form_handler->process_form( $form_data ); + + $this->assertEquals( 'The user must be logged in.', $response->get_error_message() ); + } + + public function test_form_name_is_invalid() { + $form_data = $this->event_form_handler_factory->future_inactive_event_form_data( 'invalid_form_name', $this->now ); + $response = $this->event_form_handler->process_form( $form_data ); + + $this->assertEquals( 'Invalid form name.', $response->get_error_message() ); + } + + public function test_invalid_permissions() { + $event_id = 9999; + $form_data_1 = $this->event_form_handler_factory->future_inactive_event_form_data( 'create_event', $this->now ); + $response_1 = $this->event_form_handler->process_form( $form_data_1 ); + $this->assertEquals( 'You do not have permissions to create events.', $response_1->get_error_message() ); + + $form_data_2 = $this->event_form_handler_factory->future_inactive_event_form_data( 'edit_event', $this->now, $event_id ); + $response_2 = $this->event_form_handler->process_form( $form_data_2 ); + $this->assertEquals( 'You do not have permissions to edit this event.', $response_2->get_error_message() ); + + $form_data_3 = $this->event_form_handler_factory->future_inactive_event_form_data( 'trash_event', $this->now, $event_id ); + $response_3 = $this->event_form_handler->process_form( $form_data_3 ); + $this->assertEquals( 'You do not have permissions to delete this event.', $response_3->get_error_message() ); + } + + public function test_invalid_nonce() { + add_filter( 'gp_translation_events_can_crud_event', '__return_true' ); + $form_data = $this->event_form_handler_factory->future_inactive_event_form_data( 'create_event', $this->now ); + $form_data['_event_nonce'] = wp_create_nonce( 'invalid_nonce' ); + $response = $this->event_form_handler->process_form( $form_data ); + + $this->assertArrayHasKey( 'invalid_nonce', $response->error_data ); + $this->assertEquals( 'Nonce verification failed.', $response->get_error_message() ); + } + + /** + * @dataProvider emptyFormDataProvider + */ + public function test_empty_form_fields( $action, $field, $error_key ) { + add_filter( 'gp_translation_events_can_crud_event', '__return_true' ); + $form_data = $this->event_form_handler_factory->future_inactive_event_form_data( $action, $this->now ); + $form_data[ $field ] = ''; + $response = $this->event_form_handler->process_form( $form_data ); + + $this->assertArrayHasKey( $error_key, $response->error_data ); + } + + /** + * Data provider for invalid form data test cases. + */ + public function emptyFormDataProvider() { + return array( + array( 'create_event', 'event_title', 'invalid_title' ), + array( 'create_event', 'event_description', 'invalid_title' ), + array( 'create_event', 'event_start', 'invalid_start_date' ), + array( 'create_event', 'event_end', 'invalid_end_date' ), + array( 'create_event', 'event_timezone', 'invalid_timezone' ), + array( 'create_event', 'event_attendance_mode', 'invalid event_attendance_mode' ), + array( 'edit_event', 'event_title', 'invalid_title' ), + array( 'edit_event', 'event_description', 'invalid_title' ), + array( 'edit_event', 'event_start', 'invalid_start_date' ), + array( 'edit_event', 'event_end', 'invalid_end_date' ), + array( 'edit_event', 'event_timezone', 'invalid_timezone' ), + array( 'edit_event', 'event_attendance_mode', 'invalid event_attendance_mode' ), + ); + } + +} diff --git a/tests/lib/event-form-handler-factory.php b/tests/lib/event-form-handler-factory.php new file mode 100644 index 00000000..abe38222 --- /dev/null +++ b/tests/lib/event-form-handler-factory.php @@ -0,0 +1,32 @@ + 'submit_event_ajax', + 'form_name' => $form_name, + 'event_id' => $_event_id, + 'event_form_action' => 'publish', + 'event_title' => $event_title, + 'event_description' => $event_description, + 'event_start' => $now->modify( '+1 month' )->format( 'Y-m-d H:i:s' ), + 'event_end' => $now->modify( '+2 month' )->format( 'Y-m-d H:i:s' ), + 'event_timezone' => $timezone, + 'event_attendance_mode' => $event_attendance_mode, + '_event_nonce' => $event_nonce, + ); + } +}