Browse Source

refactor: added mongoose

hover-contact
ntasicc 3 years ago
parent
commit
4f8e6a406d

+ 33
- 0
models/person.js View File

const mongoose = require('mongoose');

const PersonSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please provide a name.'],
maxlength: [60, 'Name cannot be more than 60 characters'],
trim: true,
},
age: {
type: Number,
required: [true, 'Please provide an age.'],
validate(value) {
if (value < 0) {
throw new Error('Age must be a postive number');
}
},
},
gender: {
type: String,
required: [true, 'Please provide a gender.'],
trim: true,
},
customID: {
type: String,
required: true,
unique: true,
},
});

const Person = mongoose.models.Person || mongoose.model('Person', PersonSchema);

module.exports = Person;

+ 75
- 0
models/user.js View File

import {
hashPassword,
verifyPassword,
} from '../utils/helpers/hashPasswordHelpers';

const mongoose = require('mongoose');
const validator = require('validator');

const UserSchema = new mongoose.Schema({
fullName: {
type: String,
required: [true, 'Please provide a name.'],
maxlength: [60, 'Name cannot be more than 60 characters'],
trim: true,
},
username: {
type: String,
required: [true, 'Please provide a name.'],
maxlength: [60, 'Name cannot be more than 60 characters'],
trim: true,
unique: true,
},
email: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid');
}
},
},
password: {
type: String,
required: true,
minlength: 7,
trim: true,
validate(value) {
if (value.toLowerCase().includes('password')) {
throw new Error('Password cannot contain "password"');
}
},
},
});

UserSchema.statics.findByCredentials = async (username, password) => {
const user = await User.findOne({ username });

if (!user) {
throw new Error('Unable to login');
}

const isMatch = await verifyPassword(password, user.password);

if (!isMatch) {
throw new Error('Unable to login');
}

return user;
};

UserSchema.pre('save', async function (next) {
const user = this;

if (user.isModified('password')) {
user.password = await hashPassword(user.password);
}

next();
});

const User = mongoose.models.User || mongoose.model('User', UserSchema);
module.exports = User;

+ 2
- 0
package.json View File

