diff --git a/front/src/App.tsx b/front/src/App.tsx
index 2cce1173b..596b3e0c6 100644
--- a/front/src/App.tsx
+++ b/front/src/App.tsx
@@ -39,6 +39,7 @@ function AuthRoutes() {
} />
} />
} />
+ } />
}
diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx
index 26f71c67f..fc6a5fbcb 100644
--- a/front/src/generated/graphql.tsx
+++ b/front/src/generated/graphql.tsx
@@ -1163,6 +1163,7 @@ export type Mutation = {
deleteManyPipelineProgress: AffectedRows;
deleteWorkspaceMember: WorkspaceMember;
renewToken: AuthTokens;
+ signUp: LoginToken;
updateOneCommentThread: CommentThread;
updateOneCompany?: Maybe;
updateOnePerson?: Maybe;
@@ -1244,6 +1245,13 @@ export type MutationRenewTokenArgs = {
};
+export type MutationSignUpArgs = {
+ email: Scalars['String'];
+ password: Scalars['String'];
+ workspaceInviteHash?: InputMaybe;
+};
+
+
export type MutationUpdateOneCommentThreadArgs = {
data: CommentThreadUpdateInput;
where: CommentThreadWhereUniqueInput;
@@ -2439,6 +2447,7 @@ export type PipelineWhereUniqueInput = {
export type Query = {
__typename?: 'Query';
checkUserExists: UserExists;
+ checkWorkspaceInviteHashIsValid: WorkspaceInviteHashValid;
clientConfig: ClientConfig;
currentUser: User;
currentWorkspace: Workspace;
@@ -2460,6 +2469,11 @@ export type QueryCheckUserExistsArgs = {
};
+export type QueryCheckWorkspaceInviteHashIsValidArgs = {
+ inviteHash: Scalars['String'];
+};
+
+
export type QueryFindManyCommentThreadsArgs = {
cursor?: InputMaybe;
distinct?: InputMaybe>;
@@ -2917,6 +2931,7 @@ export type Workspace = {
displayName?: Maybe;
domainName?: Maybe;
id: Scalars['ID'];
+ inviteHash?: Maybe;
logo?: Maybe;
people?: Maybe>;
pipelineProgresses?: Maybe>;
@@ -2926,6 +2941,11 @@ export type Workspace = {
workspaceMember?: Maybe>;
};
+export type WorkspaceInviteHashValid = {
+ __typename?: 'WorkspaceInviteHashValid';
+ isValid: Scalars['Boolean'];
+};
+
export type WorkspaceMember = {
__typename?: 'WorkspaceMember';
createdAt: Scalars['DateTime'];
@@ -3054,6 +3074,7 @@ export type WorkspaceUpdateInput = {
displayName?: InputMaybe;
domainName?: InputMaybe;
id?: InputMaybe;
+ inviteHash?: InputMaybe;
logo?: InputMaybe;
people?: InputMaybe;
pipelineProgresses?: InputMaybe;
@@ -3086,6 +3107,23 @@ export type ChallengeMutationVariables = Exact<{
export type ChallengeMutation = { __typename?: 'Mutation', challenge: { __typename?: 'LoginToken', loginToken: { __typename?: 'AuthToken', expiresAt: string, token: string } } };
+export type SignUpMutationVariables = Exact<{
+ email: Scalars['String'];
+ password: Scalars['String'];
+}>;
+
+
+export type SignUpMutation = { __typename?: 'Mutation', signUp: { __typename?: 'LoginToken', loginToken: { __typename?: 'AuthToken', expiresAt: string, token: string } } };
+
+export type SignUpToWorkspaceMutationVariables = Exact<{
+ email: Scalars['String'];
+ password: Scalars['String'];
+ workspaceInviteHash: Scalars['String'];
+}>;
+
+
+export type SignUpToWorkspaceMutation = { __typename?: 'Mutation', signUp: { __typename?: 'LoginToken', loginToken: { __typename?: 'AuthToken', expiresAt: string, token: string } } };
+
export type VerifyMutationVariables = Exact<{
loginToken: Scalars['String'];
}>;
@@ -3526,6 +3564,85 @@ export function useChallengeMutation(baseOptions?: Apollo.MutationHookOptions;
export type ChallengeMutationResult = Apollo.MutationResult;
export type ChallengeMutationOptions = Apollo.BaseMutationOptions;
+export const SignUpDocument = gql`
+ mutation SignUp($email: String!, $password: String!) {
+ signUp(email: $email, password: $password) {
+ loginToken {
+ expiresAt
+ token
+ }
+ }
+}
+ `;
+export type SignUpMutationFn = Apollo.MutationFunction;
+
+/**
+ * __useSignUpMutation__
+ *
+ * To run a mutation, you first call `useSignUpMutation` within a React component and pass it any options that fit your needs.
+ * When your component renders, `useSignUpMutation` returns a tuple that includes:
+ * - A mutate function that you can call at any time to execute the mutation
+ * - An object with fields that represent the current status of the mutation's execution
+ *
+ * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
+ *
+ * @example
+ * const [signUpMutation, { data, loading, error }] = useSignUpMutation({
+ * variables: {
+ * email: // value for 'email'
+ * password: // value for 'password'
+ * },
+ * });
+ */
+export function useSignUpMutation(baseOptions?: Apollo.MutationHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useMutation(SignUpDocument, options);
+ }
+export type SignUpMutationHookResult = ReturnType;
+export type SignUpMutationResult = Apollo.MutationResult;
+export type SignUpMutationOptions = Apollo.BaseMutationOptions;
+export const SignUpToWorkspaceDocument = gql`
+ mutation SignUpToWorkspace($email: String!, $password: String!, $workspaceInviteHash: String!) {
+ signUp(
+ email: $email
+ password: $password
+ workspaceInviteHash: $workspaceInviteHash
+ ) {
+ loginToken {
+ expiresAt
+ token
+ }
+ }
+}
+ `;
+export type SignUpToWorkspaceMutationFn = Apollo.MutationFunction;
+
+/**
+ * __useSignUpToWorkspaceMutation__
+ *
+ * To run a mutation, you first call `useSignUpToWorkspaceMutation` within a React component and pass it any options that fit your needs.
+ * When your component renders, `useSignUpToWorkspaceMutation` returns a tuple that includes:
+ * - A mutate function that you can call at any time to execute the mutation
+ * - An object with fields that represent the current status of the mutation's execution
+ *
+ * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
+ *
+ * @example
+ * const [signUpToWorkspaceMutation, { data, loading, error }] = useSignUpToWorkspaceMutation({
+ * variables: {
+ * email: // value for 'email'
+ * password: // value for 'password'
+ * workspaceInviteHash: // value for 'workspaceInviteHash'
+ * },
+ * });
+ */
+export function useSignUpToWorkspaceMutation(baseOptions?: Apollo.MutationHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useMutation(SignUpToWorkspaceDocument, options);
+ }
+export type SignUpToWorkspaceMutationHookResult = ReturnType;
+export type SignUpToWorkspaceMutationResult = Apollo.MutationResult;
+export type SignUpToWorkspaceMutationOptions = Apollo.BaseMutationOptions;
export const VerifyDocument = gql`
mutation Verify($loginToken: String!) {
verify(loginToken: $loginToken) {
diff --git a/front/src/index.tsx b/front/src/index.tsx
index 639529492..95070ddec 100644
--- a/front/src/index.tsx
+++ b/front/src/index.tsx
@@ -27,15 +27,15 @@ root.render(
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/front/src/modules/auth/hooks/useAuth.ts b/front/src/modules/auth/hooks/useAuth.ts
index 3584a0f07..90bfdde7a 100644
--- a/front/src/modules/auth/hooks/useAuth.ts
+++ b/front/src/modules/auth/hooks/useAuth.ts
@@ -1,7 +1,12 @@
import { useCallback } from 'react';
import { useRecoilState } from 'recoil';
-import { useChallengeMutation, useVerifyMutation } from '~/generated/graphql';
+import {
+ useChallengeMutation,
+ useSignUpMutation,
+ useSignUpToWorkspaceMutation,
+ useVerifyMutation,
+} from '~/generated/graphql';
import { currentUserState } from '../states/currentUserState';
import { isAuthenticatingState } from '../states/isAuthenticatingState';
@@ -13,6 +18,8 @@ export function useAuth() {
const [, setIsAuthenticating] = useRecoilState(isAuthenticatingState);
const [challenge] = useChallengeMutation();
+ const [signUp] = useSignUpMutation();
+ const [SignUpToWorkspace] = useSignUpToWorkspaceMutation();
const [verify] = useVerifyMutation();
const handleChallenge = useCallback(
@@ -74,10 +81,57 @@ export function useAuth() {
setTokenPair(null);
}, [setTokenPair]);
+ const handleSignUp = useCallback(
+ async (email: string, password: string) => {
+ const signUpResult = await signUp({
+ variables: {
+ email,
+ password,
+ },
+ });
+
+ if (signUpResult.errors) {
+ throw signUpResult.errors;
+ }
+
+ if (!signUpResult.data?.signUp) {
+ throw new Error('No login token');
+ }
+
+ await handleVerify(signUpResult.data?.signUp.loginToken.token);
+ },
+ [signUp, handleVerify],
+ );
+
+ const handleSignUpToWorkspace = useCallback(
+ async (email: string, password: string, workspaceInviteHash: string) => {
+ const signUpResult = await SignUpToWorkspace({
+ variables: {
+ email,
+ password,
+ workspaceInviteHash,
+ },
+ });
+
+ if (signUpResult.errors) {
+ throw signUpResult.errors;
+ }
+
+ if (!signUpResult.data?.signUp) {
+ throw new Error('No login token');
+ }
+
+ await handleVerify(signUpResult.data?.signUp.loginToken.token);
+ },
+ [SignUpToWorkspace, handleVerify],
+ );
+
return {
challenge: handleChallenge,
verify: handleVerify,
login: handleLogin,
+ signUp: handleSignUp,
+ signUpToWorkspace: handleSignUpToWorkspace,
logout: handleLogout,
};
}
diff --git a/front/src/modules/auth/services/update.ts b/front/src/modules/auth/services/update.ts
index ac6e61241..8b2e30c45 100644
--- a/front/src/modules/auth/services/update.ts
+++ b/front/src/modules/auth/services/update.ts
@@ -11,6 +11,36 @@ export const CHALLENGE = gql`
}
`;
+export const SIGN_UP = gql`
+ mutation SignUp($email: String!, $password: String!) {
+ signUp(email: $email, password: $password) {
+ loginToken {
+ expiresAt
+ token
+ }
+ }
+ }
+`;
+
+export const SIGN_UP_TO_WORKSPACE = gql`
+ mutation SignUpToWorkspace(
+ $email: String!
+ $password: String!
+ $workspaceInviteHash: String!
+ ) {
+ signUp(
+ email: $email
+ password: $password
+ workspaceInviteHash: $workspaceInviteHash
+ ) {
+ loginToken {
+ expiresAt
+ token
+ }
+ }
+ }
+`;
+
export const VERIFY = gql`
mutation Verify($loginToken: String!) {
verify(loginToken: $loginToken) {
diff --git a/front/src/modules/comments/components/right-drawer/CommentThread.tsx b/front/src/modules/comments/components/right-drawer/CommentThread.tsx
index 48af42021..277cc76d8 100644
--- a/front/src/modules/comments/components/right-drawer/CommentThread.tsx
+++ b/front/src/modules/comments/components/right-drawer/CommentThread.tsx
@@ -130,10 +130,10 @@ export function CommentThread({
}
useEffect(() => {
- if (commentThread) {
+ if (commentThread && !title) {
setTitle(commentThread?.title ?? '');
}
- }, [commentThread]);
+ }, [commentThread, title]);
if (!commentThread) {
return <>>;
diff --git a/front/src/pages/auth/PasswordLogin.tsx b/front/src/pages/auth/PasswordLogin.tsx
index 341f49e93..1a23939e8 100644
--- a/front/src/pages/auth/PasswordLogin.tsx
+++ b/front/src/pages/auth/PasswordLogin.tsx
@@ -1,5 +1,5 @@
-import { useCallback, useState } from 'react';
-import { useNavigate } from 'react-router-dom';
+import { useCallback, useEffect, useState } from 'react';
+import { useNavigate, useParams } from 'react-router-dom';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { useRecoilState } from 'recoil';
@@ -62,35 +62,61 @@ export function PasswordLogin() {
);
const [formError, setFormError] = useState('');
- const { login } = useAuth();
-
- const handleLogin = useCallback(async () => {
- try {
- setMockMode(false);
-
- await login(authFlowUserEmail, internalPassword);
-
- navigate('/auth/create/workspace');
- } catch (err: any) {
- setFormError(err.message);
- }
- }, [login, authFlowUserEmail, internalPassword, setMockMode, navigate]);
-
- useScopedHotkeys(
- 'enter',
- () => {
- handleLogin();
- },
- InternalHotkeysScope.PasswordLogin,
- [handleLogin],
- );
-
+ const { login, signUp, signUpToWorkspace } = useAuth();
const { loading, data } = useCheckUserExistsQuery({
variables: {
email: authFlowUserEmail,
},
});
+ useEffect(() => {
+ setMockMode(true);
+ }, [setMockMode]);
+
+ const workspaceInviteHash = useParams().workspaceInviteHash;
+
+ const handleSubmit = useCallback(async () => {
+ try {
+ setMockMode(false);
+ if (data?.checkUserExists.exists) {
+ await login(authFlowUserEmail, internalPassword);
+ } else {
+ if (workspaceInviteHash) {
+ await signUpToWorkspace(
+ authFlowUserEmail,
+ internalPassword,
+ workspaceInviteHash,
+ );
+ } else {
+ await signUp(authFlowUserEmail, internalPassword);
+ }
+ }
+ navigate('/auth/create/workspace');
+ } catch (err: any) {
+ setFormError(err.message);
+ }
+ }, [
+ login,
+ signUp,
+ signUpToWorkspace,
+ authFlowUserEmail,
+ internalPassword,
+ setMockMode,
+ navigate,
+ data?.checkUserExists.exists,
+
+ workspaceInviteHash,
+ ]);
+
+ useScopedHotkeys(
+ 'enter',
+ () => {
+ handleSubmit();
+ },
+ InternalHotkeysScope.PasswordLogin,
+ [handleSubmit],
+ );
+
return (
<>
@@ -124,7 +150,7 @@ export function PasswordLogin() {
diff --git a/front/src/sync-hooks/types/AuthPath.ts b/front/src/sync-hooks/types/AuthPath.ts
index e528e46ad..3d3c3aca4 100644
--- a/front/src/sync-hooks/types/AuthPath.ts
+++ b/front/src/sync-hooks/types/AuthPath.ts
@@ -4,4 +4,5 @@ export enum AuthPath {
PasswordLogin = 'password-login',
CreateWorkspace = 'create/workspace',
CreateProfile = 'create/profile',
+ InviteLink = 'invite/:workspaceInviteHash',
}
diff --git a/front/src/testing/mock-data/users.ts b/front/src/testing/mock-data/users.ts
index 8893faf04..d6f45cb15 100644
--- a/front/src/testing/mock-data/users.ts
+++ b/front/src/testing/mock-data/users.ts
@@ -13,7 +13,7 @@ type MockedUser = Pick<
workspaceMember: Pick & {
workspace: Pick<
Workspace,
- 'id' | 'displayName' | 'domainName' | 'logo' | '__typename'
+ 'id' | 'displayName' | 'domainName' | 'logo' | 'inviteHash' | '__typename'
>;
};
};
@@ -35,6 +35,7 @@ export const mockedUsersData: Array = [
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
displayName: 'Twenty',
domainName: 'twenty.com',
+ inviteHash: 'twenty.com-invite-hash',
logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACb0lEQVR4nO2VO4taQRTHr3AblbjxEVlwCwVhg7BoqqCIjy/gAyyFWNlYBOxsfH0KuxgQGwXRUkGuL2S7i1barGAgiwbdW93SnGOc4BonPiKahf3DwXFmuP/fPM4ZlvmlTxAhCBdzHnEQWYiv7Mr4C3NeuVYhQYDPzOUUQgDLBQGcLHNhvQK8DACPx8PTxiqVyvISG43GbyaT6Qfpn06n0m63e/tPAPF4vJ1MJu8kEsnWTCkWi1yr1RKGw+GDRqPBOTfr44vFQvD7/Q/lcpmaaVQAr9fLp1IpO22c47hGOBz+MB6PH+Vy+VYDAL8qlUoGtVotzOfzq4MAgsHgE/6KojiQyWR/bKVSqbSszHFM8Pl8z1YK48JsNltCOBwOnrYLO+8AAIjb+nHbycoTiUQfDJ7tFq4YAHiVSmXBxcD41u8flQU8z7fhzO0r83atVns3Go3u9Xr9x0O/RQXo9/tsIBBg6vX606a52Wz+bZ7P5/WwG29gxSJzhKgA6XTaDoFNF+krFAocmC//4yWEcSf2wTm7mCO19xFgSsKOLI16vV7b7XY7mRNoLwA0JymJ5uQIzgIAuX5PzDElT2m+E8BqtQ4ymcx7Yq7T6a6ZE4sKgOadTucaCwkxp1UzlEKh0GDxIXOwDWHAdi6Xe3swQDQa/Q7mywoolUpvsaptymazDWKxmBHTlWXZm405BFZoNpuGgwEmk4mE2SGtVivii4f1AO7J3ZopkQCQj7Ar1FeRChCJRJzVapX6DKNIfSc1Ax+wtQWQ55h6bH8FWDfYV4fO3wlwDr0C/BcADYiTPCxHqIEA2QsCZAkAKnRGkMbKN/sTX5YHPQ1e7SkAAAAASUVORK5CYII=',
},
},
@@ -54,6 +55,7 @@ export const mockedUsersData: Array = [
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
displayName: 'Twenty',
domainName: 'twenty.com',
+ inviteHash: 'twenty.com-invite-hash',
logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACb0lEQVR4nO2VO4taQRTHr3AblbjxEVlwCwVhg7BoqqCIjy/gAyyFWNlYBOxsfH0KuxgQGwXRUkGuL2S7i1barGAgiwbdW93SnGOc4BonPiKahf3DwXFmuP/fPM4ZlvmlTxAhCBdzHnEQWYiv7Mr4C3NeuVYhQYDPzOUUQgDLBQGcLHNhvQK8DACPx8PTxiqVyvISG43GbyaT6Qfpn06n0m63e/tPAPF4vJ1MJu8kEsnWTCkWi1yr1RKGw+GDRqPBOTfr44vFQvD7/Q/lcpmaaVQAr9fLp1IpO22c47hGOBz+MB6PH+Vy+VYDAL8qlUoGtVotzOfzq4MAgsHgE/6KojiQyWR/bKVSqbSszHFM8Pl8z1YK48JsNltCOBwOnrYLO+8AAIjb+nHbycoTiUQfDJ7tFq4YAHiVSmXBxcD41u8flQU8z7fhzO0r83atVns3Go3u9Xr9x0O/RQXo9/tsIBBg6vX606a52Wz+bZ7P5/WwG29gxSJzhKgA6XTaDoFNF+krFAocmC//4yWEcSf2wTm7mCO19xFgSsKOLI16vV7b7XY7mRNoLwA0JymJ5uQIzgIAuX5PzDElT2m+E8BqtQ4ymcx7Yq7T6a6ZE4sKgOadTucaCwkxp1UzlEKh0GDxIXOwDWHAdi6Xe3swQDQa/Q7mywoolUpvsaptymazDWKxmBHTlWXZm405BFZoNpuGgwEmk4mE2SGtVivii4f1AO7J3ZopkQCQj7Ar1FeRChCJRJzVapX6DKNIfSc1Ax+wtQWQ55h6bH8FWDfYV4fO3wlwDr0C/BcADYiTPCxHqIEA2QsCZAkAKnRGkMbKN/sTX5YHPQ1e7SkAAAAASUVORK5CYII=',
},
},
diff --git a/server/src/core/@generated/workspace/workspace-count-aggregate.input.ts b/server/src/core/@generated/workspace/workspace-count-aggregate.input.ts
index f1d672e1b..3037aa5b2 100644
--- a/server/src/core/@generated/workspace/workspace-count-aggregate.input.ts
+++ b/server/src/core/@generated/workspace/workspace-count-aggregate.input.ts
@@ -17,6 +17,9 @@ export class WorkspaceCountAggregateInput {
@Field(() => Boolean, {nullable:true})
logo?: true;
+ @Field(() => Boolean, {nullable:true})
+ inviteHash?: true;
+
@HideField()
deletedAt?: true;
diff --git a/server/src/core/@generated/workspace/workspace-count-aggregate.output.ts b/server/src/core/@generated/workspace/workspace-count-aggregate.output.ts
index df84d04c0..8cdb999f4 100644
--- a/server/src/core/@generated/workspace/workspace-count-aggregate.output.ts
+++ b/server/src/core/@generated/workspace/workspace-count-aggregate.output.ts
@@ -18,6 +18,9 @@ export class WorkspaceCountAggregate {
@Field(() => Int, {nullable:false})
logo!: number;
+ @Field(() => Int, {nullable:false})
+ inviteHash!: number;
+
@HideField()
deletedAt!: number;
diff --git a/server/src/core/@generated/workspace/workspace-count-order-by-aggregate.input.ts b/server/src/core/@generated/workspace/workspace-count-order-by-aggregate.input.ts
index 8ae33e3e0..5e64ba8f3 100644
--- a/server/src/core/@generated/workspace/workspace-count-order-by-aggregate.input.ts
+++ b/server/src/core/@generated/workspace/workspace-count-order-by-aggregate.input.ts
@@ -18,6 +18,9 @@ export class WorkspaceCountOrderByAggregateInput {
@Field(() => SortOrder, {nullable:true})
logo?: keyof typeof SortOrder;
+ @Field(() => SortOrder, {nullable:true})
+ inviteHash?: keyof typeof SortOrder;
+
@HideField()
deletedAt?: keyof typeof SortOrder;
diff --git a/server/src/core/@generated/workspace/workspace-create-many.input.ts b/server/src/core/@generated/workspace/workspace-create-many.input.ts
index 1059d52aa..ea966b3c9 100644
--- a/server/src/core/@generated/workspace/workspace-create-many.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create-many.input.ts
@@ -26,6 +26,11 @@ export class WorkspaceCreateManyInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-create-without-comment-threads.input.ts b/server/src/core/@generated/workspace/workspace-create-without-comment-threads.input.ts
index 87b098ca1..a4f5b8811 100644
--- a/server/src/core/@generated/workspace/workspace-create-without-comment-threads.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create-without-comment-threads.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceCreateWithoutCommentThreadsInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-create-without-comments.input.ts b/server/src/core/@generated/workspace/workspace-create-without-comments.input.ts
index 9edda0694..1c5bf3177 100644
--- a/server/src/core/@generated/workspace/workspace-create-without-comments.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create-without-comments.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceCreateWithoutCommentsInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-create-without-companies.input.ts b/server/src/core/@generated/workspace/workspace-create-without-companies.input.ts
index 04fda1215..82e08c92b 100644
--- a/server/src/core/@generated/workspace/workspace-create-without-companies.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create-without-companies.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceCreateWithoutCompaniesInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-create-without-people.input.ts b/server/src/core/@generated/workspace/workspace-create-without-people.input.ts
index 9930dd133..a8e6a9e7e 100644
--- a/server/src/core/@generated/workspace/workspace-create-without-people.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create-without-people.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceCreateWithoutPeopleInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-create-without-pipeline-progresses.input.ts b/server/src/core/@generated/workspace/workspace-create-without-pipeline-progresses.input.ts
index e96a710c7..acb95644e 100644
--- a/server/src/core/@generated/workspace/workspace-create-without-pipeline-progresses.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create-without-pipeline-progresses.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceCreateWithoutPipelineProgressesInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-create-without-pipeline-stages.input.ts b/server/src/core/@generated/workspace/workspace-create-without-pipeline-stages.input.ts
index 9bdb786e3..ba4be9ed7 100644
--- a/server/src/core/@generated/workspace/workspace-create-without-pipeline-stages.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create-without-pipeline-stages.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceCreateWithoutPipelineStagesInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-create-without-pipelines.input.ts b/server/src/core/@generated/workspace/workspace-create-without-pipelines.input.ts
index 61a433f2c..e3f462522 100644
--- a/server/src/core/@generated/workspace/workspace-create-without-pipelines.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create-without-pipelines.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceCreateWithoutPipelinesInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-create-without-workspace-member.input.ts b/server/src/core/@generated/workspace/workspace-create-without-workspace-member.input.ts
index 3687f938e..0a872a25b 100644
--- a/server/src/core/@generated/workspace/workspace-create-without-workspace-member.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create-without-workspace-member.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceCreateWithoutWorkspaceMemberInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-create.input.ts b/server/src/core/@generated/workspace/workspace-create.input.ts
index c700fcb0f..db54d1f4d 100644
--- a/server/src/core/@generated/workspace/workspace-create.input.ts
+++ b/server/src/core/@generated/workspace/workspace-create.input.ts
@@ -34,6 +34,11 @@ export class WorkspaceCreateInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-group-by.output.ts b/server/src/core/@generated/workspace/workspace-group-by.output.ts
index 0acfc669c..5b635fe67 100644
--- a/server/src/core/@generated/workspace/workspace-group-by.output.ts
+++ b/server/src/core/@generated/workspace/workspace-group-by.output.ts
@@ -29,6 +29,11 @@ export class WorkspaceGroupBy {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-max-aggregate.input.ts b/server/src/core/@generated/workspace/workspace-max-aggregate.input.ts
index 022e0dc7e..6e417e976 100644
--- a/server/src/core/@generated/workspace/workspace-max-aggregate.input.ts
+++ b/server/src/core/@generated/workspace/workspace-max-aggregate.input.ts
@@ -17,6 +17,9 @@ export class WorkspaceMaxAggregateInput {
@Field(() => Boolean, {nullable:true})
logo?: true;
+ @Field(() => Boolean, {nullable:true})
+ inviteHash?: true;
+
@HideField()
deletedAt?: true;
diff --git a/server/src/core/@generated/workspace/workspace-max-aggregate.output.ts b/server/src/core/@generated/workspace/workspace-max-aggregate.output.ts
index df11a248b..b553530e3 100644
--- a/server/src/core/@generated/workspace/workspace-max-aggregate.output.ts
+++ b/server/src/core/@generated/workspace/workspace-max-aggregate.output.ts
@@ -26,6 +26,11 @@ export class WorkspaceMaxAggregate {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-max-order-by-aggregate.input.ts b/server/src/core/@generated/workspace/workspace-max-order-by-aggregate.input.ts
index c61f48b08..267d586a4 100644
--- a/server/src/core/@generated/workspace/workspace-max-order-by-aggregate.input.ts
+++ b/server/src/core/@generated/workspace/workspace-max-order-by-aggregate.input.ts
@@ -18,6 +18,9 @@ export class WorkspaceMaxOrderByAggregateInput {
@Field(() => SortOrder, {nullable:true})
logo?: keyof typeof SortOrder;
+ @Field(() => SortOrder, {nullable:true})
+ inviteHash?: keyof typeof SortOrder;
+
@HideField()
deletedAt?: keyof typeof SortOrder;
diff --git a/server/src/core/@generated/workspace/workspace-min-aggregate.input.ts b/server/src/core/@generated/workspace/workspace-min-aggregate.input.ts
index ce6803ca1..62f0b0409 100644
--- a/server/src/core/@generated/workspace/workspace-min-aggregate.input.ts
+++ b/server/src/core/@generated/workspace/workspace-min-aggregate.input.ts
@@ -17,6 +17,9 @@ export class WorkspaceMinAggregateInput {
@Field(() => Boolean, {nullable:true})
logo?: true;
+ @Field(() => Boolean, {nullable:true})
+ inviteHash?: true;
+
@HideField()
deletedAt?: true;
diff --git a/server/src/core/@generated/workspace/workspace-min-aggregate.output.ts b/server/src/core/@generated/workspace/workspace-min-aggregate.output.ts
index c761b7d10..78ec25d71 100644
--- a/server/src/core/@generated/workspace/workspace-min-aggregate.output.ts
+++ b/server/src/core/@generated/workspace/workspace-min-aggregate.output.ts
@@ -26,6 +26,11 @@ export class WorkspaceMinAggregate {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-min-order-by-aggregate.input.ts b/server/src/core/@generated/workspace/workspace-min-order-by-aggregate.input.ts
index 6834c1f8d..e98cfa129 100644
--- a/server/src/core/@generated/workspace/workspace-min-order-by-aggregate.input.ts
+++ b/server/src/core/@generated/workspace/workspace-min-order-by-aggregate.input.ts
@@ -18,6 +18,9 @@ export class WorkspaceMinOrderByAggregateInput {
@Field(() => SortOrder, {nullable:true})
logo?: keyof typeof SortOrder;
+ @Field(() => SortOrder, {nullable:true})
+ inviteHash?: keyof typeof SortOrder;
+
@HideField()
deletedAt?: keyof typeof SortOrder;
diff --git a/server/src/core/@generated/workspace/workspace-order-by-with-aggregation.input.ts b/server/src/core/@generated/workspace/workspace-order-by-with-aggregation.input.ts
index ae5e311d8..3e27b600a 100644
--- a/server/src/core/@generated/workspace/workspace-order-by-with-aggregation.input.ts
+++ b/server/src/core/@generated/workspace/workspace-order-by-with-aggregation.input.ts
@@ -21,6 +21,9 @@ export class WorkspaceOrderByWithAggregationInput {
@Field(() => SortOrder, {nullable:true})
logo?: keyof typeof SortOrder;
+ @Field(() => SortOrder, {nullable:true})
+ inviteHash?: keyof typeof SortOrder;
+
@HideField()
deletedAt?: keyof typeof SortOrder;
diff --git a/server/src/core/@generated/workspace/workspace-order-by-with-relation.input.ts b/server/src/core/@generated/workspace/workspace-order-by-with-relation.input.ts
index 95964e2ac..3c6176ca6 100644
--- a/server/src/core/@generated/workspace/workspace-order-by-with-relation.input.ts
+++ b/server/src/core/@generated/workspace/workspace-order-by-with-relation.input.ts
@@ -26,6 +26,9 @@ export class WorkspaceOrderByWithRelationInput {
@Field(() => SortOrder, {nullable:true})
logo?: keyof typeof SortOrder;
+ @Field(() => SortOrder, {nullable:true})
+ inviteHash?: keyof typeof SortOrder;
+
@HideField()
deletedAt?: keyof typeof SortOrder;
diff --git a/server/src/core/@generated/workspace/workspace-scalar-field.enum.ts b/server/src/core/@generated/workspace/workspace-scalar-field.enum.ts
index 02cf89b8d..c4cde6d11 100644
--- a/server/src/core/@generated/workspace/workspace-scalar-field.enum.ts
+++ b/server/src/core/@generated/workspace/workspace-scalar-field.enum.ts
@@ -5,6 +5,7 @@ export enum WorkspaceScalarFieldEnum {
domainName = "domainName",
displayName = "displayName",
logo = "logo",
+ inviteHash = "inviteHash",
deletedAt = "deletedAt",
createdAt = "createdAt",
updatedAt = "updatedAt"
diff --git a/server/src/core/@generated/workspace/workspace-scalar-where-with-aggregates.input.ts b/server/src/core/@generated/workspace/workspace-scalar-where-with-aggregates.input.ts
index 7a8b4f7d1..b5b44e90f 100644
--- a/server/src/core/@generated/workspace/workspace-scalar-where-with-aggregates.input.ts
+++ b/server/src/core/@generated/workspace/workspace-scalar-where-with-aggregates.input.ts
@@ -30,6 +30,9 @@ export class WorkspaceScalarWhereWithAggregatesInput {
@Field(() => StringNullableWithAggregatesFilter, {nullable:true})
logo?: StringNullableWithAggregatesFilter;
+ @Field(() => StringNullableWithAggregatesFilter, {nullable:true})
+ inviteHash?: StringNullableWithAggregatesFilter;
+
@HideField()
deletedAt?: DateTimeNullableWithAggregatesFilter;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-create-without-comment-threads.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-create-without-comment-threads.input.ts
index c88813d0b..19d067d7b 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-create-without-comment-threads.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-create-without-comment-threads.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceUncheckedCreateWithoutCommentThreadsInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-create-without-comments.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-create-without-comments.input.ts
index 12b5fad61..f7d33b930 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-create-without-comments.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-create-without-comments.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceUncheckedCreateWithoutCommentsInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-create-without-companies.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-create-without-companies.input.ts
index bab9da2b7..1fd58c868 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-create-without-companies.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-create-without-companies.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceUncheckedCreateWithoutCompaniesInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-create-without-people.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-create-without-people.input.ts
index 34bf078af..8e8705569 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-create-without-people.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-create-without-people.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceUncheckedCreateWithoutPeopleInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipeline-progresses.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipeline-progresses.input.ts
index f1f4a0df7..398670e2e 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipeline-progresses.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipeline-progresses.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceUncheckedCreateWithoutPipelineProgressesInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipeline-stages.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipeline-stages.input.ts
index 7d004620b..ae0ec021d 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipeline-stages.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipeline-stages.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceUncheckedCreateWithoutPipelineStagesInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipelines.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipelines.input.ts
index afa376a4b..a58e27443 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipelines.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-create-without-pipelines.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceUncheckedCreateWithoutPipelinesInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-create-without-workspace-member.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-create-without-workspace-member.input.ts
index 89ab96a85..e5b0244e0 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-create-without-workspace-member.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-create-without-workspace-member.input.ts
@@ -33,6 +33,11 @@ export class WorkspaceUncheckedCreateWithoutWorkspaceMemberInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-create.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-create.input.ts
index 737c3b918..dc6e31b2a 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-create.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-create.input.ts
@@ -34,6 +34,11 @@ export class WorkspaceUncheckedCreateInput {
@Validator.IsOptional()
logo?: string;
+ @Field(() => String, {nullable:true})
+ @Validator.IsString()
+ @Validator.IsOptional()
+ inviteHash?: string;
+
@HideField()
deletedAt?: Date | string;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update-many.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update-many.input.ts
index 396e39d88..126c92f66 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update-many.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update-many.input.ts
@@ -21,6 +21,9 @@ export class WorkspaceUncheckedUpdateManyInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update-without-comment-threads.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update-without-comment-threads.input.ts
index eff6cb2a9..bef0926e0 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update-without-comment-threads.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update-without-comment-threads.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUncheckedUpdateWithoutCommentThreadsInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update-without-comments.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update-without-comments.input.ts
index 8859f5025..94e7575ef 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update-without-comments.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update-without-comments.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUncheckedUpdateWithoutCommentsInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update-without-companies.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update-without-companies.input.ts
index 87c8ff33b..73ba530d3 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update-without-companies.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update-without-companies.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUncheckedUpdateWithoutCompaniesInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update-without-people.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update-without-people.input.ts
index 92fff10aa..9b2bcdf87 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update-without-people.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update-without-people.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUncheckedUpdateWithoutPeopleInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipeline-progresses.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipeline-progresses.input.ts
index e8d6bcdf1..4c230a043 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipeline-progresses.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipeline-progresses.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUncheckedUpdateWithoutPipelineProgressesInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipeline-stages.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipeline-stages.input.ts
index fee46c1c3..80c1a4aa6 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipeline-stages.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipeline-stages.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUncheckedUpdateWithoutPipelineStagesInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipelines.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipelines.input.ts
index 06f45c274..23ff8f266 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipelines.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update-without-pipelines.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUncheckedUpdateWithoutPipelinesInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update-without-workspace-member.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update-without-workspace-member.input.ts
index 55096ed40..3007224c8 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update-without-workspace-member.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update-without-workspace-member.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUncheckedUpdateWithoutWorkspaceMemberInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-unchecked-update.input.ts b/server/src/core/@generated/workspace/workspace-unchecked-update.input.ts
index c7d8a0dd8..e063135bb 100644
--- a/server/src/core/@generated/workspace/workspace-unchecked-update.input.ts
+++ b/server/src/core/@generated/workspace/workspace-unchecked-update.input.ts
@@ -29,6 +29,9 @@ export class WorkspaceUncheckedUpdateInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update-many-mutation.input.ts b/server/src/core/@generated/workspace/workspace-update-many-mutation.input.ts
index bd659d9f2..da2cc5e99 100644
--- a/server/src/core/@generated/workspace/workspace-update-many-mutation.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update-many-mutation.input.ts
@@ -21,6 +21,9 @@ export class WorkspaceUpdateManyMutationInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update-without-comment-threads.input.ts b/server/src/core/@generated/workspace/workspace-update-without-comment-threads.input.ts
index 6e903e8fc..46d3b7a91 100644
--- a/server/src/core/@generated/workspace/workspace-update-without-comment-threads.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update-without-comment-threads.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUpdateWithoutCommentThreadsInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update-without-comments.input.ts b/server/src/core/@generated/workspace/workspace-update-without-comments.input.ts
index e36bafc48..f7e052cb3 100644
--- a/server/src/core/@generated/workspace/workspace-update-without-comments.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update-without-comments.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUpdateWithoutCommentsInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update-without-companies.input.ts b/server/src/core/@generated/workspace/workspace-update-without-companies.input.ts
index ee0e8e299..594005d65 100644
--- a/server/src/core/@generated/workspace/workspace-update-without-companies.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update-without-companies.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUpdateWithoutCompaniesInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update-without-people.input.ts b/server/src/core/@generated/workspace/workspace-update-without-people.input.ts
index 457b83ae3..728003e06 100644
--- a/server/src/core/@generated/workspace/workspace-update-without-people.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update-without-people.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUpdateWithoutPeopleInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update-without-pipeline-progresses.input.ts b/server/src/core/@generated/workspace/workspace-update-without-pipeline-progresses.input.ts
index 8ccddaeb1..ad4fc98d0 100644
--- a/server/src/core/@generated/workspace/workspace-update-without-pipeline-progresses.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update-without-pipeline-progresses.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUpdateWithoutPipelineProgressesInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update-without-pipeline-stages.input.ts b/server/src/core/@generated/workspace/workspace-update-without-pipeline-stages.input.ts
index 12dba5851..4a5d7c718 100644
--- a/server/src/core/@generated/workspace/workspace-update-without-pipeline-stages.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update-without-pipeline-stages.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUpdateWithoutPipelineStagesInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update-without-pipelines.input.ts b/server/src/core/@generated/workspace/workspace-update-without-pipelines.input.ts
index d61862282..f0153992f 100644
--- a/server/src/core/@generated/workspace/workspace-update-without-pipelines.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update-without-pipelines.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUpdateWithoutPipelinesInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update-without-workspace-member.input.ts b/server/src/core/@generated/workspace/workspace-update-without-workspace-member.input.ts
index 446fdcd6c..29088634f 100644
--- a/server/src/core/@generated/workspace/workspace-update-without-workspace-member.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update-without-workspace-member.input.ts
@@ -28,6 +28,9 @@ export class WorkspaceUpdateWithoutWorkspaceMemberInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-update.input.ts b/server/src/core/@generated/workspace/workspace-update.input.ts
index 7276fb9ff..ea5fbdb0c 100644
--- a/server/src/core/@generated/workspace/workspace-update.input.ts
+++ b/server/src/core/@generated/workspace/workspace-update.input.ts
@@ -29,6 +29,9 @@ export class WorkspaceUpdateInput {
@Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
logo?: NullableStringFieldUpdateOperationsInput;
+ @Field(() => NullableStringFieldUpdateOperationsInput, {nullable:true})
+ inviteHash?: NullableStringFieldUpdateOperationsInput;
+
@HideField()
deletedAt?: NullableDateTimeFieldUpdateOperationsInput;
diff --git a/server/src/core/@generated/workspace/workspace-where.input.ts b/server/src/core/@generated/workspace/workspace-where.input.ts
index af2357372..fb8022421 100644
--- a/server/src/core/@generated/workspace/workspace-where.input.ts
+++ b/server/src/core/@generated/workspace/workspace-where.input.ts
@@ -38,6 +38,9 @@ export class WorkspaceWhereInput {
@Field(() => StringNullableFilter, {nullable:true})
logo?: StringNullableFilter;
+ @Field(() => StringNullableFilter, {nullable:true})
+ inviteHash?: StringNullableFilter;
+
@HideField()
deletedAt?: DateTimeNullableFilter;
diff --git a/server/src/core/@generated/workspace/workspace.model.ts b/server/src/core/@generated/workspace/workspace.model.ts
index 9cf4eb6be..09f99b92e 100644
--- a/server/src/core/@generated/workspace/workspace.model.ts
+++ b/server/src/core/@generated/workspace/workspace.model.ts
@@ -27,6 +27,9 @@ export class Workspace {
@Field(() => String, {nullable:true})
logo!: string | null;
+ @Field(() => String, {nullable:true})
+ inviteHash!: string | null;
+
@HideField()
deletedAt!: Date | null;
diff --git a/server/src/core/auth/auth.module.ts b/server/src/core/auth/auth.module.ts
index 0ab8cbd82..3d6f754df 100644
--- a/server/src/core/auth/auth.module.ts
+++ b/server/src/core/auth/auth.module.ts
@@ -9,6 +9,7 @@ import { VerifyAuthController } from './controllers/verify-auth.controller';
import { TokenService } from './services/token.service';
import { AuthResolver } from './auth.resolver';
import { EnvironmentService } from 'src/integrations/environment/environment.service';
+import { WorkspaceModule } from '../workspace/workspace.module';
const jwtModule = JwtModule.registerAsync({
useFactory: async (environmentService: EnvironmentService) => {
@@ -23,7 +24,7 @@ const jwtModule = JwtModule.registerAsync({
});
@Module({
- imports: [jwtModule, UserModule],
+ imports: [jwtModule, UserModule, WorkspaceModule],
controllers: [GoogleAuthController, VerifyAuthController],
providers: [
AuthService,
diff --git a/server/src/core/auth/auth.resolver.ts b/server/src/core/auth/auth.resolver.ts
index a2b02961b..a234f8cb0 100644
--- a/server/src/core/auth/auth.resolver.ts
+++ b/server/src/core/auth/auth.resolver.ts
@@ -15,6 +15,9 @@ import {
import { Prisma } from '@prisma/client';
import { UserExists } from './dto/user-exists.entity';
import { CheckUserExistsInput } from './dto/user-exists.input';
+import { WorkspaceInviteHashValid } from './dto/workspace-invite-hash-valid.entity';
+import { WorkspaceInviteHashValidInput } from './dto/workspace-invite-hash.input';
+import { SignUpInput } from './dto/sign-up.input';
@Resolver()
export class AuthResolver {
@@ -33,6 +36,15 @@ export class AuthResolver {
return { exists };
}
+ @Query(() => WorkspaceInviteHashValid)
+ async checkWorkspaceInviteHashIsValid(
+ @Args() workspaceInviteHashValidInput: WorkspaceInviteHashValidInput,
+ ): Promise {
+ return await this.authService.checkWorkspaceInviteHashIsValid(
+ workspaceInviteHashValidInput.inviteHash,
+ );
+ }
+
@Mutation(() => LoginToken)
async challenge(@Args() challengeInput: ChallengeInput): Promise {
const user = await this.authService.challenge(challengeInput);
@@ -41,6 +53,14 @@ export class AuthResolver {
return { loginToken };
}
+ @Mutation(() => LoginToken)
+ async signUp(@Args() signUpInput: SignUpInput): Promise {
+ const user = await this.authService.signUp(signUpInput);
+ const loginToken = await this.tokenService.generateLoginToken(user.email);
+
+ return { loginToken };
+ }
+
@Mutation(() => Verify)
async verify(
@Args() verifyInput: VerifyInput,
diff --git a/server/src/core/auth/dto/sign-up.input.ts b/server/src/core/auth/dto/sign-up.input.ts
new file mode 100644
index 000000000..49931338d
--- /dev/null
+++ b/server/src/core/auth/dto/sign-up.input.ts
@@ -0,0 +1,20 @@
+import { ArgsType, Field } from '@nestjs/graphql';
+import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
+
+@ArgsType()
+export class SignUpInput {
+ @Field(() => String)
+ @IsNotEmpty()
+ @IsEmail()
+ email: string;
+
+ @Field(() => String)
+ @IsNotEmpty()
+ @IsString()
+ password: string;
+
+ @Field(() => String, { nullable: true })
+ @IsString()
+ @IsOptional()
+ workspaceInviteHash?: string;
+}
diff --git a/server/src/core/auth/dto/workspace-invite-hash-valid.entity.ts b/server/src/core/auth/dto/workspace-invite-hash-valid.entity.ts
new file mode 100644
index 000000000..4b83292f9
--- /dev/null
+++ b/server/src/core/auth/dto/workspace-invite-hash-valid.entity.ts
@@ -0,0 +1,7 @@
+import { Field, ObjectType } from '@nestjs/graphql';
+
+@ObjectType()
+export class WorkspaceInviteHashValid {
+ @Field(() => Boolean)
+ isValid: boolean;
+}
diff --git a/server/src/core/auth/dto/workspace-invite-hash.input.ts b/server/src/core/auth/dto/workspace-invite-hash.input.ts
new file mode 100644
index 000000000..848fdb531
--- /dev/null
+++ b/server/src/core/auth/dto/workspace-invite-hash.input.ts
@@ -0,0 +1,11 @@
+import { ArgsType, Field } from '@nestjs/graphql';
+import { IsNotEmpty, IsString, MinLength } from 'class-validator';
+
+@ArgsType()
+export class WorkspaceInviteHashValidInput {
+ @Field(() => String)
+ @IsString()
+ @IsNotEmpty()
+ @MinLength(10)
+ inviteHash: string;
+}
diff --git a/server/src/core/auth/services/auth.service.spec.ts b/server/src/core/auth/services/auth.service.spec.ts
index 33d44aae5..8b4739906 100644
--- a/server/src/core/auth/services/auth.service.spec.ts
+++ b/server/src/core/auth/services/auth.service.spec.ts
@@ -2,6 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';
import { TokenService } from './token.service';
import { UserService } from 'src/core/user/user.service';
+import { WorkspaceService } from 'src/core/workspace/services/workspace.service';
describe('AuthService', () => {
let service: AuthService;
@@ -18,6 +19,10 @@ describe('AuthService', () => {
provide: UserService,
useValue: {},
},
+ {
+ provide: WorkspaceService,
+ useValue: {},
+ },
],
}).compile();
diff --git a/server/src/core/auth/services/auth.service.ts b/server/src/core/auth/services/auth.service.ts
index f4a6b614c..a4c9b8420 100644
--- a/server/src/core/auth/services/auth.service.ts
+++ b/server/src/core/auth/services/auth.service.ts
@@ -12,6 +12,9 @@ import { Verify } from '../dto/verify.entity';
import { TokenService } from './token.service';
import { Prisma } from '@prisma/client';
import { UserExists } from '../dto/user-exists.entity';
+import { WorkspaceService } from 'src/core/workspace/services/workspace.service';
+import { WorkspaceInviteHashValid } from '../dto/workspace-invite-hash-valid.entity';
+import { SignUpInput } from '../dto/sign-up.input';
export type UserPayload = {
firstName: string;
@@ -24,31 +27,16 @@ export class AuthService {
constructor(
private readonly tokenService: TokenService,
private readonly userService: UserService,
+ private readonly workspaceService: WorkspaceService,
) {}
async challenge(challengeInput: ChallengeInput) {
- let user = await this.userService.findUnique({
+ const user = await this.userService.findUnique({
where: {
email: challengeInput.email,
},
});
- const isPasswordValid = PASSWORD_REGEX.test(challengeInput.password);
-
- assert(!!user || isPasswordValid, 'Password too weak', BadRequestException);
-
- if (!user) {
- const passwordHash = await hashPassword(challengeInput.password);
-
- user = await this.userService.createUser({
- data: {
- email: challengeInput.email,
- passwordHash,
- locale: 'en',
- },
- } as Prisma.UserCreateArgs);
- }
-
assert(user, "This user doesn't exist", NotFoundException);
assert(user.passwordHash, 'Incorrect login method', ForbiddenException);
@@ -62,6 +50,53 @@ export class AuthService {
return user;
}
+ async signUp(signUpInput: SignUpInput) {
+ const existingUser = await this.userService.findUnique({
+ where: {
+ email: signUpInput.email,
+ },
+ });
+ assert(!existingUser, 'This user already exists', ForbiddenException);
+
+ const isPasswordValid = PASSWORD_REGEX.test(signUpInput.password);
+ assert(isPasswordValid, 'Password too weak', BadRequestException);
+
+ const passwordHash = await hashPassword(signUpInput.password);
+
+ if (signUpInput.workspaceInviteHash) {
+ const workspace = await this.workspaceService.findFirst({
+ where: {
+ inviteHash: signUpInput.workspaceInviteHash,
+ },
+ });
+
+ assert(
+ workspace,
+ 'This workspace inviteHash is invalid',
+ ForbiddenException,
+ );
+
+ return await this.userService.createUser(
+ {
+ data: {
+ email: signUpInput.email,
+ passwordHash,
+ locale: 'en',
+ },
+ } as Prisma.UserCreateArgs,
+ workspace.id,
+ );
+ }
+
+ return await this.userService.createUser({
+ data: {
+ email: signUpInput.email,
+ passwordHash,
+ locale: 'en',
+ },
+ } as Prisma.UserCreateArgs);
+ }
+
async verify(
email: string,
select: Prisma.UserSelect & {
@@ -101,4 +136,16 @@ export class AuthService {
return { exists: !!user };
}
+
+ async checkWorkspaceInviteHashIsValid(
+ inviteHash: string,
+ ): Promise {
+ const workspace = await this.workspaceService.findFirst({
+ where: {
+ inviteHash,
+ },
+ });
+
+ return { isValid: !!workspace };
+ }
}
diff --git a/server/src/core/user/user.service.ts b/server/src/core/user/user.service.ts
index ddc609515..7bb12d766 100644
--- a/server/src/core/user/user.service.ts
+++ b/server/src/core/user/user.service.ts
@@ -46,6 +46,7 @@ export class UserService {
// Customs
async createUser(
args: Prisma.SelectSubset,
+ workspaceId?: string,
): Promise> {
assert(args.data.email, 'email is missing', BadRequestException);
@@ -55,14 +56,23 @@ export class UserService {
},
create: {
...(args.data as Prisma.UserCreateInput),
- // Assign the user to a new workspace by default
- workspaceMember: {
- create: {
- workspace: {
- create: {},
+
+ workspaceMember: workspaceId
+ ? {
+ create: {
+ workspace: {
+ connect: { id: workspaceId },
+ },
+ },
+ }
+ : // Assign the user to a new workspace by default
+ {
+ create: {
+ workspace: {
+ create: {},
+ },
+ },
},
- },
- },
locale: 'en',
},
update: {},
diff --git a/server/src/database/migrations/20230711002359_workspace_invite_hash/migration.sql b/server/src/database/migrations/20230711002359_workspace_invite_hash/migration.sql
new file mode 100644
index 000000000..d603f3293
--- /dev/null
+++ b/server/src/database/migrations/20230711002359_workspace_invite_hash/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "workspaces" ADD COLUMN "inviteHash" TEXT;
diff --git a/server/src/database/schema.prisma b/server/src/database/schema.prisma
index 85d606edd..1bc37d553 100644
--- a/server/src/database/schema.prisma
+++ b/server/src/database/schema.prisma
@@ -196,6 +196,9 @@ model Workspace {
/// @Validator.IsString()
/// @Validator.IsOptional()
logo String?
+ /// @Validator.IsString()
+ /// @Validator.IsOptional()
+ inviteHash String?
workspaceMember WorkspaceMember[]
companies Company[]
diff --git a/server/src/database/seeds/workspaces.ts b/server/src/database/seeds/workspaces.ts
index 7f3caf637..58d26b89a 100644
--- a/server/src/database/seeds/workspaces.ts
+++ b/server/src/database/seeds/workspaces.ts
@@ -7,6 +7,7 @@ export const seedWorkspaces = async (prisma: PrismaClient) => {
id: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419',
displayName: 'Apple',
domainName: 'apple.dev',
+ inviteHash: 'apple.dev-invite-hash',
logo: 'data:image/png;base64,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',
},
});
@@ -18,6 +19,7 @@ export const seedWorkspaces = async (prisma: PrismaClient) => {
id: 'twenty-dev-7ed9d212-1c25-4d02-bf25-6aeccf7ea420',
displayName: 'Twenty',
domainName: 'twenty.com',
+ inviteHash: 'twenty.com-invite-hash',
logo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACb0lEQVR4nO2VO4taQRTHr3AblbjxEVlwCwVhg7BoqqCIjy/gAyyFWNlYBOxsfH0KuxgQGwXRUkGuL2S7i1barGAgiwbdW93SnGOc4BonPiKahf3DwXFmuP/fPM4ZlvmlTxAhCBdzHnEQWYiv7Mr4C3NeuVYhQYDPzOUUQgDLBQGcLHNhvQK8DACPx8PTxiqVyvISG43GbyaT6Qfpn06n0m63e/tPAPF4vJ1MJu8kEsnWTCkWi1yr1RKGw+GDRqPBOTfr44vFQvD7/Q/lcpmaaVQAr9fLp1IpO22c47hGOBz+MB6PH+Vy+VYDAL8qlUoGtVotzOfzq4MAgsHgE/6KojiQyWR/bKVSqbSszHFM8Pl8z1YK48JsNltCOBwOnrYLO+8AAIjb+nHbycoTiUQfDJ7tFq4YAHiVSmXBxcD41u8flQU8z7fhzO0r83atVns3Go3u9Xr9x0O/RQXo9/tsIBBg6vX606a52Wz+bZ7P5/WwG29gxSJzhKgA6XTaDoFNF+krFAocmC//4yWEcSf2wTm7mCO19xFgSsKOLI16vV7b7XY7mRNoLwA0JymJ5uQIzgIAuX5PzDElT2m+E8BqtQ4ymcx7Yq7T6a6ZE4sKgOadTucaCwkxp1UzlEKh0GDxIXOwDWHAdi6Xe3swQDQa/Q7mywoolUpvsaptymazDWKxmBHTlWXZm405BFZoNpuGgwEmk4mE2SGtVivii4f1AO7J3ZopkQCQj7Ar1FeRChCJRJzVapX6DKNIfSc1Ax+wtQWQ55h6bH8FWDfYV4fO3wlwDr0C/BcADYiTPCxHqIEA2QsCZAkAKnRGkMbKN/sTX5YHPQ1e7SkAAAAASUVORK5CYII=',
},
});