Skip to content

Commit

Permalink
financial-system-server
Browse files Browse the repository at this point in the history
  • Loading branch information
zdni committed Jul 24, 2024
0 parents commit 9d141ae
Show file tree
Hide file tree
Showing 22 changed files with 4,083 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
######### SETUP SERVER
APP_PORT=4000
CORS_URL=http://localhost:3000
NODE_ENV=development # development | production

######### MONGODB SETUP
MONGODB_DB_NAME=financial-recording
MONGODB_SERVER=local # local | server
# LOCAL
MONGODB_LOCAL_URL=mongodb://localhost:27017
# ATLAS
MONGODB_ATLAS_URL=

######### JWT SETUP
JWT_ACCESS_TOKEN_SECRET=igEQntEjKt18TaNDHbyAS8WcA4tMp87r2I9VcqATy1dXZMuwsy982ezdRM8x2Pm4
JWT_ACCESS_TOKEN_LIFE=1d
JWT_REFRESH_TOKEN_SECRET=dGiC0pi47rmHVRI7eAd9pNNrMyi8MFIXbKZ257hDihPHTs3MWohBv83j0kYQvfX3
JWT_REFRESH_TOKEN_LIFE=7d
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
22 changes: 22 additions & 0 deletions connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import dotenv from "dotenv"
import mongoose from "mongoose"

const env = dotenv.config().parsed

const MONGODB_URL = (env.MONGODB_SERVER === 'local') ? env.MONGODB_LOCAL_URL : env.MONGODB_ATLAS_URL

const connection = () => {
mongoose.set("strictQuery", false);
mongoose.connect(`${MONGODB_URL}`, {
dbName: `${env.MONGODB_DB_NAME}`,
// directConnection: true
})

const connection = mongoose.connection
connection.on('error', console.error.bind( console, 'connection error:' ))
connection.once('open', () => {
console.log('Connected to MongoDB')
})
}

export default connection
139 changes: 139 additions & 0 deletions controllers/AccountController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import Account from "../models/Account.js";

import checkValidationObjectId from '../libraries/checkValidationObjectId.js';

class AccountController {
async index(req, res) {
try {
const accounts = await Account.find();
if(!accounts) { throw { code: 404, message: "ACCOUNT_DATA_NOT_FOUND", data: null, status: false } }

return res.status(200).json({
status: true,
message: "LIST_ACCOUNT",
data: accounts
});
} catch (error) {
return res.status(error.code || 500).json({
status: false,
message: error.message,
data: null
});
}
}

async store(req, res) {
try {
const { name, account_type } = req.body;
if(!name) { return { status: false, code: 428, message: "NAME_IS_REQUIRED" } }
if(!account_type) { return { status: false, code: 428, message: "TYPE_IS_REQUIRED" } }

const document = new Account({ name: name, account_type: account_type });
const account = await document.save();
if(!account) { throw { code: 500, message: "FAILED_CREATE_ACCOUNT", data: null, status: false } }

return res.status(200).json({
status: true,
message: "SUCCESS_CREATE_ACCOUNT",
data: account,
})
} catch (error) {
return res.status(error.code || 500).json({
status: false,
message: error.message,
data: null
});
}
}

async show(req, res) {
try {
const {id} = req.params
if(!id) { throw { code: 428, message: "ID_REQUIRED", data: null, status: false } }

const checkObjId = await checkValidationObjectId(id, Account, "ACCOUNT", true)
if(!checkObjId.status) return res.status(checkObjId.code).json({
status: false,
message: checkObjId.message,
data: null
});

return res.status(200).json({
status: true,
message: "ACCOUNT_FOUND",
data: { ...checkObjId.data._doc }
});
} catch (error) {
return res.status(error.code || 500).json({
status: false,
message: error.message,
data: null
});
}
}

async update(req, res) {
try {
const {id} = req.params
if(!id) { throw { code: 420, message: "ID_REQUIRED", data: null, status: false } }

const checkObjId = await checkValidationObjectId(id, Account, "ACCOUNT")
if(!checkObjId.status) return res.status(checkObjId.code).json({
status: false,
message: checkObjId.message,
data: null
});

// check if account has transaction

const account = await Account.findByIdAndUpdate( { _id: id }, req.body, { new: true } )
if(!account) { throw { code: 500, message: "ACCOUNT_UPDATE_FAILED", data: null, status: false } }

return res.status(200).json({
status: true,
message: "ACCOUNT_UPDATE_SUCCESS",
data: account,
})
} catch (error) {
return res.status(error.code || 500).json({
status: false,
message: error.message,
data: null
});
}
}

async destroy(req, res) {
try {
const {id} = req.params
if(!id) { throw { code: 420, message: "ID_REQUIRED", data: null, status: false } }

const checkObjId = await checkValidationObjectId(id, Account, "ACCOUNT")
if(!checkObjId.status) return res.status(checkObjId.code).json({
status: false,
message: checkObjId.message,
data: null
});

// check if account has transaction


const account = await Account.findOneAndDelete({ _id: id })
if(!account) { throw { code: 500, message: "ACCOUNT_DELETE_FAILED", data: null, status: false } }

return res.status(200).json({
status: true,
message: "ACCOUNT_DELETE_SUCCESS",
data: account,
})
} catch (error) {
return res.status(error.code || 500).json({
status: false,
message: error.message,
data: null
});
}
}
}

