Compare commits
	
		
			27 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| baff59181c | |||
| 490d015f80 | |||
| f1cc2c4ebe | |||
| 2f4421d9e0 | |||
| 92cc094787 | |||
| f30b46c384 | |||
| d9f679603a | |||
| 64bd9d1e14 | |||
| 721826d454 | |||
| 242fe3515c | |||
| ccf40d2161 | |||
| 832b8ba539 | |||
|  | 0477e49eca | ||
| 451b67630a | |||
| 096bbdf085 | |||
| e914e4ab45 | |||
| c1461e1f41 | |||
| 91bf2c1e2a | |||
| da3df383ed | |||
| 9816b978d3 | |||
| 8e22b0f6ea | |||
| 18359f442c | |||
| 42b8b5ea0e | |||
| 996295b1fe | |||
| 1b08c8d3d1 | |||
| 9e145f7068 | |||
| 7051edb212 | 
							
								
								
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,3 @@ | |||||||
| [submodule "torrent_search"] | [submodule "torrent_search"] | ||||||
| 	path = torrent_search | 	path = torrent_search | ||||||
| 	url = git@github.com:KevinMidboe/torrent_search.git | 	url = https://github.com/KevinMidboe/torrent_search.git | ||||||
|   | |||||||
| @@ -1,9 +1,10 @@ | |||||||
| language: node_js | language: node_js | ||||||
| node_js: '8.7.0' | node_js: '8.7.0' | ||||||
| git: | git: | ||||||
|    submodules: false |    submodules: true | ||||||
| script: | script: | ||||||
|    yarn test |    - yarn test | ||||||
|  |    - yarn coverage  | ||||||
| before_install: | before_install: | ||||||
|    - cd seasoned_api |    - cd seasoned_api | ||||||
| before_script: yarn | before_script: yarn | ||||||
|   | |||||||
| @@ -1,9 +1,12 @@ | |||||||
| # 🌶 seasonedShows | # 🌶 seasonedShows | ||||||
| [](https://travis-ci.org/KevinMidboe/seasonedShows) | [](https://travis-ci.org/KevinMidboe/seasonedShows) | ||||||
|  | [](https://coveralls.io/github/KevinMidboe/seasonedShows?branch=coverage) | ||||||
|  | [](https://www.versioneye.com/user/projects/5ac541370fb24f4489396e02) | ||||||
| [](https://snyk.io/test/github/KevinMidboe/seasonedShows?targetFile=seasoned_api/package.json) | [](https://snyk.io/test/github/KevinMidboe/seasonedShows?targetFile=seasoned_api/package.json) | ||||||
| []() | [](https://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
| Your customly *seasoned* movie and show requester, downloader and organizer. Demo page can be viewed [here](https://kevinmidboe.com/request) | Your customly *seasoned* movie and show requester, downloader and organizer.   | ||||||
|  | 📺 [Demo](https://kevinmidboe.com/request) | ||||||
|  |  | ||||||
| ## About | ## About | ||||||
| The goal of this project is to create a full custom stack that can to everything surround downloading, organizing and notifiyng of new media. From the top down we have a website using [tmdb](https://www.themoviedb.com) api to search for from over 350k movies and 70k tv shows. Using [hjone72](https://github.com/hjone72/PlexAuth) great PHP reverse proxy we can have a secure way of allowing users to login with their plex credentials which limits request capabilites to only users that are authenticated to use your plex library.  | The goal of this project is to create a full custom stack that can to everything surround downloading, organizing and notifiyng of new media. From the top down we have a website using [tmdb](https://www.themoviedb.com) api to search for from over 350k movies and 70k tv shows. Using [hjone72](https://github.com/hjone72/PlexAuth) great PHP reverse proxy we can have a secure way of allowing users to login with their plex credentials which limits request capabilites to only users that are authenticated to use your plex library.  | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								seasoned_api/conf/test.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								seasoned_api/conf/test.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | { | ||||||
|  | 	"database": { | ||||||
|  | 		"host": ":memory:" | ||||||
|  | 	}, | ||||||
|  | 	"webserver": { | ||||||
|  | 		"port": 31400 | ||||||
|  | 	}, | ||||||
|  | 	"tmdb": { | ||||||
|  | 		"apiKey": "bogus-api-key" | ||||||
|  | 	}, | ||||||
|  | 	"raven": { | ||||||
|  | 		"DSN": "" | ||||||
|  | 	}, | ||||||
|  | 	"authentication": { | ||||||
|  |     		"secret": "secret" | ||||||
|  |     	} | ||||||
|  | } | ||||||
| @@ -1,35 +1,42 @@ | |||||||
| { | { | ||||||
|   "name": "seasoned-api", |   "name": "seasoned-api", | ||||||
|  |   "description": "Packages needed to build and commands to run seasoned api node server.", | ||||||
|  |   "license": { | ||||||
|  |     "type": "MIT", | ||||||
|  |     "url": "https://www.opensource.org/licenses/mit-license.php" | ||||||
|  |   }, | ||||||
|   "main": "webserver/server.js", |   "main": "webserver/server.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "start": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. node src/webserver/server.js", |     "start": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. node src/webserver/server.js", | ||||||
|         "test": "cross-env SEASONED_CONFIG=conf/development.json TESTING=true NODE_PATH=. mocha --recursive test/system", |     "test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --recursive test", | ||||||
|         "coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. istanbul cover -x script/autogenerate-documentation.js --include-all-sources --dir test/.coverage node_modules/mocha/bin/_mocha --recursive test/**/* -- --report lcovonly && cat test/.coverage/lcov.info | coveralls && rm -rf test/.coverage", |     "coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. nyc mocha --recursive test && nyc report --reporter=text-lcov | coveralls", | ||||||
|     "lint": "./node_modules/.bin/eslint src/" |     "lint": "./node_modules/.bin/eslint src/" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "bcrypt-nodejs": "^0.0.3", |     "bcrypt-nodejs": "^0.0.3", | ||||||
|         "body-parser": "~1.0.1", |     "body-parser": "~1.18.2", | ||||||
|         "cross-env": "^3.1.3", |     "cross-env": "~5.1.4", | ||||||
|         "express": "~4.11.0", |     "express": "~4.16.0", | ||||||
|     "jsonwebtoken": "^8.0.1", |     "jsonwebtoken": "^8.0.1", | ||||||
|         "mongoose": "^3.6.13", |     "mongoose": "~5.0.11", | ||||||
|     "moviedb": "^0.2.10", |     "moviedb": "^0.2.10", | ||||||
|     "node-cache": "^4.1.1", |     "node-cache": "^4.1.1", | ||||||
|         "nodemailer": "^4.0.1", |     "python-shell": "^0.5.0", | ||||||
|         "python-shell": "^0.4.0", |     "request": "^2.85.0", | ||||||
|         "raven": "^2.2.1", |  | ||||||
|         "request": "^2.81.0", |  | ||||||
|     "request-promise": "^4.2", |     "request-promise": "^4.2", | ||||||
|         "sqlite3": "3.1.13" |     "sqlite3": "4.0.0" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|  |     "coveralls": "^3.0.0", | ||||||
|     "eslint": "^4.9.0", |     "eslint": "^4.9.0", | ||||||
|     "eslint-config-airbnb-base": "^12.1.0", |     "eslint-config-airbnb-base": "^12.1.0", | ||||||
|     "eslint-plugin-import": "^2.8.0", |     "eslint-plugin-import": "^2.8.0", | ||||||
|     "istanbul": "^0.4.5", |     "istanbul": "^0.4.5", | ||||||
|         "mocha": "^3.1.0", |     "mocha": "^5.0.4", | ||||||
|         "supertest": "^2.0.1", |     "mocha-lcov-reporter": "^1.3.0", | ||||||
|  |     "nyc": "^11.6.0", | ||||||
|  |     "raven": "^2.4.2", | ||||||
|  |     "supertest": "^3.0.0", | ||||||
|     "supertest-as-promised": "^4.0.1" |     "supertest-as-promised": "^4.0.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ class Config { | |||||||
|       const field = new Field(this.fields[section][option]); |       const field = new Field(this.fields[section][option]); | ||||||
|  |  | ||||||
|       if (field.value === '') { |       if (field.value === '') { | ||||||
|          const envField = process.env[[section.toUpperCase(), option.toUpperCase()].join('_')]; |          const envField = process.env[['SEASONED', section.toUpperCase(), option.toUpperCase()].join('_')]; | ||||||
|          if (envField !== undefined && envField.length !== 0) { return envField; } |          if (envField !== undefined && envField.length !== 0) { return envField; } | ||||||
|       } |       } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,7 @@ | |||||||
| const configuration = require('src/config/configuration').getInstance(); | const configuration = require('src/config/configuration').getInstance(); | ||||||
| const SqliteDatabase = require('src/database/sqliteDatabase'); | const SqliteDatabase = require('src/database/sqliteDatabase'); | ||||||
|  |  | ||||||
| const host = process.env.TESTING ? ':memory:' : configuration.get('database', 'host'); | const database = new SqliteDatabase(configuration.get('database', 'host')); | ||||||
| const database = new SqliteDatabase(host); |  | ||||||
| /** | /** | ||||||
|  * This module establishes a connection to the database |  * This module establishes a connection to the database | ||||||
|  * specified in the confgiuration file. It tries to setup |  * specified in the confgiuration file. It tries to setup | ||||||
|   | |||||||
| @@ -14,8 +14,8 @@ class RequestRepository { | |||||||
|       this.queries = { |       this.queries = { | ||||||
|          insertRequest: `INSERT INTO requests(id,title,year,poster_path,background_path,requested_by,ip,user_agent,type) |          insertRequest: `INSERT INTO requests(id,title,year,poster_path,background_path,requested_by,ip,user_agent,type) | ||||||
|           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, |           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, | ||||||
|          fetchRequestedItems: 'SELECT * FROM requests ORDER BY date DESC', |          fetchRequestedItems: 'SELECT * FROM requests ORDER BY date DESC LIMIT 25 OFFSET ?*25-25', | ||||||
|          fetchRequestedItemsByStatus: 'SELECT * FROM requests WHERE status IS ? AND type LIKE ? ORDER BY date DESC', |          fetchRequestedItemsByStatus: 'SELECT * FROM requests WHERE status IS ? AND type LIKE ? ORDER BY date DESC LIMIT 25 OFFSET ?*25-25', | ||||||
|          updateRequestedById: 'UPDATE requests SET status = ? WHERE id is ? AND type is ?', |          updateRequestedById: 'UPDATE requests SET status = ? WHERE id is ? AND type is ?', | ||||||
|          checkIfIdRequested: 'SELECT * FROM requests WHERE id IS ? AND type IS ?', |          checkIfIdRequested: 'SELECT * FROM requests WHERE id IS ? AND type IS ?', | ||||||
|          userRequests: 'SELECT * FROM requests WHERE requested_by IS ?', |          userRequests: 'SELECT * FROM requests WHERE requested_by IS ?', | ||||||
| @@ -67,14 +67,14 @@ class RequestRepository { | |||||||
|       }); |       }); | ||||||
|    } |    } | ||||||
|  |  | ||||||
|    fetchRequested(status, type = '%') { |    fetchRequested(status, page = '1', type = '%') { | ||||||
|    	return Promise.resolve() |    	return Promise.resolve() | ||||||
|    	.then(() => { |    	.then(() => { | ||||||
|             if (status === 'requested' || status === 'downloading' || status === 'downloaded') { | 	      if (status === 'requested' || status === 'downloading' || status === 'downloaded') | ||||||
|                return this.database.all(this.queries.fetchRequestedItemsByStatus, [status, type]); | 	         return this.database.all(this.queries.fetchRequestedItemsByStatus, [status, type, page]); | ||||||
|             } | 	      else | ||||||
|             return this.database.all(this.queries.fetchRequestedItems); | 	         return this.database.all(this.queries.fetchRequestedItems, page); | ||||||
|          }); |    	}) | ||||||
|    } |    } | ||||||
|  |  | ||||||
|    userRequests(user) { |    userRequests(user) { | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ class TMDB { | |||||||
|    /** |    /** | ||||||
|    * Retrieve a specific movie by id from TMDB. |    * Retrieve a specific movie by id from TMDB. | ||||||
|    * @param {Number} identifier of the movie you want to retrieve |    * @param {Number} identifier of the movie you want to retrieve | ||||||
|  |    * @param {String} type filter results by type (default movie). | ||||||
|    * @returns {Promise} succeeds if movie was found |    * @returns {Promise} succeeds if movie was found | ||||||
|    */ |    */ | ||||||
|    lookup(identifier, type = 'movie') { |    lookup(identifier, type = 'movie') { | ||||||
| @@ -36,7 +37,7 @@ class TMDB { | |||||||
|       const cacheKey = `${this.cacheTags.info}:${type}:${identifier}`; |       const cacheKey = `${this.cacheTags.info}:${type}:${identifier}`; | ||||||
|       return Promise.resolve() |       return Promise.resolve() | ||||||
|          .then(() => this.cache.get(cacheKey)) |          .then(() => this.cache.get(cacheKey)) | ||||||
|          .catch(() => this.tmdb(this.tmdbMethod('info', type), query)) |          .catch(() => this.tmdb(TMDB_METHODS['info'][type], query)) | ||||||
|          .catch(() => { throw new Error('Could not find a movie with that id.'); }) |          .catch(() => { throw new Error('Could not find a movie with that id.'); }) | ||||||
|          .then(response => this.cache.set(cacheKey, response)) |          .then(response => this.cache.set(cacheKey, response)) | ||||||
|          .then((response) => { |          .then((response) => { | ||||||
| @@ -50,70 +51,66 @@ class TMDB { | |||||||
|    } |    } | ||||||
|  |  | ||||||
|    /** |    /** | ||||||
|    * Retrive list of of items from TMDB matching the query and/or type given. |    * Retrive search results from TMDB. | ||||||
|    * @param {queryText, page, type} the page number to specify in the request for discover, |    * @param {String} text query you want to search for | ||||||
|  |    * @param {Number} page representing pagination of results | ||||||
|  |    * @param {String} type filter results by type (default multi) | ||||||
|    * @returns {Promise} dict with query results, current page and total_pages |    * @returns {Promise} dict with query results, current page and total_pages | ||||||
|    */ |    */ | ||||||
|    search(text, page = 1, type = 'multi') { |    search(text, page = 1, type = 'multi') { | ||||||
|       const query = { query: text, page }; |       const query = { query: text, page: page }; | ||||||
|       const cacheKey = `${this.cacheTags.search}:${page}:${type}:${text}`; |       const cacheKey = `${this.cacheTags.search}:${page}:${type}:${text}`; | ||||||
|       return Promise.resolve() |       return Promise.resolve() | ||||||
|          .then(() => this.cache.get(cacheKey)) |          .then(() => this.cache.get(cacheKey)) | ||||||
|          .catch(() => this.tmdb(this.tmdbMethod('search', type), query)) |          .catch(() => this.tmdb(TMDB_METHODS['search'][type], query)) | ||||||
|          .catch(() => { throw new Error('Could not search for movies/shows at tmdb.'); }) |          .catch(() => { throw new Error('Could not search for movies/shows at tmdb.'); }) | ||||||
|          .then(response => this.cache.set(cacheKey, response)) |          .then(response => this.cache.set(cacheKey, response)) | ||||||
|          .then(response => this.mapResults(response)) |          .then(response => this.mapResults(response)) | ||||||
|          .catch((error) => { throw new Error(error); }) |  | ||||||
|          .then(([mappedResults, pagenumber, totalpages, total_results]) => ({ |  | ||||||
|             results: mappedResults, page: pagenumber, total_results, total_pages: totalpages, |  | ||||||
|          })); |  | ||||||
|    } |    } | ||||||
|  |  | ||||||
|    /** |    /** | ||||||
|    * Fetches a given list from tmdb. |    * Fetches a given list from tmdb. | ||||||
|    * @param {listName} List we want to fetch. |    * @param {String} listName Name of list | ||||||
|    * @param {type} The  to specify in the request for discover (default 'movie'). |    * @param {String} type filter results by type (default movie) | ||||||
|    * @param {id} When finding similar a id can be added to query |    * @param {Number} page representing pagination of results | ||||||
|    * @param {page} Page number we want to fetch. |  | ||||||
|    * @returns {Promise} dict with query results, current page and total_pages |    * @returns {Promise} dict with query results, current page and total_pages | ||||||
|    */ |    */ | ||||||
|    listSearch(listName, type = 'movie', id, page = '1') { |    listSearch(listName, type = 'movie', page = '1') { | ||||||
|       const params = { id, page }; |       const query = { page: page } | ||||||
|       const cacheKey = `${this.cacheTags[listName]}:${type}:${id}:${page}`; |       console.log(query) | ||||||
|  |       const cacheKey = `${this.cacheTags[listName]}:${type}:${page}`; | ||||||
|       return Promise.resolve() |       return Promise.resolve() | ||||||
|          .then(() => this.cache.get(cacheKey)) |          .then(() => this.cache.get(cacheKey)) | ||||||
|          .catch(() => this.tmdb(this.tmdbMethod(listName, type), params)) |          .catch(() => this.tmdb(TMDB_METHODS[listName][type], query)) | ||||||
|  |          .catch(() => { throw new Error('Error fetching list from tmdb.')}) | ||||||
|          .then(response => this.cache.set(cacheKey, response)) |          .then(response => this.cache.set(cacheKey, response)) | ||||||
|          .then(response => this.mapResults(response, type)) |          .then(response => this.mapResults(response, type)) | ||||||
|          .catch((error) => { throw new Error(error); }) |  | ||||||
|          .then(([mappedResults, pagenumber, totalpages, total_results]) => ({ |  | ||||||
|             results: mappedResults, page: pagenumber, total_pages: totalpages, total_results, |  | ||||||
|          })); |  | ||||||
|    } |  | ||||||
|  |  | ||||||
|    tmdbMethod(apiMethod, type) { |  | ||||||
|       const method = TMDB_METHODS[apiMethod][type]; |  | ||||||
|       if (method !== undefined) return method; |  | ||||||
|       throw new Error('Could not find tmdb api method.'); |  | ||||||
|    } |    } | ||||||
|  |  | ||||||
|    /** |    /** | ||||||
|    * Maps our response from tmdb api to a movie/show object. |    * Maps our response from tmdb api to a movie/show object. | ||||||
|    * @param {response} JSON response from tmdb. |    * @param {String} response from tmdb. | ||||||
|    * @param {type} The type declared in listSearch. |    * @param {String} The type declared in listSearch. | ||||||
|    * @returns {Promise} dict with tmdb results, mapped as movie/show objects. |    * @returns {Promise} dict with tmdb results, mapped as movie/show objects. | ||||||
|    */ |    */ | ||||||
|    mapResults(response, type) { |    mapResults(response, type) { | ||||||
|  |       console.log(response.page) | ||||||
|       return Promise.resolve() |       return Promise.resolve() | ||||||
|          .then(() => { |          .then(() => { | ||||||
|             const mappedResults = response.results.filter((element) => { |             const mappedResults = response.results.filter((element) => { | ||||||
|                return (element.media_type === 'movie' || element.media_type === 'tv' || element.media_type === undefined); |                return (element.media_type === 'movie' || element.media_type === 'tv' || element.media_type === undefined); | ||||||
|             }).map((element) => convertTmdbToSeasoned(element, type)); |             }).map((element) => convertTmdbToSeasoned(element, type)); | ||||||
|             return [mappedResults, response.page, response.total_pages, response.total_results]; |             return {results: mappedResults, page: response.page, total_pages: response.total_pages, total_results: response.total_results} | ||||||
|          }) |          }) | ||||||
|          .catch((error) => { throw new Error(error); }); |          .catch((error) => { throw new Error(error); }); | ||||||
|    } |    } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Wraps moviedb library to support Promises. | ||||||
|  |    * @param {String} method function name in the library | ||||||
|  |    * @param {Object} argument argument to function being called | ||||||
|  |    * @returns {Promise} succeeds if callback succeeds | ||||||
|  |    */ | ||||||
|    tmdb(method, argument) { |    tmdb(method, argument) { | ||||||
|       return new Promise((resolve, reject) => { |       return new Promise((resolve, reject) => { | ||||||
|          const callback = (error, reponse) => { |          const callback = (error, reponse) => { | ||||||
|   | |||||||
| @@ -10,9 +10,9 @@ const requestRepository = new RequestRepository(); | |||||||
|  */ |  */ | ||||||
| function fetchRequestedController(req, res) { | function fetchRequestedController(req, res) { | ||||||
|    // const user = req.loggedInUser; |    // const user = req.loggedInUser; | ||||||
|    const { status } = req.query; |    const { status, page } = req.query; | ||||||
|  |  | ||||||
|    requestRepository.fetchRequested(status) |    requestRepository.fetchRequested(status, page) | ||||||
|       .then((requestedItems) => { |       .then((requestedItems) => { | ||||||
|          res.send({ success: true, results: requestedItems, total_results: requestedItems.length }); |          res.send({ success: true, results: requestedItems, total_results: requestedItems.length }); | ||||||
|       }) |       }) | ||||||
|   | |||||||
| @@ -13,8 +13,8 @@ const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey')); | |||||||
|  */ |  */ | ||||||
| function listSearchController(req, res) { | function listSearchController(req, res) { | ||||||
|    const listname = req.params.listname; |    const listname = req.params.listname; | ||||||
|    const { type, id, page } = req.query; |    const { type, page } = req.query; | ||||||
|    tmdb.listSearch(listname, type, id, page) |    tmdb.listSearch(listname, type, page) | ||||||
|       .then((results) => { |       .then((results) => { | ||||||
|          res.send(results); |          res.send(results); | ||||||
|       }).catch((error) => { |       }).catch((error) => { | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								seasoned_api/test/fixtures/arrival-info-success-response.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								seasoned_api/test/fixtures/arrival-info-success-response.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |     "background_path": "/yIZ1xendyqKvY3FGeeUYUd5X9Mm.jpg", | ||||||
|  |     "id": 329865, | ||||||
|  |     "popularity": 26.978601, | ||||||
|  |     "poster_path": "/hLudzvGfpi6JlwUnsNhXwKKg4j.jpg", | ||||||
|  |     "release_status": "Released", | ||||||
|  |     "score": 7.3, | ||||||
|  |     "summary": "Taking place after alien crafts land around the world, an expert linguist is recruited by the military to determine whether they come in peace or are a threat.", | ||||||
|  |     "tagline": "Why are they here?", | ||||||
|  |     "title": "Arrival", | ||||||
|  |     "type": "movie", | ||||||
|  |     "year": 2016 | ||||||
|  | } | ||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -7,7 +7,7 @@ const popularMoviesSuccess = require('test/fixtures/popular-movies-success-respo | |||||||
|  |  | ||||||
| describe('As a user I want to get popular movies', () => { | describe('As a user I want to get popular movies', () => { | ||||||
|   before(() => resetDatabase()); |   before(() => resetDatabase()); | ||||||
|   before(() => createCacheEntry('p:movie::1', popularMoviesSuccess)); |   before(() => createCacheEntry('p:movie:1', popularMoviesSuccess)); | ||||||
|  |  | ||||||
|   it('should return 200 with the information', () => |   it('should return 200 with the information', () => | ||||||
|     request(app) |     request(app) | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ const popularShowsSuccess = require('test/fixtures/popular-show-success-response | |||||||
|  |  | ||||||
| describe('As a user I want to get popular shows', () => { | describe('As a user I want to get popular shows', () => { | ||||||
|   before(() => resetDatabase()); |   before(() => resetDatabase()); | ||||||
|   before(() => createCacheEntry('p:show::1', popularShowsSuccess)); |   before(() => createCacheEntry('p:show:1', popularShowsSuccess)); | ||||||
|  |  | ||||||
|   it('should return 200 with the information', () => |   it('should return 200 with the information', () => | ||||||
|     request(app) |     request(app) | ||||||
|   | |||||||
| @@ -1,14 +1,17 @@ | |||||||
| const resetDatabase = require('test/helpers/resetDatabase'); | const resetDatabase = require('test/helpers/resetDatabase'); | ||||||
|  | const createCacheEntry = require('test/helpers/createCacheEntry'); | ||||||
| const app = require('src/webserver/app'); | const app = require('src/webserver/app'); | ||||||
| const request = require('supertest-as-promised'); | const request = require('supertest-as-promised'); | ||||||
| const createUser = require('test/helpers/createUser'); | const createUser = require('test/helpers/createUser'); | ||||||
| const createToken = require('test/helpers/createToken'); | const createToken = require('test/helpers/createToken'); | ||||||
|  | const infoMovieSuccess = require('test/fixtures/arrival-info-success-response.json'); | ||||||
|  |  | ||||||
| describe('As a user I want to request a movie', () => { | describe('As a user I want to request a movie', () => { | ||||||
|   before(() => { |   before(() => { | ||||||
|    return resetDatabase() |    return resetDatabase() | ||||||
|    .then(() => createUser('test_user', 'test@gmail.com', 'password')); |    .then(() => createUser('test_user', 'test@gmail.com', 'password')); | ||||||
|    }) |    }) | ||||||
|  |   before(() => createCacheEntry('i:movie:329865', infoMovieSuccess)); | ||||||
|  |  | ||||||
|   it('should return 200 when item is requested', () => |   it('should return 200 when item is requested', () => | ||||||
|     request(app) |     request(app) | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ const interstellarQuerySuccess = require('test/fixtures/interstellar-query-succe | |||||||
|  |  | ||||||
| describe('As an anonymous user I want to search for a movie', () => { | describe('As an anonymous user I want to search for a movie', () => { | ||||||
|   before(() => resetDatabase()); |   before(() => resetDatabase()); | ||||||
|   before(() => createCacheEntry('s:1:movie:interstellar', interstellarQuerySuccess)); |   before(() => createCacheEntry('se:1:multi:interstellar', interstellarQuerySuccess)); | ||||||
|  |  | ||||||
|   it('should return 200 with the search results even if user is not logged in', () => |   it('should return 200 with the search results even if user is not logged in', () => | ||||||
|     request(app) |     request(app) | ||||||
|   | |||||||
							
								
								
									
										63
									
								
								seasoned_api/test/unit/config/testConfig.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								seasoned_api/test/unit/config/testConfig.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | const assert = require('assert'); | ||||||
|  | const Config = require('src/config/configuration.js'); | ||||||
|  |  | ||||||
|  | describe('Config', () => { | ||||||
|  |   before(() => { | ||||||
|  |     this.backedUpEnvironmentVariables = Object.assign({}, process.env); | ||||||
|  |     this.backedUpConfigFields = Object.assign({}, Config.getInstance().fields); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   after(() => { | ||||||
|  |     process.env = this.backedUpEnvironmentVariables; | ||||||
|  |     Config.getInstance().fields = this.backedUpConfigFields; | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should retrieve section and option from config file', () => { | ||||||
|  |     Config.getInstance().fields = { 'webserver': { 'port': 1337 } }; | ||||||
|  |     assert.equal(Config.getInstance().get('webserver', 'port'), 1337); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should resolve to environment variables if option is filtered with env', () => { | ||||||
|  |     Config.getInstance().fields = { 'webserver': { 'port': 'env|SEASONED_WEBSERVER_PORT' } }; | ||||||
|  |     process.env.SEASONED_WEBSERVER_PORT = '1338'; | ||||||
|  |     assert.equal(Config.getInstance().get('webserver', 'port'), 1338); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('raises an exception if the environment variable does not exist', () => { | ||||||
|  |     Config.getInstance().fields = { 'webserver': { 'port': 'env|DOES_NOT_EXIST' } }; | ||||||
|  |     process.env.SEASONED_WEBSERVER_PORT = '1338'; | ||||||
|  |     assert.throws(() => Config.getInstance().get('webserver', 'port'), /empty/); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('raises an exception if the environment variable is empty', () => { | ||||||
|  |     Config.getInstance().fields = { 'webserver': { 'port': 'env|SEASONED_WEBSERVER_PORT' } }; | ||||||
|  |     process.env.SEASONED_WEBSERVER_PORT = ''; | ||||||
|  |     assert.throws(() => Config.getInstance().get('webserver', 'port'), /empty/); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('raises an exception if the section does not exist in the file', () => { | ||||||
|  |     Config.getInstance().fields = { 'webserver': { 'port': '1338' } }; | ||||||
|  |     assert.throws(() => Config.getInstance().get('woops', 'port'), /does not exist/); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('raises an exception if the option does not exist in the file', () => { | ||||||
|  |     Config.getInstance().fields = { 'webserver': { 'port': '1338' } }; | ||||||
|  |     assert.throws(() => Config.getInstance().get('webserver', 'woops'), /does not exist/); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('returns an array if field is an array', () => { | ||||||
|  |     Config.getInstance().fields = { 'bouncer': { 'whitelist': [1, 2, 3] } }; | ||||||
|  |     assert.deepEqual(Config.getInstance().get('bouncer', 'whitelist'), [1, 2, 3]); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('decodes field as base64 if base64| is before the variable', () => { | ||||||
|  |     Config.getInstance().fields = { 'webserver': { 'port': 'base64|MTMzOA==' } }; | ||||||
|  |     assert.equal(Config.getInstance().get('webserver', 'port'), 1338); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('decodes environment variable as base64 if BASE64= is before the variable', () => { | ||||||
|  |     Config.getInstance().fields = { 'webserver': { 'port': 'env|base64|SEASONED_WEBSERVER_PORT' } }; | ||||||
|  |     process.env.SEASONED_WEBSERVER_PORT = 'MTMzOA=='; | ||||||
|  |     assert.equal(Config.getInstance().get('webserver', 'port'), 1338); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										72
									
								
								seasoned_api/test/unit/config/testField.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								seasoned_api/test/unit/config/testField.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | const assert = require('assert'); | ||||||
|  | const Field = require('src/config/field.js'); | ||||||
|  |  | ||||||
|  | describe('Field', () => { | ||||||
|  |   it('should return an array if it is an array', () => { | ||||||
|  |     const field = new Field([1, 2, 3]); | ||||||
|  |     assert.deepEqual(field.value, [1, 2, 3]); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should return the plain value if it is an ordinary field', () => { | ||||||
|  |     const field = new Field('plain value'); | ||||||
|  |     assert.equal(field.value, 'plain value'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should return false if boolean false is field', () => { | ||||||
|  |     const field = new Field(false); | ||||||
|  |     assert.equal(field.value, false); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should not include any invalid filters', () => { | ||||||
|  |     const field = new Field('invalid-filter|plain value'); | ||||||
|  |     assert.equal(field.value, 'plain value'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should return the decoded value if it is filtered through base64', () => { | ||||||
|  |     const field = new Field('base64|ZW5jb2RlZCB2YWx1ZQ=='); | ||||||
|  |     assert.equal(field.value, 'encoded value'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should not decode the value if it missing the filter', () => { | ||||||
|  |     const field = new Field('ZW5jb2RlZCB2YWx1ZQ=='); | ||||||
|  |     assert.equal(field.value, 'ZW5jb2RlZCB2YWx1ZQ=='); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should retrieve the environment variable if env filter is used', () => { | ||||||
|  |     const environmentVariables = { REDIS_URL: 'redis://127.0.0.1:1234' }; | ||||||
|  |     const field = new Field('env|REDIS_URL', environmentVariables); | ||||||
|  |     assert.equal(field.value, 'redis://127.0.0.1:1234'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should return undefined if the environment variable does not exist', () => { | ||||||
|  |     const environmentVariables = { HTTP_PORT: 8080 }; | ||||||
|  |     const field = new Field('env|REDIS_URL', environmentVariables); | ||||||
|  |     assert.equal(field.value, undefined); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should return undefined if the environment variable is an empty string', () => { | ||||||
|  |     const environmentVariables = { REDIS_URL: '' }; | ||||||
|  |     const field = new Field('env|REDIS_URL', environmentVariables); | ||||||
|  |     assert.deepEqual(field.value, undefined); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   describe('Multiple filters', () => { | ||||||
|  |     it('should decode the environment variable if base64 and env filter are used', () => { | ||||||
|  |       const environmentVariables = { REDIS_URL: 'cmVkaXM6Ly9kYWdibGFkZXQubm8vMTIzNA==' }; | ||||||
|  |       const field = new Field('env|base64|REDIS_URL', environmentVariables); | ||||||
|  |       assert.equal(field.value, 'redis://dagbladet.no/1234'); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     it('should disregard the order of filters when env and base64 are used', () => { | ||||||
|  |       const environmentVariables = { REDIS_URL: 'cmVkaXM6Ly9kYWdibGFkZXQubm8vMTIzNA==' }; | ||||||
|  |       const field = new Field('base64|env|REDIS_URL', environmentVariables); | ||||||
|  |       assert.equal(field.value, 'redis://dagbladet.no/1234'); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     it('should return undefined if both filters are used and env var does not exist', () => { | ||||||
|  |       const environmentVariables = { REDIS_URL: 'cmVkaXM6Ly9kYWdibGFkZXQubm8vMTIzNA==' }; | ||||||
|  |       const field = new Field('base64|env|REDIS_LOL', environmentVariables); | ||||||
|  |       assert.equal(field.value, undefined); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										34
									
								
								seasoned_api/test/unit/config/testFilters.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								seasoned_api/test/unit/config/testFilters.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | const assert = require('assert'); | ||||||
|  | const Filters = require('src/config/filters.js'); | ||||||
|  |  | ||||||
|  | describe('Filters', () => { | ||||||
|  |   it('should extract base64 as filter if it is at start of string followed by pipe', () => { | ||||||
|  |     const filters = new Filters('base64|'); | ||||||
|  |     assert.deepEqual(filters.filters, ['base64']); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should extract base64 and env as filters if both are separated by pipe', () => { | ||||||
|  |     const filters = new Filters('base64|env|'); | ||||||
|  |     assert.deepEqual(filters.filters, ['base64', 'env']); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should not extract any filters if none are present', () => { | ||||||
|  |     const filters = new Filters('base64'); | ||||||
|  |     assert.deepEqual(filters.filters, []); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should strip env filter from the value', () => { | ||||||
|  |     const filters = new Filters('env|HELLO'); | ||||||
|  |     assert.deepEqual(filters.removeFiltersFromValue(), 'HELLO'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should strip env and base64 filter from the value', () => { | ||||||
|  |     const filters = new Filters('env|base64|HELLO'); | ||||||
|  |     assert.deepEqual(filters.removeFiltersFromValue(), 'HELLO'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should strip no filters from the value if there are no filters', () => { | ||||||
|  |     const filters = new Filters('HELLO'); | ||||||
|  |     assert.deepEqual(filters.removeFiltersFromValue(), 'HELLO'); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
		Reference in New Issue
	
	Block a user