diff --git a/api/index.js b/api/index.js deleted file mode 100644 index a8c1337..0000000 --- a/api/index.js +++ /dev/null @@ -1,106 +0,0 @@ -import axios from 'axios' - -import connectToDatabase from '../lib/dbConnect' - -export default async (req, res) => { - const { method } = req - const db = await connectToDatabase() - - switch (method) { - case 'POST': - if (!req.body || !req.body.url || !req.body.cluster) { - return res.status(400).json( - { - success: false, - message: 'Invalid body' - } - ) - } - - try { - await axios.get(req.body.url) - } catch { - return res.status(400).json( - { - success: false, - message: 'Invalid URL' - } - ) - } - - try { - await db.coll.insertOne( - { - _id: req.body.url, - cluster: req.body.cluster - } - ) - } catch { - return res.status(400).json( - { - success: false, - message: 'Error Inserting to DB' - } - ) - } - - res.status(200).json( - { - success: true, - url: req.body.url - } - ) - - break - case 'DELETE': - if (!req.query.url) { - return res.status(400).json( - { - success: false, - message: 'Invalid body' - } - ) - } - - try { - const { deletedCount } = await db.coll.deleteOne( - { - _id: req.query.url - } - ) - - if (deletedCount == 0) { - return res.status(400).json( - { - success: false, - message: 'Not Found' - } - ) - } - } catch { - return res.status(400).json( - { - success: false, - message: 'Error Deleting from DB' - } - ) - } - - res.status(200).json( - { - success: true, url: - req.query.url - } - ) - - break - default: - res.status(404).json( - { - success: false - } - ) - - break - } -} diff --git a/api/index.ts b/api/index.ts new file mode 100644 index 0000000..db88e18 --- /dev/null +++ b/api/index.ts @@ -0,0 +1,111 @@ +import { VercelRequest, VercelResponse } from '@vercel/node' +import axios from 'axios' +import dbConnect from '../lib/dbConnect' +import URLModel from '../lib/schema' + +export default async (request: VercelRequest, response: VercelResponse) => { + const { method } = request + const db = await dbConnect() + + switch (method) { + case 'POST': + if (!request.body || !request.body.url) { + return response.status(400).json( + { + success: false, + message: 'Invalid body' + } + ) + } + + try { + await axios.get(request.body.url) + } catch (err) { + return response.status(400).json( + { + success: false, + message: 'Invalid URL' + } + ) + } + + try { + const url = new URLModel({ + url: request.body.url + }) + + await url.save() + + return response.status(200).json( + { + success: true, + url: request.body.url + } + ) + } catch (err) { + console.log(err) + return response.status(400).json( + { + success: false, + message: 'Error Inserting to DB' + } + ) + } + + break + case 'DELETE': + if (!request.query.url) { + return response.status(400).json( + { + success: false, + message: 'Invalid body' + } + ) + } + + try { + const url = request.query.url + + if (typeof url != "string") { + return response.status(400).json( + { + success: false, + message: 'Query URL isn\'t string' + } + ) + } + + await URLModel.deleteOne({ + url + }) + + return response.status(200).json( + { + success: true, + message: 'Deleted!', + url + } + ) + } catch (err) { + console.log(err) + return response.status(400).json( + { + success: false, + message: 'Error Deleting from DB' + } + ) + } + + break + default: + const urls = await URLModel.find() + + response.status(200).json( + { + db: urls + } + ) + + break + } +} diff --git a/lib/dbConnect.js b/lib/dbConnect.js deleted file mode 100644 index 53c0d97..0000000 --- a/lib/dbConnect.js +++ /dev/null @@ -1,35 +0,0 @@ -import { MongoClient } from 'mongodb' - -const { MONGODB_URI, MONGODB_DB, MONGODB_COLLECTION } = process.env - -let cached = global.mongo - -if (!cached) { - cached = global.mongo = { - conn: null, - promise: null - } -} - -export default async function connectToDatabase() { - if (cached.conn) - return cached.conn - - if (!cached.promise) { - const opts = { - useNewUrlParser: true, - useUnifiedTopology: true, - } - - cached.promise = await MongoClient.connect(MONGODB_URI, opts).then(client => { - return { - client, - coll: client.db(MONGODB_DB).collection(MONGODB_COLLECTION), - } - }) - } - - cached.conn = await cached.promise - - return cached.conn -} diff --git a/lib/dbConnect.ts b/lib/dbConnect.ts new file mode 100644 index 0000000..81f590a --- /dev/null +++ b/lib/dbConnect.ts @@ -0,0 +1,29 @@ +import { connect } from "mongoose" + +interface CachedMongo { + conn: typeof import("mongoose") + promise: Promise +} + +const { MONGODB_URI, MONGODB_DB, MONGODB_COLLECTION } = process.env + +let cached: CachedMongo = global.mongo + +if (!cached) { + cached = global.mongo = { + conn: null, + promise: null + } +} + +export default async function dbConnect() { + if (cached.conn) + return cached.conn + + if (!cached.promise) + cached.promise = connect(MONGODB_URI) + + cached.conn = await cached.promise + + return cached.conn +} diff --git a/lib/schema.ts b/lib/schema.ts new file mode 100644 index 0000000..636e91f --- /dev/null +++ b/lib/schema.ts @@ -0,0 +1,23 @@ +import { model, models, Schema } from "mongoose" + +interface URL { + url: string +} + +const schema = new Schema({ + url: { + type: String, + required: true, + unique: true + } +}) + +schema.path('url').validate(async function(value) { + const count = await models.URL.countDocuments({ url: value }) + + return !count +}, 'URL already exists') + +const URLModel = model('URL', schema) + +export = URLModel diff --git a/package.json b/package.json index 6ba9836..b47fbea 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "gatsby-plugin-sass": "4.13.0", "gatsby-plugin-transition-link": "1.20.5", "gsap": "3.7.1", - "mongodb": "4.1.1", + "mongoose": "^6.0.5", "prop-types": "15.7.2", "react": "17.0.2", "react-dom": "17.0.2", @@ -33,6 +33,8 @@ "sass": "1.39.0" }, "devDependencies": { + "@types/mongoose": "^5.11.97", + "@vercel/node": "^1.12.1", "eslint": "7.32.0", "eslint-plugin-react": "7.25.1" } diff --git a/src/pages/delete.js b/src/pages/delete.js index b8de109..0d59f05 100644 --- a/src/pages/delete.js +++ b/src/pages/delete.js @@ -36,7 +36,7 @@ const DeleteURLPage = () => { success: { delay: 500, render({ data: { data } }) { - return `Deleted ${data.url}!` + return `If URL: ${data.url} existed, it has been deleted!` } }, error: { diff --git a/yarn.lock b/yarn.lock index 0d4b795..6adb759 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1598,6 +1598,13 @@ dependencies: "@types/node" "*" +"@types/mongoose@^5.11.97": + version "5.11.97" + resolved "https://registry.yarnpkg.com/@types/mongoose/-/mongoose-5.11.97.tgz#80b0357f3de6807eb597262f52e49c3e13ee14d8" + integrity sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q== + dependencies: + mongoose "*" + "@types/node-fetch@2": version "2.5.12" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" @@ -1776,6 +1783,15 @@ "@typescript-eslint/types" "4.30.0" eslint-visitor-keys "^2.0.0" +"@vercel/node@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@vercel/node/-/node-1.12.1.tgz#15f42f64690f904f8a52a387123ce0958657060f" + integrity sha512-NcawIY05BvVkWlsowaxF2hl/hJg475U8JvT2FnGykFPMx31q1/FtqyTw/awSrKfOSRXR0InrbEIDIelmS9NzPA== + dependencies: + "@types/node" "*" + ts-node "8.9.1" + typescript "4.3.4" + "@webassemblyjs/ast@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" @@ -2571,7 +2587,7 @@ browserslist@^4.0.0, browserslist@^4.12.2, browserslist@^4.14.5, browserslist@^4 escalade "^3.1.1" node-releases "^1.1.73" -bson@^4.5.1: +bson@^4.2.2, bson@^4.5.1: version "4.5.1" resolved "https://registry.yarnpkg.com/bson/-/bson-4.5.1.tgz#02e9d649ce017ab14ed258737756c11809963d6c" integrity sha512-XqFP74pbTVLyLy5KFxVfTUyRrC1mgOlmu/iXHfXqfCKT59jyP9lwbotGfbN59cHBRbJSamZNkrSopjv+N0SqAA== @@ -3403,6 +3419,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: dependencies: ms "2.0.0" +debug@4.x, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@~4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + debug@^3.0.0, debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -3410,13 +3433,6 @@ debug@^3.0.0, debug@^3.1.0, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@~4.3.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -3510,9 +3526,9 @@ delegates@^1.0.0: integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= denque@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.0.tgz#773de0686ff2d8ec2ff92914316a47b73b1c73de" - integrity sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ== + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== depd@~1.1.2: version "1.1.2" @@ -6351,6 +6367,11 @@ jsonfile@^4.0.0: array-includes "^3.1.2" object.assign "^4.1.2" +kareem@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.2.tgz#78c4508894985b8d38a0dc15e1a8e11078f2ca93" + integrity sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ== + keyv@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" @@ -7047,6 +7068,35 @@ mongodb@4.1.1: optionalDependencies: saslprep "^1.0.0" +mongoose@*, mongoose@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-6.0.5.tgz#42648005d13b49261c757607d1f23761b59a610d" + integrity sha512-1MoG52oosjEK8z45DHQVbakP6DJG1sbQI/ZASBW8sZRV+rCaG/pC3L3wWjrsiped/2+uhvanWM9C89F2n6bQ3w== + dependencies: + bson "^4.2.2" + kareem "2.3.2" + mongodb "4.1.1" + mpath "0.8.4" + mquery "4.0.0" + ms "2.1.2" + regexp-clone "1.0.0" + sift "13.5.2" + sliced "1.0.1" + +mpath@0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.4.tgz#6b566d9581621d9e931dd3b142ed3618e7599313" + integrity sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g== + +mquery@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-4.0.0.tgz#6c62160ad25289e99e0840907757cdfd62bde775" + integrity sha512-nGjm89lHja+T/b8cybAby6H0YgA4qYC/lx6UlwvHGqvTq8bDaNeCwl1sY8uRELrNbVWJzIihxVd+vphGGn1vBw== + dependencies: + debug "4.x" + regexp-clone "^1.0.0" + sliced "1.0.1" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -8491,6 +8541,11 @@ regex-parser@^2.2.11: resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== +regexp-clone@1.0.0, regexp-clone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" + integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== + regexp.prototype.flags@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" @@ -9035,6 +9090,11 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +sift@13.5.2: + version "13.5.2" + resolved "https://registry.yarnpkg.com/sift/-/sift-13.5.2.tgz#24a715e13c617b086166cd04917d204a591c9da6" + integrity sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA== + signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -9087,6 +9147,11 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" +sliced@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" + integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= + slugify@^1.4.4: version "1.6.0" resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.0.tgz#6bdf8ed01dabfdc46425b67e3320b698832ff893" @@ -9799,6 +9864,17 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-2.2.1.tgz#c5bf04a5bbec3fd118be4084461b3a27c4d796bf" integrity sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q== +ts-node@8.9.1: + version "8.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.9.1.tgz#2f857f46c47e91dcd28a14e052482eb14cfd65a5" + integrity sha512-yrq6ODsxEFTLz0R3BX2myf0WBCSQh9A+py8PBo1dCzWIOcvisbyH6akNKqDHMgXePF2kir5mm5JXJTH3OUJYOQ== + dependencies: + arg "^4.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + ts-node@^9: version "9.1.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" @@ -9916,6 +9992,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.4.tgz#3f85b986945bcf31071decdd96cf8bfa65f9dcbc" + integrity sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew== + unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"