Skip to content

Add docker support #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9802ba1
add-github-actions-support
aliartiza75 Jul 26, 2020
9b07e91
[add-docker-support] add Dockerfile
aliartiza75 Jul 26, 2020
ea99fb4
[add-github-actions-support] fix lint issues
aliartiza75 Jul 26, 2020
207d7b9
[add-github-actions-support] add pipeline statement
aliartiza75 Jul 26, 2020
3c8751f
[add-github-actions-support] add pipeline statement
aliartiza75 Jul 26, 2020
a0c8938
[add-github-actions-support] remove file
aliartiza75 Jul 26, 2020
c285992
[add-github-actions-support] update file
aliartiza75 Jul 26, 2020
c4e9a4f
[add-github-actions-support] update file
aliartiza75 Jul 26, 2020
7322c63
[add-github-actions-support] update file
aliartiza75 Jul 26, 2020
9cd7ca3
Merge pull request #3 from aliartiza75/add-github-actions-support
aliartiza75 Jul 26, 2020
bda9caa
[add-docker-support] fix issues
aliartiza75 Jul 26, 2020
44e897b
[add-docker-support] fix issues
aliartiza75 Jul 26, 2020
186fb6d
[add-docker-support] fix issues
aliartiza75 Jul 26, 2020
14bdf5b
[add-docker-support] fix issues
aliartiza75 Jul 26, 2020
98290eb
[add-docker-support] fix issues
aliartiza75 Jul 26, 2020
4e2628f
[add-docker-support] update Dockerfile and add .dockerignore file
aliartiza75 Jul 26, 2020
28e3854
[add-docker-support] update Dockerfile
aliartiza75 Jul 26, 2020
27c8ab5
[add-docker-support] update package.json
aliartiza75 Jul 26, 2020
16dd33b
[add-docker-support] update package-lock.json
aliartiza75 Jul 26, 2020
3e1e9b1
[add-docker-support] update Dockerfile
aliartiza75 Jul 26, 2020
6abe331
[add-docker-support] update manifests
aliartiza75 Jul 26, 2020
3f340bb
[add-docker-support] update README.md
aliartiza75 Jul 26, 2020
0fcf3db
[add-docker-support] update and add manifests
aliartiza75 Jul 26, 2020
b4bf90a
[add-docker-support] update manifest
aliartiza75 Jul 26, 2020
57c0d4e
[add-docker-support] update manifest
aliartiza75 Jul 26, 2020
1fdf403
[add-docker-support] update app.js
aliartiza75 Aug 26, 2020
401a886
[add-docker-support] update manifest
aliartiza75 Aug 26, 2020
b751968
[add-docker-support] update manifest
aliartiza75 Aug 26, 2020
f5d2ea4
[add-docker-support] update manifest
aliartiza75 Aug 26, 2020
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
15 changes: 15 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Directories
public
test
.github
build
postman-collection

