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,
},
],
},
};
76 changes: 55 additions & 21 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,59 @@
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/configPassport.js";
import { AVATARS_DIRECTORY, TEMP_DIRECTORY } from "./config/configDirectory.js";
import { auth } from "./middlewares/auth.js";
console.log("Directory: ", AVATARS_DIRECTORY);
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("/avatars", express.static(AVATARS_DIRECTORY));
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);
}
});
};
8 changes: 8 additions & 0 deletions config/configDirectory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const parentDirName = path.resolve(__dirname, "..");
export const AVATARS_DIRECTORY = path.join(parentDirName, "public", "avatars");
export const TEMP_DIRECTORY = path.join(parentDirName, "tmp");
33 changes: 33 additions & 0 deletions config/configPassport.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);
};
39 changes: 39 additions & 0 deletions middlewares/upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import multer from "multer";
import {
AVATARS_DIRECTORY,
TEMP_DIRECTORY,
} from "../config/configDirectory.js";
import { nanoid } from "nanoid";
const storage = multer.diskStorage({
destination: TEMP_DIRECTORY,
filename: (req, file, callback) => {
const timestamp = Date.now();
const id = nanoid();
const fileName = [timestamp, id, file.originalname].join("_");

console.log(`Uploading "${fileName} [upload.js]`.yellow);

callback(null, fileName);
},
limits: { fileSize: 1_000_000 },
});

// const fileFilter = (req, file, callback) => {
// const isForbiddenFile = !file.originalname.includes("monke");
// // const isForbiddenFile = file.originalname.includes("monke");

// callback(null, isForbiddenFile);
// };

// export const upload = multer({ storage, fileFilter });

// const storage = multer.diskStorage({
// destination: AVATARS_DIRECTORY,
// filename: (req, file, cb) => {
// const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
// const ext = path.extname(file.originalname); // Pobierz rozszerzenie pliku
// cb(null, `${file.fieldname}-${uniqueSuffix}${ext}`);
// },
// });

export const upload = multer({ storage });
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"
);
Loading