Skip to content

Commit

Permalink
Implement organization creation permission controls (#1373)
Browse files Browse the repository at this point in the history
* feat(clerk-js): Hide 'create organization' button in org switcher if no permissions
  • Loading branch information
jescalan committed Jun 19, 2023
1 parent 3214849 commit 1195481
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 4 deletions.
6 changes: 6 additions & 0 deletions .changeset/fifty-eels-work.md
@@ -0,0 +1,6 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

If user does not have permission to create an org, create org button will not display in the OrganizationSwitcher UI
2 changes: 2 additions & 0 deletions packages/clerk-js/src/core/resources/User.ts
Expand Up @@ -80,6 +80,7 @@ export class User extends BaseResource implements UserResource {
publicMetadata: UserPublicMetadata = {};
unsafeMetadata: UserUnsafeMetadata = {};
lastSignInAt: Date | null = null;
createOrganizationEnabled = false;
deleteSelfEnabled = false;
updatedAt: Date | null = null;
createdAt: Date | null = null;
Expand Down Expand Up @@ -320,6 +321,7 @@ export class User extends BaseResource implements UserResource {
this.backupCodeEnabled = data.backup_code_enabled;
this.twoFactorEnabled = data.two_factor_enabled;

this.createOrganizationEnabled = data.create_organization_enabled;
this.deleteSelfEnabled = data.delete_self_enabled;

if (data.last_sign_in_at) {
Expand Down
6 changes: 5 additions & 1 deletion packages/clerk-js/src/core/resources/UserSettings.ts
@@ -1,6 +1,5 @@
import type {
Attributes,
Actions,
OAuthProviders,
OAuthStrategy,
PasswordSettingsData,
Expand All @@ -17,6 +16,11 @@ import { BaseResource } from './internal';
const defaultMaxPasswordLength = 72;
const defaultMinPasswordLength = 8;

export type Actions = {
create_organization: boolean;
delete_self: boolean;
};

/**
* @internal
*/
Expand Down
Expand Up @@ -84,7 +84,7 @@ export const OrganizationActionList = (props: OrganizationActionListProps) => {
</PreviewButton>
))}
</Box>
{createOrganizationButton}
{user.createOrganizationEnabled && createOrganizationButton}
</SecondaryActions>
);
};
Expand Up @@ -46,7 +46,7 @@ describe('OrganizationSwitcher', () => {
it('opens the organization switcher popover when clicked', async () => {
const { wrapper, props } = await createFixtures(f => {
f.withOrganizations();
f.withUser({ email_addresses: ['test@clerk.dev'] });
f.withUser({ email_addresses: ['test@clerk.dev'], create_organization_enabled: true });
});
props.setProps({ hidePersonal: true });
const { getByText, getByRole, userEvent } = render(<OrganizationSwitcher />, { wrapper });
Expand Down Expand Up @@ -107,6 +107,7 @@ describe('OrganizationSwitcher', () => {
f.withUser({
email_addresses: ['test@clerk.dev'],
organization_memberships: [{ name: 'Org1', role: 'basic_member' }],
create_organization_enabled: true,
});
});
props.setProps({ hidePersonal: true });
Expand All @@ -116,6 +117,20 @@ describe('OrganizationSwitcher', () => {
expect(fixtures.clerk.openCreateOrganization).toHaveBeenCalled();
});

it('does not display create organization button if permissions not present', async () => {
const { wrapper, props } = await createFixtures(f => {
f.withOrganizations();
f.withUser({
email_addresses: ['test@clerk.dev'],
organization_memberships: [{ name: 'Org1', role: 'basic_member' }],
create_organization_enabled: false,
});
});
props.setProps({ hidePersonal: true });
const { queryByRole } = render(<OrganizationSwitcher />, { wrapper });
expect(queryByRole('button', { name: 'Create Organization' })).not.toBeInTheDocument();
});

it.todo('switches between active organizations when one is clicked');
});
});
1 change: 1 addition & 0 deletions packages/types/src/json.ts
Expand Up @@ -214,6 +214,7 @@ export interface UserJSON extends ClerkResourceJSON {
public_metadata: UserPublicMetadata;
unsafe_metadata: UserUnsafeMetadata;
last_sign_in_at: number | null;
create_organization_enabled: boolean;
delete_self_enabled: boolean;
updated_at: number;
created_at: number;
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/user.ts
Expand Up @@ -77,6 +77,7 @@ export interface UserResource extends ClerkResource {
publicMetadata: UserPublicMetadata;
unsafeMetadata: UserUnsafeMetadata;
lastSignInAt: Date | null;
createOrganizationEnabled: boolean;
deleteSelfEnabled: boolean;
updatedAt: Date | null;
createdAt: Date | null;
Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/userSettings.ts
Expand Up @@ -91,6 +91,7 @@ export interface UserSettingsJSON extends ClerkResourceJSON {
id: never;
object: never;
attributes: AttributesJSON;
actions: Actions;
social: OAuthProviders;

/**
Expand All @@ -101,7 +102,6 @@ export interface UserSettingsJSON extends ClerkResourceJSON {
sign_in: SignInData;
sign_up: SignUpData;
password_settings: PasswordSettingsData;
actions: Actions;
}

export interface UserSettingsResource extends ClerkResource {
Expand Down

0 comments on commit 1195481

Please sign in to comment.