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
6 changes: 0 additions & 6 deletions .env.example

This file was deleted.

151 changes: 147 additions & 4 deletions controllers/auth.controller.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,150 @@
export const register = (req, res) => {};

export const login = (req, res) => {};
import User from '../models/UserModel.js';
import bcrypt from 'bcryptjs';
import jwt from "jsonwebtoken";
import crypto from "crypto";
import nodemailer from "nodemailer";
import { Op } from "sequelize";

export const forgotPassword = (req, res) => {};

export const resetPassword = (req, res) => {};
export const register = async (req, res) => {
const { name, username, email, password, confPassword } = req.body;

if (password !== confPassword) {
return res.status(400).json({ msg: "Password dan Confirm Password tidak cocok" })
};

try {
const existingUser = await User.findOne({ where: { email: email } });
const existingUsername = await User.findOne({ where: { username: username } });

if (existingUser) {
return res.status(400).json({ msg: "Email sudah digunakan" })
}

if (existingUsername) {
return res.status(400).json({ msg: "Username sudah digunakan" })
}

const salt = await bcrypt.genSalt(10);
const hashPassword = await bcrypt.hash(password, salt);

await User.create({
name: name,
username: username,
email: email,
password: hashPassword
});

res.json({ msg: "Register Berhasil" });
} catch (error) {
console.log(error);
res.status(500).json({ msg: "Terjadi kesalahan server" });
}
};

export const login = async (req, res) => {
try {
const user = await User.findAll({
where: { username: req.body.username }
});

if (user.length === 0) return res.status(404).json({ msg: "Username tidak ditemukan" });

const match = await bcrypt.compare(req.body.password, user[0].password);
if (!match) return res.status(400).json({ msg: "Password Salah" });

const userId = user[0].id;
const name = user[0].name;
const username = user[0].username;

const accessToken = jwt.sign({ userId, name, username }, process.env.JWT_SECRET, {
expiresIn: '1d'
});

res.json({ accessToken });
} catch (error) {
res.status(500).json({ msg: "Terjadi kesalahan pada server" });
}
};

export const forgotPassword = async (req, res) => {
try {
const { email } = req.body;

const user = await User.findOne({ where: { email: email } });
if (!user) return res.status(404).json({ msg: "Email tidak terdaftar" });

const token = crypto.randomBytes(20).toString('hex');
const expireTime = Date.now() + 3600000;

await User.update({
resetPasswordToken: token,
resetPasswordExpires: expireTime
}, {
where: { email: email }
});

const transporter = nodemailer.createTransport({
host: "sandbox.smtp.mailtrap.io",
port: 2525,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS
}
});

const resetLink = `http://http://127.0.0.1:5500/frontend/index.html?token=${token}`;

const mailOptions = {
from: 'no-reply@pagebuilder.com',
to: email,
subject: 'Link Reset Password',
text: `Klik link ini untuk reset password: ${resetLink}`
};

await transporter.sendMail(mailOptions);
res.status(200).json({ msg: "Email reset password telah dikirim." });

} catch (error) {
console.log(error);
res.status(500).json({ msg: "Terjadi kesalahan server" });
}
};

export const resetPassword = async (req, res) => {
try {
const { token } = req.params;
const { newPassword, confNewPassword } = req.body;

const user = await User.findOne({
where: {
resetPasswordToken: token,
resetPasswordExpires: { [Op.gt]: Date.now() }
}
});

if (!user) return res.status(400).json({ msg: "Token tidak valid atau expired" });

if (newPassword !== confNewPassword) {
return res.status(400).json({ msg: "Password tidak cocok" });
}

const salt = await bcrypt.genSalt(10);
const hashNewPassword = await bcrypt.hash(newPassword, salt);

await User.update({
password: hashNewPassword,
resetPasswordToken: null,
resetPasswordExpires: null
}, {
where: { id: user.id }
});

res.status(200).json({ msg: "Password berhasil direset! Silakan login." });

} catch (error) {
console.log(error);
res.status(500).json({ msg: "Terjadi kesalahan server" });
}
};
43 changes: 23 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,38 @@ import dotenv from 'dotenv';
import cors from 'cors';
import db from './config/database.js';