# Files
.gitignore
.travis.yml
.eslintrc.json
LICENSE
package-lock.json
README.md
CODE_OF_CONDUCT.md
32 changes: 32 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [10.x, 12.x, 14.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: cp .env.example .env
- run: source .env
- run: npm run build --if-present
- run: npm run lint --if-present
# - run: npm test --if-present
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ npm install
```
## How to run

### Running API server locally
### Running API server locally

```bash
npm run dev
Expand All @@ -125,6 +125,20 @@ Press CTRL + C to stop the process.
```
**Note:** `YOUR_DB_CONNECTION_STRING` will be your MongoDB connection string.

## Running as Docker container

1. Build its image:

```bash
sudo docker build -t rest-api-nodejs-mongodb:0.0.1 -f build/package/Dockerfile .
```

2. Run it as a container:

```bash
sudo docker run -it -e MONGODB_URL=mongodb://127.0.0.1:27017/rest-api-nodejs-mongodb -e JWT_SECRET=abc1235 -e JWT_TIMEOUT_DURATION="2 hours" --net host api:0.0.1
```

### Creating new models

If you need to add more models to the project just create a new file in `/models/` and use them in the controllers.
Expand Down
25 changes: 14 additions & 11 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,26 @@ var cors = require("cors");
// DB connection
var MONGODB_URL = process.env.MONGODB_URL;
var mongoose = require("mongoose");
mongoose.connect(MONGODB_URL, { useNewUrlParser: true, useUnifiedTopology: true }).then(() => {
//don't show the log when it is test
if(process.env.NODE_ENV !== "test") {
console.log("Connected to %s", MONGODB_URL);
console.log("App is running ... \n");
console.log("Press CTRL + C to stop the process. \n");
}
})
.catch(err => {
console.error("App starting error:", err.message);
process.exit(1);
});
// var db = mongoose.connection;

mongoose.connect(MONGODB_URL, {useNewUrlParser: true, useUnifiedTopology: true }).then(() =>{
console.log("Connection to mongodb has been successful.");
}).catch((err) => {
console.log("Unable to connect with mongodb");
console.error(err);
process.exit(1);
});

var db = mongoose.connection;
var app = express();

//don't show the log when it is test
if(process.env.NODE_ENV !== "test") {
app.use(logger("dev"));
}


app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
Expand Down
10 changes: 10 additions & 0 deletions build/package/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM node:lts
LABEL MAINTAINER Irtiza Ali (aliartiza75@yahoo.com)

COPY . .

RUN npm install

RUN cp .env.example .env

ENTRYPOINT ["npm", "run", "dev"]
10 changes: 10 additions & 0 deletions build/package/Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM node:lts
LABEL MAINTAINER Irtiza Ali (aliartiza75@yahoo.com)

COPY . .

RUN npm install

RUN cp .env.example .env

ENTRYPOINT ["npm", "start"]
186 changes: 159 additions & 27 deletions controllers/AuthController.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const apiResponse = require("../helpers/apiResponse");
const utility = require("../helpers/utility");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const mailer = require("../helpers/mailer");
const { constants } = require("../helpers/constants");

/**
Expand All @@ -32,7 +33,7 @@ exports.register = [
}
});
}),
body("password").isLength({ min: 8 }).trim().withMessage("Password must be 8 characters or greater."),
body("password").isLength({ min: 6 }).trim().withMessage("Password must be 6 characters or greater."),
// Sanitize fields.
sanitizeBody("firstName").escape(),
sanitizeBody("lastName").escape(),
Expand All @@ -49,25 +50,42 @@ exports.register = [
}else {
//hash input password
bcrypt.hash(req.body.password,10,function(err, hash) {
// generate OTP for confirmation
let otp = utility.randomNumber(4);
// Create User object with escaped and trimmed data
var user = new UserModel(
{
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: hash }
password: hash,
confirmOTP: otp
}
);

user.save(function (err) {
if (err) { return apiResponse.ErrorResponse(res, err); }
let userData = {
_id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email
// Html email body
let html = "<p>Please Confirm your Account.</p><p>OTP: "+otp+"</p>";
// Send confirmation email
mailer.send(
constants.confirmEmails.from,
req.body.email,
"Confirm Account",
html
).then(function(){
// Save user.
user.save(function (err) {
if (err) { return apiResponse.ErrorResponse(res, err); }
let userData = {
_id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email
};
return apiResponse.successResponseWithData(res,"Registration Success.", userData);
});
}).catch(err => {
console.log(err);
return apiResponse.ErrorResponse(res,err);
}) ;
});
}
} catch (err) {
Expand Down Expand Up @@ -101,23 +119,32 @@ exports.login = [
//Compare given password with db's hash.
bcrypt.compare(req.body.password,user.password,function (err,same) {
if(same){
let userData = {
_id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
};
//Prepare JWT token for authentication
const jwtPayload = userData;
const jwtData = {
expiresIn: process.env.JWT_TIMEOUT_DURATION,
};
const secret = process.env.JWT_SECRET;
//Generated JWT token with Payload and secret.
userData.token = jwt.sign(jwtPayload, secret, jwtData);
return apiResponse.successResponseWithData(res,"Login Success.", userData);
}
else {
//Check account confirmation.
if(user.isConfirmed){
// Check User's account active or not.
if(user.status) {
let userData = {
_id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
};
//Prepare JWT token for authentication
const jwtPayload = userData;
const jwtData = {
expiresIn: process.env.JWT_TIMEOUT_DURATION,
};
const secret = process.env.JWT_SECRET;
//Generated JWT token with Payload and secret.
userData.token = jwt.sign(jwtPayload, secret, jwtData);
return apiResponse.successResponseWithData(res,"Login Success.", userData);
}else {
return apiResponse.unauthorizedResponse(res, "Account is not active. Please contact admin.");
}
}else{
return apiResponse.unauthorizedResponse(res, "Account is not confirmed. Please confirm your account.");
}
}else{
return apiResponse.unauthorizedResponse(res, "Email or Password wrong.");
}
});
Expand All @@ -129,4 +156,109 @@ exports.login = [
} catch (err) {
return apiResponse.ErrorResponse(res, err);
}
}];

/**
* Verify Confirm otp.
*
* @param {string} email
* @param {string} otp
*
* @returns {Object}
*/
exports.verifyConfirm = [
body("email").isLength({ min: 1 }).trim().withMessage("Email must be specified.")
.isEmail().withMessage("Email must be a valid email address."),
body("otp").isLength({ min: 1 }).trim().withMessage("OTP must be specified."),
sanitizeBody("email").escape(),
sanitizeBody("otp").escape(),
(req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return apiResponse.validationErrorWithData(res, "Validation Error.", errors.array());
}else {
var query = {email : req.body.email};
UserModel.findOne(query).then(user => {
if (user) {
//Check already confirm or not.
if(!user.isConfirmed){
//Check account confirmation.
if(user.confirmOTP == req.body.otp){
//Update user as confirmed
UserModel.findOneAndUpdate(query, {
isConfirmed: 1,
confirmOTP: null
}).catch(err => {
return apiResponse.ErrorResponse(res, err);
});
return apiResponse.successResponse(res,"Account confirmed success.");
}else{
return apiResponse.unauthorizedResponse(res, "Otp does not match");
}
}else{
return apiResponse.unauthorizedResponse(res, "Account already confirmed.");
}
}else{
return apiResponse.unauthorizedResponse(res, "Specified email not found.");
}
});
}
} catch (err) {
return apiResponse.ErrorResponse(res, err);
}
}];

/**
* Resend Confirm otp.
*
* @param {string} email
*
* @returns {Object}
*/
exports.resendConfirmOtp = [
body("email").isLength({ min: 1 }).trim().withMessage("Email must be specified.")
.isEmail().withMessage("Email must be a valid email address."),
sanitizeBody("email").escape(),
(req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return apiResponse.validationErrorWithData(res, "Validation Error.", errors.array());
}else {
var query = {email : req.body.email};
UserModel.findOne(query).then(user => {
if (user) {
//Check already confirm or not.
if(!user.isConfirmed){
// Generate otp
let otp = utility.randomNumber(4);
// Html email body
let html = "<p>Please Confirm your Account.</p><p>OTP: "+otp+"</p>";
// Send confirmation email
mailer.send(
constants.confirmEmails.from,
req.body.email,
"Confirm Account",
html
).then(function(){
user.isConfirmed = 0;
user.confirmOTP = otp;
// Save user.
user.save(function (err) {
if (err) { return apiResponse.ErrorResponse(res, err); }
return apiResponse.successResponse(res,"Confirm otp sent.");
});
});
}else{
return apiResponse.unauthorizedResponse(res, "Account already confirmed.");
}
}else{
return apiResponse.unauthorizedResponse(res, "Specified email not found.");
}
});
}
} catch (err) {
return apiResponse.ErrorResponse(res, err);
}
}];
Loading