Refactor authentication method to requireUser
Replaced the requireAuth method with requireUser to improve clarity and modified all instances where it was used. Renamed the import throughout multiple files and services and made changes accordingly, thus making it more specific and understandable that a logged-in user is needed. The return type of the method was also updated from Session to User to more accurately reflect the information it provides.
This commit is contained in:
@@ -30,4 +30,4 @@ NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
|
|||||||
|
|
||||||
### Supabase
|
### Supabase
|
||||||
|
|
||||||
Please follow the instructions in the [Supabase README](../supabase/README.md) to setup your Supabase project.
|
Please follow the instructions in the [Supabase README](../supabase/README.md) to setup your Supabase project.
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { z } from 'zod';
|
|||||||
import { getLineItemsFromPlanId } from '@kit/billing';
|
import { getLineItemsFromPlanId } from '@kit/billing';
|
||||||
import { getBillingGatewayProvider } from '@kit/billing-gateway';
|
import { getBillingGatewayProvider } from '@kit/billing-gateway';
|
||||||
import { Logger } from '@kit/shared/logger';
|
import { Logger } from '@kit/shared/logger';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
||||||
|
|
||||||
import appConfig from '~/config/app.config';
|
import appConfig from '~/config/app.config';
|
||||||
@@ -25,9 +25,9 @@ export async function createPersonalAccountCheckoutSession(params: {
|
|||||||
productId: string;
|
productId: string;
|
||||||
}) {
|
}) {
|
||||||
const client = getSupabaseServerActionClient();
|
const client = getSupabaseServerActionClient();
|
||||||
const { data, error } = await requireAuth(client);
|
const { data: user, error } = await requireUser(client);
|
||||||
|
|
||||||
if (error ?? !data.user) {
|
if (error ?? !user) {
|
||||||
throw new Error('Authentication required');
|
throw new Error('Authentication required');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ export async function createPersonalAccountCheckoutSession(params: {
|
|||||||
|
|
||||||
// in the case of personal accounts
|
// in the case of personal accounts
|
||||||
// the account ID is the same as the user ID
|
// the account ID is the same as the user ID
|
||||||
const accountId = data.user.id;
|
const accountId = user.id;
|
||||||
|
|
||||||
// the return URL for the checkout session
|
// the return URL for the checkout session
|
||||||
const returnUrl = getCheckoutSessionReturnUrl();
|
const returnUrl = getCheckoutSessionReturnUrl();
|
||||||
@@ -74,13 +74,13 @@ export async function createPersonalAccountCheckoutSession(params: {
|
|||||||
accountId,
|
accountId,
|
||||||
trialDays,
|
trialDays,
|
||||||
paymentType: product.paymentType,
|
paymentType: product.paymentType,
|
||||||
customerEmail: data.user.email,
|
customerEmail: user.email,
|
||||||
customerId,
|
customerId,
|
||||||
});
|
});
|
||||||
|
|
||||||
Logger.info(
|
Logger.info(
|
||||||
{
|
{
|
||||||
userId: data.user.id,
|
userId: user.id,
|
||||||
},
|
},
|
||||||
`Checkout session created. Returning checkout token to client...`,
|
`Checkout session created. Returning checkout token to client...`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ export const loadTeamWorkspace = cache(async (accountSlug: string) => {
|
|||||||
|
|
||||||
const accountData = accountResult.data[0];
|
const accountData = accountResult.data[0];
|
||||||
|
|
||||||
|
// we cannot find any record for the selected organization
|
||||||
|
// so we redirect the user to the home page
|
||||||
if (!accountData) {
|
if (!accountData) {
|
||||||
return redirect(pathsConfig.app.home);
|
return redirect(pathsConfig.app.home);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { notFound } from 'next/navigation';
|
|||||||
|
|
||||||
import { getBillingGatewayProvider } from '@kit/billing-gateway';
|
import { getBillingGatewayProvider } from '@kit/billing-gateway';
|
||||||
import { BillingSessionStatus } from '@kit/billing-gateway/components';
|
import { BillingSessionStatus } from '@kit/billing-gateway/components';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||||
|
|
||||||
import billingConfig from '~/config/billing.config';
|
import billingConfig from '~/config/billing.config';
|
||||||
@@ -66,8 +66,11 @@ export default withI18n(ReturnStripeSessionPage);
|
|||||||
|
|
||||||
export async function loadCheckoutSession(sessionId: string) {
|
export async function loadCheckoutSession(sessionId: string) {
|
||||||
const client = getSupabaseServerComponentClient();
|
const client = getSupabaseServerComponentClient();
|
||||||
|
const { error } = await requireUser(client);
|
||||||
|
|
||||||
await requireAuth(client);
|
if (error) {
|
||||||
|
throw new Error('Authentication required');
|
||||||
|
}
|
||||||
|
|
||||||
const gateway = await getBillingGatewayProvider(client);
|
const gateway = await getBillingGatewayProvider(client);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
import { getLineItemsFromPlanId } from '@kit/billing';
|
import { getLineItemsFromPlanId } from '@kit/billing';
|
||||||
import { getBillingGatewayProvider } from '@kit/billing-gateway';
|
import { getBillingGatewayProvider } from '@kit/billing-gateway';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
||||||
|
|
||||||
import appConfig from '~/config/app.config';
|
import appConfig from '~/config/app.config';
|
||||||
@@ -33,13 +33,13 @@ export async function createTeamAccountCheckoutSession(params: {
|
|||||||
const productId = z.string().min(1).parse(params.productId);
|
const productId = z.string().min(1).parse(params.productId);
|
||||||
|
|
||||||
// we require the user to be authenticated
|
// we require the user to be authenticated
|
||||||
const { data: session } = await requireAuth(client);
|
const { data: user } = await requireUser(client);
|
||||||
|
|
||||||
if (!session) {
|
if (!user) {
|
||||||
throw new Error('Authentication required');
|
throw new Error('Authentication required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = session.user.id;
|
const userId = user.id;
|
||||||
const accountId = params.accountId;
|
const accountId = params.accountId;
|
||||||
|
|
||||||
const hasPermission = await getPermissionsForAccountId(userId, accountId);
|
const hasPermission = await getPermissionsForAccountId(userId, accountId);
|
||||||
@@ -67,7 +67,7 @@ export async function createTeamAccountCheckoutSession(params: {
|
|||||||
// find the customer ID for the account if it exists
|
// find the customer ID for the account if it exists
|
||||||
// (eg. if the account has been billed before)
|
// (eg. if the account has been billed before)
|
||||||
const customerId = await getCustomerIdFromAccountId(client, accountId);
|
const customerId = await getCustomerIdFromAccountId(client, accountId);
|
||||||
const customerEmail = session.user.email;
|
const customerEmail = user.email;
|
||||||
|
|
||||||
// the return URL for the checkout session
|
// the return URL for the checkout session
|
||||||
const returnUrl = getCheckoutSessionReturnUrl(params.slug);
|
const returnUrl = getCheckoutSessionReturnUrl(params.slug);
|
||||||
@@ -100,13 +100,13 @@ export async function createBillingPortalSession(formData: FormData) {
|
|||||||
})
|
})
|
||||||
.parse(Object.fromEntries(formData));
|
.parse(Object.fromEntries(formData));
|
||||||
|
|
||||||
const { data: session, error } = await requireAuth(client);
|
const { data: user, error } = await requireUser(client);
|
||||||
|
|
||||||
if (error ?? !session) {
|
if (error ?? !user) {
|
||||||
throw new Error('Authentication required');
|
throw new Error('Authentication required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = session.user.id;
|
const userId = user.id;
|
||||||
|
|
||||||
// we require the user to have permissions to manage billing for the account
|
// we require the user to have permissions to manage billing for the account
|
||||||
const hasPermission = await getPermissionsForAccountId(userId, accountId);
|
const hasPermission = await getPermissionsForAccountId(userId, accountId);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { notFound, redirect } from 'next/navigation';
|
|||||||
import { ArrowLeft } from 'lucide-react';
|
import { ArrowLeft } from 'lucide-react';
|
||||||
|
|
||||||
import { Logger } from '@kit/shared/logger';
|
import { Logger } from '@kit/shared/logger';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||||
import { AcceptInvitationContainer } from '@kit/team-accounts/components';
|
import { AcceptInvitationContainer } from '@kit/team-accounts/components';
|
||||||
import { Button } from '@kit/ui/button';
|
import { Button } from '@kit/ui/button';
|
||||||
@@ -12,6 +12,7 @@ import { Heading } from '@kit/ui/heading';
|
|||||||
import { Trans } from '@kit/ui/trans';
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
import pathsConfig from '~/config/paths.config';
|
import pathsConfig from '~/config/paths.config';
|
||||||
|
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||||
|
|
||||||
interface Context {
|
interface Context {
|
||||||
@@ -20,9 +21,11 @@ interface Context {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateMetadata = () => {
|
export const generateMetadata = async () => {
|
||||||
|
const i18n = await createI18nServerInstance();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: 'Join Team Account',
|
title: i18n.t('teams:joinTeamAccount'),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -35,12 +38,12 @@ async function JoinTeamAccountPage({ searchParams }: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const client = getSupabaseServerComponentClient();
|
const client = getSupabaseServerComponentClient();
|
||||||
const session = await requireAuth(client);
|
const auth = await requireUser(client);
|
||||||
|
|
||||||
// if the user is not logged in or there is an error
|
// if the user is not logged in or there is an error
|
||||||
// redirect to the sign up page with the invite token
|
// redirect to the sign up page with the invite token
|
||||||
// so that they will get back to this page after signing up
|
// so that they will get back to this page after signing up
|
||||||
if (session.error ?? !session.data) {
|
if (auth.error ?? !auth.data) {
|
||||||
redirect(pathsConfig.auth.signUp + '?invite_token=' + token);
|
redirect(pathsConfig.auth.signUp + '?invite_token=' + token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +64,7 @@ async function JoinTeamAccountPage({ searchParams }: Context) {
|
|||||||
{
|
{
|
||||||
name: 'join-team-account',
|
name: 'join-team-account',
|
||||||
accountId: invitation.account.id,
|
accountId: invitation.account.id,
|
||||||
userId: session.data.user.id,
|
userId: auth.data.id,
|
||||||
},
|
},
|
||||||
'User is already in the account. Redirecting to account page.',
|
'User is already in the account. Redirecting to account page.',
|
||||||
);
|
);
|
||||||
@@ -137,8 +140,6 @@ async function getInviteDataFromInviteToken(token: string) {
|
|||||||
.gte('expires_at', new Date().toISOString())
|
.gte('expires_at', new Date().toISOString())
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
console.log(invitation, error);
|
|
||||||
|
|
||||||
if (!invitation ?? error) {
|
if (!invitation ?? error) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { redirect } from 'next/navigation';
|
|||||||
|
|
||||||
import { PasswordResetForm } from '@kit/auth/password-reset';
|
import { PasswordResetForm } from '@kit/auth/password-reset';
|
||||||
import { AuthLayoutShell } from '@kit/auth/shared';
|
import { AuthLayoutShell } from '@kit/auth/shared';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||||
|
|
||||||
import { AppLogo } from '~/components/app-logo';
|
import { AppLogo } from '~/components/app-logo';
|
||||||
@@ -11,7 +11,7 @@ import { withI18n } from '~/lib/i18n/with-i18n';
|
|||||||
|
|
||||||
async function PasswordResetPage() {
|
async function PasswordResetPage() {
|
||||||
const client = getSupabaseServerComponentClient();
|
const client = getSupabaseServerComponentClient();
|
||||||
const auth = await requireAuth(client);
|
const auth = await requireUser(client);
|
||||||
|
|
||||||
// we require the user to be logged in to access this page
|
// we require the user to be logged in to access this page
|
||||||
if (auth.error) {
|
if (auth.error) {
|
||||||
|
|||||||
@@ -152,5 +152,6 @@
|
|||||||
"acceptInvitationHeading": "Accept Invitation to join {{accountName}}",
|
"acceptInvitationHeading": "Accept Invitation to join {{accountName}}",
|
||||||
"acceptInvitationDescription": "You have been invited to join the team {{accountName}}. If you wish to accept the invitation, please click the button below.",
|
"acceptInvitationDescription": "You have been invited to join the team {{accountName}}. If you wish to accept the invitation, please click the button below.",
|
||||||
"joinTeam": "Join {{accountName}}",
|
"joinTeam": "Join {{accountName}}",
|
||||||
|
"joinTeamAccount": "Join Team",
|
||||||
"joiningTeam": "Joining team..."
|
"joiningTeam": "Joining team..."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,6 @@
|
|||||||
"build": "turbo build",
|
"build": "turbo build",
|
||||||
"clean": "git clean -xdf node_modules dist .next",
|
"clean": "git clean -xdf node_modules dist .next",
|
||||||
"clean:workspaces": "turbo clean",
|
"clean:workspaces": "turbo clean",
|
||||||
"db:generate": "turbo db:generate",
|
|
||||||
"db:push": "turbo db:push db:generate",
|
|
||||||
"db:studio": "pnpm -F db studio",
|
|
||||||
"dev": "cross-env FORCE_COLOR=1 turbo dev --parallel",
|
"dev": "cross-env FORCE_COLOR=1 turbo dev --parallel",
|
||||||
"dev:web": "turbo dev --parallel",
|
"dev:web": "turbo dev --parallel",
|
||||||
"format": "turbo format --continue -- --cache --cache-location='node_modules/.cache/.prettiercache' --ignore-path='../../.gitignore'",
|
"format": "turbo format --continue -- --cache --cache-location='node_modules/.cache/.prettiercache' --ignore-path='../../.gitignore'",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { RedirectType, redirect } from 'next/navigation';
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Logger } from '@kit/shared/logger';
|
import { Logger } from '@kit/shared/logger';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
||||||
|
|
||||||
import { DeletePersonalAccountService } from './services/delete-personal-account.service';
|
import { DeletePersonalAccountService } from './services/delete-personal-account.service';
|
||||||
@@ -28,17 +28,17 @@ export async function deletePersonalAccountAction(formData: FormData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const client = getSupabaseServerActionClient();
|
const client = getSupabaseServerActionClient();
|
||||||
const session = await requireAuth(client);
|
const auth = await requireUser(client);
|
||||||
|
|
||||||
if (session.error) {
|
if (auth.error) {
|
||||||
Logger.error(`User is not authenticated. Redirecting to login page`);
|
Logger.error(`User is not authenticated. Redirecting to login page`);
|
||||||
|
|
||||||
redirect(session.redirectTo);
|
redirect(auth.redirectTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve user ID and email
|
// retrieve user ID and email
|
||||||
const userId = session.data.user.id;
|
const userId = auth.data.id;
|
||||||
const userEmail = session.data.user.email ?? null;
|
const userEmail = auth.data.email ?? null;
|
||||||
|
|
||||||
// create a new instance of the personal accounts service
|
// create a new instance of the personal accounts service
|
||||||
const service = new DeletePersonalAccountService();
|
const service = new DeletePersonalAccountService();
|
||||||
|
|||||||
@@ -2,5 +2,4 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
export const LeaveTeamAccountSchema = z.object({
|
export const LeaveTeamAccountSchema = z.object({
|
||||||
accountId: z.string(),
|
accountId: z.string(),
|
||||||
userId: z.string(),
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { redirect } from 'next/navigation';
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Logger } from '@kit/shared/logger';
|
import { Logger } from '@kit/shared/logger';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
||||||
|
|
||||||
import { CreateTeamSchema } from '../../schema/create-team.schema';
|
import { CreateTeamSchema } from '../../schema/create-team.schema';
|
||||||
@@ -25,13 +25,13 @@ export async function createOrganizationAccountAction(
|
|||||||
|
|
||||||
const client = getSupabaseServerActionClient();
|
const client = getSupabaseServerActionClient();
|
||||||
const service = new CreateTeamAccountService(client);
|
const service = new CreateTeamAccountService(client);
|
||||||
const session = await requireAuth(client);
|
const auth = await requireUser(client);
|
||||||
|
|
||||||
if (session.error) {
|
if (auth.error) {
|
||||||
redirect(session.redirectTo);
|
redirect(auth.redirectTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = session.data.user.id;
|
const userId = auth.data.id;
|
||||||
|
|
||||||
const createAccountResponse = await service.createNewOrganizationAccount({
|
const createAccountResponse = await service.createNewOrganizationAccount({
|
||||||
name: accountName,
|
name: accountName,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { redirect } from 'next/navigation';
|
|||||||
import { SupabaseClient } from '@supabase/supabase-js';
|
import { SupabaseClient } from '@supabase/supabase-js';
|
||||||
|
|
||||||
import { Database } from '@kit/supabase/database';
|
import { Database } from '@kit/supabase/database';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
||||||
|
|
||||||
import { DeleteTeamAccountSchema } from '../../schema/delete-team-account.schema';
|
import { DeleteTeamAccountSchema } from '../../schema/delete-team-account.schema';
|
||||||
@@ -17,7 +17,7 @@ export async function deleteTeamAccountAction(formData: FormData) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const client = getSupabaseServerActionClient();
|
const client = getSupabaseServerActionClient();
|
||||||
const auth = await requireAuth(client);
|
const auth = await requireUser(client);
|
||||||
|
|
||||||
if (auth.error) {
|
if (auth.error) {
|
||||||
throw new Error('Authentication required');
|
throw new Error('Authentication required');
|
||||||
@@ -36,7 +36,7 @@ export async function deleteTeamAccountAction(formData: FormData) {
|
|||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
accountId: params.accountId,
|
accountId: params.accountId,
|
||||||
userId: auth.data.user.id,
|
userId: auth.data.id,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -47,13 +47,13 @@ async function assertUserPermissionsToDeleteTeamAccount(
|
|||||||
client: SupabaseClient<Database>,
|
client: SupabaseClient<Database>,
|
||||||
accountId: string,
|
accountId: string,
|
||||||
) {
|
) {
|
||||||
const auth = await requireAuth(client);
|
const auth = await requireUser(client);
|
||||||
|
|
||||||
if (auth.error ?? !auth.data.user.id) {
|
if (auth.error ?? !auth.data.id) {
|
||||||
throw new Error('Authentication required');
|
throw new Error('Authentication required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = auth.data.user.id;
|
const userId = auth.data.id;
|
||||||
|
|
||||||
const { data, error } = await client
|
const { data, error } = await client
|
||||||
.from('accounts')
|
.from('accounts')
|
||||||
|
|||||||
@@ -1,16 +1,35 @@
|
|||||||
'use server';
|
'use server';
|
||||||
|
|
||||||
|
import { revalidatePath } from 'next/cache';
|
||||||
|
import { redirect } from 'next/navigation';
|
||||||
|
|
||||||
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
||||||
|
|
||||||
import { LeaveTeamAccountSchema } from '../../schema/leave-team-account.schema';
|
import { LeaveTeamAccountSchema } from '../../schema/leave-team-account.schema';
|
||||||
import { LeaveAccountService } from '../services/leave-account.service';
|
import { LeaveTeamAccountService } from '../services/leave-team-account.service';
|
||||||
|
|
||||||
export async function leaveTeamAccountAction(formData: FormData) {
|
export async function leaveTeamAccountAction(formData: FormData) {
|
||||||
const body = Object.fromEntries(formData.entries());
|
const body = Object.fromEntries(formData.entries());
|
||||||
const params = LeaveTeamAccountSchema.parse(body);
|
const params = LeaveTeamAccountSchema.parse(body);
|
||||||
const service = new LeaveAccountService(getSupabaseServerActionClient());
|
const client = getSupabaseServerActionClient();
|
||||||
|
|
||||||
await service.leaveTeamAccount(params);
|
const auth = await requireUser(client);
|
||||||
|
|
||||||
return { success: true };
|
if (auth.error) {
|
||||||
|
throw new Error('Authentication required');
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = new LeaveTeamAccountService(
|
||||||
|
getSupabaseServerActionClient({ admin: true }),
|
||||||
|
);
|
||||||
|
|
||||||
|
await service.leaveTeamAccount({
|
||||||
|
accountId: params.accountId,
|
||||||
|
userId: auth.data.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
revalidatePath('/home/[account]', 'layout');
|
||||||
|
|
||||||
|
return redirect('/home');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Database } from '@kit/supabase/database';
|
import { Database } from '@kit/supabase/database';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
import { getSupabaseServerActionClient } from '@kit/supabase/server-actions-client';
|
||||||
|
|
||||||
import { AcceptInvitationSchema } from '../../schema/accept-invitation.schema';
|
import { AcceptInvitationSchema } from '../../schema/accept-invitation.schema';
|
||||||
@@ -94,7 +94,7 @@ export async function acceptInvitationAction(data: FormData) {
|
|||||||
Object.fromEntries(data),
|
Object.fromEntries(data),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { user } = await assertSession(client);
|
const user = await assertSession(client);
|
||||||
|
|
||||||
const service = new AccountInvitationsService(client);
|
const service = new AccountInvitationsService(client);
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ export async function renewInvitationAction(params: { invitationId: number }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function assertSession(client: SupabaseClient<Database>) {
|
async function assertSession(client: SupabaseClient<Database>) {
|
||||||
const { error, data } = await requireAuth(client);
|
const { error, data } = await requireUser(client);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
throw new Error(`Authentication required`);
|
throw new Error(`Authentication required`);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { z } from 'zod';
|
|||||||
import { Mailer } from '@kit/mailers';
|
import { Mailer } from '@kit/mailers';
|
||||||
import { Logger } from '@kit/shared/logger';
|
import { Logger } from '@kit/shared/logger';
|
||||||
import { Database } from '@kit/supabase/database';
|
import { Database } from '@kit/supabase/database';
|
||||||
import { requireAuth } from '@kit/supabase/require-auth';
|
import { requireUser } from '@kit/supabase/require-user';
|
||||||
|
|
||||||
import { DeleteInvitationSchema } from '../../schema/delete-invitation.schema';
|
import { DeleteInvitationSchema } from '../../schema/delete-invitation.schema';
|
||||||
import { InviteMembersSchema } from '../../schema/invite-members.schema';
|
import { InviteMembersSchema } from '../../schema/invite-members.schema';
|
||||||
@@ -102,8 +102,7 @@ export class AccountInvitationsService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const mailer = new Mailer();
|
const mailer = new Mailer();
|
||||||
|
const user = await this.getUser();
|
||||||
const { user } = await this.getUser();
|
|
||||||
|
|
||||||
const accountResponse = await this.client
|
const accountResponse = await this.client
|
||||||
.from('accounts')
|
.from('accounts')
|
||||||
@@ -258,7 +257,7 @@ export class AccountInvitationsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getUser() {
|
private async getUser() {
|
||||||
const { data, error } = await requireAuth(this.client);
|
const { data, error } = await requireUser(this.client);
|
||||||
|
|
||||||
if (error ?? !data) {
|
if (error ?? !data) {
|
||||||
throw new Error('Authentication required');
|
throw new Error('Authentication required');
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { SupabaseClient } from '@supabase/supabase-js';
|
|
||||||
|
|
||||||
import 'server-only';
|
|
||||||
import { z } from 'zod';
|
|
||||||
|
|
||||||
import { Database } from '@kit/supabase/database';
|
|
||||||
|
|
||||||
import { LeaveTeamAccountSchema } from '../../schema/leave-team-account.schema';
|
|
||||||
|
|
||||||
export class LeaveAccountService {
|
|
||||||
constructor(private readonly client: SupabaseClient<Database>) {}
|
|
||||||
|
|
||||||
async leaveTeamAccount(params: z.infer<typeof LeaveTeamAccountSchema>) {
|
|
||||||
await Promise.resolve();
|
|
||||||
|
|
||||||
console.log(params);
|
|
||||||
// TODO
|
|
||||||
// implement this method
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { SupabaseClient } from '@supabase/supabase-js';
|
||||||
|
|
||||||
|
import 'server-only';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { Database } from '@kit/supabase/database';
|
||||||
|
|
||||||
|
const Schema = z.object({
|
||||||
|
accountId: z.string(),
|
||||||
|
userId: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export class LeaveTeamAccountService {
|
||||||
|
constructor(private readonly adminClient: SupabaseClient<Database>) {}
|
||||||
|
|
||||||
|
async leaveTeamAccount(params: z.infer<typeof Schema>) {
|
||||||
|
const { accountId, userId } = Schema.parse(params);
|
||||||
|
|
||||||
|
const { error } = await this.adminClient
|
||||||
|
.from('accounts_memberships')
|
||||||
|
.delete()
|
||||||
|
.match({
|
||||||
|
account_id: accountId,
|
||||||
|
user_id: userId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -195,7 +195,7 @@ export class StripeWebhookHandlerService
|
|||||||
cancel_at_period_end: subscription.cancel_at_period_end ?? false,
|
cancel_at_period_end: subscription.cancel_at_period_end ?? false,
|
||||||
interval: interval as string,
|
interval: interval as string,
|
||||||
currency: (price as Stripe.Price).currency,
|
currency: (price as Stripe.Price).currency,
|
||||||
product_id: (price as Stripe.Price).product,
|
product_id: (price as Stripe.Price).product as string,
|
||||||
variant_id: priceId,
|
variant_id: priceId,
|
||||||
interval_count: price?.recurring?.interval_count ?? 1,
|
interval_count: price?.recurring?.interval_count ?? 1,
|
||||||
period_starts_at: getISOString(subscription.current_period_start),
|
period_starts_at: getISOString(subscription.current_period_start),
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
"./server-component-client": "./src/clients/server-component.client.ts",
|
"./server-component-client": "./src/clients/server-component.client.ts",
|
||||||
"./browser-client": "./src/clients/browser.client.ts",
|
"./browser-client": "./src/clients/browser.client.ts",
|
||||||
"./check-requires-mfa": "./src/check-requires-mfa.ts",
|
"./check-requires-mfa": "./src/check-requires-mfa.ts",
|
||||||
"./require-auth": "./src/require-auth.ts",
|
"./require-user": "./src/require-user.ts",
|
||||||
"./hooks/*": "./src/hooks/*.ts",
|
"./hooks/*": "./src/hooks/*.ts",
|
||||||
"./components/*": "./src/components/*.tsx",
|
"./components/*": "./src/components/*.tsx",
|
||||||
"./database": "./src/database.types.ts"
|
"./database": "./src/database.types.ts"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { Session, SupabaseClient } from '@supabase/supabase-js';
|
import type { SupabaseClient, User } from '@supabase/supabase-js';
|
||||||
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
@@ -15,18 +15,14 @@ const SIGN_IN_PATH = z
|
|||||||
.parse(process.env.SIGN_IN_PATH);
|
.parse(process.env.SIGN_IN_PATH);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name requireAuth
|
* @name requireUser
|
||||||
* @description Require a session to be present in the request
|
* @description Require a session to be present in the request
|
||||||
* @param client
|
* @param client
|
||||||
* @param verifyFromServer
|
|
||||||
*/
|
*/
|
||||||
export async function requireAuth(
|
export async function requireUser(client: SupabaseClient): Promise<
|
||||||
client: SupabaseClient,
|
|
||||||
verifyFromServer = true,
|
|
||||||
): Promise<
|
|
||||||
| {
|
| {
|
||||||
error: null;
|
error: null;
|
||||||
data: Session;
|
data: User;
|
||||||
}
|
}
|
||||||
| (
|
| (
|
||||||
| {
|
| {
|
||||||
@@ -41,9 +37,9 @@ export async function requireAuth(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
> {
|
> {
|
||||||
const { data, error } = await client.auth.getSession();
|
const { data, error } = await client.auth.getUser();
|
||||||
|
|
||||||
if (!data.session || error) {
|
if (!data.user || error) {
|
||||||
return {
|
return {
|
||||||
data: null,
|
data: null,
|
||||||
error: new AuthenticationError(),
|
error: new AuthenticationError(),
|
||||||
@@ -63,21 +59,9 @@ export async function requireAuth(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verifyFromServer) {
|
|
||||||
const { data: user, error } = await client.auth.getUser();
|
|
||||||
|
|
||||||
if (!user || error) {
|
|
||||||
return {
|
|
||||||
data: null,
|
|
||||||
error: new AuthenticationError(),
|
|
||||||
redirectTo: SIGN_IN_PATH,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
error: null,
|
error: null,
|
||||||
data: data.session,
|
data: data.user,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@ import type { MDXComponents } from 'mdx/types';
|
|||||||
import { getMDXComponent } from 'next-contentlayer/hooks';
|
import { getMDXComponent } from 'next-contentlayer/hooks';
|
||||||
|
|
||||||
import Components from './mdx-components';
|
import Components from './mdx-components';
|
||||||
// @ts-expect-error: weird typescript error with css modules
|
// @ts-ignore: ignore weird error
|
||||||
import styles from './mdx-renderer.module.css';
|
import styles from './mdx-renderer.module.css';
|
||||||
|
|
||||||
export function Mdx({
|
export function Mdx({
|
||||||
|
|||||||
Reference in New Issue
Block a user