2 |
3 |
4 |
5 |
6 |
7 |
8 |
An introduction to mean stack
9 |
10 |
Description: Start learning mean stack today with this book that is optimized
11 | for experiential learning.
12 |
13 |
Only for $$ 39.00
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Socket.io
6 |
7 |
8 |
News Feed
9 |
10 |
11 |
12 |
27 |
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "note-app",
3 | "version": "1.0.0",
4 | "description": "note app api",
5 | "main": "server.js",
6 | "scripts": {
7 | "test": "mocha --timeout 10000 "
8 | },
9 | "keywords": [
10 | "not",
11 | "app"
12 | ],
13 | "author": "",
14 | "license": "ISC",
15 | "dependencies": {
16 | "babel-polyfill": "^6.26.0",
17 | "bcryptjs": "^2.4.3",
18 | "body-parser": "^1.19.0",
19 | "chai": "^4.3.3",
20 | "cors": "^2.8.5",
21 | "dotenv": "^8.2.0",
22 | "express": "^4.17.1",
23 | "fast-csv": "^4.3.6",
24 | "jsonwebtoken": "^8.5.1",
25 | "memorystorage": "^0.12.0",
26 | "multer": "^1.4.2",
27 | "password-validator": "^5.1.1",
28 | "paypal-rest-sdk": "^1.8.1",
29 | "pg": "^8.5.1",
30 | "randomstring": "^1.1.5",
31 | "sequential-ids": "0.0.0",
32 | "socket.io": "^4.1.2",
33 | "swagger-ui-express": "^4.1.6",
34 | "winston": "^3.3.3"
35 | },
36 | "devDependencies": {
37 | "supertest": "^6.1.3"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/audit/audit.service.js:
--------------------------------------------------------------------------------
1 | var events = require('events');
2 | var audit = require('../model/audit.model');
3 | var queries = require('../db/queries');
4 | var dbConnection = require('../db/connection');
5 |
6 | var emitter = new events.EventEmitter();
7 |
8 | const auditEvent = 'audit';
9 | emitter.on(auditEvent , function(audit){
10 | // steps of actions - save into db
11 | console.log("Audit Event Emitter - Audit : " + JSON.stringify(audit));
12 | try {
13 | values =[audit.auditAction , JSON.stringify(audit.data) , audit.status , audit.error , audit.auditBy , audit.auditOn];
14 | var auditQuery = queries.queryList.AUDIT_QUERY;
15 | dbConnection.dbQuery(auditQuery , values);
16 |
17 | } catch (error) {
18 | console.log("Audit Event Emitter - error : " + error);
19 | }
20 |
21 |
22 |
23 |
24 |
25 |
26 | });
27 |
28 | exports.prepareAudit = function(auditAction , data , error , auditBy , auditOn){
29 | let status = 200;
30 | if(error)
31 | status = 500;
32 |
33 | var auditObj = new audit.Audit(auditAction , data , status , error , auditBy , auditOn)
34 | emitter.emit(auditEvent , auditObj);
35 | }
--------------------------------------------------------------------------------
/controller/upload.controller.js:
--------------------------------------------------------------------------------
1 | var util = require('../Util/utility');
2 | var validationUtil = require('../Util/validation');
3 | var Logger = require('../services/logger.service');
4 | var multer = require('multer');
5 | const logger = new Logger('upload.controller');
6 |
7 | exports.uploadFile = async (req , res) => {
8 | var auditOn = util.dateFormat();
9 | try {
10 | var upload = multer({ dest: process.env.UPLOAD_PATH }).single('photo');
11 | upload(req , res , next => {
12 |
13 | try {
14 | var path= req.file.path;
15 | var file =req.file;
16 | console.log("Path : " + path);
17 | console.log("file : " + JSON.stringify(file));
18 | // save file in directory
19 | // save meta dat in data base [file name (rename) , size , mimiType , path]
20 | return res.status(200).send({data : 'file is uploaded Successfully '});
21 | } catch (e) {
22 | throw e;
23 | }
24 |
25 | });
26 |
27 | } catch (err) {
28 | console.log("Error : " + err);
29 | return res.status(500).send({error : 'Failed to upload file'});
30 | }
31 | }
--------------------------------------------------------------------------------
/Util/validation.js:
--------------------------------------------------------------------------------
1 | var passwordValidator = require('password-validator');
2 | var passwordChecker = new passwordValidator();
3 | var bcrypt = require('bcryptjs');
4 |
5 | exports.isValidEmail = (email) => {
6 | const regEx = /\S+@\S+\.\S+/;
7 | return regEx.test(email);
8 | };
9 |
10 | exports.isValidatePassword = (password) => {
11 | if (password.length < 8 || password === '') {
12 | return false;
13 | }
14 | return true;
15 | };
16 |
17 | exports.comparePassword = (password , hashedPassword) =>{
18 | return bcrypt.compareSync(password , hashedPassword);
19 | }
20 |
21 |
22 | exports.isValidPassword = (password)=>{
23 | passwordChecker
24 | .is().min(8) // Minimum length 8
25 | .is().max(15) // Maximum length 100
26 | .has().uppercase() // Must have uppercase letters
27 | .has().lowercase() // Must have lowercase letters
28 | .has().digits(2) // Must have at least 2 digits
29 | .has().not().spaces() // Should not have spaces
30 | .is().not().oneOf(['Passw0rd', 'Password123']); // Blacklist these values
31 |
32 | return passwordChecker.validate(password);
33 | }
--------------------------------------------------------------------------------
/controller/export.controller.js:
--------------------------------------------------------------------------------
1 | var queries = require('../db/queries');
2 | var dbConnection = require('../db/connection');
3 | var util = require('../Util/utility');
4 | var validationUtil = require('../Util/validation');
5 | var Logger = require('../services/logger.service');
6 | var auditService = require('../audit/audit.service');
7 | var auditAction = require('../audit/auditAction');
8 | var fastCsv = require('fast-csv');
9 | var fs = require('fs');
10 | const ws = fs.createWriteStream("books.csv");
11 |
12 | const logger = new Logger('export.controller');
13 |
14 | exports.exportBooks = async (req , res) => {
15 | try {
16 | var bookListQuery = queries.queryList.GET_BOOK_LIST_QUERY;
17 | var result = await dbConnection.dbQuery(bookListQuery);
18 | logger.info("return Book List" , result.rows);
19 | const data = JSON.parse(JSON.stringify(result.rows));
20 | fastCsv.write(data , {headers : true}).on("end", ()=>{
21 | console.log("write to books.csv successfully");
22 | res.download("books.csv" , function(){
23 | console.log("file downloaded successfully");
24 | })
25 | }).pipe(ws);
26 | // return res.status(200).send({data : "export data successfully"})
27 | } catch (err) {
28 | console.log("Error : " + err);
29 | return res.status(500).send({error : 'Failed to export books'});
30 | }
31 | }
--------------------------------------------------------------------------------
/controller/paypal.controller.js:
--------------------------------------------------------------------------------
1 | var paypalService = require('../services/paypal.service');
2 |
3 |
4 | exports.createPayment = (req , res) => {
5 |
6 | // create payment object
7 | var payment = {
8 | "intent": "authorize",
9 | "payer": {
10 | "payment_method": "paypal"
11 | },
12 | "redirect_urls": {
13 | "return_url": "http://127.0.0.1:4000/success",
14 | "cancel_url": "http://127.0.0.1:4000/err"
15 | },
16 | "transactions": [{
17 | "amount": {
18 | "total": 39.00,
19 | "currency": "USD"
20 | },
21 | "description": " a book on mean stack "
22 | }]
23 | }
24 |
25 | paypalService.createPaypalPayment(payment).then((transaction)=>{
26 | console.log("Create Payment Response");
27 | console.log("transaction : " + JSON.stringify(transaction));
28 | var transactionId = transaction.id;
29 | console.log("id : " + transactionId);
30 | // NEED TO LOG ALL TRANSACTION FOR EACH REQUEST AND RESPONSE FOR AUDITING
31 | // generate transaction reference number tx_randomnumber
32 | // transaction status [Success , failed , cancelled , pending]
33 | res.redirect("/success")
34 | })
35 | .catch((err)=>{
36 | console.log( err );
37 | res.redirect("/err")
38 | throw error;
39 | })
40 | }
--------------------------------------------------------------------------------
/controller/store.controller.js:
--------------------------------------------------------------------------------
1 | var queries = require('../db/queries');
2 | var dbConnection = require('../db/connection');
3 | var util = require('../Util/utility');
4 |
5 | exports.getStoreList = async (req , res) => {
6 | try {
7 | var storeListQuery = queries.queryList.GET_STORE_LIST_QUERY;
8 | var result = await dbConnection.dbQuery(storeListQuery);
9 | return res.status(200).send(JSON.stringify(result.rows));
10 | } catch (err) {
11 | console.log("Error : " + err);
12 | return res.status(500).send({error : 'Failed to list store'});
13 | }
14 |
15 | }
16 |
17 |
18 | exports.saveStore = async (req , res) => {
19 |
20 | try {
21 |
22 | var createdBy = "admin";
23 | var createdOn = new Date();
24 | // req.body
25 | var storeName = req.body.storeName;
26 | var address = req.body.address;
27 | console.log("storeName : " + storeName + " ----- address : " + address)
28 | if(!storeName || !address){
29 | return res.status(500).send({ error: 'store name and address are required , can not empty' })
30 | }
31 |
32 | let storeCode= util.generateStoreCode();
33 |
34 | values =[storeName , storeCode , address , createdBy , createdOn];
35 | var saveStoreQuery = queries.queryList.SAVE_STORE_QUERY;
36 | await dbConnection.dbQuery(saveStoreQuery , values);
37 | return res.status(201).send("Successfully store created ");
38 | } catch (err) {
39 | console.log("Error : " + err);
40 | return res.status(500).send({error : 'Failed to save store'});
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/services/logger.service.js:
--------------------------------------------------------------------------------
1 | const winston = require('winston');
2 | const dotenv = require('dotenv');
3 | dotenv.config();
4 |
5 | // date + logger level + message
6 |
7 | const dateFormat = () =>{
8 | return new Date(Date.now()).toLocaleString();
9 | }
10 |
11 | class LoggerService {
12 |
13 | constructor(route){
14 | this.route = route;
15 | const logger = winston.createLogger({
16 | level: 'info',
17 | format: winston.format.printf(info =>{
18 | let message = `${dateFormat()} | ${info.level.toUpperCase()} | ${info.message} | `;
19 | message = info.obj ? message + `data ${JSON.stringify(info.obj)} | ` : message;
20 | return message;
21 | }),
22 | transports: [
23 | new winston.transports.Console(),
24 | new winston.transports.File({ filename: `${process.env.LOG_FILE_PATH} / ${route}.log` }),
25 | ],
26 | });
27 | this.logger = logger;
28 | }
29 |
30 | async info (message){
31 | this.logger.log('info' , message);
32 | }
33 |
34 | async info (message , obj){
35 | this.logger.log('info' , message , {obj});
36 | }
37 |
38 | async error (message){
39 | this.logger.log('error' , message);
40 | }
41 |
42 | async error (message , obj){
43 | this.logger.log('error' , message , {obj});
44 | }
45 |
46 | async debug (message){
47 | this.logger.log('debug' , message);
48 | }
49 |
50 | async debug (message , obj){
51 | this.logger.log('debug' , message , {obj});
52 | }
53 | }
54 |
55 | module.exports = LoggerService;
--------------------------------------------------------------------------------
/db/queries.js:
--------------------------------------------------------------------------------
1 | exports.queryList = {
2 |
3 | GET_STORE_LIST_QUERY : 'SELECT STORE_ID, STORE_NAME, STORE_CODE FROM BMS.STORE' ,
4 |
5 | SAVE_STORE_QUERY : 'INSERT INTO BMS.STORE (STORE_NAME, STORE_CODE, ADDRESS , CREATED_BY , CREATED_ON) VALUES($1, $2, $3, $4, $5)',
6 |
7 | GET_BOOK_LIST_QUERY : 'SELECT BOOK_ID, BOOK_TITLE, BOOK_AUTHOR, BOOK_PUBLISHER FROM BMS.BOOK',
8 |
9 | GET_BOOK_DETAILS_QUERY : `SELECT BOOK_ID, BOOK_TITLE, BOOK_DESCRIPTION, BOOK_AUTHOR, BOOK_PUBLISHER, BOOK_PAGES
10 | , BOOK.STORE_CODE, store.store_name , store.address FROM BMS.BOOK INNER JOIN BMS.STORE ON BOOK.STORE_CODE = STORE.STORE_CODE
11 | WHERE BOOK_ID =$1`,
12 |
13 | SAVE_BOOK_QUERY : ` INSERT INTO BMS.BOOK (BOOK_TITLE, BOOK_DESCRIPTION, BOOK_AUTHOR, BOOK_PUBLISHER, BOOK_PAGES, STORE_CODE, CREATED_BY , CREATED_ON)
14 | VALUES($1, $2, $3, $4, $5 , $6 , $7 , $8) `,
15 |
16 | UPDATE_BOOK_QUERY : `
17 | UPDATE BMS.BOOK SET BOOK_TITLE=$1, BOOK_DESCRIPTION=$2, BOOK_AUTHOR=$3, BOOK_PUBLISHER=$4,
18 | BOOK_PAGES=$5, STORE_CODE=$6, CREATED_BY=$7 , CREATED_ON=$8
19 | WHERE BOOK_ID=$9
20 | `,
21 |
22 | DELETE_BOOK_QUERY : ` DELETE FROM BMS.BOOK WHERE BOOK_ID=$1 `,
23 |
24 | AUDIT_QUERY : `INSERT INTO BMS.APP_AUDIT (AUDIT_ACTION, AUDIT_DATA, AUDIT_STATUS, AUDIT_ERROR , AUDIT_BY, AUDIT_ON) VALUES($1, $2, $3, $4, $5, $6)
25 | `,
26 |
27 | GET_USER_LIST_QUERY : ` SELECT USER_ID, USERNAME, EMAIL, USER_TYPE_CODE, FULL_NAME, ACTIVE FROM BMS.APP_USER `,
28 |
29 | IS_USER_EXISTS_QUERY : ` SELECT COUNT(USER_ID) FROM BMS.APP_USER WHERE LOWER(USERNAME) =LOWER($1) OR LOWER(EMAIL)=LOWER($2) `,
30 |
31 | SAVE_USER_QUERY : ` INSERT INTO BMS.APP_USER (USERNAME, PASSWORD, EMAIL, USER_TYPE_CODE, FULL_NAME, CREATED_ON, CREATED_BY) VALUES($1, $2, $3, $4, $5, $6, $7) returning * `,
32 |
33 | LOGIN_QUERY : ` SELECT USER_ID, USERNAME, PASSWORD , EMAIL, USER_TYPE_CODE, FULL_NAME, ACTIVE FROM BMS.APP_USER WHERE LOWER(USERNAME) = LOWER($1) AND ACTIVE = 1 `,
34 |
35 |
36 |
37 |
38 |
39 | }
--------------------------------------------------------------------------------
/Util/jwtUtil.js:
--------------------------------------------------------------------------------
1 | var jwt = require('jsonwebtoken');
2 | const dotenv = require('dotenv');
3 | dotenv.config();
4 |
5 | exports.generateToken = (userId , username , email , fullname , userRoles , userTypeCode)=>{
6 | var token = jwt.sign({
7 | userId:userId,
8 | username:username,
9 | email: email,
10 | fullname:fullname,
11 | roles:userRoles,
12 | userType : userTypeCode,
13 | } , process.env.SECRET , {expiresIn :"3d"})
14 | return token;
15 | }
16 |
17 | exports.verifyToken = function(roles){
18 | return async (req, res, next) => {
19 | try {
20 | const {token} = req.headers;
21 | console.log("token : " + token)
22 | if(!token){
23 | console.log("No token exist");
24 | return res.status(500).send({error : 'Token is not exist'})
25 | }
26 | // should validate if loggedIn user has the same role
27 | var decode = jwt.verify(token , process.env.SECRET);
28 | console.log("decode:" + JSON.stringify(decode))
29 | req.user = {
30 | userId:decode.userId,
31 | username:decode.username,
32 | email: decode.email,
33 | fullname:decode.fullname,
34 | roles:decode.roles,
35 | userType : roles.userType
36 | }
37 | console.log("roles : " + roles);
38 |
39 | if(!this.hasRole(roles , decode.roles)){
40 | console.log("Error : not have the same role");
41 | return res.status(401).send({error : 'Authentication failed'})
42 | }
43 | console.log("valid token");
44 | next();
45 | } catch (error) {
46 | next(error);
47 | }
48 |
49 | }
50 | }
51 |
52 | exports.hasRole = function(routeRoles , userRoles){
53 | console.log("routeRoles : " + routeRoles)
54 | let result= false;
55 | userRoles.forEach(role => {
56 | if(routeRoles.includes(role)){
57 | result = true;
58 | return;
59 | }
60 | });
61 | console.log("result : " + result);
62 | return result;
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/swagger.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "version": "1.0.0",
5 | "title": "Note & Books API",
6 | "description": "Note & Books API",
7 | "license": {
8 | "name": "MIT",
9 | "url": "https://opensource.org/licenses/MIT"
10 | }
11 | },
12 | "host": "localhost:3000",
13 | "basePath": "/",
14 | "tags": [
15 | {
16 | "name": "Note & Books",
17 | "description": "API"
18 | }
19 | ],
20 | "schemes": [
21 | "http"
22 | ],
23 | "consumes": [
24 | "application/json"
25 | ],
26 | "produces": [
27 | "application/json"
28 | ],
29 | "paths": {
30 | "/api/v1/books": {
31 | "get": {
32 | "description": "Returns all BOOKS from the system that the user has access to",
33 | "produces": [
34 | "application/json"
35 | ],
36 | "responses": {
37 | "200": {
38 | "description": "A list of books.",
39 | "schema": {
40 | "type": "array",
41 | "items": {
42 | "$ref": "#/definitions/books"
43 | }
44 | }
45 | }
46 | }
47 | }
48 | }
49 | },
50 | "definitions":{
51 | "book":{
52 | "required":[
53 | "title",
54 | "isbn",
55 | "publisher",
56 | "author"
57 | ],
58 | "properties":{
59 | "bookId":{
60 | "type":"integer"
61 | },
62 | "title":{
63 | "type":"string"
64 | },
65 | "isbn":{
66 | "type":"string"
67 | },
68 | "description":{
69 | "type":"string"
70 | },
71 | "publisher":{
72 | "type":"string"
73 | },
74 | "author":{
75 | "type":"string"
76 | },
77 | "pages":{
78 | "type":"integer"
79 | }
80 | }
81 | },
82 | "books":{
83 | "$ref": "#/definitions/book"
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/controller/noteController.js:
--------------------------------------------------------------------------------
1 | var generator = require('../Util/generator');
2 | var memStorage = require('../Util/memory.storage');
3 | var model = require('../model/note.model');
4 |
5 |
6 | exports.getAllNotes = (req , res) => {
7 | // var seqId = generator.generate();
8 | // memStorage.store.setItem(seqId , "1st_key");
9 | // var seqId_2 = generator.generate();
10 | // memStorage.store.setItem(seqId_2 , "2nd_key");
11 |
12 | // var keys = memStorage.getKeys(memStorage.store);
13 | var values = memStorage.getValues(memStorage.store);
14 | console.log("Values ....... " + JSON.stringify(values));
15 | return res.status(200).send(JSON.stringify(values));
16 | }
17 |
18 | exports.saveNote = (req , res) => {
19 | var seqId = generator.generate();
20 | var createdBy = "admin";
21 | var createdOn = new Date();
22 | // req.body
23 | var title = req.body.title;
24 | var content = req.body.content;
25 | if(!title || !content){
26 | return res.status(500).send({ error: 'Title and Content should not be empty' })
27 | }
28 |
29 | var Note = model.Note;
30 | var noteObj = new Note(seqId , title , content , createdBy , createdOn);
31 | memStorage.store.setItem(seqId , noteObj);
32 | return res.status(201).send("Successfully note saved ");
33 | }
34 |
35 |
36 | exports.updateNote = (req , res) => {
37 |
38 | var createdBy = "admin";
39 | var createdOn = new Date();
40 | // req.body
41 | var noteId = req.body.noteId;
42 | var title = req.body.title;
43 | var content = req.body.content;
44 | if(!noteId){
45 | return res.status(500).send({ error: 'noteId should not be empty' })
46 | }
47 | if(!title || !content){
48 | return res.status(500).send({ error: 'Title and Content should not be empty' })
49 | }
50 |
51 | var noteItem = memStorage.store.getItem(noteId);
52 | if(!noteItem){
53 | return res.status(500).send({ error: 'noteId is not exist' })
54 | }
55 |
56 | var Note = model.Note;
57 | var noteObj = new Note(noteId , title , content , createdBy , createdOn);
58 | memStorage.store.setItem(noteId , noteObj);
59 | return res.status(200).send("Successfully note updated ");
60 | }
61 |
62 |
63 | exports.deleteNote = (req , res) => {
64 | var noteId = req.params.noteId;
65 |
66 | // validate not empty
67 | if(!noteId){
68 | return res.status(500).send({ error: 'can not delete empty noteId' })
69 | }
70 |
71 | // validate is already exists
72 | var noteItem = memStorage.store.getItem(noteId);
73 | if(!noteItem){
74 | return res.status(500).send({ error: 'noteId is not exist' })
75 | }
76 |
77 | // is exits
78 | memStorage.store.removeItem(noteId);
79 | return res.status(200).send("Successfully note deleted ");
80 | }
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/scripts/ddl.sql:
--------------------------------------------------------------------------------
1 | CREATE SCHEMA bms;
2 |
3 | -- bms.book definition
4 |
5 | -- Drop table
6 |
7 | -- DROP TABLE bms.book;
8 |
9 | CREATE TABLE bms.book (
10 | book_id serial NOT NULL,
11 | book_title varchar(300) NOT NULL,
12 | book_description varchar(1000) NULL,
13 | book_author varchar(50) NOT NULL,
14 | book_publisher varchar(50) NOT NULL,
15 | book_pages int4 NULL,
16 | store_code varchar(5) NOT NULL,
17 | created_on timestamp NOT NULL,
18 | created_by varchar(50) NOT NULL,
19 | CONSTRAINT book_pkey PRIMARY KEY (book_id)
20 | );
21 |
22 |
23 | -- bms.store definition
24 |
25 | -- Drop table
26 |
27 | -- DROP TABLE bms.store;
28 |
29 | CREATE TABLE bms.store (
30 | store_id serial NOT NULL,
31 | store_name varchar(100) NOT NULL,
32 | store_code varchar(5) NOT NULL,
33 | created_on timestamp NOT NULL,
34 | created_by varchar(50) NOT NULL,
35 | address varchar(200) NOT NULL,
36 | CONSTRAINT store_pkey PRIMARY KEY (store_id)
37 | );
38 |
39 | -- app_audit
40 | CREATE TABLE bms.app_audit (
41 | audit_id serial NOT NULL,
42 | audit_action varchar(100) NOT NULL,
43 | audit_data json NULL,
44 | audit_by varchar(50) NOT NULL,
45 | audit_on timestamp NOT NULL,
46 | audit_status varchar(50) NULL,
47 | audit_error json NULL,
48 | CONSTRAINT app_audit_pkey PRIMARY KEY (audit_id)
49 | );
50 |
51 | CREATE TABLE bms.app_user (
52 | user_id serial NOT NULL,
53 | username varchar(100) NOT NULL,
54 | "password" varchar(100) NOT NULL,
55 | email varchar(355) NOT NULL,
56 | user_type_code varchar(10) NOT NULL,
57 | full_name varchar(500) NOT NULL,
58 | active int2 NULL DEFAULT 1,
59 | created_on timestamp NULL,
60 | created_by varchar(100) NULL,
61 | updated_on timestamp NULL,
62 | updated_by varchar(100) NULL,
63 | CONSTRAINT user_email_key UNIQUE (email),
64 | CONSTRAINT user_pkey PRIMARY KEY (user_id),
65 | CONSTRAINT user_username_key UNIQUE (username)
66 | );
67 |
68 | CREATE TABLE bms.app_group (
69 | group_id serial NOT NULL,
70 | group_name varchar(100) NOT NULL,
71 | CONSTRAINT group_group_name_key UNIQUE (group_name),
72 | CONSTRAINT group_pkey PRIMARY KEY (group_id)
73 | );
74 |
75 | CREATE TABLE bms.app_role (
76 | role_id serial NOT NULL,
77 | role_name varchar(100) NOT NULL,
78 | CONSTRAINT role_pkey PRIMARY KEY (role_id),
79 | CONSTRAINT role_role_name_key UNIQUE (role_name)
80 | );
81 |
82 | CREATE TABLE bms.user_group (
83 | user_group_id serial NOT NULL,
84 | user_id int4 NULL,
85 | group_id int4 NULL,
86 | CONSTRAINT user_group_pkey PRIMARY KEY (user_group_id)
87 | );
88 |
89 | CREATE TABLE bms.group_role (
90 | group_role_id serial NOT NULL,
91 | group_id int4 NULL,
92 | role_id int4 null,
93 | CONSTRAINT group_role_pkey PRIMARY KEY (group_role_id)
94 | );
95 |
96 | CREATE TABLE bms.user_type (
97 | user_type_id serial NOT NULL,
98 | user_type_name varchar(500) NOT NULL,
99 | user_type_code varchar(10) NOT NULL,
100 | CONSTRAINT user_type_pkey PRIMARY KEY (user_type_id)
101 | );
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | // setup server
2 | var express = require('express');
3 | var cors = require('cors');
4 | var bodyParser = require('body-parser');
5 | var noteRoute = require('./route/noteRoute');
6 | var storeRoute = require('./route/store.route');
7 | var bookRoute = require('./route/book.route');
8 | var userRoute = require('./route/user.route');
9 | var loginRoute = require('./route/login.route');
10 | var uploadRoute = require('./route/upload.route');
11 | var exportRoute = require('./route/export.route');
12 | var paypalRoute = require('./route/paypal.route');
13 | const swaggerUi = require('swagger-ui-express');
14 | const swaggerDocument = require('./swagger.json');
15 |
16 | var app = express();
17 | const { Server } = require("socket.io");
18 |
19 |
20 | app.use(cors())
21 |
22 | // parse application/x-www-form-urlencoded
23 | app.use(bodyParser.urlencoded({ extended: false }))
24 |
25 | // parse application/json
26 | app.use(bodyParser.json());
27 |
28 | app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
29 |
30 | // Expose the node_modules folder as static resources (to access socket.io.js in the browser)
31 | app.use('/static', express.static('node_modules'));
32 |
33 | app.get("/" , function(req , res) {
34 | // res.send("Server started ........");
35 | res.sendFile(__dirname + '/index.html')
36 | });
37 |
38 | app.get("/payment" , function(req , res) {
39 | // res.send("Server started ........");
40 | res.sendFile(__dirname + '/payment.html')
41 | });
42 |
43 | // success page
44 | app.get('/success' , (req ,res ) => {
45 | res.sendFile(__dirname + '/success.html')
46 | })
47 | // error page
48 | app.get('/err' , (req , res) => {
49 | res.sendFile(__dirname + '/error.html')
50 | })
51 |
52 | app.use("/api/v1" , noteRoute);
53 | app.use("/api/v1" , storeRoute);
54 | app.use("/api/v1" , bookRoute);
55 | app.use("/api/v1" , userRoute);
56 | app.use("/api/v1" , loginRoute);
57 | app.use("/api/v1" , uploadRoute);
58 | app.use("/api/v1" , exportRoute);
59 | app.use("/api/v1" , paypalRoute);
60 |
61 |
62 |
63 | const server= app.listen(4000, () => {
64 | console.log(`Server start ....... `)
65 | })
66 |
67 | // initialize & listen to server
68 | const io = new Server(server);
69 | // Handle connection
70 | io.on('connection', function (socket) {
71 | console.log("Connected successfully to the socket ...");
72 |
73 | setInterval(function(){
74 | var news = getNews();
75 | // Send news on the socket
76 | socket.emit('news', news);
77 | } , 5000);
78 |
79 |
80 | socket.on('my other event', function (data) {
81 | console.log(data);
82 | });
83 | });
84 |
85 | function getNews(){
86 | var length = Math.floor(Math.random() * 21);
87 | var news = [];
88 | for(var i = 0; i < length ; i++ ){
89 | var val = {id : i , title : 'The cure of the Sadness is to play Videogames' + i , date: new Date() }
90 | news.push(val);
91 | }
92 | return news
93 | }
94 |
95 |
96 |
97 |
98 |
99 | module.exports = app
--------------------------------------------------------------------------------
/controller/login.controller.js:
--------------------------------------------------------------------------------
1 | var queries = require('../db/queries');
2 | var dbConnection = require('../db/connection');
3 | var util = require('../Util/utility');
4 | var validationUtil = require('../Util/validation');
5 | var Logger = require('../services/logger.service');
6 | var auditService = require('../audit/audit.service');
7 | var auditAction = require('../audit/auditAction');
8 | var APIError = require('../error/api.error');
9 | var errorStatus = require('../error/error.status');
10 | var errorType = require('../error/error.type');
11 | var bcrypt = require('bcryptjs');
12 | var jwtUtil = require('../Util/jwtUtil');
13 |
14 | const logger = new Logger('login.controller');
15 |
16 |
17 | exports.getUserProfile = async (req , res) => {
18 | var user = req.user;
19 | try {
20 | return res.status(200).send(JSON.stringify(user));
21 | } catch (err) {
22 | console.log("Error : " + err);
23 | let errorMessage = 'Failed to get user : ' + err;
24 | return res.status(500).send({error : 'Failed to get user'});
25 | }
26 | }
27 |
28 | exports.signIn = async (req , res) => {
29 | try {
30 | const {username , password} = req.body;
31 |
32 | /**
33 | * 1- validate is not empty
34 | * 2- get user by username
35 | * 3- Compare password
36 | * 4- get user roles
37 | * 5- generate token
38 | */
39 |
40 | if(!username || !password){
41 | return res.status(500).send({ error: 'username , password are required , can not empty' })
42 | }
43 |
44 | var loginQuery = queries.queryList.LOGIN_QUERY;
45 | var result = await dbConnection.dbQuery(loginQuery , [username]);
46 | var dbResponse = result.rows[0];
47 | if(dbResponse == null){
48 | logger.info("user : ["+username+"] not exists in db");
49 | return res.status(errorStatus.unauthorized).send({ error: 'Invalid username or password' });
50 | }
51 |
52 | var isPasswordValid = validationUtil.comparePassword(password , dbResponse.password);
53 | if(!isPasswordValid){
54 | logger.info("Invalid password");
55 | return res.status(errorStatus.unauthorized).send({ error: 'Invalid username or password' });
56 | }
57 |
58 | var userRoles = await this.getUserRoles(dbResponse.user_id , req , res);
59 | console.log("userRoles : " + JSON.stringify(userRoles));
60 | var token = jwtUtil.generateToken(dbResponse.user_id , dbResponse.username , dbResponse.email , dbResponse.FULL_NAME , userRoles , dbResponse.user_type_code);
61 | return res.status(200).send(JSON.stringify(token));
62 | } catch (err) {
63 | logger.error("Failed to SignIn , Invalid username or password" + JSON.stringify(err))
64 | return res.status(500).send({error : 'Failed to SignIn , Invalid username or password'});
65 | }
66 |
67 | }
68 |
69 |
70 | exports.getUserRoles = async (userId) => {
71 | try {
72 | let roles = ["user"];
73 | return roles;
74 | } catch (err) {
75 |
76 | }
77 |
78 | }
79 |
80 |
81 |
--------------------------------------------------------------------------------
/controller/user.controller.js:
--------------------------------------------------------------------------------
1 | var queries = require('../db/queries');
2 | var dbConnection = require('../db/connection');
3 | var util = require('../Util/utility');
4 | var validationUtil = require('../Util/validation');
5 | var Logger = require('../services/logger.service');
6 | var auditService = require('../audit/audit.service');
7 | var auditAction = require('../audit/auditAction');
8 | var APIError = require('../error/api.error');
9 | var errorStatus = require('../error/error.status');
10 | var errorType = require('../error/error.type');
11 | var bcrypt = require('bcryptjs');
12 |
13 | const logger = new Logger('user.controller');
14 |
15 | exports.getUserList = async (req , res) => {
16 | var auditOn = util.dateFormat();
17 | try {
18 | var userListQuery = queries.queryList.GET_USER_LIST_QUERY;
19 | var result = await dbConnection.dbQuery(userListQuery);
20 | logger.info("return user List" , result.rows);
21 | auditService.prepareAudit(auditAction.actionList.GET_USER_LIST , result.rows , null , "postman" , auditOn);
22 | return res.status(200).send(JSON.stringify(result.rows));
23 | } catch (err) {
24 | console.log("Error : " + err);
25 | let errorMessage = 'Failed to get users : ' + err;
26 | auditService.prepareAudit(auditAction.actionList.GET_USER_LIST , null , JSON.stringify(errorMessage) , "postman" , auditOn);
27 | return res.status(500).send({error : 'Failed to get users'});
28 | }
29 | }
30 |
31 | /**
32 |
33 | * @param {*} req
34 | * @param {*} res
35 | * @returns
36 | */
37 | exports.saveUser = async (req , res) => {
38 |
39 | try {
40 |
41 | var createdBy = "admin";
42 | var createdOn = new Date();
43 | // req.body
44 | var username = req.body.username;
45 | var password = req.body.password;
46 | var email = req.body.email;
47 | var fullname = req.body.fullname;
48 | var userTypeCode = req.body.userTypeCode;
49 | // list groups added to user
50 | var groups = req.body.groups;
51 |
52 | if(!username || !password || !email || !fullname || !userTypeCode || !groups){
53 | return res.status(500).send({ error: 'username , password , email , fullname , userTypeCode , selected groups are required , can not empty' })
54 | }
55 |
56 | /**
57 | * Validation
58 | * 1- username or email not exist
59 | * 2- is email
60 | * 3- validate password strength
61 | * */
62 |
63 | var isUserExistsQuery = queries.queryList.IS_USER_EXISTS_QUERY;
64 | var result =await dbConnection.dbQuery(isUserExistsQuery , [username , email]);
65 | console.log("Result : " + JSON.stringify(result))
66 | if (result.rows[0].count != "0") {
67 | return res.status(500).send({ error: 'User already Exists' })
68 | }
69 |
70 | if(!validationUtil.isValidEmail(email)){
71 | return res.status(500).send({ error: 'Email is not valid' })
72 | }
73 |
74 | if(!validationUtil.isValidPassword(password)){
75 | return res.status(500).send({ error: 'Password is not valid' })
76 | }
77 |
78 | // everything is OK
79 | var hashedPassword = await bcrypt.hash(password, 10);
80 | values =[username , hashedPassword , email , userTypeCode , fullname , createdOn , createdBy];
81 | var saveUserQuery = queries.queryList.SAVE_USER_QUERY;
82 | await dbConnection.dbQuery(saveUserQuery , values);
83 | return res.status(201).send("Successfully adding new user ");
84 | } catch (err) {
85 | console.log("Error : " + err);
86 | return res.status(500).send({error : 'Failed to add new user'});
87 | }
88 | }
--------------------------------------------------------------------------------
/controller/book.controller.js:
--------------------------------------------------------------------------------
1 | var queries = require('../db/queries');
2 | var dbConnection = require('../db/connection');
3 | var util = require('../Util/utility');
4 | var Logger = require('../services/logger.service');
5 | var auditService = require('../audit/audit.service');
6 | var auditAction = require('../audit/auditAction');
7 | var APIError = require('../error/api.error');
8 | var errorStatus = require('../error/error.status');
9 | var errorType = require('../error/error.type');
10 |
11 | const logger = new Logger('book.controller');
12 |
13 | exports.getBookList = async (req , res) => {
14 | var auditOn = util.dateFormat();
15 | try {
16 | var bookListQuery = queries.queryList.GET_BOOK_LIST_QUERY;
17 | var result = await dbConnection.dbQuery(bookListQuery);
18 | logger.info("return Book List" , result.rows);
19 | auditService.prepareAudit(auditAction.actionList.GET_BOOK_LIST , result.rows , null , "postman" , auditOn);
20 | return res.status(200).send(JSON.stringify(result.rows));
21 | } catch (err) {
22 | console.log("Error : " + err);
23 | let errorMessage = 'Failed to get books' + err;
24 | auditService.prepareAudit(auditAction.actionList.GET_BOOK_LIST , null , JSON.stringify(errorMessage) , "postman" , auditOn);
25 | return res.status(500).send({error : 'Failed to get books'});
26 | }
27 | }
28 |
29 | exports.getBookDetails = async (req , res) => {
30 | try {
31 | var bookId = req.params.bookId;
32 | console.log("bookId : " + bookId);
33 | if (isNaN(bookId))
34 | throw new APIError(errorType.API_ERROR ,
35 | errorStatus.INTERNAL_SERVER_ERROR ,
36 | "Invalid bookId , is not a number , bookId value is : " + bookId ,
37 | true);
38 |
39 | var bookDetailsQuery = queries.queryList.GET_BOOK_DETAILS_QUERY;
40 | var result = await dbConnection.dbQuery(bookDetailsQuery , [bookId]);
41 | return res.status(200).send(JSON.stringify(result.rows[0]));
42 | } catch (err) {
43 | console.log("Error : " + err.description);
44 | if(err.name === errorType.SQL_INJECTION_ERROR)
45 | // handlerError();
46 | logger.error("Failed to get Book details " , JSON.stringify(err));
47 | return res.status(500).send({error : 'Failed to get book details'});
48 | }
49 | }
50 |
51 |
52 | exports.saveBook = async (req , res) => {
53 |
54 | try {
55 |
56 | var createdBy = "admin";
57 | var createdOn = new Date();
58 | // req.body
59 | var title = req.body.title;
60 | var description = req.body.description;
61 | var author = req.body.author;
62 | var publisher = req.body.publisher;
63 | var pages = req.body.pages;
64 | var storeCode = req.body.storeCode;
65 |
66 | // console.log("storeName : " + storeName + " ----- address : " + address)
67 | if(!title || !author || !publisher || !storeCode){
68 | return res.status(500).send({ error: 'title , author , publisher , storeCode are required , can not empty' })
69 | }
70 |
71 | values =[title , description , author , publisher , pages , storeCode, createdBy , createdOn];
72 | var saveBookQuery = queries.queryList.SAVE_BOOK_QUERY;
73 | await dbConnection.dbQuery(saveBookQuery , values);
74 | return res.status(201).send("Successfully adding new book ");
75 | } catch (err) {
76 | console.log("Error : " + err);
77 | return res.status(500).send({error : 'Failed to add new book'});
78 | }
79 | }
80 |
81 | exports.updateBook = async (req , res) => {
82 |
83 | try {
84 |
85 | var createdBy = "admin";
86 | var createdOn = new Date();
87 | // req.body
88 | var bookId=req.body.bookId;
89 | var title = req.body.title;
90 | var description = req.body.description;
91 | var author = req.body.author;
92 | var publisher = req.body.publisher;
93 | var pages = req.body.pages;
94 | var storeCode = req.body.storeCode;
95 |
96 | if(!bookId || !title || !author || !publisher || !storeCode){
97 | return res.status(500).send({ error: 'bookId , title , author , publisher , storeCode are required , can not empty' })
98 | }
99 |
100 | values =[title , description , author , publisher , pages , storeCode, createdBy , createdOn , bookId];
101 | var updateBookQuery = queries.queryList.UPDATE_BOOK_QUERY;
102 | await dbConnection.dbQuery(updateBookQuery , values);
103 | return res.status(200).send("Successfully update book title :" + title);
104 | } catch (err) {
105 | console.log("Error : " + err);
106 | return res.status(500).send({error : 'Failed to update book title : '+ title});
107 | }
108 | }
109 |
110 | exports.deleteBook = async (req , res) => {
111 | var bookId = req.params.bookId;
112 |
113 | try {
114 | // validate not empty
115 | if(!bookId){
116 | return res.status(500).send({ error: 'can not delete empty bookId' })
117 | }
118 |
119 | var deleteBookQuery = queries.queryList.DELETE_BOOK_QUERY;
120 | await dbConnection.dbQuery(deleteBookQuery , [bookId]);
121 |
122 | return res.status(200).send("Successfully book deleted ");
123 | } catch (err) {
124 | console.log("Error : " + err);
125 | return res.status(500).send({error : 'Failed to delete book with id : '+ bookId});
126 | }
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | }
--------------------------------------------------------------------------------