diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6e87a00 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.env b/.env index 48679b1..ae747a9 100644 --- a/.env +++ b/.env @@ -1,15 +1,25 @@ NEXT_PUBLIC_API_URL=https://otherway.dev.fergl.ie:3000 +QSTASH_CURRENT_SIGNING_KEY=khs3lpVBv1QtV/L9MTdXlcnoI8tTlg0aDfrFz+o8utA= +DATABASE_URL="postgresql://postgres:hackme@localhost:5432/radio-otherway?schema=public" #auth NEXTAUTH_URL=https://otherway.dev.fergl.ie:3000 GOOGLE_CLIENT_ID=47147490249-adhc8cbko4nvigrfoodo17oa3qfsg4pd.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=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 - #calendar api GOOGLE_CALENDAR_PROJECT_ID=47147490249 -GOOGLE_CALENDAR_ID=geh501qel59lf3505v2huebo18@group.calendar.google.com +LIVE_GOOGLE_CALENDAR_ID=geh501qel59lf3505v2huebo18@group.calendar.google.com +GOOGLE_CALENDAR_ID=7732f7973f574db2638371394769a94aad5e38b98362d528cd985728d98cf3bd@group.calendar.google.com + GOOGLE_CALENDAR_API_KEY=AIzaSyAMvrSrwqvz9o4Y8b-0zneU-REWDIzuKR0 GOOGLE_CALENDAR_CREDENTIALS_PRIVATE_KEY_ID="d694fded9dca2e36e5974032d458c28edfd40852" GOOGLE_CALENDAR_CREDENTIALS_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCaMVP3P+Do/KcZ\np/EH2cbj6bDb0weBcJzAyL8McrmZta8sSizQ63ui6CEcqrFhLVIT49Auzyx7KQcW\n/cu0/gLWUz/uZkbuqhCuYr0EYZWSQgTCdqK/llbxfVaKVDj4/noykqi175UWnRDW\nBG7PU3TeXTVwfH5WSWQq+ZWm9Br0wlR/dYxuAfVKIFJd+PbvvyzQhDDdU4GQdo39\ntKh9h6LJnQs7JxofleYEHAxFiA4gDTkFyV6s6TqG2zcEwWieH3LdH44chHYZuuZC\nVAZ38/Aofva1gYjdkos2OTch9SDKbijaLSYPHDHW0MNWScSIDvcUKULaPFv8Y5nt\nnOiRow0rAgMBAAECggEAH0oRQuQojL7wXclxpOkxbgB3DjSlmkOy24AhHLKPLTzs\nHi2zKHYQsb8vMPUGZ7TdqgGZtlX+LcPml2jLFKBTDRD5sTP6AuZp2ilZN/Fhe7t/\n4cJXRk+Itxp7HDj5ErX5MBgIulqyw1L+Hp/pqJLD7Xe2p2vr6zCbbgkVsDpq2e3g\nuX82oqzSIrrfPpZQDYi0rxOTVVdLc/EUtTc3VDvzaylUBXhSvgV22tOQYds7H+Si\njMsMD6dIZGejiNn+rtLaK3/yEH6iik4XSKNXtDUCBzNbpTkxhk78OOdfAa2ySSM8\naNsNHa/kBoM0W8/+aSjFHYbru5YRJB4IWuUWCO49SQKBgQDJUEqIsm6UhAsgrCDN\nUDXbCnijs75cpt6YYHVlWNNHD2gG8FSz0Smk1TXlwqF85SrKir30cktRHi08AuJ3\nXf38/u9BWFYRs8qELPEgIJ6VrB+i7KLS1X8/Vd6Q+72exwGqyBZGAW9juCmkHiuF\nNTX7ClmaALfoSJ1jOPnX4LG2HwKBgQDEFCl9xvGDFcuLt1Hdg2rcx2gnN+RmDGfh\neTagw70zVvEjp1kQxhzaQArWCkB2kSV9EEZl//TwK+h7KVdvNDR1ufVxbaQVV2S3\nWFfwr9RH1DhPtjhhYawbxhsC/S62JPc7maLNBUg2YwrHiX+gal35ePAvs8+0Kl4V\nbKxw62EPdQKBgQCw3++srQFFUcKpITLs0VWQL2IRisJti1u2C8H5mpJ/M8UVm6EA\nIHzzSzVAusHCB2OSc1Y0aRtNmTLrMCmj8RxQZfj2s9NjWFFN0mLE9IQBQyrErh7d\nGSHlFuAnCFfxIi6Py57uQSKKPeuwO6XHMxpLiCtziMAMwYgu/oddqhjZxwKBgDi2\nzDmBLaIIz9MdtyQnOuWZF9sgI4QQ2osxEEf31eXfo+f4I57ibr4CACBg3rxsxzch\nWftuyV4elSPqlUupAfN7Ui7405kIqi0N9IG9md0c2RzVTAF+ytVNu8pliPlOP+SR\nT7GVcYmppBiLAMtZeM0L2g0yKUWna4cu48HVk0FxAoGBAKCSVvU2yAPKQlFZMjWZ\nf3lZVssPNf1/xSfvnsSqzURN7MzPlQRChZK7XgoAtKARep3vl8Uiti+OnPXCSf0P\nOvq6ckSGQxViVA3xlVTkYFA37CqCsCk5e3pAmv6nFcEnhbWMEIiK1+fEoVYpcMJB\ng8dJPLVOhoUcuGMYFE9KBp3K\n-----END PRIVATE KEY-----\n" GOOGLE_CALENDAR_CREDENTIALS_CLIENT_EMAIL="otherway-calendar-proxy@radio-otherway.iam.gserviceaccount.com" + +# This was inserted by `prisma init`: +# Environment variables declared in this file are automatically made available to Prisma. +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema + +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. +# See the documentation for all the connection string options: https://pris.ly/d/connection-strings diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f589ca3 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/web.iml b/.idea/web.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/web.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index c1ae5e0..d049007 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,13 @@ "lint": "next lint" }, "dependencies": { + "@next-auth/prisma-adapter": "^1.0.5", "@next/font": "13.1.5", + "@prisma/client": "^4.9.0", "@types/node": "18.11.18", "@types/react": "18.0.27", "@types/react-dom": "18.0.10", + "@upstash/qstash": "^0.3.6", "daisyui": "^2.49.0", "eslint": "8.32.0", "eslint-config-next": "13.1.5", @@ -32,6 +35,7 @@ "postcss": "^8.4.21", "prettier": "^2.8.3", "prettier-plugin-tailwindcss": "^0.2.2", + "prisma": "^4.9.0", "tailwindcss": "^3.2.4" } } diff --git a/postcss.config.js b/postcss.config.js index 33ad091..b4dfba6 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,6 +1,7 @@ module.exports = { plugins: { - tailwindcss: {}, + tailwindcss: { + }, autoprefixer: {}, }, } diff --git a/prisma/migrations/20230130203220_initial/migration.sql b/prisma/migrations/20230130203220_initial/migration.sql new file mode 100644 index 0000000..7ae4196 --- /dev/null +++ b/prisma/migrations/20230130203220_initial/migration.sql @@ -0,0 +1,66 @@ +-- CreateTable +CREATE TABLE "Account" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "type" TEXT NOT NULL, + "provider" TEXT NOT NULL, + "providerAccountId" TEXT NOT NULL, + "refresh_token" TEXT, + "access_token" TEXT, + "expires_at" INTEGER, + "token_type" TEXT, + "scope" TEXT, + "id_token" TEXT, + "session_state" TEXT, + + CONSTRAINT "Account_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Session" ( + "id" TEXT NOT NULL, + "sessionToken" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "expires" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Session_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "name" TEXT, + "email" TEXT, + "emailVerified" TIMESTAMP(3), + "image" TEXT, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "VerificationToken" ( + "identifier" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expires" TIMESTAMP(3) NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token"); + +-- CreateIndex +CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token"); + +-- AddForeignKey +ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..f68456f --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,56 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model Account { + id String @id @default(cuid()) + userId String + type String + provider String + providerAccountId String + refresh_token String? @db.Text + access_token String? @db.Text + expires_at Int? + token_type String? + scope String? + id_token String? @db.Text + session_state String? + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([provider, providerAccountId]) +} + +model Session { + id String @id @default(cuid()) + sessionToken String @unique + userId String + expires DateTime + user User @relation(fields: [userId], references: [id], onDelete: Cascade) +} + +model User { + id String @id @default(cuid()) + name String? + email String? @unique + emailVerified DateTime? + image String? + accounts Account[] + sessions Session[] +} + +model VerificationToken { + identifier String + token String @unique + expires DateTime + + @@unique([identifier, token]) +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 7e1ca0d..f4350d6 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -18,7 +18,7 @@ export default function RootLayout({ -
+
{children}
diff --git a/src/app/page.tsx b/src/app/page.tsx index 8a8679e..0b1c3de 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,17 +7,21 @@ const getData = async () => { export default async function Home() { const results = await getData(); - return results.events.length === 0 ? ( -

- No upcoming events -

+ return results.events.length === 0 && results.message ? ( +
+
+
+

{results.message}

+
+
+
) : (

Upcoming Shows

-
+
diff --git a/src/components/auth/LoginPage.tsx b/src/components/auth/LoginPage.tsx index 066bdab..ebc93aa 100644 --- a/src/components/auth/LoginPage.tsx +++ b/src/components/auth/LoginPage.tsx @@ -1,15 +1,17 @@ "use client"; import React from "react"; -import { signIn } from "next-auth/react"; +import {signIn} from "next-auth/react"; +import {useRouter} from "next/navigation"; const LoginPage = () => { + const router = useRouter() return (

Login

- +
diff --git a/src/components/layout/NavBar.tsx b/src/components/layout/NavBar.tsx index fbcd10c..133397b 100644 --- a/src/components/layout/NavBar.tsx +++ b/src/components/layout/NavBar.tsx @@ -1,11 +1,14 @@ "use client"; -import { signOut, useSession } from "next-auth/react"; +import {signOut, useSession} from "next-auth/react"; import React from "react"; -import { BiLogInCircle } from "react-icons/bi"; +import {BiLogInCircle} from "react-icons/bi"; +import Link from "next/link"; + const Navbar = () => { - const { data: session, status } = useSession(); + const {data: session, status} = useSession(); return ( -
+
diff --git a/src/lib/prismadb.ts b/src/lib/prismadb.ts new file mode 100644 index 0000000..1e77578 --- /dev/null +++ b/src/lib/prismadb.ts @@ -0,0 +1,10 @@ +import { PrismaClient } from "@prisma/client"; + +declare global { + var prisma: PrismaClient | undefined; +} + +const client = globalThis.prisma || new PrismaClient(); +if (process.env.NODE_ENV !== "production") globalThis.prisma = client; + +export default client; diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js index 0c6bca5..640c708 100644 --- a/src/pages/api/auth/[...nextauth].js +++ b/src/pages/api/auth/[...nextauth].js @@ -1,13 +1,16 @@ import NextAuth from "next-auth"; import GoogleProvider from "next-auth/providers/google"; +import prisma from "@/lib/prismadb"; +import {PrismaAdapter} from "@next-auth/prisma-adapter"; export const authOptions = { - providers: [ - GoogleProvider({ - clientId: process.env.GOOGLE_CLIENT_ID, - clientSecret: process.env.GOOGLE_CLIENT_SECRET, - }), - ], + adapter: PrismaAdapter(prisma), + providers: [ + GoogleProvider({ + clientId: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + }), + ], }; export default NextAuth(authOptions); diff --git a/src/pages/api/cron.ts b/src/pages/api/cron.ts new file mode 100644 index 0000000..be7c0a3 --- /dev/null +++ b/src/pages/api/cron.ts @@ -0,0 +1,29 @@ +import { NextApiRequest, NextApiResponse } from "next"; +import { verifySignature } from "@upstash/qstash/nextjs"; + +async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method === "POST") { + try { + res.status(200).json({ success: true }); + } catch (err) { + res.status(500).json({ + statusCode: 500, + message: err instanceof Error ? err.message : "Unknown error occurred", + }); + } + } else { + res.setHeader("Allow", "POST"); + res.status(405).end("Method Not Allowed"); + } +} + +export default verifySignature(handler, { + currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY, + nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY, +}); + +export const config = { + api: { + bodyParser: false, + }, +}; diff --git a/src/pages/api/shows/upcoming.ts b/src/pages/api/shows/upcoming.ts index bbb99ed..617f1d3 100644 --- a/src/pages/api/shows/upcoming.ts +++ b/src/pages/api/shows/upcoming.ts @@ -38,7 +38,12 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) { if (result.data.items.length) { res.send(JSON.stringify({ events: result.data.items })); } else { - res.send(JSON.stringify({ message: "No upcoming events found." })); + res.send( + JSON.stringify({ + events: [], + message: "No upcoming events.", + }) + ); } } } diff --git a/yarn.lock b/yarn.lock index 888af50..b0c47d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,6 +9,11 @@ dependencies: regenerator-runtime "^0.13.11" +"@deno/shim-crypto@~0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@deno/shim-crypto/-/shim-crypto-0.3.1.tgz#416155b2b6f9ad728f80ebcb422c803efc1023c2" + integrity sha512-ed4pNnfur6UbASEgF34gVxR9p7Mc3qF+Ygbmjiil8ws5IhNFhPDFy5vE5hQAUA9JmVsSxXPcVLM5Rf8LOZqQ5Q== + "@eslint/eslintrc@^1.4.1": version "1.4.1" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" @@ -53,6 +58,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@next-auth/prisma-adapter@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@next-auth/prisma-adapter/-/prisma-adapter-1.0.5.tgz#41a2fc7b44907054b81d456b426164e58becf4ed" + integrity sha512-VqMS11IxPXrPGXw6Oul6jcyS/n8GLOWzRMrPr3EMdtD6eOalM6zz05j08PcNiis8QzkfuYnCv49OvufTuaEwYQ== + "@next/env@13.1.5": version "13.1.5" resolved "https://registry.yarnpkg.com/@next/env/-/env-13.1.5.tgz#72b24d3726a6b752be6b7b9a937f7af31b3ce410" @@ -173,6 +183,23 @@ tiny-glob "^0.2.9" tslib "^2.4.0" +"@prisma/client@^4.9.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.9.0.tgz#4a4068f3540732ea5723c008d49ed684d20f9340" + integrity sha512-bz6QARw54sWcbyR1lLnF2QHvRW5R/Jxnbbmwh3u+969vUKXtBkXgSgjDA85nji31ZBlf7+FrHDy5x+5ydGyQDg== + dependencies: + "@prisma/engines-version" "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5" + +"@prisma/engines-version@4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5": + version "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5.tgz#9d817a5779fc05b107eb02f63d197ad296d60b3c" + integrity sha512-M16aibbxi/FhW7z1sJCX8u+0DriyQYY5AyeTH7plQm9MLnURoiyn3CZBqAyIoQ+Z1pS77usCIibYJWSgleBMBA== + +"@prisma/engines@4.9.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.9.0.tgz#05a1411964e047c1bc43f777c7a1c69f86a2a26c" + integrity sha512-t1pt0Gsp+HcgPJrHFc+d/ZSAaKKWar2G/iakrE07yeKPNavDP3iVKPpfXP22OTCHZUWf7OelwKJxQgKAm5hkgw== + "@rushstack/eslint-patch@^1.1.3": version "1.2.0" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728" @@ -265,6 +292,13 @@ "@typescript-eslint/types" "5.49.0" eslint-visitor-keys "^3.3.0" +"@upstash/qstash@^0.3.6": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@upstash/qstash/-/qstash-0.3.6.tgz#1407f6f6fc1785d21497d31cbaf0a771946fa59c" + integrity sha512-NKN4jbPhB5lfHoSIaU7AuQ3F+yGS20e/FBRiUuPetcKoi354wHhKj9AJFfkFT5SSeLq0XEsXRNynm8gqCS4HjQ== + dependencies: + "@deno/shim-crypto" "~0.3.0" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -2169,6 +2203,13 @@ pretty-format@^3.8.0: resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385" integrity sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew== +prisma@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.9.0.tgz#295954b2a89cd35a0e6bcf66b2b036dbf80c75ee" + integrity sha512-bS96oZ5oDFXYgoF2l7PJ3Mp1wWWfLOo8B/jAfbA2Pn0Wm5Z/owBHzaMQKS3i1CzVBDWWPVnOohmbJmjvkcHS5w== + dependencies: + "@prisma/engines" "4.9.0" + prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"