Update localization texts, add permissions check, and seed data

This commit removes the membersTabDescription, updates the deleteAccountDescription text in the localization files, and adds a condition to check permissions in account invitation component. It also includes test credentials in README and provides a significant amount of seed data for testing the database.
This commit is contained in:
giancarlo
2024-04-20 16:53:54 +08:00
parent 0148265b5f
commit efd27aa7de
21 changed files with 634 additions and 122 deletions

View File

@@ -106,6 +106,11 @@ This command will run the web application.
Please refer to `apps/web/README.md` for more information about the web application.
To get started right away, use the credentials below:
- **Email**: `test@makerkit.dev`
- **Password**: `testingpassword`
#### Turbopack
Makerkit uses Turbopack by default. Turbopack is the new bundler for Next.js - and it is still experimental. It is faster, but it may have some issues.

View File

@@ -43,7 +43,4 @@ NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING=true
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETION=true
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING=true
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS=true
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION=true
# MAIL
MAILER_PROVIDER=cloudflare
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION=true

View File

@@ -16,4 +16,7 @@ EMAIL_USER=user
EMAIL_PASSWORD=password
# STRIPE
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
# MAILER
MAILER_PROVIDER=nodemailer

View File

@@ -76,7 +76,7 @@ export const AccountLayoutMobileNavigation = (
</DropdownMenuTrigger>
<DropdownMenuContent sideOffset={10} className={'w-screen rounded-none'}>
<OrganizationsModal />
<TeamAccountsModal />
{Links}
@@ -130,7 +130,7 @@ function SignOutDropdownItem(
);
}
function OrganizationsModal() {
function TeamAccountsModal() {
const router = useRouter();
return (
@@ -143,7 +143,7 @@ function OrganizationsModal() {
<Home className={'h-4'} />
<span>
<Trans i18nKey={'common:yourOrganizations'} />
<Trans i18nKey={'common:yourAccounts'} />
</span>
</DropdownMenuItem>
</DialogTrigger>
@@ -151,7 +151,7 @@ function OrganizationsModal() {
<DialogContent>
<DialogHeader>
<DialogTitle>
<Trans i18nKey={'common:yourOrganizations'} />
<Trans i18nKey={'common:yourAccounts'} />
</DialogTitle>
</DialogHeader>

View File

@@ -9,10 +9,10 @@ import { getSupabaseServerComponentClient } from '@kit/supabase/server-component
import pathsConfig from '~/config/paths.config';
/**
* Load the organization workspace data.
* Load the account workspace data.
* We place this function into a separate file so it can be reused in multiple places across the server components.
*
* This function is used in the layout component for the organization workspace.
* This function is used in the layout component for the account workspace.
* It is cached so that the data is only fetched once per request.
*
* @param accountSlug
@@ -42,7 +42,7 @@ export const loadTeamWorkspace = cache(async (accountSlug: string) => {
throw accountResult.error;
}
// we cannot find any record for the selected organization
// we cannot find any record for the selected account
// so we redirect the user to the home page
if (!accountResult.data.length) {
return redirect(pathsConfig.app.home);
@@ -50,7 +50,7 @@ export const loadTeamWorkspace = cache(async (accountSlug: string) => {
const accountData = accountResult.data[0];
// we cannot find any record for the selected organization
// we cannot find any record for the selected account
// so we redirect the user to the home page
if (!accountData) {
return redirect(pathsConfig.app.home);

View File

@@ -132,7 +132,7 @@
"dangerZoneDescription": "Some actions cannot be undone. Please be careful.",
"deleteAccount": "Delete your Account",
"deletingAccount": "Deleting account. Please wait...",
"deleteAccountDescription": "This will delete your account and the organizations you own. Furthermore, we will immediately cancel any active subscriptions. This action cannot be undone.",
"deleteAccountDescription": "This will delete your account and the accounts you own. Furthermore, we will immediately cancel any active subscriptions. This action cannot be undone.",
"deleteProfileConfirmationInputLabel": "Type DELETE to confirm",
"deleteAccountErrorHeading": "Sorry, we couldn't delete your account",
"needsReauthentication": "Reauthentication Required",

View File

@@ -11,8 +11,6 @@
"orContinueWithEmail": "or continue with email",
"doNotHaveAccountYet": "Do not have an account yet?",
"alreadyHaveAnAccount": "Already have an account?",
"joinOrganizationHeading": "Join {{organization}}",
"joinOrganizationSubHeading": "You were invited to join <b>{{organization}}</Bold>",
"signUpToAcceptInvite": "Please sign in/up to accept the invite",
"clickToAcceptAs": "Click the button below to accept the invite with as <b>{{email}}</b>",
"acceptInvite": "Accept invite",
@@ -22,7 +20,6 @@
"acceptInviteWithDifferentAccount": "Want to accept the invite with a different account?",
"alreadyHaveAccountStatement": "I already have an account, I want to sign in instead",
"doNotHaveAccountStatement": "I do not have an account, I want to sign up instead",
"addingToOrganization": "We are adding you to <b>{{name}}</b>. Please Wait...",
"signInWithProvider": "Sign in with {{provider}}",
"signInWithPhoneNumber": "Sign in with Phone Number",
"signInWithEmail": "Sign in with Email",

View File

@@ -12,12 +12,12 @@
"cancelAtPeriodEndDescription": "Your subscription is scheduled to be canceled on {{- endDate }}.",
"renewAtPeriodEndDescription": "Your subscription is scheduled to be renewed on {{- endDate }}",
"noPermissionsAlertHeading": "You don't have permissions to change the billing settings",
"noPermissionsAlertBody": "Please contact your organization owner to change the billing settings for your organization.",
"noPermissionsAlertBody": "Please contact your account owner to change the billing settings for your account.",
"checkoutSuccessTitle": "Done! You're all set.",
"checkoutSuccessDescription": "Thank you for subscribing, we have successfully processed your subscription! A confirmation email will be sent to {{ customerEmail }}.",
"checkoutSuccessBackButton": "Proceed to App",
"cannotManageBillingAlertTitle": "You cannot manage billing",
"cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your organization owner.",
"cannotManageBillingAlertDescription": "You do not have permissions to manage billing. Please contact your account owner.",
"manageTeamPlan": "Manage your Team Plan",
"manageTeamPlanDescription": "Choose a plan that fits your team's needs. You can upgrade or downgrade your plan at any time.",
"basePlan": "Base Plan",

View File

@@ -2,16 +2,15 @@
"homeTabLabel": "Home",
"homeTabDescription": "Welcome to your home page",
"accountMembers": "Members",
"membersTabDescription": "Manage your organization's members",
"membersTabDescription": "Here you can manage the members of your team.",
"billingTabLabel": "Billing",
"billingTabDescription": "Manage your billing and subscription",
"yourAccountTabLabel": "Account Settings",
"dashboardTabLabel": "Dashboard",
"organizationSettingsTabLabel": "Organization",
"settingsTabLabel": "Settings",
"profileSettingsTabLabel": "Profile",
"subscriptionSettingsTabLabel": "Subscription",
"dashboardTabDescription": "An overview of your organization's activity and performance across all your projects.",
"dashboardTabDescription": "An overview of your accoount's activity and performance across all your projects.",
"settingsTabDescription": "Manage your settings and preferences.",
"emailAddress": "Email Address",
"password": "Password",
@@ -42,7 +41,7 @@
"retry": "Retry",
"contactUs": "Contact Us",
"loading": "Loading. Please wait...",
"yourOrganizations": "Your Organizations",
"yourAccounts": "Your Accounts",
"continue": "Continue",
"skip": "Skip",
"signedInAs": "Signed in as",

View File

@@ -30,7 +30,6 @@
"primaryOwnerLabel": "Primary Owner",
"joinedAtLabel": "Joined at",
"invitedAtLabel": "Invited at",
"membersTabDescription": "Here you can manage the members of your team.",
"inviteMembersPageSubheading": "Invite members to your Team",
"createTeamModalHeading": "Create Team",
"createTeamModalDescription": "Create a new Team to manage your projects and members.",

View File

@@ -104,7 +104,7 @@ create type public.payment_status as ENUM(
/*
* Billing Provider
- We create the billing provider for the Supabase MakerKit. These providers are used to manage the billing provider for the accounts and organizations
- We create the billing provider for the Supabase MakerKit. These providers are used to manage the billing provider for the accounts
- The providers are 'stripe', 'lemon-squeezy', and 'paddle'.
- You can add more providers as needed.
*/
@@ -268,7 +268,7 @@ grant execute on function public.is_set(text) to authenticated;
/*
* -------------------------------------------------------
* Section: Accounts
* We create the schema for the accounts. Accounts are the top level entity in the Supabase MakerKit. They can be organizations or personal accounts.
* We create the schema for the accounts. Accounts are the top level entity in the Supabase MakerKit. They can be team or personal accounts.
* -------------------------------------------------------
*/
-- Accounts table
@@ -289,7 +289,7 @@ create table if not exists public.accounts(
primary key (id)
);
comment on table public.accounts is 'Accounts are the top level entity in the Supabase MakerKit. They can be organizations or personal accounts.';
comment on table public.accounts is 'Accounts are the top level entity in the Supabase MakerKit. They can be team or personal accounts.';
comment on column public.accounts.is_personal_account is 'Whether the account is a personal account or not';
@@ -299,7 +299,7 @@ comment on column public.accounts.slug is 'The slug of the account';
comment on column public.accounts.primary_owner_user_id is 'The primary owner of the account';
comment on column public.accounts.email is 'The email of the account. For organizations, this is the email of the organization (if any)';
comment on column public.accounts.email is 'The email of the account. For teams, this is the email of the team (if any)';
-- Enable RLS on the accounts table
alter table "public"."accounts" enable row level security;
@@ -774,41 +774,6 @@ create policy accounts_team_read on public.accounts
where
public.is_team_member(membership.account_id, id)));
/*
* -------------------------------------------------------
* Section: Account Roles
* We create the schema for the account roles. Account roles are the roles for an account.
* -------------------------------------------------------
*/
-- Account Roles table
create table public.account_roles(
id bigint generated by default as identity primary key,
account_id uuid references public.accounts(id) on delete cascade not null,
role varchar(50) references public.roles(name) not null,
unique (account_id, role)
);
comment on table public.account_roles is 'The roles for an account';
comment on column public.account_roles.account_id is 'The account the role is for';
comment on column public.account_roles.role is 'The role for the account';
-- Open up access to account roles
grant select, insert, update, delete on table public.account_roles to
authenticated, service_role;
-- Enable RLS on the account_roles table
alter table public.account_roles enable row level security;
-- RLS
-- SELECT: Users can read account roles of an account they are a
-- member of
create policy account_roles_read_self on public.account_roles
for select to authenticated
using (has_role_on_account(account_id));
/*
* -------------------------------------------------------
* Section: Role Permissions
@@ -948,7 +913,8 @@ create table if not exists public.invitations(
created_at timestamptz default current_timestamp not null,
updated_at timestamptz default current_timestamp not null,
expires_at timestamptz default current_timestamp + interval
'7 days' not null
'7 days' not null,
unique(email, account_id)
);
comment on table public.invitations is 'The invitations for an account';
@@ -961,6 +927,10 @@ comment on column public.invitations.role is 'The role for the invitation';
comment on column public.invitations.invite_token is 'The token for the invitation';
comment on column public.invitations.expires_at is 'The expiry date for the invitation';
comment on column public.invitations.email is 'The email of the user being invited';
-- Open up access to invitations table for authenticated users and
-- service_role
grant select, insert, update, delete on table public.invitations to
@@ -969,7 +939,7 @@ grant select, insert, update, delete on table public.invitations to
-- Enable RLS on the invitations table
alter table public.invitations enable row level security;
create or replace function check_organization_account()
create or replace function check_team_account()
returns trigger
as $$
begin
@@ -980,7 +950,7 @@ begin
public.accounts
where
id = new.account_id) then
raise exception 'Account must be an organization account';
raise exception 'Account must be an team account';
end if;
@@ -991,9 +961,9 @@ end;
$$
language plpgsql;
create trigger only_organization_accounts_check
create trigger only_team_accounts_check
before insert or update on public.invitations for each row
execute procedure check_organization_account();
execute procedure check_team_account();
-- RLS
-- SELECT: Users can read invitations to users of an account they
@@ -1108,6 +1078,8 @@ comment on column public.billing_customers.provider is 'The provider of the bill
comment on column public.billing_customers.customer_id is 'The customer ID for the billing customer';
comment on column public.billing_customers.email is 'The email of the billing customer';
-- Open up access to billing_customers table for authenticated users
-- and service_role
grant select, insert, update, delete on table
@@ -1172,6 +1144,11 @@ comment on column public.subscriptions.trial_starts_at is 'The start of the tria
comment on column public.subscriptions.trial_ends_at is 'The end of the trial period for the subscription';
comment on column public.subscriptions.active is 'Whether the subscription is active';
comment on column public.subscriptions.billing_customer_id is 'The billing customer ID for the subscription';
-- Open up access to subscriptions table for authenticated users and
-- service_role
grant select, insert, update, delete on table public.subscriptions to
@@ -1403,8 +1380,21 @@ create table if not exists public.orders(
updated_at timestamptz not null default current_timestamp
);
-- Open up access to subscription_items table for authenticated users
-- and service_role
comment on table public.orders is 'The one-time orders for an account';
comment on column public.orders.account_id is 'The account the order is for';
comment on column public.orders.billing_provider is 'The provider of the order';
comment on column public.orders.total_amount is 'The total amount for the order';
comment on column public.orders.currency is 'The currency for the order';
comment on column public.orders.status is 'The status of the order';
comment on column public.orders.billing_customer_id is 'The billing customer ID for the order';
-- Open up access to orders table for authenticated users and service_role
grant select on table public.orders to authenticated;
grant select, insert, update, delete on table public.orders to service_role;
@@ -1420,7 +1410,6 @@ create policy orders_read_self on public.orders
using ((account_id = auth.uid() and public.is_set('enable_account_billing'))
or (has_role_on_account(account_id) and public.is_set('enable_team_account_billing')));
/**
* -------------------------------------------------------
* Section: Order Items
@@ -1438,6 +1427,22 @@ create table if not exists public.order_items(
unique (order_id, product_id, variant_id)
);
comment on table public.order_items is 'The items in an order';
comment on column public.order_items.order_id is 'The order the item is for';
comment on column public.order_items.product_id is 'The product ID for the item';
comment on column public.order_items.variant_id is 'The variant ID for the item';
comment on column public.order_items.price_amount is 'The price amount for the item';
comment on column public.order_items.quantity is 'The quantity of the item';
comment on column public.order_items.created_at is 'The creation date of the item';
comment on column public.order_items.updated_at is 'The last update date of the item';
-- Open up access to order_items table for authenticated users and
-- service_role
grant select on table public.order_items to authenticated, service_role;
@@ -1737,7 +1742,7 @@ grant execute on function public.create_team_account(text) to
authenticated, service_role;
-- RLS
-- Authenticated users can create organization accounts
-- Authenticated users can create team accounts
create policy create_org_account on public.accounts
for insert to authenticated
with check (
@@ -1821,7 +1826,7 @@ where
grant select on public.user_accounts to authenticated, service_role;
--
-- Function: get the account workspace for an organization account
-- Function: get the account workspace for a team account
-- to load all the required data for the authenticated user within the account scope
create or replace function
public.team_account_workspace(account_slug text)
@@ -1875,6 +1880,7 @@ grant execute on function public.team_account_workspace(text)
to authenticated, service_role;
-- Functions: get account members
-- Function to get the members of an account by the account slug
create or replace function public.get_account_members(account_slug text)
returns table(
id uuid,
@@ -1919,6 +1925,7 @@ $$;
grant execute on function public.get_account_members(text) to
authenticated, service_role;
-- Function to get the account invitations by the account slug
create or replace function public.get_account_invitations(account_slug text)
returns table(
id integer,
@@ -1960,6 +1967,7 @@ language plpgsql;
grant execute on function public.get_account_invitations(text) to
authenticated, service_role;
-- Function to append invitations to an account
create or replace function
public.add_invitations_to_account(account_slug text, invitations
public.invitation[])

View File

@@ -1,3 +1,6 @@
-- WEBHOOKS SEED
-- PLEASE NOTE: These webhooks are only for development purposes. Leave them as they are or add new ones.
-- These webhooks are only for development purposes.
-- In production, you should manually create webhooks in the Supabase dashboard (or create a migration to do so).
-- We don't do it because you'll need to manually add your webhook URL and secret key.
@@ -35,4 +38,357 @@ execute function "supabase_functions"."http_request"(
'{"Content-Type":"application/json", "X-Supabase-Event-Signature":"WEBHOOKSECRET"}',
'{}',
'5000'
);
);
-- DATA SEED
-- This is a data dump for testing purposes. It should be used to seed the database with data for testing.
SET session_replication_role = replica;
pg_dump: warning: there are circular foreign-key constraints on this table:
pg_dump: detail: key
pg_dump: hint: You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.
pg_dump: hint: Consider using a full dump instead of a --data-only dump to avoid this problem.
--
-- PostgreSQL database dump
--
-- Dumped from database version 15.1 (Ubuntu 15.1-1.pgdg20.04+1)
-- Dumped by pg_dump version 15.5 (Ubuntu 15.5-1.pgdg20.04+1)
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- Data for Name: audit_log_entries; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
INSERT INTO "auth"."audit_log_entries" ("instance_id", "id", "payload", "created_at", "ip_address") VALUES
('00000000-0000-0000-0000-000000000000', '45d9f5dc-ae78-45aa-8dcf-7777639eafb3', '{"action":"user_confirmation_requested","actor_id":"31a03e74-1639-45b6-bfa7-77447f1a4762","actor_username":"test@makerkit.dev","actor_via_sso":false,"log_type":"user","traits":{"provider":"email"}}', '2024-04-20 08:20:34.463864+00', ''),
('00000000-0000-0000-0000-000000000000', 'a15ab66b-f291-427b-9f15-5364840b7cfb', '{"action":"user_signedup","actor_id":"31a03e74-1639-45b6-bfa7-77447f1a4762","actor_username":"test@makerkit.dev","actor_via_sso":false,"log_type":"team"}', '2024-04-20 08:20:38.163624+00', ''),
('00000000-0000-0000-0000-000000000000', 'c625f494-d041-44a9-8487-88f71cec3ca2', '{"action":"login","actor_id":"31a03e74-1639-45b6-bfa7-77447f1a4762","actor_username":"test@makerkit.dev","actor_via_sso":false,"log_type":"account","traits":{"provider_type":"email"}}', '2024-04-20 08:20:39.086702+00', ''),
('00000000-0000-0000-0000-000000000000', 'c579eedc-4089-4752-b5da-869d62b63c94', '{"action":"user_confirmation_requested","actor_id":"5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf","actor_username":"owner@makerkit.dev","actor_via_sso":false,"log_type":"user","traits":{"provider":"email"}}', '2024-04-20 08:36:27.638468+00', ''),
('00000000-0000-0000-0000-000000000000', '9f0349fd-fd4a-4a78-926d-3045c086055d', '{"action":"user_signedup","actor_id":"5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf","actor_username":"owner@makerkit.dev","actor_via_sso":false,"log_type":"team"}', '2024-04-20 08:36:37.517553+00', ''),
('00000000-0000-0000-0000-000000000000', '0a7673c0-8a4c-4984-a1f2-2b02d829fc85', '{"action":"login","actor_id":"5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf","actor_username":"owner@makerkit.dev","actor_via_sso":false,"log_type":"account","traits":{"provider_type":"email"}}', '2024-04-20 08:36:37.613295+00', ''),
('00000000-0000-0000-0000-000000000000', '4f1b635c-f00b-46a4-80de-1edb48250f8b', '{"action":"logout","actor_id":"5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf","actor_username":"owner@makerkit.dev","actor_via_sso":false,"log_type":"account"}', '2024-04-20 08:36:50.193801+00', ''),
('00000000-0000-0000-0000-000000000000', 'f0ec2dd0-b870-4822-a606-4208b7e17add', '{"action":"logout","actor_id":"31a03e74-1639-45b6-bfa7-77447f1a4762","actor_username":"test@makerkit.dev","actor_via_sso":false,"log_type":"account"}', '2024-04-20 08:37:13.584462+00', ''),
('00000000-0000-0000-0000-000000000000', '9b0174f5-c278-4e28-ba16-d3a845345abb', '{"action":"user_confirmation_requested","actor_id":"b73eb03e-fb7a-424d-84ff-18e2791ce0b4","actor_username":"custom@makerkit.dev","actor_via_sso":false,"log_type":"user","traits":{"provider":"email"}}', '2024-04-20 08:37:43.343197+00', ''),
('00000000-0000-0000-0000-000000000000', '26275d69-7031-45e3-a0b4-9d48dbeab82a', '{"action":"user_signedup","actor_id":"b73eb03e-fb7a-424d-84ff-18e2791ce0b4","actor_username":"custom@makerkit.dev","actor_via_sso":false,"log_type":"team"}', '2024-04-20 08:38:00.859507+00', ''),
('00000000-0000-0000-0000-000000000000', '498c38bf-318b-4653-b26b-d4e6daaca4f1', '{"action":"login","actor_id":"b73eb03e-fb7a-424d-84ff-18e2791ce0b4","actor_username":"custom@makerkit.dev","actor_via_sso":false,"log_type":"account","traits":{"provider_type":"email"}}', '2024-04-20 08:38:00.937756+00', ''),
('00000000-0000-0000-0000-000000000000', 'f53e4bd9-87d3-42f7-8b83-5fa9a9b914fe', '{"action":"login","actor_id":"31a03e74-1639-45b6-bfa7-77447f1a4762","actor_username":"test@makerkit.dev","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-04-20 08:40:08.032833+00', ''),
('00000000-0000-0000-0000-000000000000', '24e13912-f40c-457c-a380-ee079b904df8', '{"action":"user_confirmation_requested","actor_id":"6b83d656-e4ab-48e3-a062-c0c54a427368","actor_username":"member@makerkit.dev","actor_via_sso":false,"log_type":"user","traits":{"provider":"email"}}', '2024-04-20 08:41:08.68908+00', ''),
('00000000-0000-0000-0000-000000000000', '4341c565-778d-4ea1-8ccc-1b99674c1c40', '{"action":"user_signedup","actor_id":"6b83d656-e4ab-48e3-a062-c0c54a427368","actor_username":"member@makerkit.dev","actor_via_sso":false,"log_type":"team"}', '2024-04-20 08:41:15.376428+00', ''),
('00000000-0000-0000-0000-000000000000', 'bb38e0c7-4cb1-4eea-8a06-5ee4b34b261a', '{"action":"login","actor_id":"6b83d656-e4ab-48e3-a062-c0c54a427368","actor_username":"member@makerkit.dev","actor_via_sso":false,"log_type":"account","traits":{"provider_type":"email"}}', '2024-04-20 08:41:15.484323+00', '');
--
-- Data for Name: flow_state; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
--
-- Data for Name: users; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
INSERT INTO "auth"."users" ("instance_id", "id", "aud", "role", "email", "encrypted_password", "email_confirmed_at", "invited_at", "confirmation_token", "confirmation_sent_at", "recovery_token", "recovery_sent_at", "email_change_token_new", "email_change", "email_change_sent_at", "last_sign_in_at", "raw_app_meta_data", "raw_user_meta_data", "is_super_admin", "created_at", "updated_at", "phone", "phone_confirmed_at", "phone_change", "phone_change_token", "phone_change_sent_at", "email_change_token_current", "email_change_confirm_status", "banned_until", "reauthentication_token", "reauthentication_sent_at", "is_sso_user", "deleted_at", "is_anonymous") VALUES
('00000000-0000-0000-0000-000000000000', 'b73eb03e-fb7a-424d-84ff-18e2791ce0b4', 'authenticated', 'authenticated', 'custom@makerkit.dev', '$2a$10$b3ZPpU6TU3or30QzrXnZDuATPAx2pPq3JW.sNaneVY3aafMSuR4yi', '2024-04-20 08:38:00.860548+00', NULL, '', '2024-04-20 08:37:43.343769+00', '', NULL, '', '', NULL, '2024-04-20 08:38:00.93864+00', '{"provider": "email", "providers": ["email"]}', '{"sub": "b73eb03e-fb7a-424d-84ff-18e2791ce0b4", "email": "custom@makerkit.dev", "email_verified": false, "phone_verified": false}', NULL, '2024-04-20 08:37:43.3385+00', '2024-04-20 08:38:00.942809+00', NULL, NULL, '', '', NULL, '', 0, NULL, '', NULL, false, NULL, false),
('00000000-0000-0000-0000-000000000000', '31a03e74-1639-45b6-bfa7-77447f1a4762', 'authenticated', 'authenticated', 'test@makerkit.dev', '$2a$10$uC911UKLmGbkp2Di7K2UfO9QYUQFz5et.gPpjhxWEob1jeXkLrNZu', '2024-04-20 08:20:38.165331+00', NULL, '', '2024-04-20 08:20:34.464746+00', '', NULL, '', '', NULL, '2024-04-20 08:40:08.033665+00', '{"provider": "email", "providers": ["email"]}', '{"sub": "31a03e74-1639-45b6-bfa7-77447f1a4762", "email": "test@makerkit.dev", "email_verified": false, "phone_verified": false}', NULL, '2024-04-20 08:20:34.459113+00', '2024-04-20 08:40:08.035046+00', NULL, NULL, '', '', NULL, '', 0, NULL, '', NULL, false, NULL, false),
('00000000-0000-0000-0000-000000000000', '5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf', 'authenticated', 'authenticated', 'owner@makerkit.dev', '$2a$10$D6arGxWJShy8q4RTW18z7eW0vEm2hOxEUovUCj5f3NblyHfamm5/a', '2024-04-20 08:36:37.517993+00', NULL, '', '2024-04-20 08:36:27.639648+00', '', NULL, '', '', NULL, '2024-04-20 08:36:37.614337+00', '{"provider": "email", "providers": ["email"]}', '{"sub": "5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf", "email": "owner@makerkit.dev", "email_verified": false, "phone_verified": false}', NULL, '2024-04-20 08:36:27.630379+00', '2024-04-20 08:36:37.617955+00', NULL, NULL, '', '', NULL, '', 0, NULL, '', NULL, false, NULL, false),
('00000000-0000-0000-0000-000000000000', '6b83d656-e4ab-48e3-a062-c0c54a427368', 'authenticated', 'authenticated', 'member@makerkit.dev', '$2a$10$6h/x.AX.6zzphTfDXIJMzuYx13hIYEi/Iods9FXH19J2VxhsLycfa', '2024-04-20 08:41:15.376778+00', NULL, '', '2024-04-20 08:41:08.689674+00', '', NULL, '', '', NULL, '2024-04-20 08:41:15.484606+00', '{"provider": "email", "providers": ["email"]}', '{"sub": "6b83d656-e4ab-48e3-a062-c0c54a427368", "email": "member@makerkit.dev", "email_verified": false, "phone_verified": false}', NULL, '2024-04-20 08:41:08.683395+00', '2024-04-20 08:41:15.485494+00', NULL, NULL, '', '', NULL, '', 0, NULL, '', NULL, false, NULL, false);
--
-- Data for Name: identities; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
INSERT INTO "auth"."identities" ("provider_id", "user_id", "identity_data", "provider", "last_sign_in_at", "created_at", "updated_at", "id") VALUES
('31a03e74-1639-45b6-bfa7-77447f1a4762', '31a03e74-1639-45b6-bfa7-77447f1a4762', '{"sub": "31a03e74-1639-45b6-bfa7-77447f1a4762", "email": "test@makerkit.dev", "email_verified": false, "phone_verified": false}', 'email', '2024-04-20 08:20:34.46275+00', '2024-04-20 08:20:34.462773+00', '2024-04-20 08:20:34.462773+00', '9bb58bad-24a4-41a8-9742-1b5b4e2d8abd'),
('5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf', '5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf', '{"sub": "5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf", "email": "owner@makerkit.dev", "email_verified": false, "phone_verified": false}', 'email', '2024-04-20 08:36:27.637388+00', '2024-04-20 08:36:27.637409+00', '2024-04-20 08:36:27.637409+00', '090598a1-ebba-4879-bbe3-38d517d5066f'),
('b73eb03e-fb7a-424d-84ff-18e2791ce0b4', 'b73eb03e-fb7a-424d-84ff-18e2791ce0b4', '{"sub": "b73eb03e-fb7a-424d-84ff-18e2791ce0b4", "email": "custom@makerkit.dev", "email_verified": false, "phone_verified": false}', 'email', '2024-04-20 08:37:43.342194+00', '2024-04-20 08:37:43.342218+00', '2024-04-20 08:37:43.342218+00', '4392e228-a6d8-4295-a7d6-baed50c33e7c'),
('6b83d656-e4ab-48e3-a062-c0c54a427368', '6b83d656-e4ab-48e3-a062-c0c54a427368', '{"sub": "6b83d656-e4ab-48e3-a062-c0c54a427368", "email": "member@makerkit.dev", "email_verified": false, "phone_verified": false}', 'email', '2024-04-20 08:41:08.687948+00', '2024-04-20 08:41:08.687982+00', '2024-04-20 08:41:08.687982+00', 'd122aca5-4f29-43f0-b1b1-940b000638db');
--
-- Data for Name: instances; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
--
-- Data for Name: sessions; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
INSERT INTO "auth"."sessions" ("id", "user_id", "created_at", "updated_at", "factor_id", "aal", "not_after", "refreshed_at", "user_agent", "ip", "tag") VALUES
('6110bfeb-31e9-4c70-9c54-d723abd52048', 'b73eb03e-fb7a-424d-84ff-18e2791ce0b4', '2024-04-20 08:38:00.938815+00', '2024-04-20 08:38:00.938815+00', NULL, 'aal1', NULL, NULL, 'node', '192.168.228.1', NULL),
('d5086cc6-9897-47e0-874b-7f8f11649560', '31a03e74-1639-45b6-bfa7-77447f1a4762', '2024-04-20 08:40:08.033701+00', '2024-04-20 08:40:08.033701+00', NULL, 'aal1', NULL, NULL, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', '192.168.228.1', NULL),
('469be37b-b21f-46aa-b30b-52f828b1baad', '6b83d656-e4ab-48e3-a062-c0c54a427368', '2024-04-20 08:41:15.484635+00', '2024-04-20 08:41:15.484635+00', NULL, 'aal1', NULL, NULL, 'node', '192.168.228.1', NULL);
--
-- Data for Name: mfa_amr_claims; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
INSERT INTO "auth"."mfa_amr_claims" ("session_id", "created_at", "updated_at", "authentication_method", "id") VALUES
('6110bfeb-31e9-4c70-9c54-d723abd52048', '2024-04-20 08:38:00.943514+00', '2024-04-20 08:38:00.943514+00', 'email/signup', '42337df0-b3d0-42f5-bff5-3740ccad191b'),
('d5086cc6-9897-47e0-874b-7f8f11649560', '2024-04-20 08:40:08.035464+00', '2024-04-20 08:40:08.035464+00', 'password', 'e0d54b55-9813-44b5-b502-06b081c3a44b'),
('469be37b-b21f-46aa-b30b-52f828b1baad', '2024-04-20 08:41:15.485666+00', '2024-04-20 08:41:15.485666+00', 'email/signup', '55704b9a-6a31-48e6-ae2b-662f6b7ce302');
--
-- Data for Name: mfa_factors; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
--
-- Data for Name: mfa_challenges; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
--
-- Data for Name: refresh_tokens; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
INSERT INTO "auth"."refresh_tokens" ("instance_id", "id", "token", "user_id", "revoked", "created_at", "updated_at", "parent", "session_id") VALUES
('00000000-0000-0000-0000-000000000000', 3, 'lRWBgOYDQHq2GfqAc5iPpw', 'b73eb03e-fb7a-424d-84ff-18e2791ce0b4', false, '2024-04-20 08:38:00.940523+00', '2024-04-20 08:38:00.940523+00', NULL, '6110bfeb-31e9-4c70-9c54-d723abd52048'),
('00000000-0000-0000-0000-000000000000', 4, 'XuRjZ1Ipdh8Eb19lPRUJhw', '31a03e74-1639-45b6-bfa7-77447f1a4762', false, '2024-04-20 08:40:08.03433+00', '2024-04-20 08:40:08.03433+00', NULL, 'd5086cc6-9897-47e0-874b-7f8f11649560'),
('00000000-0000-0000-0000-000000000000', 5, 'iQ0e1JiLv3R29gkHZYZggw', '6b83d656-e4ab-48e3-a062-c0c54a427368', false, '2024-04-20 08:41:15.484992+00', '2024-04-20 08:41:15.484992+00', NULL, '469be37b-b21f-46aa-b30b-52f828b1baad');
--
-- Data for Name: sso_providers; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
--
-- Data for Name: saml_providers; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
--
-- Data for Name: saml_relay_states; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
--
-- Data for Name: sso_domains; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
--
--
-- Data for Name: key; Type: TABLE DATA; Schema: pgsodium; Owner: supabase_admin
--
--
-- Data for Name: accounts; Type: TABLE DATA; Schema: public; Owner: postgres
--
INSERT INTO "public"."accounts" ("id", "primary_owner_user_id", "name", "slug", "email", "is_personal_account", "updated_at", "created_at", "created_by", "updated_by", "picture_url", "public_data") VALUES
('31a03e74-1639-45b6-bfa7-77447f1a4762', '31a03e74-1639-45b6-bfa7-77447f1a4762', 'test', NULL, 'test@makerkit.dev', true, NULL, NULL, NULL, NULL, NULL, '{}'),
('5deaa894-2094-4da3-b4fd-1fada0809d1c', '31a03e74-1639-45b6-bfa7-77447f1a4762', 'Makerkit', 'makerkit', NULL, false, NULL, NULL, NULL, NULL, NULL, '{}'),
('5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf', '5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf', 'owner', NULL, 'owner@makerkit.dev', true, NULL, NULL, NULL, NULL, NULL, '{}'),
('b73eb03e-fb7a-424d-84ff-18e2791ce0b4', 'b73eb03e-fb7a-424d-84ff-18e2791ce0b4', 'custom', NULL, 'custom@makerkit.dev', true, NULL, NULL, NULL, NULL, NULL, '{}'),
('6b83d656-e4ab-48e3-a062-c0c54a427368', '6b83d656-e4ab-48e3-a062-c0c54a427368', 'member', NULL, 'member@makerkit.dev', true, NULL, NULL, NULL, NULL, NULL, '{}');
--
-- Data for Name: roles; Type: TABLE DATA; Schema: public; Owner: postgres
--
INSERT INTO "public"."roles" ("name", "hierarchy_level", "account_id") VALUES
('owner', 1, NULL),
('member', 2, NULL),
('custom-role', 4, '5deaa894-2094-4da3-b4fd-1fada0809d1c');
--
-- Data for Name: accounts_memberships; Type: TABLE DATA; Schema: public; Owner: postgres
--
INSERT INTO "public"."accounts_memberships" ("user_id", "account_id", "account_role", "created_at", "updated_at", "created_by", "updated_by") VALUES
('31a03e74-1639-45b6-bfa7-77447f1a4762', '5deaa894-2094-4da3-b4fd-1fada0809d1c', 'owner', '2024-04-20 08:21:16.802867+00', '2024-04-20 08:21:16.802867+00', NULL, NULL),
('5c064f1b-78ee-4e1c-ac3b-e99aa97c99bf', '5deaa894-2094-4da3-b4fd-1fada0809d1c', 'owner', '2024-04-20 08:36:44.21028+00', '2024-04-20 08:36:44.21028+00', NULL, NULL),
('b73eb03e-fb7a-424d-84ff-18e2791ce0b4', '5deaa894-2094-4da3-b4fd-1fada0809d1c', 'custom-role', '2024-04-20 08:38:02.50993+00', '2024-04-20 08:38:02.50993+00', NULL, NULL),
('6b83d656-e4ab-48e3-a062-c0c54a427368', '5deaa894-2094-4da3-b4fd-1fada0809d1c', 'member', '2024-04-20 08:41:17.833709+00', '2024-04-20 08:41:17.833709+00', NULL, NULL);
--
-- Data for Name: billing_customers; Type: TABLE DATA; Schema: public; Owner: postgres
--
--
-- Data for Name: config; Type: TABLE DATA; Schema: public; Owner: postgres
--
INSERT INTO "public"."config" ("enable_team_accounts", "enable_account_billing", "enable_team_account_billing", "billing_provider") VALUES
(true, true, true, 'stripe');
--
-- Data for Name: invitations; Type: TABLE DATA; Schema: public; Owner: postgres
--
--
-- Data for Name: orders; Type: TABLE DATA; Schema: public; Owner: postgres
--
--
-- Data for Name: order_items; Type: TABLE DATA; Schema: public; Owner: postgres
--
--
-- Data for Name: role_permissions; Type: TABLE DATA; Schema: public; Owner: postgres
--
INSERT INTO "public"."role_permissions" ("id", "role", "permission") VALUES
(1, 'owner', 'roles.manage'),
(2, 'owner', 'billing.manage'),
(3, 'owner', 'settings.manage'),
(4, 'owner', 'members.manage'),
(5, 'owner', 'invites.manage'),
(6, 'member', 'settings.manage'),
(7, 'member', 'invites.manage');
--
-- Data for Name: subscriptions; Type: TABLE DATA; Schema: public; Owner: postgres
--
--
-- Data for Name: subscription_items; Type: TABLE DATA; Schema: public; Owner: postgres
--
--
-- Data for Name: buckets; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
--
INSERT INTO "storage"."buckets" ("id", "name", "owner", "created_at", "updated_at", "public", "avif_autodetection", "file_size_limit", "allowed_mime_types", "owner_id") VALUES
('account_image', 'account_image', NULL, '2024-04-20 08:18:41.364926+00', '2024-04-20 08:18:41.364926+00', true, false, NULL, NULL, NULL);
--
-- Data for Name: objects; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
--
--
-- Data for Name: s3_multipart_uploads; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
--
--
-- Data for Name: s3_multipart_uploads_parts; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
--
--
-- Data for Name: hooks; Type: TABLE DATA; Schema: supabase_functions; Owner: supabase_functions_admin
--
INSERT INTO "supabase_functions"."hooks" ("id", "hook_table_id", "hook_name", "created_at", "request_id") VALUES
(1, 17811, 'invitations_insert', '2024-04-20 08:22:15.403223+00', 1),
(2, 17811, 'invitations_insert', '2024-04-20 08:22:15.403223+00', 2),
(3, 17811, 'invitations_insert', '2024-04-20 08:22:15.403223+00', 3),
(4, 17811, 'invitations_insert', '2024-04-20 08:25:04.593848+00', 4),
(5, 17811, 'invitations_insert', '2024-04-20 08:25:04.593848+00', 5),
(6, 17811, 'invitations_insert', '2024-04-20 08:25:04.593848+00', 6),
(7, 17811, 'invitations_insert', '2024-04-20 08:26:43.163367+00', 7),
(8, 17811, 'invitations_insert', '2024-04-20 08:26:43.163367+00', 8),
(9, 17811, 'invitations_insert', '2024-04-20 08:26:43.163367+00', 9),
(10, 17811, 'invitations_insert', '2024-04-20 08:28:46.753609+00', 10),
(11, 17811, 'invitations_insert', '2024-04-20 08:28:46.753609+00', 11),
(12, 17811, 'invitations_insert', '2024-04-20 08:28:46.753609+00', 12),
(13, 17811, 'invitations_insert', '2024-04-20 08:30:12.356719+00', 13),
(14, 17811, 'invitations_insert', '2024-04-20 08:33:11.210097+00', 14),
(15, 17811, 'invitations_insert', '2024-04-20 08:33:52.113026+00', 15),
(16, 17811, 'invitations_insert', '2024-04-20 08:35:21.557382+00', 16),
(17, 17811, 'invitations_insert', '2024-04-20 08:35:21.557382+00', 17),
(18, 17811, 'invitations_insert', '2024-04-20 08:35:21.557382+00', 18),
(19, 17811, 'invitations_insert', '2024-04-20 08:40:20.99569+00', 19);
--
-- Data for Name: secrets; Type: TABLE DATA; Schema: vault; Owner: supabase_admin
--
--
-- Name: refresh_tokens_id_seq; Type: SEQUENCE SET; Schema: auth; Owner: supabase_auth_admin
--
SELECT pg_catalog.setval('"auth"."refresh_tokens_id_seq"', 5, true);
--
-- Name: key_key_id_seq; Type: SEQUENCE SET; Schema: pgsodium; Owner: supabase_admin
--
SELECT pg_catalog.setval('"pgsodium"."key_key_id_seq"', 1, false);
--
-- Name: billing_customers_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
SELECT pg_catalog.setval('"public"."billing_customers_id_seq"', 1, false);
--
-- Name: invitations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
SELECT pg_catalog.setval('"public"."invitations_id_seq"', 19, true);
--
-- Name: role_permissions_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
SELECT pg_catalog.setval('"public"."role_permissions_id_seq"', 7, true);
--
-- Name: hooks_id_seq; Type: SEQUENCE SET; Schema: supabase_functions; Owner: supabase_functions_admin
--
SELECT pg_catalog.setval('"supabase_functions"."hooks_id_seq"', 19, true);
--
-- PostgreSQL database dump complete
--
RESET ALL;

View File

@@ -1,9 +1,9 @@
create schema if not exists makerkit;
-- anon, authenticated, and service_role should have access to tests schema
-- anon, authenticated, and service_role should have access to makerkit schema
grant USAGE on schema makerkit to anon, authenticated, service_role;
-- Don't allow public to execute any functions in the tests schema
-- Don't allow public to execute any functions in the makerkit schema
alter default PRIVILEGES in schema makerkit revoke execute on FUNCTIONS from public;
-- Grant execute to anon, authenticated, and service_role for testing purposes
@@ -29,6 +29,57 @@ end;
$$ language PLPGSQL;
create or replace function makerkit.get_account_id_by_slug(
account_slug text
)
returns uuid
as $$
begin
return
(select
id
from
accounts
where
slug = account_slug);
end;
$$ language PLPGSQL;
create or replace function makerkit.get_user_id(
user_email text
)
returns uuid
as $$
begin
return
(select
primary_owner_user_id
from
accounts
where
email = user_email);
end;
$$ language PLPGSQL;
begin;
select plan(1);
select is_empty($$
select
*
from
makerkit.get_account_by_slug('test') $$,
'get_account_by_slug should return an empty set when the account does not exist'
);
select
*
from

View File

@@ -9,13 +9,92 @@ select tests.create_supabase_user('test1', 'test1@test.com');
select tests.create_supabase_user('test2');
-- Create an organization account
-- Create an team account
select tests.authenticate_as('test1');
select public.create_account('Test');
select public.create_team_account('Test');
-- the owner account has permissions to manage members
select row_eq(
$$ select public.has_permission(
auth.uid(), makerkit.get_account_id_by_slug('test'), 'members.manage'::app_permissions) $$,
row(true::boolean),
'The owner of the team account should have the members.manage permission'
);
-- the owner account has permissions to manage billing
select row_eq(
$$ select public.has_permission(
auth.uid(), makerkit.get_account_id_by_slug('test'), 'billing.manage'::app_permissions) $$,
row(true::boolean),
'The owner of the team account should have the billing.manage permission'
);
-- Foreigner should not have permissions to manage members
select tests.authenticate_as('test2');
select row_eq(
$$ select public.has_permission(
auth.uid(), makerkit.get_account_id_by_slug('test'), 'members.manage'::app_permissions) $$,
row(false::boolean),
'Foreigners should not have the members.manage permission'
);
-- Custom roles
-- New roles created for the app
set local role service_role;
-- the name should be unique
select throws_ok(
$$ insert into public.roles (name, hierarchy_level) values ('owner', 4) $$,
'duplicate key value violates unique constraint "roles_pkey"'
);
-- the hierarchy level should be unique
select throws_ok(
$$ insert into public.roles (name, hierarchy_level) values ('custom-role-2', 1) $$,
'duplicate key value violates unique constraint "idx_unique_hierarchy_per_account"'
);
-- Custom Account Role
-- Roles created specifically for the account
set local role service_role;
-- the names should be unique
select throws_ok(
$$ insert into public.roles (name, hierarchy_level, account_id) values ('owner', 1, makerkit.get_account_id_by_slug('test')) $$,
'duplicate key value violates unique constraint "roles_pkey"'
);
-- update user role to custom role
update public.accounts_memberships
set account_role = 'custom-role'
where account_id = makerkit.get_account_id_by_slug('test')
and user_id = makerkit.get_user_id('test1@test.com');
select tests.authenticate_as('test1');
-- the custom role does not have permissions to manage billing
select row_eq(
$$ select public.has_permission(
auth.uid(), makerkit.get_account_id_by_slug('test'), 'billing.manage'::app_permissions) $$,
row(false::boolean),
'The custom role should not have the billing.manage permission'
);
-- the custom role can manage members
select row_eq(
$$ select public.has_permission(
auth.uid(), makerkit.get_account_id_by_slug('test'), 'members.manage'::app_permissions) $$,
row(true::boolean),
'The custom role should have the members.manage permission'
);
select * from finish();
ROLLBACK;
rollback;

View File

@@ -9,31 +9,31 @@ select tests.create_supabase_user('test1', 'test1@test.com');
select tests.create_supabase_user('test2');
-- Create an organization account
-- Create an team account
select tests.authenticate_as('test1');
select public.create_account('Test');
select public.create_account('Test');
select public.create_account('Test');
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' $$,
row('test'::text),
'The first organization account should automatically create a slug named "test"'
'The first team account should automatically create a slug named "test"'
);
select row_eq(
$$ select slug from public.accounts where name = 'Test' and slug = 'test-1' $$,
row('test-1'::text),
'The second organization account should automatically create a slug named "test-1"'
'The second team account should automatically create a slug named "test-1"'
);
select row_eq(
$$ select slug from public.accounts where name = 'Test' and slug = 'test-2' $$,
row('test-2'::text),
'The third organization account should automatically create a slug named "test-2"'
'The third team account should automatically create a slug named "test-2"'
);
-- Should automatically update the slug if the name is updated
@@ -42,7 +42,7 @@ update public.accounts set name = 'Test 4' where slug = 'test-2';
select row_eq(
$$ select slug from public.accounts where name = 'Test 4' $$,
row('test-4'::text),
'Updating the name of an organization account should update the slug'
'Updating the name of a team account should update the slug'
);
-- Should fail if the slug is updated to an existing slug

View File

@@ -12,12 +12,12 @@ select
select
tests.create_supabase_user('test2');
-- Create an organization account
-- Create an team account
select
tests.authenticate_as('test1');
select
public.create_account('Test');
public.create_team_account('Test');
select
row_eq($$
@@ -25,9 +25,9 @@ select
primary_owner_user_id, is_personal_account, slug, name from
makerkit.get_account_by_slug('test') $$, row
(tests.get_supabase_uid('test1'), false, 'test'::text,
'Test'::varchar), 'Users can create an organization account');
'Test'::varchar), 'Users can create a team account');
-- Should be the primary owner of the organization account by default
-- Should be the primary owner of the team account by default
select
row_eq($$
select
@@ -40,17 +40,17 @@ select
where
slug = 'test')
and user_id = tests.get_supabase_uid('test1') $$, row
('owner'::public.account_role), 'The primary owner should have the owner role for the organization account');
('owner'::varchar), 'The primary owner should have the owner role for the team account');
-- Should be able to see the organization account
-- Should be able to see the team account
select
isnt_empty($$
select
* from public.accounts
where
primary_owner_user_id = tests.get_supabase_uid('test1') $$, 'The primary owner should be able to see the organization account');
primary_owner_user_id = tests.get_supabase_uid('test1') $$, 'The primary owner should be able to see the team account');
-- Others should not be able to see the organization account
-- Others should not be able to see the team account
select
tests.authenticate_as('test2');
@@ -59,16 +59,16 @@ select
select
* from public.accounts
where
primary_owner_user_id = tests.get_supabase_uid('test1') $$, 'Other users should not be able to see the organization account');
primary_owner_user_id = tests.get_supabase_uid('test1') $$, 'Other users should not be able to see the team account');
-- should not have any role for the organization account
-- should not have any role for the team account
select
is (public.has_role_on_account((
select
id
from makerkit.get_account_by_slug('test'))),
false,
'Foreign users should not have any role for the organization account');
'Foreign users should not have any role for the team account');
select
*

View File

@@ -16,7 +16,7 @@ SELECT schema_privs_are('public', 'anon', Array [NULL], 'Anon should not have ac
-- set the role to anonymous for verifying access tests
set role anon;
select throws_ok('select public.get_config()');
select throws_ok('select public.is_set(''enable_organization_accounts'')');
select throws_ok('select public.is_set(''enable_team_accounts'')');
-- set the role to the service_role for testing access
set role service_role;
@@ -26,7 +26,7 @@ select ok(public.get_config() is not null),
-- set the role to authenticated for tests
set role authenticated;
select ok(public.get_config() is not null), 'Makerkit get_config should be accessible to authenticated users';
select ok(public.is_set('enable_organization_accounts')),
select ok(public.is_set('enable_team_accounts')),
'Makerkit is_set should be accessible to authenticated users';
select isnt_empty('select * from public.config', 'authenticated users should have access to Makerkit config');

View File

@@ -162,6 +162,10 @@ function ActionsDropdown({
const [isUpdatingRole, setIsUpdatingRole] = useState(false);
const [iRenewingInvite, setIsRenewingInvite] = useState(false);
if (!permissions.canUpdateInvitation && !permissions.canRemoveInvitation) {
return null;
}
return (
<>
<DropdownMenu>

View File

@@ -5,7 +5,7 @@ import { Trans } from '@kit/ui/trans';
type Role = string;
const roleClassNameBuilder = cva('font-medium capitalize', {
const roleClassNameBuilder = cva('font-medium capitalize shadow-none', {
variants: {
role: {
owner: '',

View File

@@ -116,13 +116,16 @@ export class AccountInvitationsWebhookService {
logger.info(ctx, 'Invitation email successfully sent!');
})
.catch((error) => {
logger.warn({ error, ...ctx }, 'Failed to send invitation email');
console.error(error);
logger.error({ error, ...ctx }, 'Failed to send invitation email');
});
return {
success: true,
};
} catch (error) {
console.error(error);
logger.warn({ error, ...ctx }, 'Failed to invite user to team');
return {

View File

@@ -9,30 +9,41 @@ const MAILER_PROVIDER = z
* @description Get the mailer based on the environment variable.
*/
export async function getMailer() {
switch (process.env.MAILER_PROVIDER as typeof MAILER_PROVIDER) {
case 'nodemailer': {
if (process.env.NEXT_RUNTIME !== 'edge') {
const { Nodemailer } = await import('./impl/nodemailer');
switch (MAILER_PROVIDER) {
case 'nodemailer':
return getNodemailer();
return new Nodemailer();
} else {
throw new Error('Nodemailer is not available on the edge runtime side');
}
}
case 'cloudflare':
return getCloudflareMailer();
case 'cloudflare': {
const { CloudflareMailer } = await import('./impl/cloudflare');
return new CloudflareMailer();
}
case 'resend': {
const { ResendMailer } = await import('./impl/resend');
return new ResendMailer();
}
case 'resend':
return getResendMailer();
default:
throw new Error(`Invalid mailer: ${MAILER_PROVIDER as string}`);
}
}
async function getNodemailer() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { Nodemailer } = await import('./impl/nodemailer');
return new Nodemailer();
} else {
throw new Error(
'Nodemailer is not available on the edge runtime. Please use another mailer.',
);
}
}
async function getCloudflareMailer() {
const { CloudflareMailer } = await import('./impl/cloudflare');
return new CloudflareMailer();
}
async function getResendMailer() {
const { ResendMailer } = await import('./impl/resend');
return new ResendMailer();
}