4
seasoned_api/.gitignore
vendored
4
seasoned_api/.gitignore
vendored
@@ -61,4 +61,6 @@ typings/
|
|||||||
# - - - - -
|
# - - - - -
|
||||||
# My own gitignore files and folders
|
# My own gitignore files and folders
|
||||||
shows.db
|
shows.db
|
||||||
conf/
|
conf/development.json
|
||||||
|
|
||||||
|
# conf/development-prod.json
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"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 NODE_PATH=. mocha --recursive test/system",
|
"test": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. mocha --recursive test/system",
|
||||||
"coverage": "cross-env PLANFLIX_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=. 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/"
|
"lint": "./node_modules/.bin/eslint src/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"body-parser": "~1.0.1",
|
"body-parser": "~1.0.1",
|
||||||
"cross-env": "^3.1.3",
|
"cross-env": "^3.1.3",
|
||||||
"express": "~4.11.0",
|
"express": "~4.11.0",
|
||||||
"jsonwebtoken": "^8.0.1",
|
"jsonwebtoken": "^8.0.1",
|
||||||
"mongoose": "^3.6.13",
|
"mongoose": "^3.6.13",
|
||||||
"moviedb": "^0.2.10",
|
"moviedb": "^0.2.10",
|
||||||
"node-cache": "^4.1.1",
|
"node-cache": "^4.1.1",
|
||||||
@@ -21,17 +21,15 @@
|
|||||||
"raven": "^2.2.1",
|
"raven": "^2.2.1",
|
||||||
"request": "^2.81.0",
|
"request": "^2.81.0",
|
||||||
"request-promise": "^4.2",
|
"request-promise": "^4.2",
|
||||||
"sqlite": "^2.9.0"
|
"sqlite3": "3.1.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"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",
|
||||||
"eslint": "^4.9.0",
|
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"mocha": "^3.1.0",
|
"mocha": "^3.1.0",
|
||||||
"supertest": "^2.0.1",
|
"supertest": "^2.0.1",
|
||||||
"supertest-as-promised": "^4.0.1"
|
"supertest-as-promised": "^4.0.1"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ CREATE TABLE IF NOT EXISTS user (
|
|||||||
user_name varchar(127) UNIQUE,
|
user_name varchar(127) UNIQUE,
|
||||||
password varchar(127),
|
password varchar(127),
|
||||||
email varchar(127) UNIQUE,
|
email varchar(127) UNIQUE,
|
||||||
|
admin boolean DEFAULT 0,
|
||||||
primary key (user_name)
|
primary key (user_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ CREATE TABLE IF NOT EXISTS requests(
|
|||||||
background_path TEXT DEFAULT NULL,
|
background_path TEXT DEFAULT NULL,
|
||||||
requested_by TEXT,
|
requested_by TEXT,
|
||||||
ip TEXT,
|
ip TEXT,
|
||||||
requested_date DATE DEFAULT CURRENT_DATE NOT NULL,
|
date DATE DEFAULT CURRENT_TIMESTAMP,
|
||||||
status CHAR(25) DEFAULT 'requested' NOT NULL,
|
status CHAR(25) DEFAULT 'requested' NOT NULL,
|
||||||
user_agent CHAR(255) DEFAULT NULL,
|
user_agent CHAR(255) DEFAULT NULL,
|
||||||
type CHAR(50) DEFAULT 'movie'
|
type CHAR(50) DEFAULT 'movie'
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const sqlite = require('sqlite');
|
const sqlite3 = require('sqlite3').verbose();
|
||||||
|
|
||||||
class SqliteDatabase {
|
class SqliteDatabase {
|
||||||
|
|
||||||
constructor(host) {
|
constructor(host) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.connection = sqlite;
|
this.connection = this.connect()
|
||||||
this.schemaDirectory = path.join(__dirname, 'schemas');
|
this.schemaDirectory = path.join(__dirname, 'schemas');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,9 +15,9 @@ class SqliteDatabase {
|
|||||||
* @returns {Promise} succeeds if connection was established
|
* @returns {Promise} succeeds if connection was established
|
||||||
*/
|
*/
|
||||||
connect() {
|
connect() {
|
||||||
return Promise.resolve()
|
let database = new sqlite3.Database(this.host);
|
||||||
.then(() => sqlite.open(this.host))
|
this.connection = database;
|
||||||
.then(() => sqlite.exec('pragma foreign_keys = on;'));
|
return database;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,7 +27,13 @@ class SqliteDatabase {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
run(sql, parameters) {
|
run(sql, parameters) {
|
||||||
return this.connection.run(sql, parameters);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.connection.run(sql, parameters, (error, result) => {
|
||||||
|
if (error)
|
||||||
|
reject(error);
|
||||||
|
resolve(result)
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,8 +42,15 @@ class SqliteDatabase {
|
|||||||
* @param {Array} parameters in the SQL query
|
* @param {Array} parameters in the SQL query
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
all(sql, parameters) {
|
async all(sql, parameters) {
|
||||||
return this.connection.all(sql, parameters);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.connection.all(sql, parameters, (err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve(rows);
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,8 +59,15 @@ class SqliteDatabase {
|
|||||||
* @param {Array} parameters in the SQL query
|
* @param {Array} parameters in the SQL query
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
get(sql, parameters) {
|
async get(sql, parameters) {
|
||||||
return this.connection.get(sql, parameters);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.connection.get(sql, parameters, (err, rows) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve(rows);
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,8 +76,10 @@ class SqliteDatabase {
|
|||||||
* @param {Array} parameters in the SQL query
|
* @param {Array} parameters in the SQL query
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
execute(sql) {
|
async execute(sql) {
|
||||||
return this.connection.exec(sql);
|
return new Promise(resolve => {
|
||||||
|
resolve(this.connection.exec(sql));
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,22 @@
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const http = require('http');
|
||||||
|
const { URL } = require('url');
|
||||||
const PythonShell = require('python-shell');
|
const PythonShell = require('python-shell');
|
||||||
|
|
||||||
|
function getMagnetFromURL(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const options = new URL(url);
|
||||||
|
if (options.protocol.includes('magnet'))
|
||||||
|
resolve(url)
|
||||||
|
|
||||||
|
http.get(options, (res) => {
|
||||||
|
if (res.statusCode == 301) {
|
||||||
|
resolve(res.headers.location)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function find(searchterm, callback) {
|
async function find(searchterm, callback) {
|
||||||
const options = {
|
const options = {
|
||||||
pythonPath: '/usr/bin/python3',
|
pythonPath: '/usr/bin/python3',
|
||||||
@@ -13,14 +29,21 @@ async function find(searchterm, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function callPythonAddMagnet(magnet, callback) {
|
async function callPythonAddMagnet(url, callback) {
|
||||||
const options = {
|
getMagnetFromURL(url)
|
||||||
pythonPath: '/usr/bin/python',
|
.then((magnet) => {
|
||||||
// pythonPath: '/Library/Frameworks/Python.framework/Versions/3.6/bin/python3',
|
const options = {
|
||||||
args: [magnet],
|
pythonPath: '/usr/bin/python',
|
||||||
};
|
// pythonPath: '/Library/Frameworks/Python.framework/Versions/3.6/bin/python3',
|
||||||
|
args: [magnet],
|
||||||
|
};
|
||||||
|
|
||||||
PythonShell.run('../app/magnet.py', options, callback);
|
PythonShell.run('../app/magnet.py', options, callback);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
throw new Error(err);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function SearchPiratebay(query) {
|
async function SearchPiratebay(query) {
|
||||||
@@ -39,13 +62,14 @@ async function SearchPiratebay(query) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function AddMagnet(magnet) {
|
async function AddMagnet(magnet) {
|
||||||
return await new Promise(resolve => callPythonAddMagnet(magnet, (err, results) => {
|
return await new Promise((resolve, reject) => callPythonAddMagnet(magnet, (err, results) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
reject(Error('Enable to add torrent', err))
|
||||||
}
|
}
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
console.log(results);
|
console.log('result/error:', err, results);
|
||||||
resolve({ success: true });
|
resolve({ success: true });
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ class PlexRepository {
|
|||||||
inPlex(tmdbResult) {
|
inPlex(tmdbResult) {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.search(tmdbResult.title))
|
.then(() => this.search(tmdbResult.title))
|
||||||
.then(plexResult => this.compareTmdbToPlex(tmdbResult, plexResult));
|
.then(plexResult => this.compareTmdbToPlex(tmdbResult, plexResult))
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error)
|
||||||
|
tmdbResult.matchedInPlex = false;
|
||||||
|
return tmdbResult;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
search(query) {
|
search(query) {
|
||||||
@@ -19,6 +24,9 @@ class PlexRepository {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return rp(options)
|
return rp(options)
|
||||||
|
.catch((error) => {
|
||||||
|
throw new Error('Unable to search plex.')
|
||||||
|
})
|
||||||
.then(result => this.mapResults(result))
|
.then(result => this.mapResults(result))
|
||||||
.then(([mappedResults, resultCount]) => ({ results: mappedResults, total_results: resultCount }));
|
.then(([mappedResults, resultCount]) => ({ results: mappedResults, total_results: resultCount }));
|
||||||
}
|
}
|
||||||
@@ -26,10 +34,15 @@ class PlexRepository {
|
|||||||
compareTmdbToPlex(tmdb, plexResult) {
|
compareTmdbToPlex(tmdb, plexResult) {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
plexResult.results.map((plexItem) => {
|
if (plexResult.results.length === 0) {
|
||||||
if (tmdb.title === plexItem.title && tmdb.year === plexItem.year) { tmdb.matchedInPlex = true; }
|
tmdb.matchedInPlex = false
|
||||||
return tmdb;
|
}
|
||||||
});
|
else {
|
||||||
|
plexResult.results.map((plexItem) => {
|
||||||
|
if (tmdb.title === plexItem.title && tmdb.year === plexItem.year) { tmdb.matchedInPlex = true; }
|
||||||
|
return tmdb;
|
||||||
|
});
|
||||||
|
}
|
||||||
return tmdb;
|
return tmdb;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,19 +16,24 @@ class RequestRepository {
|
|||||||
constructor(cache, database) {
|
constructor(cache, database) {
|
||||||
this.database = database || establishedDatabase;
|
this.database = database || establishedDatabase;
|
||||||
this.queries = {
|
this.queries = {
|
||||||
insertRequest: "INSERT INTO requests VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_DATE, 'requested', ?, ?)",
|
insertRequest: `INSERT INTO requests(id,title,year,poster_path,background_path,requested_by,ip,user_agent,type)
|
||||||
fetchRequstedItems: 'SELECT * FROM requests',
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||||
|
fetchRequestedItems: 'SELECT * FROM requests ORDER BY date DESC',
|
||||||
|
fetchRequestedItemsByStatus: 'SELECT * FROM requests WHERE status IS ? AND type LIKE ?',
|
||||||
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 ?'
|
||||||
|
};
|
||||||
|
this.cacheTags = {
|
||||||
|
search: 'se',
|
||||||
|
lookup: 'i',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
search(query, type, page) {
|
search(query, type, page) {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => tmdb.search(query, type, page))
|
.then(() => tmdb.search(query, type, page))
|
||||||
// .then((tmdbResult) => plexRepository.multipleInPlex(tmdbResult))
|
.catch(error => Error(`error in the house${error}`));
|
||||||
.then(result => result)
|
|
||||||
.catch(error => `error in the house${error}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lookup(identifier, type = 'movie') {
|
lookup(identifier, type = 'movie') {
|
||||||
@@ -60,53 +65,33 @@ class RequestRepository {
|
|||||||
* @returns {Promise} If nothing has gone wrong.
|
* @returns {Promise} If nothing has gone wrong.
|
||||||
*/
|
*/
|
||||||
sendRequest(identifier, type, ip, user_agent, user) {
|
sendRequest(identifier, type, ip, user_agent, user) {
|
||||||
tmdb.lookup(identifier, type).then((movie) => {
|
return Promise.resolve()
|
||||||
if (user === 'false') { user = 'NULL'; }
|
.then(() => tmdb.lookup(identifier, type))
|
||||||
|
.then((movie) => {
|
||||||
|
const username = user == undefined ? undefined : user.username;
|
||||||
// Add request to database
|
// Add request to database
|
||||||
this.database.run(this.queries.insertRequest, [movie.id, movie.title, movie.year, movie.poster_path, movie.background_path, user, ip, user_agent, movie.type]);
|
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]);
|
||||||
|
|
||||||
|
|
||||||
// create reusable transporter object using the default SMTP transport
|
|
||||||
const transporter = nodemailer.createTransport({
|
|
||||||
service: 'gmail',
|
|
||||||
auth: {
|
|
||||||
user: configuration.get('mail', 'user_pi'),
|
|
||||||
pass: configuration.get('mail', 'password_pi'),
|
|
||||||
},
|
|
||||||
// host: configuration.get('mail', 'host'),
|
|
||||||
// port: 26,
|
|
||||||
// ignoreTLS: true,
|
|
||||||
// tls :{rejectUnauthorized: false},
|
|
||||||
// secure: false, // secure:true for port 465, secure:false for port 587
|
|
||||||
});
|
|
||||||
|
|
||||||
const mailTemplate = new MailTemplate(movie);
|
|
||||||
|
|
||||||
// setup email data with unicode symbols
|
|
||||||
const mailOptions = {
|
|
||||||
// TODO get the mail adr from global location (easy to add)
|
|
||||||
from: 'MovieRequester <pi.midboe@gmail.com>', // sender address
|
|
||||||
to: 'kevin.midboe@gmail.com', // list of receivers
|
|
||||||
subject: 'Download request', // Subject line
|
|
||||||
text: mailTemplate.toText(),
|
|
||||||
html: mailTemplate.toHTML(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// send mail with defined transport object
|
|
||||||
transporter.sendMail(mailOptions, (error, info) => {
|
|
||||||
if (error) {
|
|
||||||
return console.log(error);
|
|
||||||
}
|
|
||||||
console.log('Message %s sent: %s', info.messageId, info.response);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO add better response when done.
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchRequested() {
|
fetchRequested(status, type = '%') {
|
||||||
return this.database.all(this.queries.fetchRequstedItems);
|
return Promise.resolve()
|
||||||
|
.then(() => {
|
||||||
|
if (status === 'requested' || status === 'downloading' || status === 'downloaded')
|
||||||
|
return this.database.all(this.queries.fetchRequestedItemsByStatus, [status, type]);
|
||||||
|
else
|
||||||
|
return this.database.all(this.queries.fetchRequestedItems);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
userRequests(user) {
|
||||||
|
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')}
|
||||||
|
})
|
||||||
|
.then((result) => { return result })
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRequestedById(id, type, status) {
|
updateRequestedById(id, type, status) {
|
||||||
|
|||||||
@@ -15,8 +15,15 @@ class SearchHistory {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
read(user) {
|
read(user) {
|
||||||
return this.database.all(this.queries.read, user)
|
return new Promise((resolve, reject) => this.database.all(this.queries.read, user)
|
||||||
.then(rows => rows.map(row => row.search_query));
|
.then((result, error) => {
|
||||||
|
if (error) throw new Error(error);
|
||||||
|
resolve(result.map(row => row.search_query));
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log('Error when fetching history from database:', error)
|
||||||
|
reject('Unable to get history.');
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,7 +33,8 @@ class SearchHistory {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
create(user, searchQuery) {
|
create(user, searchQuery) {
|
||||||
return this.database.run(this.queries.create, [searchQuery, user])
|
return Promise.resolve()
|
||||||
|
.then(() => this.database.run(this.queries.create, [searchQuery, user]))
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.message.includes('FOREIGN')) {
|
if (error.message.includes('FOREIGN')) {
|
||||||
throw new Error('Could not create search history.');
|
throw new Error('Could not create search history.');
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class Cache {
|
|||||||
* @param {Number} timeToLive the number of seconds before entry expires
|
* @param {Number} timeToLive the number of seconds before entry expires
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
set(key, value, timeToLive = 172800) {
|
set(key, value, timeToLive = 10800) {
|
||||||
const json = JSON.stringify(value);
|
const json = JSON.stringify(value);
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.database.run(this.queries.create, [key, json, timeToLive]))
|
.then(() => this.database.run(this.queries.create, [key, json, timeToLive]))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
class User {
|
class User {
|
||||||
constructor(username, email) {
|
constructor(username, email=undefined) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.email = email;
|
this.email = email;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ class UserRepository {
|
|||||||
this.database = database || establishedDatabase;
|
this.database = database || establishedDatabase;
|
||||||
this.queries = {
|
this.queries = {
|
||||||
read: 'select * from user where lower(user_name) = lower(?)',
|
read: 'select * from user where lower(user_name) = lower(?)',
|
||||||
create: 'insert into user (user_name, email) values(?, ?)',
|
create: 'insert into user (user_name) values (?)',
|
||||||
change: 'update user set password = ? where user_name = ?',
|
change: 'update user set password = ? where user_name = ?',
|
||||||
retrieveHash: 'select * from user where user_name = ?',
|
retrieveHash: 'select * from user where user_name = ?',
|
||||||
|
getAdminStateByUser: 'select admin from user where user_name = ?'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,13 +21,10 @@ class UserRepository {
|
|||||||
create(user) {
|
create(user) {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.database.get(this.queries.read, user.username))
|
.then(() => this.database.get(this.queries.read, user.username))
|
||||||
.then(row => assert.equal(row, undefined))
|
.then(() => this.database.run(this.queries.create, user.username))
|
||||||
.then(() => this.database.run(this.queries.create, [user.username, user.email]))
|
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.message.endsWith('email')) {
|
if (error.name === 'AssertionError' || error.message.endsWith('user_name')) {
|
||||||
throw new Error('That email is already taken');
|
throw new Error('That username is already registered');
|
||||||
} else if (error.name === 'AssertionError' || error.message.endsWith('user_name')) {
|
|
||||||
throw new Error('That username is already taken');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -52,6 +50,12 @@ class UserRepository {
|
|||||||
changePassword(user, password) {
|
changePassword(user, password) {
|
||||||
return this.database.run(this.queries.change, [password, user.username]);
|
return this.database.run(this.queries.change, [password, user.username]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkAdmin(user) {
|
||||||
|
return this.database.get(this.queries.getAdminStateByUser, user.username).then((row) => {
|
||||||
|
return row.admin;
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = UserRepository;
|
module.exports = UserRepository;
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ class UserSecurity {
|
|||||||
createNewUser(user, clearPassword) {
|
createNewUser(user, clearPassword) {
|
||||||
if (user.username.trim() === '') {
|
if (user.username.trim() === '') {
|
||||||
throw new Error('The username is empty.');
|
throw new Error('The username is empty.');
|
||||||
} else if (user.email.trim() === '') {
|
|
||||||
throw new Error('The email is empty.');
|
|
||||||
} else if (clearPassword.trim() === '') {
|
} else if (clearPassword.trim() === '') {
|
||||||
throw new Error('The password is empty.');
|
throw new Error('The password is empty.');
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const Raven = require('raven');
|
|||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
const tokenToUser = require('./middleware/tokenToUser');
|
const tokenToUser = require('./middleware/tokenToUser');
|
||||||
const mustBeAuthenticated = require('./middleware/mustBeAuthenticated');
|
const mustBeAuthenticated = require('./middleware/mustBeAuthenticated');
|
||||||
|
const mustBeAdmin = require('./middleware/mustBeAdmin');
|
||||||
const configuration = require('src/config/configuration').getInstance();
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
|
||||||
// TODO: Have our raven router check if there is a value, if not don't enable raven.
|
// TODO: Have our raven router check if there is a value, if not don't enable raven.
|
||||||
@@ -61,7 +62,8 @@ app.use(function onError(err, req, res, next) {
|
|||||||
*/
|
*/
|
||||||
router.post('/v1/user', require('./controllers/user/register.js'));
|
router.post('/v1/user', require('./controllers/user/register.js'));
|
||||||
router.post('/v1/user/login', require('./controllers/user/login.js'));
|
router.post('/v1/user/login', require('./controllers/user/login.js'));
|
||||||
router.get('/v1/user/history', require('./controllers/user/history.js'));
|
router.get('/v1/user/history', mustBeAuthenticated, require('./controllers/user/history.js'));
|
||||||
|
router.get('/v1/user/requests', mustBeAuthenticated, require('./controllers/user/requests.js'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seasoned
|
* Seasoned
|
||||||
@@ -104,6 +106,10 @@ router.get('/v1/tmdb/:mediaId', require('./controllers/tmdb/readMedia.js'));
|
|||||||
*/
|
*/
|
||||||
router.post('/v1/git/dump', require('./controllers/git/dumpHook.js'));
|
router.post('/v1/git/dump', require('./controllers/git/dumpHook.js'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* misc
|
||||||
|
*/
|
||||||
|
router.get('/v1/emoji', require('./controllers/misc/emoji.js'));
|
||||||
|
|
||||||
// REGISTER OUR ROUTES -------------------------------
|
// REGISTER OUR ROUTES -------------------------------
|
||||||
// all of our routes will be prefixed with /api
|
// all of our routes will be prefixed with /api
|
||||||
|
|||||||
23
seasoned_api/src/webserver/controllers/misc/emoji.js
Normal file
23
seasoned_api/src/webserver/controllers/misc/emoji.js
Normal file
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
const PirateRepository = require('src/pirate/pirateRepository');
|
const PirateRepository = require('src/pirate/pirateRepository');
|
||||||
|
|
||||||
function updateRequested(req, res) {
|
function addMagnet(req, res) {
|
||||||
const magnet = req.body.magnet;
|
const magnet = req.body.magnet;
|
||||||
|
|
||||||
PirateRepository.AddMagnet(magnet)
|
PirateRepository.AddMagnet(magnet)
|
||||||
@@ -16,8 +16,8 @@ function updateRequested(req, res) {
|
|||||||
res.send(result);
|
res.send(result);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
res.status(401).send({ success: false, error: error.message });
|
res.status(500).send({ success: false, error: error.message });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = updateRequested;
|
module.exports = addMagnet;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: KevinMidboe
|
* @Author: KevinMidboe
|
||||||
* @Date: 2017-10-21 09:54:31
|
* @Date: 2017-10-21 09:54:31
|
||||||
* @Last Modified by: KevinMidboe
|
* @Last Modified by: KevinMidboe
|
||||||
* @Last Modified time: 2017-10-21 12:12:26
|
* @Last Modified time: 2018-02-26 19:56:32
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const PirateRepository = require('src/pirate/pirateRepository');
|
const PirateRepository = require('src/pirate/pirateRepository');
|
||||||
@@ -19,7 +19,7 @@ function updateRequested(req, res) {
|
|||||||
|
|
||||||
PirateRepository.SearchPiratebay(query, page, type)
|
PirateRepository.SearchPiratebay(query, page, type)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
res.send({ success: true, torrents: result });
|
res.send({ success: true, results: result });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
res.status(401).send({ success: false, error: error.message });
|
res.status(401).send({ success: false, error: error.message });
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ const requestRepository = new RequestRepository();
|
|||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function historyController(req, res) {
|
function fetchRequestedController(req, res) {
|
||||||
// const user = req.loggedInUser;
|
// const user = req.loggedInUser;
|
||||||
|
const { status } = req.query;
|
||||||
|
|
||||||
requestRepository.fetchRequested()
|
requestRepository.fetchRequested(status)
|
||||||
.then((requestedItems) => {
|
.then((requestedItems) => {
|
||||||
res.send({ success: true, results: requestedItems, total_results: requestedItems.length });
|
res.send({ success: true, results: requestedItems, total_results: requestedItems.length });
|
||||||
})
|
})
|
||||||
@@ -20,4 +21,4 @@ function historyController(req, res) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = historyController;
|
module.exports = fetchRequestedController;
|
||||||
|
|||||||
@@ -8,17 +8,18 @@ const searchHistory = new SearchHistory();
|
|||||||
|
|
||||||
|
|
||||||
function searchRequestController(req, res) {
|
function searchRequestController(req, res) {
|
||||||
const user = req.headers.loggedinuser;
|
const user = req.loggedInUser;
|
||||||
const { query, page, type } = req.query;
|
const { query, page, type } = req.query;
|
||||||
|
const username = user == undefined ? undefined : user.username;
|
||||||
|
|
||||||
Promise.resolve()
|
Promise.resolve()
|
||||||
.then(() => searchHistory.create(user, query))
|
.then(() => searchHistory.create(username, query))
|
||||||
.then(() => requestRepository.search(query, page, type))
|
.then(() => requestRepository.search(query, page, type))
|
||||||
.then((searchResult) => {
|
.then((searchResult) => {
|
||||||
res.send(searchResult);
|
res.send(searchResult);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
res.status(500).send({ success: false, error: error.message });
|
res.status(500).send({ success: false, error: error });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ function submitRequestController(req, res) {
|
|||||||
const type = req.query.type;
|
const type = req.query.type;
|
||||||
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||||
const user_agent = req.headers['user-agent'];
|
const user_agent = req.headers['user-agent'];
|
||||||
const user = req.headers.loggedinuser;
|
const user = req.loggedInUser;
|
||||||
|
|
||||||
requestRepository.sendRequest(id, type, ip, user_agent, user)
|
requestRepository.sendRequest(id, type, ip, user_agent, user)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ const searchHistory = new SearchHistory();
|
|||||||
*/
|
*/
|
||||||
function historyController(req, res) {
|
function historyController(req, res) {
|
||||||
const user = req.loggedInUser;
|
const user = req.loggedInUser;
|
||||||
|
const username = user == undefined ? undefined : user.username;
|
||||||
|
|
||||||
searchHistory.read(user)
|
searchHistory.read(username)
|
||||||
.then((searchQueries) => {
|
.then((searchQueries) => {
|
||||||
res.send({ success: true, searchQueries });
|
res.send({ success: true, searchQueries });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
res.status(401).send({ success: false, error: error.message });
|
res.status(404).send({ success: false, error: error });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
const User = require('src/user/user');
|
const User = require('src/user/user');
|
||||||
const Token = require('src/user/token');
|
const Token = require('src/user/token');
|
||||||
const UserSecurity = require('src/user/userSecurity');
|
const UserSecurity = require('src/user/userSecurity');
|
||||||
|
const UserRepository = require('src/user/userRepository');
|
||||||
const configuration = require('src/config/configuration').getInstance();
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
|
||||||
const secret = configuration.get('authentication', 'secret');
|
const secret = configuration.get('authentication', 'secret');
|
||||||
const userSecurity = new UserSecurity();
|
const userSecurity = new UserSecurity();
|
||||||
|
const userRepository = new UserRepository();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller: Log in a user provided correct credentials.
|
* Controller: Log in a user provided correct credentials.
|
||||||
@@ -17,9 +19,11 @@ function loginController(req, res) {
|
|||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
|
|
||||||
userSecurity.login(user, password)
|
userSecurity.login(user, password)
|
||||||
.then(() => {
|
.then(() => userRepository.checkAdmin(user))
|
||||||
|
.then((checkAdmin) => {
|
||||||
const token = new Token(user).toString(secret);
|
const token = new Token(user).toString(secret);
|
||||||
res.send({ success: true, token });
|
const admin_state = checkAdmin == 1 ? true : false;
|
||||||
|
res.send({ success: true, token, admin: admin_state });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
res.status(401).send({ success: false, error: error.message });
|
res.status(401).send({ success: false, error: error.message });
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
const User = require('src/user/user');
|
const User = require('src/user/user');
|
||||||
|
const Token = require('src/user/token');
|
||||||
const UserSecurity = require('src/user/userSecurity');
|
const UserSecurity = require('src/user/userSecurity');
|
||||||
|
const UserRepository = require('src/user/userRepository');
|
||||||
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
|
||||||
|
const secret = configuration.get('authentication', 'secret');
|
||||||
const userSecurity = new UserSecurity();
|
const userSecurity = new UserSecurity();
|
||||||
|
const userRepository = new UserRepository();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller: Register a new user
|
* Controller: Register a new user
|
||||||
@@ -14,8 +19,11 @@ function registerController(req, res) {
|
|||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
|
|
||||||
userSecurity.createNewUser(user, password)
|
userSecurity.createNewUser(user, password)
|
||||||
.then(() => {
|
.then(() => userRepository.checkAdmin(user))
|
||||||
res.send({ success: true, message: 'Welcome to Seasoned!' });
|
.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 });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
res.status(401).send({ success: false, error: error.message });
|
res.status(401).send({ success: false, error: error.message });
|
||||||
|
|||||||
24
seasoned_api/src/webserver/controllers/user/requests.js
Normal file
24
seasoned_api/src/webserver/controllers/user/requests.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
const RequestRepository = require('src/plex/requestRepository.js');
|
||||||
|
|
||||||
|
const requestRepository = new RequestRepository();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller: Retrieves requested items of a logged in user
|
||||||
|
* @param {Request} req http request variable
|
||||||
|
* @param {Response} res
|
||||||
|
* @returns {Callback}
|
||||||
|
*/
|
||||||
|
function requestsController(req, res) {
|
||||||
|
const user = req.loggedInUser;
|
||||||
|
|
||||||
|
requestRepository.userRequests(user)
|
||||||
|
.then((requests) => {
|
||||||
|
res.send({ success: true, results: requests, total_results: requests.length });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error)
|
||||||
|
res.status(500).send({ success: false, error: error });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = requestsController;
|
||||||
27
seasoned_api/src/webserver/middleware/mustBeAdmin.js
Normal file
27
seasoned_api/src/webserver/middleware/mustBeAdmin.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const establishedDatabase = require('src/database/database');
|
||||||
|
|
||||||
|
const mustBeAdmin = (req, res, next) => {
|
||||||
|
let database = establishedDatabase;
|
||||||
|
|
||||||
|
if (req.loggedInUser === undefined) {
|
||||||
|
return res.status(401).send({
|
||||||
|
success: false,
|
||||||
|
error: 'You must be logged in.',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
database.get(`SELECT admin FROM user WHERE user_name IS ?`, req.loggedInUser.username)
|
||||||
|
.then((isAdmin) => {
|
||||||
|
console.log(isAdmin, req.loggedInUser)
|
||||||
|
if (isAdmin.admin == 0) {
|
||||||
|
return res.status(401).send({
|
||||||
|
success: false,
|
||||||
|
error: 'You must be logged in as a admin.'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = mustBeAdmin;
|
||||||
Reference in New Issue
Block a user