Skip to content
Open
35 changes: 20 additions & 15 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
const express = require('express')
const logger = require('morgan')
const cors = require('cors')
const express = require('express');
const logger = require('morgan');
const cors = require('cors');
const path = require('path');

const contactsRouter = require('./routes/api/contacts')
const contactsRouter = require('./routes/api/contacts');
const usersRouter = require('./routes/api/users');

const app = express()
const app = express();

const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short'
const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short';

app.use(logger(formatsLogger))
app.use(cors())
app.use(express.json())
app.use(logger(formatsLogger));
app.use(cors());
app.use(express.json());

app.use('/api/contacts', contactsRouter)
app.use('/avatars', express.static(path.join(__dirname, 'public', 'avatars')));

app.use('/api/users', usersRouter);
app.use('/api/contacts', contactsRouter);

app.use((req, res) => {
res.status(404).json({ message: 'Not found' })
})
res.status(404).json({ message: 'Not found' });
});

app.use((err, req, res, next) => {
res.status(500).json({ message: err.message })
})
res.status(500).json({ message: err.message });
});

module.exports = app
module.exports = app;
16 changes: 16 additions & 0 deletions config/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require('dotenv').config();
const mongoose = require('mongoose');

const DB_URI = process.env.DB_URI;

const connectDB = async () => {
try {
await mongoose.connect(DB_URI);
console.log('Database connection successful');
} catch (err) {
console.error('Database connection error:', err);
process.exit(1);
}
};

module.exports = connectDB;
31 changes: 31 additions & 0 deletions middleware/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const jwt = require('jsonwebtoken');
const User = require('../models/users');

const authMiddleware = async (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];

if (!token) {
return res.status(401).json({ message: 'Not authorized' });
}

try {
const decoded = jwt.verify(token, process.env.JWT_SECRET_KEY);

const user = await User.findById(decoded.userId);
if (!user) {
return res.status(401).json({ message: 'Not authorized' });
}

if (user.token !== token) {
return res.status(401).json({ message: 'Not authorized' });
}

req.user = user;
next();
} catch (error) {
console.error(error);
return res.status(401).json({ message: 'Not authorized' });
}
};

module.exports = authMiddleware;
29 changes: 29 additions & 0 deletions models/contactModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// contactModel.js
const mongoose = require('mongoose');
const { Schema } = mongoose;

const contactSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Set name for contact'],
},
email: {
type: String,
},
phone: {
type: String,
},
favorite: {
type: Boolean,
default: false,
},
owner: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
}
});

const Contact = mongoose.model('Contact', contactSchema);

module.exports = Contact;
43 changes: 36 additions & 7 deletions models/contacts.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,48 @@
// const fs = require('fs/promises')
const mongoose = require('mongoose');
const Contact = require('./contactModel');
const connectDB = require('../config/db');

const listContacts = async () => {}
connectDB();

const getContactById = async (contactId) => {}
const listContacts = async (userId) => {
return await Contact.find({ owner: userId });
};

const removeContact = async (contactId) => {}
const getContactById = async (contactId, userId) => {
return await Contact.findOne({ _id: contactId, owner: userId });
};

const addContact = async (body) => {}
const removeContact = async (contactId, userId) => {
return await Contact.findOneAndDelete({ _id: contactId, owner: userId });
};

const updateContact = async (contactId, body) => {}
const addContact = async (body, userId) => {
const newContact = new Contact({ ...body, owner: userId });
await newContact.save();
return newContact;
};

const updateContact = async (contactId, body, userId) => {
return await Contact.findOneAndUpdate(
{ _id: contactId, owner: userId },
body,
{ new: true }
);
};

const updateStatusContact = async (contactId, { favorite }, userId) => {
return await Contact.findOneAndUpdate(
{ _id: contactId, owner: userId },
{ favorite },
{ new: true, runValidators: true }
);
};

module.exports = {
listContacts,
getContactById,
removeContact,
addContact,
updateContact,
}
updateStatusContact,
};
8 changes: 7 additions & 1 deletion models/contacts.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,11 @@
"name": "Alec Howard",
"email": "Donec.elementum@scelerisquescelerisquedui.net",
"phone": "(748) 206-2688"
},
{
"id": "11",
"name": "Julia Lane",
"email": "mattis.Cras@nonenimKauris.net",
"phone": "5424514038"
}
]
]
51 changes: 51 additions & 0 deletions models/users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;
const bcrypt = require('bcryptjs');
const { required } = require('joi');
const gravatar = require('gravatar');

const userSchema = new Schema({
password: {
type: String,
required: [true, 'Password is required'],
},
email: {
type: String,
required: [true, 'Email is required'],
unique: true,
match: [/\S+@\S+\.\S+/, 'Email is not valid'],
},
subscription: {
type: String,
enum: ['starter', 'pro', 'business'],
default: 'starter',
},
token: {
type: String,
default: null,
},
avatarURL: {
type: String,
required: true,
},
});

userSchema.pre('save', async function (next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 10);
next();
});

userSchema.pre('save', function (next) {
if (this.isNew && !this.avatarURL) {
const avatar = gravatar.url(this.email, { s: '200', r: 'pg', d: 'mm' });
this.avatarURL = avatar;
}
next();
});

userSchema.methods.isValidPassword = async function (password) {
return await bcrypt.compare(password, this.password);
};

module.exports = mongoose.model('User', userSchema);
24 changes: 24 additions & 0 deletions models/validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const Joi = require('joi');

const contactSchema = Joi.object({
name: Joi.string().min(3).max(50).required(),
email: Joi.string().email().required(),
phone: Joi.string().pattern(/^[0-9]+$/).required(),
favorite: Joi.boolean(),
});

const signupSchema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().min(6).required(),
});

const loginSchema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().min(6).required(),
});

module.exports = {
contactSchema,
signupSchema,
loginSchema
};
Loading