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
24 changes: 24 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
Binary file modified .gitignore
Binary file not shown.
11 changes: 11 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"configurations": [
{
"name": "Docker Node.js Launch",
"type": "docker",
"request": "launch",
"preLaunchTask": "docker-run: debug",
"platform": "node"
}
]
}
35 changes: 35 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "docker-build",
"label": "docker-build",
"platform": "node",
"dockerBuild": {
"dockerfile": "${workspaceFolder}/Dockerfile",
"context": "${workspaceFolder}",
"pull": true
}
},
{
"type": "docker-run",
"label": "docker-run: release",
"dependsOn": ["docker-build"],
"platform": "node"
},
{
"type": "docker-run",
"label": "docker-run: debug",
"dependsOn": ["docker-build"],
"dockerRun": {
"env": {
"DEBUG": "*",
"NODE_ENV": "development"
}
},
"node": {
"enableDebugging": true
}
}
]
}
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Folosește o imagine oficială Node.js ca bază
FROM node:20

# Setează directorul de lucru
WORKDIR /app

# Copiază fișierele necesare
COPY package*.json ./

# Instalează dependențele
RUN npm install

# Copiază codul aplicației
COPY . .

# Expune portul 3000
EXPOSE 3001

# Comanda de start
CMD ["node", "server.js"]
52 changes: 36 additions & 16 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,45 @@
const express = require('express')
const logger = require('morgan')
const cors = require('cors')
require("dotenv").config();
const express = require("express");
const logger = require("morgan");
const cors = require("cors");
const mongoose = require("mongoose");

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'
app.use(express.static("public"));

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

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

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

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
res.status(500).json({ message: err.message });
});

const { DB_HOST, PORT = 3001 } = process.env;

mongoose
.connect(DB_HOST)
.then(() => {
console.log("Database connection succesful^_^");
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
})
.catch((error) => {
console.error("Database connection error:", error.message);
});

module.exports = app;
130 changes: 130 additions & 0 deletions controllers/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
require("dotenv").config();
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const User = require("../models/user");
const { v4: uuidv4 } = require("uuid");
const { sendVerificationEmail } = require("../services/email");

// POST /users/login
const login = async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });

if (!user) {
return res.status(401).json({ message: "Email not found ^_^" });
}

const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
console.log(
password + " " + user.password + " ispasswordvalid: " + isPasswordValid
);
return res.status(401).json({ message: "Password is wrong ^_^" });
}

if (!user.verify) {
return res
.status(401)
.json({ message: "Please verify your email first ^_^" });
}

const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, {
expiresIn: "1h",
});

await User.findByIdAndUpdate(user._id, { token });

res.status(200).json({
token,
user: {
email: user.email,
subscription: user.subscription,
},
});
};

// POST /users/signup
const signup = async (req, res) => {
const { email, password } = req.body;
const existingUser = await User.findOne({ email });

if (existingUser)
return res.status(409).json({ message: "Email in use ^_^" });

const verificationToken = uuidv4();

const user = new User({ email, password, verificationToken });
await user.save();

await sendVerificationEmail(email, verificationToken);

res.status(201).json({
message: "User created successfully ^_^",
user: {
email: user.email,
subscription: user.subscription,
},
});
};

// GET /users/logout
const logout = async (req, res) => {
try {
const user = await User.findById(req.user._id);
if (!user) {
return res.status(404).json({ message: "User not found ^_^" });
}

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

res.status(200).json({ message: "Logged out successfully ^_^" });
} catch (error) {
res.status(500).json({ message: "Logout failed", error: error.message });
}
};

const verifyEmail = async (req, res) => {
const { verificationToken } = req.params;
const user = await User.findOne({ verificationToken });

if (!user) {
return res.status(404).json({ message: "User not found ^.^" });
}

await User.findByIdAndUpdate(user._id, {
verify: true,
verificationToken: null,
});

res.status(200).json({ message: "Verification successful" });
};

const resendVerificationEmail = async (req, res) => {
const { email } = req.body;
if (!email) {
return res.status(400).json({ message: "missing required field email" });
}

const user = await User.findOne({ email });

if (!user) {
return res.status(400).json({ message: "User not found ^_^" });
}

if (user.verify) {
return res.status(400).json({ message: "Verification already done ^_^" });
}

await sendVerificationEmail(user.email, user.verificationToken);

res.status(200).json({ message: "Verification email sent ^_^" });
};

module.exports = {
login,
signup,
logout,
verifyEmail,
resendVerificationEmail,
};
72 changes: 72 additions & 0 deletions controllers/contacts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const Contact = require("../models/contact");

// GET /api/contacts
const listContacts = async (page, limit, filter) => {
const contacts = await Contact.find({ ...filter })
.skip((page - 1) * limit)
.limit(limit)
.exec();
const totalContacts = await Contact.countDocuments({ ...filter });
return {
totalContacts,
totalPages: Math.ceil(totalContacts / limit),
page,
limit,
contacts,
};
};

// GET /api/contacts/:id
const getContactById = async (req, res) => {
const contact = await Contact.findById(req.params.id);
if (!contact) return res.status(404).json({ message: "Contact not found" });
res.status(200).json(contact);
};

// POST /api/contacts
const addContact = async (req, res) => {
const { name, email, phone, favorite } = req.body;
const contact = new Contact({
name,
email,
phone,
favorite,
owner: req.user._id,
});
await contact.save();
res.status(201).json(contact);
};

// DELETE /api/contacts/:id
const removeContact = async (req, res) => {
const contact = await Contact.findByIdAndDelete(req.params.id);
if (!contact) return res.status(404).json({ message: "Contact not found" });
res.status(200).json({ message: "Contact deleted" });
};

// PUT /api/contacts/:id
const updateContact = async (req, res) => {
const contact = await Contact.findByIdAndUpdate(req.params.id, req.body, {
new: true,
});
if (!contact) return res.status(404).json({ message: "Contact not found" });
res.status(200).json(contact);
};

// PATCH /api/contacts/:id/favorite
const updateFavorite = async (req, res) => {
const contact = await Contact.findById(req.params.id);
if (!contact) return res.status(404).json({ message: "Contact not found" });
contact.favorite = !contact.favorite;
await contact.save();
res.status(200).json(contact);
};

module.exports = {
listContacts,
getContactById,
addContact,
removeContact,
updateContact,
updateFavorite,
};
Loading