From bdbf6d573e992696c179a002ccae7bfedee29fc4 Mon Sep 17 00:00:00 2001 From: Kelly Dwan Date: Tue, 10 Dec 2019 14:07:48 -0500 Subject: [PATCH] Pledge Management: Allow pledge admins to remove the pledge (#123) * Rename generic "frontend" file to dialog * Add a "remove pledge" action * Process pledge deactivation * Trigger an email on user-initiated pledge deactivation * Show an error when trying to manage a deactivated pledge * Add a label for "deactivated" pledges --- plugins/wporg-5ftf/assets/js/admin.js | 8 ++- .../assets/js/{frontend.js => dialog.js} | 8 +-- plugins/wporg-5ftf/includes/email.php | 22 +++++++ plugins/wporg-5ftf/includes/pledge-form.php | 63 +++++++++++++++++-- plugins/wporg-5ftf/includes/pledge-meta.php | 5 +- plugins/wporg-5ftf/includes/pledge.php | 55 +++++++++++----- .../wporg-5ftf/views/form-pledge-manage.php | 2 + .../wporg-5ftf/views/form-pledge-remove.php | 31 +++++++++ .../css/components/_pledge-single.scss | 9 +++ .../wporg-5ftf/css/objects/_pledge-form.scss | 3 +- themes/wporg-5ftf/single-5ftf_pledge.php | 4 ++ 11 files changed, 184 insertions(+), 26 deletions(-) rename plugins/wporg-5ftf/assets/js/{frontend.js => dialog.js} (95%) create mode 100644 plugins/wporg-5ftf/views/form-pledge-remove.php diff --git a/plugins/wporg-5ftf/assets/js/admin.js b/plugins/wporg-5ftf/assets/js/admin.js index f4822dd..c2d961e 100644 --- a/plugins/wporg-5ftf/assets/js/admin.js +++ b/plugins/wporg-5ftf/assets/js/admin.js @@ -1,4 +1,4 @@ -/* global ajaxurl, FiveForTheFuture, fftfContributors, jQuery */ +/* global FiveForTheFuture, fftfContributors, jQuery */ /* eslint no-alert: "off" */ jQuery( document ).ready( function( $ ) { let ajaxurl = window.ajaxurl; @@ -153,4 +153,10 @@ jQuery( document ).ready( function( $ ) { _addContributors(); } } ); + + $( '#5ftf-pledge-remove' ).on( 'click', function( event ) { + if ( ! confirm( FiveForTheFuture.removePrompt ) ) { + event.preventDefault(); + } + } ); } ); diff --git a/plugins/wporg-5ftf/assets/js/frontend.js b/plugins/wporg-5ftf/assets/js/dialog.js similarity index 95% rename from plugins/wporg-5ftf/assets/js/frontend.js rename to plugins/wporg-5ftf/assets/js/dialog.js index b8f4054..8eca409 100644 --- a/plugins/wporg-5ftf/assets/js/frontend.js +++ b/plugins/wporg-5ftf/assets/js/dialog.js @@ -1,4 +1,4 @@ -/* global FiveForTheFuture, jQuery */ +/* global FFTF_Dialog, jQuery */ jQuery( document ).ready( function( $ ) { const button = document.getElementById( 'toggle-management-link-form' ); const template = wp.template( '5ftf-send-link-dialog' ); @@ -84,12 +84,12 @@ jQuery( document ).ready( function( $ ) { $( event.target.querySelector( '.message' ) ).html( '' ); $.ajax( { type: 'POST', - url: FiveForTheFuture.ajaxurl, + url: FFTF_Dialog.ajaxurl, data: { action: 'send-manage-email', - pledge_id: FiveForTheFuture.pledgeId, + pledge_id: FFTF_Dialog.pledgeId, email, - _ajax_nonce: FiveForTheFuture.ajaxNonce, + _ajax_nonce: FFTF_Dialog.ajaxNonce, }, success( response ) { if ( response.message ) { diff --git a/plugins/wporg-5ftf/includes/email.php b/plugins/wporg-5ftf/includes/email.php index 9558262..1988a59 100644 --- a/plugins/wporg-5ftf/includes/email.php +++ b/plugins/wporg-5ftf/includes/email.php @@ -154,3 +154,25 @@ function send_manage_pledge_link( $pledge_id ) { return $result; } + +/** + * Email pledge manager to notify that the pledge has been removed. + * + * @param WP_Post $pledge The pledge object, used to add the title now that the pledge itself has been deleted. + * + * @return bool + */ +function send_pledge_deactivation_email( $pledge ) { + $message = sprintf( + "Your organization, %s, has been removed from the Five for the Future listing.\n\n" . + 'Please reply to this email if this was a mistake.', + $pledge->post_title + ); + + return send_email( + $pledge->{'5ftf_org-pledge-email'}, + 'Pledge removed from Five for the Future', + $message, + $pledge->ID + ); +} diff --git a/plugins/wporg-5ftf/includes/pledge-form.php b/plugins/wporg-5ftf/includes/pledge-form.php index f059898..5a89978 100755 --- a/plugins/wporg-5ftf/includes/pledge-form.php +++ b/plugins/wporg-5ftf/includes/pledge-form.php @@ -123,15 +123,40 @@ function render_form_manage() { $can_view_form = Auth\can_manage_pledge( $pledge_id, $auth_token ); if ( is_wp_error( $can_view_form ) ) { - // Can't manage pledge, only show errors. $errors = array( $can_view_form->get_error_message() ); + } else if ( ! in_array( get_post_status( $pledge_id ), array( 'pending', 'publish' ), true ) ) { + $errors = array( + sprintf( + __( 'This pledge has been removed from Five for the Future. If this was a mistake, please contact us to reactivate your pledge.', 'wporg-5ftf' ), + get_permalink( get_page_by_path( 'report' ) ) + ), + ); + } + if ( count( $errors ) > 0 ) { ob_start(); require FiveForTheFuture\PATH . 'views/partial-result-messages.php'; return ob_get_clean(); } - if ( 'Update Pledge' === $action ) { + if ( 'remove-pledge' === $action ) { + $results = process_form_remove( $pledge_id, $auth_token ); + + if ( is_wp_error( $results ) ) { + $errors = $results->get_error_messages(); + } else { + $messages = array( + sprintf( + __( 'Your pledge has been removed. If this was a mistake, please contact us to reactivate your pledge.', 'wporg-5ftf' ), + get_permalink( get_page_by_path( 'report' ) ) + ), + ); + } + + ob_start(); + require FiveForTheFuture\PATH . 'views/partial-result-messages.php'; + return ob_get_clean(); + } else if ( 'Update Pledge' === $action ) { $results = process_form_manage( $pledge_id, $auth_token ); if ( is_wp_error( $results ) ) { @@ -215,12 +240,42 @@ function process_form_manage( $pledge_id, $auth_token ) { } } - // @todo Save contributors. - // If we made it to here, we've successfully saved the pledge. return true; } +/** + * Process a submission from the Manage Pledge form. + * + * @return WP_Error|true An error if the pledge could not be saved. Otherwise true. + */ +function process_form_remove( $pledge_id, $auth_token ) { + $errors = array(); + $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING ); + $nonce_action = 'remove_pledge_' . $pledge_id; + $has_valid_nonce = wp_verify_nonce( $nonce, $nonce_action ); + $can_view_form = Auth\can_manage_pledge( $pledge_id, $auth_token ); + + if ( ! $has_valid_nonce || is_wp_error( $can_view_form ) ) { + return new WP_Error( + 'invalid_token', + sprintf( + __( 'Your link has expired, please obtain a new one.', 'wporg-5ftf' ), + get_permalink( $pledge_id ) + ) + ); + } + + $result = Pledge\deactivate( $pledge_id, true ); + + if ( is_wp_error( $result ) ) { + return $result; + } + + // If we made it to here, we've successfully removed the pledge. + return true; +} + /** * Process a request to confirm a company's email address. * diff --git a/plugins/wporg-5ftf/includes/pledge-meta.php b/plugins/wporg-5ftf/includes/pledge-meta.php index 10248da..3a5f272 100755 --- a/plugins/wporg-5ftf/includes/pledge-meta.php +++ b/plugins/wporg-5ftf/includes/pledge-meta.php @@ -549,13 +549,14 @@ function enqueue_assets() { $pledge_id = is_admin() ? get_the_ID() : absint( $_REQUEST['pledge_id'] ?? 0 ); $auth_token = sanitize_text_field( $_REQUEST['auth_token'] ?? '' ); - $script_data = [ + $script_data = array( // The global ajaxurl is not set on the frontend. 'ajaxurl' => admin_url( 'admin-ajax.php', 'relative' ), 'pledgeId' => $pledge_id, 'manageNonce' => wp_create_nonce( 'manage-contributors' ), 'authToken' => $auth_token, - ]; + 'removePrompt' => __( 'Are you sure you want to remove this pledge?', 'wporg-5ftf' ), + ); wp_add_inline_script( '5ftf-admin', sprintf( diff --git a/plugins/wporg-5ftf/includes/pledge.php b/plugins/wporg-5ftf/includes/pledge.php index e76c876..903cc17 100755 --- a/plugins/wporg-5ftf/includes/pledge.php +++ b/plugins/wporg-5ftf/includes/pledge.php @@ -205,10 +205,7 @@ function handle_activation_action( $post_id ) { $sendback = remove_query_arg( [ 'deactivated', 'reactivated' ], $sendback ); if ( 'deactivate' === $action ) { - wp_update_post( array( - 'ID' => $post_id, - 'post_status' => DEACTIVE_STATUS, - ) ); + deactivate( $post_id ); wp_redirect( add_query_arg( 'deactivated', 1, $sendback ) ); exit(); } else { @@ -355,6 +352,31 @@ function create_new_pledge( $name ) { return $pledge_id; } +/** + * Remove a pledge from view by setting its status to "deactivated". + * + * @param int $pledge_id The pledge to deactivate. + * @param bool $notify Whether the pledge admin should be notified of the deactivation. + * + * @return int|WP_Error Post ID on success. Otherwise WP_Error. + */ +function deactivate( $pledge_id, $notify = false ) { + $pledge = get_post( $pledge_id ); + $result = wp_update_post( + array( + 'ID' => $pledge_id, + 'post_status' => DEACTIVE_STATUS, + ), + true // Return a WP_Error. + ); + + if ( $notify && ! is_wp_error( $result ) ) { + Email\send_pledge_deactivation_email( $pledge ); + } + + return $result; +} + /** * Filter query for archive & search pages to ensure we're only showing the expected data. * @@ -462,21 +484,26 @@ function has_existing_pledge( $key, $key_type, int $current_pledge_id = 0 ) { * @return void */ function enqueue_assets() { - wp_register_script( 'wicg-inert', plugins_url( 'assets/js/inert.min.js', __DIR__ ), [], '3.0.0', true ); + wp_register_script( 'wicg-inert', plugins_url( 'assets/js/inert.min.js', __DIR__ ), array(), '3.0.0', true ); if ( CPT_ID === get_post_type() ) { - $ver = filemtime( FiveForTheFuture\PATH . '/assets/js/frontend.js' ); - wp_enqueue_script( '5ftf-frontend', plugins_url( 'assets/js/frontend.js', __DIR__ ), [ 'jquery', 'wp-a11y', 'wp-util', 'wicg-inert' ], $ver, true ); + wp_enqueue_script( + '5ftf-dialog', + plugins_url( 'assets/js/dialog.js', __DIR__ ), + array( 'jquery', 'wp-a11y', 'wp-util', 'wicg-inert' ), + filemtime( FiveForTheFuture\PATH . '/assets/js/dialog.js' ), + true + ); - $script_data = [ - 'ajaxurl' => admin_url( 'admin-ajax.php', 'relative' ), // The global ajaxurl is not set on the frontend. - 'pledgeId' => get_the_ID(), - 'ajaxNonce' => wp_create_nonce( 'send-manage-email' ), - ]; + $script_data = array( + 'ajaxurl' => admin_url( 'admin-ajax.php', 'relative' ), // The global ajaxurl is not set on the frontend. + 'pledgeId' => get_the_ID(), + 'ajaxNonce' => wp_create_nonce( 'send-manage-email' ), + ); wp_add_inline_script( - '5ftf-frontend', + '5ftf-dialog', sprintf( - 'var FiveForTheFuture = JSON.parse( decodeURIComponent( \'%s\' ) );', + 'var FFTF_Dialog = JSON.parse( decodeURIComponent( \'%s\' ) );', rawurlencode( wp_json_encode( $script_data ) ) ), 'before' diff --git a/plugins/wporg-5ftf/views/form-pledge-manage.php b/plugins/wporg-5ftf/views/form-pledge-manage.php index ba4a3ac..f7cdb16 100644 --- a/plugins/wporg-5ftf/views/form-pledge-manage.php +++ b/plugins/wporg-5ftf/views/form-pledge-manage.php @@ -42,4 +42,6 @@ require __DIR__ . '/partial-result-messages.php'; + + diff --git a/plugins/wporg-5ftf/views/form-pledge-remove.php b/plugins/wporg-5ftf/views/form-pledge-remove.php new file mode 100644 index 0000000..0ef1b4c --- /dev/null +++ b/plugins/wporg-5ftf/views/form-pledge-remove.php @@ -0,0 +1,31 @@ + + +
+ +
+

+ +

+ +

+ +

+ + + + + +

+
diff --git a/themes/wporg-5ftf/css/components/_pledge-single.scss b/themes/wporg-5ftf/css/components/_pledge-single.scss index 223a6ca..833bf46 100644 --- a/themes/wporg-5ftf/css/components/_pledge-single.scss +++ b/themes/wporg-5ftf/css/components/_pledge-single.scss @@ -31,6 +31,15 @@ body.single.single-5ftf_pledge { margin-top: ms(2); } } + + .pledge-status { + display: inline-block; + padding: 4px 12px; + font-size: ms(-1); + text-transform: uppercase; + background-color: $color-error-red; + color: white; + } } .entry-title { diff --git a/themes/wporg-5ftf/css/objects/_pledge-form.scss b/themes/wporg-5ftf/css/objects/_pledge-form.scss index 19b1b85..d0a098f 100644 --- a/themes/wporg-5ftf/css/objects/_pledge-form.scss +++ b/themes/wporg-5ftf/css/objects/_pledge-form.scss @@ -29,7 +29,8 @@ height: auto; } - [id*="help"] p { + [id*="help"] p, + p[id*="help"] { margin-top: ms(-5); font-size: ms(-2); } diff --git a/themes/wporg-5ftf/single-5ftf_pledge.php b/themes/wporg-5ftf/single-5ftf_pledge.php index bca4e80..36864f8 100644 --- a/themes/wporg-5ftf/single-5ftf_pledge.php +++ b/themes/wporg-5ftf/single-5ftf_pledge.php @@ -6,6 +6,7 @@ use WordPressDotOrg\FiveForTheFuture\XProfile; use WP_Post; use const WordPressDotOrg\FiveForTheFuture\PledgeMeta\META_PREFIX; +use const WordPressDotOrg\FiveForTheFuture\Pledge\DEACTIVE_STATUS; $contribution_data = XProfile\get_aggregate_contributor_data_for_pledge( get_the_ID() ); @@ -30,6 +31,9 @@ get_header();
>
+ + + ', '' ); ?>