diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/README.md b/README.md new file mode 100644 index 0000000..98adbcf --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +#Node.js-Express-MongoDB CRUD sample Application + +This is a simple Node.js CRUD application using MongoDB. + +It is based on +[https://github.com/ijason/NodeJS-Sample-App](https://github.com/ijason/NodeJS-Sample-App) and has the following features: + ++ includes Wercker configuration ++ application changes to run on Oracle Container Cloud Service + +### How to run + + npm install + node app.js + +### Configuration + +MongoDB: `mongodb://mongodb` + +Express: `app.listen(process.env.PORT || 3000);` + +##History + +### 1.0.0 + +- Initial version + +## License + +The Universal Permissive License (UPL), Version 1.0 + diff --git a/app.js b/app.js new file mode 100644 index 0000000..45e24a4 --- /dev/null +++ b/app.js @@ -0,0 +1,92 @@ +/** + * Module dependencies. + */ + +var express = require('express') + , routes = require('./routes') + , user = require('./routes/user') + , http = require('http') + , path = require('path') + , EmployeeProvider = require('./employeeprovider').EmployeeProvider; + +var app = express(); + +app.configure(function(){ + app.set('port', process.env.PORT || 3000); + app.set('views', __dirname + '/views'); + app.set('view engine', 'jade'); + app.set('view options', {layout: false}); + app.use(express.favicon()); + app.use(express.logger('dev')); + app.use(express.bodyParser()); + app.use(express.methodOverride()); + app.use(app.router); + app.use(express.static(path.join(__dirname, 'public'))); + app.enable('trust proxy'); +}); + +app.configure('development', function(){ + app.use(express.errorHandler()); +}); + +var employeeProvider= new EmployeeProvider(); + +//Routes + +//index +app.get('/', function(req, res){ + employeeProvider.findAll(function(error, emps){ + res.render('index', { + title: 'Employees', + employees:emps + }); + }); +}); + +//new employee +app.get('/employee/new', function(req, res) { + res.render('employee_new', { + title: 'New Employee' + }); +}); + +//save new employee +app.post('/employee/new', function(req, res){ + employeeProvider.save({ + name: req.param('name'), + title: req.param('title') + }, function( error, docs) { + res.redirect('/') + }); +}); + +//update an employee +app.get('/employee/:id/edit', function(req, res) { + employeeProvider.findById(req.params.id, function(error, employee) { + res.render('employee_edit', + { + _id: employee._id.toHexString(), + name: employee.name, + title: employee.title, + }); + }); +}); + +//save updated employee +app.post('/employee/:id/edit', function(req, res) { + employeeProvider.update(req.params.id,{ + name: req.param('name'), + title: req.param('title') + }, function(error, docs) { + res.redirect('/') + }); +}); + +//delete an employee +app.get('/employee/:id/delete', function(req, res) { + employeeProvider.delete(req.params.id, function(error, docs) { + res.redirect('/') + }); +}); + +app.listen(process.env.PORT || 3000); diff --git a/employeeprovider.js b/employeeprovider.js new file mode 100644 index 0000000..c380b9f --- /dev/null +++ b/employeeprovider.js @@ -0,0 +1,108 @@ +var Db = require('mongodb').Db, + MongoClient = require('mongodb').MongoClient, + Server = require('mongodb').Server, + ReplSetServers = require('mongodb').ReplSetServers, + ObjectID = require('mongodb').ObjectID, + Binary = require('mongodb').Binary, + GridStore = require('mongodb').GridStore, + Grid = require('mongodb').Grid, + Code = require('mongodb').Code, + BSON = require('mongodb').pure().BSON, + assert = require('assert'); + +EmployeeProvider = function() { + var that = this; + mongodbUri = process.env.MONGOLAB_URI || 'mongodb://mongodb'; + MongoClient.connect(mongodbUri, function(err, db){ + if(err) { return console.dir(err); } + that.db = db; + }) +}; + + +EmployeeProvider.prototype.getCollection= function(callback) { + this.db.collection('employees', function(error, employee_collection) { + if( error ) callback(error); + else callback(null, employee_collection); + }); +}; + +//find all employees +EmployeeProvider.prototype.findAll = function(callback) { + this.getCollection(function(error, employee_collection) { + if( error ) callback(error) + else { + employee_collection.find().toArray(function(error, results) { + if( error ) callback(error) + else callback(null, results) + }); + } + }); +}; + +//find an employee by ID +EmployeeProvider.prototype.findById = function(id, callback) { + this.getCollection(function(error, employee_collection) { + if( error ) callback(error) + else { + employee_collection.findOne({_id: employee_collection.db.bson_serializer.ObjectID.createFromHexString(id)}, function(error, result) { + if( error ) callback(error) + else callback(null, result) + }); + } + }); +}; + + +//save new employee +EmployeeProvider.prototype.save = function(employees, callback) { + this.getCollection(function(error, employee_collection) { + if( error ) callback(error) + else { + if( typeof(employees.length)=="undefined") + employees = [employees]; + + for( var i =0;i< employees.length;i++ ) { + employee = employees[i]; + employee.created_at = new Date(); + } + + employee_collection.insert(employees, function() { + callback(null, employees); + }); + } + }); +}; + +// update an employee +EmployeeProvider.prototype.update = function(employeeId, employees, callback) { + this.getCollection(function(error, employee_collection) { + if( error ) callback(error); + else { + employee_collection.update( + {_id: employee_collection.db.bson_serializer.ObjectID.createFromHexString(employeeId)}, + employees, + function(error, employees) { + if(error) callback(error); + else callback(null, employees) + }); + } + }); +}; + +//delete employee +EmployeeProvider.prototype.delete = function(employeeId, callback) { + this.getCollection(function(error, employee_collection) { + if(error) callback(error); + else { + employee_collection.remove( + {_id: employee_collection.db.bson_serializer.ObjectID.createFromHexString(employeeId)}, + function(error, employee){ + if(error) callback(error); + else callback(null, employee) + }); + } + }); +}; + +exports.EmployeeProvider = EmployeeProvider; diff --git a/package.json b/package.json new file mode 100644 index 0000000..c0a8bee --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "ExpressTut", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app" + }, + "dependencies": { + "express": "3.4.0", + "jade": "*", + "mongodb": "1.3.19" + } +} diff --git a/public/img/rocket.png b/public/img/rocket.png new file mode 100644 index 0000000..3ed2540 Binary files /dev/null and b/public/img/rocket.png differ diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css new file mode 100644 index 0000000..99f9b75 --- /dev/null +++ b/public/stylesheets/style.css @@ -0,0 +1,60 @@ +@import url(http://fonts.googleapis.com/css?family=Titillium+Web:300); + +html, +body { + background: #eee url("../img/rocket.png") bottom left / auto 50% no-repeat; + height: 100%; + font-family: 'Titillium Web', sans-serif; +} + +h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { + font-family: 'Titillium Web', sans-serif; + text-align: center; +} + +#employees { + margin: 0 auto; + padding-bottom: 20px; + width: auto; + max-width: 680px; +} + +.container { + width: auto; +} + +.form-signin { + max-width: 330px; + padding: 15px; + margin: 0 auto; +} +.form-signin .form-signin-heading, +.form-signin .checkbox { + margin-bottom: 10px; +} +.form-signin .checkbox { + font-weight: normal; +} +.form-signin .form-control { + position: relative; + font-size: 16px; + height: auto; + padding: 10px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.form-signin .form-control:focus { + z-index: 2; +} +.form-signin input[name="name"] { + margin-bottom: -1px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +.form-signin input[name="title"] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..f296005 --- /dev/null +++ b/routes/index.js @@ -0,0 +1,8 @@ + +/* + * GET home page. + */ + +exports.index = function(req, res){ + res.render('index', { title: 'Express' }); +}; \ No newline at end of file diff --git a/routes/user.js b/routes/user.js new file mode 100644 index 0000000..d5b34aa --- /dev/null +++ b/routes/user.js @@ -0,0 +1,8 @@ + +/* + * GET users listing. + */ + +exports.list = function(req, res){ + res.send("respond with a resource"); +}; \ No newline at end of file diff --git a/views/employee_edit.jade b/views/employee_edit.jade new file mode 100644 index 0000000..62b933c --- /dev/null +++ b/views/employee_edit.jade @@ -0,0 +1,12 @@ +extends layout + +block content + div.container + form.form-signin(method="post") + h2.form-singin-heading= "Edit Employee" + input(name="_id", type="hidden", value=_id) + input.form-control(type="text", name="name", id="editEmployeeName", placeholder="Name", value=name, autofocus) + input.form-control(type="text", name="title", id="editEmployeeTitle", placeholder="Title", value=title) + input(type="submit", value="Update", class="btn btn-lg btn-primary btn-block") + br + a(href="/")!= "Back to Employee List" diff --git a/views/employee_new.jade b/views/employee_new.jade new file mode 100644 index 0000000..e540c1c --- /dev/null +++ b/views/employee_new.jade @@ -0,0 +1,11 @@ +extends layout + +block content + div.container + form.form-signin(method="post") + h2.form-singin-heading= title + input.form-control(type="text", name="name", id="editEmployeeName", placeholder="Name", autofocus) + input.form-control(type="text", name="title", id="editEmployeeTitle", placeholder="Title") + input(type="submit", value="Save", class="btn btn-lg btn-primary btn-block") + br + a(href="/")!= "Back to Employee List" diff --git a/views/index.jade b/views/index.jade new file mode 100644 index 0000000..48bba5e --- /dev/null +++ b/views/index.jade @@ -0,0 +1,20 @@ +extends layout + +block content + div.container + div.page-header + h1 Hi, I'm an Express + MongoDB app running on OCCS1! + #employees + h2= title + - each employee in employees + div(class="panel panel-primary") + div.created_at(class="hidden")= employee.created_at + div.panel-heading + div.title(class="panel-title")= employee.name + div.panel-body + div(class="col-xs-10 col-md-10")= employee.title + div(class="col-xs-1 col-md-1") + a(href="/employee/" + employee._id.toHexString() + "/edit" class="btn btn-info")!= "Edit" + div(class="col-xs-1 col-md-1") + a(href="/employee/" + employee._id.toHexString() + "/delete" class="btn btn-danger")!= "X" + a(href="/employee/new" class="btn btn-default")!= "Add New Employee" diff --git a/views/layout.jade b/views/layout.jade new file mode 100644 index 0000000..444943d --- /dev/null +++ b/views/layout.jade @@ -0,0 +1,8 @@ +doctype html +html + head + title Node.js + Express + MongoDB App running on cloudControl + link(rel='stylesheet', href='//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css') + link(rel='stylesheet', href='/stylesheets/style.css') + body + block content diff --git a/wercker.yml b/wercker.yml new file mode 100644 index 0000000..287a9bc --- /dev/null +++ b/wercker.yml @@ -0,0 +1,15 @@ +box: node:6.10 +build: + steps: + # A step that executes `npm install` command + - npm-install +push: + steps: + # Push to public docker repo + - internal/docker-push: + username: $DOCKER_USERNAME + password: $DOCKER_PASSWORD + tag: 0.0.1 + repository: $DOCKER_REPOSITORY + registry: https://index.docker.io/v1/ + cmd: node pipeline/source/app.js