Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 634d4513eb | |||
| 0a1276a474 | |||
| 3a34d8995e | |||
| 918e629a06 | |||
| 7dd016a56e | |||
| c10bbcf518 | |||
| 3402a52633 | |||
| 86e9188a5c | |||
| 8918b7906e | |||
| 7e028a461d | |||
| fe5f0c815e | |||
| d02e79e59e | |||
| 5b49216c9d | |||
| 657ab10034 | |||
| ed07c77b13 | |||
| 4fe85d9fae | |||
| b99b5b32ec | |||
| e8058c5e4c | |||
| 7332b7d474 | |||
| 7980f14426 | |||
| 65540fafbd | |||
| 64ede43dec | |||
| bed12cff72 | |||
| 59e7f96643 | |||
| 71e9a5a46e | |||
| fce6dc7658 | |||
| baff59181c | |||
| 0592cca16b | |||
| e4d5f5085c | |||
| 66a2a06f9b | |||
| e984feeb8d | |||
| 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 | |||
| 0581813ee3 | |||
| edf1de223e |
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
||||
# Docs : https://git-scm.com/book/en/v2/Git-Tools-Submodules
|
||||
|
||||
[submodule "torrent_search"]
|
||||
path = torrent_search
|
||||
url = git@github.com:KevinMidboe/torrent_search.git
|
||||
url = https://github.com/KevinMidboe/torrent_search.git
|
||||
branch = master
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
language: node_js
|
||||
node_js: '8.7.0'
|
||||
git:
|
||||
submodules: false
|
||||
submodules: true
|
||||
script:
|
||||
yarn test
|
||||
- yarn test
|
||||
- yarn coverage
|
||||
before_install:
|
||||
- cd seasoned_api
|
||||
before_script: yarn
|
||||
|
||||
134
README.md
134
README.md
@@ -1,11 +1,133 @@
|
||||
# 🌶 seasonedShows
|
||||
[](https://travis-ci.org/KevinMidboe/seasonedShows)
|
||||
[](https://snyk.io/test/github/KevinMidboe/seasonedShows?targetFile=seasoned_api/package.json)
|
||||
[]()
|
||||
|
||||
Your customly *seasoned* movie and show requester, downloader and organizer. Demo page can be viewed [here](https://kevinmidboe.com/request)
|
||||
<h1 align="center">
|
||||
🌶 seasonedShows
|
||||
</h1>
|
||||
|
||||
<h4 align="center"> Season your media library with the shows and movies that you and your friends want.</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/KevinMidboe/seasonedShows">
|
||||
<img src="https://travis-ci.org/KevinMidboe/seasonedShows.svg?branch=master"
|
||||
alt="Travis CI">
|
||||
</a>
|
||||
<a href="https://coveralls.io/github/KevinMidboe/seasonedShows?branch=coverage">
|
||||
<img src="https://coveralls.io/repos/github/KevinMidboe/seasonedShows/badge.svg?branch=coverage" alt="">
|
||||
</a>
|
||||
<a href="https://www.versioneye.com/user/projects/5ac541370fb24f4489396e02">
|
||||
<img src="https://www.versioneye.com/user/projects/5ac541370fb24f4489396e02/badge.svg" alt="">
|
||||
</a>
|
||||
<a href="https://snyk.io/test/github/KevinMidboe/seasonedShows?targetFile=seasoned_api/package.json">
|
||||
<img src="https://snyk.io/test/github/KevinMidboe/seasonedShows/badge.svg?targetFile=seasoned_api/package.json" alt="">
|
||||
</a>
|
||||
<a href="https://opensource.org/licenses/MIT">
|
||||
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#demo-documentation">D & D</a> •
|
||||
<a href="#about">About</a> •
|
||||
<a href="#key-features">Key features</a> •
|
||||
<a href="#installation">Installation</a> •
|
||||
<a href="#setup">Setup</a> •
|
||||
<a href="#running">Running</a> •
|
||||
<a href="#daemon">Setup daemon</a> •
|
||||
<a href="#contributing">Contributing</a>
|
||||
</p>
|
||||
|
||||
## <a name="demo-documentation"></a> Demo & Documentation
|
||||
📺 [DEMO](https://kevinmidboe.com/request)
|
||||
📝 Documentation of the api.
|
||||
💖 Checkout my [fancy vue.js page](https://github.com/KevinMidboe/seasonedRequest) for interfacing the api.
|
||||
|
||||
## <a name="about"></a> About
|
||||
This is the backend api for [seasoned request] that allows for uesrs to request movies and shows by fetching movies from themoviedb api and checks them with your plex library to identify if a movie is already present or not. This api allows to search my query, get themoviedb movie lists like popular and now playing, all while checking if the item is already in your plex library. Your friends can create users to see what movies or shows they have requested and searched for.
|
||||
|
||||
The api also uses torrent_search to search for matching torrents and returns results from any site or service available from torrent_search. As a admin of the site you can query torrent_search and return a magnet link that can be added to a autoadd folder of your favorite torrent client.
|
||||
|
||||
## <a name="key-features"></a> Key features
|
||||
### Code
|
||||
- Uses [tmdb api](https://www.themoviedb.org/documentation/api) with over 350k movies and 70k tv shows
|
||||
- Written asynchronously
|
||||
- Uses caching for external requests
|
||||
- Test coverage
|
||||
- CI and dependency integrated
|
||||
- Use either config file or env_variables
|
||||
### Functionality
|
||||
- Queries plex library to check if items exists
|
||||
- Create admin and normal user accounts
|
||||
- [torrent_search](https://github.com/KevinMidboe/torrent_search) to search for torrents
|
||||
- Fetch curated lists from tmdb
|
||||
|
||||
## <a name="installation"></a> Installation
|
||||
Before we can use seasonedShows we need to download node and a package manager. For instructions on how to install [yarn](https://yarnpkg.com/en/) or [npm](https://www.npmjs.com) package managers refer to [wiki: install package manager](https://github.com/KevinMidboe/seasonedShows/wiki/Install-package-manager). This api is written with express using node.js as the JavaScript runtime engine. To download node.js head over the the official [node.js download page](https://nodejs.org/en/download/).
|
||||
|
||||
### Install seasonedShows
|
||||
After you have downloaded a package manager and node.js javascript engine, the following will guide you through how to download, install and run seasonedShows.
|
||||
|
||||
### macOS
|
||||
- Open terminal
|
||||
- Install git. This can be done by running `xcode-select --install` in your favorite terminal.
|
||||
- Install a package manager, refer to this [wiki page] for yarn or [wiki page] for npm
|
||||
- Type: `git clone https://github.com/KevinMidboe/seasonedShows.git`
|
||||
- Type: `cd seasonedShows/`
|
||||
- Install required packages
|
||||
* yarn: `yarn install`
|
||||
* npm: `npm install`
|
||||
- Start server:
|
||||
* yarn: `yarn start`
|
||||
* npm: `npm run start`
|
||||
- seasonedShows will now be running at http://localhost:31459
|
||||
- To have seasonedShows run headless on startup, check out this wiki page to [install as a daemon].
|
||||
|
||||
### Linux
|
||||
- Open terminal
|
||||
- Install git
|
||||
* Ubuntu/Debian: `sudo apt-get install git-core`
|
||||
* Fedora: `sudo yum install git`
|
||||
- Type: `git clone https://github.com/KevinMidboe/seasonedShows.git`
|
||||
- Type: `cd seasonedShows/`
|
||||
- Install required packages
|
||||
* yarn: `yarn install`
|
||||
* npm: `npm install`
|
||||
- Start server:
|
||||
* yarn: `yarn start`
|
||||
* npm: `npm run start`
|
||||
- seasonedShows will now be running at http://localhost:31459
|
||||
- To have seasonedShows run headless on startup, check out this wiki page to [install as a daemon].
|
||||
|
||||
-- same --
|
||||
(install yarn or npm in a different way)
|
||||
After you have installed the required packages you will have a node_modules directory with all the packages required in packages.json.
|
||||
|
||||
### Requirements
|
||||
- Node 7.6 < [wiki page]
|
||||
- Plex library
|
||||
|
||||
## <a name="setup"></a> Setup and/ configuration
|
||||
There is a config file template, what the values mean and how to change them.
|
||||
Also show how to hide file from git if not want to show up as uncommitted file.
|
||||
Also set variables in environment.
|
||||
|
||||
## <a name="running"></a> Running/using
|
||||
yarn/npm start. (can also say this above)
|
||||
How to create service on linux. This means that
|
||||
|
||||
## <a name="daemon"></a> Setup a daemon
|
||||
The next step is to setup seasonedShows api to run in the background as a daemon. I have written a [wiki page](https://github.com/KevinMidboe/seasonedShows/wiki/Install-as-a-daemon) on how to create a daemon on several unix distors and macOS.
|
||||
*Please don't hesitate to add your own system if you get it running on something that is not yet lists on the formentioned wiki page.*
|
||||
|
||||
## <a name="contributing"></a> Contributing
|
||||
- Fork it!
|
||||
- Create your feature branch: git checkout -b my-new-feature
|
||||
- Commit your changes: git commit -am 'Add some feature'
|
||||
- Push to the branch: git push origin my-new-feature
|
||||
- Submit a pull request
|
||||
|
||||
|
||||
## Api documentation
|
||||
|
||||
|
||||
## 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.
|
||||
seasonedShows is a intelligent organizer for your tv show episodes. It is made to automate and simplify to process of renaming and moving newly downloaded tv show episodes following Plex file naming and placement.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# @Author: KevinMidboe
|
||||
# @Date: 2017-04-05 18:40:11
|
||||
# @Last Modified by: KevinMidboe
|
||||
# @Last Modified time: 2017-06-18 21:49:33
|
||||
# @Last Modified time: 2018-04-03 22:58:20
|
||||
import os.path, hashlib, time, glob, sqlite3, re, json, tweepy
|
||||
import logging
|
||||
from functools import reduce
|
||||
@@ -61,7 +61,7 @@ class strayEpisode(object):
|
||||
return hashlib.md5("b'{}'".format(self.parent).encode()).hexdigest()[:8]
|
||||
|
||||
def findSeriesName(self):
|
||||
find = re.compile("^[a-zA-Z. ]*")
|
||||
find = re.compile("^[a-zA-Z0-9. ]*")
|
||||
m = re.match(find, self.parent)
|
||||
if m:
|
||||
name, hit = process.extractOne(m.group(0), getShowNames().keys())
|
||||
@@ -188,6 +188,9 @@ def XOR(list1, list2):
|
||||
return set(list1) ^ set(list2)
|
||||
|
||||
def filterChildItems(parent):
|
||||
if (not os.path.isdir(parent)):
|
||||
strayEpisode(parent[:-4], parent)
|
||||
return
|
||||
try:
|
||||
children = getDirContent('/'.join([env.input_dir, parent]))
|
||||
if children:
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
# @Author: KevinMidboe
|
||||
# @Date: 2017-04-12 23:27:51
|
||||
# @Last Modified by: KevinMidboe
|
||||
# @Last Modified time: 2017-06-27 15:58:09
|
||||
# @Last Modified time: 2018-05-13 19:17:17
|
||||
|
||||
import sys, sqlite3, json, os.path
|
||||
import logging
|
||||
import env_variables as env
|
||||
import shutil
|
||||
|
||||
import delugeClient.deluge_cli as delugeCli
|
||||
|
||||
class episode(object):
|
||||
def __init__(self, id):
|
||||
self.id = id
|
||||
@@ -91,8 +93,18 @@ def moveStray(strayId):
|
||||
except FileNotFoundError:
|
||||
logging.warning('Cannot remove ' + ep.typeDir('parent_input') + ', file no longer exists.')
|
||||
|
||||
# Remove from deluge client
|
||||
logging.info('Removing {} for deluge'.format(ep.parent))
|
||||
deluge = delugeCli.Deluge()
|
||||
response = deluge.remove(ep.parent)
|
||||
logging.info('Deluge response after delete: {}'.format(response))
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if (os.path.exists(env.logfile)):
|
||||
abspath = os.path.abspath(__file__)
|
||||
dname = os.path.dirname(abspath)
|
||||
if (os.path.exists(os.path.join(dname, env.logfile))):
|
||||
logging.basicConfig(filename=env.logfile, level=logging.INFO)
|
||||
else:
|
||||
print('Logfile could not be found at ' + env.logfile + '. Verifiy presence or disable logging in config.')
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
"prefer-destructuring": 0,
|
||||
"camelcase": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/no-extraneous-dependencies": 0
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"object-shorthand": 0,
|
||||
"comma-dangle": 0
|
||||
}
|
||||
}
|
||||
|
||||
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,43 @@
|
||||
{
|
||||
"name": "seasoned-api",
|
||||
"main": "webserver/server.js",
|
||||
"scripts": {
|
||||
"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",
|
||||
"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",
|
||||
"lint": "./node_modules/.bin/eslint src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"bcrypt-nodejs": "^0.0.3",
|
||||
"body-parser": "~1.0.1",
|
||||
"cross-env": "^3.1.3",
|
||||
"express": "~4.11.0",
|
||||
"jsonwebtoken": "^8.0.1",
|
||||
"mongoose": "^3.6.13",
|
||||
"moviedb": "^0.2.10",
|
||||
"node-cache": "^4.1.1",
|
||||
"nodemailer": "^4.0.1",
|
||||
"python-shell": "^0.4.0",
|
||||
"raven": "^2.2.1",
|
||||
"request": "^2.81.0",
|
||||
"request-promise": "^4.2",
|
||||
"sqlite3": "3.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^4.9.0",
|
||||
"eslint-config-airbnb-base": "^12.1.0",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"istanbul": "^0.4.5",
|
||||
"mocha": "^3.1.0",
|
||||
"supertest": "^2.0.1",
|
||||
"supertest-as-promised": "^4.0.1"
|
||||
}
|
||||
"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",
|
||||
"scripts": {
|
||||
"start": "cross-env SEASONED_CONFIG=conf/development.json PROD=true NODE_PATH=. node src/webserver/server.js",
|
||||
"test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --recursive test",
|
||||
"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/",
|
||||
"update": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. node src/plex/updateRequestsInPlex.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"bcrypt-nodejs": "^0.0.3",
|
||||
"body-parser": "~1.18.2",
|
||||
"cross-env": "~5.1.4",
|
||||
"express": "~4.16.0",
|
||||
"jsonwebtoken": "^8.0.1",
|
||||
"mongoose": "~5.0.11",
|
||||
"moviedb": "^0.2.10",
|
||||
"node-cache": "^4.1.1",
|
||||
"python-shell": "^0.5.0",
|
||||
"request": "^2.85.0",
|
||||
"request-promise": "^4.2",
|
||||
"sqlite3": "4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^3.0.0",
|
||||
"eslint": "^4.9.0",
|
||||
"eslint-config-airbnb-base": "^12.1.0",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"istanbul": "^0.4.5",
|
||||
"mocha": "^5.0.4",
|
||||
"mocha-lcov-reporter": "^1.3.0",
|
||||
"nyc": "^11.6.0",
|
||||
"raven": "^2.4.2",
|
||||
"supertest": "^3.0.0",
|
||||
"supertest-as-promised": "^4.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class Config {
|
||||
const field = new Field(this.fields[section][option]);
|
||||
|
||||
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; }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const SqliteDatabase = require('src/database/sqliteDatabase');
|
||||
|
||||
const host = process.env.TESTING ? ':memory:' : configuration.get('database', 'host');
|
||||
const database = new SqliteDatabase(host);
|
||||
const database = new SqliteDatabase(configuration.get('database', 'host'));
|
||||
/**
|
||||
* This module establishes a connection to the database
|
||||
* specified in the confgiuration file. It tries to setup
|
||||
|
||||
@@ -15,6 +15,7 @@ class PlexRepository {
|
||||
}
|
||||
|
||||
search(query) {
|
||||
console.log('searching:', query)
|
||||
const options = {
|
||||
uri: `http://10.0.0.44:32400/search?query=${query}`,
|
||||
headers: {
|
||||
@@ -39,7 +40,8 @@ class PlexRepository {
|
||||
}
|
||||
else {
|
||||
plexResult.results.map((plexItem) => {
|
||||
if (tmdb.title === plexItem.title && tmdb.year === plexItem.year) { tmdb.matchedInPlex = true; }
|
||||
if (tmdb.title === plexItem.title && tmdb.year === plexItem.year)
|
||||
tmdb.matchedInPlex = true;
|
||||
return tmdb;
|
||||
});
|
||||
}
|
||||
@@ -50,6 +52,7 @@ class PlexRepository {
|
||||
mapResults(response) {
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
console.log('plexResponse:', response)
|
||||
if (!response.MediaContainer.hasOwnProperty('Metadata')) return [[], 0];
|
||||
|
||||
const mappedResults = response.MediaContainer.Metadata.filter((element) => {
|
||||
@@ -72,7 +75,7 @@ class PlexRepository {
|
||||
return rp(options)
|
||||
.then((result) => {
|
||||
if (result.MediaContainer.size > 0) {
|
||||
const playing = result.MediaContainer.Video.map(convertPlexToStream);
|
||||
const playing = result.MediaContainer.Metadata.map(convertPlexToStream);
|
||||
return { size: Object.keys(playing).length, video: playing };
|
||||
}
|
||||
return { size: 0, video: [] };
|
||||
|
||||
@@ -8,21 +8,17 @@ const plexRepository = new PlexRepository();
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
|
||||
const MailTemplate = require('src/plex/mailTemplate');
|
||||
const nodemailer = require('nodemailer');
|
||||
|
||||
|
||||
class RequestRepository {
|
||||
constructor(cache, database) {
|
||||
constructor(database) {
|
||||
this.database = database || establishedDatabase;
|
||||
this.queries = {
|
||||
insertRequest: `INSERT INTO requests(id,title,year,poster_path,background_path,requested_by,ip,user_agent,type)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
fetchRequestedItems: 'SELECT * FROM requests ORDER BY date DESC',
|
||||
fetchRequestedItemsByStatus: 'SELECT * FROM requests WHERE status IS ? AND type LIKE ?',
|
||||
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 LIMIT 25 OFFSET ?*25-25',
|
||||
updateRequestedById: 'UPDATE requests SET status = ? 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 ? ORDER BY date DESC',
|
||||
};
|
||||
this.cacheTags = {
|
||||
search: 'se',
|
||||
@@ -51,10 +47,7 @@ class RequestRepository {
|
||||
.then(() => this.database.get(this.queries.checkIfIdRequested, [tmdbMovie.id, tmdbMovie.type]))
|
||||
.then((result, error) => {
|
||||
if (error) { throw new Error(error); }
|
||||
let already_requested = false;
|
||||
if (result) { already_requested = true; }
|
||||
|
||||
tmdbMovie.requested = already_requested;
|
||||
tmdbMovie.requested = result ? true : false;
|
||||
return tmdbMovie;
|
||||
});
|
||||
}
|
||||
@@ -68,30 +61,32 @@ class RequestRepository {
|
||||
return Promise.resolve()
|
||||
.then(() => tmdb.lookup(identifier, type))
|
||||
.then((movie) => {
|
||||
const username = user == undefined ? undefined : user.username;
|
||||
const username = user === undefined ? undefined : user.username;
|
||||
// Add request to database
|
||||
return this.database.run(this.queries.insertRequest, [movie.id, movie.title, movie.year, movie.poster_path, movie.background_path, username, ip, user_agent, movie.type]);
|
||||
});
|
||||
}
|
||||
|
||||
fetchRequested(status, type = '%') {
|
||||
fetchRequested(status, page = '1', type = '%') {
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
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) {
|
||||
return Promise.resolve()
|
||||
return Promise.resolve()
|
||||
.then(() => this.database.all(this.queries.userRequests, user.username))
|
||||
.catch((error) => {
|
||||
if (String(error).includes('no such column')) { throw new Error('Username not found'); }
|
||||
else { throw new Error('Unable to fetch your requests')}
|
||||
if (String(error).includes('no such column')) {
|
||||
throw new Error('Username not found');
|
||||
}
|
||||
throw new Error('Unable to fetch your requests');
|
||||
})
|
||||
.then((result) => { return result })
|
||||
.then((result) => { return result; });
|
||||
}
|
||||
|
||||
updateRequestedById(id, type, status) {
|
||||
|
||||
@@ -43,7 +43,7 @@ class StrayRepository {
|
||||
assert.notEqual(row, undefined, `Stray '${strayId}' already verified.`);
|
||||
|
||||
const options = {
|
||||
pythonPath: '/usr/bin/python3',
|
||||
pythonPath: '../app/env/bin/python3',
|
||||
args: [strayId],
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ const TMDB_METHODS = {
|
||||
nowplaying: { movie: 'miscNowPlayingMovies', show: 'tvOnTheAir' },
|
||||
similar: { movie: 'movieSimilar', show: 'tvSimilar' },
|
||||
search: { movie: 'searchMovie', show: 'searchTv', multi: 'searchMulti' },
|
||||
info: { movie: 'movieInfo', show: 'tvInfo' },
|
||||
info: { movie: 'movieInfo', show: 'tvInfo' }
|
||||
};
|
||||
|
||||
class TMDB {
|
||||
@@ -29,6 +29,7 @@ class TMDB {
|
||||
/**
|
||||
* Retrieve a specific movie by id from TMDB.
|
||||
* @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
|
||||
*/
|
||||
lookup(identifier, type = 'movie') {
|
||||
@@ -36,7 +37,7 @@ class TMDB {
|
||||
const cacheKey = `${this.cacheTags.info}:${type}:${identifier}`;
|
||||
return Promise.resolve()
|
||||
.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.'); })
|
||||
.then(response => this.cache.set(cacheKey, response))
|
||||
.then((response) => {
|
||||
@@ -50,70 +51,71 @@ class TMDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive list of of items from TMDB matching the query and/or type given.
|
||||
* @param {queryText, page, type} the page number to specify in the request for discover,
|
||||
* Retrive search results from TMDB.
|
||||
* @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
|
||||
*/
|
||||
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}`;
|
||||
return Promise.resolve()
|
||||
.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.'); })
|
||||
.then(response => this.cache.set(cacheKey, 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,
|
||||
}));
|
||||
.then(response => this.mapResults(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a given list from tmdb.
|
||||
* @param {listName} List we want to fetch.
|
||||
* @param {type} The to specify in the request for discover (default 'movie').
|
||||
* @param {id} When finding similar a id can be added to query
|
||||
* @param {page} Page number we want to fetch.
|
||||
* @param {String} listName Name of list
|
||||
* @param {String} type filter results by type (default movie)
|
||||
* @param {Number} page representing pagination of results
|
||||
* @returns {Promise} dict with query results, current page and total_pages
|
||||
*/
|
||||
listSearch(listName, type = 'movie', id, page = '1') {
|
||||
const params = { id, page };
|
||||
const cacheKey = `${this.cacheTags[listName]}:${type}:${id}:${page}`;
|
||||
listSearch(listName, type = 'movie', page = '1') {
|
||||
const query = { page: page };
|
||||
console.log(query);
|
||||
const cacheKey = `${this.cacheTags[listName]}:${type}:${page}`;
|
||||
return Promise.resolve()
|
||||
.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.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.');
|
||||
.then(response => this.mapResults(response, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps our response from tmdb api to a movie/show object.
|
||||
* @param {response} JSON response from tmdb.
|
||||
* @param {type} The type declared in listSearch.
|
||||
* @param {String} response from tmdb.
|
||||
* @param {String} The type declared in listSearch.
|
||||
* @returns {Promise} dict with tmdb results, mapped as movie/show objects.
|
||||
*/
|
||||
mapResults(response, type) {
|
||||
console.log(response.page);
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
const mappedResults = response.results.filter((element) => {
|
||||
return (element.media_type === 'movie' || element.media_type === 'tv' || element.media_type === undefined);
|
||||
}).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); });
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = (error, reponse) => {
|
||||
|
||||
@@ -41,7 +41,7 @@ class UserRepository {
|
||||
assert(row, 'The user does not exist.');
|
||||
return row.password;
|
||||
})
|
||||
.catch((err) => console.log('there was a error when getting hash', err));
|
||||
.catch((err) => { console.log(error); throw new Error('Unable to find your user.'); });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +57,7 @@ class UserRepository {
|
||||
checkAdmin(user) {
|
||||
return this.database.get(this.queries.getAdminStateByUser, user.username).then((row) => {
|
||||
return row.admin;
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,6 @@ app.use(bodyParser.json());
|
||||
// router.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
|
||||
/* Decode the Authorization header if provided */
|
||||
// router.use(tokenToUser);
|
||||
|
||||
const router = express.Router();
|
||||
const allowedOrigins = ['https://kevinmidboe.com', 'http://localhost:8080'];
|
||||
|
||||
@@ -27,9 +24,7 @@ const allowedOrigins = ['https://kevinmidboe.com', 'http://localhost:8080'];
|
||||
// router.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
|
||||
// This is probably a correct middleware/router setup
|
||||
/* Translate the user token to a user name */
|
||||
/* Decode the Authorization header if provided */
|
||||
router.use(tokenToUser);
|
||||
|
||||
// TODO: Should have a separate middleware/router for handling headers.
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -10,9 +10,9 @@ const requestRepository = new RequestRepository();
|
||||
*/
|
||||
function fetchRequestedController(req, res) {
|
||||
// const user = req.loggedInUser;
|
||||
const { status } = req.query;
|
||||
const { status, page } = req.query;
|
||||
|
||||
requestRepository.fetchRequested(status)
|
||||
requestRepository.fetchRequested(status, page)
|
||||
.then((requestedItems) => {
|
||||
res.send({ success: true, results: requestedItems, total_results: requestedItems.length });
|
||||
})
|
||||
|
||||
@@ -10,7 +10,7 @@ const searchHistory = new SearchHistory();
|
||||
function searchRequestController(req, res) {
|
||||
const user = req.loggedInUser;
|
||||
const { query, page, type } = req.query;
|
||||
const username = user == undefined ? undefined : user.username;
|
||||
const username = user === undefined ? undefined : user.username;
|
||||
|
||||
Promise.resolve()
|
||||
.then(() => searchHistory.create(username, query))
|
||||
|
||||
@@ -13,8 +13,8 @@ const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
*/
|
||||
function listSearchController(req, res) {
|
||||
const listname = req.params.listname;
|
||||
const { type, id, page } = req.query;
|
||||
tmdb.listSearch(listname, type, id, page)
|
||||
const { type, page } = req.query;
|
||||
tmdb.listSearch(listname, type, page)
|
||||
.then((results) => {
|
||||
res.send(results);
|
||||
}).catch((error) => {
|
||||
|
||||
@@ -10,7 +10,7 @@ const searchHistory = new SearchHistory();
|
||||
*/
|
||||
function historyController(req, res) {
|
||||
const user = req.loggedInUser;
|
||||
const username = user == undefined ? undefined : user.username;
|
||||
const username = user === undefined ? undefined : user.username;
|
||||
|
||||
searchHistory.read(username)
|
||||
.then((searchQueries) => {
|
||||
|
||||
@@ -22,7 +22,7 @@ function loginController(req, res) {
|
||||
.then(() => userRepository.checkAdmin(user))
|
||||
.then((checkAdmin) => {
|
||||
const token = new Token(user).toString(secret);
|
||||
const admin_state = checkAdmin == 1 ? true : false;
|
||||
const admin_state = checkAdmin === 1 ? true : false;
|
||||
res.send({ success: true, token, admin: admin_state });
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
@@ -22,8 +22,10 @@ function registerController(req, res) {
|
||||
.then(() => userRepository.checkAdmin(user))
|
||||
.then((checkAdmin) => {
|
||||
const token = new Token(user).toString(secret);
|
||||
const admin_state = checkAdmin == 1 ? true : false;
|
||||
res.send({ success: true, message: 'Welcome to Seasoned!', token, admin: admin_state });
|
||||
const admin_state = checkAdmin === 1 ? true : false;
|
||||
res.send({
|
||||
success: true, message: 'Welcome to Seasoned!', token, admin: admin_state,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
res.status(401).send({ success: false, error: error.message });
|
||||
|
||||
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', () => {
|
||||
before(() => resetDatabase());
|
||||
before(() => createCacheEntry('p:movie::1', popularMoviesSuccess));
|
||||
before(() => createCacheEntry('p:movie:1', popularMoviesSuccess));
|
||||
|
||||
it('should return 200 with the information', () =>
|
||||
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', () => {
|
||||
before(() => resetDatabase());
|
||||
before(() => createCacheEntry('p:show::1', popularShowsSuccess));
|
||||
before(() => createCacheEntry('p:show:1', popularShowsSuccess));
|
||||
|
||||
it('should return 200 with the information', () =>
|
||||
request(app)
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
const resetDatabase = require('test/helpers/resetDatabase');
|
||||
const createCacheEntry = require('test/helpers/createCacheEntry');
|
||||
const app = require('src/webserver/app');
|
||||
const request = require('supertest-as-promised');
|
||||
const createUser = require('test/helpers/createUser');
|
||||
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', () => {
|
||||
before(() => {
|
||||
return resetDatabase()
|
||||
.then(() => createUser('test_user', 'test@gmail.com', 'password'));
|
||||
})
|
||||
before(() => createCacheEntry('i:movie:329865', infoMovieSuccess));
|
||||
|
||||
it('should return 200 when item is requested', () =>
|
||||
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', () => {
|
||||
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', () =>
|
||||
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');
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
Submodule torrent_search updated: 4996f20bbc...9985358efb
Reference in New Issue
Block a user