diff --git a/components/layout/Navbar.tsx b/components/layout/Navbar.tsx
index 0b3d515..189aa89 100644
--- a/components/layout/Navbar.tsx
+++ b/components/layout/Navbar.tsx
@@ -11,7 +11,7 @@ const Navbar = () => {
-
Upload
diff --git a/package.json b/package.json
index ac85451..33b2411 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
- "dev": "next dev",
+ "dev": "node ./server.js",
"build": "next build",
"start": "next start",
"lint": "next lint"
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 4b25ef2..79520d5 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -1,11 +1,12 @@
import React from 'react'
import '../styles/globals.css'
-import type {AppProps} from 'next/app'
-import {PageLayout} from 'components/layout'
-import {generateBrowserId} from 'utils/browser'
+import type { AppProps } from 'next/app'
+import { PageLayout } from 'components/layout'
+import { generateBrowserId } from 'utils/browser'
import Cookies from 'js-cookie'
+import Head from 'next/head'
-function MyApp({Component, pageProps}: AppProps) {
+function MyApp({ Component, pageProps }: AppProps) {
React.useEffect(() => {
const checkBrowserId = async () => {
const storedId = localStorage.getItem('__effp')
@@ -18,9 +19,22 @@ function MyApp({Component, pageProps}: AppProps) {
.catch(console.error);
}, [])
return (
-
-
- )
+ <>
+
+
Frasier Gifs
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
}
export default MyApp
diff --git a/pages/api/votes.ts b/pages/api/votes.ts
index 3e7d4e8..224f2b3 100644
--- a/pages/api/votes.ts
+++ b/pages/api/votes.ts
@@ -1,37 +1,102 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
-import type {NextApiRequest, NextApiResponse} from "next";
-import {PrismaClient} from "@prisma/client";
-import {getBrowserId} from "utils/browser";
-import qs from 'querystring'
+import type { NextApiRequest, NextApiResponse } from "next";
+import { PrismaClient } from "@prisma/client";
+import { getBrowserId } from "utils/browser";
+import qs from "querystring";
export default async function handler(
- req: NextApiRequest,
- res: NextApiResponse
+ req: NextApiRequest,
+ res: NextApiResponse
) {
- const {
- query: {gifId, isUp},
- } = req;
- const prisma = new PrismaClient();
- const browserId = req.cookies.bid;
-
- const exists = await prisma.votes.count({
- where: {
- gifId: gifId as string,
- browserId: browserId,
- },
- });
-
- if (exists !== 0) {
- res.status(403).json({
- message: "You have already voted on this gif",
- });
- }
- const result = await prisma.votes.create({
- data: {
- isUp: isUp === "1",
- browserId: browserId as string,
- gifId: gifId as string,
- },
- });
- res.status(200).json(result);
+ const {
+ query: { gifId, isUp },
+ } = req;
+ const browserId = req.cookies.bid;
+ if (!gifId || !browserId) {
+ return res.status(400);
+ }
+ if (isUp === "1") {
+ return _processUpvote(res, gifId as string, browserId);
+ } else {
+ return _processDownvote(res, gifId as string, browserId);
+ }
}
+const _processDownvote = async (
+ res: NextApiResponse,
+ gifId: string,
+ browserId: string
+) => {
+ const prisma = new PrismaClient();
+ //check for existing downvote
+ const exists = await prisma.downVotes.count({
+ where: {
+ gifId: gifId,
+ browserId: browserId,
+ },
+ });
+
+ if (exists !== 0) {
+ return res.status(403).json({
+ message: "You have already downvoted on this gif",
+ });
+ }
+
+ //delete any upvotes
+ try {
+ await prisma.upVotes.delete({
+ where: {
+ browserId_gifId: {
+ gifId: gifId,
+ browserId: browserId,
+ },
+ },
+ });
+ } catch {}
+ const result = await prisma.downVotes.create({
+ data: {
+ browserId: browserId as string,
+ gifId: gifId as string,
+ },
+ });
+ return res.status(200).json(result);
+};
+const _processUpvote = async (
+ res: NextApiResponse,
+ gifId: string,
+ browserId: string
+) => {
+ const prisma = new PrismaClient();
+ //check for existing upvote
+ const exists = await prisma.upVotes.count({
+ where: {
+ gifId: gifId,
+ browserId: browserId,
+ },
+ });
+
+ if (exists !== 0) {
+ return res.status(403).json({
+ message: "You have already upvoted this gif",
+ });
+ }
+
+ //delete any downvotes
+ try {
+ await prisma.downVotes.delete({
+ where: {
+ browserId_gifId: {
+ gifId: gifId,
+ browserId: browserId,
+ },
+ },
+ });
+ } catch {}
+
+ const result = await prisma.upVotes.create({
+ data: {
+ browserId: browserId as string,
+ gifId: gifId as string,
+ },
+ });
+ return res.status(200).json(result);
+};
diff --git a/pages/index.tsx b/pages/index.tsx
index 3b13acf..af120b3 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,21 +1,21 @@
-import {PrismaClient} from "@prisma/client";
-import type {GetServerSideProps, NextPage} from "next";
-import {Gif} from "models"
-import {GifContainer} from "components";
-import {getBrowserId} from "../utils/browser";
+import { PrismaClient } from "@prisma/client";
+import type { GetServerSideProps, NextPage } from "next";
+import { Gif } from "models"
+import { GifContainer } from "components";
+import { getBrowserId } from "../utils/browser";
interface IHomeProps {
gifs: Gif[]
}
-const Home: NextPage
= ({gifs}) => {
+const Home: NextPage = ({ gifs }) => {
return (
{gifs.map((gif: Gif) => {
return (
-
+
)
})}
@@ -24,51 +24,31 @@ const Home: NextPage
= ({gifs}) => {
);
};
-export const getServerSideProps: GetServerSideProps = async ({req}) => {
+export const getServerSideProps: GetServerSideProps = async ({ req }) => {
const browserId = getBrowserId(req.headers.cookie || '');
const prisma = new PrismaClient();
const results = await prisma.gif.findMany({
- take: 12, orderBy: {title: 'asc'},
+ take: 12, orderBy: { title: 'asc' },
include: {
_count: {
select: {
- votes: {where: {isUp: true}},
- // votes: { where: { isUp: false } }, //how to achieve
+ upVotes: true,
+ downVotes: true,
}
}
}
});
const gifs = await Promise.all(results.map(async (gif): Promise => {
- const votes = await prisma.votes.count({
- where: {
- gifId: gif.id as string,
- browserId: browserId,
- },
- })
- const upVotes = await prisma.votes.count({
- where: {
- gifId: gif.id as string,
- browserId: browserId,
- isUp: true
- },
- })
- const downVotes = await prisma.votes.count({
- where: {
- gifId: gif.id as string,
- browserId: browserId,
- isUp: false
- },
- })
return {
id: gif.id,
title: gif.title,
description: gif.description,
fileName: gif.fileName,
dateCreated: gif.createdAt.toISOString(),
- upVotes: upVotes,
- downVotes: downVotes,
- hasVoted: votes !== 0
+ upVotes: gif._count.upVotes,
+ downVotes: gif._count.downVotes,
+ hasVoted: false
}
}))
return {
diff --git a/prisma/migrations/20221001162558_add_counts/migration.sql b/prisma/migrations/20221001162558_add_counts/migration.sql
new file mode 100644
index 0000000..3e7c159
--- /dev/null
+++ b/prisma/migrations/20221001162558_add_counts/migration.sql
@@ -0,0 +1,39 @@
+/*
+ Warnings:
+
+ - You are about to drop the `Votes` table. If the table is not empty, all the data it contains will be lost.
+
+*/
+-- DropForeignKey
+ALTER TABLE "Votes" DROP CONSTRAINT "Votes_gifId_fkey";
+
+-- DropTable
+DROP TABLE "Votes";
+
+-- CreateTable
+CREATE TABLE "UpVotes" (
+ "id" TEXT NOT NULL,
+ "isUp" BOOLEAN NOT NULL,
+ "browserId" VARCHAR(1000) NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "gifId" TEXT NOT NULL,
+
+ CONSTRAINT "UpVotes_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateTable
+CREATE TABLE "DownVotes" (
+ "id" TEXT NOT NULL,
+ "isUp" BOOLEAN NOT NULL,
+ "browserId" VARCHAR(1000) NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "gifId" TEXT NOT NULL,
+
+ CONSTRAINT "DownVotes_pkey" PRIMARY KEY ("id")
+);
+
+-- AddForeignKey
+ALTER TABLE "UpVotes" ADD CONSTRAINT "UpVotes_gifId_fkey" FOREIGN KEY ("gifId") REFERENCES "Gif"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "DownVotes" ADD CONSTRAINT "DownVotes_gifId_fkey" FOREIGN KEY ("gifId") REFERENCES "Gif"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
diff --git a/prisma/migrations/20221001163420_remove_direction/migration.sql b/prisma/migrations/20221001163420_remove_direction/migration.sql
new file mode 100644
index 0000000..a4f2b55
--- /dev/null
+++ b/prisma/migrations/20221001163420_remove_direction/migration.sql
@@ -0,0 +1,12 @@
+/*
+ Warnings:
+
+ - You are about to drop the column `isUp` on the `DownVotes` table. All the data in the column will be lost.
+ - You are about to drop the column `isUp` on the `UpVotes` table. All the data in the column will be lost.
+
+*/
+-- AlterTable
+ALTER TABLE "DownVotes" DROP COLUMN "isUp";
+
+-- AlterTable
+ALTER TABLE "UpVotes" DROP COLUMN "isUp";
diff --git a/prisma/migrations/20221001190625_add_unique_constraintes/migration.sql b/prisma/migrations/20221001190625_add_unique_constraintes/migration.sql
new file mode 100644
index 0000000..f18b799
--- /dev/null
+++ b/prisma/migrations/20221001190625_add_unique_constraintes/migration.sql
@@ -0,0 +1,12 @@
+/*
+ Warnings:
+
+ - A unique constraint covering the columns `[browserId,gifId]` on the table `DownVotes` will be added. If there are existing duplicate values, this will fail.
+ - A unique constraint covering the columns `[browserId,gifId]` on the table `UpVotes` will be added. If there are existing duplicate values, this will fail.
+
+*/
+-- CreateIndex
+CREATE UNIQUE INDEX "DownVotes_browserId_gifId_key" ON "DownVotes"("browserId", "gifId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "UpVotes_browserId_gifId_key" ON "UpVotes"("browserId", "gifId");
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 2259c2b..381178c 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -20,17 +20,30 @@ model Gif {
//this is temporary, filenames should always match the GUID above
fileName String @db.VarChar(100)
- votes Votes[]
+ upVotes UpVotes[]
+ downVotes DownVotes[]
createdAt DateTime @default(now())
}
-model Votes {
- id String @id @default(uuid())
- isUp Boolean @db.Boolean()
- browserId String @db.VarChar(1000)
+model UpVotes {
+ id String @id @default(uuid())
+ browserId String @db.VarChar(1000)
createdAt DateTime @default(now())
gif Gif @relation(fields: [gifId], references: [id])
gifId String
+
+ @@unique([browserId, gifId])
+}
+
+model DownVotes {
+ id String @id @default(uuid())
+ browserId String @db.VarChar(1000)
+
+ createdAt DateTime @default(now())
+ gif Gif @relation(fields: [gifId], references: [id])
+ gifId String
+
+ @@unique([browserId, gifId])
}
diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png
new file mode 100644
index 0000000..521cda0
Binary files /dev/null and b/public/android-chrome-192x192.png differ
diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png
new file mode 100644
index 0000000..9230a01
Binary files /dev/null and b/public/android-chrome-512x512.png differ
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
new file mode 100644
index 0000000..6e230fb
Binary files /dev/null and b/public/apple-touch-icon.png differ
diff --git a/public/browserconfig.xml b/public/browserconfig.xml
new file mode 100644
index 0000000..b3930d0
--- /dev/null
+++ b/public/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ #da532c
+
+
+
diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png
new file mode 100644
index 0000000..027975d
Binary files /dev/null and b/public/favicon-16x16.png differ
diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png
new file mode 100644
index 0000000..e47fad0
Binary files /dev/null and b/public/favicon-32x32.png differ
diff --git a/public/favicon.ico b/public/favicon.ico
index 718d6fe..a1bf24c 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/public/mstile-150x150.png b/public/mstile-150x150.png
new file mode 100644
index 0000000..54b000a
Binary files /dev/null and b/public/mstile-150x150.png differ
diff --git a/public/safari-pinned-tab.svg b/public/safari-pinned-tab.svg
new file mode 100644
index 0000000..ca4c58d
--- /dev/null
+++ b/public/safari-pinned-tab.svg
@@ -0,0 +1,155 @@
+
+
+
diff --git a/public/site.webmanifest b/public/site.webmanifest
new file mode 100644
index 0000000..b20abb7
--- /dev/null
+++ b/public/site.webmanifest
@@ -0,0 +1,19 @@
+{
+ "name": "",
+ "short_name": "",
+ "icons": [
+ {
+ "src": "/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#ffffff",
+ "background_color": "#ffffff",
+ "display": "standalone"
+}
diff --git a/public/vercel.svg b/public/vercel.svg
deleted file mode 100644
index fbf0e25..0000000
--- a/public/vercel.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
\ No newline at end of file
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..8c3c857
--- /dev/null
+++ b/server.js
@@ -0,0 +1,22 @@
+var https = require("https");
+var fs = require("fs");
+
+const next = require("next");
+const port = 3000;
+const dev = process.env.NODE_ENV !== "production";
+const app = next({ dev, dir: __dirname });
+const handle = app.getRequestHandler();
+
+var options = {
+ key: fs.readFileSync("/etc/letsencrypt/live/fergl.ie/privkey.pem"),
+ cert: fs.readFileSync("/etc/letsencrypt/live/fergl.ie/cert.pem"),
+};
+
+app.prepare().then(() => {
+ https
+ .createServer(options, (req, res) => handle(req, res))
+ .listen(port, (err) => {
+ if (err) throw err;
+ console.log(`> Ready on localhost:${port}`);
+ });
+});