Fix: Tests lint and src folder #138

Merged
KevinMidboe merged 27 commits from fix/tests-lint-and-src-folder into master 2022-08-20 15:41:47 +00:00
55 changed files with 726 additions and 526 deletions
Showing only changes of commit b1d959389d - Show all commits

11
src/cache/redis.js vendored
View File

@@ -1,4 +1,3 @@
const { promisify } = require("util");
const configuration = require("../config/configuration").getInstance(); const configuration = require("../config/configuration").getInstance();
let client; let client;
@@ -16,7 +15,7 @@ try {
client.on("connect", () => console.log("Redis connection established!")); client.on("connect", () => console.log("Redis connection established!"));
client.on("error", function (err) { client.on("error", () => {
client.quit(); client.quit();
console.error("Unable to connect to redis, setting up redis-mock."); console.error("Unable to connect to redis, setting up redis-mock.");
@@ -38,7 +37,7 @@ function set(key, value, TTL = 10800) {
const json = JSON.stringify(value); const json = JSON.stringify(value);
client.set(key, json, (error, reply) => { client.set(key, json, (error, reply) => {
if (reply == "OK") { if (reply === "OK") {
// successfully set value with key, now set TTL for key // successfully set value with key, now set TTL for key
client.expire(key, TTL, e => { client.expire(key, TTL, e => {
if (e) if (e)
@@ -55,14 +54,14 @@ function set(key, value, TTL = 10800) {
return value; return value;
} }
function get() { function get(key) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
client.get(key, (error, reply) => { client.get(key, (error, reply) => {
if (reply == null) { if (reply === null) {
return reject(); return reject();
} }
resolve(JSON.parse(reply)); return resolve(JSON.parse(reply));
}); });
}); });
} }

View File

@@ -1,5 +1,5 @@
const path = require("path"); const path = require("path");
const Field = require("./field.js"); const Field = require("./field");
let instance = null; let instance = null;

View File

@@ -1,5 +1,5 @@
const Filters = require("./filters.js"); const Filters = require("./filters");
const EnvironmentVariables = require("./environmentVariables.js"); const EnvironmentVariables = require("./environmentVariables");
class Field { class Field {
constructor(rawValue, environmentVariables) { constructor(rawValue, environmentVariables) {

View File

@@ -72,12 +72,11 @@ class SqliteDatabase {
/** /**
* Run a SQL query against the database and retrieve the status. * Run a SQL query against the database and retrieve the status.
* @param {String} sql SQL query * @param {String} sql SQL query
* @param {Array} parameters in the SQL query
* @returns {Promise} * @returns {Promise}
*/ */
execute(sql) { execute(sql) {
return new Promise(resolve => { return new Promise((resolve, reject) => {
this.connection.exec(sql, (err, database) => { this.connection.exec(sql, err => {
if (err) { if (err) {
console.log("ERROR: ", err); console.log("ERROR: ", err);
reject(err); reject(err);

View File

@@ -1,3 +1,5 @@
/* eslint-disable camelcase */
const Media = require("./media"); const Media = require("./media");
class Plex extends Media { class Plex extends Media {

View File

@@ -1,3 +1,5 @@
/* eslint-disable camelcase */
const Media = require("./media"); const Media = require("./media");
class TMDB extends Media { class TMDB extends Media {

View File

@@ -1,6 +1,15 @@
const request = require("request"); const request = require("request");
const configuration = require("../config/configuration").getInstance(); const configuration = require("../config/configuration").getInstance();
class SMSUnexpectedError extends Error {
constructor(errorMessage) {
const message = "Unexpected error from sms provider.";
super(message);
this.errorMessage = errorMessage;
}
}
const sendSMS = message => { const sendSMS = message => {
const apiKey = configuration.get("sms", "apikey"); const apiKey = configuration.get("sms", "apikey");
@@ -24,8 +33,8 @@ const sendSMS = message => {
} }
}, },
function (err, r, body) { function (err, r, body) {
console.log(err || body); const smsError = new SMSUnexpectedError(err || body);
console.log("sms provider response:", body); console.error(smsError.message);
resolve(); resolve();
} }
); );

View File

@@ -1,4 +1,3 @@
const assert = require("assert");
const http = require("http"); const http = require("http");
const { URL } = require("url"); const { URL } = require("url");
const PythonShell = require("python-shell"); const PythonShell = require("python-shell");
@@ -8,12 +7,12 @@ const establishedDatabase = require("../database/database");
const cache = require("../cache/redis"); const cache = require("../cache/redis");
function getMagnetFromURL(url) { function getMagnetFromURL(url) {
return new Promise((resolve, reject) => { return new Promise(resolve => {
const options = new URL(url); const options = new URL(url);
if (options.protocol.includes("magnet")) resolve(url); if (options.protocol.includes("magnet")) resolve(url);
http.get(options, res => { http.get(options, res => {
if (res.statusCode == 301 || res.statusCode == 302) { if (res.statusCode === 301 || res.statusCode === 302) {
resolve(res.headers.location); resolve(res.headers.location);
} }
}); });
@@ -43,7 +42,6 @@ async function callPythonAddMagnet(url, callback) {
PythonShell.run("deluge_cli.py", options, callback); PythonShell.run("deluge_cli.py", options, callback);
}) })
.catch(err => { .catch(err => {
console.log(err);
throw new Error(err); throw new Error(err);
}); });
} }
@@ -76,7 +74,7 @@ async function SearchPiratebay(query) {
); );
} }
async function AddMagnet(magnet, name, tmdb_id) { async function AddMagnet(magnet, name, tmdbId) {
return await new Promise((resolve, reject) => return await new Promise((resolve, reject) =>
callPythonAddMagnet(magnet, (err, results) => { callPythonAddMagnet(magnet, (err, results) => {
if (err) { if (err) {
@@ -87,12 +85,12 @@ async function AddMagnet(magnet, name, tmdb_id) {
/* eslint-disable no-console */ /* eslint-disable no-console */
console.log("result/error:", err, results); console.log("result/error:", err, results);
database = establishedDatabase; const database = establishedDatabase;
insert_query = const insert_query =
"INSERT INTO requested_torrent(magnet,torrent_name,tmdb_id) \ "INSERT INTO requested_torrent(magnet,torrent_name,tmdb_id) \
VALUES (?,?,?)"; VALUES (?,?,?)";
const response = database.run(insert_query, [magnet, name, tmdb_id]); const response = database.run(insert_query, [magnet, name, tmdbId]);
console.log(`Response from requsted_torrent insert: ${response}`); console.log(`Response from requsted_torrent insert: ${response}`);
resolve({ success: true }); resolve({ success: true });

View File

@@ -1,3 +1,5 @@
/* eslint-disable camelcase */
const Plex = require("../media_classes/plex"); const Plex = require("../media_classes/plex");
function translateAdded(date_string) { function translateAdded(date_string) {
@@ -27,7 +29,6 @@ function convertPlexToSeasoned(plex) {
seasons, seasons,
episodes episodes
); );
// seasoned.print();
return seasoned; return seasoned;
} }

View File

@@ -1,7 +0,0 @@
const configuration = require("../config/configuration").getInstance();
function hookDumpController(req, res) {
console.log(req);
}
module.exports = hookDumpController;

View File

@@ -3,8 +3,6 @@ const convertPlexToMovie = require("./convertPlexToMovie");
const convertPlexToShow = require("./convertPlexToShow"); const convertPlexToShow = require("./convertPlexToShow");
const convertPlexToEpisode = require("./convertPlexToEpisode"); const convertPlexToEpisode = require("./convertPlexToEpisode");
const { Movie, Show, Person } = require("../tmdb/types");
const redisCache = require("../cache/redis"); const redisCache = require("../cache/redis");
const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, ""); const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, "");
@@ -19,15 +17,14 @@ const matchingTitleAndYear = (plex, tmdb) => {
let matchingTitle; let matchingTitle;
let matchingYear; let matchingYear;
if (plex.title != null && tmdb.title != null) { if (plex?.title && tmdb?.title) {
const plexTitle = sanitize(plex.title); const plexTitle = sanitize(plex.title);
const tmdbTitle = sanitize(tmdb.title); const tmdbTitle = sanitize(tmdb.title);
matchingTitle = plexTitle == tmdbTitle; matchingTitle = plexTitle === tmdbTitle;
matchingTitle = matchingTitle || plexTitle.startsWith(tmdbTitle); matchingTitle = matchingTitle || plexTitle.startsWith(tmdbTitle);
} else matchingTitle = false; } else matchingTitle = false;
if (plex.year != null && tmdb.year != null) if (plex?.year && tmdb?.year) matchingYear = plex.year === tmdb.year;
matchingYear = plex.year == tmdb.year;
else matchingYear = false; else matchingYear = false;
return matchingTitle && matchingYear; return matchingTitle && matchingYear;
@@ -37,9 +34,9 @@ const successfullResponse = response => {
if (response && response.MediaContainer) return response; if (response && response.MediaContainer) return response;
if ( if (
response == null || response === null ||
response.status == null || response.status === null ||
response.statusText == null response.statusText === null
) { ) {
throw Error("Unable to decode response"); throw Error("Unable to decode response");
} }
@@ -83,7 +80,7 @@ class Plex {
) )
.then(machineInfo => resolve(machineInfo.machineIdentifier)) .then(machineInfo => resolve(machineInfo.machineIdentifier))
.catch(error => { .catch(error => {
if (error != undefined && error.type === "request-timeout") { if (error !== undefined && error.type === "request-timeout") {
reject({ reject({
message: "Plex did not respond", message: "Plex did not respond",
status: 408, status: 408,
@@ -99,7 +96,7 @@ class Plex {
matchTmdbAndPlexMedia(plex, tmdb) { matchTmdbAndPlexMedia(plex, tmdb) {
let match; let match;
if (plex == null || tmdb == null) return false; if (plex === null || tmdb === null) return false;
if (plex instanceof Array) { if (plex instanceof Array) {
const possibleMatches = plex.map(plexItem => const possibleMatches = plex.map(plexItem =>
@@ -129,7 +126,7 @@ class Plex {
this.matchTmdbAndPlexMedia(plex, query) this.matchTmdbAndPlexMedia(plex, query)
); );
const matchesIndex = matchesInPlex.findIndex(el => el === true); const matchesIndex = matchesInPlex.findIndex(el => el === true);
return matchesInPlex != -1 ? plexResults[matchesIndex] : null; return matchesInPlex !== -1 ? plexResults[matchesIndex] : null;
}); });
} }
@@ -145,10 +142,10 @@ class Plex {
matchingObjectInPlexPromise matchingObjectInPlexPromise
]).then(([machineIdentifier, matchingObjectInPlex]) => { ]).then(([machineIdentifier, matchingObjectInPlex]) => {
if ( if (
matchingObjectInPlex == false || matchingObjectInPlex === false ||
matchingObjectInPlex == null || matchingObjectInPlex === null ||
matchingObjectInPlex.key == null || matchingObjectInPlex.key === null ||
machineIdentifier == null machineIdentifier === null
) )
return false; return false;
@@ -177,7 +174,7 @@ class Plex {
.then(this.mapResults) .then(this.mapResults)
.then(resolve) .then(resolve)
.catch(error => { .catch(error => {
if (error != undefined && error.type === "request-timeout") { if (error !== undefined && error.type === "request-timeout") {
reject({ reject({
message: "Plex did not respond", message: "Plex did not respond",
status: 408, status: 408,
@@ -202,7 +199,7 @@ class Plex {
cacheKey, cacheKey,
(error, (error,
response => { response => {
if (response == 1) return true; if (response === 1) return true;
// TODO improve cache key matching by lowercasing it on the backend. // TODO improve cache key matching by lowercasing it on the backend.
// what do we actually need to check for if the key was deleted or not // what do we actually need to check for if the key was deleted or not
@@ -213,11 +210,7 @@ class Plex {
} }
mapResults(response) { mapResults(response) {
if ( if (response?.MediaContainer?.Hub === null) {
response == null ||
response.MediaContainer == null ||
response.MediaContainer.Hub == null
) {
return []; return [];
} }
@@ -232,8 +225,10 @@ class Plex {
if (category.type === "episode") { if (category.type === "episode") {
return category.Metadata.map(convertPlexToEpisode); return category.Metadata.map(convertPlexToEpisode);
} }
return null;
}) })
.filter(result => result !== undefined); .filter(result => result !== null);
} }
} }

View File

@@ -66,7 +66,7 @@ class RequestRepository {
* @param {identifier, type} the id of the media object and type of media must be defined * @param {identifier, type} the id of the media object and type of media must be defined
* @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, userAgent, user) {
return Promise.resolve() return Promise.resolve()
.then(() => tmdb.lookup(identifier, type)) .then(() => tmdb.lookup(identifier, type))
.then(movie => { .then(movie => {
@@ -80,7 +80,7 @@ class RequestRepository {
movie.background_path, movie.background_path,
username, username,
ip, ip,
user_agent, userAgent,
movie.type movie.type
]); ]);
}); });

View File

@@ -4,7 +4,6 @@ const TMDB = require("../tmdb/tmdb");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const establishedDatabase = require("../database/database"); const establishedDatabase = require("../database/database");
const utils = require("./utils");
class RequestRepository { class RequestRepository {
constructor(database) { constructor(database) {
@@ -19,76 +18,23 @@ class RequestRepository {
'select count(*) as totalRequests from requests where status != "downloaded"', 'select count(*) as totalRequests from requests where status != "downloaded"',
totalRequestsFilteredStatus: totalRequestsFilteredStatus:
"select count(*) as totalRequests from requests where status = ?", "select count(*) as totalRequests from requests where status = ?",
fetchAllSort: `select id, type from request order by ? ?`, // fetchAllSort: `select id, type from request order by ? ?`,
fetchAllFilter: `select id, type from request where ? is "?"`, // fetchAllFilter: `select id, type from request where ? is "?"`,
fetchAllQuery: `select id, type from request where title like "%?%" or year like "%?%"`, // fetchAllQuery: `select id, type from request where title like "%?%" or year like "%?%"`,
fetchAllFilterAndSort: `select id, type from request where ? is "?" order by ? ?`, // fetchAllFilterAndSort: `select id, type from request where ? is "?" order by ? ?`,
downloaded: // downloaded: "(select status from requests where id is request.id and type is request.type limit 1)",
"(select status from requests where id is request.id and type is request.type limit 1)",
// deluge: '(select status from deluge_torrent where id is request.id and type is request.type limit 1)', // deluge: '(select status from deluge_torrent where id is request.id and type is request.type limit 1)',
// fetchAllFilterStatus: 'select * from request where ' // fetchAllFilterStatus: 'select * from request where '
readWithoutUserData: // readWithoutUserData: "select id, title, year, type, status, date from requests where id is ? and type is ?",
"select id, title, year, type, status, date from requests where id is ? and type is ?",
read: "select id, title, year, type, status, requested_by, ip, date, user_agent from requests where id is ? and type is ?" read: "select id, title, year, type, status, requested_by, ip, date, user_agent from requests where id is ? and type is ?"
}; };
} }
sortAndFilterToDbQuery(by, direction, filter, query) {
let dbQuery;
if (query !== undefined) {
const dbParams = [query, query];
const dbquery = this.queries.fetchAllQuery;
dbQuery = dbquery
.split("")
.map(char => (char === "?" ? dbParams.shift() : char))
.join("");
} else if (by !== undefined && filter !== undefined) {
const paramToColumnAndValue = {
movie: ["type", "movie"],
show: ["type", "show"]
};
const dbParams = paramToColumnAndValue[filter].concat([by, direction]);
const query = this.queries.fetchAllFilterAndSort;
dbQuery = query
.split("")
.map(char => (char === "?" ? dbParams.shift() : char))
.join("");
} else if (by !== undefined) {
const dbParams = [by, direction];
const query = this.queries.fetchAllSort;
dbQuery = query
.split("")
.map(char => (char === "?" ? dbParams.shift() : char))
.join("");
} else if (filter !== undefined) {
const paramToColumnAndValue = {
movie: ["type", "movie"],
show: ["type", "show"],
downloaded: [this.queries.downloaded, "downloaded"]
// downloading: [this.database.delugeStatus, 'downloading']
};
const dbParams = paramToColumnAndValue[filter];
const query = this.queries.fetchAllFilter;
dbQuery = query
.split("")
.map(char => (char === "?" ? dbParams.shift() : char))
.join("");
} else {
dbQuery = this.queries.fetchAll;
}
return dbQuery;
}
mapToTmdbByType(rows) { mapToTmdbByType(rows) {
return rows.map(row => { return rows.map(row => {
if (row.type === "movie") return tmdb.movieInfo(row.id); if (row.type === "movie") return tmdb.movieInfo(row.id);
if (row.type === "show") return tmdb.showInfo(row.id); if (row.type === "show") return tmdb.showInfo(row.id);
return null;
}); });
} }
@@ -97,7 +43,7 @@ class RequestRepository {
* @param {tmdb} tmdb class of movie|show to add * @param {tmdb} tmdb class of movie|show to add
* @returns {Promise} * @returns {Promise}
*/ */
requestFromTmdb(tmdb, ip, user_agent, username) { requestFromTmdb(tmdb, ip, userAgent, username) {
return Promise.resolve() return Promise.resolve()
.then(() => this.database.get(this.queries.read, [tmdb.id, tmdb.type])) .then(() => this.database.get(this.queries.read, [tmdb.id, tmdb.type]))
.then(row => .then(row =>
@@ -112,7 +58,7 @@ class RequestRepository {
tmdb.backdrop, tmdb.backdrop,
username, username,
ip, ip,
user_agent, userAgent,
tmdb.type tmdb.type
]) ])
) )
@@ -153,20 +99,12 @@ class RequestRepository {
/** /**
* Fetch all requests with optional sort and filter params * Fetch all requests with optional sort and filter params
* @param {String} what we are sorting by * @param {String} what we are sorting by
* @param {String} direction that can be either 'asc' or 'desc', default 'asc'.
* @param {String} params to filter by * @param {String} params to filter by
* @param {String} query param to filter result on. Filters on title and year
* @returns {Promise} * @returns {Promise}
*/ */
fetchAll( fetchAll(_page = 1, filter = null) {
page = 1,
sort_by = undefined,
sort_direction = "asc",
filter = undefined,
query = undefined
) {
// TODO implemented sort and filter // TODO implemented sort and filter
page = parseInt(page); const page = parseInt(_page);
let fetchQuery = this.queries.fetchAll; let fetchQuery = this.queries.fetchAll;
let fetchTotalResults = this.queries.totalRequests; let fetchTotalResults = this.queries.totalRequests;
let fetchParams = [page]; let fetchParams = [page];
@@ -177,26 +115,24 @@ class RequestRepository {
filter === "downloaded" || filter === "downloaded" ||
filter === "requested") filter === "requested")
) { ) {
console.log("tes");
fetchQuery = this.queries.fetchAllFilteredStatus; fetchQuery = this.queries.fetchAllFilteredStatus;
fetchTotalResults = this.queries.totalRequestsFilteredStatus; fetchTotalResults = this.queries.totalRequestsFilteredStatus;
fetchParams = [filter, page]; fetchParams = [filter, page];
} else {
filter = undefined;
} }
return Promise.resolve() return this.database
.then(dbQuery => this.database.all(fetchQuery, fetchParams)) .all(fetchQuery, fetchParams)
.then(async rows => { .then(async rows => {
const sqliteResponse = await this.database.get( const sqliteResponse = await this.database.get(
fetchTotalResults, fetchTotalResults,
filter || undefined filter || null
); );
const { totalRequests } = sqliteResponse; const { totalRequests } = sqliteResponse;
const totalPages = Math.ceil(totalRequests / 26); const totalPages = Math.ceil(totalRequests / 26);
return [ return [
rows.map(item => { rows.map(_item => {
const item = _item;
item.poster = item.poster_path; item.poster = item.poster_path;
delete item.poster_path; delete item.poster_path;
item.backdrop = item.background_path; item.backdrop = item.background_path;
@@ -206,7 +142,8 @@ class RequestRepository {
totalPages, totalPages,
totalRequests totalRequests
]; ];
return Promise.all(this.mapToTmdbByType(rows));
return this.mapToTmdbByType(rows);
}) })
.then(([result, totalPages, totalRequests]) => .then(([result, totalPages, totalRequests]) =>
Promise.resolve({ Promise.resolve({

View File

@@ -29,13 +29,13 @@ function validSort(by, direction) {
}); });
} }
function validFilter(filter_param) { function validFilter(filterParam) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (filter_param === undefined) { if (filterParam === undefined) {
resolve(); resolve();
} }
if (filter_param && validFilterParams.includes(filter_param)) { if (filterParam && validFilterParams.includes(filterParam)) {
resolve(); resolve();
} else { } else {
reject( reject(

View File

@@ -1,5 +1,15 @@
const establishedDatabase = require("../database/database"); const establishedDatabase = require("../database/database");
class SearchHistoryCreateDatabaseError extends Error {
constructor(message = "an unexpected error occured", errorResponse = null) {
super(message);
this.source = "database";
this.statusCode = 500;
this.errorResponse = errorResponse;
}
}
class SearchHistory { class SearchHistory {
constructor(database) { constructor(database) {
this.database = database || establishedDatabase; this.database = database || establishedDatabase;
@@ -16,18 +26,12 @@ class SearchHistory {
* @returns {Promise} * @returns {Promise}
*/ */
read(user) { read(user) {
return new Promise((resolve, reject) => return this.database
this.database .all(this.queries.read, user)
.all(this.queries.read, user) .then(result => result.map(row => row.search_query))
.then((result, error) => { .catch(error => {
if (error) throw new Error(error); throw new Error("Unable to get history.", error);
resolve(result.map(row => row.search_query)); });
})
.catch(error => {
console.log("Error when fetching history from database:", error);
reject("Unable to get history.");
})
);
} }
/** /**
@@ -41,15 +45,12 @@ class SearchHistory {
.run(this.queries.create, [searchQuery, username]) .run(this.queries.create, [searchQuery, username])
.catch(error => { .catch(error => {
if (error.message.includes("FOREIGN")) { if (error.message.includes("FOREIGN")) {
throw new Error("Could not create search history."); throw new SearchHistoryCreateDatabaseError(
"Could not create search history."
);
} }
throw { throw new SearchHistoryCreateDatabaseError();
success: false,
status: 500,
message: "An unexpected error occured",
source: "database"
};
}); });
} }
} }

View File

@@ -1,5 +1,15 @@
const fetch = require("node-fetch"); const fetch = require("node-fetch");
class TautulliUnexpectedError extends Error {
constructor(errorMessage) {
const message = "Unexpected error fetching from tautulli.";
super(message);
this.statusCode = 500;
this.errorMessage = errorMessage;
}
}
class Tautulli { class Tautulli {
constructor(apiKey, ip, port) { constructor(apiKey, ip, port) {
this.apiKey = apiKey; this.apiKey = apiKey;
@@ -7,38 +17,37 @@ class Tautulli {
this.port = port; this.port = port;
} }
buildUrlWithCmdAndUserid(cmd, user_id) { buildUrlWithCmdAndUserid(cmd, userId) {
const url = new URL("api/v2", `http://${this.ip}:${this.port}`); const url = new URL("api/v2", `http://${this.ip}:${this.port}`);
url.searchParams.append("apikey", this.apiKey); url.searchParams.append("apikey", this.apiKey);
url.searchParams.append("cmd", cmd); url.searchParams.append("cmd", cmd);
url.searchParams.append("user_id", user_id); url.searchParams.append("user_id", userId);
return url; return url;
} }
/* eslint-disable-next-line class-methods-use-this */
logTautulliError(error) { logTautulliError(error) {
console.error("error fetching from tautulli"); throw new TautulliUnexpectedError(error);
throw error;
} }
getPlaysByDayOfWeek(plexUserId, days, y_axis) { getPlaysByDayOfWeek(plexUserId, days, yAxis) {
const url = this.buildUrlWithCmdAndUserid( const url = this.buildUrlWithCmdAndUserid(
"get_plays_by_dayofweek", "get_plays_by_dayofweek",
plexUserId plexUserId
); );
url.searchParams.append("time_range", days); url.searchParams.append("time_range", days);
url.searchParams.append("y_axis", y_axis); url.searchParams.append("y_axis", yAxis);
return fetch(url.href) return fetch(url.href)
.then(resp => resp.json()) .then(resp => resp.json())
.catch(error => this.logTautulliError(error)); .catch(error => this.logTautulliError(error));
} }
getPlaysByDays(plexUserId, days, y_axis) { getPlaysByDays(plexUserId, days, yAxis) {
const url = this.buildUrlWithCmdAndUserid("get_plays_by_date", plexUserId); const url = this.buildUrlWithCmdAndUserid("get_plays_by_date", plexUserId);
url.searchParams.append("time_range", days); url.searchParams.append("time_range", days);
url.searchParams.append("y_axis", y_axis); url.searchParams.append("y_axis", yAxis);
return fetch(url.href) return fetch(url.href)
.then(resp => resp.json()) .then(resp => resp.json())
@@ -63,8 +72,6 @@ class Tautulli {
url.searchParams.append("start", 0); url.searchParams.append("start", 0);
url.searchParams.append("length", 50); url.searchParams.append("length", 50);
console.log("fetching url", url.href);
return fetch(url.href) return fetch(url.href)
.then(resp => resp.json()) .then(resp => resp.json())
.catch(error => this.logTautulliError(error)); .catch(error => this.logTautulliError(error));

View File

@@ -3,25 +3,41 @@ const redisCache = require("../cache/redis");
const { Movie, Show, Person, Credits, ReleaseDates } = require("./types"); const { Movie, Show, Person, Credits, ReleaseDates } = require("./types");
const tmdbErrorResponse = (error, typeString = undefined) => { class TMDBNotFoundError extends Error {
constructor(message) {
super(message);
this.statusCode = 404;
}
}
class TMDBUnauthorizedError extends Error {
constructor(message = "TMDB returned access denied, requires api token.") {
super(message);
this.statusCode = 401;
}
}
class TMDBUnexpectedError extends Error {
constructor(type) {
const message = `An unexpected error occured while fetching ${type} from tmdb`;
super(message);
this.statusCode = 500;
}
}
const tmdbErrorResponse = (error, type = null) => {
if (error.status === 404) { if (error.status === 404) {
const message = error.response.body.status_message; const message = error.response.body.status_message;
throw { throw new TMDBNotFoundError(`${message.slice(0, -1)} in tmdb.`);
status: 404,
message: `${message.slice(0, -1)} in tmdb.`
};
} else if (error.status === 401) { } else if (error.status === 401) {
throw { throw new TMDBUnauthorizedError(error?.response?.body?.status_message);
status: 401,
message: error.response.body.status_message
};
} }
throw { throw new TMDBUnexpectedError(type);
status: 500,
message: `An unexpected error occured while fetching ${typeString} from tmdb`
};
}; };
class TMDB { class TMDB {
@@ -166,9 +182,9 @@ class TMDB {
.then(credits => Credits.convertFromTmdbResponse(credits)); .then(credits => Credits.convertFromTmdbResponse(credits));
} }
multiSearch(search_query, page = 1, include_adult = true) { multiSearch(searchQuery, page = 1, includeAdult = true) {
const query = { query: search_query, page, include_adult }; const query = { query: searchQuery, page, include_adult: includeAdult };
const cacheKey = `tmdb/${this.cacheTags.multiSearch}:${page}:${search_query}:${include_adult}`; const cacheKey = `tmdb/${this.cacheTags.multiSearch}:${page}:${searchQuery}:${includeAdult}`;
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMulti", query) return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMulti", query)
.then(response => this.cache.set(cacheKey, response, this.defaultTTL)) .then(response => this.cache.set(cacheKey, response, this.defaultTTL))
@@ -181,9 +197,13 @@ class TMDB {
* @param {Number} page representing pagination of results * @param {Number} page representing pagination of results
* @returns {Promise} dict with query results, current page and total_pages * @returns {Promise} dict with query results, current page and total_pages
*/ */
movieSearch(search_query, page = 1, include_adult = true) { movieSearch(searchQuery, page = 1, includeAdult = true) {
const tmdbquery = { query: search_query, page, include_adult }; const tmdbquery = {
const cacheKey = `tmdb/${this.cacheTags.movieSearch}:${page}:${search_query}:${include_adult}`; query: searchQuery,
page,
include_adult: includeAdult
};
const cacheKey = `tmdb/${this.cacheTags.movieSearch}:${page}:${searchQuery}:${includeAdult}`;
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMovie", tmdbquery) return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMovie", tmdbquery)
.then(response => this.cache.set(cacheKey, response, this.defaultTTL)) .then(response => this.cache.set(cacheKey, response, this.defaultTTL))
@@ -196,9 +216,13 @@ class TMDB {
* @param {Number} page representing pagination of results * @param {Number} page representing pagination of results
* @returns {Promise} dict with query results, current page and total_pages * @returns {Promise} dict with query results, current page and total_pages
*/ */
showSearch(search_query, page = 1, include_adult = true) { showSearch(searchQuery, page = 1, includeAdult = true) {
const tmdbquery = { query: search_query, page, include_adult }; const tmdbquery = {
const cacheKey = `tmdb/${this.cacheTags.showSearch}:${page}:${search_query}:${include_adult}`; query: searchQuery,
page,
include_adult: includeAdult
};
const cacheKey = `tmdb/${this.cacheTags.showSearch}:${page}:${searchQuery}:${includeAdult}`;
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchTv", tmdbquery) return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchTv", tmdbquery)
.then(response => this.cache.set(cacheKey, response, this.defaultTTL)) .then(response => this.cache.set(cacheKey, response, this.defaultTTL))
@@ -211,27 +235,31 @@ class TMDB {
* @param {Number} page representing pagination of results * @param {Number} page representing pagination of results
* @returns {Promise} dict with query results, current page and total_pages * @returns {Promise} dict with query results, current page and total_pages
*/ */
personSearch(search_query, page = 1, include_adult = true) { personSearch(searchQuery, page = 1, includeAdult = true) {
const tmdbquery = { query: search_query, page, include_adult }; const tmdbquery = {
const cacheKey = `tmdb/${this.cacheTags.personSearch}:${page}:${search_query}:${include_adult}`; query: searchQuery,
page,
include_adult: includeAdult
};
const cacheKey = `tmdb/${this.cacheTags.personSearch}:${page}:${searchQuery}:${includeAdult}`;
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchPerson", tmdbquery) return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchPerson", tmdbquery)
.then(response => this.cache.set(cacheKey, response, this.defaultTTL)) .then(response => this.cache.set(cacheKey, response, this.defaultTTL))
.then(response => this.mapResults(response, "person")); .then(response => this.mapResults(response, "person"));
} }
movieList(listname, page = 1) { movieList(listName, page = 1) {
const query = { page }; const query = { page };
const cacheKey = `tmdb/${this.cacheTags[listname]}:${page}`; const cacheKey = `tmdb/${this.cacheTags[listName]}:${page}`;
return this.getFromCacheOrFetchFromTmdb(cacheKey, listname, query) return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query)
.then(response => this.cache.set(cacheKey, response, this.defaultTTL)) .then(response => this.cache.set(cacheKey, response, this.defaultTTL))
.then(response => this.mapResults(response, "movie")); .then(response => this.mapResults(response, "movie"));
} }
showList(listname, page = 1) { showList(listName, page = 1) {
const query = { page }; const query = { page };
const cacheKey = `tmdb/${this.cacheTags[listname]}:${page}`; const cacheKey = `tmdb/${this.cacheTags[listName]}:${page}`;
return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query) return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query)
.then(response => this.cache.set(cacheKey, response, this.defaultTTL)) .then(response => this.cache.set(cacheKey, response, this.defaultTTL))
@@ -244,8 +272,9 @@ class TMDB {
* @param {String} 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.
*/ */
// eslint-disable-next-line class-methods-use-this
mapResults(response, type = undefined) { mapResults(response, type = undefined) {
const results = response.results.map(result => { const results = response?.results?.map(result => {
if (type === "movie" || result.media_type === "movie") { if (type === "movie" || result.media_type === "movie") {
const movie = Movie.convertFromTmdbResponse(result); const movie = Movie.convertFromTmdbResponse(result);
return movie.createJsonResponse(); return movie.createJsonResponse();
@@ -258,6 +287,8 @@ class TMDB {
const person = Person.convertFromTmdbResponse(result); const person = Person.convertFromTmdbResponse(result);
return person.createJsonResponse(); return person.createJsonResponse();
} }
return {};
}); });
return { return {
@@ -280,7 +311,7 @@ class TMDB {
if (error) { if (error) {
return reject(error); return reject(error);
} }
resolve(reponse); return resolve(reponse);
}; };
if (!argument) { if (!argument) {

View File

@@ -1,7 +1,7 @@
const Movie = require("./types/movie.js"); const Movie = require("./types/movie");
const Show = require("./types/show.js"); const Show = require("./types/show");
const Person = require("./types/person.js"); const Person = require("./types/person");
const Credits = require("./types/credits.js"); const Credits = require("./types/credits");
const ReleaseDates = require("./types/releaseDates.js"); const ReleaseDates = require("./types/releaseDates");
module.exports = { Movie, Show, Person, Credits, ReleaseDates }; module.exports = { Movie, Show, Person, Credits, ReleaseDates };

View File

@@ -61,4 +61,4 @@ interface Genre {
name: string; name: string;
} }
export { Movie, Show, Person, Genre } export { Movie, Show, Person, Genre };

View File

@@ -1,5 +1,55 @@
import Movie from "./movie"; /* eslint-disable camelcase */
import Show from "./show"; const Movie = require("./movie");
const Show = require("./show");
class CreditedMovie extends Movie {}
class CreditedShow extends Show {}
class CastMember {
constructor(character, gender, id, name, profile_path) {
this.character = character;
this.gender = gender;
this.id = id;
this.name = name;
this.profile_path = profile_path;
this.type = "person";
}
createJsonResponse() {
return {
character: this.character,
gender: this.gender,
id: this.id,
name: this.name,
profile_path: this.profile_path,
type: this.type
};
}
}
class CrewMember {
constructor(department, gender, id, job, name, profile_path) {
this.department = department;
this.gender = gender;
this.id = id;
this.job = job;
this.name = name;
this.profile_path = profile_path;
this.type = "person";
}
createJsonResponse() {
return {
department: this.department,
gender: this.gender,
id: this.id,
job: this.job,
name: this.name,
profile_path: this.profile_path,
type: this.type
};
}
}
class Credits { class Credits {
constructor(id, cast = [], crew = []) { constructor(id, cast = [], crew = []) {
@@ -63,53 +113,4 @@ class Credits {
} }
} }
class CastMember {
constructor(character, gender, id, name, profile_path) {
this.character = character;
this.gender = gender;
this.id = id;
this.name = name;
this.profile_path = profile_path;
this.type = "person";
}
createJsonResponse() {
return {
character: this.character,
gender: this.gender,
id: this.id,
name: this.name,
profile_path: this.profile_path,
type: this.type
};
}
}
class CrewMember {
constructor(department, gender, id, job, name, profile_path) {
this.department = department;
this.gender = gender;
this.id = id;
this.job = job;
this.name = name;
this.profile_path = profile_path;
this.type = "person";
}
createJsonResponse() {
return {
department: this.department,
gender: this.gender,
id: this.id,
job: this.job,
name: this.name,
profile_path: this.profile_path,
type: this.type
};
}
}
class CreditedMovie extends Movie {}
class CreditedShow extends Show {}
module.exports = Credits; module.exports = Credits;

View File

@@ -1,3 +1,5 @@
/* eslint-disable camelcase */
class Movie { class Movie {
constructor( constructor(
id, id,

View File

@@ -1,3 +1,5 @@
/* eslint-disable camelcase */
class Person { class Person {
constructor( constructor(
id, id,

View File

@@ -1,3 +1,57 @@
const releaseTypeEnum = {
1: "Premier",
2: "Limited theatrical",
3: "Theatrical",
4: "Digital",
5: "Physical",
6: "TV"
};
class Release {
constructor(country, releaseDates) {
this.country = country;
this.releaseDates = releaseDates;
}
createJsonResponse() {
return {
country: this.country,
release_dates: this.releaseDates.map(releaseDate =>
releaseDate.createJsonResponse()
)
};
}
}
class ReleaseDate {
constructor(certification, language, releaseDate, type, note) {
this.certification = certification;
this.language = language;
this.releaseDate = releaseDate;
this.type = this.releaseTypeLookup(type);
this.note = note;
}
static releaseTypeLookup(releaseTypeKey) {
if (releaseTypeKey <= Object.keys(releaseTypeEnum).length) {
return releaseTypeEnum[releaseTypeKey];
}
// TODO log | Release type not defined, does this need updating?
return null;
}
createJsonResponse() {
return {
certification: this.certification,
language: this.language,
release_date: this.releaseDate,
type: this.type,
note: this.note
};
}
}
class ReleaseDates { class ReleaseDates {
constructor(id, releases) { constructor(id, releases) {
this.id = id; this.id = id;
@@ -35,56 +89,4 @@ class ReleaseDates {
} }
} }
class Release {
constructor(country, releaseDates) {
this.country = country;
this.releaseDates = releaseDates;
}
createJsonResponse() {
return {
country: this.country,
release_dates: this.releaseDates.map(releaseDate =>
releaseDate.createJsonResponse()
)
};
}
}
class ReleaseDate {
constructor(certification, language, releaseDate, type, note) {
this.certification = certification;
this.language = language;
this.releaseDate = releaseDate;
this.type = this.releaseTypeLookup(type);
this.note = note;
}
releaseTypeLookup(releaseTypeKey) {
const releaseTypeEnum = {
1: "Premier",
2: "Limited theatrical",
3: "Theatrical",
4: "Digital",
5: "Physical",
6: "TV"
};
if (releaseTypeKey <= Object.keys(releaseTypeEnum).length) {
return releaseTypeEnum[releaseTypeKey];
}
// TODO log | Release type not defined, does this need updating?
return null;
}
createJsonResponse() {
return {
certification: this.certification,
language: this.language,
release_date: this.releaseDate,
type: this.type,
note: this.note
};
}
}
module.exports = ReleaseDates; module.exports = ReleaseDates;

View File

@@ -1,3 +1,5 @@
/* eslint-disable camelcase */
class Show { class Show {
constructor( constructor(
id, id,

View File

@@ -51,8 +51,7 @@ class UserRepository {
assert(row, "The user does not exist."); assert(row, "The user does not exist.");
return row.password; return row.password;
}) })
.catch(err => { .catch(() => {
console.log(error);
throw new Error("Unable to find your user."); throw new Error("Unable to find your user.");
}); });
} }
@@ -78,17 +77,14 @@ class UserRepository {
this.database this.database
.run(this.queries.link, [plexUserID, username]) .run(this.queries.link, [plexUserID, username])
.then(row => resolve(row)) .then(row => resolve(row))
.catch(error => { .catch(error =>
// TODO log this unknown db error
console.error("db error", error);
reject({ reject({
status: 500, status: 500,
message: message:
"An unexpected error occured while linking plex and seasoned accounts", "An unexpected error occured while linking plex and seasoned accounts",
source: "seasoned database" source: "seasoned database"
}); })
}); );
}); });
} }
@@ -102,17 +98,14 @@ class UserRepository {
this.database this.database
.run(this.queries.unlink, username) .run(this.queries.unlink, username)
.then(row => resolve(row)) .then(row => resolve(row))
.catch(error => { .catch(error =>
// TODO log this unknown db error
console.log("db error", error);
reject({ reject({
status: 500, status: 500,
message: message:
"An unexpected error occured while unlinking plex and seasoned accounts", "An unexpected error occured while unlinking plex and seasoned accounts",
source: "seasoned database" source: "seasoned database"
}); })
}); );
}); });
} }
@@ -162,18 +155,14 @@ class UserRepository {
resolve(row); resolve(row);
}) })
.catch(error => { .catch(() =>
console.error(
"Unexpected error occured while fetching settings for your account. Error:",
error
);
reject({ reject({
status: 500, status: 500,
message: message:
"An unexpected error occured while fetching settings for your account", "An unexpected error occured while fetching settings for your account",
source: "seasoned database" source: "seasoned database"
}); })
}); );
}); });
} }
@@ -184,12 +173,12 @@ class UserRepository {
* @param {String} emoji * @param {String} emoji
* @returns {Promsie} * @returns {Promsie}
*/ */
updateSettings(username, dark_mode = undefined, emoji = undefined) { updateSettings(username, darkMode = null, emoji = null) {
const settings = this.getSettings(username); const settings = this.getSettings(username);
dark_mode = dark_mode !== undefined ? dark_mode : settings.dark_mode; darkMode = darkMode ? darkMode : settings.darkMode;
emoji = emoji !== undefined ? emoji : settings.emoji; emoji = emoji ? emoji : settings.emoji;
return this.dbUpdateSettings(username, dark_mode, emoji).catch(error => { return this.dbUpdateSettings(username, darkMode, emoji).catch(error => {
if (error.status && error.message) { if (error.status && error.message) {
return error; return error;
} }
@@ -225,10 +214,10 @@ class UserRepository {
* @param {String} username * @param {String} username
* @returns {Promsie} * @returns {Promsie}
*/ */
dbUpdateSettings(username, dark_mode, emoji) { dbUpdateSettings(username, darkMode, emoji) {
return new Promise((resolve, reject) => return new Promise(resolve =>
this.database this.database
.run(this.queries.updateSettings, [username, dark_mode, emoji]) .run(this.queries.updateSettings, [username, darkMode, emoji])
.then(row => resolve(row)) .then(row => resolve(row))
); );
} }
@@ -240,7 +229,6 @@ const rejectUnexpectedDatabaseError = (
error, error,
reject = null reject = null
) => { ) => {
console.error(error);
const body = { const body = {
status, status,
message, message,
@@ -248,7 +236,7 @@ const rejectUnexpectedDatabaseError = (
}; };
if (reject == null) { if (reject == null) {
return new Promise((resolve, reject) => reject(body)); return new Promise((_, reject) => reject(body));
} }
reject(body); reject(body);
}; };

View File

@@ -50,7 +50,7 @@ class UserSecurity {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
bcrypt.compare(clearPassword, hash, (error, match) => { bcrypt.compare(clearPassword, hash, (error, match) => {
if (match) resolve(true); if (match) resolve(true);
reject(false); reject(error);
}); });
}); });
} }
@@ -61,7 +61,7 @@ class UserSecurity {
* @returns {Promise} * @returns {Promise}
*/ */
static hashPassword(clearPassword) { static hashPassword(clearPassword) {
return new Promise(resolve => { return new Promise((resolve, reject) => {
const saltRounds = 10; const saltRounds = 10;
bcrypt.hash(clearPassword, saltRounds, (error, hash) => { bcrypt.hash(clearPassword, saltRounds, (error, hash) => {
if (error) reject(error); if (error) reject(error);

View File

@@ -11,7 +11,7 @@ const mustBeAdmin = require("./middleware/mustBeAdmin");
const mustHaveAccountLinkedToPlex = require("./middleware/mustHaveAccountLinkedToPlex"); const mustHaveAccountLinkedToPlex = require("./middleware/mustHaveAccountLinkedToPlex");
const listController = require("./controllers/list/listController"); const listController = require("./controllers/list/listController");
const tautulli = require("./controllers/user/viewHistory.js"); const tautulli = require("./controllers/user/viewHistory");
const SettingsController = require("./controllers/user/settings"); const SettingsController = require("./controllers/user/settings");
const AuthenticatePlexAccountController = require("./controllers/user/authenticatePlexAccount"); const AuthenticatePlexAccountController = require("./controllers/user/authenticatePlexAccount");
@@ -24,7 +24,7 @@ app.use(bodyParser.json());
app.use(cookieParser()); app.use(cookieParser());
const router = express.Router(); const router = express.Router();
const allowedOrigins = configuration.get("webserver", "origins"); // const allowedOrigins = configuration.get("webserver", "origins");
// TODO: All JSON handling in a single router // TODO: All JSON handling in a single router
// router.use(bodyParser.json()); // router.use(bodyParser.json());
@@ -57,7 +57,7 @@ router.get("/", (req, res) => {
}); });
app.use(Raven.errorHandler()); app.use(Raven.errorHandler());
app.use((err, req, res, next) => { app.use((err, req, res) => {
res.statusCode = 500; res.statusCode = 500;
res.end(`${res.sentry}\n`); res.end(`${res.sentry}\n`);
}); });
@@ -65,9 +65,9 @@ app.use((err, req, res, next) => {
/** /**
* User * User
*/ */
router.post("/v1/user", require("./controllers/user/register.js")); router.post("/v1/user", require("./controllers/user/register"));
router.post("/v1/user/login", require("./controllers/user/login.js")); router.post("/v1/user/login", require("./controllers/user/login"));
router.post("/v1/user/logout", require("./controllers/user/logout.js")); router.post("/v1/user/logout", require("./controllers/user/logout"));
router.get( router.get(
"/v1/user/settings", "/v1/user/settings",
@@ -82,12 +82,12 @@ router.put(
router.get( router.get(
"/v1/user/search_history", "/v1/user/search_history",
mustBeAuthenticated, mustBeAuthenticated,
require("./controllers/user/searchHistory.js") require("./controllers/user/searchHistory")
); );
router.get( router.get(
"/v1/user/requests", "/v1/user/requests",
mustBeAuthenticated, mustBeAuthenticated,
require("./controllers/user/requests.js") require("./controllers/user/requests")
); );
router.post( router.post(
@@ -125,46 +125,40 @@ router.get(
/** /**
* Seasoned * Seasoned
*/ */
router.get("/v1/seasoned/all", require("./controllers/seasoned/readStrays.js")); router.get("/v1/seasoned/all", require("./controllers/seasoned/readStrays"));
router.get( router.get(
"/v1/seasoned/:strayId", "/v1/seasoned/:strayId",
require("./controllers/seasoned/strayById.js") require("./controllers/seasoned/strayById")
); );
router.post( router.post(
"/v1/seasoned/verify/:strayId", "/v1/seasoned/verify/:strayId",
require("./controllers/seasoned/verifyStray.js") require("./controllers/seasoned/verifyStray")
); );
router.get("/v2/search/", require("./controllers/search/multiSearch.js")); router.get("/v2/search/", require("./controllers/search/multiSearch"));
router.get("/v2/search/movie", require("./controllers/search/movieSearch.js")); router.get("/v2/search/movie", require("./controllers/search/movieSearch"));
router.get("/v2/search/show", require("./controllers/search/showSearch.js")); router.get("/v2/search/show", require("./controllers/search/showSearch"));
router.get( router.get("/v2/search/person", require("./controllers/search/personSearch"));
"/v2/search/person",
require("./controllers/search/personSearch.js")
);
router.get("/v2/movie/now_playing", listController.nowPlayingMovies); router.get("/v2/movie/now_playing", listController.nowPlayingMovies);
router.get("/v2/movie/popular", listController.popularMovies); router.get("/v2/movie/popular", listController.popularMovies);
router.get("/v2/movie/top_rated", listController.topRatedMovies); router.get("/v2/movie/top_rated", listController.topRatedMovies);
router.get("/v2/movie/upcoming", listController.upcomingMovies); router.get("/v2/movie/upcoming", listController.upcomingMovies);
router.get("/v2/movie/:id/credits", require("./controllers/movie/credits.js")); router.get("/v2/movie/:id/credits", require("./controllers/movie/credits"));
router.get( router.get(
"/v2/movie/:id/release_dates", "/v2/movie/:id/release_dates",
require("./controllers/movie/releaseDates.js") require("./controllers/movie/releaseDates")
); );
router.get("/v2/movie/:id", require("./controllers/movie/info.js")); router.get("/v2/movie/:id", require("./controllers/movie/info"));
router.get("/v2/show/now_playing", listController.nowPlayingShows); router.get("/v2/show/now_playing", listController.nowPlayingShows);
router.get("/v2/show/popular", listController.popularShows); router.get("/v2/show/popular", listController.popularShows);
router.get("/v2/show/top_rated", listController.topRatedShows); router.get("/v2/show/top_rated", listController.topRatedShows);
router.get("/v2/show/:id/credits", require("./controllers/show/credits.js")); router.get("/v2/show/:id/credits", require("./controllers/show/credits"));
router.get("/v2/show/:id", require("./controllers/show/info.js")); router.get("/v2/show/:id", require("./controllers/show/info"));
router.get( router.get("/v2/person/:id/credits", require("./controllers/person/credits"));
"/v2/person/:id/credits", router.get("/v2/person/:id", require("./controllers/person/info"));
require("./controllers/person/credits.js")
);
router.get("/v2/person/:id", require("./controllers/person/info.js"));
/** /**
* Plex * Plex
@@ -174,40 +168,40 @@ router.get("/v2/plex/search", require("./controllers/plex/search"));
/** /**
* List * List
*/ */
router.get("/v1/plex/search", require("./controllers/plex/searchMedia.js")); router.get("/v1/plex/search", require("./controllers/plex/searchMedia"));
router.get("/v1/plex/playing", require("./controllers/plex/plexPlaying.js")); router.get("/v1/plex/playing", require("./controllers/plex/plexPlaying"));
router.get("/v1/plex/request", require("./controllers/plex/searchRequest.js")); router.get("/v1/plex/request", require("./controllers/plex/searchRequest"));
router.get( router.get(
"/v1/plex/request/:mediaId", "/v1/plex/request/:mediaId",
require("./controllers/plex/readRequest.js") require("./controllers/plex/readRequest")
); );
router.post( router.post(
"/v1/plex/request/:mediaId", "/v1/plex/request/:mediaId",
require("./controllers/plex/submitRequest.js") require("./controllers/plex/submitRequest")
); );
router.post("/v1/plex/hook", require("./controllers/plex/hookDump.js")); router.post("/v1/plex/hook", require("./controllers/plex/hookDump"));
router.get( router.get(
"/v1/plex/watch-link", "/v1/plex/watch-link",
mustBeAuthenticated, mustBeAuthenticated,
require("./controllers/plex/watchDirectLink.js") require("./controllers/plex/watchDirectLink")
); );
/** /**
* Requests * Requests
*/ */
router.get("/v2/request", require("./controllers/request/fetchAllRequests.js")); router.get("/v2/request", require("./controllers/request/fetchAllRequests"));
router.get("/v2/request/:id", require("./controllers/request/getRequest.js")); router.get("/v2/request/:id", require("./controllers/request/getRequest"));
router.post("/v2/request", require("./controllers/request/requestTmdbId.js")); router.post("/v2/request", require("./controllers/request/requestTmdbId"));
router.get( router.get(
"/v1/plex/requests/all", "/v1/plex/requests/all",
require("./controllers/plex/fetchRequested.js") require("./controllers/plex/fetchRequested")
); );
router.put( router.put(
"/v1/plex/request/:requestId", "/v1/plex/request/:requestId",
mustBeAuthenticated, mustBeAuthenticated,
require("./controllers/plex/updateRequested.js") require("./controllers/plex/updateRequested")
); );
/** /**
@@ -215,24 +209,24 @@ router.put(
*/ */
router.get( router.get(
"/v1/pirate/search", "/v1/pirate/search",
mustBeAuthenticated, mustBeAdmin,
require("./controllers/pirate/searchTheBay.js") require("./controllers/pirate/searchTheBay")
); );
router.post( router.post(
"/v1/pirate/add", "/v1/pirate/add",
mustBeAuthenticated, mustBeAdmin,
require("./controllers/pirate/addMagnet.js") require("./controllers/pirate/addMagnet")
); );
/** /**
* git * git
*/ */
router.post("/v1/git/dump", require("./controllers/git/dumpHook.js")); router.post("/v1/git/dump", require("./controllers/git/dumpHook"));
/** /**
* misc * misc
*/ */
router.get("/v1/emoji", require("./controllers/misc/emoji.js")); router.get("/v1/emoji", require("./controllers/misc/emoji"));
// REGISTER OUR ROUTES ------------------------------- // REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api // all of our routes will be prefixed with /api

View File

@@ -5,12 +5,8 @@ const gitRepository = new GitRepository();
function dumpHookController(req, res) { function dumpHookController(req, res) {
gitRepository gitRepository
.dumpHook(req.body) .dumpHook(req.body)
.then(() => { .then(() => res.status(200))
res.status(200); .catch(() => res.status(500));
})
.catch(error => {
res.status(500);
});
} }
module.exports = dumpHookController; module.exports = dumpHookController;

View File

@@ -21,17 +21,12 @@ function handleError(error, res) {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
console.log("caught list controller error", error);
res res
.status(500) .status(500)
.send({ message: "An unexpected error occured while requesting list" }); .send({ message: "An unexpected error occured while requesting list" });
} }
} }
function handleListResponse(response, res) {
return res.send(response).catch(error => handleError(error, res));
}
function fetchTmdbList(req, res, listname, type) { function fetchTmdbList(req, res, listname, type) {
const { page } = req.query; const { page } = req.query;
@@ -48,7 +43,7 @@ function fetchTmdbList(req, res, listname, type) {
.catch(error => handleError(error, res)); .catch(error => handleError(error, res));
} }
handleError( return handleError(
{ {
status: 400, status: 400,
message: `'${type}' is not a valid list type.` message: `'${type}' is not a valid list type.`

View File

@@ -15,8 +15,6 @@ const movieCreditsController = (req, res) => {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
// TODO log unhandled errors
console.log("caugth movie credits controller error", error);
res.status(500).send({ res.status(500).send({
message: "An unexpected error occured while requesting movie credits" message: "An unexpected error occured while requesting movie credits"
}); });

View File

@@ -1,6 +1,7 @@
const configuration = require("../../../config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require("../../../tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const Plex = require("../../../plex/plex"); const Plex = require("../../../plex/plex");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const plex = new Plex(configuration.get("plex", "ip")); const plex = new Plex(configuration.get("plex", "ip"));
@@ -10,9 +11,10 @@ function handleError(error, res) {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
console.log("caught movieinfo controller error", error);
res.status(500).send({ res.status(500).send({
message: "An unexpected error occured while requesting movie info" success: false,
message: "An unexpected error occured while requesting movie info",
errorResponse: error?.message
}); });
} }
} }
@@ -25,21 +27,18 @@ function handleError(error, res) {
*/ */
async function movieInfoController(req, res) { async function movieInfoController(req, res) {
const movieId = req.params.id; const movieId = req.params.id;
let { credits, release_dates, check_existance } = req.query;
credits && credits.toLowerCase() === "true" let credits = req.query?.credits;
? (credits = true) let releaseDates = req.query?.release_dates;
: (credits = false); let checkExistance = req.query?.check_existance;
release_dates && release_dates.toLowerCase() === "true"
? (release_dates = true)
: (release_dates = false);
check_existance && check_existance.toLowerCase() === "true"
? (check_existance = true)
: (check_existance = false);
let tmdbQueue = [tmdb.movieInfo(movieId)]; credits = credits.toLowerCase() === "true";
releaseDates = releaseDates.toLowerCase() === "true";
checkExistance = checkExistance.toLowerCase() === "true";
const tmdbQueue = [tmdb.movieInfo(movieId)];
if (credits) tmdbQueue.push(tmdb.movieCredits(movieId)); if (credits) tmdbQueue.push(tmdb.movieCredits(movieId));
if (release_dates) tmdbQueue.push(tmdb.movieReleaseDates(movieId)); if (releaseDates) tmdbQueue.push(tmdb.movieReleaseDates(movieId));
try { try {
const [Movie, Credits, ReleaseDates] = await Promise.all(tmdbQueue); const [Movie, Credits, ReleaseDates] = await Promise.all(tmdbQueue);
@@ -47,19 +46,12 @@ async function movieInfoController(req, res) {
const movie = Movie.createJsonResponse(); const movie = Movie.createJsonResponse();
if (Credits) movie.credits = Credits.createJsonResponse(); if (Credits) movie.credits = Credits.createJsonResponse();
if (ReleaseDates) if (ReleaseDates)
movie.release_dates = ReleaseDates.createJsonResponse().results; movie.releaseDates = ReleaseDates.createJsonResponse().results;
if (check_existance) { if (checkExistance) {
try { try {
movie.exists_in_plex = await plex.existsInPlex(movie); movie.exists_in_plex = await plex.existsInPlex(movie);
} catch (error) { } catch {}
if (error.status === 401) {
console.log("Unathorized request, check plex server LAN settings");
} else {
console.log("Unkown error from plex!");
}
console.log(error?.message);
}
} }
res.send(movie); res.send(movie);

View File

@@ -15,8 +15,6 @@ const movieReleaseDatesController = (req, res) => {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
// TODO log unhandled errors : here our at tmdbReleaseError ?
console.log("caugth release dates controller error", error);
res.status(500).send({ res.status(500).send({
message: "An unexpected error occured while requesting movie credits" message: "An unexpected error occured while requesting movie credits"
}); });

View File

@@ -15,8 +15,6 @@ const personCreditsController = (req, res) => {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
// TODO log unhandled errors
console.log("caugth show credits controller error", error);
res.status(500).send({ res.status(500).send({
message: "An unexpected error occured while requesting person credits" message: "An unexpected error occured while requesting person credits"
}); });

View File

@@ -9,7 +9,6 @@ function handleError(error, res) {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
console.log("caught personinfo controller error", error);
res.status(500).send({ res.status(500).send({
message: "An unexpected error occured while requesting person info." message: "An unexpected error occured while requesting person info."
}); });
@@ -26,11 +25,8 @@ function handleError(error, res) {
async function personInfoController(req, res) { async function personInfoController(req, res) {
const personId = req.params.id; const personId = req.params.id;
let { credits } = req.query; let { credits } = req.query;
arguments;
credits && credits.toLowerCase() === "true" credits = credits.toLowerCase() === "true";
? (credits = true)
: (credits = false);
const tmdbQueue = [tmdb.personInfo(personId)]; const tmdbQueue = [tmdb.personInfo(personId)];
if (credits) tmdbQueue.push(tmdb.personCredits(personId)); if (credits) tmdbQueue.push(tmdb.personCredits(personId));
@@ -43,7 +39,7 @@ async function personInfoController(req, res) {
return res.send(person); return res.send(person);
} catch (error) { } catch (error) {
handleError(error, res); return handleError(error, res);
} }
} }

View File

@@ -8,14 +8,11 @@
const PirateRepository = require("../../../pirate/pirateRepository"); const PirateRepository = require("../../../pirate/pirateRepository");
function addMagnet(req, res) { function addMagnet(req, res) {
const { magnet } = req.body; const { magnet, name } = req.body;
const { name } = req.body; const tmdbId = req.body?.tmdb_id;
const { tmdb_id } = req.body;
PirateRepository.AddMagnet(magnet, name, tmdb_id) PirateRepository.AddMagnet(magnet, name, tmdbId)
.then(result => { .then(result => res.send(result))
res.send(result);
})
.catch(error => { .catch(error => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, message: error.message });
}); });

View File

@@ -1,4 +1,4 @@
const RequestRepository = require("../../../plex/requestRepository.js"); const RequestRepository = require("../../../plex/requestRepository");
const requestRepository = new RequestRepository(); const requestRepository = new RequestRepository();

View File

@@ -1,12 +1,8 @@
/*
* @Author: KevinMidboe
* @Date: 2017-05-03 23:26:46
* @Last Modified by: KevinMidboe
* @Last Modified time: 2018-02-06 20:54:22
*/
function hookDumpController(req, res) { function hookDumpController(req, res) {
console.log(req); // eslint-disable-next-line no-console
console.log("plex hook dump:", req);
res.status(200);
} }
module.exports = hookDumpController; module.exports = hookDumpController;

View File

@@ -1,6 +1,6 @@
const SearchHistory = require("../../../searchHistory/searchHistory"); const SearchHistory = require("../../../searchHistory/searchHistory");
const Cache = require("../../../tmdb/cache"); const Cache = require("../../../tmdb/cache");
const RequestRepository = require("../../../plex/requestRepository.js"); const RequestRepository = require("../../../plex/requestRepository");
const cache = new Cache(); const cache = new Cache();
const requestRepository = new RequestRepository(cache); const requestRepository = new RequestRepository(cache);
@@ -10,8 +10,8 @@ function searchRequestController(req, res) {
const { query, page, type } = req.query; const { query, page, type } = req.query;
const username = req.loggedInUser ? req.loggedInUser.username : null; const username = req.loggedInUser ? req.loggedInUser.username : null;
Promise.resolve() searchHistory
.then(() => searchHistory.create(username, query)) .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);

View File

@@ -24,16 +24,14 @@ function submitRequestController(req, res) {
const id = req.params.mediaId; const id = req.params.mediaId;
const type = req.query.type ? req.query.type.toLowerCase() : undefined; const type = req.query.type ? req.query.type.toLowerCase() : undefined;
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 userAgent = req.headers["user-agent"];
const username = req.loggedInUser ? req.loggedInUser.username : null; const username = req.loggedInUser ? req.loggedInUser.username : null;
let mediaFunction; let mediaFunction;
if (type === "movie") { if (type === "movie") {
console.log("movie");
mediaFunction = tmdbMovieInfo; mediaFunction = tmdbMovieInfo;
} else if (type === "show") { } else if (type === "show") {
console.log("show");
mediaFunction = tmdbShowInfo; mediaFunction = tmdbShowInfo;
} else { } else {
res.status(422).send({ res.status(422).send({
@@ -49,7 +47,7 @@ function submitRequestController(req, res) {
mediaFunction(id) mediaFunction(id)
.then(tmdbMedia => .then(tmdbMedia =>
request.requestFromTmdb(tmdbMedia, ip, user_agent, username) request.requestFromTmdb(tmdbMedia, ip, userAgent, username)
) )
.then(() => .then(() =>
res.send({ success: true, message: "Media item successfully requested" }) res.send({ success: true, message: "Media item successfully requested" })

View File

@@ -16,7 +16,7 @@ function watchDirectLink(req, res) {
plex plex
.getDirectLinkByTitleAndYear(title, year) .getDirectLinkByTitleAndYear(title, year)
.then(plexDirectLink => { .then(plexDirectLink => {
if (plexDirectLink == false) if (plexDirectLink === false)
res.status(404).send({ success: true, link: null }); res.status(404).send({ success: true, link: null });
else res.status(200).send({ success: true, link: plexDirectLink }); else res.status(200).send({ success: true, link: plexDirectLink });
}) })

View File

@@ -9,16 +9,10 @@ const request = new RequestRepository();
* @returns {Callback} * @returns {Callback}
*/ */
function fetchAllRequests(req, res) { function fetchAllRequests(req, res) {
const { page, filter, sort, query } = req.query; const { page, filter } = req.query;
let sort_by = sort;
let sort_direction;
if (sort !== undefined && sort.includes(":")) { request
[sort_by, sort_direction] = sort.split(":"); .fetchAll(page, filter)
}
Promise.resolve()
.then(() => request.fetchAll(page, sort_by, sort_direction, filter, query))
.then(result => res.send(result)) .then(result => res.send(result))
.catch(error => { .catch(error => {
res.status(404).send({ success: false, message: error.message }); res.status(404).send({ success: false, message: error.message });

View File

@@ -24,7 +24,7 @@ function requestTmdbIdController(req, res) {
const { id, type } = req.body; const { id, type } = req.body;
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 userAgent = req.headers["user-agent"];
const username = req.loggedInUser ? req.loggedInUser.username : null; const username = req.loggedInUser ? req.loggedInUser.username : null;
let mediaFunction; let mediaFunction;
@@ -50,7 +50,7 @@ function requestTmdbIdController(req, res) {
mediaFunction(id) mediaFunction(id)
// .catch((error) => { console.error(error); res.status(404).send({ success: false, error: 'Id not found' }) }) // .catch((error) => { console.error(error); res.status(404).send({ success: false, error: 'Id not found' }) })
.then(tmdbMedia => { .then(tmdbMedia => {
request.requestFromTmdb(tmdbMedia, ip, user_agent, username); request.requestFromTmdb(tmdbMedia, ip, userAgent, username);
// TODO enable SMS // TODO enable SMS
// const url = `https://request.movie?${tmdbMedia.type}=${tmdbMedia.id}`; // const url = `https://request.movie?${tmdbMedia.type}=${tmdbMedia.id}`;

View File

@@ -14,7 +14,7 @@ const searchHistory = new SearchHistory();
function movieSearchController(req, res) { function movieSearchController(req, res) {
const { query, page, adult } = req.query; const { query, page, adult } = req.query;
const username = req.loggedInUser ? req.loggedInUser.username : null; const username = req.loggedInUser ? req.loggedInUser.username : null;
const includeAdult = adult == "true"; const includeAdult = adult === "true";
if (username) { if (username) {
searchHistory.create(username, query); searchHistory.create(username, query);
@@ -29,8 +29,6 @@ function movieSearchController(req, res) {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
// TODO log unhandled errors
console.log("caugth movie search controller error", error);
res.status(500).send({ res.status(500).send({
message: `An unexpected error occured while searching movies with query: ${query}` message: `An unexpected error occured while searching movies with query: ${query}`
}); });

View File

@@ -5,13 +5,6 @@ const SearchHistory = require("../../../searchHistory/searchHistory");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const searchHistory = new SearchHistory(); const searchHistory = new SearchHistory();
function checkAndCreateJsonResponse(result) {
if (typeof result.createJsonResponse === "function") {
return result.createJsonResponse();
}
return result;
}
/** /**
* Controller: Search for multi (movies, shows and people by query and pagey * Controller: Search for multi (movies, shows and people by query and pagey
* @param {Request} req http request variable * @param {Request} req http request variable
@@ -21,13 +14,14 @@ function checkAndCreateJsonResponse(result) {
function multiSearchController(req, res) { function multiSearchController(req, res) {
const { query, page, adult } = req.query; const { query, page, adult } = req.query;
const username = req.loggedInUser ? req.loggedInUser.username : null; const username = req.loggedInUser ? req.loggedInUser.username : null;
const includeAdult = adult === "true";
if (username) { if (username) {
searchHistory.create(username, query); searchHistory.create(username, query);
} }
return tmdb return tmdb
.multiSearch(query, page, adult) .multiSearch(query, page, includeAdult)
.then(multiSearchResults => res.send(multiSearchResults)) .then(multiSearchResults => res.send(multiSearchResults))
.catch(error => { .catch(error => {
const { status, message } = error; const { status, message } = error;
@@ -35,8 +29,6 @@ function multiSearchController(req, res) {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
// TODO log unhandled errors
console.log("caugth multi search controller error", error);
res.status(500).send({ res.status(500).send({
message: `An unexpected error occured while searching with query: ${query}` message: `An unexpected error occured while searching with query: ${query}`
}); });

View File

@@ -14,7 +14,7 @@ const searchHistory = new SearchHistory();
function personSearchController(req, res) { function personSearchController(req, res) {
const { query, page, adult } = req.query; const { query, page, adult } = req.query;
const username = req.loggedInUser ? req.loggedInUser.username : null; const username = req.loggedInUser ? req.loggedInUser.username : null;
const includeAdult = adult == "true"; const includeAdult = adult === "true";
if (username) { if (username) {
searchHistory.create(username, query); searchHistory.create(username, query);
@@ -29,8 +29,6 @@ function personSearchController(req, res) {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
// TODO log unhandled errors
console.log("caugth person search controller error", error);
res.status(500).send({ res.status(500).send({
message: `An unexpected error occured while searching people with query: ${query}` message: `An unexpected error occured while searching people with query: ${query}`
}); });

View File

@@ -14,7 +14,7 @@ const searchHistory = new SearchHistory();
function showSearchController(req, res) { function showSearchController(req, res) {
const { query, page, adult } = req.query; const { query, page, adult } = req.query;
const username = req.loggedInUser ? req.loggedInUser.username : null; const username = req.loggedInUser ? req.loggedInUser.username : null;
const includeAdult = adult == "true"; const includeAdult = adult === "true";
if (username) { if (username) {
searchHistory.create(username, query); searchHistory.create(username, query);

View File

@@ -15,8 +15,6 @@ const showCreditsController = (req, res) => {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
// TODO log unhandled errors
console.log("caugth show credits controller error", error);
res.status(500).send({ res.status(500).send({
message: "An unexpected error occured while requesting show credits" message: "An unexpected error occured while requesting show credits"
}); });

View File

@@ -11,7 +11,6 @@ function handleError(error, res) {
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }); res.status(status).send({ success: false, message });
} else { } else {
console.log("caught showinfo controller error", error);
res.status(500).send({ res.status(500).send({
message: "An unexpected error occured while requesting show info." message: "An unexpected error occured while requesting show info."
}); });
@@ -27,14 +26,11 @@ function handleError(error, res) {
async function showInfoController(req, res) { async function showInfoController(req, res) {
const showId = req.params.id; const showId = req.params.id;
let { credits, check_existance } = req.query; let credits = req.query?.credits;
let checkExistance = req.query?.check_existance;
credits && credits.toLowerCase() === "true" credits = credits?.toLowerCase() === "true";
? (credits = true) checkExistance = checkExistance?.toLowerCase() === "true";
: (credits = false);
check_existance && check_existance.toLowerCase() === "true"
? (check_existance = true)
: (check_existance = false);
const tmdbQueue = [tmdb.showInfo(showId)]; const tmdbQueue = [tmdb.showInfo(showId)];
if (credits) tmdbQueue.push(tmdb.showCredits(showId)); if (credits) tmdbQueue.push(tmdb.showCredits(showId));
@@ -45,7 +41,12 @@ async function showInfoController(req, res) {
const show = Show.createJsonResponse(); const show = Show.createJsonResponse();
if (credits) show.credits = Credits.createJsonResponse(); if (credits) show.credits = Credits.createJsonResponse();
if (check_existance) show.exists_in_plex = await plex.existsInPlex(show); if (checkExistance) {
/* eslint no-empty: ["error", { "allowEmptyCatch": true }] */
try {
show.exists_in_plex = await plex.existsInPlex(show);
} catch {}
}
res.send(show); res.send(show);
} catch (error) { } catch (error) {

View File

@@ -1,20 +1,33 @@
const FormData = require("form-data");
const UserRepository = require("../../../user/userRepository"); const UserRepository = require("../../../user/userRepository");
const userRepository = new UserRepository(); const userRepository = new UserRepository();
const fetch = require("node-fetch");
const FormData = require("form-data"); class PlexAuthenticationError extends Error {
constructor(errorResponse, statusCode) {
const message =
"Unexptected error while authenticating to plex signin api. View error response.";
super(message);
this.errorResponse = errorResponse;
this.statusCode = statusCode;
this.success = false;
}
}
function handleError(error, res) { function handleError(error, res) {
let { status, message, source } = error; const status = error?.status;
let { message, source } = error;
if (status && message) { if (status && message) {
if (status === 401) { if (status === 401) {
(message = "Unauthorized. Please check plex credentials."), message = "Unauthorized. Please check plex credentials.";
(source = "plex"); source = "plex";
} }
res.status(status).send({ success: false, message, source }); res.status(status).send({ success: false, message, source });
} else { } else {
// eslint-disable-next-line no-console
console.log("caught authenticate plex account controller error", error); console.log("caught authenticate plex account controller error", error);
res.status(500).send({ res.status(500).send({
message: message:
@@ -26,11 +39,7 @@ function handleError(error, res) {
function handleResponse(response) { function handleResponse(response) {
if (!response.ok) { if (!response.ok) {
throw { throw new PlexAuthenticationError(response.statusText, response.status);
success: false,
status: response.status,
message: response.statusText
};
} }
return response.json(); return response.json();
@@ -64,7 +73,7 @@ function link(req, res) {
return plexAuthenticate(username, password) return plexAuthenticate(username, password)
.then(plexUser => userRepository.linkPlexUserId(user.username, plexUser.id)) .then(plexUser => userRepository.linkPlexUserId(user.username, plexUser.id))
.then(response => .then(() =>
res.send({ res.send({
success: true, success: true,
message: message:
@@ -79,7 +88,7 @@ function unlink(req, res) {
return userRepository return userRepository
.unlinkPlexUserId(username) .unlinkPlexUserId(username)
.then(response => .then(() =>
res.send({ res.send({
success: true, success: true,
message: "Successfully unlinked plex account from seasoned request." message: "Successfully unlinked plex account from seasoned request."

View File

@@ -1,12 +1,10 @@
const User = require("../../../user/user"); const User = require("../../../user/user");
const Token = require("../../../user/token"); const Token = require("../../../user/token");
const UserSecurity = require("../../../user/userSecurity"); const UserSecurity = require("../../../user/userSecurity");
const UserRepository = require("../../../user/userRepository");
const configuration = require("../../../config/configuration").getInstance(); const configuration = require("../../../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();
const isProduction = process.env.NODE_ENV === "production"; const isProduction = process.env.NODE_ENV === "production";
const cookieOptions = { const cookieOptions = {

View File

@@ -1,4 +1,4 @@
const RequestRepository = require("../../../plex/requestRepository.js"); const RequestRepository = require("../../../plex/requestRepository");
const requestRepository = new RequestRepository(); const requestRepository = new RequestRepository();

View File

@@ -23,11 +23,12 @@ const getSettingsController = (req, res) => {
const updateSettingsController = (req, res) => { const updateSettingsController = (req, res) => {
const username = req.loggedInUser ? req.loggedInUser.username : null; const username = req.loggedInUser ? req.loggedInUser.username : null;
const idempotencyKey = req.headers("Idempotency-Key"); // TODO implement better transactions // const idempotencyKey = req.headers("Idempotency-Key"); // TODO implement better transactions
const { dark_mode, emoji } = req.body; const emoji = req.body?.emoji;
const darkMode = req.body?.dark_mode;
userRepository userRepository
.updateSettings(username, dark_mode, emoji) .updateSettings(username, darkMode, emoji)
.then(settings => { .then(settings => {
res.send({ success: true, settings }); res.send({ success: true, settings });
}) })

View File

@@ -12,7 +12,7 @@ function handleError(error, res) {
if (status && message) { if (status && message) {
return res.status(status).send({ success: false, message }); return res.status(status).send({ success: false, message });
} }
console.log("caught view history controller error", error);
return res.status(500).send({ return res.status(500).send({
message: "An unexpected error occured while fetching view history" message: "An unexpected error occured while fetching view history"
}); });
@@ -35,10 +35,11 @@ function watchTimeStatsController(req, res) {
function getPlaysByDayOfWeekController(req, res) { function getPlaysByDayOfWeekController(req, res) {
const user = req.loggedInUser; const user = req.loggedInUser;
const { days, y_axis } = req.query; const days = req.query?.days;
const yAxis = req.query?.y_axis;
return tautulli return tautulli
.getPlaysByDayOfWeek(user.plexUserId, days, y_axis) .getPlaysByDayOfWeek(user.plexUserId, days, yAxis)
.then(data => .then(data =>
res.send({ res.send({
success: true, success: true,
@@ -51,7 +52,8 @@ function getPlaysByDayOfWeekController(req, res) {
function getPlaysByDaysController(req, res) { function getPlaysByDaysController(req, res) {
const user = req.loggedInUser; const user = req.loggedInUser;
const { days, y_axis } = req.query; const days = req.query?.days;
const yAxis = req.query?.y_axis;
if (days === undefined) { if (days === undefined) {
return res.status(422).send({ return res.status(422).send({
@@ -61,7 +63,7 @@ function getPlaysByDaysController(req, res) {
} }
const allowedYAxisDataType = ["plays", "duration"]; const allowedYAxisDataType = ["plays", "duration"];
if (!allowedYAxisDataType.includes(y_axis)) { if (!allowedYAxisDataType.includes(yAxis)) {
return res.status(422).send({ return res.status(422).send({
success: false, success: false,
message: `Y axis parameter must be one of values: [${allowedYAxisDataType}]` message: `Y axis parameter must be one of values: [${allowedYAxisDataType}]`
@@ -69,7 +71,7 @@ function getPlaysByDaysController(req, res) {
} }
return tautulli return tautulli
.getPlaysByDays(user.plexUserId, days, y_axis) .getPlaysByDays(user.plexUserId, days, yAxis)
.then(data => .then(data =>
res.send({ res.send({
success: true, success: true,

View File

@@ -1 +1,89 @@
[{"adult":false,"backdrop_path":"/mVr0UiqyltcfqxbAUcLl9zWL8ah.jpg","belongs_to_collection":{"id":422837,"name":"Blade Runner Collection","poster_path":"/cWESb1o9lW2i2Z3Xllv9u40aNIk.jpg","backdrop_path":"/bSHZIvLoPBWyGLeiAudN1mXdvQX.jpg"},"budget":150000000,"genres":[{"id":9648,"name":"Mystery"},{"id":878,"name":"Science Fiction"},{"id":53,"name":"Thriller"}],"homepage":"http://bladerunnermovie.com/","id":335984,"imdb_id":"tt1856101","original_language":"en","original_title":"Blade Runner 2049","overview":"Thirty years after the events of the first film, a new blade runner, LAPD Officer K, unearths a long-buried secret that has the potential to plunge what's left of society into chaos. K's discovery leads him on a quest to find Rick Deckard, a former LAPD blade runner who has been missing for 30 years.","popularity":30.03,"poster_path":"/gajva2L0rPYkEWjzgFlBXCAVBE5.jpg","production_companies":[{"id":79529,"logo_path":"/gVN3k8emmKy4iV4KREWcCtxusZK.png","name":"Torridon Films","origin_country":"US"},{"id":101829,"logo_path":"/8IOjCvgjq0zTrtP91cWD3kL2jMK.png","name":"16:14 Entertainment","origin_country":"US"},{"id":1645,"logo_path":"/6Ry6uNBaa0IbbSs1XYIgX5DkA9r.png","name":"Scott Free Productions","origin_country":""},{"id":5,"logo_path":"/71BqEFAF4V3qjjMPCpLuyJFB9A.png","name":"Columbia Pictures","origin_country":"US"},{"id":1088,"logo_path":"/9WOE5AQUXbOtLU6GTwfjS8OMF0v.png","name":"Alcon Entertainment","origin_country":"US"},{"id":78028,"logo_path":"/sTFcDFfJaSVT3sv3DoaZDE4SlGB.png","name":"Thunderbird Entertainment","origin_country":"CA"},{"id":174,"logo_path":"/ky0xOc5OrhzkZ1N6KyUxacfQsCk.png","name":"Warner Bros. Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"CA","name":"Canada"},{"iso_3166_1":"US","name":"United States of America"},{"iso_3166_1":"HU","name":"Hungary"},{"iso_3166_1":"GB","name":"United Kingdom"}],"release_date":"2017-10-04","revenue":259239658,"runtime":163,"spoken_languages":[{"iso_639_1":"en","name":"English"},{"iso_639_1":"fi","name":"suomi"}],"status":"Released","tagline":"There's still a page left.","title":"Blade Runner 2049","video":false,"vote_average":7.3,"vote_count":5478}] [
{
"adult": false,
"backdrop_path": "/mVr0UiqyltcfqxbAUcLl9zWL8ah.jpg",
"belongs_to_collection": {
"id": 422837,
"name": "Blade Runner Collection",
"poster_path": "/cWESb1o9lW2i2Z3Xllv9u40aNIk.jpg",
"backdrop_path": "/bSHZIvLoPBWyGLeiAudN1mXdvQX.jpg"
},
"budget": 150000000,
"genres": [
{ "id": 9648, "name": "Mystery" },
{ "id": 878, "name": "Science Fiction" },
{ "id": 53, "name": "Thriller" }
],
"homepage": "http://bladerunnermovie.com/",
"id": 335984,
"imdb_id": "tt1856101",
"original_language": "en",
"original_title": "Blade Runner 2049",
"overview": "Thirty years after the events of the first film, a new blade runner, LAPD Officer K, unearths a long-buried secret that has the potential to plunge what's left of society into chaos. K's discovery leads him on a quest to find Rick Deckard, a former LAPD blade runner who has been missing for 30 years.",
"popularity": 30.03,
"poster_path": "/gajva2L0rPYkEWjzgFlBXCAVBE5.jpg",
"production_companies": [
{
"id": 79529,
"logo_path": "/gVN3k8emmKy4iV4KREWcCtxusZK.png",
"name": "Torridon Films",
"origin_country": "US"
},
{
"id": 101829,
"logo_path": "/8IOjCvgjq0zTrtP91cWD3kL2jMK.png",
"name": "16:14 Entertainment",
"origin_country": "US"
},
{
"id": 1645,
"logo_path": "/6Ry6uNBaa0IbbSs1XYIgX5DkA9r.png",
"name": "Scott Free Productions",
"origin_country": ""
},
{
"id": 5,
"logo_path": "/71BqEFAF4V3qjjMPCpLuyJFB9A.png",
"name": "Columbia Pictures",
"origin_country": "US"
},
{
"id": 1088,
"logo_path": "/9WOE5AQUXbOtLU6GTwfjS8OMF0v.png",
"name": "Alcon Entertainment",
"origin_country": "US"
},
{
"id": 78028,
"logo_path": "/sTFcDFfJaSVT3sv3DoaZDE4SlGB.png",
"name": "Thunderbird Entertainment",
"origin_country": "CA"
},
{
"id": 174,
"logo_path": "/ky0xOc5OrhzkZ1N6KyUxacfQsCk.png",
"name": "Warner Bros. Pictures",
"origin_country": "US"
}
],
"production_countries": [
{ "iso_3166_1": "CA", "name": "Canada" },
{ "iso_3166_1": "US", "name": "United States of America" },
{ "iso_3166_1": "HU", "name": "Hungary" },
{ "iso_3166_1": "GB", "name": "United Kingdom" }
],
"release_date": "2017-10-04",
"revenue": 259239658,
"runtime": 163,
"spoken_languages": [
{ "iso_639_1": "en", "name": "English" },
{ "iso_639_1": "fi", "name": "suomi" }
],
"status": "Released",
"tagline": "There's still a page left.",
"title": "Blade Runner 2049",
"video": false,
"vote_average": 7.3,
"vote_count": 5478
}
]

File diff suppressed because one or more lines are too long