generated from pascalmartineau/wp-skeleton
feat: Initial user switching mutations
This commit is contained in:
38
wp-content/themes/ccat/app/composables/useUserSwitching.ts
Normal file
38
wp-content/themes/ccat/app/composables/useUserSwitching.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
export const useUserSwitching = () => {
|
||||
const session = useUserSession();
|
||||
|
||||
const isSwitched = computed(() => Boolean(session.data.value?.switchedBy));
|
||||
|
||||
const switchTo = async (userId: string | number) => {
|
||||
const response = await $fetch("/api/switch-to", {
|
||||
method: "POST",
|
||||
body: { userId },
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
await session.fetch();
|
||||
return response;
|
||||
}
|
||||
|
||||
throw new Error(response.message || "Switch failed");
|
||||
};
|
||||
|
||||
const switchBack = async () => {
|
||||
const response = await $fetch("/api/switch-back", {
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
await session.fetch();
|
||||
return response;
|
||||
}
|
||||
|
||||
throw new Error(response.message || "Switch back failed");
|
||||
};
|
||||
|
||||
return {
|
||||
isSwitched,
|
||||
switchTo,
|
||||
switchBack,
|
||||
};
|
||||
};
|
||||
@@ -22,6 +22,9 @@ require_once __DIR__ . '/includes/taxonomies/resource-category.php';
|
||||
|
||||
// Forms
|
||||
|
||||
// GraphQL
|
||||
require_once __DIR__ . '/includes/graphql/user-switching.php';
|
||||
|
||||
// Roles
|
||||
|
||||
// Sections
|
||||
|
||||
103
wp-content/themes/ccat/includes/graphql/user-switching.php
Normal file
103
wp-content/themes/ccat/includes/graphql/user-switching.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
// Register userSwitchTo mutation
|
||||
add_action( 'graphql_register_types', 'ccat_graphql_register_user_switch_to' );
|
||||
function ccat_graphql_register_user_switch_to() {
|
||||
register_graphql_mutation(
|
||||
'userSwitchTo',
|
||||
array(
|
||||
'inputFields' => array(
|
||||
'userId' => array(
|
||||
'type' => 'ID',
|
||||
'description' => esc_html__( 'The ID of the user to switch to', 'ccat' ),
|
||||
),
|
||||
),
|
||||
'outputFields' => array(
|
||||
'authToken' => array(
|
||||
'type' => 'String',
|
||||
'description' => esc_html__( 'JWT Token for the target user', 'ccat' ),
|
||||
),
|
||||
'refreshToken' => array(
|
||||
'type' => 'String',
|
||||
'description' => esc_html__( 'JWT Refresh Token for the target user', 'ccat' ),
|
||||
),
|
||||
'user' => array(
|
||||
'type' => 'User',
|
||||
'description' => esc_html__( 'The target user object', 'ccat' ),
|
||||
),
|
||||
),
|
||||
'mutateAndGetPayload' => 'ccat_graphql_switch_to_mutation',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Callback for userSwitchTo mutation
|
||||
function ccat_graphql_switch_to_mutation( $input ) {
|
||||
if ( ! is_user_logged_in() || ! current_user_can( 'manage_options' ) ) {
|
||||
throw new \GraphQL\Error\UserError( esc_html__( 'Insufficient permissions', 'ccat' ) );
|
||||
}
|
||||
$user_id = absint( $input['userId'] );
|
||||
$current_user_id = get_current_user_id();
|
||||
if ( $user_id === $current_user_id ) {
|
||||
throw new \GraphQL\Error\UserError( esc_html__( 'Cannot switch to yourself', 'ccat' ) );
|
||||
}
|
||||
$target_user = get_user_by( 'ID', $user_id );
|
||||
if ( ! $target_user ) {
|
||||
throw new \GraphQL\Error\UserError( esc_html__( 'User not found', 'ccat' ) );
|
||||
}
|
||||
$secret_key = defined( 'GRAPHQL_JWT_AUTH_SECRET_KEY' ) ? GRAPHQL_JWT_AUTH_SECRET_KEY : wp_salt();
|
||||
$issued_at = time();
|
||||
$expire = $issued_at + ( DAY_IN_SECONDS * 7 );
|
||||
$token_data = array(
|
||||
'iss' => get_bloginfo( 'url' ),
|
||||
'iat' => $issued_at,
|
||||
'nbf' => $issued_at,
|
||||
'exp' => $expire,
|
||||
'data' => array(
|
||||
'user' => array(
|
||||
'id' => $target_user->ID,
|
||||
),
|
||||
'switched_by' => $current_user_id,
|
||||
),
|
||||
);
|
||||
$auth_token = \Firebase\JWT\JWT::encode( $token_data, $secret_key, 'HS256' );
|
||||
$refresh_token_data = array(
|
||||
'iss' => get_bloginfo( 'url' ),
|
||||
'iat' => $issued_at,
|
||||
'nbf' => $issued_at,
|
||||
'exp' => $issued_at + ( DAY_IN_SECONDS * 30 ),
|
||||
'data' => array(
|
||||
'user' => array( 'id' => $target_user->ID ),
|
||||
'switched_by' => $current_user_id,
|
||||
),
|
||||
);
|
||||
$refresh_token = \Firebase\JWT\JWT::encode( $refresh_token_data, $secret_key, 'HS256' );
|
||||
return array(
|
||||
'authToken' => $auth_token,
|
||||
'refreshToken' => $refresh_token,
|
||||
'user' => \WPGraphQL::get_app_context()->get_loader( 'user' )->load_deferred( $target_user->ID ),
|
||||
);
|
||||
}
|
||||
|
||||
// Register userSwitchBack mutation
|
||||
add_action( 'graphql_register_types', 'ccat_graphql_register_user_switch_back' );
|
||||
function ccat_graphql_register_user_switch_back() {
|
||||
register_graphql_mutation(
|
||||
'userSwitchBack',
|
||||
array(
|
||||
'inputFields' => array(),
|
||||
'outputFields' => array(
|
||||
'success' => array(
|
||||
'type' => 'Boolean',
|
||||
'description' => esc_html__( 'Whether switching back was successful', 'ccat' ),
|
||||
),
|
||||
),
|
||||
'mutateAndGetPayload' => 'ccat_graphql_switch_back_mutation',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Callback for userSwitchBack mutation
|
||||
function ccat_graphql_switch_back_mutation() {
|
||||
return array( 'success' => true );
|
||||
}
|
||||
19
wp-content/themes/ccat/server/api/switch-back.post.ts
Normal file
19
wp-content/themes/ccat/server/api/switch-back.post.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { defineEventHandler } from "h3";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const response = await useGraphqlMutation("userSwitchBack");
|
||||
|
||||
if (response.errors?.length) {
|
||||
throw new Error(response.errors[0]?.message || "Switch back failed");
|
||||
}
|
||||
|
||||
await clearUserSession(event);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Switch back failed";
|
||||
return { success: false, message };
|
||||
}
|
||||
});
|
||||
33
wp-content/themes/ccat/server/api/switch-to.post.ts
Normal file
33
wp-content/themes/ccat/server/api/switch-to.post.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { defineEventHandler, readBody } from "h3";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { userId } = await readBody(event);
|
||||
|
||||
try {
|
||||
const currentSession = await getUserSession(event);
|
||||
if (!currentSession?.user) {
|
||||
throw new Error("Authentication required");
|
||||
}
|
||||
|
||||
const response = await useGraphqlMutation("userSwitchTo", { userId });
|
||||
|
||||
if (response.errors?.length) {
|
||||
throw new Error(response.errors[0]?.message || "Switch failed");
|
||||
}
|
||||
|
||||
const { authToken, refreshToken, user } = response.data.userSwitchTo;
|
||||
|
||||
await setUserSession(event, {
|
||||
user,
|
||||
secure: { authToken, refreshToken },
|
||||
loggedInAt: new Date().toISOString(),
|
||||
switchedBy: currentSession.user.id,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Switch failed";
|
||||
return { success: false, message };
|
||||
}
|
||||
});
|
||||
@@ -17146,6 +17146,18 @@ type RootMutation {
|
||||
"""Input for the updateUser mutation"""
|
||||
input: UpdateUserInput!
|
||||
): UpdateUserPayload
|
||||
|
||||
"""The userSwitchBack mutation"""
|
||||
userSwitchBack(
|
||||
"""Input for the userSwitchBack mutation"""
|
||||
input: UserSwitchBackInput!
|
||||
): UserSwitchBackPayload
|
||||
|
||||
"""The userSwitchTo mutation"""
|
||||
userSwitchTo(
|
||||
"""Input for the userSwitchTo mutation"""
|
||||
input: UserSwitchToInput!
|
||||
): UserSwitchToPayload
|
||||
}
|
||||
|
||||
"""The root entry point into the Graph"""
|
||||
@@ -24625,6 +24637,53 @@ enum UserRoleEnum {
|
||||
SUBSCRIBER
|
||||
}
|
||||
|
||||
"""Input for the userSwitchBack mutation."""
|
||||
input UserSwitchBackInput {
|
||||
"""
|
||||
This is an ID that can be passed to a mutation by the client to track the progress of mutations and catch possible duplicate mutation submissions.
|
||||
"""
|
||||
clientMutationId: String
|
||||
}
|
||||
|
||||
"""The payload for the userSwitchBack mutation."""
|
||||
type UserSwitchBackPayload {
|
||||
"""
|
||||
If a 'clientMutationId' input is provided to the mutation, it will be returned as output on the mutation. This ID can be used by the client to track the progress of mutations and catch possible duplicate mutation submissions.
|
||||
"""
|
||||
clientMutationId: String
|
||||
|
||||
"""Whether switching back was successful"""
|
||||
success: Boolean
|
||||
}
|
||||
|
||||
"""Input for the userSwitchTo mutation."""
|
||||
input UserSwitchToInput {
|
||||
"""
|
||||
This is an ID that can be passed to a mutation by the client to track the progress of mutations and catch possible duplicate mutation submissions.
|
||||
"""
|
||||
clientMutationId: String
|
||||
|
||||
"""The ID of the user to switch to"""
|
||||
userId: ID
|
||||
}
|
||||
|
||||
"""The payload for the userSwitchTo mutation."""
|
||||
type UserSwitchToPayload {
|
||||
"""JWT Token for the target user"""
|
||||
authToken: String
|
||||
|
||||
"""
|
||||
If a 'clientMutationId' input is provided to the mutation, it will be returned as output on the mutation. This ID can be used by the client to track the progress of mutations and catch possible duplicate mutation submissions.
|
||||
"""
|
||||
clientMutationId: String
|
||||
|
||||
"""JWT Refresh Token for the target user"""
|
||||
refreshToken: String
|
||||
|
||||
"""The target user object"""
|
||||
user: User
|
||||
}
|
||||
|
||||
"""Connection between the User type and the Comment type"""
|
||||
type UserToCommentConnection implements CommentConnection & Connection {
|
||||
"""Edges for the UserToCommentConnection connection"""
|
||||
|
||||
5
wp-content/themes/ccat/server/graphql/userSwitchBack.gql
Normal file
5
wp-content/themes/ccat/server/graphql/userSwitchBack.gql
Normal file
@@ -0,0 +1,5 @@
|
||||
mutation userSwitchBack {
|
||||
userSwitchBack(input: {}) {
|
||||
success
|
||||
}
|
||||
}
|
||||
17
wp-content/themes/ccat/server/graphql/userSwitchTo.gql
Normal file
17
wp-content/themes/ccat/server/graphql/userSwitchTo.gql
Normal file
@@ -0,0 +1,17 @@
|
||||
mutation userSwitchTo($userId: ID!) {
|
||||
userSwitchTo(input: { userId: $userId }) {
|
||||
authToken
|
||||
refreshToken
|
||||
user {
|
||||
id
|
||||
databaseId
|
||||
username
|
||||
email
|
||||
firstName
|
||||
lastName
|
||||
avatar {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user