Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
♻️ refactor: refactor the server db implement (lobehub#2991)
Browse files Browse the repository at this point in the history
* ♻️ refactor: refactor the server db implement

* ✅ test: fix tests
arvinxx authored and Mingholy committed Jul 1, 2024
1 parent 692f352 commit 8a331b4
Showing 24 changed files with 2,117 additions and 126 deletions.
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ vi.mock('@/features/User/DataStatistics', () => ({
default: vi.fn(() => <div>Mocked DataStatistics</div>),
}));

vi.mock('@/features/User/UserLoginOrSignup', () => ({
vi.mock('@/features/User/UserLoginOrSignup/Community', () => ({
default: vi.fn(() => <div>Mocked UserLoginOrSignup</div>),
}));

2 changes: 1 addition & 1 deletion src/app/(main)/(mobile)/me/(home)/features/UserBanner.tsx
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ import { Flexbox } from 'react-layout-kit';
import { enableAuth } from '@/const/auth';
import DataStatistics from '@/features/User/DataStatistics';
import UserInfo from '@/features/User/UserInfo';
import UserLoginOrSignup from '@/features/User/UserLoginOrSignup';
import UserLoginOrSignup from '@/features/User/UserLoginOrSignup/Community';
import { useUserStore } from '@/store/user';
import { authSelectors } from '@/store/user/selectors';

Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ const useStyles = createStyles(({ css, prefixCls, responsive, token }) => ({
`,
}));

export interface ProviderConfigProps extends Omit<ModelProviderCard, 'id'> {
export interface ProviderConfigProps extends Omit<ModelProviderCard, 'id' | 'chatModels'> {
apiKeyItems?: FormItemProps[];
canDeactivate?: boolean;
checkerItem?: FormItemProps;
92 changes: 6 additions & 86 deletions src/app/api/webhooks/clerk/route.ts
Original file line number Diff line number Diff line change
@@ -1,97 +1,16 @@
import { UserJSON } from '@clerk/backend';
import { NextResponse } from 'next/server';

import { authEnv } from '@/config/auth';
import { isServerMode } from '@/const/version';
import { UserModel } from '@/database/server/models/user';
import { pino } from '@/libs/logger';
import { UserService } from '@/server/services/user';

import { validateRequest } from './validateRequest';

if (authEnv.NEXT_PUBLIC_ENABLE_CLERK_AUTH && isServerMode && !authEnv.CLERK_WEBHOOK_SECRET) {
throw new Error('`CLERK_WEBHOOK_SECRET` environment variable is missing');
}

const createUser = async (id: string, params: UserJSON) => {
pino.info('creating user due to clerk webhook');

const userModel = new UserModel();

// Check if user already exists
const res = await userModel.findById(id);

// If user already exists, skip creating a new user
if (res)
return NextResponse.json(
{ message: 'user not created due to user already existing in the database', success: false },
{ status: 200 },
);

const email = params.email_addresses.find((e) => e.id === params.primary_email_address_id);
const phone = params.phone_numbers.find((e) => e.id === params.primary_phone_number_id);

await userModel.createUser({
avatar: params.image_url,
clerkCreatedAt: new Date(params.created_at),
email: email?.email_address,
firstName: params.first_name,
id,
lastName: params.last_name,
phone: phone?.phone_number,
username: params.username,
});

return NextResponse.json({ message: 'user created', success: true }, { status: 200 });
};

const deleteUser = async (id?: string) => {
if (id) {
pino.info('delete user due to clerk webhook');
const userModel = new UserModel();

await userModel.deleteUser(id);

return NextResponse.json({ message: 'user deleted' }, { status: 200 });
} else {
pino.warn('clerk sent a delete user request, but no user ID was included in the payload');
return NextResponse.json({ message: 'ok' }, { status: 200 });
}
};

const updateUser = async (id: string, params: UserJSON) => {
pino.info('updating user due to clerk webhook');

const userModel = new UserModel();

// Check if user already exists
const res = await userModel.findById(id);

// If user not exists, skip update the user
if (!res)
return NextResponse.json(
{
message: "user not updated due to the user don't existing in the database",
success: false,
},
{ status: 200 },
);

const email = params.email_addresses.find((e) => e.id === params.primary_email_address_id);
const phone = params.phone_numbers.find((e) => e.id === params.primary_phone_number_id);

await userModel.updateUser(id, {
avatar: params.image_url,
email: email?.email_address,
firstName: params.first_name,
id,
lastName: params.last_name,
phone: phone?.phone_number,
username: params.username,
});

return NextResponse.json({ message: 'user updated', success: true }, { status: 200 });
};

export const POST = async (req: Request): Promise<NextResponse> => {
const payload = await validateRequest(req, authEnv.CLERK_WEBHOOK_SECRET!);

@@ -106,22 +25,23 @@ export const POST = async (req: Request): Promise<NextResponse> => {

pino.trace(`clerk webhook payload: ${{ data, type }}`);

const userService = new UserService();
switch (type) {
case 'user.created': {
return createUser(data.id, data);
return userService.createUser(data.id, data);
}
case 'user.deleted': {
return deleteUser(data.id);
return userService.deleteUser(data.id);
}
case 'user.updated': {
return updateUser(data.id, data);
return userService.updateUser(data.id, data);
}

default: {
pino.warn(
`${req.url} received event type "${type}", but no handler is defined for this type`,
);
return NextResponse.json({ error: `uncreognised payload type: ${type}` }, { status: 400 });
return NextResponse.json({ error: `unrecognised payload type: ${type}` }, { status: 400 });
}
// case 'user.updated':
// break;
28 changes: 28 additions & 0 deletions src/app/trpc/tools/[trpc]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import type { NextRequest } from 'next/server';

import { pino } from '@/libs/logger';
import { createContext } from '@/server/context';
import { toolsRouter } from '@/server/routers/tools';

export const maxDuration = 120;

const handler = (req: NextRequest) =>
fetchRequestHandler({
/**
* @link https://trpc.io/docs/v11/context
*/
createContext: () => createContext(req),

endpoint: '/trpc/tools',

onError: ({ error, path, type }) => {
pino.info(`Error in tRPC handler (tools) on path: ${path}, type: ${type}`);
console.error(error);
},

req,
router: toolsRouter,
});

export { handler as GET, handler as POST };
46 changes: 46 additions & 0 deletions src/database/server/migrations/0003_naive_echo.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
CREATE TABLE IF NOT EXISTS "user_budgets" (
"id" text PRIMARY KEY NOT NULL,
"free_budget_id" text,
"free_budget_key" text,
"subscription_budget_id" text,
"subscription_budget_key" text,
"package_budget_id" text,
"package_budget_key" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "user_subscriptions" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"stripe_id" text,
"currency" text,
"pricing" integer,
"billing_paid_at" integer,
"billing_cycle_start" integer,
"billing_cycle_end" integer,
"cancel_at_period_end" boolean,
"cancel_at" integer,
"next_billing" jsonb,
"plan" text,
"recurring" text,
"storage_limit" integer,
"status" integer,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "preference" DROP DEFAULT;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "user_budgets" ADD CONSTRAINT "user_budgets_id_users_id_fk" FOREIGN KEY ("id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "user_subscriptions" ADD CONSTRAINT "user_subscriptions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "users" DROP COLUMN IF EXISTS "key";
Loading

0 comments on commit 8a331b4

Please sign in to comment.