import { User, Component, Project, ProjectComponent } from './models/index.js';

// Import Routes
import authRoutes from './routes/auth.routes.js';
import componentRoutes from './routes/component.routes.js';
import dashboardRoutes from './routes/dashboard.routes.js';
import projectRoutes from './routes/project.routes.js';
import userRoutes from './routes/user.routes.js';
import dashboardRoutes from './routes/dashboard.routes.js';

dotenv.config();
const app = express();

try {
await db.authenticate();
console.log('Database connected...');
const startServer = async () => {
try {
await db.authenticate();
console.log('Database Connected...');

await db.sync();
console.log('All models were synchronized successfully.');
} catch (error) {
console.error('Connection error:', error);
}
await db.sync({ alter: true });

app.use(cors({ credentials: true, origin: 'http://localhost:3000' }));
app.use(express.json());
} catch (error) {
console.error('Connection error:', error);
}

app.use('/api/auth', authRoutes);
app.use('/api/components', componentRoutes);
app.use('/api/projects', projectRoutes);
app.use('/api/users', userRoutes);
app.use('/api/dashboard', dashboardRoutes);
app.use(cors());
app.use(express.json());

app.use('/auth', authRoutes);
// app.use('/api/components', componentRoutes); // Nyalakan jika file routes sudah siap
// app.use('/api/projects', projectRoutes); // Nyalakan jika file routes sudah siap
// app.use('/api/users', userRoutes); // Nyalakan jika file routes sudah siap
// app.use('/api/dashboard', dashboardRoutes); // Nyalakan jika file routes sudah siap

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
}

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
startServer();
15 changes: 15 additions & 0 deletions middleware/verifyToken.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const jwt = require('jsonwebtoken');

exports.verifyToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];

if (token == null) return res.sendStatus(401);

jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) return res.sendStatus(403);
req.email = decoded.email;
req.userId = decoded.userId;
next();
});
}
18 changes: 8 additions & 10 deletions models/UserModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,36 @@ import db from "../config/database.js";
const { DataTypes } = Sequelize;

const User = db.define('users', {
name:{
name: {
type: DataTypes.STRING,
allowNull: false
},
username:{
username: {
type: DataTypes.STRING,
allowNull: false
},
email:{
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate:{
validate: {
isEmail: true
}
},
password:{
password: {
type: DataTypes.STRING,
allowNull: false
},
role:{
role: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'user'
},
resetPasswordToken:{
resetPasswordToken: {
type: DataTypes.STRING,
allowNull: true
},
resetPasswordExpires: {
type: DataTypes.STRING,
allowNull: true
type: DataTypes.DATE,
}
}, {
freezeTableName: true
Expand Down
12 changes: 12 additions & 0 deletions models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,23 @@ import User from "./UserModel.js";
import Component from "./ComponentModel.js";
import Project from "./ProjectModel.js";
import ProjectComponent from "./ProjectComponentModel.js";
import express from 'express';

const authRoutes = require('./routes/auth.routes.js');

const app = express;

app.use('/api/auth', authRoutes);

User.hasMany(Project, { foreignKey: 'user_id' });
Project.belongsTo(User, { foreignKey: 'user_id' });

Project.belongsToMany(Component, { through: ProjectComponent, foreignKey: 'project_id' });
Component.belongsToMany(Project, { through: ProjectComponent, foreignKey: 'component_id' });

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log('Server is running on port ${PORT}');
});

export { User, Component, Project, ProjectComponent };
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"express": "^5.1.0",
"jsonwebtoken": "^9.0.2",
"mysql2": "^3.14.3",
"nodemailer": "^7.0.11",
"sequelize": "^6.37.7"
}
}
1 change: 1 addition & 0 deletions routes/auth.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const router = express.Router();

router.post('/register', register);
router.post('/login', login);

router.post('/forgot-password', forgotPassword);
router.post('/reset-password/:token', resetPassword);

Expand Down