Added selected team to the user object (#42)

* added selected team

* fixed hooks order bug

* fixed bug

* removed test code

* fixed db schema
This commit is contained in:
Zai Shi 2024-05-21 08:11:28 +02:00 committed by GitHub
parent 982fbb7f61
commit 8e0eb8f472
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 38 additions and 3 deletions

View File

@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "ProjectUser" ADD COLUMN "selectedTeamId" UUID;
-- AddForeignKey
ALTER TABLE "ProjectUser" ADD CONSTRAINT "ProjectUser_projectId_selectedTeamId_fkey" FOREIGN KEY ("projectId", "selectedTeamId") REFERENCES "Team"("projectId", "teamId") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -90,9 +90,10 @@ model Team {
displayName String
project Project @relation(fields: [projectId], references: [id])
permissions Permission[]
teamMembers TeamMember[]
project Project @relation(fields: [projectId], references: [id])
permissions Permission[]
teamMembers TeamMember[]
selectedProjectUser ProjectUser[]
@@id([projectId, teamId])
}
@ -199,6 +200,9 @@ model ProjectUser {
serverMetadata Json?
clientMetadata Json?
selectedTeam Team? @relation(fields: [projectId, selectedTeamId], references: [projectId, teamId])
selectedTeamId String? @db.Uuid
@@id([projectId, projectUserId])
}

View File

@ -52,6 +52,7 @@ export const usersCrudHandlers = createPrismaCrudHandlers(usersCrud, "projectUse
hasPassword: !!prisma.passwordHash,
authWithEmail: prisma.authWithEmail,
oauthProviders: prisma.projectUserOAuthAccounts.map((a) => a.oauthProviderConfigId),
selectedTeamId: prisma.selectedTeamId,
};
},
});

View File

@ -43,6 +43,7 @@ export async function updateClientUser(
{
displayName: update.displayName,
clientMetadata: update.clientMetadata,
selectedTeamId: update.selectedTeamId,
},
);
if (!user) {
@ -76,6 +77,7 @@ export async function updateServerUser(
primaryEmailVerified: update.primaryEmailVerified,
clientMetadata: update.clientMetadata as any,
serverMetadata: update.serverMetadata as any,
selectedTeamId: update.selectedTeamId,
}),
});
} catch (e) {
@ -122,6 +124,7 @@ function getClientUserFromServerUser(serverUser: ServerUserJson): UserJson {
authWithEmail: serverUser.authWithEmail,
hasPassword: serverUser.hasPassword,
oauthProviders: serverUser.oauthProviders,
selectedTeamId: serverUser.selectedTeamId,
};
}
@ -142,6 +145,7 @@ export function getServerUserFromDbType(
hasPassword: !!user.passwordHash,
authWithEmail: user.authWithEmail,
oauthProviders: user.projectUserOAuthAccounts.map((a) => a.oauthProviderConfigId),
selectedTeamId: user.selectedTeamId,
};
}

View File

@ -13,6 +13,7 @@ import { generateSecureRandomString } from '../utils/crypto';
type UserCustomizableJson = {
displayName: string | null,
clientMetadata: ReadonlyJson,
selectedTeamId: string | null,
};
export type UserJson = UserCustomizableJson & {
@ -31,6 +32,7 @@ export type UserJson = UserCustomizableJson & {
hasPassword: boolean,
authWithEmail: boolean,
oauthProviders: string[],
selectedTeamId: string | null,
};
export type UserUpdateJson = Partial<UserCustomizableJson>;

View File

@ -5,6 +5,7 @@ import { usersCrudServerReadSchema, usersCrudServerUpdateSchema } from "./users"
const clientUpdateSchema = usersCrudServerUpdateSchema.pick([
"displayName",
"clientMetadata",
"selectedTeamId",
]).required();
const serverUpdateSchema = usersCrudServerUpdateSchema;
@ -22,6 +23,7 @@ const clientReadSchema = usersCrudServerReadSchema.pick([
"hasPassword",
"authWithEmail",
"oauthProviders",
"selectedTeamId",
]).nullable().defined();
const serverReadSchema = usersCrudServerReadSchema.nullable().defined();

View File

@ -7,6 +7,7 @@ export const usersCrudServerUpdateSchema = yup.object({
serverMetadata: yup.object().optional(),
primaryEmail: yup.string().optional(),
primaryEmailVerified: yup.boolean().optional(),
selectedTeamId: yup.string().nullable().optional(),
}).required();
export const usersCrudServerReadSchema = yup.object({
@ -16,6 +17,7 @@ export const usersCrudServerReadSchema = yup.object({
primaryEmailVerified: yup.boolean().required(),
displayName: yup.string().nullable().defined(),
clientMetadata: yup.object().nullable().defined().transform((value) => JSON.parse(JSON.stringify(value))),
selectedTeamId: yup.string().nullable().defined(),
profileImageUrl: yup.string().nullable().defined(),
signedUpAtMillis: yup.number().required(),
/**

View File

@ -387,6 +387,12 @@ class _StackClientAppImpl<HasTokenStore extends boolean, ProjectId extends strin
hasPassword: json.hasPassword,
authWithEmail: json.authWithEmail,
oauthProviders: json.oauthProviders,
async getSelectedTeam() {
return await this.getTeam(json.selectedTeamId || "");
},
useSelectedTeam() {
return this.useTeam(json.selectedTeamId || "");
},
async getTeam(teamId: string) {
const teams = await this.listTeams();
return teams.find((t) => t.id === teamId) ?? null;
@ -461,6 +467,9 @@ class _StackClientAppImpl<HasTokenStore extends boolean, ProjectId extends strin
const currentUser: CurrentUser = {
...this._userFromJson(json),
tokenStore,
async updateSelectedTeam(team: Team | null) {
await app._updateUser({ selectedTeamId: team?.id ?? null }, tokenStore);
},
update(update) {
return app._updateUser(update, tokenStore);
},
@ -1049,6 +1058,9 @@ class _StackServerAppImpl<HasTokenStore extends boolean, ProjectId extends strin
await app._refreshUser(tokenStore);
return res;
},
async updateSelectedTeam(team: Team | null) {
await this.update({ selectedTeamId: team?.id ?? null });
},
async update(update: ServerUserUpdateJson) {
const res = await nonCurrentServerUser.update(update);
await app._refreshUser(tokenStore);
@ -1421,6 +1433,7 @@ type RedirectToOptions = {
type Auth<T, C> = {
readonly tokenStore: ReadonlyTokenStore,
updateSelectedTeam(this: T, team: Team | null): Promise<void>,
update(this: T, user: C): Promise<void>,
signOut(this: T): Promise<void>,
sendVerificationEmail(this: T): Promise<KnownErrors["EmailAlreadyVerified"] | undefined>,
@ -1461,6 +1474,8 @@ export type User = (
readonly oauthProviders: readonly string[],
hasPermission(this: CurrentUser, scope: Team, permissionId: string): Promise<boolean>,
getSelectedTeam(this: CurrentUser): Promise<Team | null>,
useSelectedTeam(this: CurrentUser): Team | null,
toJson(this: CurrentUser): UserJson,
}