diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..0a7660436 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 646ac519e..fa76cfae7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,30 @@ -.DS_Store -node_modules/ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- +node_modules + +# Debug log from npm +npm-debug.log diff --git a/app.js b/app.js index f0579b1dc..3ae5c78dd 100644 --- a/app.js +++ b/app.js @@ -4,24 +4,44 @@ var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); +var app = express(); -var routes = require('./routes/index'); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); -var app = express(); +var massive = require("massive") +var connectionString = "postgres://localhost/radio_star_" + app.get('env'); + + +// connect to Massive and get the db instance. You can safely use the +// convenience sync method here because its on app load +// you can also use loadSync - it's an alias +var db = massive.connectSync({connectionString : connectionString}); +// console.log(db) +// var db = massive.connectSync({db : "radio_star"}) + +// Set a reference to the massive instance on Express' app: +app.set("db", db); // view engine setup app.set('views', path.join(__dirname, 'views')); -app.set('view engine', 'jade'); +app.set('view engine', 'ejs'); + +module.exports = app; + +var routes = require('./routes/index'); +var users = require('./routes/users'); +// var rentals = require('./routes/rentals'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', routes); +app.use('/users', users); +// app.use('/rentals', rentals) // catch 404 and forward to error handler app.use(function(req, res, next) { @@ -53,6 +73,3 @@ app.use(function(err, req, res, next) { error: {} }); }); - - -module.exports = app; diff --git a/bin/www b/bin/www index 23e9de753..544a8a07d 100755 --- a/bin/www +++ b/bin/www @@ -5,7 +5,7 @@ */ var app = require('../app'); -var debug = require('debug')('video-store-api:server'); +var debug = require('debug')('js-bank-accounts:server'); var http = require('http'); /** diff --git a/controllers/customers.js b/controllers/customers.js new file mode 100644 index 000000000..89447de88 --- /dev/null +++ b/controllers/customers.js @@ -0,0 +1,58 @@ +var Cust = require("../models/customer"); + +var CustController = { + index: function(req, res, next) { + Cust.all(function(error, custs) { + if(error) { + var err = new Error("Error retrieving customer list:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(custs) + } + }); + }, + + subset: function(req, res, next) { + // console.log(req.query) + // console.log("req params query: ", req.params.query) + Cust.sort(req.params.query, req.query.n , req.query.p, function(error, custs) { + // var n = req.params.n + // var p = req.params.p + if(error) { + var err = new Error("Error retrieving customer list:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(custs) + } + }); + }, + +// /customers/:id/current + current: function(req, res, next) { + Cust.find([req.params.id, 'true'], function(error, rentals) { + if(error) { + var err = new Error("Error retrieving customer's current movie list:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(rentals) + } + }); + }, + + history: function(req, res, next) { + Cust.history([req.params.id, 'false'], "rentals.rental_date", function(error, rentals) { + if(error) { + var err = new Error("Error retrieving customer list:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(rentals) + } + }); + } +} + +module.exports = CustController; diff --git a/controllers/index.js b/controllers/index.js new file mode 100644 index 000000000..d694cbad9 --- /dev/null +++ b/controllers/index.js @@ -0,0 +1,37 @@ +var docs = require('../docs.json'); + + +var Controller = { + locals: { + documentation: docs + }, + + index: function(req, res, next) { + res.json('It works!!'); + }, + + docsHTML: function(req, res, next) { + res.render('docs', Controller.locals); + }, + + docsJSON: function(req, res, next) { + res.json(200, docs); + } +}; + +module.exports = Controller; + + + +// var HomePage = { +// zomg: function(req,response) { +// var hi= {"hi": "ZOMG"} +// response.json({cow: 'ZOMG!'}) +// }, +// +// nothing: function(req, response) { +// response.render('index', {title: 'Express'}); +// } +// }; +// +// module.exports = HomePage; diff --git a/controllers/movies.js b/controllers/movies.js new file mode 100644 index 000000000..84a71d63c --- /dev/null +++ b/controllers/movies.js @@ -0,0 +1,91 @@ +var Movie = require("../models/movie"); + +var MovieController = { + index: function(req, res, next) { + Movie.all(function(error, movies) { + if(error) { + var err = new Error("Error retrieving movies list:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(movies) + } + }); + }, + + find: function(req, res, next) { + Movie.sort(req.params.query, req.query.n , req.query.p, function(error, movies) { + if(error) { + var err = new Error("Error retrieving movies list:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(movies) + } + }); + }, + +// /movies/:movie/current + current: function(req, res, next) { + var movie = req.params.movie + var movie = movie.toLowerCase().replace(/^./, movie[0].toUpperCase()); + Movie.find(['true', movie], function(error, movies) { + if(error) { + var err = new Error("Error retrieving customer list:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(movies) + } + }); + }, + + history: function(req, res, next) { + var movie = req.params.movie + var movie = movie.toLowerCase().replace(/^./, movie[0].toUpperCase()); + + console.log(req.params.query) + Movie.history(['false', movie], req.params.query, function(error, movies) { + if(error) { + var err = new Error("Error retrieving customer list:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(movies) + } + }); + } + + // subset: function(req, res, next) { + // Movie.subs(function(error, movies) { + // var n = req.params.n + // var p = req.params.p + // if(error) { + // var err = new Error("Error retrieving movies list:\n" + error.message); + // err.status = 500; + // next(err); + // } else { + // res.json(movies) + // } + // }); + + +// Retrieve a subset of movies (/movies/sort/release-date?n=5&p=1) +// Given a sort column, return n movie records, offset by p records (this will be used to create "pages" of movies) +// Sort columns are +// title +// release_date + + // sort: function(req, res, next) { + // Movie.sort(function(error, movies) { + // if(error) { + // var err = new Error("Error retrieving movie info:\n" + error.message); + // err.status = 500; + // next(err); + // } else { + // res.json(movies) + // } + // }) + // } +} +module.exports = MovieController; diff --git a/controllers/rentals.js b/controllers/rentals.js new file mode 100644 index 000000000..b02605e11 --- /dev/null +++ b/controllers/rentals.js @@ -0,0 +1,74 @@ +var Rental = require('../models/rental'); + +var RentalsController = { + // /rentals/:movie + // returns overview, release_date available inventory and total inventory + find: function(req, res, next) { + Rental.search([req.params.movie.toLowerCase().replace(/ /g, "").replace(/\./g, "")], function(error, movie) { + if(error) { + var err = new Error("Error retrieving movie:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(movie) + } + }); + }, + + findCustomers: function(req, res, next) { + Rental.searchCust(['true', req.params.movie.toLowerCase().replace(/ /g, "").replace(/\./g, "")], function(error, customers) { + if(error) { + var err = new Error("Error:" + error.message); + err.status = 500; + next(err); + } else { + res.json(customers) + } + }); + }, + + checkOut: function(req, res, next) { + // Rental.checkout([req.body.customer], [req.params.movie.toLowerCase().replace(/ /g, "").replace(/\./g, "")], function(error, customers) { + console.log(req.params.id) + Rental.checkout([req.params.id], [req.params.movie.toLowerCase().replace(/ /g, "").replace(/\./g, "")], function(error, customers) { + if(error) { + var err = new Error("Error, could not check out movie at this time:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(customers) + } + }); + }, + + return: function(req, res, next) { + // Rental.return([req.body.customer], [req.params.movie.toLowerCase().replace(/ /g, "").replace(/\./g, "")], function(error, customers) { + Rental.return([req.params.id], [req.params.movie.toLowerCase().replace(/ /g, "").replace(/\./g, "")], function(error, customers) { + if(error) { + var err = new Error("Error, could not return movie at this time:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(customers) + } + }); + }, + + // See a list of customers with overdue movies (/rentals/overdue) + // include customer name, movie title, check-out date, and return date + overdue: function(req, res, next) { + Rental.overdue(Date.now(), function(error, overdueInfo) { + if(error) { + var err = new Error("Error could not retrieve customers:\n" + error.message); + err.status = 500; + next(err); + } else { + res.json(overdueInfo) + } + }); + } + +}; + + +module.exports = RentalsController; diff --git a/db/seeds/rentals.json b/db/seeds/rentals.json new file mode 100644 index 000000000..6a28c37c0 --- /dev/null +++ b/db/seeds/rentals.json @@ -0,0 +1,23 @@ +[ +{ +"movie_id": "1", +"customer_id": "1", +"checked": "false", +"rental_date": "Wed, 29 Apr 2015 07:54:14 -0700", +"due_date": "Wed, 06 May 2015 07:54:14 -0700" +}, +{ +"movie_id": "2", +"customer_id": "1", +"checked": "true", +"rental_date": "Fri, Jun 17 2016 13:33:34 -0700", +"due_date": "Fri, Jun 24 2016 13:33:34 -0700" +}, +{ +"movie_id": "3", +"customer_id": "1", +"checked": "true", +"rental_date": "Fri, Jun 17 2016 13:33:34 -0700", +"due_date": "Fri, Jun 24 2016 13:33:34 -0700" +} +] diff --git a/db/setup/schema.sql b/db/setup/schema.sql new file mode 100644 index 000000000..d380a9a36 --- /dev/null +++ b/db/setup/schema.sql @@ -0,0 +1,45 @@ +DROP TABLE IF EXISTS rentals; +DROP TABLE IF EXISTS movies; +DROP TABLE IF EXISTS customers; + +CREATE TABLE movies( + id serial PRIMARY KEY, + title text, + search_title text, + overview text, + release_date text, + inventory integer, + inventory_total integer +); + +CREATE INDEX movies_title ON movies (title); +CREATE INDEX movies_date ON movies (release_date); + +CREATE TABLE customers( + id serial PRIMARY KEY, + name text, + registered_at text, + address text, + city text, + state text, + postal_code text, + phone text, + account_credit decimal +); + +CREATE INDEX customers_name ON customers (name); +CREATE INDEX customers_date ON customers (registered_at); +CREATE INDEX customers_postal ON customers (postal_code); + +CREATE TABLE rentals( + id serial PRIMARY KEY, + movie_id integer REFERENCES movies (id), + customer_id integer REFERENCES customers (id), + checked text, + rental_date text, + due_date text, + return_date text +); + +CREATE INDEX rentals_customers ON rentals (customer_id); +CREATE INDEX rentals_states ON rentals (checked); diff --git a/docs.json b/docs.json new file mode 100644 index 000000000..47a069add --- /dev/null +++ b/docs.json @@ -0,0 +1,238 @@ +{ + "base_url": "http://localhost:3000", + "data_format": "JSON", + + "endpoints": [ + { + "verb": "GET", + "uri": "/customers", + "description": "Returns a list of all customers that exist in the database.", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "Search results are JSON documents containing an array of customer result hashes", + "no_data": "Error retrieving customer list, status code 500", + "error": "Error retrieving customer list, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/customers/sort/:query", + "description": "Returns a list of customers in the database, sorted by a given parameter. By using an optional query param, the amount displayed can be limited.", + "required_parameters (select one)": [ + { + "parameter": "name", + "description": "customers returned will be sorted in alphabetical order by name" + }, + { + "parameter": "registered_at", + "description": "customers returned will be sorted in ascending order by when they registered" + }, + { + "parameter": "postal_code", + "description": "customers returned will be sorted in ascending order by postal code" + } + ], + "optional_parameters": [ + { + "parameter": "n", + "description": "a query parameter that determines the number of customer records to return" + }, + { + "parameter": "p", + "description": "a query parameter that determines the offset of customer records, to create pages of customers" + } + ], + "return_data": { + "found": "Search results are JSON documents containing an array of customer result hashes", + "no_data": "Error retrieving customer list, status code 500", + "error": "Error retrieving customer list, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/customers/:id/current", + "description": "Returns a list of movies that a customer currently has checked out.", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "Search results are JSON documents containing an array of movie result hashes", + "no_data": "Error retrieving customer's current movie list, status code 500", + "error": "Error retrieving customer's current movie list, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/customers/:id/history", + "description": "Returns a list of movies that a customer has checked out in the past, ordered by checkout date.", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "Search results are JSON documents containing an array of movie result hashes", + "no_data": "Error retrieving rental history list, status code 500", + "error": "Error retrieving rental history list, status code 500" + } + }, + + + { + "verb": "GET", + "uri": "/movies", + "description": "Returns a list of all movies that exist in the database.", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "Search results are JSON documents containing an array of movie result hashes", + "no_data": "Error retrieving movies list, status code 500", + "error": "Error retrieving movies list, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/movies/sort/:query", + "description": "Returns a list of movies in the database, sorted by a given parameter. By using an optional query param, the amount displayed can be limited.", + "required_parameters (select one)": [ + { + "parameter": "title", + "description": "movies returned will be sorted in alphabetical order by movie title" + }, + { + "parameter": "release_date", + "description": "movies returned will be sorted in ascending order by release_date" + } + ], + "optional_parameters": [ + { + "parameter": "n", + "description": "a query parameter that determines the number of movie records to return" + }, + { + "parameter": "p", + "description": "a query parameter that determines the offset of movie records, to create pages of movies" + } + ], + "return_data": { + "found": "Search results are JSON documents containing an array of movie result hashes", + "no_data": "Error retrieving movies list, status code 500", + "error": "Error retrieving movies list, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/movies/:movie/current", + "description": "Returns a list of customers that have currently checked out a copy of the movie.", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "Search results are JSON documents containing an array of customer result hashes", + "no_data": "Error retrieving customer list, status code 500", + "error": "Error retrieving customer list, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/movies/:movie/history/sort/:query", + "description": "Returns a list of customers that have checked out a film in the past", + "required_parameters (select one)": [ + { + "parameter": "name", + "description": "customers returned will be sorted in alphabetical order by customer name" + }, + { + "parameter": "checkout date", + "description": "customers returned will be sorted in ascending order by the checkout date of their rental" + } + ], + "optional_parameters": [], + "return_data": { + "found": "Search results are JSON documents containing an array of customer result hashes", + "no_data": "Error retrieving customer list, status code 500", + "error": "Error retrieving customer list, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/rentals/:title", + "description": "Returns movie info including synopsis, release date, available inventory (not currently checked-out to a customer), and inventory total", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "Search results are JSON documents containing an array of movie info result hash", + "no_data": "Error retrieving movie info, status code 500", + "error": "Error retrieving movie info, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/rentals/:movie/customers", + "description": "See a list of customers that have currently checked out any of the movie’s inventory", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "Search results are JSON documents containing an array of customer result hash", + "no_data": "Error retrieving customers, status code 500", + "error": "Error retrieving customers, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/rentals/:movie/check-out", + "description": "Check out one of the movie’s inventory to the customer, establishes a return date, and charges customer account $1.50", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "JSON document that has rental due date", + "no_data": "Error, could not check out movie at this time, status code 500", + "error": "Error, could not check out movie at this time, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/rentals/:movie/return", + "description": "Check in one of customer’s rentals", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "JSON document confirms movie returned successfully", + "no_data": "Error, could not return movie at this time, status code 500", + "error": "Error, could not return movie at this time, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/rentals/overdue", + "description": "See a list of customers that have currently checked out any of the movie’s inventory", + "required_parameters": [], + "optional_parameters": [], + "return_data": { + "found": "Search results are JSON documents containing an array of customer result hashes", + "no_data": "Error could not retrieve customers, status code 500", + "error": "Error could not retrieve customers, status code 500" + } + }, + + { + "verb": "GET", + "uri": "/api/docs", + "description": "Serves a HTML view of documentation" + }, + + { + "verb": "GET", + "uri": "/api/docs.json", + "description": "Serves JSON documentation" + } + + ] +} diff --git a/models/customer.js b/models/customer.js new file mode 100644 index 000000000..51f3414e6 --- /dev/null +++ b/models/customer.js @@ -0,0 +1,76 @@ +var app = require("../app"); +var db = app.get("db"); + +var Cust = function(cust) { + this.id = cust; +}; + +// class +Cust.all = function(callback) { + db.query("select * from customers", function(error, custs) { + if(error || !custs || custs === 0) { + callback(error || new Error("Could not retrieve customers"), undefined); + } else { + var allCusts = custs.map(function(cust) { + return new Cust(cust); + }); + // console.log(allCusts) + callback(null, allCusts) + }; + }); +}; + +Cust.sort = function(query, n, p, callback) { + db.customers.find({}, { + order: query, + limit: n, + offset: p + }, function(error, custs) { + console.log(custs) + if(error || !custs) { + callback(error || new Error("Could not retrieve customer"), undefined); + } else { + var allCusts = custs.map(function(cust) { + return new Cust(cust); + }); + callback(null, allCusts) + }; + }); +}; + +Cust.find = function(input, callback) { + // find all rentals that this customer has checked out + // console/.log(input) + db.run("SELECT * FROM movies INNER JOIN rentals ON rentals.movie_id=movies.id WHERE rentals.customer_id=$1 and rentals.checked=$2;", input, function(error, rentals) { + // console.log(rentals) + if(error || !rentals || rentals.length ===0) { + callback(error || new Error("Could not retrieve customers rentals"), undefined); + } else { + callback(null, rentals.map(function(rental) { + return rental; + })); + }; + }); +}; + +Cust.history = function(input, query, callback) { + db.run("SELECT * FROM movies INNER JOIN rentals ON rentals.movie_id=movies.id WHERE rentals.customer_id=$1 and rentals.checked=$2 ORDER BY " + query + ";" , input, function(error, rentals) { + // console.log(rentals) + if(error || !rentals || rentals.length === 0) { + callback(error || new Error("Could not retrieve customers rentals"), undefined); + } else { + callback(null, rentals.map(function(rental) { + return (rental); + })); + } + }); +} + +// only attach this function if we're in test mode +// if (app.get('env') === 'test') { +// Cust.close_connection = function() { +// console.log("closing connection") +// db.end() +// } +// } +module.exports = Cust; diff --git a/models/movie.js b/models/movie.js new file mode 100644 index 000000000..afdaaba41 --- /dev/null +++ b/models/movie.js @@ -0,0 +1,79 @@ +var app = require("../app"); +var db = app.get("db"); + +// console.log(db) +var Movie = function(movie) { + this.id = movie.id; + this.title = movie.title; + this.release_date = movie.release_date; + this.synopsis = movie.overview; +}; + +// Instance functions + +// class +Movie.all = function(callback) { + db.query("select * from movies", function(error, movies) { + if(error || !movies) { + callback(error || new Error("Could not retrieve movies"), undefined); + } else { + callback(null, movies.map(function(movie){ + return new Movie(movie); + })) + }; + }); +}; + +Movie.sort = function(query, n, p, callback) { + db.movies.find({}, { + order: query, + limit: n, + offset: p + }, function(error, movies) { + if(error || !movies) { + callback(error || new Error("Could not retrieve movies"), undefined); + } else { + var allMovies = movies.map(function(movie) { + return new Movie(movie); + }); + callback(null, allMovies) + }; + }); +}; + + +Movie.find = function(input, callback) { + db.run("SELECT customers.* FROM movies INNER JOIN rentals ON rentals.movie_id=movies.id INNER JOIN customers ON customers.id=rentals.customer_id WHERE rentals.checked=$1 AND movies.search_title=$2", input, function(error,customers) { + if(error || !customers) { + callback(error || new Error("Could not retrieve customers customers"), undefined); + } else { + callback(null, customers.map(function(customer) { + return (customer); + })); + }; + }); +}; + +Movie.history = function(input, query, callback) { + // console.log(input) + db.run("SELECT customers.* FROM movies INNER JOIN rentals ON rentals.movie_id=movies.id INNER JOIN customers ON customers.id=rentals.customer_id WHERE rentals.checked = $1 AND movies.title=$2 ORDER BY " + query + ";", input, function(error,customers) { + if(error || !customers || customers.length ===0) { + callback(error || new Error("Could not retrieve a history of customers who have rented this movie."), undefined); + } else { + callback(null, customers.map(function(customer) { + return (customer); + })); + } + }); +} + + + +// only attach this function if we're in test mode +if (app.get('env') === 'test') { + Movie.close_connection = function() { + console.log("closing connection") + db.end() + } +} +module.exports = Movie; diff --git a/models/rental.js b/models/rental.js new file mode 100644 index 000000000..9a6e344bb --- /dev/null +++ b/models/rental.js @@ -0,0 +1,191 @@ +var app = require('../app') +var db = app.get("db") +// var Movie = require('./movie') + +var Rental = function (rental) { + this.rental = rental; +}; + +// /rentals/:movie +// returns overview, release_date available inventory and total inventory +Rental.search = function (input, callback) { + db.run("SELECT overview, release_date, inventory, inventory_total FROM movies WHERE search_title=$1", input, function (error, movie) { + if (error || !movie) { + callback(new Error("Could not retrieve movie"), undefined) + } else { + callback(null, movie.map (function (movies) { + return (movies) + })); + } + }); +} + +// /rentals/:movie/customers +// returns list of customers (assume its full info) +Rental.searchCust = function (input, callback) { + console.log(input) + db.run("SELECT customers.* FROM movies INNER JOIN rentals ON rentals.movie_id=movies.id INNER JOIN customers ON customers.id=rentals.customer_id WHERE rentals.checked=$1 AND search_title=$2", input, function (error, customer) { + if (error || !customer || customer.length === 0) { + console.log(customer) + callback(new Error("Could not retrieve customer"), undefined) + } else { + callback(null, customer.map (function (customers) { + return (customers) + })); + } + }) +} + + +Rental.checkout = function (customer_id, movie, callback) { + // check to see if movie exists + db.run("SELECT movies.id from movies WHERE search_title=$1", movie, function (error, movieid) { + if (error || !movieid || movieid.length===0) { + callback(new Error("Could not retrieve movie based on movie title."), undefined) + } else { + + // check to see if there is inventory + db.run("SELECT * from movies WHERE search_title=$1 AND inventory > 0", movie, function (error, movieinfo) { + if (error || !movieinfo || movieinfo.length===0) { + callback(new Error("Movie is not available to rent. Zero inventory."), undefined) + } else { + + // check to see if customer exists + db.run("SELECT customers.id from customers WHERE id=$1", customer_id, function (error, customerid) { + if (error || !customerid || customerid.length===0) { + callback(new Error("Could not retrieve customer from database. Customer id should be sent in JSON body."), undefined) + } else { + + // check to see if customer got $$$$$ + db.run("SELECT * from customers WHERE id=$1 AND account_credit > 1.49", customer_id, function (error, cust) { + if (error || !cust || cust.length===0) { + callback(new Error("Customer does not have enough money for a rental."), undefined) + } else { + + // update RENTALSSSS. this should always work, thanks to the movie and customer checks above. + var insertArray = []; + // duedate is 7 days after Date.now + var duedate = (new Date(Date.now(new Date())+604800000)).toString(); + insertArray.push(movieid[0]["id"], customer_id[0], 'true', (new Date()).toString(), duedate) + db.run("INSERT INTO rentals (movie_id, customer_id, checked, rental_date, due_date) VALUES ($1, $2, $3, $4, $5);", insertArray, function (error, rentals) { + if (error || !rentals) { + callback(new Error("Could not update rental info"), undefined) + } else { + + // update customer credit -1.50 AFTER making the rental + db.run("UPDATE customers SET account_credit=account_credit-1.5 WHERE id=$1;", customer_id, function (error, updates) { + if (error || !updates) { + callback(new Error("Could not update customer credit, might not have enough money"), undefined) + } else { + + // update movie inventory + db.run("UPDATE movies SET inventory=inventory-1 WHERE search_title=$1;", movie, function (error, updatesmovie) { + if (error || !updatesmovie) { + callback(new Error("Could not update movie inventory"), undefined) + } else { + + // NO ERRORSSSSS! return the due date for the rental + callback(null, {return_date: duedate}); + } + }) + }}); + }}); + }}); + }}); + }}); + }}); +}; + +Rental.return = function (customer_id, movie_title, callback) { + // check to see if movie exists + db.movies.where("search_title=$1", movie_title, function (error, movie) { + // console.log(movie) + if (error || !movie) { + callback(new Error("Could not retrieve movie based on given movie title"), undefined) + } else { + + // check to see if customer exists + db.customers.where("id=$1", customer_id, function (error, customer) { + if (error || !customer) { + callback(new Error("Could not retrieve customer from database"), undefined) + } else { + + // does this person even have a rental?? + // if multiple rentals.. assume customer wants to return one with closest due date -> LIMIT 1 will limit to the first found id. + var arrCheck = [] + arrCheck.push(customer_id[0], movie[0].id, 'true') + db.run("SELECT * FROM rentals WHERE customer_id=$1 AND movie_id=$2 AND checked=$3 LIMIT 1", arrCheck, function (error, rental) { + if (error || !rental || rental.length===0) { + callback(new Error("Customer currently does not have this movie checked out"), undefined) + } else { + + // Update rentals checked in and return date + // This should always work, thanks to the movie, customer and rental checks above. + var insertArray = []; + var returndate = (new Date()).toString(); + insertArray.push('false', returndate, rental[0]["id"]) + db.run("UPDATE rentals SET checked=$1, return_date=$2 WHERE id=$3;", insertArray, function (error, rentalupdate) { + if (error || !rentalupdate) { + callback(new Error("Could not update rental info"), undefined) + } else { + + // update movie inventory + console.log(movie_title) + db.run("UPDATE movies SET inventory=inventory+1 WHERE search_title=$1;", movie_title, function (error, updatesmovie) { + if (error || !updatesmovie) { + callback(new Error("Could not update movie inventory"), undefined) + } else { + callback(undefined, {return: "Movie has been successfully returned"}) + }}) + }}) + }}) + }}) + }}) +}; + + +Rental.overdue = function (date, callback) { + // find all rentals that are checked out + var totaloutput = [] + db.run("SELECT * FROM rentals WHERE checked='true'", function (error, overdue) { + if (error || !overdue || overdue.length ===0) { + callback(new Error("Could not find overdue rentals"), undefined) + }else { + var arrayOfOverdue = [] + overdue.map(function(info) { + if (date > (new Date(info.due_date).getTime()) ) { + arrayOfOverdue.push(info) + }}); + for (var rental of arrayOfOverdue) { + console.log(rental) + db.movies.findOne({id: rental.movie_id}, function(rental, error, movie) { + console.log("movie?: ", movie) + if (error || !movie) { + callback(new Error("Could not find movie"), undefined) + } else { + db.customers.findOne({id: rental.customer_id}, function(error, customer) { + console.log("customer?: ", customer) + if (error || !customer) { + callback(new Error("Could not find customer"), undefined) + } else { + var output = { + customer: customer.name, + movie: movie.title, + checkout_date: rental.rental_date, + due_date: rental.due_date + } + totaloutput.push(output) + if (arrayOfOverdue.length === totaloutput.length) { + callback(null, totaloutput); + } + } + }); + } + }.bind(db.movies, rental) + )} + } + }) +}; + + +module.exports = Rental; diff --git a/package.json b/package.json index d39b26403..f1c3c188a 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,34 @@ { - "name": "video-store-api", + "name": "VideoStoreAPI", "version": "0.0.0", "private": true, "scripts": { - "start": "nodemon ./bin/www", - "test": "clear; jasmine-node --verbose spec/" + "setup": "node ./setup.js", + "start": "./node_modules/.bin/nodemon ./bin/www", + "start-test": "NODE_ENV=test ./node_modules/.bin/nodemon ./bin/www", + "test": "clear; ./node_modules/.bin/istanbul cover -x 'spec/**/*' -- ./node_modules/.bin/jasmine-node --captureExceptions --verbose spec/", + "db:drop": "dropdb radio_star_development", + "db:create": "createdb radio_star_development", + "db:dropt": "dropdb radio_star_test", + "db:createt": "createdb radio_star_test", + "db:schema": "node tasks/load_schema.js", + "db:seed": "node tasks/seed_data.js", + "db:reset": "npm run db:drop; npm run db:dropt; npm run db:create; npm run db:createt; npm run db:schema; npm run db:schema; npm run db:seed" }, "dependencies": { "body-parser": "~1.13.2", "cookie-parser": "~1.3.5", "debug": "~2.2.0", "express": "~4.13.1", - "jade": "~1.11.0", + "massive": "^2.3.0", "morgan": "~1.6.1", - "sequelize": "^3.23.3", + "nodemon": "^1.9.2", "serve-favicon": "~2.3.0" }, "devDependencies": { + "istanbul": "^0.4.4", "jasmine-node": "^1.14.5", + "massive": "^2.3.0", "nodemon": "^1.9.2", "request": "^2.72.0" } diff --git a/routes/index.js b/routes/index.js index 06cfc1137..684862a98 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,9 +1,95 @@ var express = require('express'); var router = express.Router(); +var Controller = require('../controllers/index'); +var MovieController = require('../controllers/movies'); +var CustController = require('../controllers/customers'); +var RentalController = require('../controllers/rentals'); + /* GET home page. */ router.get('/', function(req, res, next) { - res.status(200).json({whatevs: 'whatevs!!!'}) + res.render('index', { title: 'Express' }); }); +// router.get('/', Controller.nothing) + +// router.get('/zomg', Controller.zomg) + + +// Retrive a list of all customers +router.get('/customers/', CustController.index); + + +// Retrive a subset of customers +// Given a sort column, return n customer records, offset by p records (this will be used to create "pages" of customers) +// Sort columns are: name, registered_at, postal_code +// router.get('/customers/sort/:query', CustController.subset); +router.get('/customers/sort/:query', CustController.subset); + +// Given a customer's id... +// List the movies they currently have checked out +router.get('/customers/:id/current', CustController.current) + + +// Given a customer's id... +// List the movies a customer has checked out in the past (ordered by check out date, includes return date) +router.get('/customers/:id/history', CustController.history) + + +// Retrieve a list of all movies +router.get('/movies', MovieController.index); + +// Retrieve a subset of movie +// Given a sort column, return n movie records, offset by p records (this will be used to create "pages" of movies) +// Sort columns are: title, release_date + router.get('/movies/sort/:query', MovieController.find) + // router.get('/movies/sort/:query?n=1&p=5', MovieController.subset) + // query of title or release_date + + + // Given a movie's title... + // Get a list of customers that have currently checked out a copy of the film + // include each customer's name, phone number, and account credit + router.get('/movies/:movie/current', MovieController.current) + +// +// Given a movie's title... +// Get a list of customers that have checked out a copy in the past +// include each customer's name, phone number, and account credit +// ordered by customer name or ordered by check out date +router.get('/movies/:movie/history/sort/:query', MovieController.history) + +// See a list of customers with overdue movies (/rentals/overdue) +// include customer name, movie title, check-out date, and return date +router.get('/rentals/overdue', RentalController.overdue); + +// Look a movie up by title to see (/rentals/Jaws) +// it's synopsis +// release date +// available inventory (not currently checked-out to a customer) +// and inventory total +router.get('/rentals/:movie', RentalController.find); + +// See a list of customers that have currently checked out any of the movie's inventory (/rentals/Jaws/customers) +router.get('/rentals/:movie/customers/', RentalController.findCustomers); + +// Given a customer's id and a movie's title ... +// "check out" one of the movie's inventory to the customer (/rentals/Jaws/check-out) +// Establish a return date +// Charge the customer's account (cost up to you) +router.get('/rentals/:movie/check-out/:id', RentalController.checkOut); + + +// "check in" one of customer's rentals (/rentals/Jaws/return) +// return the movie to its inventory +router.get('/rentals/:movie/return/:id', RentalController.return); + +//HTML API Documentation +router.get('/api/docs', Controller.docsHTML); + + +//JSON API Documentation +router.get('/api/docs.json', Controller.docsJSON); + + module.exports = router; diff --git a/routes/rentals.js b/routes/rentals.js new file mode 100644 index 000000000..75c77f866 --- /dev/null +++ b/routes/rentals.js @@ -0,0 +1,41 @@ +// var express = require('express'); +// var router = express.Router(); +// +// var RentalController = require('../controllers/rentals'); +// +// router.get('/', RentalController.getRentals); + + +// Look a movie up by title to see: it's synopsis, release date, available inventory (not currently checked-out to a customer), and inventory total + + // router.get('/:movie_title', RentalController.findTitle) +// +// +// // See a list of customers that have currently checked out any of the movie's inventory + // router.get('/:movie_title/customers', RentalController.customersNames) + // + +// +// // Given a customer's id and a movie's title ... +// // "check out" one of the movie's inventory to the customer +// // Establish a return date, Charge the customer's account (cost up to you) + + // router.get (':movie_title/check-out') + +// +// +// // Given a customer's id and a movie's title ... +// // "check in" one of customer's rentals +// // return the movie to its inventory + + // router.get(':movie_title/return') +// +// +// // See a list of customers with overdue movies +// // include customer name, movie title, check-out date, and return date + // router.get('/overdue') + + + + +// module.exports = router; diff --git a/routes/users.js b/routes/users.js new file mode 100644 index 000000000..623e4302b --- /dev/null +++ b/routes/users.js @@ -0,0 +1,9 @@ +var express = require('express'); +var router = express.Router(); + +/* GET users listing. */ +router.get('/', function(req, res, next) { + res.send('respond with a resource'); +}); + +module.exports = router; diff --git a/setup.js b/setup.js new file mode 100644 index 000000000..4d0ed823a --- /dev/null +++ b/setup.js @@ -0,0 +1,17 @@ +var spawn = require('child_process').spawnSync; +var Massive = require('massive'); + +['development', 'test'].forEach(function(env) { + var dbName = `radio_star_${env}`; + + // Create the DB if it doesn't already exist + var createDB = spawn('createdb', [dbName]); + if(createDB.error) { + console.log("Error creating database " + dbName + ":"); + console.log(createDB); + return; + } else { + console.log("Successfully created database " + dbName + "."); + } + +}); diff --git a/spec/controllers/customers.spec.js b/spec/controllers/customers.spec.js new file mode 100644 index 000000000..a43ea1b69 --- /dev/null +++ b/spec/controllers/customers.spec.js @@ -0,0 +1,119 @@ +var request = require("request") +var baseUrl = "http://localhost:3000" + +describe("CustomerController", function() { + var url = function(endpoint) { + return baseUrl + "/customers" + endpoint + } + + describe(".index", function(done) { + it("returns a response", function(done) { + request.get(url("/"), function(error, response, body) { + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + for (var record of data) { + expect(Object.keys(record)).toEqual([ 'id' ]) + } + done() + }) + }) + }) + + describe('.subset', function(done) { + it('returns a successful response', function(done) { + request.get(url("/sort/name"), function(error, response, body) { + expect(response.statusCode).toBe(200) + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/sort/name"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/sort/name"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + + for (var record of data) { + expect(Object.keys(record)).toEqual([ 'id' ]) + } + done() + }) + }) + }) + + describe('.current', function(done) { + it('returns a successful response', function(done) { + request.get(url("/1/current"), function(error, response, body) { + expect(response.statusCode).toBe(200) + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/1/current"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/1/current"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + + for (var record of data) { + expect(Object.keys(record)).toEqual([ 'id', 'title', 'search_title', 'overview', 'release_date', 'inventory', 'inventory_total', 'movie_id', 'customer_id', 'checked', 'rental_date', 'due_date', 'return_date' ]) + } + done() + }) + }) + }) + + describe('.history', function(done) { + it('returns a successful response', function(done) { + request.get(url("/5/history"), function(error, response, body) { + expect(response.statusCode).toBe(200) + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/5/history/"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/5/history/"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + + for (var record of data) { + expect(Object.keys(record)).toEqual([ 'id', 'title', 'search_title', 'overview', 'release_date', 'inventory', 'inventory_total', 'movie_id', 'customer_id', 'checked', 'rental_date', 'due_date', 'return_date' ]) + } + done() + }) + }) + }) + +}) diff --git a/spec/controllers/index.spec.js b/spec/controllers/index.spec.js index e4151d267..a9198697c 100644 --- a/spec/controllers/index.spec.js +++ b/spec/controllers/index.spec.js @@ -1,29 +1,29 @@ -var request = require('request') -var base_url = "http://localhost:3000/" - -describe("Endpoint at /", function () { - it('responds with a 200 status code', function (done) { - request.get(base_url, function(error, response, body) { - expect(response.statusCode).toEqual(200) - done() - }) - }) - - describe("the returned json data", function() { - it('has the right keys', function(done) { - request.get(base_url, function(error, response, body) { - var data = JSON.parse(body) - expect(Object.keys(data)).toEqual(['whatevs']) - done() - }) - }) - - it('has the right values for the keys', function(done) { - request.get(base_url, function(error, response, body) { - var data = JSON.parse(body) - expect(data.whatevs).toEqual('whatevs!!!') - done() - }) - }) - }) -}) +// var request = require('request') +// var base_url = "http://localhost:3000/" +// +// describe("Endpoint at /", function () { +// it('responds with a 200 status code', function (done) { +// request.get(base_url, function(error, response, body) { +// expect(response.statusCode).toEqual(200) +// done() +// }) +// }) +// +// describe("the returned json data", function() { +// it('has the right keys', function(done) { +// request.get(base_url, function(error, response, body) { +// var data = JSON.parse(body) +// expect(Object.keys(data)).toEqual(['whatevs']) +// done() +// }) +// }) +// +// it('has the right values for the keys', function(done) { +// request.get(base_url, function(error, response, body) { +// var data = JSON.parse(body) +// expect(data.whatevs).toEqual('whatevs!!!') +// done() +// }) +// }) +// }) +// }) diff --git a/spec/controllers/movies.spec.js b/spec/controllers/movies.spec.js index ddcaf2f68..5671a50cb 100644 --- a/spec/controllers/movies.spec.js +++ b/spec/controllers/movies.spec.js @@ -1,5 +1,119 @@ -var request = require('request'); +var request = require("request") +var baseUrl = "http://localhost:3000" -describe("Endpoints under /movies", function() { +describe("MovieController", function() { + var url = function(endpoint) { + return baseUrl + "/movies" + endpoint + } + + describe(".all", function(done) { + it("returns a response", function(done) { + request.get(url("/"), function(error, response, body) { + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + for (var record of data) { + expect(Object.keys(record)).toEqual([ 'id', 'title', 'release_date', 'synopsis' ]) + } + done() + }) + }) + }) + + describe('.sort', function(done) { + it('returns a successful response', function(done) { + request.get(url("/sort/title?n=1&p=2"), function(error, response, body) { + expect(response.statusCode).toBe(200) + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/sort/title?n=1&p=2"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/sort/title?n=1&p=2"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + + for (var record of data) { + expect(Object.keys(record)).toEqual([ 'id', 'title', 'release_date', 'synopsis' ]) + } + done() + }) + }) + }) + + describe('.find', function(done) { + it('returns a successful response', function(done) { + request.get(url("/psycho/current"), function(error, response, body) { + expect(response.statusCode).toBe(200) + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/psycho/current"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/psycho/current"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + + for (var record of data) { + expect(Object.keys(record)).toEqual([ 'id', 'title', 'release_date', 'synopsis' ]) + } + done() + }) + }) + }) + + describe('.history', function(done) { + it('returns a successful response', function(done) { + request.get(url("/psycho/history/sort/name"), function(error, response, body) { + expect(response.statusCode).toBe(200) + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/Psycho/history/sort/name"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/Psycho/history/sort/name"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + + for (var record of data) { + expect(Object.keys(record)).toEqual(['id', 'name', 'registered_at', 'address', 'city', 'state', 'postal_code', 'phone', 'account_credit']) + } + done() + }) + }) + }) }) diff --git a/spec/controllers/rentals.spec.js b/spec/controllers/rentals.spec.js new file mode 100644 index 000000000..fa5ac482c --- /dev/null +++ b/spec/controllers/rentals.spec.js @@ -0,0 +1,140 @@ +var request = require("request") +var baseUrl = "http://localhost:3000" + +describe("RentalsController", function() { + var url = function(endpoint) { + return baseUrl + "/rentals" + endpoint + } + + describe(".find", function(done) { + it("returns a response", function(done) { + request.get(url("/psycho"), function(error, response, body) { + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/psycho"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/psycho"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + for (var record of data) { + expect(Object.keys(record)).toEqual([ 'overview', 'release_date', 'inventory', 'inventory_total' ]) + } + done() + }) + }) + }) + + describe('.findCustomers', function(done) { + it('returns a successful response', function(done) { + request.get(url("/psycho/customers"), function(error, response, body) { + expect(response.statusCode).toBe(200) + done() + }) + }) + + it("returns JSON", function(done) { + request.get(url("/psycho/customers"), function(error, response, body) { + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + + it("should be an array of objects", function(done) { + request.get(url("/psycho/customers"), function(error, response, body) { + var data = JSON.parse(body) + expect(typeof data).toEqual('object') + + for (var record of data) { + expect(Object.keys(record)).toEqual([ 'id', 'name', 'registered_at', 'address', 'city', 'state', 'postal_code', 'phone', 'account_credit' ]) + } + done() + }) + }) + }) + +// /rentals/:movie/check-out/:id + describe('.checkOut', function(done) { + it('returns a successful response', function(done) { + request.get(url("/alien/check-out/22"), function(error, response, body) { + expect(response.statusCode).toBe(200) + expect(response.headers['content-type']).toContain('application/json') + + // var data = JSON.parse(body) + // expect(typeof data).toEqual('object') + // + // for (var record of data) { + // expect(Object.keys(record)).toEqual([ 'return_date' ]) + // } + done() + }) + }) + }) + + describe('.return', function(done) { + it('returns a successful response', function(done) { + request.get(url("/alien/return/22"), function(error, response, body) { + expect(response.statusCode).toBe(200) + expect(response.headers['content-type']).toContain('application/json') + // var data = JSON.parse(body) + // expect(typeof data).toEqual('object') + // + // for (var record of data) { + // expect(Object.keys(record)).toEqual(['id', 'name', 'registered_at', 'address', 'city', 'state', 'postal_code', 'phone', 'account_credit']) + // } + done() + }) + }) + }) + + + // it("should be an array of objects", function(done) { + // request.get(url("/Psycho/history/sort/name"), function(error, response, body) { + // var data = JSON.parse(body) + // expect(typeof data).toEqual('object') + // + // for (var record of data) { + // expect(Object.keys(record)).toEqual(['id', 'name', 'registered_at', 'address', 'city', 'state', 'postal_code', 'phone', 'account_credit']) + // } + // done() + // }) + // }) + // }), + // + describe('.overdue', function(done) { + it('returns a successful response', function(done) { + request.get(url("/overdue"), function(error, response, body) { + expect(response.statusCode).toBe(200) + expect(response.headers['content-type']).toContain('application/json') + done() + }) + }) + }) + // + // it("returns JSON", function(done) { + // request.get(url("/Psycho/history/sort/name"), function(error, response, body) { + // done() + // }) + // }) + // + // it("should be an array of objects", function(done) { + // request.get(url("/Psycho/history/sort/name"), function(error, response, body) { + // var data = JSON.parse(body) + // expect(typeof data).toEqual('object') + // + // for (var record of data) { + // expect(Object.keys(record)).toEqual(['id', 'name', 'registered_at', 'address', 'city', 'state', 'postal_code', 'phone', 'account_credit']) + // } + // done() + // }) + // }) + // }) + +}) diff --git a/spec/models/customers.spec.js b/spec/models/customers.spec.js new file mode 100644 index 000000000..c2510923e --- /dev/null +++ b/spec/models/customers.spec.js @@ -0,0 +1,68 @@ +var app = require('../../app') +var db = app.get('db') +var Customer = require('../../models/customer') + +describe('Customer', function () { + afterEach(function () { + db.end() + }) + +// testing .all + describe('all', function () { + it('should return all customers', function (done) { + Customer.all(function (error, customers) { + expect(customers.length).toEqual(200) + done() + }) + }) + }) + +// testing .sort + describe('sort', function () { + it('should return customers sorted by name', function (done) { + Customer.sort('name', 1, 1, function (error, customers) { + expect(customers.length).toEqual(1) + done() + }) + }) + }) + + describe('find', function () { + it('Errors when fed bad info', function(done) { + Customer.find([10000,'true'], function(error, result) { + expect(error.message).toBe("Could not retrieve customers rentals") + expect(result).toEqual(null) + done() + }) + }) + }) + + describe('find', function () { + it('should return rentals that customer has checked out', function(done) { + Customer.find([1,'true'], function(error, customers) { + expect(customers.length).toEqual(7) + done() + }) + }) + }) + + describe('history', function () { + it('select customer history', function(done) { + Customer.history([1,'false'], "rentals.rental_date",function(error, customers) { + expect(customers.length).toEqual(5) + done() + }) + }) + }) + + describe('history', function () { + it('Errors when fed bad info', function(done) { + Customer.history([10000,'false'], "rentals.rental_date", function(error, result) { + expect(error.message).toBe("Could not retrieve customers rentals") + expect(result).toEqual(null) + done() + }) + }) + }) + +}) diff --git a/spec/models/rentals.spec.js b/spec/models/rentals.spec.js new file mode 100644 index 000000000..e020e8fd4 --- /dev/null +++ b/spec/models/rentals.spec.js @@ -0,0 +1,263 @@ +// var app = require('../../app') +// var db = app.get('db') +// var Rental = require('../../models/rentals') +// +// describe('Rental', function () { +// afterEach(function () { +// Rental.end() +// }) +// +// // testing .find_current +// describe('find_current', function () { +// it('Errors when fed bad info', function(done) { +// Rental.find_current('Fake column', function(error, result) { +// expect(error.message).toBe('invalid input syntax for integer: "Fake column"') +// expect(result).toEqual(null) +// done() +// }) +// }) +// }) +// +// describe('find_current', function () { +// it('returns an array', function(done) { +// Rental.find_current(1, function (error, result) { +// expect(error).toBe(null) +// expect(result).toEqual(jasmine.any(Array)) +// done() +// }) +// }) +// }) +// +// describe('find_current', function () { +// it('returns instances with correct keys', function(done) { +// Rental.find_current(2, function(error, result) { +// expect(error).toBe(null) +// expect(Object.keys(result[0])).toEqual(['id', 'customer_id', 'video_id', 'checkout_date', 'due_date', 'checkin_date', 'charge']) +// done() +// }) +// }) +// }) +// +// describe('find_current', function () { +// it('returns instances where the checkin_date is null', function(done) { +// Rental.find_current(2, function(error, result) { +// expect(error).toBe(null) +// expect(result[0]['checkin_date']).toBe(null) +// done() +// }) +// }) +// }) +// +// describe('find_current', function () { +// it('returns instances for one customer only', function(done) { +// Rental.find_current(2, function(error, result) { +// expect(error).toBe(null) +// for (var instance of result) { +// expect(instance['customer_id']).toBe(2) +// } +// done() +// }) +// }) +// }) +// +// // testing .find_history +// describe('find_history', function () { +// it('Errors when fed bad info', function(done) { +// Rental.find_history('Fake column', function(error, result) { +// expect(error.message).toBe('invalid input syntax for integer: "Fake column"') +// expect(result).toEqual(null) +// done() +// }) +// }) +// }) +// +// describe('find_history', function () { +// it('returns an array', function(done) { +// Rental.find_history(1, function (error, result) { +// expect(error).toBe(null) +// expect(result).toEqual(jasmine.any(Array)) +// done() +// }) +// }) +// }) +// +// describe('find_history', function () { +// it('returns instances with correct keys', function(done) { +// Rental.find_history(1, function(error, result) { +// expect(error).toBe(null) +// expect(Object.keys(result[0])).toEqual(['id', 'customer_id', 'video_id', 'checkout_date', 'due_date', 'checkin_date', 'charge']) +// done() +// }) +// }) +// }) +// +// describe('find_history', function () { +// it('returns instances where the checkin_date is not null', function(done) { +// Rental.find_history(1, function(error, result) { +// expect(error).toBe(null) +// expect(result[0]['checkin_date']).not.toBe(null) +// done() +// }) +// }) +// }) +// +// describe('find_history', function () { +// it('returns instances for one customer only', function(done) { +// Rental.find_history(1, function(error, result) { +// expect(error).toBe(null) +// for (var instance of result) { +// expect(instance['customer_id']).toBe(1) +// } +// done() +// }) +// }) +// }) +// +// // testing .overdue +// describe('overdue', function () { +// it('returns an array', function(done) { +// Rental.overdue(function (error, result) { +// expect(error).toBe(null) +// expect(result).toEqual(jasmine.any(Array)) +// done() +// }) +// }) +// }) +// +// describe('overdue', function () { +// it('returns instances with correct keys', function(done) { +// Rental.overdue(function(error, result) { +// expect(error).toBe(null) +// for (var instance of result) { +// expect(Object.keys(instance)).toEqual(['customer', 'video', 'checkout_date', 'due_date']) +// } +// done() +// }) +// }) +// }) +// +// describe('overdue', function () { +// it('returns instances where the checkin_date is not null', function(done) { +// Rental.overdue(function(error, result) { +// expect(error).toBe(null) +// for (var instance of result) { +// expect(instance['checkin_date']).not.toBe(null) +// } +// done() +// }) +// }) +// }) +// +// // testing .video_current +// describe('video_current', function () { +// it('returns an array', function(done) { +// Rental.video_current('Psycho', function (error, result) { +// expect(error).toBe(null) +// expect(result).toEqual(jasmine.any(Array)) +// done() +// }) +// }) +// }) +// +// describe('video_current', function () { +// it('returns instances with correct keys', function(done) { +// Rental.video_current('Psycho', function(error, result) { +// expect(error).toBe(null) +// for (var instance of result) { +// expect(Object.keys(instance)).toEqual(['id', 'name', 'registered_at', 'address', 'city', 'state', 'postal_code', 'phone', 'account_credit']) +// } +// done() +// }) +// }) +// }) +// +// describe('video_current', function () { +// it('returns correct customer', function(done) { +// Rental.video_current('Psycho', function(error, result) { +// expect(error).toBe(null) +// for (var instance of result) { +// expect(instance['id']).toBe(8) +// expect(instance['name']).toBe('Amanda Curtis') +// } +// done() +// }) +// }) +// }) +// +// // testing .find_video_history +// describe('find_video_history', function () { +// it('returns an array', function(done) { +// Rental.find_video_history('Psycho', 'name', function (error, result) { +// expect(error).toBe(null) +// expect(result).toEqual(jasmine.any(Array)) +// done() +// }) +// }) +// }) +// +// describe('find_video_history', function () { +// it('returns instances with correct keys', function(done) { +// Rental.find_video_history('Psycho', 'name', function(error, result) { +// expect(error).toBe(null) +// for (var instance of result) { +// expect(Object.keys(instance)).toEqual(['id', 'name', 'registered_at', 'address', 'city', 'state', 'postal_code', 'phone', 'account_credit']) +// } +// done() +// }) +// }) +// }) +// +// describe('find_video_history', function () { +// it('returns correct number of records', function(done) { +// Rental.find_video_history('Psycho', 'name', function(error, result) { +// expect(error).toBe(null) +// var iteration = 0 +// for (var instance of result) { +// iteration++ +// } +// expect(iteration).toEqual(3) +// done() +// }) +// }) +// }) +// +// describe('find_video_history', function () { +// it('orders by name', function(done) { +// Rental.find_video_history('Psycho', 'name', function(error, result) { +// expect(error).toBe(null) +// expect(result[0]['name']).toBe('Carolyn Chandler') +// done() +// }) +// }) +// }) +// +// describe('find_video_history', function () { +// it('orders by checkout_date', function(done) { +// Rental.find_video_history('Psycho', 'checkout_date', function(error, result) { +// expect(error).toBe(null) +// expect(result[0]['name']).toBe('Shelley Rocha') +// done() +// }) +// }) +// }) +// +// describe('checkout', function () { +// it('returns an array', function(done) { +// Rental.checkout('Psycho', 1, function (error, result) { +// expect(error).toBe(null) +// expect(typeof result).toEqual('object') +// done() +// }) +// }) +// }) +// +// describe('checkin', function () { +// it('returns an array', function(done) { +// Rental.checkin('Psycho', 1, function (error, result) { +// expect(error).toBe(null) +// expect(typeof result).toEqual('object') +// done() +// }) +// }) +// }) +// }) diff --git a/tasks/load_schema.js b/tasks/load_schema.js new file mode 100644 index 000000000..3bdb5a9f1 --- /dev/null +++ b/tasks/load_schema.js @@ -0,0 +1,17 @@ +var spawn = require('child_process').spawnSync; +var Massive = require('massive'); + +['development', 'test'].forEach(function(env) { + // console.log(env) + // var env = 'development' + var dbName = `radio_star_${env}`; + var db = Massive.connectSync({ db: dbName }); + db.setup.schema([], function(err, res) { + if (err) { + // throw(new Error(err.message)) + return console.log('migration error', err.message); + } + console.log("yay schema!"); + process.exit(); + }); +}); diff --git a/tasks/seed_data.js b/tasks/seed_data.js new file mode 100644 index 000000000..ba8f82bb0 --- /dev/null +++ b/tasks/seed_data.js @@ -0,0 +1,71 @@ +// var massive = require('massive') +var spawn = require('child_process').spawnSync; +var Massive = require('massive'); + +var movies_data = require("../db/seeds/movies.json") +var customer_data = require("../db/seeds/customers.json") +var rental_data = require("../db/seeds/rentals.json") + +// ['development', 'test'].forEach(function(env) { + function seed_pls() { + var dbName = `radio_star_test`; + var dbNames = `radio_star_development`; + var db = Massive.connectSync({ db: dbName }); + var dbs = Massive.connectSync({ db: dbNames }); + + for(var movie of movies_data){ + db.movies.save( + {title: movie.title, + search_title: movie.title.toLowerCase().replace(/ /g, "").replace(/\./g, ""), + overview: movie.overview, + release_date: movie.release_date, + inventory: movie.inventory, + inventory_total: movie.inventory}, function(err,res){ + if(err) { + throw new Error(err.message) + } + }) + } + + for(var movie of movies_data){ + dbs.movies.save( + {title: movie.title, + search_title: movie.title.toLowerCase().replace(/ /g, "").replace(/\./g, ""), + overview: movie.overview, + release_date: movie.release_date, + inventory: movie.inventory, + inventory_total: movie.inventory}, function(err,res){ + if(err) { + throw new Error(err.message) + } + }) + } + + // for(var movie of movies_data){ + // db.movies.saveSync(title: , + // search_title text, + // overview text, + // release_date text, + // inventory integer, + // inventory_total integer); + // dbs.movies.saveSync(movie); + // } + + for(var customer of customer_data){ + db.customers.saveSync(customer); + dbs.customers.saveSync(customer); + } + + for(var rental of rental_data){ + db.rentals.saveSync(rental); + dbs.rentals.saveSync(rental); + } + + + console.log("seeding done"); + process.exit(); + }; + + + +seed_pls(); diff --git a/views/error.jade b/views/error.ejs similarity index 100% rename from views/error.jade rename to views/error.ejs diff --git a/views/error2.ejs b/views/error2.ejs new file mode 100644 index 000000000..7cf94edf1 --- /dev/null +++ b/views/error2.ejs @@ -0,0 +1,3 @@ +
<%= error.stack %>diff --git a/views/html-doc.ejs b/views/html-doc.ejs new file mode 100644 index 000000000..6ee26a7b7 --- /dev/null +++ b/views/html-doc.ejs @@ -0,0 +1,214 @@ + + + + + + +
GET '/customers/'
)GET '/customers/sort/:query'
)'customers/sort/name?n=10&p=2'
)'customers/sort/registered-at?n=10&p=2'
)'customers/sort'/postal-code?n=10&p=2'
)GET '/customers/:id/current'
)GET '/customers/:id/history'
)GET '/movies'
)GET '/movies/sort/:query'
)'movies/sort/title?n=5&p=1'
)'movies/sort/release-date?n=5&p=1'
)GET '/movies/:movie/current'
)GET '/movies/:movie/history/sort/:query'
)'/movies/:movie_id/history/sort/name'
)'/movies/:movie_id/history/sort/date'
)GET '/rentals/:title
)
+ Returned info:
+ GET '/rentals/:movie/customers'
)GET '/rentals/:movie/check-out'
)GET '/rentals/:movie/return'
)GET '/rentals/overdue'
)/api/docs
) (Serves a HTML view of documentation)/api/docs.json
) (Serves JSON documentation)Welcome to <%= title %>
+ +