feat(core): impl invitation link (#11181)

feat(core): add invitee to getInviteInfoQuery

feat(core): enable invitation link

refactor(core): replace AcceptInviteService to InvitationService
This commit is contained in:
JimmFly
2025-03-26 02:45:12 +00:00
parent 64b25dfd89
commit 014556b61f
19 changed files with 409 additions and 116 deletions
@@ -7,13 +7,13 @@ export { AccountLoggedOut } from './events/account-logged-out';
export { AuthProvider } from './provider/auth';
export { ValidatorProvider } from './provider/validator';
export { ServerScope } from './scopes/server';
export { AcceptInviteService } from './services/accept-invite';
export { AuthService } from './services/auth';
export { CaptchaService } from './services/captcha';
export { DefaultServerService } from './services/default-server';
export { EventSourceService } from './services/eventsource';
export { FetchService } from './services/fetch';
export { GraphQLService } from './services/graphql';
export { InvitationService } from './services/invitation';
export { InvoicesService } from './services/invoices';
export { PublicUserService } from './services/public-user';
export { SelfhostGenerateLicenseService } from './services/selfhost-generate-license';
@@ -33,6 +33,7 @@ export { WorkspaceServerService } from './services/workspace-server';
export { WorkspaceSubscriptionService } from './services/workspace-subscription';
export type { ServerConfig } from './types';
// eslint-disable-next-line simple-import-sort/imports
import { type Framework } from '@toeverything/infra';
import { DocScope } from '../doc/scopes/doc';
@@ -56,7 +57,7 @@ import { configureDefaultAuthProvider } from './impl/auth';
import { AuthProvider } from './provider/auth';
import { ValidatorProvider } from './provider/validator';
import { ServerScope } from './scopes/server';
import { AcceptInviteService } from './services/accept-invite';
import { InvitationService } from './services/invitation';
import { AuthService } from './services/auth';
import { BlocksuiteWriterInfoService } from './services/blocksuite-writer-info';
import { CaptchaService } from './services/captcha';
@@ -153,7 +154,7 @@ export function configureCloudModule(framework: Framework) {
.service(SelfhostGenerateLicenseService, [SelfhostGenerateLicenseStore])
.store(SelfhostGenerateLicenseStore, [GraphQLService])
.store(InviteInfoStore, [GraphQLService])
.service(AcceptInviteService, [AcceptInviteStore, InviteInfoStore])
.service(InvitationService, [AcceptInviteStore, InviteInfoStore])
.store(AcceptInviteStore, [GraphQLService])
.service(PublicUserService, [PublicUserStore])
.store(PublicUserStore, [GraphQLService])
@@ -16,20 +16,19 @@ import type { InviteInfoStore } from '../stores/invite-info';
export type InviteInfo = GetInviteInfoQuery['getInviteInfo'];
export class AcceptInviteService extends Service {
export class InvitationService extends Service {
constructor(
private readonly store: AcceptInviteStore,
private readonly acceptInviteStore: AcceptInviteStore,
private readonly inviteInfoStore: InviteInfoStore
) {
super();
}
inviteId$ = new LiveData<string | undefined>(undefined);
inviteInfo$ = new LiveData<InviteInfo | undefined>(undefined);
accepted$ = new LiveData<boolean>(false);
loading$ = new LiveData(false);
error$ = new LiveData<any>(null);
readonly acceptInvite = effect(
readonly getInviteInfo = effect(
switchMap(({ inviteId }: { inviteId: string }) => {
if (!inviteId) {
return EMPTY;
@@ -39,16 +38,6 @@ export class AcceptInviteService extends Service {
}).pipe(
mergeMap(res => {
this.inviteInfo$.setValue(res);
return fromPromise(async () => {
return await this.store.acceptInvite(
res.workspace.id,
inviteId,
true
);
});
}),
mergeMap(res => {
this.accepted$.next(res);
return EMPTY;
}),
smartRetry({
@@ -59,7 +48,6 @@ export class AcceptInviteService extends Service {
this.inviteId$.setValue(inviteId);
this.loading$.setValue(true);
this.inviteInfo$.setValue(undefined);
this.accepted$.setValue(false);
}),
onComplete(() => {
this.loading$.setValue(false);
@@ -68,21 +56,20 @@ export class AcceptInviteService extends Service {
})
);
async waitForAcceptInvite(inviteId: string) {
this.acceptInvite({ inviteId });
async acceptInvite(inviteId: string) {
this.getInviteInfo({ inviteId });
await this.loading$.waitFor(f => !f);
if (this.accepted$.value) {
return true; // invite is accepted
if (!this.inviteInfo$.value) {
throw new Error('Invalid invite id');
}
if (this.error$.value) {
throw this.error$.value;
}
return false; // invite is expired
return await this.acceptInviteStore.acceptInvite(
this.inviteInfo$.value.workspace.id,
inviteId,
true
);
}
override dispose(): void {
this.acceptInvite.unsubscribe();
this.getInviteInfo.unsubscribe();
}
}