-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 9d141ae
Showing
22 changed files
with
4,083 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.