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
17 changes: 14 additions & 3 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@ module.exports = {
es2021: true,
node: true,
},
extends: ['standard', 'prettier'],
extends: ["standard", "prettier"],
parserOptions: {
ecmaVersion: 12,
},
rules: {},
}
rules: {
"no-unused-vars": [
"error",
{
vars: "all",
args: "after-used",
caughtErrors: "all",
ignoreRestSiblings: false,
reportUsedIgnorePattern: false,
},
],
},
};
73 changes: 52 additions & 21 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,56 @@
const express = require('express')
const logger = require('morgan')
const cors = require('cors')

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

const app = express()

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

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

app.use('/api/contacts', contactsRouter)
import express from "express";
import logger from "morgan";
import cors from "cors";
import colors from "colors";
import { contactsRouter } from "./routes/api/contactsApi.js";
import { usersRouter } from "./routes/api/userApi.js";
import passport from "./config/config.js";
import { auth } from "./middlewares/auth.js";

const app = express();

const formatsLogger = app.get("env") === "development" ? "dev" : "short";
const logger1 = (req, res, next) => {
const { method, originalUrl } = req;

const date = new Date().toLocaleString();
console.log(`[${date}] [${method}] - ${originalUrl} app.js`.yellow);

next();
};

app.use(logger1);
app.use(logger(formatsLogger));
app.use(cors());
app.use(express.json());
app.use(passport.initialize());
app.use("/api/", usersRouter);
app.use("/api/contacts", auth, 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 })
})

module.exports = app
const error = err.stack;
console.error(error.bgRed, "[app.js]");
res.status(500).json({ message: err.message });
});

export const startServer = (port) => {
app
.listen(port, () => {
console.log(`[server] Server running on port ${port}`.bgWhite);
console.log(`[server] http://localhost:${port}/api/contacts/ `.bgWhite);
})
.on("error", (err) => {
if (err.code === "EADDRINUSE") {
console.log(
`Port ${port} is already in use. Trying a different port...`.red
);
startServer(port + 1);
} else {
console.error(err);
}
});
};
33 changes: 33 additions & 0 deletions config/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import passport from "passport";
import passportJWT from "passport-jwt";
import { UserModel } from "../models/users/userShema.js";
import dotenv from "dotenv";
dotenv.config();

const secret = process.env.JWT_SECRET_KEY;

const ExtractJWT = passportJWT.ExtractJwt;
const Strategy = passportJWT.Strategy;
const params = {
secretOrKey: secret,
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
};

// JWT Strategy
passport.use(
new Strategy(params, async (payload, done) => {
try {
const user = await UserModel.findById(payload.id);

if (!user) {
return done(null, false, { message: "User not found" });
}

return done(null, user);
} catch (err) {
return done(err, false);
}
})
);

export default passport;
38 changes: 38 additions & 0 deletions config/dbConnection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import mongoose from "mongoose";
import dotenv from "dotenv";
dotenv.config();

const dbName = process.env.DB_DBNAME;
const uri = process.env.DB_URI;

export const connectDB = async () => {
try {
console.log(`[DB] Connecting to MongoDB: ${dbName} ...`.blue);
await mongoose.connect(uri);
console.log(`[DB] MongoDB: ${dbName} connected successfully`.blue);
} catch (error) {
console.error(
`[DB] Error connecting to MongoDB: ${dbName} :${error.message}`.red
);
process.exit(1);
}
};

export const disconnectDB = async () => {
try {
await mongoose.disconnect();
console.log("[DB] MongoDB disconnected successfully".blue);
} catch (error) {
console.error(
`[DB] Error disconnecting from MongoDB: ${error.message}`.red
);
process.exit(0);
}
};

export function checkConnectionState() {
const state = mongoose.connections[0].readyState;
const stateText = mongoose.connections[0].states[state];
console.log(`Current connection state: ${stateText}`);
return state;
}
47 changes: 47 additions & 0 deletions middlewares/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import passport from "passport";
import mongoose from "mongoose";
import { UserModel } from "../models/users/userShema.js";

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

// Pobierz token z nagłówka `Authorization`
const tokenFromHeader = req.headers.authorization?.split(" ")[1];
if (!tokenFromHeader) {
return res.status(401).json({
message: "Not authorized",
});
}

