Relabelling organization with workspace (#2992)

* Relabelling organization with workspace

* placeholder fix

* Bug fixes

* fix

* firefox issue fix
This commit is contained in:
Midhun G S 2022-05-11 16:30:25 +05:30 committed by GitHub
parent 863f91c77b
commit e656ea9259
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1934 additions and 1068 deletions

View file

@ -34,11 +34,11 @@ SMTP_PASSWORD=
SMTP_DOMAIN=
SMTP_PORT=
# DISABLE USER SIGNUPS (true or false). only applicable if MULTI_ORGANIZATION=true
# DISABLE USER SIGNUPS (true or false). only applicable if Multi-Workspace feature is enabled
DISABLE_SIGNUPS=
# Enables all multi organization features
MULTI_ORGANIZATION=
# Disable Multi-Workspace features (true or false)
DISABLE_MULTI_WORKSPACE=
# OBSERVABILITY
APM_VENDOR=

View file

@ -34,11 +34,11 @@
"value": "--max-old-space-size=4096"
},
"DISABLE_SIGNUPS": {
"description": "Disable sign up in login page only applicable if MULTI_ORGANIZATION=true",
"description": "Disable sign up in login page only applicable if Multi-Workspace feature is turned on",
"value": "false"
},
"MULTI_ORGANIZATION": {
"description": "Enables multi organization feature",
"DISABLE_MULTI_WORKSPACE": {
"description": "Disables Multi-Workspace feature",
"value": "false"
}
},

View file

@ -5,9 +5,9 @@ sidebar_label: Password Login
# Password Login
Password login is enabled by default for all organizations. User with admin privilege can enable/disable it.
Password login is enabled by default for all workspaces. User with admin privilege can enable/disable it.
Select `Manage SSO` from organization options
Select `Manage SSO` from workspace options
<div style={{textAlign: 'center'}}>

View file

@ -73,14 +73,14 @@ You can specify a different server for backend if it is hosted on another server
| -------- | ---------------------- |
| SERVER_HOST | Configure a hostname for the server as a proxy pass. If no value is set, it defaults to `server`. |
#### Enable multiple organizations ( optional )
#### Disable Multi-Workspace ( optional )
If you want to enable multiple environments, set the environment variable `MULTI_ORGANIZATION` to `true`.
If you want to disable Multi-Workspace feature, set the environment variable `DISABLE_MULTI_WORKSPACE` to `true`.
#### Disabling signups ( optional )
Sign up is enabled only for multiple organization environment. If you want to restrict the signups and allow new users only by invitations, set the environment variable `DISABLE_SIGNUPS` to `true`.
Sign up is enabled only if Multi-Workspace is enabled. If you want to restrict the signups and allow new users only by invitations, set the environment variable `DISABLE_SIGNUPS` to `true`.
:::tip
You will still be able to see the signup page but won't be able to successfully submit the form.
@ -93,7 +93,7 @@ You can set `SERVE_CLIENT` to `true` and the server will attempt to serve the cl
#### SMTP configuration ( optional )
ToolJet uses SMTP services to send emails ( Eg: invitation email when you add new users to your organization ).
ToolJet uses SMTP services to send emails ( Eg: invitation email when you add new users to your workspace ).
| variable | description |
| ------------------ | ----------------------------------------- |

View file

@ -5,7 +5,7 @@ sidebar_label: General Settings
# Single Sign-On General Settings
Select `Manage SSO` from organization options
Select `Manage SSO` from workspace options
<div style={{textAlign: 'center'}}>

View file

