From ffee0df99e260f28177211a2f4b78fd5b91f2688 Mon Sep 17 00:00:00 2001 From: Yakir Sitbon Date: Tue, 26 Nov 2024 17:49:10 +0200 Subject: [PATCH 1/3] New: Added option to save content created by temporary user [ED-16249] --- core/ajax.php | 25 ++++++++++-- core/options.php | 25 ++++++++++-- src/admin/api/index.ts | 4 +- src/admin/components/confirm-dialog.tsx | 4 +- src/admin/components/page-active.tsx | 15 +++++++- src/admin/components/page-inactive.tsx | 51 +++++++++++++++++++++---- 6 files changed, 105 insertions(+), 19 deletions(-) diff --git a/core/ajax.php b/core/ajax.php index b9daffc..fcd5651 100644 --- a/core/ajax.php +++ b/core/ajax.php @@ -26,8 +26,11 @@ public static function get_app_data() { wp_send_json_error( esc_html__( "You don't have permission to access this request", 'temporary-login' ) ); } + $current_user = wp_get_current_user(); + $data = [ 'status' => 'inactive', + 'current_user_logged_in_display_name' => $current_user->display_name ?? 'Unknown', ]; $temporary_users = Options::get_temporary_users(); @@ -57,11 +60,23 @@ private static function get_active_page_data( \WP_User $temporary_user ): array $is_elementor_connected = $elementor_connect->is_connected(); } + $created_by_user_id = Options::get_created_by_user_id( $temporary_user->ID ); + if ( $created_by_user_id ) { + $created_user = get_user_by( 'ID', $created_by_user_id ); + + if ( $created_user ) { + $reassign_to = $created_user->display_name; + $reassign_user_profile_link = get_edit_user_link( $created_user->ID ); + } + } + return [ 'status' => 'active', 'is_elementor_connected' => $is_elementor_connected, 'login_url' => Options::get_login_url( $temporary_user->ID ), 'expiration_human' => Options::get_expiration_human( $temporary_user->ID ), + 'reassign_to' => $reassign_to ?? '', + 'reassign_user_profile_link' => $reassign_user_profile_link ?? '', ]; } @@ -87,9 +102,13 @@ public static function enable_access() { wp_send_json_success(); } - $user_id = Options::generate_temporary_user(); - if ( is_wp_error( $user_id ) ) { - wp_send_json_error( $user_id ); + $user_ID = Options::generate_temporary_user(); + if ( is_wp_error( $user_ID ) ) { + wp_send_json_error( $user_ID ); + } + + if ( ! empty( $_POST['is_keep_user_posts'] ) && 'true' === $_POST['is_keep_user_posts'] ) { + Options::set_created_by_user_id( $user_ID ); } wp_send_json_success(); diff --git a/core/options.php b/core/options.php index 262b878..6fd16ba 100644 --- a/core/options.php +++ b/core/options.php @@ -83,6 +83,14 @@ private static function delete_site_token(): void { delete_option( '_temporary_login_site_token' ); } + public static function set_created_by_user_id( $user_ID ) { + update_user_meta( $user_ID, '_temporary_login_created_by_user_id', get_current_user_id() ); + } + + public static function get_created_by_user_id( $user_ID ) { + return get_user_meta( $user_ID, '_temporary_login_created_by_user_id', true ); + } + public static function is_temporary_user( $user_ID ) : bool { return (bool) get_user_meta( $user_ID, '_temporary_login', true ); } @@ -175,15 +183,24 @@ public static function remove_all_temporary_users() { return; } + foreach ( $temporary_users as $user ) { + static::remove_user( $user->ID ); + } + + static::delete_site_token(); + } + + private static function remove_user( $user_ID ) { if ( ! function_exists( 'wp_delete_user' ) ) { require_once ABSPATH . 'wp-admin/includes/user.php'; } - foreach ( $temporary_users as $user ) { - wp_delete_user( $user->ID ); + $reassign_user_ID = static::get_created_by_user_id( $user_ID ); + if ( empty( $reassign_user_ID ) ) { + $reassign_user_ID = null; } - static::delete_site_token(); + wp_delete_user( $user_ID, $reassign_user_ID ); } public static function remove_expired_temporary_users() { @@ -201,7 +218,7 @@ public static function remove_expired_temporary_users() { } foreach ( $users_IDs as $user_ID ) { - wp_delete_user( $user_ID ); + static::remove_user( $user_ID ); } } } diff --git a/src/admin/api/index.ts b/src/admin/api/index.ts index 9c7b863..3476a72 100644 --- a/src/admin/api/index.ts +++ b/src/admin/api/index.ts @@ -29,7 +29,7 @@ const getConfigData = () => { return ( window as unknown as WindowWithData ).ePremiumSupportSettings; }; -export const generateTemporaryUser = async () => { +export const generateTemporaryUser = async ( isKeepUserPosts = false ) => { const configData = getConfigData(); const response = await fetch( configData.ajaxurl, { @@ -37,7 +37,7 @@ export const generateTemporaryUser = async () => { headers: new Headers( { 'Content-Type': 'application/x-www-form-urlencoded', } ), - body: `action=temporary_login_generate_temporary_user&nonce=${ configData.nonce }`, + body: `action=temporary_login_generate_temporary_user&nonce=${ configData.nonce }&is_keep_user_posts=${ isKeepUserPosts }`, } ); const responseJson = await response.json(); diff --git a/src/admin/components/confirm-dialog.tsx b/src/admin/components/confirm-dialog.tsx index 3093132..f767c01 100644 --- a/src/admin/components/confirm-dialog.tsx +++ b/src/admin/components/confirm-dialog.tsx @@ -26,7 +26,7 @@ export const ConfirmDialog = ( props: ConfirmDialogParams ): ReactElement => { isDismissible={ false } onRequestClose={ () => setIsConfirmDialogOpen( false ) } > -

{ } } > { children } -

+ { @@ -92,12 +94,16 @@ export const PageActive = ( props: IActiveData ): ReactElement => { } } > event.target.select() } onChange={ () => {} } + style={ { + marginBottom: 'calc(8px)', + } } /> @@ -122,6 +128,13 @@ export const PageActive = ( props: IActiveData ): ReactElement => { + { props.reassign_to && ( + <> + { __( 'Content Attributed', 'temporary-login' ) }: { props.reassign_to } + { '. ' } + + ) } + { __( 'Expiration', 'temporary-login' ) + ':' } diff --git a/src/admin/components/page-inactive.tsx b/src/admin/components/page-inactive.tsx index 67ccc4b..be1248c 100644 --- a/src/admin/components/page-inactive.tsx +++ b/src/admin/components/page-inactive.tsx @@ -1,18 +1,20 @@ import { ReactElement } from 'react'; -import { Button } from '@wordpress/components'; +import { Button, CheckboxControl, ExternalLink, Icon, Notice } from '@wordpress/components'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { QUERY_KEY } from '../common/constants'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { generateTemporaryUser } from '../api'; import { ConfirmDialog } from './confirm-dialog'; import { useState } from '@wordpress/element'; interface IInActiveData { status: 'inactive'; + current_user_logged_in_display_name: string; } export const PageInactive = (): ReactElement => { const [ isConfirmDialogOpen, setIsConfirmDialogOpen ] = useState( false ); + const [ isKeepUserPosts, setIsKeepUserPosts ] = useState( false ); const queryClient = useQueryClient(); @@ -22,7 +24,7 @@ export const PageInactive = (): ReactElement => { mutationFn: () => { setIsConfirmDialogOpen( false ); - return generateTemporaryUser(); + return generateTemporaryUser( isKeepUserPosts ); }, onSuccess: () => { return queryClient.invalidateQueries( { @@ -33,11 +35,26 @@ export const PageInactive = (): ReactElement => { return ( <> + + +
+ +
+
+ @@ -56,12 +73,32 @@ export const PageInactive = (): ReactElement => { onConfirm={ generateUserMutation.mutate } confirmButtonText={ __( 'Grant', 'temporary-login' ) } > - { __( - 'Authorize Temporary Login to create admin-level access to your website.', - 'temporary-login' - ) } +

+ { __( + 'Authorize Temporary Login to create admin-level access to your website.', + 'temporary-login' + ) } +

) } ); }; + +const ContentAttributedExplain = ( { displayName } ) => { + const formattedMessage = sprintf( + __( + 'Content created by the temporary login user is temporary. To save it, select the option provided. The content will then be attributed to the %s user once the temporary access expires.', + 'temporary-login' + ), + '' + displayName + '' + ); + + return ( +

+ ); +}; From 008d0e4479600aab53b4160b98a2f1a10957a8e4 Mon Sep 17 00:00:00 2001 From: Yakir Sitbon Date: Tue, 26 Nov 2024 17:50:22 +0200 Subject: [PATCH 2/3] Remove unuse code --- src/admin/components/page-active.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin/components/page-active.tsx b/src/admin/components/page-active.tsx index f9ea7d4..7aa7c46 100644 --- a/src/admin/components/page-active.tsx +++ b/src/admin/components/page-active.tsx @@ -6,7 +6,7 @@ import { FlexItem, Icon, Notice, - TextControl, Tooltip, + TextControl, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useMutation, useQueryClient } from '@tanstack/react-query'; From 8ef80699f1db0023d68c827b57d17e1a4979c8eb Mon Sep 17 00:00:00 2001 From: Yakir Sitbon Date: Tue, 26 Nov 2024 17:55:39 +0200 Subject: [PATCH 3/3] Fix lint --- src/admin/components/page-active.tsx | 10 +++++++++- src/admin/components/page-inactive.tsx | 8 ++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/admin/components/page-active.tsx b/src/admin/components/page-active.tsx index 7aa7c46..4bb4cef 100644 --- a/src/admin/components/page-active.tsx +++ b/src/admin/components/page-active.tsx @@ -130,7 +130,15 @@ export const PageActive = ( props: IActiveData ): ReactElement => { { props.reassign_to && ( <> - { __( 'Content Attributed', 'temporary-login' ) }: { props.reassign_to } + + { __( + 'Content Attributed:', + 'temporary-login' + ) } + { ' ' } + + { props.reassign_to } + { '. ' } ) } diff --git a/src/admin/components/page-inactive.tsx b/src/admin/components/page-inactive.tsx index be1248c..be3a7a3 100644 --- a/src/admin/components/page-inactive.tsx +++ b/src/admin/components/page-inactive.tsx @@ -1,5 +1,5 @@ import { ReactElement } from 'react'; -import { Button, CheckboxControl, ExternalLink, Icon, Notice } from '@wordpress/components'; +import { Button, CheckboxControl, Notice } from '@wordpress/components'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { QUERY_KEY } from '../common/constants'; import { __, sprintf } from '@wordpress/i18n'; @@ -42,7 +42,10 @@ export const PageInactive = (): ReactElement => {

@@ -87,6 +90,7 @@ export const PageInactive = (): ReactElement => { const ContentAttributedExplain = ( { displayName } ) => { const formattedMessage = sprintf( + /* translators: %s: user display name */ __( 'Content created by the temporary login user is temporary. To save it, select the option provided. The content will then be attributed to the %s user once the temporary access expires.', 'temporary-login'