Fix server metadata
Some checks are pending
Runs E2E API Tests / build (20.x) (push) Waiting to run
Lint & build / lint_and_build (18.x) (push) Waiting to run
Lint & build / lint_and_build (20.x) (push) Waiting to run

This commit is contained in:
Stan Wohlwend 2024-07-27 15:43:13 -07:00
parent 71f599ca39
commit b3ea2b0425
2 changed files with 112 additions and 39 deletions

View File

@ -519,8 +519,106 @@ describe("with server access", () => {
it.todo("should not be able to create a user");
it.todo("should be able to update a user");
it("should be able to update a user", async ({ expect }) => {
await Auth.Otp.signIn();
const signedInResponse = (await niceBackendFetch("/api/v1/users/me", {
accessType: "server",
}));
const userId = signedInResponse.body.id;
backendContext.set({
userAuth: null,
});
const response1 = await niceBackendFetch("/api/v1/users/" + userId, {
accessType: "server",
method: "PATCH",
body: {
display_name: "John Doe",
server_metadata: { key: "value" },
},
});
expect(response1).toMatchInlineSnapshot(`
NiceResponse {
"status": 200,
"body": {
"auth_with_email": true,
"client_metadata": null,
"display_name": "John Doe",
"has_password": false,
"id": "<stripped UUID>",
"oauth_providers": [],
"primary_email": "<stripped UUID>@stack-generated.example.com",
"primary_email_verified": true,
"profile_image_url": null,
"selected_team": null,
"selected_team_id": null,
"server_metadata": { "key": "value" },
"signed_up_at_millis": <stripped field 'signed_up_at_millis'>,
},
"headers": Headers { <some fields may have been hidden> },
}
`);
const response2 = await niceBackendFetch("/api/v1/users/" + userId, {
accessType: "server",
});
expect(response2).toMatchInlineSnapshot(`
NiceResponse {
"status": 200,
"body": {
"auth_with_email": true,
"client_metadata": null,
"display_name": "John Doe",
"has_password": false,
"id": "<stripped UUID>",
"oauth_providers": [],
"primary_email": "<stripped UUID>@stack-generated.example.com",
"primary_email_verified": true,
"profile_image_url": null,
"selected_team": null,
"selected_team_id": null,
"server_metadata": { "key": "value" },
"signed_up_at_millis": <stripped field 'signed_up_at_millis'>,
},
"headers": Headers { <some fields may have been hidden> },
}
`);
});
it.todo("should be able to delete a user");
it("should be able to delete a user", async ({ expect }) => {
await Auth.Otp.signIn();
const signedInResponse = (await niceBackendFetch("/api/v1/users/me", {
accessType: "server",
}));
const userId = signedInResponse.body.id;
backendContext.set({
userAuth: null,
});
const response1 = await niceBackendFetch("/api/v1/users/" + userId, {
accessType: "server",
method: "DELETE",
});
expect(response1).toMatchInlineSnapshot(`
NiceResponse {
"status": 200,
"body": { "success": true },
"headers": Headers { <some fields may have been hidden> },
}
`);
const response2 = await niceBackendFetch("/api/v1/users/" + userId, {
accessType: "server",
});
expect(response2).toMatchInlineSnapshot(`
NiceResponse {
"status": 404,
"body": {
"code": "USER_NOT_FOUND",
"error": "User not found.",
},
"headers": Headers {
"x-stack-known-error": "USER_NOT_FOUND",
<some fields may have been hidden>,
},
}
`);
});
});

View File

