Treat suspended workspace as workspaces that need to be synced (#9669)
In this PR: - migrate WorkspaceActivationStatus to twenty-shared (and update case to make FE and BE consistent) - introduce isWorkspaceActiveOrSuspended in twenty-shared - refactor the code to use it (when we fetch data on the FE, we want to keep SUSPENDED workspace working + when we sync workspaces we want it too)
This commit is contained in:
@ -1,28 +1,26 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||
import { SignInUpService } from 'src/engine/core-modules/auth/services/sign-in-up.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||
import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service';
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||
import {
|
||||
AuthProviderWithPasswordType,
|
||||
ExistingUserOrPartialUserWithPicture,
|
||||
SignInUpBaseParams,
|
||||
} from 'src/engine/core-modules/auth/types/signInUp.type';
|
||||
import {
|
||||
Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
import { UserService } from 'src/engine/core-modules/user/services/user.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
jest.mock('src/utils/image', () => {
|
||||
return {
|
||||
|
||||
@ -3,12 +3,16 @@ import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import FileType from 'file-type';
|
||||
import { TWENTY_ICONS_BASE_URL } from 'twenty-shared';
|
||||
import {
|
||||
TWENTY_ICONS_BASE_URL,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'twenty-shared';
|
||||
import { Repository } from 'typeorm';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
|
||||
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||
import {
|
||||
AuthException,
|
||||
AuthExceptionCode,
|
||||
@ -18,22 +22,6 @@ import {
|
||||
compareHash,
|
||||
hashPassword,
|
||||
} from 'src/engine/core-modules/auth/auth.util';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service';
|
||||
import {
|
||||
Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
|
||||
import { getDomainNameByEmail } from 'src/utils/get-domain-name-by-email';
|
||||
import { getImageBufferFromUrl } from 'src/utils/image';
|
||||
import { isWorkEmail } from 'src/utils/is-work-email';
|
||||
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||
import {
|
||||
AuthProviderWithPasswordType,
|
||||
ExistingUserOrPartialUserWithPicture,
|
||||
@ -41,7 +29,19 @@ import {
|
||||
SignInUpBaseParams,
|
||||
SignInUpNewUserPayload,
|
||||
} from 'src/engine/core-modules/auth/types/signInUp.type';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
import { UserService } from 'src/engine/core-modules/user/services/user.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
|
||||
import { getDomainNameByEmail } from 'src/utils/get-domain-name-by-email';
|
||||
import { getImageBufferFromUrl } from 'src/utils/image';
|
||||
import { isWorkEmail } from 'src/utils/is-work-email';
|
||||
|
||||
@Injectable()
|
||||
// eslint-disable-next-line @nx/workspace-inject-workspace-repository
|
||||
|
||||
@ -2,6 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { Request } from 'express';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||
@ -12,10 +13,7 @@ import { EnvironmentService } from 'src/engine/core-modules/environment/environm
|
||||
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
||||
import { SSOService } from 'src/engine/core-modules/sso/services/sso.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import {
|
||||
Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
|
||||
import { AccessTokenService } from './access-token.service';
|
||||
|
||||
@ -5,6 +5,7 @@ import { addMilliseconds } from 'date-fns';
|
||||
import { Request } from 'express';
|
||||
import ms from 'ms';
|
||||
import { ExtractJwt } from 'passport-jwt';
|
||||
import { isWorkspaceActiveOrSuspended } from 'twenty-shared';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
@ -20,14 +21,11 @@ import {
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import {
|
||||
Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { userValidator } from 'src/engine/core-modules/user/user.validate';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
|
||||
import { userValidator } from 'src/engine/core-modules/user/user.validate';
|
||||
|
||||
@Injectable()
|
||||
export class AccessTokenService {
|
||||
@ -67,7 +65,7 @@ export class AccessTokenService {
|
||||
|
||||
workspaceValidator.assertIsDefinedOrThrow(workspace);
|
||||
|
||||
if (workspace.activationStatus === WorkspaceActivationStatus.ACTIVE) {
|
||||
if (isWorkspaceActiveOrSuspended(workspace)) {
|
||||
const workspaceMemberRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
|
||||
workspaceId,
|
||||
|
||||
@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import Stripe from 'stripe';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { BillingCustomer } from 'src/engine/core-modules/billing/entities/billing-customer.entity';
|
||||
@ -12,10 +13,7 @@ import { StripeCustomerService } from 'src/engine/core-modules/billing/stripe/se
|
||||
import { transformStripeSubscriptionEventToCustomerRepositoryData } from 'src/engine/core-modules/billing/utils/transform-stripe-subscription-event-to-customer-repository-data.util';
|
||||
import { transformStripeSubscriptionEventToSubscriptionItemRepositoryData } from 'src/engine/core-modules/billing/utils/transform-stripe-subscription-event-to-subscription-item-repository-data.util';
|
||||
import { transformStripeSubscriptionEventToSubscriptionRepositoryData } from 'src/engine/core-modules/billing/utils/transform-stripe-subscription-event-to-subscription-repository-data.util';
|
||||
import {
|
||||
Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
@Injectable()
|
||||
export class BillingWebhookSubscriptionService {
|
||||
protected readonly logger = new Logger(
|
||||
@ -88,10 +86,11 @@ export class BillingWebhookSubscriptionService {
|
||||
|
||||
if (
|
||||
data.object.status === SubscriptionStatus.Canceled ||
|
||||
data.object.status === SubscriptionStatus.Unpaid
|
||||
data.object.status === SubscriptionStatus.Unpaid ||
|
||||
data.object.status === SubscriptionStatus.Paused
|
||||
) {
|
||||
await this.workspaceRepository.update(workspaceId, {
|
||||
activationStatus: WorkspaceActivationStatus.INACTIVE,
|
||||
activationStatus: WorkspaceActivationStatus.SUSPENDED,
|
||||
});
|
||||
}
|
||||
|
||||
@ -99,7 +98,7 @@ export class BillingWebhookSubscriptionService {
|
||||
(data.object.status === SubscriptionStatus.Active ||
|
||||
data.object.status === SubscriptionStatus.Trialing ||
|
||||
data.object.status === SubscriptionStatus.PastDue) &&
|
||||
workspace.activationStatus == WorkspaceActivationStatus.INACTIVE
|
||||
workspace.activationStatus == WorkspaceActivationStatus.SUSPENDED
|
||||
) {
|
||||
await this.workspaceRepository.update(workspaceId, {
|
||||
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared';
|
||||
|
||||
import { BillingService } from 'src/engine/core-modules/billing/services/billing.service';
|
||||
import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum';
|
||||
import { UserVarsService } from 'src/engine/core-modules/user/user-vars/services/user-vars.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import {
|
||||
Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
export enum OnboardingStepKeys {
|
||||
ONBOARDING_CONNECT_ACCOUNT_PENDING = 'ONBOARDING_CONNECT_ACCOUNT_PENDING',
|
||||
|
||||
@ -3,6 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import assert from 'assert';
|
||||
|
||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { isWorkspaceActiveOrSuspended } from 'twenty-shared';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
@ -14,10 +15,7 @@ import {
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { userValidator } from 'src/engine/core-modules/user/user.validate';
|
||||
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
|
||||
import {
|
||||
Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
@ -41,10 +39,7 @@ export class UserService extends TypeOrmQueryService<User> {
|
||||
}
|
||||
|
||||
async loadWorkspaceMember(user: User, workspace: Workspace) {
|
||||
if (
|
||||
workspace?.activationStatus !== WorkspaceActivationStatus.ACTIVE &&
|
||||
workspace?.activationStatus !== WorkspaceActivationStatus.SUSPENDED
|
||||
) {
|
||||
if (!isWorkspaceActiveOrSuspended(workspace)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -62,7 +57,7 @@ export class UserService extends TypeOrmQueryService<User> {
|
||||
}
|
||||
|
||||
async loadWorkspaceMembers(workspace: Workspace) {
|
||||
if (workspace.activationStatus !== WorkspaceActivationStatus.ACTIVE) {
|
||||
if (!isWorkspaceActiveOrSuspended(workspace)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import assert from 'assert';
|
||||
|
||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
|
||||
@ -14,10 +15,7 @@ import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-works
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { ActivateWorkspaceInput } from 'src/engine/core-modules/workspace/dtos/activate-workspace-input';
|
||||
import {
|
||||
Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import {
|
||||
WorkspaceException,
|
||||
WorkspaceExceptionCode,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
|
||||
|
||||
import { IDField, UnPagedRelation } from '@ptc-org/nestjs-query-graphql';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared';
|
||||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
@ -23,14 +24,6 @@ import { PostgresCredentials } from 'src/engine/core-modules/postgres-credential
|
||||
import { WorkspaceSSOIdentityProvider } from 'src/engine/core-modules/sso/workspace-sso-identity-provider.entity';
|
||||
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
|
||||
export enum WorkspaceActivationStatus {
|
||||
ONGOING_CREATION = 'ONGOING_CREATION',
|
||||
PENDING_CREATION = 'PENDING_CREATION',
|
||||
ACTIVE = 'ACTIVE',
|
||||
INACTIVE = 'INACTIVE',
|
||||
SUSPENDED = 'SUSPENDED',
|
||||
}
|
||||
|
||||
registerEnumType(WorkspaceActivationStatus, {
|
||||
name: 'WorkspaceActivationStatus',
|
||||
});
|
||||
|
||||
@ -1,17 +1,16 @@
|
||||
import {
|
||||
Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
} from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { CustomException } from 'src/utils/custom-exception';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared';
|
||||
|
||||
import {
|
||||
AuthException,
|
||||
AuthExceptionCode,
|
||||
} from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { WorkspaceAuthProvider } from 'src/engine/core-modules/workspace/types/workspace.type';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import {
|
||||
WorkspaceException,
|
||||
WorkspaceExceptionCode,
|
||||
} from 'src/engine/core-modules/workspace/workspace.exception';
|
||||
import { CustomException } from 'src/utils/custom-exception';
|
||||
|
||||
const assertIsDefinedOrThrow = (
|
||||
workspace: Workspace | undefined | null,
|
||||
|
||||
Reference in New Issue
Block a user