Compare commits

...
Author SHA1 Message Date
Marie Stoppa e4462ff33e Bump version 2025-03-19 14:46:42 +01:00
9faa711aba [permissions] Fix user is assigned default role after SSO sign-in (#11023)
When logging using a SSO method, we call signInUp service in which we
were wrongfully assigning a role to the user even if the user is signing
in and not signin up.

This went unnoticed during our QA as a different sign-in method is
called when logging with the credentials.

---------

Co-authored-by: Weiko <corentin@twenty.com>
2025-03-19 14:43:40 +01:00
Charles Bochet aa1c9107f6 Bump version 2025-03-19 01:49:28 +01:00
Charles Bochet c59e0d766e Bump version 2025-03-19 01:21:02 +01:00
Charles Bochet c9ffffeda8 Bump version 2025-03-19 00:45:44 +01:00
15 changed files with 81 additions and 25 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-e2e-testing",
"version": "0.44.0-canary",
"version": "0.44.8",
"description": "",
"author": "",
"private": true,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-emails",
"version": "0.44.0-canary",
"version": "0.44.8",
"description": "",
"author": "",
"private": true,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-front",
"version": "0.44.0-canary",
"version": "0.44.8",
"private": true,
"type": "module",
"scripts": {
@@ -151,7 +151,10 @@ export const ActivityRichTextEditor = ({
return {
...oldActivity,
id: activityId,
body: newStringifiedBody,
bodyV2: {
blocknote: newStringifiedBody,
markdown: null,
},
__typename: 'Activity',
};
});
@@ -159,8 +162,11 @@ export const ActivityRichTextEditor = ({
modifyRecordFromCache({
recordId: activityId,
fieldModifiers: {
body: () => {
return newStringifiedBody;
bodyV2: () => {
return {
blocknote: newStringifiedBody,
markdown: null,
};
},
},
cache,
@@ -10,7 +10,6 @@ const task: Task = {
id: '123',
status: 'DONE',
title: 'Test',
body: 'Test',
bodyV2: {
blocknote: 'Test',
markdown: 'Test',
@@ -3,7 +3,6 @@ export type Activity = {
createdAt: string;
updatedAt: string;
title: string;
body: string | null;
bodyV2?: {
blocknote: string | null;
markdown: string | null;
@@ -1,12 +1,14 @@
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { lazy, Suspense } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared';
const ActivityRichTextEditor = lazy(() =>
import('@/activities/components/ActivityRichTextEditor').then((module) => ({
@@ -56,6 +58,14 @@ export const ShowPageActivityContainer = ({
| CoreObjectNameSingular.Note
| CoreObjectNameSingular.Task;
const recordFromStore = useRecoilValue(
recordStoreFamilyState(targetableObject.id),
);
if (!isDefined(recordFromStore)) {
return <></>;
}
return !isNewViewableRecordLoading ? (
<ScrollWrapper
contextProviderName="showPageActivityContainer"
@@ -9,7 +9,6 @@ export const mockedNotes: Array<MockedNote> = [
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
title: 'My very first note',
body: null,
bodyV2: {
blocknote: null,
markdown: null,
@@ -68,7 +67,6 @@ export const mockedNotes: Array<MockedNote> = [
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
title: 'Another note',
body: null,
bodyV2: {
blocknote: null,
markdown: null,
@@ -26,7 +26,6 @@ export const mockedTasks: Array<MockedTask> = [
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
title: 'My very first note',
body: null,
bodyV2: {
blocknote: null,
markdown: null,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-server",
"version": "0.44.0-canary",
"version": "0.44.8",
"description": "",
"author": "",
"private": true,
@@ -366,7 +366,7 @@ describe('SignInUpService', () => {
expect(WorkspaceRepository.save).toHaveBeenCalled();
});
it('should assign default role when permissions are enabled', async () => {
it('should not assign default role when permissions are enabled and user exists', async () => {
const params: SignInUpBaseParams &
ExistingUserOrPartialUserWithPicture &
AuthProviderWithPasswordType = {
@@ -392,6 +392,49 @@ describe('SignInUpService', () => {
await service.signInUp(params);
expect(params.workspace).toBeDefined();
expect(userRoleService.assignRoleToUserWorkspace).not.toHaveBeenCalled();
});
it('should assign default role when permissions are enabled and user does not exist', async () => {
const params: SignInUpBaseParams &
ExistingUserOrPartialUserWithPicture &
AuthProviderWithPasswordType = {
workspace: {
id: 'workspaceId',
defaultRoleId: 'defaultRoleId',
activationStatus: WorkspaceActivationStatus.ACTIVE,
} as Workspace,
authParams: { provider: 'password', password: 'validPassword' },
userData: {
type: 'newUserWithPicture',
newUserWithPicture: {
email: 'newuser@example.com',
picture: 'pictureUrl',
},
},
};
const mockUserWorkspace = { id: 'userWorkspaceId' };
jest.spyOn(featureFlagService, 'isFeatureEnabled').mockResolvedValue(true);
jest.spyOn(fileUploadService, 'uploadImage').mockResolvedValue({
id: '',
mimeType: '',
paths: ['path/to/image'],
});
jest.spyOn(UserRepository, 'create').mockReturnValue({} as User);
jest
.spyOn(UserRepository, 'save')
.mockResolvedValue({ id: 'newUserId' } as User);
jest.spyOn(userWorkspaceService, 'addUserToWorkspace').mockResolvedValue({
user: {} as User,
userWorkspace: mockUserWorkspace as UserWorkspace,
});
await service.signInUp(params);
expect(params.workspace).toBeDefined();
expect(userRoleService.assignRoleToUserWorkspace).toHaveBeenCalledWith({
workspaceId: params.workspace!.id,
@@ -243,16 +243,18 @@ export class SignInUpService {
const user = Object.assign(currentUser, updatedUser);
if (params.userData.type === 'newUserWithPicture') {
await this.activateOnboardingForUser(user, params.workspace);
}
const isSignUp = params.userData.type === 'newUserWithPicture';
if (params.workspace.defaultRoleId) {
await this.userRoleService.assignRoleToUserWorkspace({
workspaceId: params.workspace.id,
userWorkspaceId: userWorkspace.id,
roleId: params.workspace.defaultRoleId,
});
if (isSignUp) {
await this.activateOnboardingForUser(user, params.workspace);
if (params.workspace.defaultRoleId) {
await this.userRoleService.assignRoleToUserWorkspace({
workspaceId: params.workspace.id,
userWorkspaceId: userWorkspace.id,
roleId: params.workspace.defaultRoleId,
});
}
}
return user;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-shared",
"version": "0.44.0-canary",
"version": "0.44.8",
"license": "AGPL-3.0",
"main": "./dist/index.js",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-ui",
"version": "0.44.0-canary",
"version": "0.44.8",
"type": "module",
"main": "./src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-website",
"version": "0.44.0-canary",
"version": "0.44.8",
"private": true,
"scripts": {
"nx": "NX_DEFAULT_PROJECT=twenty-website node ../../node_modules/nx/bin/nx.js",