@ -1260,7 +1260,7 @@ class _StackServerAppImpl<HasTokenStore extends boolean, ProjectId extends strin
});
private async _updateServerUser(userId: string, update: ServerUserUpdateOptions): Promise<UsersCrud['Server']['Read']> {
const result = await this._interface.updateServerUser(userId, userUpdateOptionsToCrud(update));
const result = await this._interface.updateServerUser(userId, serverUserUpdateOptionsToCrud(update));
await this._refreshUsers();
return result;
}
@ -1293,22 +1293,11 @@ class _StackServerAppImpl<HasTokenStore extends boolean, ProjectId extends strin
});
}
protected override _createBaseUser(crud: UsersCrud['Server']['Read']): ServerBaseUser & BaseUser;
protected override _createBaseUser(crud: CurrentUserCrud['Client']['Read']): BaseUser;
protected override _createBaseUser(crud: CurrentUserCrud['Client']['Read'] | UsersCrud['Server']['Read']): ({} | ServerBaseUser) & BaseUser {
protected _serverUserFromCrud(crud: UsersCrud['Server']['Read']): ServerUser {
const app = this;
if (!crud) {
throw new StackAssertionError("User not found");
}
return {
...super._createBaseUser(crud),
..."server_metadata" in crud ? {
// server user
serverMetadata: crud.server_metadata,
} : {},
async setServerMetadata(metadata: Record<string, any>) {
await app._updateServerUser(crud.id, { serverMetadata: metadata });
},
serverMetadata: crud.server_metadata,
async setPrimaryEmail(email: string, options?: { verified?: boolean }) {
await app._updateServerUser(crud.id, { primaryEmail: email, primaryEmailVerified: options?.verified });
},
@ -1337,28 +1326,18 @@ class _StackServerAppImpl<HasTokenStore extends boolean, ProjectId extends strin
},
};
},
};
}
protected override _createUserExtra(crud: UsersCrud['Server']['Read']): UserExtra;
protected override _createUserExtra(crud: CurrentUserCrud['Client']['Read']): UserExtra;
protected override _createUserExtra(crud: CurrentUserCrud['Client']['Read'] | UsersCrud['Server']['Read']): UserExtra {
if (!crud) {
throw new StackAssertionError("User not found");
}
const app = this;
return {
async setDisplayName(displayName: string) {
return await this.update({ displayName });
},
async setClientMetadata(metadata: Record<string, any>) {
return await this.update({ clientMetadata: metadata });
},
async setServerMetadata(metadata: Record<string, any>) {
return await this.update({ serverMetadata: metadata });
},
async setSelectedTeam(team: Team | null) {
return await this.update({ selectedTeamId: team?.id ?? null });
},
getConnectedAccount: async () => {
return await app._checkFeatureSupport("getConnectedAccount() on ServerUser", {});
},
@ -1417,13 +1396,6 @@ class _StackServerAppImpl<HasTokenStore extends boolean, ProjectId extends strin
};
}
protected _serverUserFromCrud(crud: UsersCrud['Server']['Read']): ServerUser {
return {
...this._createUserExtra(crud),
...this._createBaseUser(crud),
};
}
protected override _currentUserFromCrud(crud: UsersCrud['Server']['Read'], session: InternalSession): ProjectCurrentServerUser<ProjectId> {
const app = this;
const currentUser = {
@ -2076,6 +2048,7 @@ function userUpdateOptionsToCrud(options: UserUpdateOptions): CurrentUserCrud["C
};
}
type ___________server_user = never; // this is a marker for VSCode's outline view
type ServerBaseUser = {
@ -2124,11 +2097,13 @@ type ServerUserUpdateOptions = {
function serverUserUpdateOptionsToCrud(options: ServerUserUpdateOptions): CurrentUserCrud["Server"]["Update"] {
return {
display_name: options.displayName,
client_metadata: options.clientMetadata,
selected_team_id: options.selectedTeamId,
primary_email: options.primaryEmail,
primary_email_verified: options.primaryEmailVerified,
client_metadata: options.clientMetadata,
server_metadata: options.serverMetadata,
selected_team_id: options.selectedTeamId,
primary_email_auth_enabled: options.primaryEmailAuthEnabled,
primary_email_verified: options.primaryEmailVerified,
password: options.password,
};
}