Skip to content

Commit 47dc2ae

Browse files
committed
feat: add S3 avatar upload during user creation from social provider
1 parent c9a9779 commit 47dc2ae

File tree

1 file changed

+52
-0
lines changed

1 file changed

+52
-0
lines changed

packages/auth/src/auth.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createAuthMiddleware } from "better-auth/api";
44
import { apiKey } from "better-auth/plugins";
55
import { magicLink } from "better-auth/plugins/magic-link";
66
import { env } from "next-runtime-env";
7+
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
78

89
import type { dbClient } from "@kan/db/client";
910
import * as memberRepo from "@kan/db/repository/member.repo";
@@ -12,6 +13,14 @@ import * as schema from "@kan/db/schema";
1213
import { sendEmail } from "@kan/email";
1314
import { createStripeClient } from "@kan/stripe";
1415

16+
async function downloadImage(url: string): Promise<Buffer> {
17+
const response = await fetch(url);
18+
if (!response.ok) {
19+
throw new Error(`Failed to download image: ${response.statusText}`);
20+
}
21+
return Buffer.from(await response.arrayBuffer());
22+
}
23+
1524
export const initAuth = (db: dbClient) => {
1625
return betterAuth({
1726
secret: process.env.BETTER_AUTH_SECRET!,
@@ -65,6 +74,49 @@ export const initAuth = (db: dbClient) => {
6574
},
6675
}),
6776
],
77+
databaseHooks: {
78+
user: {
79+
create: {
80+
async before(user, context) {
81+
const newUser = { ...user };
82+
if (user.image && !user.image.includes(process.env.NEXT_PUBLIC_STORAGE_DOMAIN!)) {
83+
try {
84+
const client = new S3Client({
85+
region: env("S3_REGION") ?? "",
86+
endpoint: env("S3_ENDPOINT") ?? "",
87+
credentials: {
88+
accessKeyId: env("S3_ACCESS_KEY_ID") ?? "",
89+
secretAccessKey: env("S3_SECRET_ACCESS_KEY") ?? "",
90+
},
91+
});
92+
93+
console.log(user.image);
94+
95+
const allowedFileExtensions = ["jpg", "jpeg", "png", "webp"];
96+
97+
const fileExtension = user.image.split('.').pop()?.split('?')[0] || 'jpg';
98+
const key = `${Date.now()}-${Math.random().toString(36).substring(2, 15)}.${!allowedFileExtensions.includes(fileExtension) ? 'jpg' : fileExtension}`;
99+
100+
const imageBuffer = await downloadImage(user.image);
101+
102+
await client.send(new PutObjectCommand({
103+
Bucket: env("NEXT_PUBLIC_AVATAR_BUCKET_NAME") ?? "",
104+
Key: key,
105+
Body: imageBuffer,
106+
ContentType: `image/${!allowedFileExtensions.includes(fileExtension) ? 'jpeg' : fileExtension}`,
107+
ACL: 'public-read',
108+
}));
109+
110+
newUser.image = key;
111+
} catch (error) {
112+
console.error(error);
113+
}
114+
}
115+
return { data: newUser };
116+
}
117+
}
118+
}
119+
},
68120
hooks: {
69121
after: createAuthMiddleware(async (ctx) => {
70122
if (ctx.path.startsWith("/get-session")) {

0 commit comments

Comments
 (0)