chore: bump version to 2.23.2 and enhance team account creation (#440)

* chore: bump version to 2.23.2 and enhance team account creation

- Updated application version from 2.23.1 to 2.23.2 in package.json.
- Enhanced team account creation to support slugs for non-Latin names, including validation and UI updates.
- Updated localization files to reflect new slug requirements and error messages.
- Refactored related schemas and server actions to accommodate slug handling in team account creation and updates.

* refactor: remove old trigger and function for adding current user to new account

- Dropped the trigger "add_current_user_to_new_account" and the associated function from the database schema.
- Updated permissions for the function public.create_team_account to ensure proper access control.
This commit is contained in:
Giancarlo Buomprisco
2026-01-08 14:18:13 +01:00
committed by GitHub
parent e1bfbc8106
commit 0636f8cf11
21 changed files with 2042 additions and 1619 deletions

View File

@@ -91,13 +91,23 @@ export class TeamAccountsPageObject {
}).toPass();
}
async tryCreateTeam(teamName: string) {
await this.page.locator('[data-test="create-team-form"] input').fill('');
await this.page.waitForTimeout(200);
async tryCreateTeam(teamName: string, slug?: string) {
const nameInput = this.page.locator(
'[data-test="create-team-form"] [data-test="team-name-input"]',
);
await this.page
.locator('[data-test="create-team-form"] input')
.fill(teamName);
await nameInput.fill('');
await nameInput.fill(teamName);
// If slug is provided (for non-Latin names), fill the slug field
if (slug) {
const slugInput = this.page.locator(
'[data-test="create-team-form"] [data-test="team-slug-input"]',
);
await expect(slugInput).toBeVisible();
await slugInput.fill(slug);
}
return this.page.click('[data-test="create-team-form"] button:last-child');
}
@@ -106,7 +116,14 @@ export class TeamAccountsPageObject {
await this.openAccountsSelector();
await this.page.click('[data-test="create-team-account-trigger"]');
await this.page.fill('[data-test="create-team-form"] input', teamName);
await this.page.fill(
'[data-test="create-team-form"] [data-test="team-name-input"]',
teamName,
);
// Slug field is only shown for non-Latin names, so we don't fill it for Latin names
// The database trigger will auto-generate the slug from the name
const click = this.page.click(
'[data-test="create-team-form"] button:last-child',
@@ -115,23 +132,77 @@ export class TeamAccountsPageObject {
const response = this.page.waitForURL(`/home/${slug}`);
await Promise.all([click, response]);
// Verify user landed on the team page
await expect(this.page).toHaveURL(`/home/${slug}`);
// Verify the team was created and appears in the selector
await this.openAccountsSelector();
await expect(this.getTeamFromSelector(teamName)).toBeVisible();
// Close the selector
await this.page.keyboard.press('Escape');
}
async updateName(name: string, slug: string) {
async createTeamWithNonLatinName(teamName: string, slug: string) {
await this.openAccountsSelector();
await this.page.click('[data-test="create-team-account-trigger"]');
await this.page.fill(
'[data-test="create-team-form"] [data-test="team-name-input"]',
teamName,
);
// Wait for slug field to appear (triggered by non-Latin name)
await expect(this.getSlugField()).toBeVisible();
await this.page.fill(
'[data-test="create-team-form"] [data-test="team-slug-input"]',
slug,
);
const click = this.page.click(
'[data-test="create-team-form"] button:last-child',
);
const response = this.page.waitForURL(`/home/${slug}`);
await Promise.all([click, response]);
// Verify user landed on the team page
await expect(this.page).toHaveURL(`/home/${slug}`);
// Verify the team was created and appears in the selector
await this.openAccountsSelector();
await expect(this.getTeamFromSelector(teamName)).toBeVisible();
// Close the selector
await this.page.keyboard.press('Escape');
}
getSlugField() {
return this.page.locator(
'[data-test="create-team-form"] [data-test="team-slug-input"]',
);
}
async updateTeamName(name: string) {
await expect(async () => {
await this.page.fill(
'[data-test="update-team-account-name-form"] input',
name,
);
const click = this.page.click(
'[data-test="update-team-account-name-form"] button',
);
// the slug should be updated to match the new team name
const response = this.page.waitForURL(`**/home/${slug}/settings`);
return Promise.all([click, response]);
await Promise.all([
this.page.click('[data-test="update-team-account-name-form"] button'),
this.page.waitForResponse((response) => {
return (
response.url().includes('settings') &&
response.request().method() === 'POST'
);
}),
]);
}).toPass();
}
@@ -165,8 +236,11 @@ export class TeamAccountsPageObject {
await this.page.click(`[data-test="role-option-${newRole}"]`);
// Wait for the update to complete and page to reload
const response = this.page.waitForResponse(response => {
return response.url().includes('members') && response.request().method() === 'POST'
const response = this.page.waitForResponse((response) => {
return (
response.url().includes('members') &&
response.request().method() === 'POST'
);
});
return Promise.all([

View File

@@ -65,22 +65,20 @@ test.describe('Team Accounts', () => {
await teamAccounts.setup();
});
test('user can update their team name (and slug)', async ({ page }) => {
test('user can update their team name', async ({ page }) => {
const teamAccounts = new TeamAccountsPageObject(page);
const { teamName, slug } = teamAccounts.createTeamName();
const newTeamName = `Updated-Team-${(Math.random() * 100000000).toFixed(0)}`;
await teamAccounts.goToSettings();
const request = teamAccounts.updateName(teamName, slug);
// Update just the name (slug stays the same for Latin names)
await teamAccounts.updateTeamName(newTeamName);
// the slug should be updated to match the new team name
const newUrl = page.waitForURL(`**/home/${slug}/settings`);
await Promise.all([request, newUrl]);
await page.waitForTimeout(500);
await teamAccounts.openAccountsSelector();
await expect(teamAccounts.getTeamFromSelector(teamName)).toBeVisible();
await expect(teamAccounts.getTeamFromSelector(newTeamName)).toBeVisible();
});
test('cannot create a Team account using reserved names', async ({
@@ -176,54 +174,73 @@ test.describe('Team Accounts', () => {
await expectError();
});
test('cannot create a Team account using non-latin characters', async ({
test('can create a Team account with non-Latin name when providing a slug', async ({
page,
}) => {
const teamAccounts = new TeamAccountsPageObject(page);
await teamAccounts.createTeam();
const random = (Math.random() * 100000000).toFixed(0);
const slug = `korean-team-${random}`;
// Create team with Korean name
await teamAccounts.createTeamWithNonLatinName('한국 팀', slug);
// Verify we're on the team page
await expect(page).toHaveURL(`/home/${slug}`);
// Verify team appears in selector
await teamAccounts.openAccountsSelector();
await expect(teamAccounts.getTeamFromSelector('한국 팀')).toBeVisible();
});
test('slug validation shows error for invalid characters', async ({
page,
}) => {
const teamAccounts = new TeamAccountsPageObject(page);
await teamAccounts.createTeam();
// Use non-Latin name to trigger the slug field visibility
await teamAccounts.openAccountsSelector();
await page.click('[data-test="create-team-account-trigger"]');
function expectNonLatinError() {
return expect(
page.getByText(
'This name can only contain Latin characters (a-z), numbers, spaces, and hyphens.',
),
).toBeVisible();
}
await page.fill(
'[data-test="create-team-form"] [data-test="team-name-input"]',
'テストチーム',
);
// Test Cyrillic characters
await teamAccounts.tryCreateTeam('Тест Команда');
await expectNonLatinError();
// Wait for slug field to appear (triggered by non-Latin name)
await expect(teamAccounts.getSlugField()).toBeVisible();
// Test Chinese characters
await teamAccounts.tryCreateTeam('测试团队');
await expectNonLatinError();
// Test invalid slug with uppercase
await page.fill(
'[data-test="create-team-form"] [data-test="team-slug-input"]',
'Invalid-Slug',
);
// Test Japanese characters
await teamAccounts.tryCreateTeam('テストチーム');
await expectNonLatinError();
await page.click('[data-test="create-team-form"] button:last-child');
// Test Arabic characters
await teamAccounts.tryCreateTeam('فريق اختبار');
await expectNonLatinError();
// Test mixed Latin and non-Latin
await teamAccounts.tryCreateTeam('Test Команда');
await expectNonLatinError();
// Test emoji
await teamAccounts.tryCreateTeam('Test Team 🚀');
await expectNonLatinError();
// Ensure valid Latin names still work (should NOT show error)
await teamAccounts.tryCreateTeam('Valid Team Name 123');
await expect(
page.getByText(
'This name can only contain Latin characters (a-z), numbers, spaces, and hyphens.',
'Only English letters (a-z), numbers (0-9), and hyphens (-) are allowed',
{ exact: true },
),
).not.toBeVisible();
).toBeVisible();
// Test invalid slug with non-Latin characters
await page.fill(
'[data-test="create-team-form"] [data-test="team-slug-input"]',
'тест-slug',
);
await page.click('[data-test="create-team-form"] button:last-child');
await expect(
page.getByText(
'Only English letters (a-z), numbers (0-9), and hyphens (-) are allowed',
{ exact: true },
),
).toBeVisible();
});
});

View File

@@ -743,7 +743,7 @@ export type Database = {
Returns: Json
}
create_team_account: {
Args: { account_name: string }
Args: { account_name: string; account_slug?: string }
Returns: {
created_at: string | null
created_by: string | null

View File

@@ -160,7 +160,11 @@
"leaveTeamInputDescription": "By leaving the team, you will no longer have access to it.",
"reservedNameError": "This name is reserved. Please choose a different one.",
"specialCharactersError": "This name cannot contain special characters. Please choose a different one.",
"nonLatinCharactersError": "This name can only contain Latin characters (a-z), numbers, spaces, and hyphens.",
"teamSlugLabel": "Team URL",
"teamSlugDescription": "Only English letters (a-z), numbers (0-9), and hyphens (-) are allowed. Example: my-team-name",
"slugRequiredForNonLatinName": "Since your team name uses non-English characters, please provide a URL using only English letters",
"invalidSlugError": "Only English letters (a-z), numbers (0-9), and hyphens (-) are allowed",
"duplicateSlugError": "This URL is already taken. Please choose a different one.",
"checkingPolicies": "Loading. Please wait...",
"policyCheckError": "We are unable to verify invitations restrictions. Please try again.",
"invitationsBlockedMultiple": "Invitations are currently not allowed for the following reasons:",

View File

@@ -0,0 +1,67 @@
drop policy "create_org_account" on "public"."accounts";
drop function if exists "public"."create_team_account"(text);
set check_function_bodies = off;
CREATE OR REPLACE FUNCTION public.create_team_account(account_name text, user_id uuid, account_slug text DEFAULT NULL::text)
RETURNS public.accounts
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO ''
AS $function$
declare
new_account public.accounts;
owner_role varchar(50);
begin
if (not public.is_set('enable_team_accounts')) then
raise exception 'Team accounts are not enabled';
end if;
-- Get the highest system role for the owner
select public.get_upper_system_role() into owner_role;
-- Insert the new team account
-- The slug will be auto-generated from name by the "set_slug_from_account_name"
-- trigger if account_slug is null
insert into public.accounts(
name,
slug,
is_personal_account,
primary_owner_user_id)
values (
account_name,
account_slug,
false,
user_id)
returning * into new_account;
-- Create membership for the owner (atomic with account creation)
insert into public.accounts_memberships(
account_id,
user_id,
account_role)
values (
new_account.id,
user_id,
coalesce(owner_role, 'owner'));
return new_account;
end;
$function$
;
-- Revoke from all roles first to ensure exclusivity
revoke all on function public.create_team_account(text, uuid, text) from public;
revoke all on function public.create_team_account(text, uuid, text) from authenticated;
-- Grant only to service_role
grant execute on function public.create_team_account(text, uuid, text) to service_role;
-- Drop trigger (handled by the new function)
drop trigger if exists "add_current_user_to_new_account" on "public"."accounts";
drop function if exists "kit"."add_current_user_to_new_account"();

View File

@@ -223,37 +223,6 @@ $$ language plpgsql;
grant
execute on function public.get_upper_system_role () to service_role;
-- Function "kit.add_current_user_to_new_account"
-- Trigger to add the current user to a new account as the primary owner
create
or replace function kit.add_current_user_to_new_account () returns trigger language plpgsql security definer
set
search_path = '' as $$
begin
if new.primary_owner_user_id = auth.uid() then
insert into public.accounts_memberships(
account_id,
user_id,
account_role)
values(
new.id,
auth.uid(),
public.get_upper_system_role());
end if;
return NEW;
end;
$$;
-- trigger the function whenever a new account is created
create trigger "add_current_user_to_new_account"
after insert on public.accounts for each row
when (new.is_personal_account = false)
execute function kit.add_current_user_to_new_account ();
-- create a trigger to update the account email when the primary owner email is updated
create
or replace function kit.handle_update_user_email () returns trigger language plpgsql security definer
@@ -470,36 +439,62 @@ execute procedure kit.setup_new_user ();
* -------------------------------------------------------
*/
-- Function "public.create_team_account"
-- Create a team account if team accounts are enabled
-- Create a team account with membership in a single transaction
-- Called by service_role only (Policies API enforced in application layer)
create
or replace function public.create_team_account (account_name text) returns public.accounts
or replace function public.create_team_account (
account_name text,
user_id uuid,
account_slug text default null
) returns public.accounts
language plpgsql
security definer
set
search_path = '' as $$
declare
new_account public.accounts;
owner_role varchar(50);
begin
if (not public.is_set('enable_team_accounts')) then
raise exception 'Team accounts are not enabled';
end if;
-- Get the highest system role for the owner
select public.get_upper_system_role() into owner_role;
-- Insert the new team account
-- The slug will be auto-generated from name by the "set_slug_from_account_name"
-- trigger if account_slug is null
insert into public.accounts(
name,
is_personal_account)
slug,
is_personal_account,
primary_owner_user_id)
values (
account_name,
false)
returning
* into new_account;
account_slug,
false,
user_id)
returning * into new_account;
-- Create membership for the owner (atomic with account creation)
insert into public.accounts_memberships(
account_id,
user_id,
account_role)
values (
new_account.id,
user_id,
coalesce(owner_role, 'owner'));
return new_account;
end;
$$ language plpgsql;
$$;
grant
execute on function public.create_team_account (text) to authenticated,
service_role;
execute on function public.create_team_account (text, uuid, text) to service_role;
-- RLS(public.accounts)
-- Authenticated users can delete team accounts

View File

@@ -9,12 +9,14 @@ select tests.create_supabase_user('test1', 'test1@test.com');
select tests.create_supabase_user('test2');
-- Create an team account
-- Create team account using service_role (function is now service_role only)
set local role service_role;
select public.create_team_account('Test', tests.get_supabase_uid('test1'));
-- Switch back to authenticated user for testing
select makerkit.authenticate_as('test1');
select public.create_team_account('Test');
-- the owner account has permissions to manage members
select row_eq(
$$ select public.has_permission(

View File

@@ -9,14 +9,16 @@ select tests.create_supabase_user('test1', 'test1@test.com');
select tests.create_supabase_user('test2');
-- Create an team account
-- Create team accounts using service_role (function is now service_role only)
set local role service_role;
select public.create_team_account('Test', tests.get_supabase_uid('test1'));
select public.create_team_account('Test', tests.get_supabase_uid('test1'));
select public.create_team_account('Test', tests.get_supabase_uid('test1'));
-- Switch back to authenticated user for testing
select makerkit.authenticate_as('test1');
select public.create_team_account('Test');
select public.create_team_account('Test');
select public.create_team_account('Test');
-- should automatically create slugs for the accounts
select row_eq(
$$ select slug from public.accounts where name = 'Test' and slug = 'test' $$,

View File

@@ -12,12 +12,19 @@ select
select
tests.create_supabase_user('test2');
-- Create an team account
select
makerkit.authenticate_as('test1');
-- Create an team account (without explicit slug, should auto-generate)
-- DON'T authenticate first - the add_current_user_to_new_account trigger
-- would also create a membership if auth.uid() = primary_owner_user_id
-- The function already creates the membership, so we avoid duplicate by keeping auth.uid() NULL
set local role service_role;
select
public.create_team_account('Test');
public.create_team_account('Test', tests.get_supabase_uid('test1'));
-- Reset to postgres and then authenticate as test1 for proper RLS context
set local role postgres;
select
makerkit.authenticate_as('test1');
select
row_eq($$
@@ -28,6 +35,44 @@ select
'test'::text, 'Test'::varchar),
'Users can create a team account');
-- Test creating team account with explicit slug parameter
select
tests.create_supabase_user('slugtest1', 'slugtest1@test.com');
-- Switch to service_role to call the function
set local role service_role;
select
public.create_team_account('Custom Team Name', tests.get_supabase_uid('slugtest1'), 'custom-slug-123');
-- Switch back to authenticated user for testing
select
makerkit.authenticate_as('slugtest1');
select
row_eq($$
select
primary_owner_user_id, is_personal_account, slug, name
from makerkit.get_account_by_slug('custom-slug-123') $$,
row (tests.get_supabase_uid('slugtest1'), false,
'custom-slug-123'::text, 'Custom Team Name'::varchar),
'Users can create a team account with custom slug');
-- Verify membership is created for custom slug team
select
row_eq($$
select
account_role from public.accounts_memberships
where
account_id = (select id from public.accounts where slug = 'custom-slug-123')
and user_id = tests.get_supabase_uid('slugtest1')
$$, row ('owner'::varchar),
'The primary owner should have the owner role for team with custom slug');
-- Switch back to test1 for testing the original 'test' account
select
makerkit.authenticate_as('test1');
-- Should be the primary owner of the team account by default
select
row_eq($$
@@ -106,12 +151,13 @@ create or replace function kit.single_account_per_owner()
declare
total_accounts int;
begin
-- Check if this user already owns an account by checking NEW.primary_owner_user_id
select
count(id)
from
public.accounts
where
primary_owner_user_id = auth.uid() into total_accounts;
primary_owner_user_id = NEW.primary_owner_user_id into total_accounts;
if total_accounts > 0 then
raise exception 'User can only own 1 account';
@@ -129,14 +175,13 @@ create trigger single_account_per_owner
before insert on public.accounts for each row
execute function kit.single_account_per_owner();
-- Create an team account
select
makerkit.authenticate_as('test1');
-- Try to create another team account for the same owner (should fail due to trigger)
set local role service_role;
select
throws_ok(
$$ select
public.create_team_account('Test2') $$, 'User can only own 1 account');
public.create_team_account('Test2', tests.get_supabase_uid('test1')) $$, 'User can only own 1 account');
set local role postgres;
@@ -151,11 +196,10 @@ select
tests.create_supabase_user('updatetest2', 'updatetest2@test.com');
-- Create a team account for update tests
select
makerkit.authenticate_as('updatetest1');
set local role service_role;
select
public.create_team_account('UpdateTeam');
public.create_team_account('UpdateTeam', tests.get_supabase_uid('updatetest1'));
-- Add updatetest2 as a member
set local role postgres;
@@ -259,11 +303,10 @@ select
tests.create_supabase_user('roletest2', 'roletest2@test.com');
-- Create a team account for role tests
select
makerkit.authenticate_as('roletest1');
set local role service_role;
select
public.create_team_account('RoleTeam');
public.create_team_account('RoleTeam', tests.get_supabase_uid('roletest1'));
-- Add roletest2 as a member
set local role postgres;
@@ -333,11 +376,10 @@ select
tests.create_supabase_user('deletetest2', 'deletetest2@test.com');
-- Create a team account for delete tests
select
makerkit.authenticate_as('deletetest1');
set local role service_role;
select
public.create_team_account('DeleteTeam');
public.create_team_account('DeleteTeam', tests.get_supabase_uid('deletetest1'));
-- Add deletetest2 as a member
set local role postgres;
@@ -383,8 +425,8 @@ select tests.create_supabase_user('permtest2', 'permtest2@test.com');
select tests.create_supabase_user('permtest3', 'permtest3@test.com');
-- Create a team account for permission tests
select makerkit.authenticate_as('permtest1');
select public.create_team_account('PermTeam');
set local role service_role;
select public.create_team_account('PermTeam', tests.get_supabase_uid('permtest1'));
-- Get the account ID for PermTeam to avoid NULL references
set local role postgres;
@@ -470,8 +512,8 @@ select tests.create_supabase_user('hiertest3', 'hiertest3@test.com');
select tests.create_supabase_user('hiertest4', 'hiertest4@test.com');
-- Create a team account for hierarchy tests
select makerkit.authenticate_as('hiertest1');
select public.create_team_account('HierTeam');
set local role service_role;
select public.create_team_account('HierTeam', tests.get_supabase_uid('hiertest1'));
-- Add users with different roles
set local role postgres;
@@ -540,8 +582,8 @@ select tests.create_supabase_user('vistest2', 'vistest2@test.com');
select tests.create_supabase_user('vistest3', 'vistest3@test.com');
-- Create a team account
select makerkit.authenticate_as('vistest1');
select public.create_team_account('VisTeam');
set local role service_role;
select public.create_team_account('VisTeam', tests.get_supabase_uid('vistest1'));
-- Add vistest2 as a member
set local role postgres;
@@ -578,8 +620,8 @@ select tests.create_supabase_user('functest1', 'functest1@test.com');
select tests.create_supabase_user('functest2', 'functest2@test.com');
-- Create team account
select makerkit.authenticate_as('functest1');
select public.create_team_account('FuncTeam');
set local role service_role;
select public.create_team_account('FuncTeam', tests.get_supabase_uid('functest1'));
-- Test: get_account_members function properly restricts data
select makerkit.authenticate_as('functest2');
@@ -619,10 +661,11 @@ select tests.create_supabase_user('ownerupdate1', 'ownerupdate1@test.com');
select tests.create_supabase_user('ownerupdate2', 'ownerupdate2@test.com');
-- Create team account
select makerkit.authenticate_as('ownerupdate1');
select public.create_team_account('TeamChange');
set local role service_role;
select public.create_team_account('TeamChange', tests.get_supabase_uid('ownerupdate1'));
-- Update the team name as the owner
select makerkit.authenticate_as('ownerupdate1');
select lives_ok(
$$ UPDATE public.accounts
SET name = 'Updated Owner Team'
@@ -668,23 +711,16 @@ select
tests.create_supabase_user('crosstest2', 'crosstest2@test.com');
-- Create first team account with crosstest1 as owner
select
makerkit.authenticate_as('crosstest1');
set local role service_role;
select
public.create_team_account('TeamA');
public.create_team_account('TeamA', tests.get_supabase_uid('crosstest1'));
-- Create second team account with crosstest2 as owner
select
makerkit.authenticate_as('crosstest2');
select
public.create_team_account('TeamB');
public.create_team_account('TeamB', tests.get_supabase_uid('crosstest2'));
-- Add crosstest2 as a member to TeamA
select
makerkit.authenticate_as('crosstest1');
set local role postgres;
-- Add member to first team
@@ -767,6 +803,31 @@ select
'TeamB name should remain unchanged after attempted update by non-member'
);
-- Test 7: Security - Public/anon role cannot execute create_team_account
select
tests.create_supabase_user('securitytest1', 'securitytest1@test.com');
-- Test as anon role (public) - should get permission denied (either for schema or function)
set local role anon;
select
throws_ok(
$$ select public.create_team_account('SecurityTeam', tests.get_supabase_uid('securitytest1')) $$,
'permission denied for schema public',
'Anonymous/public role should not be able to execute create_team_account'
);
-- Test as authenticated role (still should fail - only service_role is allowed)
select
makerkit.authenticate_as('securitytest1');
select
throws_ok(
$$ select public.create_team_account('SecurityTeam', tests.get_supabase_uid('securitytest1')) $$,
'permission denied for function create_team_account',
'Authenticated role should not be able to execute create_team_account directly'
);
select
*
from

View File

@@ -9,15 +9,15 @@ select plan(12);
--- Create test users
select tests.create_supabase_user('trigger_test_user1', 'test1@example.com');
-- Authenticate as test user
select makerkit.authenticate_as('trigger_test_user1');
------------
--- Test accounts table timestamp triggers - INSERT
------------
INSERT INTO public.accounts (name, is_personal_account)
VALUES ('Test Account', false);
-- Use service_role to insert (create_org_account policy was removed)
set role service_role;
INSERT INTO public.accounts (name, is_personal_account, primary_owner_user_id)
VALUES ('Test Account', false, tests.get_supabase_uid('trigger_test_user1'));
SELECT ok(
(SELECT created_at IS NOT NULL FROM public.accounts WHERE name = 'Test Account'),
@@ -38,9 +38,9 @@ SELECT ok(
--- Test invitations table timestamp triggers - INSERT
------------
-- Create a team account for invitation testing
INSERT INTO public.accounts (name, is_personal_account)
VALUES ('Invitation Test Team', false);
-- Create a team account for invitation testing (still in service_role from above)
INSERT INTO public.accounts (name, is_personal_account, primary_owner_user_id)
VALUES ('Invitation Test Team', false, tests.get_supabase_uid('trigger_test_user1'));
-- Switch to service_role to insert invitations (INSERT policy removed, handled by server action)
set role service_role;
@@ -56,9 +56,7 @@ VALUES (
now() + interval '7 days'
);
-- Switch back to authenticated user for assertion
select makerkit.authenticate_as('trigger_test_user1');
-- Stay in service_role for assertions (testing triggers, not RLS)
SELECT ok(
(SELECT created_at IS NOT NULL FROM public.invitations WHERE email = 'invitee@example.com'),
'invitations: created_at should be set automatically on insert'

View File

@@ -13,12 +13,19 @@ select tests.create_supabase_user('user_tracking_test1', 'tracking1@example.com'
--- Test accounts table user tracking triggers - INSERT
------------
-- Authenticate as first user for insert
-- Authenticate first to set JWT claims (for auth.uid() in triggers)
select makerkit.authenticate_as('user_tracking_test1');
-- Switch to service_role for INSERT (create_org_account policy was removed)
-- but JWT claims are preserved so auth.uid() still works in triggers
set local role service_role;
-- Test INSERT: created_by and updated_by should be set to current user
INSERT INTO public.accounts (name, is_personal_account)
VALUES ('User Tracking Test Account', false);
INSERT INTO public.accounts (name, is_personal_account, primary_owner_user_id)
VALUES ('User Tracking Test Account', false, tests.get_supabase_uid('user_tracking_test1'));
-- Switch back to authenticated for assertions
select makerkit.authenticate_as('user_tracking_test1');
SELECT ok(
(SELECT created_by = tests.get_supabase_uid('user_tracking_test1')

View File

@@ -7,15 +7,15 @@ select no_plan();
select tests.create_supabase_user('update_test_owner', 'update-owner@test.com');
select tests.create_supabase_user('update_test_member', 'update-member@test.com');
-- Authenticate as owner to create team account
select makerkit.authenticate_as('update_test_owner');
-- Create team account using service_role and create_team_account function
-- DON'T authenticate first - the add_current_user_to_new_account trigger
-- would also create a membership if auth.uid() = primary_owner_user_id
-- The function already creates the membership, so we avoid duplicate by keeping auth.uid() NULL
set local role service_role;
-- Create a team account (owner is added automatically via trigger)
insert into public.accounts (name, is_personal_account)
values ('Update Test Team', false);
select public.create_team_account('Update Test Team', tests.get_supabase_uid('update_test_owner'));
-- Add member to the team with 'member' role using service_role
set role service_role;
-- Add member to the team with 'member' role (still in service_role)
insert into public.accounts_memberships (account_id, user_id, account_role)
values (