diff --git a/.gitignore b/.gitignore index b12bf67..34811c7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ package-lock.json .env .env.local .vscode +.vercel .prisma \ No newline at end of file diff --git a/README.md b/README.md index f3c24b2..a84069d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # 🚩 **RevBots:- Rev Revolt Bots...** > RevBots is a Revolt bot list website that allows users to showcase their Revolt bots. This repository contains the code for both the ` RevBots ` website and the ` RevBot ` Discord bot. -⚠️ **Website Currently Using Non-Production Database** +⚠️ **Website Currently Using Non-Production Vercel Storage Database** --- --- @@ -26,7 +26,7 @@ Welcome to RevBots, a Revolt bot list website showcasing a collection of powerfu - Explore detailed bot profiles with descriptions, owner, socials etc. - Easily add bots to your Revolt server with just a click - Add your own bot easily -- Safe authentication system with Revolt API +- Authentication system with Revolt API - Better and Modern UI - Easy to explore and search @@ -82,9 +82,6 @@ Visit the [Live Preview](https://rev-bots-tau.vercel.app) to explore RevBots and ## 🧮 License RevBots and RevBot are both licensed under the ISC License. See the [LICENSE](LICENSE) file for more details. -## ⚡ Version -Latest version for **"RevBots"** repo is **` v0.1.1 `** - > _💫 Feel free to explore, contribute, and enjoy the world of RevBots and RevBot! And don't forget to give a star to this repo..._ --- diff --git a/bot/package.json b/bot/package.json index 187ff13..e85627e 100644 --- a/bot/package.json +++ b/bot/package.json @@ -1,6 +1,6 @@ { "name": "revbots-bot", - "version": "0.1.1", + "version": "0.1.3", "description": "Bot for Rev Bots Site!", "main": "index.js", "scripts": { diff --git a/package.json b/package.json index c48bb51..ffb1c6b 100644 --- a/package.json +++ b/package.json @@ -1,128 +1,7 @@ { "name": "revbots", - "version": "0.1.1", + "version": "0.1.3", "description": "Mono repo of RevBot's Bot and Website", - "dependencies": { - "acorn": "^8.8.2", - "acorn-jsx": "^5.3.2", - "astring": "^1.8.4", - "bail": "^2.0.2", - "busboy": "^1.6.0", - "ccount": "^2.0.1", - "character-entities": "^2.0.2", - "character-entities-html4": "^2.1.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.1", - "comma-separated-tokens": "^2.0.3", - "debug": "^4.3.4", - "decode-named-character-reference": "^1.0.2", - "dequal": "^2.0.3", - "diff": "^5.1.0", - "esbuild": "^0.17.18", - "estree-util-attach-comments": "^2.1.1", - "estree-util-build-jsx": "^2.2.2", - "estree-util-is-identifier-name": "^2.1.0", - "estree-util-to-js": "^1.2.0", - "estree-util-visit": "^1.2.1", - "estree-walker": "^3.0.3", - "extend": "^3.0.2", - "globrex": "^0.1.2", - "hast-util-to-estree": "^2.3.2", - "hast-util-whitespace": "^2.0.1", - "inline-style-parser": "^0.1.1", - "is-alphabetical": "^2.0.1", - "is-alphanumerical": "^2.0.1", - "is-buffer": "^2.0.5", - "is-decimal": "^2.0.1", - "is-hexadecimal": "^2.0.1", - "is-plain-obj": "^4.1.0", - "is-reference": "^3.0.1", - "kleur": "^4.1.5", - "longest-streak": "^3.1.0", - "markdown-extensions": "^1.1.1", - "mdast-util-definitions": "^5.1.2", - "mdast-util-from-markdown": "^1.3.0", - "mdast-util-mdx": "^2.0.1", - "mdast-util-mdx-expression": "^1.3.2", - "mdast-util-mdx-jsx": "^2.1.2", - "mdast-util-mdxjs-esm": "^1.3.1", - "mdast-util-phrasing": "^3.0.1", - "mdast-util-to-hast": "^12.3.0", - "mdast-util-to-markdown": "^1.5.0", - "mdast-util-to-string": "^3.2.0", - "micromark": "^3.1.0", - "micromark-core-commonmark": "^1.0.6", - "micromark-extension-mdx-expression": "^1.0.4", - "micromark-extension-mdx-jsx": "^1.0.3", - "micromark-extension-mdx-md": "^1.0.1", - "micromark-extension-mdxjs": "^1.0.0", - "micromark-extension-mdxjs-esm": "^1.0.3", - "micromark-factory-destination": "^1.0.0", - "micromark-factory-label": "^1.0.2", - "micromark-factory-mdx-expression": "^1.0.7", - "micromark-factory-space": "^1.0.0", - "micromark-factory-title": "^1.0.2", - "micromark-factory-whitespace": "^1.0.0", - "micromark-util-character": "^1.1.0", - "micromark-util-chunked": "^1.0.0", - "micromark-util-classify-character": "^1.0.0", - "micromark-util-combine-extensions": "^1.0.0", - "micromark-util-decode-numeric-character-reference": "^1.0.0", - "micromark-util-decode-string": "^1.0.2", - "micromark-util-encode": "^1.0.1", - "micromark-util-events-to-acorn": "^1.2.1", - "micromark-util-html-tag-name": "^1.1.0", - "micromark-util-normalize-identifier": "^1.0.0", - "micromark-util-resolve-all": "^1.0.0", - "micromark-util-sanitize-uri": "^1.1.0", - "micromark-util-subtokenize": "^1.0.2", - "micromark-util-symbol": "^1.0.1", - "micromark-util-types": "^1.0.2", - "mri": "^1.2.0", - "ms": "^2.1.2", - "nanoid": "^3.3.6", - "node-bin-setup": "^1.1.3", - "parse-entities": "^4.0.1", - "periscopic": "^3.1.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "property-information": "^6.2.0", - "remark-mdx": "^2.3.0", - "remark-parse": "^10.0.1", - "remark-rehype": "^10.1.0", - "rollup": "^3.21.6", - "sade": "^1.8.1", - "source-map": "^0.7.4", - "source-map-js": "^1.0.2", - "space-separated-tokens": "^2.0.2", - "streamsearch": "^1.1.0", - "stringify-entities": "^4.0.3", - "style-to-object": "^0.4.1", - "trim-lines": "^3.0.1", - "trough": "^2.1.0", - "tsconfck": "^2.1.1", - "undici": "^5.22.1", - "unified": "^10.1.2", - "unist-util-generated": "^2.0.1", - "unist-util-is": "^5.2.1", - "unist-util-position": "^4.0.4", - "unist-util-position-from-estree": "^1.1.2", - "unist-util-remove-position": "^4.0.2", - "unist-util-stringify-position": "^3.0.3", - "unist-util-visit": "^4.1.2", - "unist-util-visit-parents": "^5.1.3", - "uvu": "^0.5.6", - "vfile": "^5.3.7", - "vfile-location": "^4.1.0", - "vfile-message": "^3.1.4", - "vite": "^4.3.5", - "vite-tsconfig-paths": "^4.2.0", - "zod": "^3.21.4", - "zwitch": "^2.0.4" - }, - "devDependencies": { - "node": "^20.2.0" - }, "repository": { "type": "git", "url": "git+https://github.com/ArnavK-09/RevBots.git" @@ -132,7 +11,5 @@ "bugs": { "url": "https://github.com/ArnavK-09/RevBots/issues" }, - "homepage": "https://github.com/ArnavK-09/RevBots#readme", - "main": "index.js", - "keywords": [] + "homepage": "https://github.com/ArnavK-09/RevBots#readme" } diff --git a/website/package.json b/website/package.json index 2fec6e1..cdba4d1 100644 --- a/website/package.json +++ b/website/package.json @@ -1,6 +1,6 @@ { "name": "revbots-site", - "version": "0.1.1", + "version": "0.1.3", "description": "Website for Rev Bots!", "author": "ArnavK-09", "license": "ISC", @@ -18,8 +18,9 @@ "@iconify/svelte": "^3.1.3", "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/adapter-vercel": "^3.0.0", - "@sveltejs/kit": "^1.5.0", + "@sveltejs/kit": "^1.20.3", "@types/crypto-js": "^4.1.1", + "@types/ms": "^0.7.31", "@types/showdown": "^2.0.1", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", @@ -42,10 +43,12 @@ "dependencies": { "@prisma/client": "^4.15.0", "@tailwindcss/forms": "^0.5.3", - "@types/node": "^20.2.5", + "@types/node": "^20.3.1", "axios": "^1.4.0", "crypto-js": "^4.1.1", - "dotenv": "^16.0.3", - "showdown": "^2.1.0" + "dotenv": "^16.3.0", + "ms": "^2.1.3", + "showdown": "^2.1.0", + "tiny-glob": "^0.2.9" } } diff --git a/website/prisma/schema.prisma b/website/prisma/schema.prisma index e8ac460..7d478f8 100644 --- a/website/prisma/schema.prisma +++ b/website/prisma/schema.prisma @@ -1,6 +1,4 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - +// Base Prisma generator client { provider = "prisma-client-js" previewFeatures = ["fullTextSearch"] @@ -11,14 +9,17 @@ datasource db { url = env("DB_URL") } +// Models model User { - id String @id @default(uuid()) @db.Uuid - username String @unique - identifier String @unique - avatar String @default("/logo.png") - verified Boolean @default(false) - createdAt DateTime @default(now()) - bots Bot[] + id String @id @default(uuid()) @db.Uuid + username String + discriminator String + identifier String @unique + avatar String @default("/logo.png") + verified Boolean @default(false) + createdAt DateTime @default(now()) + bots Bot[] + vote_timers Vote[] } model Bot { @@ -34,14 +35,34 @@ model Bot { support String? github String invite String - username String @unique + username String identifier String @unique + discriminator String publishedOn DateTime @default(now()) prefix String status BotStatus @default(PENDING) promoted Boolean @default(false) + active_votes Vote[] +} + +model Request { + code String @id @unique @default("CODE") + status Boolean @default(false) + user String @unique +} + +model Vote { + voter User @relation(fields: [voterIdentifier], references: [identifier], onDelete: Cascade) + voterIdentifier String + bot Bot @relation(fields: [botIdentifier], references: [identifier], onDelete: Cascade) + botIdentifier String + key String @unique @default(uuid()) @db.Uuid + time DateTime @default(now()) + + @@unique([botIdentifier, voterIdentifier]) } +// Enums enum Tag { ANIME FUN @@ -61,9 +82,3 @@ enum BotStatus { DEPRECATED PENDING } - -model Request { - code String @id @unique @default("CODE") - status Boolean @default(false) - user String @unique -} diff --git a/website/src/app.html b/website/src/app.html index 8f09dd7..3423abd 100644 --- a/website/src/app.html +++ b/website/src/app.html @@ -3,6 +3,7 @@
+ %sveltekit.head% diff --git a/website/src/global.css b/website/src/global.css index 9f1f5cd..5a4d439 100644 --- a/website/src/global.css +++ b/website/src/global.css @@ -14,7 +14,7 @@ body { /* no scroll bar */ @layer utilities { - @variants responsive { + @layer components { /* Hide scrollbar for Chrome, Safari and Opera */ .no-scrollbar::-webkit-scrollbar { display: none; diff --git a/website/src/lib/components/Botpage/Header.svelte b/website/src/lib/components/Botpage/Header.svelte index cac88ca..397bc08 100644 --- a/website/src/lib/components/Botpage/Header.svelte +++ b/website/src/lib/components/Botpage/Header.svelte @@ -4,9 +4,10 @@ // props export let name = 'Revolt Name'; - export let description = 'Bot Description'; + export let description = 'No Bot Description Provided...'; export let id = 0; export let avatar = '/favicon.png'; + export let actions = true;{description}
{/if} -
Server ID: #{bot.id}
@@ -46,7 +46,7 @@
Short Description: {bot.shortDescription ?? 'No Short Description'}
+
{bot.description}
diff --git a/website/src/routes/api/+server.ts b/website/src/routes/(backend)/api/+server.ts similarity index 95% rename from website/src/routes/api/+server.ts rename to website/src/routes/(backend)/api/+server.ts index ac48a6d..2522e2c 100644 --- a/website/src/routes/api/+server.ts +++ b/website/src/routes/(backend)/api/+server.ts @@ -2,7 +2,7 @@ import { json } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; import os from 'os'; -import { version as appVersion } from '../../../package.json'; +import { version as appVersion } from '../../../../package.json'; import { version as svelteKitVersion } from '@sveltejs/kit/package.json'; import { version as prismaV } from '@prisma/client/package.json'; diff --git a/website/src/routes/api/auth/+server.ts b/website/src/routes/(backend)/api/auth/+server.ts similarity index 95% rename from website/src/routes/api/auth/+server.ts rename to website/src/routes/(backend)/api/auth/+server.ts index b367c2c..ada7835 100644 --- a/website/src/routes/api/auth/+server.ts +++ b/website/src/routes/(backend)/api/auth/+server.ts @@ -3,7 +3,7 @@ import { error, json, redirect } from '@sveltejs/kit'; import DB from '$lib/server/database'; import type { RequestHandler } from './$types'; import { encrypt } from '$lib/server/modules/JWA'; -import axios from 'axios'; +import axios, { type AxiosResponse } from 'axios'; import { env } from '$env/dynamic/private'; /* Helper functions*/ @@ -114,21 +114,21 @@ export const GET = async ({ url, cookies }: any) => { // if user not exist if (!user) { // fetch revolt user data - const revoltUserData: any = await axios + const revoltUserData: AxiosResponse = await axios .get(`https://api.revolt.chat/users/${requestOnDB.user}`, { headers: { 'X-Bot-Token': env.BOT_TOKEN } }) - .catch((e) => { - console.log(e, env.BOT_TOKEN); + .catch(() => { throw error(403, { message: 'Unable to fetch revolt profile' }); }); // create user const userData: any = { avatar: `https://autumn.revolt.chat/avatars/${revoltUserData.data.avatar._id}/${revoltUserData.data.avatar.filename}`, identifier: requestOnDB.user, - username: revoltUserData.data.username + username: revoltUserData.data.username, + discriminator: revoltUserData.data.discriminator }; const createdUser = await DB.user.create({ data: userData }).catch(() => { throw error(500, { message: 'Error in creating new user' }); diff --git a/website/src/routes/api/bots/+server.ts b/website/src/routes/(backend)/api/bots/+server.ts similarity index 100% rename from website/src/routes/api/bots/+server.ts rename to website/src/routes/(backend)/api/bots/+server.ts diff --git a/website/src/routes/api/bots/[id]/+server.ts b/website/src/routes/(backend)/api/bots/[id]/+server.ts similarity index 96% rename from website/src/routes/api/bots/[id]/+server.ts rename to website/src/routes/(backend)/api/bots/[id]/+server.ts index ad2e776..db6d3b7 100644 --- a/website/src/routes/api/bots/[id]/+server.ts +++ b/website/src/routes/(backend)/api/bots/[id]/+server.ts @@ -9,7 +9,7 @@ export const GET = (async ({ params }: any) => { const selectedBot = await DB.bot .findUnique({ where: { - username: params.id + identifier: params.id } }) .catch(() => { diff --git a/website/src/routes/(backend)/api/bots/[id]/vote/+server.ts b/website/src/routes/(backend)/api/bots/[id]/vote/+server.ts new file mode 100644 index 0000000..b8bcb67 --- /dev/null +++ b/website/src/routes/(backend)/api/bots/[id]/vote/+server.ts @@ -0,0 +1,68 @@ +// imports +import { json, error } from '@sveltejs/kit'; +import DB from '$lib/server/database'; +import type { RequestHandler } from './$types'; +import { decrypt } from '$lib/server/modules/JWA'; +import ms from 'ms'; + +// helper function +function userCanVote(vote: any) { + const result = 86400000 - (Date.now() - new Date(vote.time).getTime()); + const fmtRes = ms(result, { long: true }); + if (result <= 0 || fmtRes.includes('-')) + return { + status: true, + time_left: 'Time to vote now' + }; + return { + status: false, + time_left: fmtRes + }; +} + +// GET /api/bots/[id]/vote +export const GET = (async ({ params, cookies }: any) => { + // data + const botID = params.id; + const voterID: any = decrypt(cookies.get('revAuth')); + + // validate + if (!botID) { + throw error(400, { message: 'Missing Params' }); + } + // get user + const voter = await DB.user + .findUnique({ + where: { + id: voterID + } + }) + .catch(() => { + throw error(500, { message: 'Unable to contact database' }); + }); + if (!voter) { + throw error(401, { message: 'No user found' }); + } + // get pending req + const pendingRequest = await DB.vote + .findFirst({ + where: { + botIdentifier: botID, + voterIdentifier: voter.identifier + } + }) + .catch(() => { + throw error(500, { message: 'Unable to contact database' }); + }); + if (pendingRequest) { + return json({ vote: pendingRequest, can_vote: userCanVote(pendingRequest) }); + } + // if not pending req + return json({ + vote: null, + can_vote: { + status: true, + time_left: 'Time to vote now' + } + }); +}) satisfies RequestHandler; diff --git a/website/src/routes/api/me/+server.ts b/website/src/routes/(backend)/api/me/+server.ts similarity index 100% rename from website/src/routes/api/me/+server.ts rename to website/src/routes/(backend)/api/me/+server.ts diff --git a/website/src/routes/api/me/bots/+server.ts b/website/src/routes/(backend)/api/me/bots/+server.ts similarity index 84% rename from website/src/routes/api/me/bots/+server.ts rename to website/src/routes/(backend)/api/me/bots/+server.ts index 604c903..4001f6e 100644 --- a/website/src/routes/api/me/bots/+server.ts +++ b/website/src/routes/(backend)/api/me/bots/+server.ts @@ -3,7 +3,7 @@ import type { RequestHandler } from './$types'; import { json, error } from '@sveltejs/kit'; import DB from '$lib/server/database'; import { decrypt } from '$lib/server/modules/JWA'; -import axios from 'axios'; +import axios, { type AxiosResponse } from 'axios'; import { env } from '$env/dynamic/private'; // GET /api/me/bots @@ -12,7 +12,7 @@ export const GET = (async ({ cookies }) => { const auth: string | null = decrypt(cookies.get('revAuth')); // if if (!auth) { - throw error(401, { message: 'No auth?' }); + throw error(401, { message: 'No auth provided' }); } // get user bots @@ -49,24 +49,28 @@ export const POST = (async ({ request, cookies }) => { throw error(400, { message: 'Invalid Github Repo' }); } // check if bot exists - const botOnDB = await DB.bot.findUnique({ - where: { - identifier: data.identifier.trim().toUpperCase() - } - }); + const botOnDB = await DB.bot + .findUnique({ + where: { + identifier: data.identifier.trim().toUpperCase() + } + }) + .catch(() => { + throw error(500, { message: 'Unable to contact database' }); + }); if (botOnDB) { return json(botOnDB); } // fetch username - const bot = await axios + const bot: AxiosResponse = await axios .get(`https://api.revolt.chat/bots/${data.identifier.toString()}/invite`) .catch(() => { throw error(406, { message: 'Unable to fetch bot on revolt' }); }); // fetch revolt bot data - const revoltBotData = await axios + const revoltBotData: AxiosResponse = await axios .get(`https://api.revolt.chat/users/${data.identifier.toUpperCase()}`, { headers: { 'X-Bot-Token': env.BOT_TOKEN @@ -81,10 +85,10 @@ export const POST = (async ({ request, cookies }) => { if (revoltBotData.data.avatar) { avatar = `https://autumn.revolt.chat/avatars/${revoltBotData.data.avatar._id}/${revoltBotData.data.avatar.filename}`; } - // create bot - const botData = { + const botData: any = { username: bot.data.username, + discriminator: revoltBotData.data.discriminator, identifier: data.identifier, avatar: avatar, description: data.longDescription, @@ -102,8 +106,7 @@ export const POST = (async ({ request, cookies }) => { .create({ data: botData }) - .catch((err) => { - console.log(err); + .catch(() => { throw error(500, { message: 'Unable to create bot' }); }); diff --git a/website/src/routes/api/search/bots/+server.ts b/website/src/routes/(backend)/api/search/bots/+server.ts similarity index 100% rename from website/src/routes/api/search/bots/+server.ts rename to website/src/routes/(backend)/api/search/bots/+server.ts diff --git a/website/src/routes/api/tags/+server.ts b/website/src/routes/(backend)/api/tags/+server.ts similarity index 100% rename from website/src/routes/api/tags/+server.ts rename to website/src/routes/(backend)/api/tags/+server.ts diff --git a/website/src/routes/me/+layout.svelte b/website/src/routes/(frontend)/@me/+layout.svelte similarity index 100% rename from website/src/routes/me/+layout.svelte rename to website/src/routes/(frontend)/@me/+layout.svelte diff --git a/website/src/routes/me/+page.svelte b/website/src/routes/(frontend)/@me/+page.svelte similarity index 86% rename from website/src/routes/me/+page.svelte rename to website/src/routes/(frontend)/@me/+page.svelte index 730c5f3..8ca064e 100644 --- a/website/src/routes/me/+page.svelte +++ b/website/src/routes/(frontend)/@me/+page.svelte @@ -26,7 +26,7 @@ }); -No Bio Set...