Skip to content

Commit

Permalink
Migrated to BunnyCDN for image upload (#337)
Browse files Browse the repository at this point in the history
* Migrated to BunnyCDN for image upload

* Reverted package.json

* Refactored env for CDN

* Added docs for image cdn domain config

* Fixed lint
  • Loading branch information
SujithThirumalaisamy authored Sep 15, 2024
1 parent 90e9ee4 commit 167def8
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 75 deletions.
6 changes: 3 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ NEXTAUTH_URL="http://localhost:3000"
#
# Bunny CDN
#
CDN_SZ_NAME=
CDN_BASE_PATH=
CDN_API_KEY=
CDN_API_KEY=api-key
CDN_BASE_UPLOAD_URL=https://sg.storage.bunnycdn.com/job-board/assets
CDN_BASE_ACCESS_URL=https://job-board.b-cdn.net/assets
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Project Name: Job Board

[All about job board](https://marmalade-height-05f.notion.site/100xDevs-Job-board-ab8ca399180d49e4bc0c2ff5c81dfb08?pvs=25) <br/>
[Job board bugs](https://marmalade-height-05f.notion.site/100xDevs-JOB-BOARD-Bugs-10115651c69c80478fc8f673a139bc60)

## Table of Contents

- [Description](#description)
Expand Down Expand Up @@ -38,25 +40,27 @@ Follow these steps to set up the repository locally and run it.

```bash
#
# Database
# Database
#
DATABASE_URL="postgres://postgres:password@localhost:5432/postgres"

#
# AUTH
# AUTH
#
NEXTAUTH_SECRET="koXrQGB5TFD4KALDX4kAvnQ5RHHvAOIzB"
NEXTAUTH_URL="http://localhost:3000"

#
# Bunny CDN
#
CDN_SZ_NAME=
CDN_BASE_PATH=
CDN_API_KEY=
CDN_API_KEY=api-key
CDN_BASE_UPLOAD_URL=https://sg.storage.bunnycdn.com/job-board/assets
CDN_BASE_ACCESS_URL=https://job-board.b-cdn.net/assets
```

2. To generate AUTH_SECRET,
2. Change the hostname in `next.config.js` with your CDN access hostname by Ref of provided example.

3. To generate AUTH_SECRET,

Run this command in your terminal:

Expand All @@ -68,7 +72,6 @@ Follow these steps to set up the repository locally and run it.

[Run in browser](https://www.cryptool.org/en/cto/openssl/)


### Running the Project with Docker

```bash
Expand Down
4 changes: 2 additions & 2 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ const nextConfig = {
remotePatterns: [
{
protocol: 'https',
//Add aws s3 bucket hostname
hostname: '<bucket_url/hostname>', //example - youraws.s3.ap-south-2.amazonaws.com
//Change it with your cdn access domain here
hostname: 'job-board.b-cdn.net',
},
],
},
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-toast": "^1.2.1",
"@types/lodash": "^4.17.7",
"@types/uuid": "^10.0.0",
"@uidotdev/usehooks": "^2.4.1",
"bcryptjs": "^2.4.3",
"class-variance-authority": "^0.7.0",
Expand All @@ -55,6 +56,7 @@
"react-quill": "^2.0.0",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
"uuid": "^10.0.0",
"vaul": "^0.9.1",
"zod": "^3.23.8",
"zod-error": "^1.5.0"
Expand Down
4 changes: 2 additions & 2 deletions src/app/[...404]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ const Custom404Page = () => {
className="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-6 rounded-full transition-colors duration-300"
>
<Link href="/">
<a className="flex items-center">
<span className="flex items-center">
<Home className="mr-2 h-5 w-5" />
Return to Homepage
</a>
</span>
</Link>
</Button>
</motion.div>
Expand Down
43 changes: 0 additions & 43 deletions src/app/api/s3-upload/route.ts

This file was deleted.

49 changes: 49 additions & 0 deletions src/app/api/upload-to-cdn/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { NextResponse } from 'next/server';
import { v4 as uuidv4 } from 'uuid';

const CDN_BASE_UPLOAD_URL = process.env.CDN_BASE_UPLOAD_URL;
const CDN_BASE_ACCESS_URL = process.env.CDN_BASE_ACCESS_URL;
const CDN_API_KEY = process.env.CDN_API_KEY!;

export async function POST(req: Request): Promise<NextResponse> {
try {
const formData = await req.formData();
const file = formData.get('file') as File;
const uniqueFileName = formData.get('uniqueFileName') || uuidv4(); // Generate unique key if not provided

if (!file) {
return NextResponse.json({ error: 'File is required' }, { status: 400 });
}

const uploadUrl = `${CDN_BASE_UPLOAD_URL}/${uniqueFileName}`;

const fileBuffer = Buffer.from(await file.arrayBuffer());

const response = await fetch(uploadUrl, {
method: 'PUT',
headers: {
AccessKey: CDN_API_KEY,
'Content-Type': 'application/octet-stream',
},
body: fileBuffer,
});

if (response.ok) {
return NextResponse.json({
message: 'File uploaded successfully',
url: `${CDN_BASE_ACCESS_URL}/${uniqueFileName}`,
});
} else {
return NextResponse.json(
{ error: 'Failed to upload file' },
{ status: response.status }
);
}
} catch (error) {
console.error('Error uploading file to BunnyCDN:', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
27 changes: 9 additions & 18 deletions src/components/job-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,29 +74,20 @@ const PostJobForm = () => {
formData.append('file', file);

try {
const uniqueFileName = `${file.name}-${Date.now()}`;
const fileType = file.type;
const uniqueFileName = `${Date.now()}-${file.name}`;
formData.append('uniqueFileName', uniqueFileName);

const res = await fetch(
`/api/s3-upload?file=${encodeURIComponent(file.name)}&fileType=${encodeURIComponent(fileType)}&uniqueKey=${encodeURIComponent(uniqueFileName)}`
);
if (!res.ok) {
throw new Error('Failed to fetch presigned URL');
}

const { url: presignedUrl } = await res.json();
const upload = await fetch(presignedUrl, {
method: 'PUT',
body: file,
headers: { 'Content-Type': fileType },
const res = await fetch(`/api/upload-to-cdn`, {
method: 'POST',
body: formData,
});

if (!upload.ok) {
throw new Error('Upload failed');
if (!res.ok) {
throw new Error('Failed to upload image');
}

const pubUrl = presignedUrl.split('?')[0];
return pubUrl;
const uploadRes = await res.json();
return uploadRes.url;
} catch (error) {
console.error('Image upload failed:', error);
}
Expand Down

0 comments on commit 167def8

Please sign in to comment.