@ -5,7 +5,7 @@ title: GitHub
# GitHub Single Sign-on
Select `Manage SSO` from organization options
Select `Manage SSO` from workspace options
<div style={{textAlign: 'center'}}>
@ -55,4 +55,4 @@ Go to [GitHub Developer settings](https://github.com/settings/developers) and na
Lastly, enter `Client Id` and `Client Secret` in Git manage SSO page and save.
The GitHub sign-in button will now be available in your ToolJet login screen if you have not enabled multiple organization.
The GitHub sign-in button will now be available in your ToolJet login screen if you have not enabled Multi-Workspace.

View file

@ -5,7 +5,7 @@ title: Google
# Google Single Sign-on
Select `Manage SSO` from organization options
Select `Manage SSO` from workspace options
<div style={{textAlign: 'center'}}>
@ -45,7 +45,7 @@ Go to [Google cloud console](https://console.cloud.google.com/) and create a pro
</div>
- You'll be asked to select user type in consent screen. To allow only users within your organization, select 'Internal', otherwise,
- You'll be asked to select user type in consent screen. To allow only users within your workspace, select 'Internal', otherwise,
select 'External'.
<div style={{textAlign: 'center'}}>
@ -82,4 +82,4 @@ Set the `Redirect URL` generated at manage SSO `Google` page under Authorised re
Lastly, set the `client id` in google manage SSO page. This value will be available from your [Google cloud console credentials page](https://console.cloud.google.com/apis/credentials)
The Google sign-in button will now be available in your ToolJet login screen, if you are not enabled multiple organization.
The Google sign-in button will now be available in your ToolJet login screen, if you are not enabled Multi-Workspace.

View file

@ -6,7 +6,7 @@ title: Adding a data source
# Adding a data source
:::tip
The data sources are created on app level and not on organization level.
The data sources are created on app level and not on workspace level.
:::
**Datasource manager** is on the left-sidebar of the app builder. To add a new data source, click on the `Add datasource` button.

View file

@ -7,7 +7,7 @@ title: Managing Users and Groups
## Managing Users
Admin of an organization can add users to the organization. To manage the users in your organization, just go to the **Account menu** on top right corner and click on the **Manage Users**.
Admin of a workspace can add users to the workspace. To manage the users in your workspace, just go to the **Workspace menu** on top right corner and click on the **Manage Users**.
<div style={{textAlign: 'center'}}>
@ -17,7 +17,7 @@ Admin of an organization can add users to the organization. To manage the users
### Inviting users
Admins can invite anyone to a ToolJet organization using the email address. To invite a user:
Admins can invite anyone to a workspace using the email address. To invite a user:
- On the **Manage Users** page click on the `Invite new user` button.
@ -35,7 +35,7 @@ Admins can invite anyone to a ToolJet organization using the email address. To i
</div>
- An email including the **Invite Link** to join your organization will be send to the created user. The status will turn from **invited** to **active** after the user successfully joins your organization using the invite link.
- An email including the **Invite Link** to join your workspace will be send to the created user. The status will turn from **invited** to **active** after the user successfully joins your workspace using the invite link.
:::tip
@ -51,7 +51,7 @@ You can also copy the invitation url by clicking on the copy icon next to `invit
### Disabling a user's access
You can disable any active user's access to your organization by clicking on the **Archive** and then the status of the user will change from **active** to **archived**.
You can disable any active user's access to your workspace by clicking on the **Archive** and then the status of the user will change from **active** to **archived**.
<div style={{textAlign: 'center'}}>
@ -71,7 +71,7 @@ Similar to archiving a user's access, you can enable it again by clicking on **U
## Managing Groups
On ToolJet, Admins can create groups for users added in an organization and grant them access to particular app(s) with specific permissions. To manage groups, just go to the **Account menu** on top right corner and click on the **Manage Groups**.
On ToolJet, Admins can create groups for users added in a workspace and grant them access to particular app(s) with specific permissions. To manage groups, just go to the **Account menu** on top right corner and click on the **Manage Groups**.
<div style={{textAlign: 'center'}}>
@ -115,13 +115,13 @@ Admins can set granular permission like creating/deleting apps or creating folde
:::tip
All the activities performed by any Admin or any user in a ToolJet organization is logged in `Audit logs` - including any activity related with managing users and groups.
All the activities performed by any Admin or any user in a workspace is logged in `Audit logs` - including any activity related with managing users and groups.
:::
### Predefined Groups
By default, every organization will have two User Groups:
By default, every workspace will have two User Groups:
**1. All Users**
@ -129,7 +129,7 @@ This group contains all the users and admins.
| Apps | Users | Permissions |
| ----------- | ----------- | ----------- |
| You can add or remove apps. | Modification is disabled. This group will have all the users and admins added in an organization. | You can edit permissions for all the users globally. |
| You can add or remove apps. | Modification is disabled. This group will have all the users and admins added in a workspace. | You can edit permissions for all the users globally. |
<div style={{textAlign: 'center'}}>
@ -143,7 +143,7 @@ This group contains admins by default. Admins can add more admins or remove the
| Apps | Users | Permissions |
| ----------- | ----------- | ----------- |
| Modification is disabled. By default, this group has `Edit` permission for all the apps in an organization | Admins can add or remove users in this group. | Modification is disabled. By default, all the admins can create and delete apps or create folders. |
| Modification is disabled. By default, this group has `Edit` permission for all the apps in a workspace | Admins can add or remove users in this group. | Modification is disabled. By default, all the admins can create and delete apps or create folders. |
<div style={{textAlign: 'center'}}>

View file

@ -126,7 +126,7 @@ class ConfirmationPage extends React.Component {
</div>
</div>
<div className="mb-3">
<label className="form-label">Organization</label>
<label className="form-label">Workspace</label>
<div className="input-group input-group-flat">
<input
onChange={this.handleChange}

View file

@ -10,7 +10,7 @@ class OrganizationInvitationPage extends React.Component {
isLoading: false,
};
this.formRef = React.createRef(null);
this.single_organization = window.public_config?.MULTI_ORGANIZATION !== 'true';
this.single_organization = window.public_config?.DISABLE_MULTI_WORKSPACE === 'true';
}
handleChange = (event) => {
@ -49,7 +49,7 @@ class OrganizationInvitationPage extends React.Component {
})
.then(() => {
this.setState({ isLoading: false });
toast.success(`Added to the organization${isSetPassword ? ' and password has been set ' : ' '}successfully.`, {
toast.success(`Added to the workspace${isSetPassword ? ' and password has been set ' : ' '}successfully.`, {
position: 'top-center',
});
this.props.history.push('/login');

View file

@ -306,7 +306,7 @@ class ManageAppUsers extends React.Component {
<Modal.Footer>
<a href="/users" target="_blank" className="btn color-primary mt-3">
Manage Organization Users
Manage Users
</a>
</Modal.Footer>
</Modal>

View file

@ -16,7 +16,7 @@ class LoginPage extends React.Component {
isGettingConfigs: true,
configs: undefined,
};
this.single_organization = window.public_config?.MULTI_ORGANIZATION !== 'true';
this.single_organization = window.public_config?.DISABLE_MULTI_WORKSPACE === 'true';
}
componentDidMount() {
@ -132,7 +132,7 @@ class LoginPage extends React.Component {
this.showLoading()
) : (
<div className="card-body">
{!configs && <div className="text-center">No login methods enabled for this organization</div>}
{!configs && <div className="text-center">No login methods enabled for this workspace</div>}
{configs?.form?.enabled && (
<div>
<h2 className="card-title text-center mb-4" data-cy="login-page-header">

View file

@ -77,7 +77,7 @@ export function Google({ settings, updateData }) {
<input
type="text"
className="form-control"
placeholder="Enter Client Secret"
placeholder="Enter Client Id"
value={clientId}
onChange={(e) => setClientId(e.target.value)}
/>

View file

@ -6,7 +6,7 @@ import { toast } from 'react-hot-toast';
import { SearchBox } from './SearchBox';
export const Organization = function Organization() {
const isSingleOrganization = window.public_config?.MULTI_ORGANIZATION !== 'true';
const isSingleOrganization = window.public_config?.DISABLE_MULTI_WORKSPACE === 'true';
const { admin, organization_id } = authenticationService.currentUserValue;
const [organization, setOrganization] = useState(authenticationService.currentUserValue?.organization);
const [showCreateOrg, setShowCreateOrg] = useState(false);
@ -21,11 +21,13 @@ export const Organization = function Organization() {
const getAvatar = (organization) => {
if (!organization) return;
const orgName = organization.split(' ');
const orgName = organization.split(' ').filter((e) => e && !!e.trim());
if (orgName.length > 1) {
return `${orgName[0]?.[0]}${orgName[1]?.[0]}`;
} else {
} else if (organization.length >= 2) {
return `${organization[0]}${organization[1]}`;
} else {
return `${organization[0]}${organization[0]}`;
}
};
@ -58,7 +60,7 @@ export const Organization = function Organization() {
const createOrganization = () => {
if (!(newOrgName && newOrgName.trim())) {
toast.error("organization name can't be empty.", {
toast.error('Workspace name can not be empty.', {
position: 'top-center',
});
return;
@ -66,21 +68,22 @@ export const Organization = function Organization() {
setIsCreating(true);
organizationService.createOrganization(newOrgName).then(
(data) => {
setIsCreating(false);
authenticationService.updateCurrentUserDetails(data);
window.location.href = '/';
},
() => {
toast.error('Error while creating organization', {
setIsCreating(false);
toast.error('Error while creating workspace', {
position: 'top-center',
});
}
);
setIsCreating(false);
};
const editOrganization = () => {
if (!(newOrgName && newOrgName.trim())) {
toast.error("organization name can't be empty.", {
toast.error('Workspace name can not be empty.', {
position: 'top-center',
});
return;
@ -89,13 +92,13 @@ export const Organization = function Organization() {
organizationService.editOrganization({ name: newOrgName }).then(
() => {
authenticationService.updateCurrentUserDetails({ organization: newOrgName });
toast.success('Organization updated', {
toast.success('Workspace updated', {
position: 'top-center',
});
setOrganization(newOrgName);
},
() => {
toast.error('Error while editing organization', {
toast.error('Error while editing workspace', {
position: 'top-center',
});
}
@ -258,7 +261,7 @@ export const Organization = function Organization() {
</div>
{!isSingleOrganization && (
<div className="dropdown-item org-actions">
<div onClick={showCreateModal}>Add Organizations</div>
<div onClick={showCreateModal}>Add workspace</div>
</div>
)}
{admin && (
@ -281,8 +284,12 @@ export const Organization = function Organization() {
return (
<div>
<div className="dropdown organization-list" onMouseEnter={() => setIsListOrganizations(false)}>
<a href="#" className={`btn ${!isSingleOrganization || admin ? 'dropdown-toggle' : ''}`}>
<div className="dropdown organization-list">
<a
href="#"
className={`btn ${!isSingleOrganization || admin ? 'dropdown-toggle' : ''}`}
onMouseOver={() => setIsListOrganizations(false)}
>
<div>{organization}</div>
</a>
{(!isSingleOrganization || admin) && (
@ -291,14 +298,14 @@ export const Organization = function Organization() {
</div>
)}
</div>
<Modal show={showCreateOrg} closeModal={() => setShowCreateOrg(false)} title="Create organization">
<Modal show={showCreateOrg} closeModal={() => setShowCreateOrg(false)} title="Create workspace">
<div className="row">
<div className="col modal-main">
<input
type="text"
onChange={(e) => setNewOrgName(e.target.value)}
className="form-control"
placeholder="organization name"
placeholder="workspace name"
disabled={isCreating}
maxLength={25}
/>
@ -314,19 +321,19 @@ export const Organization = function Organization() {
className={`btn btn-primary ${isCreating ? 'btn-loading' : ''}`}
onClick={createOrganization}
>
Create organization
Create workspace
</button>
</div>
</div>
</Modal>
<Modal show={showEditOrg} closeModal={() => setShowEditOrg(false)} title="Edit organization">
<Modal show={showEditOrg} closeModal={() => setShowEditOrg(false)} title="Edit workspace">
<div className="row">
<div className="col modal-main">
<input
type="text"
onChange={(e) => setNewOrgName(e.target.value)}
className="form-control"
placeholder="organization name"
placeholder="workspace name"
disabled={isCreating}
value={newOrgName}
maxLength={25}

View file

@ -63,12 +63,12 @@ export class OauthService {
async #findAndActivateUser(email: string, organizationId: string): Promise<User> {
const user = await this.usersService.findByEmail(email, organizationId);
if (!user) {
throw new UnauthorizedException('User not exist in the organization');
throw new UnauthorizedException('User not exist in the workspace');
}
const organizationUser: OrganizationUser = user.organizationUsers?.[0];
if (!organizationUser) {
throw new UnauthorizedException('User not exist in the organization');
throw new UnauthorizedException('User not exist in the workspace');
}
if (organizationUser.status != 'active') await this.organizationUsersService.activate(organizationUser);
return user;

View file

@ -9,7 +9,7 @@ export class PopulateSSOConfigs1650485473528 implements MigrationInterface {
const encryptionService = new EncryptionService();
const OrganizationRepository = entityManager.getRepository(Organization);
const isSingleOrganization = process.env.MULTI_ORGANIZATION !== 'true';
const isSingleOrganization = process.env.DISABLE_MULTI_WORKSPACE === 'true';
const enableSignUp = process.env.SSO_DISABLE_SIGNUP !== 'true';
const domain = process.env.SSO_RESTRICTED_DOMAIN;

View file

@ -49,7 +49,7 @@ export class OrganizationsController {
@Get(['/:organizationId/public-configs', '/public-configs'])
async getOrganizationDetails(@Param('organizationId') organizationId: string) {
if (!organizationId && this.configService.get<string>('MULTI_ORGANIZATION') !== 'true') {
if (!organizationId && this.configService.get<string>('DISABLE_MULTI_WORKSPACE') === 'true') {
// Request from single organization login page - find one from organization and setting
organizationId = (await this.organizationsService.getSingleOrganization()).id;
}

View file

@ -7,6 +7,6 @@ export class MultiOrganizationGuard implements CanActivate {
constructor(private configService: ConfigService) {}
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
return this.configService.get<string>('MULTI_ORGANIZATION') === 'true';
return this.configService.get<string>('DISABLE_MULTI_WORKSPACE') !== 'true';
}
}

View file

@ -23,7 +23,7 @@ export class AppConfigService {
'SENTRY_DNS',
'SENTRY_DEBUG',
'DISABLE_SIGNUPS',
'MULTI_ORGANIZATION',
'DISABLE_MULTI_WORKSPACE',
];
}

View file

@ -51,7 +51,7 @@ export class AuthService {
if (!organizationId) {
// Global login
// Determine the organization to be loaded
if (this.configService.get<string>('MULTI_ORGANIZATION') !== 'true') {
if (this.configService.get<string>('DISABLE_MULTI_WORKSPACE') === 'true') {
// Single organization
organization = await this.organizationsService.getSingleOrganization();
if (!organization?.ssoConfigs?.find((oc) => oc.sso == 'form' && oc.enabled)) {
@ -72,7 +72,7 @@ export class AuthService {
organization = organizationList[0];
} else {
// no form login enabled organization available for user - creating new one
organization = await this.organizationsService.create('Untitled organization', user);
organization = await this.organizationsService.create('Untitled workspace', user);
}
}
user.organizationId = organization.id;
@ -122,7 +122,7 @@ export class AuthService {
if (!(isNewOrganization || user.isPasswordLogin)) {
throw new UnauthorizedException();
}
if (this.configService.get<string>('MULTI_ORGANIZATION') !== 'true') {
if (this.configService.get<string>('DISABLE_MULTI_WORKSPACE') === 'true') {
throw new UnauthorizedException();
}
const newUser = await this.usersService.findByEmail(user.email, newOrganizationId);
@ -174,7 +174,7 @@ export class AuthService {
let organization: Organization;
// Check if the configs allows user signups
if (this.configService.get<string>('MULTI_ORGANIZATION') !== 'true') {
if (this.configService.get<string>('DISABLE_MULTI_WORKSPACE') === 'true') {
// Single organization checking if organization exist
organization = await this.organizationsService.getSingleOrganization();
@ -188,7 +188,7 @@ export class AuthService {
}
}
// Create default organization
organization = await this.organizationsService.create('Untitled organization');
organization = await this.organizationsService.create('Untitled workspace');
const user = await this.usersService.create({ email }, organization.id, ['all_users', 'admin'], existingUser, true);
await this.organizationUsersService.create(user, organization, true);
await this.emailService.sendWelcomeEmail(user.email, user.firstName, user.invitationToken);

View file

@ -100,7 +100,7 @@ export class EmailService {
<p>Hi ${name || ''},</p>
<br>
<span>
${sender} has invited you to use ToolJet organisation ${organisationName}. Use the link below to set up your account and get started.
${sender} has invited you to use ToolJet workspace ${organisationName}. Use the link below to set up your account and get started.
</span>
<br>
<a href="${inviteUrl}">${inviteUrl}</a>

View file

@ -30,7 +30,7 @@ export class SeedsService {
sso: 'form',
},
],
name: 'My organization',
name: 'My workspace',
});
await manager.save(organization);

View file

@ -38,6 +38,18 @@ describe('Authentication', () => {
});
describe('Single organization', () => {
beforeEach(async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'DISABLE_SIGNUPS':
return 'false';
case 'DISABLE_MULTI_WORKSPACE':
return 'true';
default:
return process.env[key];
}
});
});
it('should create new users and organization', async () => {
const response = await request(app.getHttpServer()).post('/api/signup').send({ email: 'test@tooljet.io' });
expect(response.statusCode).toBe(201);
@ -52,7 +64,7 @@ describe('Authentication', () => {
});
expect(user.defaultOrganizationId).toBe(user?.organizationUsers?.[0]?.organizationId);
expect(organization.name).toBe('Untitled organization');
expect(organization.name).toBe('Untitled workspace');
const groupPermissions = await user.groupPermissions;
const groupNames = groupPermissions.map((x) => x.group);
@ -142,8 +154,6 @@ describe('Authentication', () => {
switch (key) {
case 'DISABLE_SIGNUPS':
return 'false';
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
@ -155,8 +165,6 @@ describe('Authentication', () => {
switch (key) {
case 'DISABLE_SIGNUPS':
return 'true';
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
@ -182,7 +190,7 @@ describe('Authentication', () => {
});
expect(user.defaultOrganizationId).toBe(user?.organizationUsers?.[0]?.organizationId);
expect(organization?.name).toBe('Untitled organization');
expect(organization?.name).toBe('Untitled workspace');
const groupPermissions = await user.groupPermissions;
const groupNames = groupPermissions.map((x) => x.group);
@ -255,7 +263,7 @@ describe('Authentication', () => {
.send({ email: 'admin@tooljet.io', password: 'password' });
expect(response.statusCode).toBe(201);
expect(response.body.organization_id).not.toBe(current_organization.id);
expect(response.body.organization).toBe('Untitled organization');
expect(response.body.organization).toBe('Untitled workspace');
});
it('should be able to switch between organizations with admin privilage', async () => {
const { organization: invited_organization } = await createUser(

File diff suppressed because it is too large Load diff

View file

@ -13,14 +13,6 @@ describe('organizations controller', () => {
beforeEach(async () => {
await clearDB();
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'MULTI_ORGANIZATION':
return 'false';
default:
return process.env[key];
}
});
});
beforeAll(async () => {
@ -65,28 +57,20 @@ describe('organizations controller', () => {
describe('create organization', () => {
it('should allow only authenticated users to create organization', async () => {
await request(app.getHttpServer()).post('/api/organizations').send({ name: 'My organization' }).expect(401);
await request(app.getHttpServer()).post('/api/organizations').send({ name: 'My workspace' }).expect(401);
});
it('should create new organization if multi organization supported', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
});
it('should create new organization if Multi-Workspace supported', async () => {
const { user, organization } = await createUser(app, {
email: 'admin@tooljet.io',
});
const response = await request(app.getHttpServer())
.post('/api/organizations')
.send({ name: 'My organization' })
.send({ name: 'My workspace' })
.set('Authorization', authHeaderForUser(user));
expect(response.statusCode).toBe(201);
expect(response.body.organization_id).not.toBe(organization.id);
expect(response.body.organization).toBe('My organization');
expect(response.body.organization).toBe('My workspace');
expect(response.body.admin).toBeTruthy();
const newUser = await userRepository.findOneOrFail({ where: { id: user.id } });
@ -94,14 +78,6 @@ describe('organizations controller', () => {
});
it('should throw error if name is empty', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
});
const { user } = await createUser(app, { email: 'admin@tooljet.io' });
const response = await request(app.getHttpServer())
.post('/api/organizations')
@ -111,35 +87,35 @@ describe('organizations controller', () => {
expect(response.statusCode).toBe(400);
});
it('should not create new organization if multi organization not supported', async () => {
const { user } = await createUser(app, { email: 'admin@tooljet.io' });
await request(app.getHttpServer())
.post('/api/organizations')
.send({ name: 'My organization' })
.set('Authorization', authHeaderForUser(user))
.expect(403);
});
it('should create new organization if multi organization supported and user logged in via SSO', async () => {
it('should not create new organization if Multi-Workspace not supported', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'MULTI_ORGANIZATION':
case 'DISABLE_MULTI_WORKSPACE':
return 'true';
default:
return process.env[key];
}
});
const { user } = await createUser(app, { email: 'admin@tooljet.io' });
await request(app.getHttpServer())
.post('/api/organizations')
.send({ name: 'My workspace' })
.set('Authorization', authHeaderForUser(user))
.expect(403);
});
it('should create new organization if Multi-Workspace supported and user logged in via SSO', async () => {
const { user, organization } = await createUser(app, {
email: 'admin@tooljet.io',
});
const response = await request(app.getHttpServer())
.post('/api/organizations')
.send({ name: 'My organization' })
.send({ name: 'My workspace' })
.set('Authorization', authHeaderForUser(user, null, false));
expect(response.statusCode).toBe(201);
expect(response.body.organization_id).not.toBe(organization.id);
expect(response.body.organization).toBe('My organization');
expect(response.body.organization).toBe('My workspace');
expect(response.body.admin).toBeTruthy();
});
});
@ -252,6 +228,14 @@ describe('organizations controller', () => {
describe('get public organization configs', () => {
it('should get organization details for all users for single organization', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'DISABLE_MULTI_WORKSPACE':
return 'true';
default:
return process.env[key];
}
});
const { user } = await createUser(app, {
email: 'admin@tooljet.io',
});
@ -291,14 +275,6 @@ describe('organizations controller', () => {
});
it('should get organization specific details for all users for multiple organization deployment', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
});
const { user, organization } = await createUser(app, {
email: 'admin@tooljet.io',
});

View file

@ -12,22 +12,17 @@ describe('users controller', () => {
beforeEach(async () => {
await clearDB();
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'DISABLE_SIGNUPS':
return 'false';
case 'MULTI_ORGANIZATION':
return 'false';
default:
return process.env[key];
}
});
});
beforeAll(async () => {
({ app, mockConfig } = await createNestAppInstanceWithEnvMock());
});
afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
});
describe('PATCH /api/users/change_password', () => {
it('should allow users to update their password', async () => {
const userData = await createUser(app, { email: 'admin@tooljet.io' });
@ -87,17 +82,7 @@ describe('users controller', () => {
});
describe('POST /api/users/set_password_from_token', () => {
it('should allow users to setup account after sign up using multi organization', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'DISABLE_SIGNUPS':
return 'false';
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
});
it('should allow users to setup account after sign up using Multi-Workspace', async () => {
const invitationToken = uuidv4();
const userData = await createUser(app, {
email: 'signup@tooljet.io',
@ -125,17 +110,7 @@ describe('users controller', () => {
expect(organizationUser.status).toEqual('active');
});
it('should return error if required params are not present - multi organization', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'DISABLE_SIGNUPS':
return 'false';
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
});
it('should return error if required params are not present - Multi-Workspace', async () => {
const invitationToken = uuidv4();
await createUser(app, {
email: 'signup@tooljet.io',
@ -155,6 +130,14 @@ describe('users controller', () => {
});
it('should not allow users to setup account for single organization', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'DISABLE_MULTI_WORKSPACE':
return 'true';
default:
return process.env[key];
}
});
const invitationToken = uuidv4();
await createUser(app, {
email: 'signup@tooljet.io',
@ -174,13 +157,11 @@ describe('users controller', () => {
expect(response.statusCode).toBe(403);
});
it('should not allow users to setup account for multi organization and sign up disabled', async () => {
it('should not allow users to setup account for Multi-Workspace and sign up disabled', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'DISABLE_SIGNUPS':
return 'true';
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
@ -216,15 +197,6 @@ describe('users controller', () => {
organization: org,
});
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
});
const signUpResponse = await request(app.getHttpServer())
.post('/api/signup')
.send({ email: 'invited@tooljet.io' });
@ -269,15 +241,6 @@ describe('users controller', () => {
organization: org,
});
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
});
const signUpResponse = await request(app.getHttpServer())
.post('/api/signup')
.send({ email: 'invited@tooljet.io' });
@ -321,15 +284,7 @@ describe('users controller', () => {
});
describe('POST /api/users/accept-invite', () => {
it('should allow users to accept invitation when multi organization is enabled', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'MULTI_ORGANIZATION':
return 'true';
default:
return process.env[key];
}
});
it('should allow users to accept invitation when Multi-Workspace is enabled', async () => {
const userData = await createUser(app, {
email: 'organizationUser@tooljet.io',
status: 'invited',
@ -347,11 +302,11 @@ describe('users controller', () => {
expect(organizationUser.status).toEqual('active');
});
it('should allow users to accept invitation when multi organization is disabled', async () => {
it('should allow users to accept invitation when Multi-Workspace is disabled', async () => {
jest.spyOn(mockConfig, 'get').mockImplementation((key: string) => {
switch (key) {
case 'MULTI_ORGANIZATION':
return 'false';
case 'DISABLE_MULTI_WORKSPACE':
return 'true';
default:
return process.env[key];
}