Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
const express = require('express')
const logger = require('morgan')
const cors = require('cors')
import "dotenv/config";
import express from "express";
import logger from "morgan";
import cors from "cors";
import contactsRouter from "./routes/api/contacts.js";
import authRouter from "./routes/api/users.js";
import connectToDb from "./utils/connectToDb.js";
import passport from "./utils/passport.js";

const contactsRouter = require('./routes/api/contacts')
const app = express();
const formatsLogger = app.get("env") === "development" ? "dev" : "short";

const app = express()
connectToDb();

const formatsLogger = app.get('env') === 'development' ? 'dev' : 'short'
app.use(logger(formatsLogger));
app.use(cors());
app.use(express.json());
app.use(passport.initialize());

app.use(logger(formatsLogger))
app.use(cors())
app.use(express.json())
app.use("/api/contacts", contactsRouter);
app.use("/api/users", authRouter);

app.use('/api/contacts', contactsRouter)
app.use((_, res) => {
res.status(404).json({ message: "Not found" });
});

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

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

module.exports = app
export default app;
106 changes: 106 additions & 0 deletions controllers/authControllers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import jwt from "jsonwebtoken";
import "dotenv/config";
import User from "../models/users.js";
import bcrypt from "bcrypt";
import passport from "passport";

const AuthController = {
login,
signup,
validateAuth,
getPayloadFromJWT,
};

const secretForToken = process.env.TOKEN_SECRET;

async function signup(data) {
const { email, password } = data;
if (!email || !password) {
throw new Error("Email and password are required");
}

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
throw new Error("Invalid email format");
}

if (password.length < 8) {
throw new Error("Password must be at least 8 characters long");
}

const existingUser = await User.findOne({ email });
if (existingUser) {
throw new Error("Email in use");
}

const newUser = new User({
email: data.email,
subscription: "starter",
});

newUser.password(data.password);

await newUser.save();

return newUser;
}

async function login(data) {
const { email, password } = data;

if (!email || !password) {
throw new Error("Email and password are required");
}

const user = await User.findOne({ email });
if (!user) {
throw new Error("Email or password is wrong");
}

const passwordMatch = await bcrypt.compare(password, user.password);
if (!passwordMatch) {
throw new Error("Email or password is wrong");
}

const token = jwt.sign(
{
userId: user._id,
},
secretForToken,
{
expiresIn: "1h",
}
);

user.token = token;
await user.save();

return { token, user };
}

function getPayloadFromJWT(token) {
try {
const payload = jwt.verify(token, secretForToken);

return payload;
} catch (err) {
console.error(err);
}
}

export function validateAuth(req, res, next) {
passport.authenticate("jwt", { session: false }, (err, user) => {
if (!user || err) {
return res.status(401).json({
status: "error",
code: 401,
message: "Unauthorized",
data: "Unauthorized",
});
}
req.user = user;
next();
})(req, res, next);
}

export default AuthController;
76 changes: 76 additions & 0 deletions controllers/contactControllers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import Contact from "../models/contacts.js";

async function listContacts(page = -1, limit = 20, favorite = null) {
try {
const skip = (page = -1) * limit;
let query = {};
if (favorite !== null) {
query.favorite = favorite;
}
const contacts = await Contact.find(query).skip(skip).limit(limit);
return contacts;
} catch (error) {
throw new Error("Failed to retrieve contacts");
}
}

async function getContactById(contactId) {
try {
const contact = await Contact.findById(contactId);
return contact;
} catch (error) {
throw new Error("Failed to retrieve contact");
}
}

async function removeContact(contactId) {
try {
const result = await Contact.findByIdAndDelete(contactId);
return result;
} catch (error) {
throw new Error("Failed to delete contact");
}
}

async function addContact(contact) {
try {
const newContact = new Contact(contact);
await newContact.save();
return newContact;
} catch (error) {
throw new Error("Failed to add contact");
}
}

async function updateContact(updatedContact, contactId) {
try {
const result = await Contact.findByIdAndUpdate(contactId, updatedContact, {
new: true,
});
return result;
} catch (error) {
throw new Error("Failed to update contact");
}
}
async function updateStatusContact(contactId, body) {
try {
const result = await Contact.findByIdAndUpdate(
contactId,
{ favorite: body.favorite },
{ new: true }
);
return result;
} catch (error) {
throw new Error("Failed to update contact status");
}
}
const ContactsServices = {
listContacts,
getContactById,
removeContact,
addContact,
updateContact,
updateStatusContact,
};

export default ContactsServices;
20 changes: 20 additions & 0 deletions controllers/userController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import User from "../models/users.js";

const UserController = {
async updateSubscription(userId, subscription) {
try {
const user = await User.findById(userId);
if (!user) {
throw new Error("User not found");
}

user.subscription = subscription;
await user.save();
return user;
} catch (error) {
throw new Error(`Error updating subscription: ${error.message}`);
}
},
};

export default UserController;
42 changes: 25 additions & 17 deletions models/contacts.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
// const fs = require('fs/promises')
import mongoose from "mongoose";
const { Schema, model } = mongoose;

const listContacts = async () => {}
const schema = new 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 = model("Contact", schema);

const getContactById = async (contactId) => {}

const removeContact = async (contactId) => {}

const addContact = async (body) => {}

const updateContact = async (contactId, body) => {}

module.exports = {
listContacts,
getContactById,
removeContact,
addContact,
updateContact,
}
export default Contact;
10 changes: 5 additions & 5 deletions models/contacts.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@
"phone": "(704) 398-7993"
},
{
"id": "rsKkOQUi80UsgVPCcLZZW",
"name": "Alec Howard",
"email": "[email protected]",
"phone": "(748) 206-2688"
"name": "John Doe",
"email": "[email protected]",
"phone": "12345678899",
"id": "7dd187d0-f907-4737-b843-91b45bd7256b"
}
]
]
35 changes: 35 additions & 0 deletions models/users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import mongoose from "mongoose";
import bcrypt from "bcrypt";
const { Schema, model } = mongoose;

const userSchema = new Schema({
email: {
type: String,
required: [true, "Email is required"],
unique: true,
},
password: {
type: String,
required: [true, "Password is required"],
},
subscription: {
type: String,
enum: ["starter", "pro", "business"],
default: "starter",
},
token: {
type: String,
default: null,
},
});

userSchema.methods.setPassword = function (password) {
this.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10));
};

userSchema.methods.validPassword = function (password) {
return bcrypt.compareSync(password, this.password);
};

const User = model("User", userSchema);
export default User;
Loading