export default new AccountController;
108 changes: 108 additions & 0 deletions controllers/AuthController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import bcrypt from 'bcrypt'
import jwt from 'jsonwebtoken'
import dotenv from 'dotenv'

import User from '../models/User.js'

const env = dotenv.config().parsed

const generateAccessToken = async (payload) => {
return jwt.sign(
payload,
env.JWT_ACCESS_TOKEN_SECRET,
{ expiresIn: env.JWT_ACCESS_TOKEN_LIFE }
)
}

const generateRefreshToken = async (payload) => {
return jwt.sign(
payload,
env.JWT_REFRESH_TOKEN_SECRET,
{ expiresIn: env.JWT_REFRESH_TOKEN_LIFE }
)
}

class AuthController {
async login(req, res) {
try {
const { email, password } = req.body
if(!email) { throw { code: 428, message: "EMAIL_IS_REQUIRED", data: null, status: false } }
if(!password) { throw { code: 428, message: "PASSWORD_IS_REQUIRED", data: null, status: false } }

const user = await User.findOne({ email: email })
if(!user) { throw { code: 403, message: "USER_NOT_FOUND", data: null, status: false } }

const isMatch = bcrypt.compareSync(password, user.password)
if(!isMatch) { throw { code: 403, message: "WRONG_PASSWORD", data: null, status: false } }

const payload = { id: user.id, role: user.role }
const accessToken = await generateAccessToken(payload)
const refreshToken = await generateRefreshToken(payload)

let data = { ...user._doc }
delete data.password

return res.status(200).json({
status: true,
message: "LOGIN_SUCCESS",
data: {
user: data,
accessToken,
refreshToken,
},
})
} catch(err) {
if(!err.code) { err.code = 500 }
return res.status(err.code).json({
status: false,
message: err.message,
data: null
})
}
}

async refreshToken(req, res) {
try {
const { refreshToken } = req.body
if(!refreshToken) { throw { code: 428, message: "REFRESH_TOKEN_IS_REQUIRED", data: null, status: false } }

const verify = jwt.verify(refreshToken, env.JWT_REFRESH_TOKEN_SECRET)
const payload = { id: verify.id, role: verify.role }

const accessToken = await generateAccessToken(payload)
const _refreshToken = await generateRefreshToken(payload)

const user = await User.findOne({ _id: verify.id })
if(!user) { throw { code: 403, message: "USER_NOT_FOUND", data: null, status: false } }

let data = { ...user._doc }
delete data.password

return res.status(200).json({
status: true,
message: "REFRESH_TOKEN_SUCCESS",
data: {
user: data,
accessToken,
refreshToken: _refreshToken,
}
})
} catch (err) {
if(!err.code) { err.code = 500 }

if(err.message === "jwt expired") {
err.message = "REFRESH_TOKEN_EXPIRED"
} else if(err.message === 'invalid signature' || err.message === 'invalid token') {
err.message = "REFRESH_TOKEN_INVALID"
}

return res.status(err.code).json({
status: false,
message: err.message,
data: null
})
}
}
}

export default new AuthController
Loading

0 comments on commit 9d141ae

Please sign in to comment.