From efd27aa7de0aaa8871e640132c6824c51fdf8177 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Sat, 20 Apr 2024 16:53:54 +0800 Subject: [PATCH] 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. --- README.md | 5 + apps/web/.env | 5 +- apps/web/.env.development | 5 +- .../account-layout-mobile-navigation.tsx | 8 +- .../server/team-account-workspace.loader.ts | 8 +- apps/web/public/locales/en/account.json | 2 +- apps/web/public/locales/en/auth.json | 3 - apps/web/public/locales/en/billing.json | 4 +- apps/web/public/locales/en/common.json | 7 +- apps/web/public/locales/en/teams.json | 1 - .../migrations/20221215192558_schema.sql | 106 +++--- apps/web/supabase/seed.sql | 358 +++++++++++++++++- .../tests/database/00000-makerkit-helpers.sql | 55 ++- .../database/account-permissions.test.sql | 85 ++++- .../tests/database/account-slug.test.sql | 16 +- ...test.sql => create-team-accounts.test.sql} | 22 +- .../supabase/tests/database/schema.test.sql | 4 +- .../invitations/account-invitations-table.tsx | 4 + .../src/components/members/role-badge.tsx | 2 +- .../account-invitations-webhook.service.ts | 5 +- packages/mailers/src/index.ts | 51 ++- 21 files changed, 634 insertions(+), 122 deletions(-) rename apps/web/supabase/tests/database/{create-organization-accounts.test.sql => create-team-accounts.test.sql} (64%) diff --git a/README.md b/README.md index d9cdae828..4b7338186 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/apps/web/.env b/apps/web/.env index 3ca8a759a..c11631f5e 100644 --- a/apps/web/.env +++ b/apps/web/.env @@ -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 \ No newline at end of file +NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION=true \ No newline at end of file diff --git a/apps/web/.env.development b/apps/web/.env.development index df6d86794..99bb9a23b 100644 --- a/apps/web/.env.development +++ b/apps/web/.env.development @@ -16,4 +16,7 @@ EMAIL_USER=user EMAIL_PASSWORD=password # STRIPE -NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= \ No newline at end of file +NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= + +# MAILER +MAILER_PROVIDER=nodemailer \ No newline at end of file diff --git a/apps/web/app/(dashboard)/home/[account]/_components/account-layout-mobile-navigation.tsx b/apps/web/app/(dashboard)/home/[account]/_components/account-layout-mobile-navigation.tsx index 38e08d852..697d69564 100644 --- a/apps/web/app/(dashboard)/home/[account]/_components/account-layout-mobile-navigation.tsx +++ b/apps/web/app/(dashboard)/home/[account]/_components/account-layout-mobile-navigation.tsx @@ -76,7 +76,7 @@ export const AccountLayoutMobileNavigation = ( - + {Links} @@ -130,7 +130,7 @@ function SignOutDropdownItem( ); } -function OrganizationsModal() { +function TeamAccountsModal() { const router = useRouter(); return ( @@ -143,7 +143,7 @@ function OrganizationsModal() { - + @@ -151,7 +151,7 @@ function OrganizationsModal() { - + diff --git a/apps/web/app/(dashboard)/home/[account]/_lib/server/team-account-workspace.loader.ts b/apps/web/app/(dashboard)/home/[account]/_lib/server/team-account-workspace.loader.ts index 03977bcc0..47902d92c 100644 --- a/apps/web/app/(dashboard)/home/[account]/_lib/server/team-account-workspace.loader.ts +++ b/apps/web/app/(dashboard)/home/[account]/_lib/server/team-account-workspace.loader.ts @@ -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); diff --git a/apps/web/public/locales/en/account.json b/apps/web/public/locales/en/account.json index 74ef254fc..fe1809d28 100644 --- a/apps/web/public/locales/en/account.json +++ b/apps/web/public/locales/en/account.json @@ -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", diff --git a/apps/web/public/locales/en/auth.json b/apps/web/public/locales/en/auth.json index 07b1b169c..783e4757e 100644 --- a/apps/web/public/locales/en/auth.json +++ b/apps/web/public/locales/en/auth.json @@ -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 {{organization}}", "signUpToAcceptInvite": "Please sign in/up to accept the invite", "clickToAcceptAs": "Click the button below to accept the invite with as {{email}}", "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 {{name}}. Please Wait...", "signInWithProvider": "Sign in with {{provider}}", "signInWithPhoneNumber": "Sign in with Phone Number", "signInWithEmail": "Sign in with Email", diff --git a/apps/web/public/locales/en/billing.json b/apps/web/public/locales/en/billing.json index e2d087566..45832f083 100644 --- a/apps/web/public/locales/en/billing.json +++ b/apps/web/public/locales/en/billing.json @@ -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", diff --git a/apps/web/public/locales/en/common.json b/apps/web/public/locales/en/common.json index 8380f8313..139ef16fb 100644 --- a/apps/web/public/locales/en/common.json +++ b/apps/web/public/locales/en/common.json @@ -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", diff --git a/apps/web/public/locales/en/teams.json b/apps/web/public/locales/en/teams.json index 2b348bbf8..079d7b2cb 100644 --- a/apps/web/public/locales/en/teams.json +++ b/apps/web/public/locales/en/teams.json @@ -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.", diff --git a/apps/web/supabase/migrations/20221215192558_schema.sql b/apps/web/supabase/migrations/20221215192558_schema.sql index 29ad8e0cd..53a04f2d9 100644 --- a/apps/web/supabase/migrations/20221215192558_schema.sql +++ b/apps/web/supabase/migrations/20221215192558_schema.sql @@ -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[]) diff --git a/apps/web/supabase/seed.sql b/apps/web/supabase/seed.sql index f7eef2305..ec4a06ec6 100644 --- a/apps/web/supabase/seed.sql +++ b/apps/web/supabase/seed.sql @@ -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' -); \ No newline at end of file +); + + +-- 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; diff --git a/apps/web/supabase/tests/database/00000-makerkit-helpers.sql b/apps/web/supabase/tests/database/00000-makerkit-helpers.sql index 8258c5199..b582a41bf 100644 --- a/apps/web/supabase/tests/database/00000-makerkit-helpers.sql +++ b/apps/web/supabase/tests/database/00000-makerkit-helpers.sql @@ -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 diff --git a/apps/web/supabase/tests/database/account-permissions.test.sql b/apps/web/supabase/tests/database/account-permissions.test.sql index 69f1550b2..d8de8fd24 100644 --- a/apps/web/supabase/tests/database/account-permissions.test.sql +++ b/apps/web/supabase/tests/database/account-permissions.test.sql @@ -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; \ No newline at end of file +rollback; \ No newline at end of file diff --git a/apps/web/supabase/tests/database/account-slug.test.sql b/apps/web/supabase/tests/database/account-slug.test.sql index 6a8036066..3651bcdb1 100644 --- a/apps/web/supabase/tests/database/account-slug.test.sql +++ b/apps/web/supabase/tests/database/account-slug.test.sql @@ -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 diff --git a/apps/web/supabase/tests/database/create-organization-accounts.test.sql b/apps/web/supabase/tests/database/create-team-accounts.test.sql similarity index 64% rename from apps/web/supabase/tests/database/create-organization-accounts.test.sql rename to apps/web/supabase/tests/database/create-team-accounts.test.sql index 13eaadcfe..77236bebb 100644 --- a/apps/web/supabase/tests/database/create-organization-accounts.test.sql +++ b/apps/web/supabase/tests/database/create-team-accounts.test.sql @@ -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 * diff --git a/apps/web/supabase/tests/database/schema.test.sql b/apps/web/supabase/tests/database/schema.test.sql index 6e2948e1a..f706dee31 100644 --- a/apps/web/supabase/tests/database/schema.test.sql +++ b/apps/web/supabase/tests/database/schema.test.sql @@ -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'); diff --git a/packages/features/team-accounts/src/components/invitations/account-invitations-table.tsx b/packages/features/team-accounts/src/components/invitations/account-invitations-table.tsx index 336a7ef6a..005c4f91b 100644 --- a/packages/features/team-accounts/src/components/invitations/account-invitations-table.tsx +++ b/packages/features/team-accounts/src/components/invitations/account-invitations-table.tsx @@ -162,6 +162,10 @@ function ActionsDropdown({ const [isUpdatingRole, setIsUpdatingRole] = useState(false); const [iRenewingInvite, setIsRenewingInvite] = useState(false); + if (!permissions.canUpdateInvitation && !permissions.canRemoveInvitation) { + return null; + } + return ( <> diff --git a/packages/features/team-accounts/src/components/members/role-badge.tsx b/packages/features/team-accounts/src/components/members/role-badge.tsx index a543557d3..e52b290f2 100644 --- a/packages/features/team-accounts/src/components/members/role-badge.tsx +++ b/packages/features/team-accounts/src/components/members/role-badge.tsx @@ -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: '', diff --git a/packages/features/team-accounts/src/server/services/webhooks/account-invitations-webhook.service.ts b/packages/features/team-accounts/src/server/services/webhooks/account-invitations-webhook.service.ts index bd3562694..1d830a4f6 100644 --- a/packages/features/team-accounts/src/server/services/webhooks/account-invitations-webhook.service.ts +++ b/packages/features/team-accounts/src/server/services/webhooks/account-invitations-webhook.service.ts @@ -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 { diff --git a/packages/mailers/src/index.ts b/packages/mailers/src/index.ts index 6f0c3f584..5162a0946 100644 --- a/packages/mailers/src/index.ts +++ b/packages/mailers/src/index.ts @@ -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(); +}