Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
.next
.git
Dockerfile
npm-debug.log
23 changes: 23 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 1. Base image
FROM node:20-alpine

# 2. Set working directory
WORKDIR /app

# 3. Copy package files
COPY package*.json ./

# 4. Install dependencies
RUN npm install

# 5. Copy all project files
COPY . .

# 6. Build Next.js app
RUN npm run build

# 7. Expose port
EXPOSE 3000

# 8. Start app
CMD ["npm", "run", "start"]
10 changes: 7 additions & 3 deletions database/database.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import mongoose from "mongoose";

const MONGO_URL = process.env.MONGO_URL;


let cached = global.mongoose;

if (!cached) {
cached = global.mongoose = { conn: null, promise: null };
}

export async function connectDatabase() {
if (!process.env.MONGO_URL) {
throw new Error("Couldn't find MONGO_URL in environment variables");
if (!MONGO_URL) {
console.log("Skipping mongo connection.");
return null;
}

// Prevent reconnecting to mongoose on every request
Expand All @@ -17,7 +21,7 @@ export async function connectDatabase() {
}

if (!cached.promise) {
cached.promise = mongoose.connect(process.env.MONGO_URL, {
cached.promise = mongoose.connect(MONGO_URL, {
// Prevent queries from hanging when mongodb isn't connected
bufferCommands: false,
});
Expand Down
26 changes: 26 additions & 0 deletions pages/api/artworks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { connectDatabase } from '@/database/database';
import Post from '@/database/schemas/Post';

export default async function handler (req, res) {
try {
if (!process.env.MONGO_URL) {
return res.status(200).json([]);
}
await connectDatabase();

const limit = parseInt(req.query.limit);

const artworksRaw = await Post.find(
{ type: 'art' },
{ _id: 0, metadata: 0, type: 0, page: 0, hype: 0, __v: 0 }
)
.sort({ date: -1 })
.limit(limit)
.lean();

res.status(200).json(artworksRaw);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Failed to fetch artworks' });
}
}
23 changes: 23 additions & 0 deletions pages/api/members.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { connectDatabase } from '@/database/database';
import Member from '@/database/schemas/Member';

export default async function handler (req, res) {
try {
if (!process.env.MONGO_URL) {
return res.status(200).json([]);
}
await connectDatabase();


const membersData = await Member.find(
{},
{ _id: 0 }
)
.lean();

res.status(200).json(membersData);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Failed to fetch members' });
}
}
44 changes: 16 additions & 28 deletions pages/art.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,26 @@ import SeasonFilter from '@/components/ArtSeasonFilter';
import Carousel from '@/components/Carousel';
import ArtCarouselCard from '@/components/ArtCarosuelCard';
import styles from '@/styles/ArtPage.module.css';
import { connectDatabase } from '@/database/database';
import Post from '@/database/schemas/Post';

export async function getStaticProps () {
await connectDatabase();
let artworksRaw = await Post.find(
{ type: 'art' },
{ _id: 0, metadata: 0, type: 0, page: 0, hype: 0, __v: 0 }
).sort({ date: -1 }).lean();
artworksRaw = artworksRaw.map(item => ({
...item,
date: item.date instanceof Date ? item.date.toISOString() : item.date
}));

export async function getServerSideProps (context) {
const host = context.req.headers.host;
const res = await fetch(`http://${host}/api/artworks`);
const artworksRaw = await res.json();

const artworks = artworksRaw.map(item => {
const d = new Date(item.date);

return {
src: `/assets/art/${item.link}`,
year: String(d.getFullYear()),
author: item.attr?.join(', ') || '',
description: item.name,
season: getSeason(d.getMonth())
};
});
const d = new Date(item.date);

return {
props: { artworks },
return {
src: `/assets/art/${item.link}`,
year: String(d.getFullYear()),
author: item.attr?.join(', ') || '',
description: item.name,
season: getSeason(d.getMonth())
};
});

revalidate: process.env.NODE_ENV === 'production'
? 60 * 60 // Once per hour
: 1 // every second for development
return {
props: { artworks }
};
}

Expand Down
21 changes: 6 additions & 15 deletions pages/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,26 @@ import RecentEventsSection from '@/components/home/RecentEventsSection';
import FanartSection from '@/components/home/FanartSection';
import AMVSection from '@/components/home/AMVSection';
import AboutUsSection from '@/components/home/AboutUsSection';
import { connectDatabase } from '@/database/database';
import Post from '@/database/schemas/Post';
// TODO: Move this to database
import events from '@/data/Events.json';

export async function getStaticProps () {
await connectDatabase();
const artworksRaw = await Post.find(
{ type: 'art' },
{ _id: 0, metadata: 0, type: 0, page: 0, hype: 0, __v: 0 }
).sort({ date: -1 }).limit(6).lean();
export async function getServerSideProps (context) {
const host = context.req.headers.host;
const res = await fetch(`http://${host}/api/artworks?limit=6`);
const artworksRaw = await res.json();

const artworks = artworksRaw.map(item => {
const d = item.date instanceof Date ? item.date : new Date(item.date);
return {
src: `/assets/art/${item.link}`
};
});

return {
props: { artworks, events },

revalidate: process.env.NODE_ENV === 'production'
? 60 * 60
: 1
props: { artworks }
};
}

export default function Home ({ artworks, events }) {
export default function Home ({ artworks }) {
return (
<div className={styles.home}>
<HeroSection />
Expand Down
17 changes: 7 additions & 10 deletions pages/members.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@ import { FaCaretDown } from 'react-icons/fa';
import { useState } from 'react';
import styles from '@/styles/MembersPage.module.css';
import MemberCard from '@/components/MemberCard';
import { connectDatabase } from '@/database/database';
import Member from '@/database/schemas/Member';

export async function getStaticProps () {
await connectDatabase();
const membersData = await Member.find({}, { _id: 0 }).lean();
return {
props: { membersData },
export async function getServerSideProps (context) {
const host = context.req.headers.host;
const res = await fetch(`http://${host}/api/members`);
const membersData = await res.json();

revalidate: process.env.NODE_ENV === 'production'
? 60 * 60 // Once per hour
: 1 // every second for development
return {
props: { membersData }
};

}

function getMembers (membersData, selectedYear) {
Expand Down
12 changes: 2 additions & 10 deletions tests/site.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { describe, test, expect, beforeAll, afterAll } from "vitest";
import { createServer } from "http";
import next from "next";
import { connectDatabase } from "../database/database.js";
import Member from "../database/schemas/Member.js";

let appServer;
let PORT;
Expand All @@ -12,6 +11,8 @@ beforeAll(async () => {
const handle = app.getRequestHandler();
await app.prepare();

await connectDatabase();

appServer = createServer((req, res) => handle(req, res));
await new Promise((resolve) => appServer.listen(0, resolve));
PORT = appServer.address().port;
Expand All @@ -24,19 +25,10 @@ afterAll(async () => {
const pages = ["", "events", "members", "newsletters", "videos", "art"];

describe("Server", () => {
beforeAll(async () => {
await connectDatabase();
});

describe("Database", () => {
test("should connect without throwing an error", async () => {
await expect(connectDatabase()).resolves.not.toThrow();
});

test("should find the MASK user", async () => {
const member = await Member.findOne({ name: "Tadi Joshua Raj" });
expect(member?.name).toBe("Tadi Joshua Raj");
});
});

pages.forEach(page => {
Expand Down
Loading