"date-fns": "^2.29.1", "date-fns": "^2.29.1",
"formik": "^2.2.9", "formik": "^2.2.9",
"mongodb": "^4.8.1", "mongodb": "^4.8.1",
"mongoose": "^6.5.2",
"next": "12.2.3", "next": "12.2.3",
"next-auth": "^4.10.2", "next-auth": "^4.10.2",
"next-i18next": "^11.3.0", "next-i18next": "^11.3.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"sass": "^1.54.0", "sass": "^1.54.0",
"swr": "^1.3.0", "swr": "^1.3.0",
"validator": "^13.7.0",
"yup": "^0.32.11" "yup": "^0.32.11"
}, },
"devDependencies": { "devDependencies": {

+ 6
- 25
pages/api/auth/[...nextauth].js View File

import NextAuth from 'next-auth'; import NextAuth from 'next-auth';
import Credentials from 'next-auth/providers/credentials'; import Credentials from 'next-auth/providers/credentials';

import { connectToDatabase } from '../../../utils/helpers/dbHelpers';
import { verifyPassword } from '../../../utils/helpers/hashPasswordHelpers';
import dbConnect from '../../../utils/helpers/dbHelpers';
const User = require('../../../models/user');


export default NextAuth({ export default NextAuth({
session: { session: {
providers: [ providers: [
Credentials({ Credentials({
async authorize(credentials) { async authorize(credentials) {
const client = await connectToDatabase();

const usersCollection = client.db().collection('users');

const user = await usersCollection.findOne({
username: credentials.username,
});
await dbConnect();


if (!user) {
client.close();
throw new Error('No user found!');
}

const isValid = await verifyPassword(
credentials.password,
user.password
const user = await User.findByCredentials(
credentials.username,
credentials.password
); );

if (!isValid) {
client.close();
throw new Error('Could not log you in!');
}

client.close();
return { name: user.fullName }; return { name: user.fullName };
}, },
}), }),

+ 21
- 45
pages/api/auth/signup.js View File

import { connectToDatabase } from '../../../utils/helpers/dbHelpers';
import { hashPassword } from '../../../utils/helpers/hashPasswordHelpers';
import User from '../../../models/user';
import dbConnect from '../../../utils/helpers/dbHelpers';


async function handler(req, res) { async function handler(req, res) {
if (req.method !== 'POST') {
return;
const { method } = req;

await dbConnect();

switch (method) {
case 'POST': {
try {
const user = await User.create(req.body);
res
.status(201)
.json({ message: `User (${user.fullName}) created sucessfully!` });
} catch (error) {
res.status(400).json({ message: error.message });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
} }

const { fullName, username, email, password } = req.body;

if (
!fullName ||
!username ||
!email ||
!email.includes('@') ||
!password ||
password.trim().length < 7
) {
res.status(422).json({
message: 'Invalid input ',
});
return;
}

const client = await connectToDatabase();
const db = client.db();

const existingUser = await db
.collection('users')
.findOne({ $or: [{ email: email }, { username: username }] });

if (existingUser) {
res.status(422).json({ message: 'User exists already!' });
client.close();
return;
}

const hashedPassword = await hashPassword(password);

const result = await db.collection('users').insertOne({
fullName: fullName,
username: username,
email: email,
password: hashedPassword,
});

res.status(201).json({ message: 'Created user!', result: result });
client.close();
} }


export default handler; export default handler;

+ 51
- 34
pages/api/data.js View File

import { connectToDatabase } from '../../utils/helpers/dbHelpers';
const Person = require('../../models/person');
import dbConnect from '../../utils/helpers/dbHelpers';


async function handler(req, res) { async function handler(req, res) {
if (req.method !== 'GET') {
return;
}
const { method } = req;
await dbConnect();


const pageIndex = req.query.page; const pageIndex = req.query.page;


return; return;
} }


const client = await connectToDatabase();
const db = client.db();
switch (method) {
case 'GET': {
try {
const dataCount = await Person.countDocuments();


const dataCount = await db.collection('randomData').countDocuments();

if ((pageIndex - 1) * 4 >= dataCount) {
res.status(422).json({
message: 'Page does not exist ',
});
client.close();
return;
}
if (dataCount === 0) {
res.status(200).json({
message: 'No data.',
data: [],
dataCount: 0,
});
break;
}


const dataFromDB = await db
.collection('randomData')
.find()
.skip((pageIndex - 1) * 4)
.limit(4)
.toArray();
if ((pageIndex - 1) * 4 >= dataCount) {
throw new Error('Page does not exist!');
}


if (!dataFromDB) {
res.status(422).json({ message: 'No data!' });
client.close();
return;
}
const dataFromDB = await Person.find({})
.skip((pageIndex - 1) * 4)
.limit(4);


res.status(201).json({
message: 'Created user!',
data: dataFromDB,
dataCount: dataCount,
});
if (!dataFromDB) {
throw new Error('No data!');
}


setTimeout(() => {
client.close();
}, 1500);
res.status(200).json({
message: 'Fetched data succesfully',
data: dataFromDB,
dataCount,
});
} catch (error) {
res.status(400).json({ message: error.message });
}
break;
}
case 'POST': {
try {
const person = await Person.create(
req.body
); /* create a new model in the database */
res.status(201).json({ message: 'Created succesfully!', data: person });
} catch (error) {
res.status(400).json({ success: false });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
}
} }


export default handler; export default handler;

+ 30
- 34
pages/api/single-data/[dataId].js View File

import { connectToDatabase } from '../../../utils/helpers/dbHelpers';
const Person = require('../../../models/person');
import dbConnect from '../../../utils/helpers/dbHelpers';


async function handler(req, res) { async function handler(req, res) {
if (req.method !== 'GET') {
return;
const { method } = req;

await dbConnect();

switch (method) {
case 'GET': {
try {
const dataId = req.query.dataId;

const person = await Person.findOne({ customID: dataId });

console.log(person);
if (!person) {
throw new Error('Person with this id does not exist!');
}

res.status(200).json({
message: 'Fetch single data successfull!',
singleData: person,
});
} catch (error) {
res.status(400).json({ message: error.message });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
} }

const dataId = req.query.dataId;

let client;

try {
client = await connectToDatabase();
} catch (error) {
res.status(500).json({ message: 'Connecting to the database failed!' });
return;
}

const db = client.db();

const singleData = await db
.collection('randomData')
.findOne({ customID: dataId });

if (!singleData) {
res.status(422).json({ message: 'No data!' });
client.close();
return;
}

res.status(201).json({
message: 'Fetch single data successfull!',
singleData: singleData,
});
setTimeout(() => {
client.close();
}, 1500);
} }


export default handler; export default handler;

+ 39
- 29
pages/api/single-data/index.js View File

import { connectToDatabase } from '../../../utils/helpers/dbHelpers';
const Person = require('../../../models/person');
import dbConnect from '../../../utils/helpers/dbHelpers';


async function handler(req, res) { async function handler(req, res) {
if (req.method !== 'GET') {
return;
const { method } = req;

await dbConnect();

switch (method) {
case 'GET': {
try {
const dataCount = await Person.countDocuments();

if (dataCount === 0) {
res.status(200).json({
message: 'No data.',
dataIds: [],
});
break;
}

const dataFromDB = await Person.find({}).limit(4);

if (!dataFromDB) {
throw new Error('No data!');
}

const dataIds = dataFromDB.map((item) => item.customID);

res.status(200).json({
message: 'Fetch ids successfull!',
dataIds: dataIds,
});
} catch (error) {
res.status(400).json({ message: error.message });
}
break;
}
default:
res.status(405).json({ message: 'Method not allowed' });
break;
} }

const client = await connectToDatabase();
const db = client.db();

const dataFromDB = await db
.collection('randomData')
.find()
.limit(4)
.toArray();

if (!dataFromDB) {
res.status(422).json({ message: 'No data!' });
client.close();
return;
}

const dataIds = dataFromDB.map((item) => item.customID);

res.status(201).json({
message: 'Fetch ids successfull!',
dataIds: dataIds,
});

setTimeout(() => {
client.close();
}, 1500);
} }


export default handler; export default handler;

+ 6
- 3
pages/single-data/[dataId].js View File

import { getDataIds } from '../../requests/dataIdsRequest'; import { getDataIds } from '../../requests/dataIdsRequest';
import { getSingleData } from '../../requests/singleDataRequest'; import { getSingleData } from '../../requests/singleDataRequest';


function SignelDataPage(props) {
const SignelDataPage = (props) => {
const data = props.selectedData; const data = props.selectedData;


console.log(data);
if (!data) { if (!data) {
return <h1>No data!</h1>;
return <h1>{props.message}</h1>;
} }
return <DataDetailsCard data={data.singleData} />; return <DataDetailsCard data={data.singleData} />;
}
};


export async function getStaticProps(context) { export async function getStaticProps(context) {
const dataId = context.params.dataId; const dataId = context.params.dataId;
return { return {
props: { props: {
selectedData: null, selectedData: null,
message: error.message,
}, },
revalidate: 60, revalidate: 60,
}; };
params: { dataId: id }, params: { dataId: id },
})); }));


console.log(paths);
return { return {
paths: paths, paths: paths,
fallback: 'blocking', fallback: 'blocking',

+ 42
- 2
utils/helpers/dbHelpers.js View File

import { MongoClient } from "mongodb";
import { MongoClient } from 'mongodb';
import mongoose from 'mongoose';


export async function connectToDatabase() { export async function connectToDatabase() {
const client = await MongoClient.connect(process.env.MONGODB_AUTH);
const client = await MongoClient.connect(process.env.MONGODB_URI);


return client; return client;
} }

const MONGODB_URI = process.env.MONGODB_URI;

if (!MONGODB_URI) {
throw new Error(
'Please define the MONGODB_URI environment variable inside .env.local'
);
}

/**
* Global is used here to maintain a cached connection across hot reloads
* in development. This prevents connections growing exponentially
* during API Route usage.
*/
let cached = global.mongoose;

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

async function dbConnect() {
if (cached.conn) {
return cached.conn;
}

if (!cached.promise) {
const opts = {
bufferCommands: false,
};

cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
return mongoose;
});
}
cached.conn = await cached.promise;
return cached.conn;
}

export default dbConnect;

+ 48
- 8
yarn.lock View File

dependencies: dependencies:
ms "2.0.0" ms "2.0.0"


[email protected], debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"

debug@^3.0.0, debug@^3.2.7: debug@^3.0.0, debug@^3.2.7:
version "3.2.7" version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
dependencies: dependencies:
ms "^2.1.1" ms "^2.1.1"


debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"

decamelize-keys@^1.1.0: decamelize-keys@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1"
integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==


[email protected]:
version "2.4.1"
resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.4.1.tgz#7d81ec518204a48c1cb16554af126806c3cd82b0"
integrity sha512-aJ9opVoXroQUPfovYP5kaj2lM7Jn02Gw13bL0lg9v0V7SaUc0qavPs0Eue7d2DcC3NjqI6QAUElXNsuZSeM+EA==

kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2" version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
"@types/whatwg-url" "^8.2.1" "@types/whatwg-url" "^8.2.1"
whatwg-url "^11.0.0" whatwg-url "^11.0.0"


mongodb@^4.8.1:
[email protected], mongodb@^4.8.1:
version "4.8.1" version "4.8.1"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.8.1.tgz#596de88ff4519128266d9254dbe5b781c4005796" resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.8.1.tgz#596de88ff4519128266d9254dbe5b781c4005796"
integrity sha512-/NyiM3Ox9AwP5zrfT9TXjRKDJbXlLaUDQ9Rg//2lbg8D2A8GXV0VidYYnA/gfdK6uwbnL4FnAflH7FbGw3TS7w== integrity sha512-/NyiM3Ox9AwP5zrfT9TXjRKDJbXlLaUDQ9Rg//2lbg8D2A8GXV0VidYYnA/gfdK6uwbnL4FnAflH7FbGw3TS7w==
optionalDependencies: optionalDependencies:
saslprep "^1.0.3" saslprep "^1.0.3"


mongoose@^6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-6.5.2.tgz#630ae67c4d2576635ba1f859b2840560b27b7775"
integrity sha512-3CFDrSLtK2qjM1pZeZpLTUyqPRkc11Iuh74ZrwS4IwEJ3K2PqGnmyPLw7ex4Kzu37ujIMp3MAuiBlUjfrcb6hw==
dependencies:
bson "^4.6.5"
kareem "2.4.1"
mongodb "4.8.1"
mpath "0.9.0"
mquery "4.0.3"
ms "2.1.3"
sift "16.0.0"

[email protected]:
version "0.9.0"
resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.9.0.tgz#0c122fe107846e31fc58c75b09c35514b3871904"
integrity sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==

[email protected]:
version "4.0.3"
resolved "https://registry.yarnpkg.com/mquery/-/mquery-4.0.3.tgz#4d15f938e6247d773a942c912d9748bd1965f89d"
integrity sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==
dependencies:
debug "4.x"

[email protected]: [email protected]:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
get-intrinsic "^1.0.2" get-intrinsic "^1.0.2"
object-inspect "^1.9.0" object-inspect "^1.9.0"


[email protected]:
version "16.0.0"
resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.0.tgz#447991577db61f1a8fab727a8a98a6db57a23eb8"
integrity sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==

signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
version "3.0.7" version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
spdx-correct "^3.0.0" spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0" spdx-expression-parse "^3.0.0"


validator@^13.7.0:
version "13.7.0"
resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857"
integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==

vary@~1.1.2: vary@~1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"

Loading…
Cancel
Save