// Sprawdź, czy token w bazie danych jest zgodny z tokenem w nagłówku
try {
if (!mongoose.Types.ObjectId.isValid(user._id)) {
console.error(`Invalid ID format: ${contactId}`.bgRed);
return res.status(400).json({
message: "Bad Request: Invalid User.ID format",
});
}

const userFromDb = await UserModel.findById(user._id); // Znajdź użytkownika w bazie danych
if (!userFromDb || userFromDb.token !== tokenFromHeader) {
return res.status(401).json({
message: "Not authorized",
});
}

req.user = userFromDb; // Przekaż użytkownika do kolejnych middleware'ów
next();
} catch (dbError) {
console.log(`Database error occurred: ${dbError} [auth.js]`.bgRed);
return res.status(500).json({
message: "Database error during token verification",
});
}
})(req, res, next);
};
30 changes: 30 additions & 0 deletions models/contact/contactShema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import mongoose from "mongoose";

// Definiowanie schematu dla kontaktów
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: mongoose.Schema.Types.ObjectId,
ref: "user",
},
});

// Tworzenie modelu na podstawie schematu
export const ContactModel = mongoose.model(
"Contact",
contactSchema,
"contacts"
);
121 changes: 121 additions & 0 deletions models/contact/contacts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import mongoose from "mongoose";
import { nanoid } from "nanoid";
import { ContactModel } from "./contactShema.js";

export const listContacts = async (userId) => {
try {
const contacts = await ContactModel.find({ owner: userId }); // Filtrowanie kontaktów po owner
console.log("[DB] Contacts fetched successfully".bgGreen);
return contacts;
} catch (error) {
console.error(`[DB] Error fetching contacts: ${error.message}`.red);
throw new Error("Error fetching contacts from the database");
}
};

export const getContactById = async (contactId) => {
try {
if (!mongoose.Types.ObjectId.isValid(contactId)) {
console.error(`Invalid ID format: ${contactId}`.bgYellow);
return null;
}

const contact = await ContactModel.findById(contactId);

if (!contact) {
console.error(`Contact with ID: ${contactId} not found`.bgYellow);
return null;
}

return contact;
} catch (error) {
console.error(`Error getContactById: ${error.message}`.bgRed);
throw new Error(`Unable to fetch contact by ID: ${contactId}`);
}
};

export const removeContact = async (contactId) => {
try {
const removedContact = await ContactModel.findByIdAndDelete(contactId);

if (!removedContact) {
console.error(`Contact with ID: ${contactId} not found`.bgYellow);
return null;
}

console.log(`Contact with ID: ${contactId} removed successfully`.bgGreen);
return removedContact;
} catch (error) {
console.error(`Error removing contact: ${error}`.bgRed);
return null;
}
};

export const addContact = async (body) => {
try {
const { name, email, phone, favorite, owner } = body;

const contact = new ContactModel({
// id: nanoid(),
name,
email,
phone,
favorite: favorite || false,
owner,
});

await contact.save();
console.log(`Contact added successfully`.bgGreen);
console.log(contact.name.bgGreen);
return contact;
} catch (error) {
console.error(`Error addContact: ${error} [contacts.js]`.bgRed);
}
};

export const updateContact = async (contactId, body) => {
try {
const updatedContact = await ContactModel.findByIdAndUpdate(
contactId,
body,
{ new: true, runValidators: true }
);

if (!updatedContact) {
console.error(`Contact with ID: ${contactId} not found`);
return null;
}

console.log(`Contact with ID: ${contactId} updated successfully`);
return updatedContact;
} catch (error) {
console.error(`Error updateContact: ${error}`);
return null;
}
};

export const updateStatusContact = async (contactId, body) => {
try {
if (!Object.prototype.hasOwnProperty.call(body, "favorite")) {
console.error(`Missing "favorite" field in body`);
return null;
}

const updatedContact = await ContactModel.findByIdAndUpdate(
contactId,
{ favorite: body.favorite },
{ new: true, runValidators: true }
);

if (!updatedContact) {
console.error(`Contact with ID: ${contactId} not found`);
return null;
}

console.log(`Contact with ID: ${contactId} updated successfully`);
return updatedContact;
} catch (error) {
console.error(`Error updating favorite field: ${error}`);
return null;
}
};
19 changes: 0 additions & 19 deletions models/contacts.js

This file was deleted.

Loading