Feat: Cookie authentication #130
@@ -7,7 +7,7 @@
|
|||||||
},
|
},
|
||||||
"main": "webserver/server.js",
|
"main": "webserver/server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cross-env SEASONED_CONFIG=conf/development.json PROD=true NODE_PATH=. babel-node src/webserver/server.js",
|
"start": "cross-env SEASONED_CONFIG=conf/development.json NODE_ENV=production NODE_PATH=. babel-node src/webserver/server.js",
|
||||||
"test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --require @babel/register --recursive test/unit test/system",
|
"test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --require @babel/register --recursive test/unit test/system",
|
||||||
"coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. nyc mocha --require @babel/register --recursive test && nyc report --reporter=text-lcov | coveralls",
|
"coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. nyc mocha --require @babel/register --recursive test && nyc report --reporter=text-lcov | coveralls",
|
||||||
"lint": "./node_modules/.bin/eslint src/",
|
"lint": "./node_modules/.bin/eslint src/",
|
||||||
@@ -18,12 +18,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"bcrypt": "^3.0.6",
|
"bcrypt": "^5.0.1",
|
||||||
"body-parser": "~1.18.2",
|
"body-parser": "~1.18.2",
|
||||||
|
"cookie-parser": "^1.4.6",
|
||||||
"cross-env": "~5.1.4",
|
"cross-env": "~5.1.4",
|
||||||
"express": "~4.16.0",
|
"express": "~4.16.0",
|
||||||
"form-data": "^2.5.1",
|
"form-data": "^2.5.1",
|
||||||
"jsonwebtoken": "^8.2.0",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"km-moviedb": "^0.2.12",
|
"km-moviedb": "^0.2.12",
|
||||||
"node-cache": "^4.1.1",
|
"node-cache": "^4.1.1",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
"redis": "^3.0.2",
|
"redis": "^3.0.2",
|
||||||
"request": "^2.87.0",
|
"request": "^2.87.0",
|
||||||
"request-promise": "^4.2",
|
"request-promise": "^4.2",
|
||||||
"sqlite3": "^4.0.0"
|
"sqlite3": "^5.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.5.5",
|
"@babel/core": "^7.5.5",
|
||||||
|
|||||||
33
seasoned_api/src/cache/redis.js
vendored
33
seasoned_api/src/cache/redis.js
vendored
@@ -11,15 +11,15 @@ class Cache {
|
|||||||
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))
|
resolve(JSON.parse(reply));
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert cache entry with key and value.
|
* Insert cache entry with key and value.
|
||||||
* @param {String} key of the cache entry
|
* @param {String} key of the cache entry
|
||||||
* @param {String} value of the cache entry
|
* @param {String} value of the cache entry
|
||||||
@@ -27,22 +27,25 @@ class Cache {
|
|||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
set(key, value, timeToLive = 10800) {
|
set(key, value, timeToLive = 10800) {
|
||||||
if (value == null || key == null)
|
if (value == null || key == null) return null;
|
||||||
return null
|
|
||||||
|
|
||||||
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, timeToLive, (e) => {
|
client.expire(key, timeToLive, e => {
|
||||||
if (e)
|
if (e)
|
||||||
console.error('Unexpected error while setting expiration for key:', key, '. Error:', error)
|
console.error(
|
||||||
})
|
"Unexpected error while setting expiration for key:",
|
||||||
|
key,
|
||||||
|
". Error:",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return value
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
seasoned_api/src/notifications/sms.js
Normal file
35
seasoned_api/src/notifications/sms.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const request = require("request");
|
||||||
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
|
||||||
|
const sendSMS = (message) => {
|
||||||
|
const apiKey = configuration.get('sms', 'apikey')
|
||||||
|
|
||||||
|
if (!apiKey) {
|
||||||
|
console.warning("api key for sms not set, cannot send sms.")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const sender = configuration.get('sms', 'sender')
|
||||||
|
const recipient = configuration.get('sms', 'recipient')
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
request.post(
|
||||||
|
{
|
||||||
|
url: `https://gatewayapi.com/rest/mtsms?token=${apiKey}`,
|
||||||
|
json: true,
|
||||||
|
body: {
|
||||||
|
sender,
|
||||||
|
message,
|
||||||
|
recipients: [{ msisdn: `47${recipient}` }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(err, r, body) {
|
||||||
|
console.log(err ? err : body);
|
||||||
|
console.log("sms provider response:", body)
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { sendSMS }
|
||||||
@@ -10,6 +10,12 @@ const redisCache = new RedisCache();
|
|||||||
|
|
||||||
const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, "");
|
const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, "");
|
||||||
|
|
||||||
|
function fixedEncodeURIComponent(str) {
|
||||||
|
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
||||||
|
return "%" + c.charCodeAt(0).toString(16).toUpperCase();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const matchingTitleAndYear = (plex, tmdb) => {
|
const matchingTitleAndYear = (plex, tmdb) => {
|
||||||
let matchingTitle, matchingYear;
|
let matchingTitle, matchingYear;
|
||||||
|
|
||||||
@@ -121,15 +127,12 @@ class Plex {
|
|||||||
findPlexItemByTitleAndYear(title, year) {
|
findPlexItemByTitleAndYear(title, year) {
|
||||||
const query = { title, year };
|
const query = { title, year };
|
||||||
|
|
||||||
return this.search(query.title).then(plexSearchResults => {
|
return this.search(title).then(plexResults => {
|
||||||
const matchesInPlex = plexSearchResults.map(plex =>
|
const matchesInPlex = plexResults.map(plex =>
|
||||||
this.matchTmdbAndPlexMedia(plex, query)
|
this.matchTmdbAndPlexMedia(plex, query)
|
||||||
);
|
);
|
||||||
|
const matchesIndex = matchesInPlex.findIndex(el => el === true);
|
||||||
if (matchesInPlex.includes(true) === false) return false;
|
return matchesInPlex != -1 ? plexResults[matchesIndex] : null;
|
||||||
|
|
||||||
const firstMatchIndex = matchesInPlex.indexOf(true);
|
|
||||||
return plexSearchResults[firstMatchIndex][0];
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +155,7 @@ class Plex {
|
|||||||
)
|
)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const keyUriComponent = encodeURIComponent(matchingObjectInPlex.key);
|
const keyUriComponent = fixedEncodeURIComponent(matchingObjectInPlex.key);
|
||||||
return `https://app.plex.tv/desktop#!/server/${machineIdentifier}/details?key=${keyUriComponent}`;
|
return `https://app.plex.tv/desktop#!/server/${machineIdentifier}/details?key=${keyUriComponent}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -162,7 +165,7 @@ class Plex {
|
|||||||
|
|
||||||
const url = `http://${this.plexIP}:${
|
const url = `http://${this.plexIP}:${
|
||||||
this.plexPort
|
this.plexPort
|
||||||
}/hubs/search?query=${encodeURIComponent(query)}`;
|
}/hubs/search?query=${fixedEncodeURIComponent(query)}`;
|
||||||
const options = {
|
const options = {
|
||||||
timeout: 20000,
|
timeout: 20000,
|
||||||
headers: { Accept: "application/json" }
|
headers: { Accept: "application/json" }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const fetch = require('node-fetch');
|
const fetch = require("node-fetch");
|
||||||
|
|
||||||
class Tautulli {
|
class Tautulli {
|
||||||
constructor(apiKey, ip, port) {
|
constructor(apiKey, ip, port) {
|
||||||
@@ -8,50 +8,66 @@ class Tautulli {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildUrlWithCmdAndUserid(cmd, user_id) {
|
buildUrlWithCmdAndUserid(cmd, user_id) {
|
||||||
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", user_id);
|
||||||
|
|
||||||
return url
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
logTautulliError(error) {
|
||||||
|
console.error("error fetching from tautulli");
|
||||||
|
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlaysByDayOfWeek(plex_userid, days, y_axis) {
|
getPlaysByDayOfWeek(plex_userid, days, y_axis) {
|
||||||
const url = this.buildUrlWithCmdAndUserid('get_plays_by_dayofweek', plex_userid)
|
const url = this.buildUrlWithCmdAndUserid(
|
||||||
url.searchParams.append('time_range', days)
|
"get_plays_by_dayofweek",
|
||||||
url.searchParams.append('y_axis', y_axis)
|
plex_userid
|
||||||
|
);
|
||||||
|
url.searchParams.append("time_range", days);
|
||||||
|
url.searchParams.append("y_axis", y_axis);
|
||||||
|
|
||||||
return fetch(url.href)
|
return fetch(url.href)
|
||||||
.then(resp => resp.json())
|
.then(resp => resp.json())
|
||||||
|
.catch(error => this.logTautulliError(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlaysByDays(plex_userid, days, y_axis) {
|
getPlaysByDays(plex_userid, days, y_axis) {
|
||||||
const url = this.buildUrlWithCmdAndUserid('get_plays_by_date', plex_userid)
|
const url = this.buildUrlWithCmdAndUserid("get_plays_by_date", plex_userid);
|
||||||
url.searchParams.append('time_range', days)
|
url.searchParams.append("time_range", days);
|
||||||
url.searchParams.append('y_axis', y_axis)
|
url.searchParams.append("y_axis", y_axis);
|
||||||
|
|
||||||
return fetch(url.href)
|
return fetch(url.href)
|
||||||
.then(resp => resp.json())
|
.then(resp => resp.json())
|
||||||
|
.catch(error => this.logTautulliError(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
watchTimeStats(plex_userid) {
|
watchTimeStats(plex_userid) {
|
||||||
const url = this.buildUrlWithCmdAndUserid('get_user_watch_time_stats', plex_userid)
|
const url = this.buildUrlWithCmdAndUserid(
|
||||||
url.searchParams.append('grouping', 0)
|
"get_user_watch_time_stats",
|
||||||
|
plex_userid
|
||||||
|
);
|
||||||
|
url.searchParams.append("grouping", 0);
|
||||||
|
|
||||||
return fetch(url.href)
|
return fetch(url.href)
|
||||||
.then(resp => resp.json())
|
.then(resp => resp.json())
|
||||||
}
|
.catch(error => this.logTautulliError(error));
|
||||||
|
}
|
||||||
|
|
||||||
viewHistory(plex_userid) {
|
viewHistory(plex_userid) {
|
||||||
const url = this.buildUrlWithCmdAndUserid('get_history', plex_userid)
|
const url = this.buildUrlWithCmdAndUserid("get_history", plex_userid);
|
||||||
|
|
||||||
url.searchParams.append('start', 0)
|
|
||||||
url.searchParams.append('length', 50)
|
|
||||||
|
|
||||||
console.log('fetching url', url.href)
|
url.searchParams.append("start", 0);
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,35 @@
|
|||||||
const moviedb = require('km-moviedb');
|
const moviedb = require("km-moviedb");
|
||||||
const RedisCache = require('src/cache/redis')
|
const RedisCache = require("src/cache/redis");
|
||||||
const redisCache = new RedisCache()
|
const redisCache = new RedisCache();
|
||||||
|
|
||||||
const { Movie, Show, Person, Credits, ReleaseDates } = require('src/tmdb/types');
|
const {
|
||||||
|
Movie,
|
||||||
|
Show,
|
||||||
|
Person,
|
||||||
|
Credits,
|
||||||
|
ReleaseDates
|
||||||
|
} = require("src/tmdb/types");
|
||||||
|
|
||||||
const tmdbErrorResponse = (error, typeString=undefined) => {
|
const tmdbErrorResponse = (error, typeString = undefined) => {
|
||||||
if (error.status === 404) {
|
if (error.status === 404) {
|
||||||
let message = error.response.body.status_message;
|
let message = error.response.body.status_message;
|
||||||
|
|
||||||
throw {
|
throw {
|
||||||
status: 404,
|
status: 404,
|
||||||
message: message.slice(0, -1) + " in tmdb."
|
message: message.slice(0, -1) + " in tmdb."
|
||||||
}
|
};
|
||||||
} else if (error.status === 401) {
|
} else if (error.status === 401) {
|
||||||
throw {
|
throw {
|
||||||
status: 401,
|
status: 401,
|
||||||
message: error.response.body.status_message
|
message: error.response.body.status_message
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
throw {
|
throw {
|
||||||
status: 500,
|
status: 500,
|
||||||
message: `An unexpected error occured while fetching ${typeString} from tmdb`
|
message: `An unexpected error occured while fetching ${typeString} from tmdb`
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
class TMDB {
|
class TMDB {
|
||||||
constructor(apiKey, cache, tmdbLibrary) {
|
constructor(apiKey, cache, tmdbLibrary) {
|
||||||
@@ -31,34 +37,38 @@ class TMDB {
|
|||||||
|
|
||||||
this.cache = cache || redisCache;
|
this.cache = cache || redisCache;
|
||||||
this.cacheTags = {
|
this.cacheTags = {
|
||||||
multiSearch: 'mus',
|
multiSearch: "mus",
|
||||||
movieSearch: 'mos',
|
movieSearch: "mos",
|
||||||
showSearch: 'ss',
|
showSearch: "ss",
|
||||||
personSearch: 'ps',
|
personSearch: "ps",
|
||||||
movieInfo: 'mi',
|
movieInfo: "mi",
|
||||||
movieCredits: 'mc',
|
movieCredits: "mc",
|
||||||
movieReleaseDates: 'mrd',
|
movieReleaseDates: "mrd",
|
||||||
showInfo: 'si',
|
movieImages: "mimg",
|
||||||
showCredits: 'sc',
|
showInfo: "si",
|
||||||
personInfo: 'pi',
|
showCredits: "sc",
|
||||||
miscNowPlayingMovies: 'npm',
|
personInfo: "pi",
|
||||||
miscPopularMovies: 'pm',
|
personCredits: "pc",
|
||||||
miscTopRatedMovies: 'tpm',
|
miscNowPlayingMovies: "npm",
|
||||||
miscUpcomingMovies: 'um',
|
miscPopularMovies: "pm",
|
||||||
tvOnTheAir: 'toa',
|
miscTopRatedMovies: "tpm",
|
||||||
miscPopularTvs: 'pt',
|
miscUpcomingMovies: "um",
|
||||||
miscTopRatedTvs: 'trt',
|
tvOnTheAir: "toa",
|
||||||
|
miscPopularTvs: "pt",
|
||||||
|
miscTopRatedTvs: "trt"
|
||||||
};
|
};
|
||||||
this.defaultTTL = 86400
|
this.defaultTTL = 86400;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFromCacheOrFetchFromTmdb(cacheKey, tmdbMethod, query) {
|
getFromCacheOrFetchFromTmdb(cacheKey, tmdbMethod, query) {
|
||||||
return new Promise((resolve, reject) => this.cache.get(cacheKey)
|
return new Promise((resolve, reject) =>
|
||||||
.then(resolve)
|
this.cache
|
||||||
.catch(() => this.tmdb(tmdbMethod, query))
|
.get(cacheKey)
|
||||||
.then(resolve)
|
.then(resolve)
|
||||||
.catch(error => reject(tmdbErrorResponse(error, tmdbMethod)))
|
.catch(() => this.tmdb(tmdbMethod, query))
|
||||||
)
|
.then(resolve)
|
||||||
|
.catch(error => reject(tmdbErrorResponse(error, tmdbMethod)))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,9 +82,9 @@ class TMDB {
|
|||||||
const query = { id: identifier };
|
const query = { id: identifier };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.movieInfo}:${identifier}`;
|
const cacheKey = `tmdb/${this.cacheTags.movieInfo}:${identifier}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'movieInfo', query)
|
return this.getFromCacheOrFetchFromTmdb(cacheKey, "movieInfo", query)
|
||||||
.then(movie => this.cache.set(cacheKey, movie, this.defaultTTL))
|
.then(movie => this.cache.set(cacheKey, movie, this.defaultTTL))
|
||||||
.then(movie => Movie.convertFromTmdbResponse(movie))
|
.then(movie => Movie.convertFromTmdbResponse(movie));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,12 +93,12 @@ class TMDB {
|
|||||||
* @returns {Promise} movie cast object
|
* @returns {Promise} movie cast object
|
||||||
*/
|
*/
|
||||||
movieCredits(identifier) {
|
movieCredits(identifier) {
|
||||||
const query = { id: identifier }
|
const query = { id: identifier };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.movieCredits}:${identifier}`
|
const cacheKey = `tmdb/${this.cacheTags.movieCredits}:${identifier}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'movieCredits', query)
|
return this.getFromCacheOrFetchFromTmdb(cacheKey, "movieCredits", query)
|
||||||
.then(credits => this.cache.set(cacheKey, credits, this.defaultTTL))
|
.then(credits => this.cache.set(cacheKey, credits, this.defaultTTL))
|
||||||
.then(credits => Credits.convertFromTmdbResponse(credits))
|
.then(credits => Credits.convertFromTmdbResponse(credits));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,18 +125,18 @@ class TMDB {
|
|||||||
const query = { id: identifier };
|
const query = { id: identifier };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.showInfo}:${identifier}`;
|
const cacheKey = `tmdb/${this.cacheTags.showInfo}:${identifier}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'tvInfo', query)
|
return this.getFromCacheOrFetchFromTmdb(cacheKey, "tvInfo", query)
|
||||||
.then(show => this.cache.set(cacheKey, show, this.defaultTTL))
|
.then(show => this.cache.set(cacheKey, show, this.defaultTTL))
|
||||||
.then(show => Show.convertFromTmdbResponse(show))
|
.then(show => Show.convertFromTmdbResponse(show));
|
||||||
}
|
}
|
||||||
|
|
||||||
showCredits(identifier) {
|
showCredits(identifier) {
|
||||||
const query = { id: identifier }
|
const query = { id: identifier };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.showCredits}:${identifier}`
|
const cacheKey = `tmdb/${this.cacheTags.showCredits}:${identifier}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'tvCredits', query)
|
return this.getFromCacheOrFetchFromTmdb(cacheKey, "tvCredits", query)
|
||||||
.then(credits => this.cache.set(cacheKey, credits, this.defaultTTL))
|
.then(credits => this.cache.set(cacheKey, credits, this.defaultTTL))
|
||||||
.then(credits => Credits.convertFromTmdbResponse(credits))
|
.then(credits => Credits.convertFromTmdbResponse(credits));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,16 +149,29 @@ class TMDB {
|
|||||||
const query = { id: identifier };
|
const query = { id: identifier };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.personInfo}:${identifier}`;
|
const cacheKey = `tmdb/${this.cacheTags.personInfo}:${identifier}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'personInfo', query)
|
return this.getFromCacheOrFetchFromTmdb(cacheKey, "personInfo", query)
|
||||||
.then(person => this.cache.set(cacheKey, person, this.defaultTTL))
|
.then(person => this.cache.set(cacheKey, person, this.defaultTTL))
|
||||||
.then(person => Person.convertFromTmdbResponse(person))
|
.then(person => Person.convertFromTmdbResponse(person));
|
||||||
}
|
}
|
||||||
|
|
||||||
multiSearch(search_query, page=1, adult=true) {
|
personCredits(identifier) {
|
||||||
const query = { query: search_query, page: page, include_adult: adult };
|
const query = { id: identifier };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.multiSearch}:${page}:${search_query}:${adult}`;
|
const cacheKey = `tmdb/${this.cacheTags.personCredits}:${identifier}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'searchMulti', query)
|
return this.getFromCacheOrFetchFromTmdb(
|
||||||
|
cacheKey,
|
||||||
|
"personCombinedCredits",
|
||||||
|
query
|
||||||
|
)
|
||||||
|
.then(credits => this.cache.set(cacheKey, credits, this.defaultTTL))
|
||||||
|
.then(credits => Credits.convertFromTmdbResponse(credits));
|
||||||
|
}
|
||||||
|
|
||||||
|
multiSearch(search_query, page = 1, include_adult = true) {
|
||||||
|
const query = { query: search_query, page, include_adult };
|
||||||
|
const cacheKey = `tmdb/${this.cacheTags.multiSearch}:${page}:${search_query}:${include_adult}`;
|
||||||
|
|
||||||
|
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMulti", query)
|
||||||
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
||||||
.then(response => this.mapResults(response));
|
.then(response => this.mapResults(response));
|
||||||
}
|
}
|
||||||
@@ -159,13 +182,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(query, page=1, adult=true) {
|
movieSearch(search_query, page = 1, include_adult = true) {
|
||||||
const tmdbquery = { query: query, page: page, adult: adult };
|
const tmdbquery = { query: search_query, page, include_adult };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.movieSearch}:${page}:${query}:${adult}`;
|
const cacheKey = `tmdb/${this.cacheTags.movieSearch}:${page}:${search_query}:${include_adult}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'searchMovie', query)
|
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMovie", tmdbquery)
|
||||||
.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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,13 +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
|
||||||
*/
|
*/
|
||||||
showSearch(query, page=1) {
|
showSearch(search_query, page = 1, include_adult = true) {
|
||||||
const tmdbquery = { query: query, page: page };
|
const tmdbquery = { query: search_query, page, include_adult };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.showSearch}:${page}:${query}`;
|
const cacheKey = `tmdb/${this.cacheTags.showSearch}:${page}:${search_query}:${include_adult}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'searchTv', query)
|
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchTv", tmdbquery)
|
||||||
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
||||||
.then(response => this.mapResults(response, 'show'))
|
.then(response => this.mapResults(response, "show"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,14 +212,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
|
||||||
*/
|
*/
|
||||||
personSearch(query, page=1) {
|
personSearch(search_query, page = 1, include_adult = true) {
|
||||||
|
const tmdbquery = { query: search_query, page, include_adult };
|
||||||
|
const cacheKey = `tmdb/${this.cacheTags.personSearch}:${page}:${search_query}:${include_adult}`;
|
||||||
|
|
||||||
const tmdbquery = { query: query, page: page, include_adult: true };
|
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchPerson", tmdbquery)
|
||||||
const cacheKey = `tmdb/${this.cacheTags.personSearch}:${page}:${query}:${include_adult}`;
|
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'searchPerson', query)
|
|
||||||
.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) {
|
||||||
@@ -205,16 +227,16 @@ class TMDB {
|
|||||||
|
|
||||||
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: page };
|
const query = { page: 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, 'show'))
|
.then(response => this.mapResults(response, "show"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,27 +245,26 @@ 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.
|
||||||
*/
|
*/
|
||||||
mapResults(response, type=undefined) {
|
mapResults(response, type = undefined) {
|
||||||
|
|
||||||
let results = response.results.map(result => {
|
let 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();
|
||||||
} else if (type === 'show' || result.media_type === 'tv') {
|
} else if (type === "show" || result.media_type === "tv") {
|
||||||
const show = Show.convertFromTmdbResponse(result)
|
const show = Show.convertFromTmdbResponse(result);
|
||||||
return show.createJsonResponse()
|
return show.createJsonResponse();
|
||||||
} else if (type === 'person' || result.media_type === 'person') {
|
} else if (type === "person" || result.media_type === "person") {
|
||||||
const person = Person.convertFromTmdbResponse(result)
|
const person = Person.convertFromTmdbResponse(result);
|
||||||
return person.createJsonResponse()
|
return person.createJsonResponse();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
results: results,
|
results: results,
|
||||||
page: response.page,
|
page: response.page,
|
||||||
total_results: response.total_results,
|
total_results: response.total_results,
|
||||||
total_pages: response.total_pages
|
total_pages: response.total_pages
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -252,25 +273,22 @@ class TMDB {
|
|||||||
* @param {Object} argument argument to function being called
|
* @param {Object} argument argument to function being called
|
||||||
* @returns {Promise} succeeds if callback succeeds
|
* @returns {Promise} succeeds if callback succeeds
|
||||||
*/
|
*/
|
||||||
tmdb(method, argument) {
|
tmdb(method, argument) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const callback = (error, reponse) => {
|
const callback = (error, reponse) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
return reject(error);
|
return reject(error);
|
||||||
}
|
}
|
||||||
resolve(reponse);
|
resolve(reponse);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!argument) {
|
|
||||||
this.tmdbLibrary[method](callback);
|
|
||||||
} else {
|
|
||||||
this.tmdbLibrary[method](argument, callback);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!argument) {
|
||||||
|
this.tmdbLibrary[method](callback);
|
||||||
|
} else {
|
||||||
|
this.tmdbLibrary[method](argument, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = TMDB;
|
module.exports = TMDB;
|
||||||
|
|||||||
@@ -1,20 +1,55 @@
|
|||||||
class Credits {
|
import Movie from "./movie";
|
||||||
constructor(id, cast=[], crew=[]) {
|
import Show from "./show";
|
||||||
|
|
||||||
|
class Credits {
|
||||||
|
constructor(id, cast = [], crew = []) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.cast = cast;
|
this.cast = cast;
|
||||||
this.crew = crew;
|
this.crew = crew;
|
||||||
this.type = 'credits';
|
this.type = "credits";
|
||||||
}
|
}
|
||||||
|
|
||||||
static convertFromTmdbResponse(response) {
|
static convertFromTmdbResponse(response) {
|
||||||
const { id, cast, crew } = response;
|
const { id, cast, crew } = response;
|
||||||
|
|
||||||
const allCast = cast.map(cast =>
|
const allCast = cast.map(cast => {
|
||||||
new CastMember(cast.character, cast.gender, cast.id, cast.name, cast.profile_path))
|
if (cast["media_type"]) {
|
||||||
const allCrew = crew.map(crew =>
|
if (cast.media_type === "movie") {
|
||||||
new CrewMember(crew.department, crew.gender, crew.id, crew.job, crew.name, crew.profile_path))
|
return CreditedMovie.convertFromTmdbResponse(cast);
|
||||||
|
} else if (cast.media_type === "tv") {
|
||||||
|
return CreditedShow.convertFromTmdbResponse(cast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new Credits(id, allCast, allCrew)
|
return new CastMember(
|
||||||
|
cast.character,
|
||||||
|
cast.gender,
|
||||||
|
cast.id,
|
||||||
|
cast.name,
|
||||||
|
cast.profile_path
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const allCrew = crew.map(crew => {
|
||||||
|
if (cast["media_type"]) {
|
||||||
|
if (cast.media_type === "movie") {
|
||||||
|
return CreditedMovie.convertFromTmdbResponse(cast);
|
||||||
|
} else if (cast.media_type === "tv") {
|
||||||
|
return CreditedShow.convertFromTmdbResponse(cast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CrewMember(
|
||||||
|
crew.department,
|
||||||
|
crew.gender,
|
||||||
|
crew.id,
|
||||||
|
crew.job,
|
||||||
|
crew.name,
|
||||||
|
crew.profile_path
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Credits(id, allCast, allCrew);
|
||||||
}
|
}
|
||||||
|
|
||||||
createJsonResponse() {
|
createJsonResponse() {
|
||||||
@@ -22,7 +57,7 @@ class Credits {
|
|||||||
id: this.id,
|
id: this.id,
|
||||||
cast: this.cast.map(cast => cast.createJsonResponse()),
|
cast: this.cast.map(cast => cast.createJsonResponse()),
|
||||||
crew: this.crew.map(crew => crew.createJsonResponse())
|
crew: this.crew.map(crew => crew.createJsonResponse())
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +68,7 @@ class CastMember {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.profile_path = profile_path;
|
this.profile_path = profile_path;
|
||||||
this.type = 'cast member';
|
this.type = "person";
|
||||||
}
|
}
|
||||||
|
|
||||||
createJsonResponse() {
|
createJsonResponse() {
|
||||||
@@ -44,7 +79,7 @@ class CastMember {
|
|||||||
name: this.name,
|
name: this.name,
|
||||||
profile_path: this.profile_path,
|
profile_path: this.profile_path,
|
||||||
type: this.type
|
type: this.type
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +91,7 @@ class CrewMember {
|
|||||||
this.job = job;
|
this.job = job;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.profile_path = profile_path;
|
this.profile_path = profile_path;
|
||||||
this.type = 'crew member';
|
this.type = "person";
|
||||||
}
|
}
|
||||||
|
|
||||||
createJsonResponse() {
|
createJsonResponse() {
|
||||||
@@ -68,8 +103,11 @@ class CrewMember {
|
|||||||
name: this.name,
|
name: this.name,
|
||||||
profile_path: this.profile_path,
|
profile_path: this.profile_path,
|
||||||
type: this.type
|
type: this.type
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CreditedMovie extends Movie {}
|
||||||
|
class CreditedShow extends Show {}
|
||||||
|
|
||||||
module.exports = Credits;
|
module.exports = Credits;
|
||||||
|
|||||||
@@ -1,23 +1,54 @@
|
|||||||
class Person {
|
class Person {
|
||||||
constructor(id, name, poster=undefined, birthday=undefined, deathday=undefined,
|
constructor(
|
||||||
adult=undefined, knownForDepartment=undefined) {
|
id,
|
||||||
|
name,
|
||||||
|
poster = undefined,
|
||||||
|
birthday = undefined,
|
||||||
|
deathday = undefined,
|
||||||
|
adult = undefined,
|
||||||
|
placeOfBirth = undefined,
|
||||||
|
biography = undefined,
|
||||||
|
knownForDepartment = undefined
|
||||||
|
) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.poster = poster;
|
this.poster = poster;
|
||||||
this.birthday = birthday;
|
this.birthday = birthday;
|
||||||
this.deathday = deathday;
|
this.deathday = deathday;
|
||||||
this.adult = adult;
|
this.adult = adult;
|
||||||
|
this.placeOfBirth = placeOfBirth;
|
||||||
|
this.biography = biography;
|
||||||
this.knownForDepartment = knownForDepartment;
|
this.knownForDepartment = knownForDepartment;
|
||||||
this.type = 'person';
|
this.type = "person";
|
||||||
}
|
}
|
||||||
|
|
||||||
static convertFromTmdbResponse(response) {
|
static convertFromTmdbResponse(response) {
|
||||||
const { id, name, profile_path, birthday, deathday, adult, known_for_department } = response;
|
const {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
profile_path,
|
||||||
|
birthday,
|
||||||
|
deathday,
|
||||||
|
adult,
|
||||||
|
place_of_birth,
|
||||||
|
biography,
|
||||||
|
known_for_department
|
||||||
|
} = response;
|
||||||
|
|
||||||
const birthDay = new Date(birthday)
|
const birthDay = new Date(birthday);
|
||||||
const deathDay = deathday ? new Date(deathday) : null
|
const deathDay = deathday ? new Date(deathday) : null;
|
||||||
|
|
||||||
return new Person(id, name, profile_path, birthDay, deathDay, adult, known_for_department)
|
return new Person(
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
profile_path,
|
||||||
|
birthDay,
|
||||||
|
deathDay,
|
||||||
|
adult,
|
||||||
|
place_of_birth,
|
||||||
|
biography,
|
||||||
|
known_for_department
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
createJsonResponse() {
|
createJsonResponse() {
|
||||||
@@ -27,10 +58,12 @@ class Person {
|
|||||||
poster: this.poster,
|
poster: this.poster,
|
||||||
birthday: this.birthday,
|
birthday: this.birthday,
|
||||||
deathday: this.deathday,
|
deathday: this.deathday,
|
||||||
|
place_of_birth: this.placeOfBirth,
|
||||||
|
biography: this.biography,
|
||||||
known_for_department: this.knownForDepartment,
|
known_for_department: this.knownForDepartment,
|
||||||
adult: this.adult,
|
adult: this.adult,
|
||||||
type: this.type
|
type: this.type
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,25 @@
|
|||||||
const User = require('src/user/user');
|
const User = require("src/user/user");
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require("jsonwebtoken");
|
||||||
|
|
||||||
class Token {
|
class Token {
|
||||||
constructor(user, admin=false) {
|
constructor(user, admin = false, settings = null) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.admin = admin;
|
this.admin = admin;
|
||||||
|
this.settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a new token.
|
* Generate a new token.
|
||||||
* @param {String} secret a cipher of the token
|
* @param {String} secret a cipher of the token
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
toString(secret) {
|
toString(secret) {
|
||||||
const username = this.user.username;
|
const { user, admin, settings } = this;
|
||||||
const admin = this.admin;
|
|
||||||
let data = { username }
|
|
||||||
|
|
||||||
if (admin)
|
let data = { username: user.username, settings };
|
||||||
data = { ...data, admin }
|
if (admin) data["admin"] = admin;
|
||||||
|
|
||||||
return jwt.sign(data, secret, { expiresIn: '90d' });
|
return jwt.sign(data, secret, { expiresIn: "90d" });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,15 +29,12 @@ class Token {
|
|||||||
* @returns {Token}
|
* @returns {Token}
|
||||||
*/
|
*/
|
||||||
static fromString(jwtToken, secret) {
|
static fromString(jwtToken, secret) {
|
||||||
let username = null;
|
const token = jwt.verify(jwtToken, secret, { clockTolerance: 10000 });
|
||||||
|
if (token.username == null) throw new Error("Malformed token");
|
||||||
|
|
||||||
const token = jwt.verify(jwtToken, secret, { clockTolerance: 10000 })
|
const { username, admin, settings } = token;
|
||||||
if (token.username === undefined || token.username === null)
|
const user = new User(username);
|
||||||
throw new Error('Malformed token')
|
return new Token(user, admin, settings);
|
||||||
|
|
||||||
username = token.username
|
|
||||||
const user = new User(username)
|
|
||||||
return new Token(user)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,219 +1,256 @@
|
|||||||
const assert = require('assert');
|
const assert = require("assert");
|
||||||
const establishedDatabase = require('src/database/database');
|
const establishedDatabase = require("src/database/database");
|
||||||
|
|
||||||
class UserRepository {
|
class UserRepository {
|
||||||
constructor(database) {
|
constructor(database) {
|
||||||
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) 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 = ?',
|
getAdminStateByUser: "select admin from user where user_name = ?",
|
||||||
link: 'update settings set plex_userid = ? where user_name = ?',
|
link: "update settings set plex_userid = ? where user_name = ?",
|
||||||
unlink: 'update settings set plex_userid = null where user_name = ?',
|
unlink: "update settings set plex_userid = null where user_name = ?",
|
||||||
createSettings: 'insert into settings (user_name) values (?)',
|
createSettings: "insert into settings (user_name) values (?)",
|
||||||
updateSettings: 'update settings set user_name = ?, dark_mode = ?, emoji = ?',
|
updateSettings:
|
||||||
getSettings: 'select * from settings where user_name = ?'
|
"update settings set user_name = ?, dark_mode = ?, emoji = ?",
|
||||||
|
getSettings: "select * from settings where user_name = ?"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a user in a database.
|
* Create a user in a database.
|
||||||
* @param {User} user the user you want to create
|
* @param {User} user the user you want to create
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
create(user) {
|
create(user) {
|
||||||
return this.database.get(this.queries.read, user.username)
|
return this.database
|
||||||
|
.get(this.queries.read, user.username)
|
||||||
.then(() => this.database.run(this.queries.create, user.username))
|
.then(() => this.database.run(this.queries.create, user.username))
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
if (error.name === 'AssertionError' || error.message.endsWith('user_name')) {
|
if (
|
||||||
throw new Error('That username is already registered');
|
error.name === "AssertionError" ||
|
||||||
|
error.message.endsWith("user_name")
|
||||||
|
) {
|
||||||
|
throw new Error("That username is already registered");
|
||||||
}
|
}
|
||||||
throw Error(error)
|
throw Error(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a password from a database.
|
* Retrieve a password from a database.
|
||||||
* @param {User} user the user you want to retrieve the password
|
* @param {User} user the user you want to retrieve the password
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
retrieveHash(user) {
|
retrieveHash(user) {
|
||||||
return this.database.get(this.queries.retrieveHash, user.username)
|
return this.database
|
||||||
|
.get(this.queries.retrieveHash, user.username)
|
||||||
.then(row => {
|
.then(row => {
|
||||||
assert(row, 'The user does not exist.');
|
assert(row, "The user does not exist.");
|
||||||
return row.password;
|
return row.password;
|
||||||
})
|
})
|
||||||
.catch(err => { console.log(error); throw new Error('Unable to find your user.'); })
|
.catch(err => {
|
||||||
|
console.log(error);
|
||||||
|
throw new Error("Unable to find your user.");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change a user's password in a database.
|
* Change a user's password in a database.
|
||||||
* @param {User} user the user you want to create
|
* @param {User} user the user you want to create
|
||||||
* @param {String} password the new password you want to change
|
* @param {String} password the new password you want to change
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Link plex userid with seasoned user
|
* Link plex userid with seasoned user
|
||||||
* @param {String} username the user you want to lunk plex userid with
|
* @param {String} username the user you want to lunk plex userid with
|
||||||
* @param {Number} plexUserID plex unique id
|
* @param {Number} plexUserID plex unique id
|
||||||
* @returns {Promsie}
|
* @returns {Promsie}
|
||||||
*/
|
*/
|
||||||
linkPlexUserId(username, plexUserID) {
|
linkPlexUserId(username, plexUserID) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.database.run(this.queries.link, [plexUserID, username])
|
this.database
|
||||||
|
.run(this.queries.link, [plexUserID, username])
|
||||||
.then(row => resolve(row))
|
.then(row => resolve(row))
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// TODO log this unknown db error
|
// TODO log this unknown db error
|
||||||
console.log('db error', error)
|
console.error("db error", error);
|
||||||
|
|
||||||
reject({
|
reject({
|
||||||
status: 500,
|
status: 500,
|
||||||
message: 'An unexpected error occured while linking plex and seasoned accounts',
|
message:
|
||||||
source: 'seasoned database'
|
"An unexpected error occured while linking plex and seasoned accounts",
|
||||||
})
|
source: "seasoned database"
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlink plex userid with seasoned user
|
* Unlink plex userid with seasoned user
|
||||||
* @param {User} user the user you want to lunk plex userid with
|
* @param {User} user the user you want to lunk plex userid with
|
||||||
* @returns {Promsie}
|
* @returns {Promsie}
|
||||||
*/
|
*/
|
||||||
unlinkPlexUserId(username) {
|
unlinkPlexUserId(username) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.database.run(this.queries.unlink, username)
|
this.database
|
||||||
|
.run(this.queries.unlink, username)
|
||||||
.then(row => resolve(row))
|
.then(row => resolve(row))
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// TODO log this unknown db error
|
// TODO log this unknown db error
|
||||||
console.log('db error', error)
|
console.log("db error", error);
|
||||||
|
|
||||||
reject({
|
reject({
|
||||||
status: 500,
|
status: 500,
|
||||||
message: 'An unexpected error occured while unlinking plex and seasoned accounts',
|
message:
|
||||||
source: 'seasoned database'
|
"An unexpected error occured while unlinking plex and seasoned accounts",
|
||||||
})
|
source: "seasoned database"
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the user has boolean flag set for admin in database
|
* Check if the user has boolean flag set for admin in database
|
||||||
* @param {User} user object
|
* @param {User} user object
|
||||||
* @returns {Promsie}
|
* @returns {Promsie}
|
||||||
*/
|
*/
|
||||||
checkAdmin(user) {
|
checkAdmin(user) {
|
||||||
return this.database.get(this.queries.getAdminStateByUser, user.username)
|
return this.database
|
||||||
.then((row) => row.admin);
|
.get(this.queries.getAdminStateByUser, user.username)
|
||||||
|
.then(row => row.admin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get settings for user matching string username
|
* Get settings for user matching string username
|
||||||
* @param {String} username
|
* @param {String} username
|
||||||
* @returns {Promsie}
|
* @returns {Promsie}
|
||||||
*/
|
*/
|
||||||
getSettings(username) {
|
getSettings(username) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.database.get(this.queries.getSettings, username)
|
this.database
|
||||||
.then(async (row) => {
|
.get(this.queries.getSettings, username)
|
||||||
|
.then(async row => {
|
||||||
if (row == null) {
|
if (row == null) {
|
||||||
console.log(`settings do not exist for user: ${username}. Creating settings entry.`)
|
console.debug(
|
||||||
|
`settings do not exist for user: ${username}. Creating settings entry.`
|
||||||
|
);
|
||||||
|
|
||||||
const userExistsWithUsername = await this.database.get('select * from user where user_name is ?', username)
|
const userExistsWithUsername = await this.database.get(
|
||||||
|
"select * from user where user_name is ?",
|
||||||
|
username
|
||||||
|
);
|
||||||
if (userExistsWithUsername !== undefined) {
|
if (userExistsWithUsername !== undefined) {
|
||||||
try {
|
try {
|
||||||
resolve(this.dbCreateSettings(username))
|
resolve(this.dbCreateSettings(username));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reject(error)
|
reject(error);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reject({
|
reject({
|
||||||
status: 404,
|
status: 404,
|
||||||
message: 'User not found, no settings to get'
|
message: "User not found, no settings to get"
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(row)
|
resolve(row);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Unexpected error occured while fetching settings for your account. Error:', error)
|
console.error(
|
||||||
|
"Unexpected error occured while fetching settings for your account. Error:",
|
||||||
|
error
|
||||||
|
);
|
||||||
reject({
|
reject({
|
||||||
status: 500,
|
status: 500,
|
||||||
message: 'An unexpected error occured while fetching settings for your account',
|
message:
|
||||||
source: 'seasoned database'
|
"An unexpected error occured while fetching settings for your account",
|
||||||
})
|
source: "seasoned database"
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update settings values for user matching string username
|
* Update settings values for user matching string username
|
||||||
* @param {String} username
|
* @param {String} username
|
||||||
* @param {String} dark_mode
|
* @param {String} dark_mode
|
||||||
* @param {String} emoji
|
* @param {String} emoji
|
||||||
* @returns {Promsie}
|
* @returns {Promsie}
|
||||||
*/
|
*/
|
||||||
updateSettings(username, dark_mode=undefined, emoji=undefined) {
|
updateSettings(username, dark_mode = undefined, emoji = undefined) {
|
||||||
const settings = this.getSettings(username)
|
const settings = this.getSettings(username);
|
||||||
dark_mode = dark_mode !== undefined ? dark_mode : settings.dark_mode
|
dark_mode = dark_mode !== undefined ? dark_mode : settings.dark_mode;
|
||||||
emoji = emoji !== undefined ? emoji : settings.emoji
|
emoji = emoji !== undefined ? emoji : settings.emoji;
|
||||||
|
|
||||||
return this.dbUpdateSettings(username, dark_mode, emoji)
|
return this.dbUpdateSettings(username, dark_mode, emoji).catch(error => {
|
||||||
.catch(error => {
|
if (error.status && error.message) {
|
||||||
if (error.status && error.message) {
|
return error;
|
||||||
return error
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: 500,
|
status: 500,
|
||||||
message: 'An unexpected error occured while updating settings for your account'
|
message:
|
||||||
}
|
"An unexpected error occured while updating settings for your account"
|
||||||
})
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for creating settings in the database
|
* Helper function for creating settings in the database
|
||||||
* @param {String} username
|
* @param {String} username
|
||||||
* @returns {Promsie}
|
* @returns {Promsie}
|
||||||
*/
|
*/
|
||||||
dbCreateSettings(username) {
|
dbCreateSettings(username) {
|
||||||
return this.database.run(this.queries.createSettings, username)
|
return this.database
|
||||||
|
.run(this.queries.createSettings, username)
|
||||||
.then(() => this.database.get(this.queries.getSettings, username))
|
.then(() => this.database.get(this.queries.getSettings, username))
|
||||||
.catch(error => rejectUnexpectedDatabaseError('Unexpected error occured while creating settings', 503, error))
|
.catch(error =>
|
||||||
|
rejectUnexpectedDatabaseError(
|
||||||
|
"Unexpected error occured while creating settings",
|
||||||
|
503,
|
||||||
|
error
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for updating settings in the database
|
* Helper function for updating settings in the database
|
||||||
* @param {String} username
|
* @param {String} username
|
||||||
* @returns {Promsie}
|
* @returns {Promsie}
|
||||||
*/
|
*/
|
||||||
dbUpdateSettings(username, dark_mode, emoji) {
|
dbUpdateSettings(username, dark_mode, emoji) {
|
||||||
return new Promise((resolve, reject) =>
|
return new Promise((resolve, reject) =>
|
||||||
this.database.run(this.queries.updateSettings, [username, dark_mode, emoji])
|
this.database
|
||||||
.then(row => resolve(row)))
|
.run(this.queries.updateSettings, [username, dark_mode, emoji])
|
||||||
|
.then(row => resolve(row))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const rejectUnexpectedDatabaseError = (
|
||||||
const rejectUnexpectedDatabaseError = (message, status, error, reject=null) => {
|
message,
|
||||||
console.error(error)
|
status,
|
||||||
|
error,
|
||||||
|
reject = null
|
||||||
|
) => {
|
||||||
|
console.error(error);
|
||||||
const body = {
|
const body = {
|
||||||
status,
|
status,
|
||||||
message,
|
message,
|
||||||
source: 'seasoned database'
|
source: "seasoned database"
|
||||||
}
|
};
|
||||||
|
|
||||||
if (reject == null) {
|
if (reject == null) {
|
||||||
return new Promise((resolve, reject) => reject(body))
|
return new Promise((resolve, reject) => reject(body));
|
||||||
}
|
}
|
||||||
reject(body)
|
reject(body);
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = UserRepository;
|
module.exports = UserRepository;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require("bcrypt");
|
||||||
const UserRepository = require('src/user/userRepository');
|
const UserRepository = require("src/user/userRepository");
|
||||||
|
|
||||||
class UserSecurity {
|
class UserSecurity {
|
||||||
constructor(database) {
|
constructor(database) {
|
||||||
this.userRepository = new UserRepository(database);
|
this.userRepository = new UserRepository(database);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new user in PlanFlix.
|
* Create a new user in PlanFlix.
|
||||||
@@ -13,15 +13,15 @@ class UserSecurity {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
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 (clearPassword.trim() === '') {
|
} else if (clearPassword.trim() === "") {
|
||||||
throw new Error('The password is empty.');
|
throw new Error("The password is empty.");
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve()
|
return this.userRepository
|
||||||
.then(() => this.userRepository.create(user))
|
.create(user)
|
||||||
.then(() => UserSecurity.hashPassword(clearPassword))
|
.then(() => UserSecurity.hashPassword(clearPassword))
|
||||||
.then(hash => this.userRepository.changePassword(user, hash))
|
.then(hash => this.userRepository.changePassword(user, hash));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,24 +32,25 @@ class UserSecurity {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
login(user, clearPassword) {
|
login(user, clearPassword) {
|
||||||
return Promise.resolve()
|
return this.userRepository
|
||||||
.then(() => this.userRepository.retrieveHash(user))
|
.retrieveHash(user)
|
||||||
.then(hash => UserSecurity.compareHashes(hash, clearPassword))
|
.then(hash => UserSecurity.compareHashes(hash, clearPassword))
|
||||||
.catch(() => { throw new Error('Incorrect username or password.'); });
|
.catch(() => {
|
||||||
|
throw new Error("Incorrect username or password.");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare between a password and a hash password from database.
|
* Compare between a password and a hash password from database.
|
||||||
* @param {String} hash the hash password from database
|
* @param {String} hash the hash password from database
|
||||||
* @param {String} clearPassword the user's password
|
* @param {String} clearPassword the user's password
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
static compareHashes(hash, clearPassword) {
|
static compareHashes(hash, clearPassword) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
bcrypt.compare(clearPassword, hash, (error, match) => {
|
bcrypt.compare(clearPassword, hash, (error, match) => {
|
||||||
if (match)
|
if (match) resolve(true);
|
||||||
resolve()
|
reject(false);
|
||||||
reject()
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -60,9 +61,11 @@ class UserSecurity {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
static hashPassword(clearPassword) {
|
static hashPassword(clearPassword) {
|
||||||
return new Promise((resolve) => {
|
return new Promise(resolve => {
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
bcrypt.hash(clearPassword, saltRounds, (error, hash) => {
|
bcrypt.hash(clearPassword, saltRounds, (error, hash) => {
|
||||||
|
if (error) reject(error);
|
||||||
|
|
||||||
resolve(hash);
|
resolve(hash);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
const express = require("express");
|
const express = require("express");
|
||||||
const Raven = require("raven");
|
const Raven = require("raven");
|
||||||
|
const cookieParser = require("cookie-parser");
|
||||||
const bodyParser = require("body-parser");
|
const bodyParser = require("body-parser");
|
||||||
const tokenToUser = require("./middleware/tokenToUser");
|
|
||||||
|
const configuration = require("src/config/configuration").getInstance();
|
||||||
|
|
||||||
|
const reqTokenToUser = require("./middleware/reqTokenToUser");
|
||||||
const mustBeAuthenticated = require("./middleware/mustBeAuthenticated");
|
const mustBeAuthenticated = require("./middleware/mustBeAuthenticated");
|
||||||
const mustBeAdmin = require("./middleware/mustBeAdmin");
|
const mustBeAdmin = require("./middleware/mustBeAdmin");
|
||||||
const mustHaveAccountLinkedToPlex = require("./middleware/mustHaveAccountLinkedToPlex");
|
const mustHaveAccountLinkedToPlex = require("./middleware/mustHaveAccountLinkedToPlex");
|
||||||
const configuration = require("src/config/configuration").getInstance();
|
|
||||||
|
|
||||||
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.js");
|
||||||
@@ -18,6 +21,7 @@ Raven.config(configuration.get("raven", "DSN")).install();
|
|||||||
const app = express(); // define our app using express
|
const app = express(); // define our app using express
|
||||||
app.use(Raven.requestHandler());
|
app.use(Raven.requestHandler());
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
app.use(cookieParser());
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const allowedOrigins = configuration.get("webserver", "origins");
|
const allowedOrigins = configuration.get("webserver", "origins");
|
||||||
@@ -26,31 +30,34 @@ const allowedOrigins = configuration.get("webserver", "origins");
|
|||||||
// router.use(bodyParser.json());
|
// router.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
/* Decode the Authorization header if provided */
|
/* Check header and cookie for authentication and set req.loggedInUser */
|
||||||
router.use(tokenToUser);
|
router.use(reqTokenToUser);
|
||||||
|
|
||||||
// TODO: Should have a separate middleware/router for handling headers.
|
// TODO: Should have a separate middleware/router for handling headers.
|
||||||
router.use((req, res, next) => {
|
router.use((req, res, next) => {
|
||||||
// TODO add logging of all incoming
|
// TODO add logging of all incoming
|
||||||
const origin = req.headers.origin;
|
// const origin = req.headers.origin;
|
||||||
if (allowedOrigins.indexOf(origin) > -1) {
|
// if (allowedOrigins.indexOf(origin) > -1) {
|
||||||
res.setHeader("Access-Control-Allow-Origin", origin);
|
// res.setHeader("Access-Control-Allow-Origin", origin);
|
||||||
}
|
// }
|
||||||
|
|
||||||
res.header(
|
res.header(
|
||||||
"Access-Control-Allow-Headers",
|
"Access-Control-Allow-Headers",
|
||||||
"Content-Type, Authorization, loggedinuser"
|
"Content-Type, Authorization, loggedinuser, set-cookie"
|
||||||
);
|
);
|
||||||
res.header("Access-Control-Allow-Methods", "POST, GET, PUT");
|
|
||||||
|
res.header("Access-Control-Allow-Credentials", "true");
|
||||||
|
res.header("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS");
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/", function mainHandler(req, res) {
|
router.get("/", (req, res) => {
|
||||||
throw new Error("Broke!");
|
res.send("welcome to seasoned api");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(Raven.errorHandler());
|
app.use(Raven.errorHandler());
|
||||||
app.use(function onError(err, req, res, next) {
|
app.use((err, req, res, next) => {
|
||||||
res.statusCode = 500;
|
res.statusCode = 500;
|
||||||
res.end(res.sentry + "\n");
|
res.end(res.sentry + "\n");
|
||||||
});
|
});
|
||||||
@@ -60,6 +67,7 @@ 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.post("/v1/user/logout", require("./controllers/user/logout.js"));
|
||||||
router.get(
|
router.get(
|
||||||
"/v1/user/settings",
|
"/v1/user/settings",
|
||||||
mustBeAuthenticated,
|
mustBeAuthenticated,
|
||||||
@@ -137,20 +145,23 @@ 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/show/now_playing", listController.nowPlayingShows);
|
|
||||||
router.get("/v2/show/popular", listController.popularShows);
|
|
||||||
router.get("/v2/show/top_rated", listController.topRatedShows);
|
|
||||||
|
|
||||||
router.get("/v2/movie/:id/credits", require("./controllers/movie/credits.js"));
|
router.get("/v2/movie/:id/credits", require("./controllers/movie/credits.js"));
|
||||||
router.get(
|
router.get(
|
||||||
"/v2/movie/:id/release_dates",
|
"/v2/movie/:id/release_dates",
|
||||||
require("./controllers/movie/releaseDates.js")
|
require("./controllers/movie/releaseDates.js")
|
||||||
);
|
);
|
||||||
router.get("/v2/show/:id/credits", require("./controllers/show/credits.js"));
|
|
||||||
|
|
||||||
router.get("/v2/movie/:id", require("./controllers/movie/info.js"));
|
router.get("/v2/movie/:id", require("./controllers/movie/info.js"));
|
||||||
|
|
||||||
|
router.get("/v2/show/now_playing", listController.nowPlayingShows);
|
||||||
|
router.get("/v2/show/popular", listController.popularShows);
|
||||||
|
router.get("/v2/show/top_rated", listController.topRatedShows);
|
||||||
|
router.get("/v2/show/:id/credits", require("./controllers/show/credits.js"));
|
||||||
router.get("/v2/show/:id", require("./controllers/show/info.js"));
|
router.get("/v2/show/:id", require("./controllers/show/info.js"));
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
"/v2/person/:id/credits",
|
||||||
|
require("./controllers/person/credits.js")
|
||||||
|
);
|
||||||
router.get("/v2/person/:id", require("./controllers/person/info.js"));
|
router.get("/v2/person/:id", require("./controllers/person/info.js"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
26
seasoned_api/src/webserver/controllers/person/credits.js
Normal file
26
seasoned_api/src/webserver/controllers/person/credits.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const configuration = require("src/config/configuration").getInstance();
|
||||||
|
const TMDB = require("src/tmdb/tmdb");
|
||||||
|
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
||||||
|
|
||||||
|
const personCreditsController = (req, res) => {
|
||||||
|
const personId = req.params.id;
|
||||||
|
|
||||||
|
return tmdb
|
||||||
|
.personCredits(personId)
|
||||||
|
.then(credits => res.send(credits))
|
||||||
|
.catch(error => {
|
||||||
|
const { status, message } = error;
|
||||||
|
|
||||||
|
if (status && message) {
|
||||||
|
res.status(status).send({ success: false, message });
|
||||||
|
} else {
|
||||||
|
// TODO log unhandled errors
|
||||||
|
console.log("caugth show credits controller error", error);
|
||||||
|
res.status(500).send({
|
||||||
|
message: "An unexpected error occured while requesting person credits"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = personCreditsController;
|
||||||
@@ -1,23 +1,49 @@
|
|||||||
const configuration = require('src/config/configuration').getInstance();
|
const configuration = require("src/config/configuration").getInstance();
|
||||||
const TMDB = require('src/tmdb/tmdb');
|
const TMDB = require("src/tmdb/tmdb");
|
||||||
const tmdb = new TMDB(configuration.get('tmdb', 'apiKey'));
|
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
||||||
|
|
||||||
|
function handleError(error, res) {
|
||||||
|
const { status, message } = error;
|
||||||
|
|
||||||
|
if (status && message) {
|
||||||
|
res.status(status).send({ success: false, message });
|
||||||
|
} else {
|
||||||
|
console.log("caught personinfo controller error", error);
|
||||||
|
res.status(500).send({
|
||||||
|
message: "An unexpected error occured while requesting person info."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller: Retrieve information for a person
|
* Controller: Retrieve information for a person
|
||||||
* @param {Request} req http request variable
|
* @param {Request} req http request variable
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function personInfoController(req, res) {
|
async function personInfoController(req, res) {
|
||||||
const personId = req.params.id;
|
const personId = req.params.id;
|
||||||
|
let { credits } = req.query;
|
||||||
|
arguments;
|
||||||
|
|
||||||
|
credits && credits.toLowerCase() === "true"
|
||||||
|
? (credits = true)
|
||||||
|
: (credits = false);
|
||||||
|
|
||||||
tmdb.personInfo(personId)
|
let tmdbQueue = [tmdb.personInfo(personId)];
|
||||||
.then(person => res.send(person.createJsonResponse()))
|
if (credits) tmdbQueue.push(tmdb.personCredits(personId));
|
||||||
.catch(error => {
|
|
||||||
res.status(404).send({ success: false, message: error.message });
|
try {
|
||||||
});
|
const [Person, Credits] = await Promise.all(tmdbQueue);
|
||||||
|
|
||||||
|
const person = Person.createJsonResponse();
|
||||||
|
if (credits) person.credits = Credits.createJsonResponse();
|
||||||
|
|
||||||
|
return res.send(person);
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error, res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = personInfoController;
|
module.exports = personInfoController;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const TMDB = require("src/tmdb/tmdb");
|
|||||||
const RequestRepository = require("src/request/request");
|
const RequestRepository = require("src/request/request");
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
||||||
const request = new RequestRepository();
|
const request = new RequestRepository();
|
||||||
|
// const { sendSMS } = require("src/notifications/sms");
|
||||||
|
|
||||||
const tmdbMovieInfo = id => {
|
const tmdbMovieInfo = id => {
|
||||||
return tmdb.movieInfo(id);
|
return tmdb.movieInfo(id);
|
||||||
@@ -47,9 +48,14 @@ 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, user_agent, username);
|
||||||
)
|
|
||||||
|
// TODO enable SMS
|
||||||
|
// const url = `https://request.movie?${tmdbMedia.type}=${tmdbMedia.id}`;
|
||||||
|
// const message = `${tmdbMedia.title} (${tmdbMedia.year}) requested!\n${url}`;
|
||||||
|
// sendSMS(message);
|
||||||
|
})
|
||||||
.then(() =>
|
.then(() =>
|
||||||
res.send({ success: true, message: "Request has been submitted." })
|
res.send({ success: true, message: "Request has been submitted." })
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,15 +11,16 @@ const searchHistory = new SearchHistory();
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function movieSearchController(req, res) {
|
function movieSearchController(req, res) {
|
||||||
const { query, page } = 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" ? true : false;
|
||||||
|
|
||||||
if (username) {
|
if (username) {
|
||||||
return searchHistory.create(username, query);
|
searchHistory.create(username, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmdb
|
return tmdb
|
||||||
.movieSearch(query, page)
|
.movieSearch(query, page, includeAdult)
|
||||||
.then(movieSearchResults => res.send(movieSearchResults))
|
.then(movieSearchResults => res.send(movieSearchResults))
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
const { status, message } = error;
|
const { status, message } = error;
|
||||||
|
|||||||
@@ -11,18 +11,17 @@ const searchHistory = new SearchHistory();
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function personSearchController(req, res) {
|
function personSearchController(req, res) {
|
||||||
const { query, page } = 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" ? true : false;
|
||||||
|
|
||||||
if (username) {
|
if (username) {
|
||||||
return searchHistory.create(username, query);
|
searchHistory.create(username, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmdb
|
return tmdb
|
||||||
.personSearch(query, page)
|
.personSearch(query, page, includeAdult)
|
||||||
.then(person => {
|
.then(persons => res.send(persons))
|
||||||
res.send(person);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
const { status, message } = error;
|
const { status, message } = error;
|
||||||
|
|
||||||
|
|||||||
@@ -11,17 +11,16 @@ const searchHistory = new SearchHistory();
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function showSearchController(req, res) {
|
function showSearchController(req, res) {
|
||||||
const { query, page } = 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" ? true : false;
|
||||||
|
|
||||||
Promise.resolve()
|
if (username) {
|
||||||
.then(() => {
|
searchHistory.create(username, query);
|
||||||
if (username) {
|
}
|
||||||
return searchHistory.create(username, query);
|
|
||||||
}
|
return tmdb
|
||||||
return null;
|
.showSearch(query, page, includeAdult)
|
||||||
})
|
|
||||||
.then(() => tmdb.showSearch(query, page))
|
|
||||||
.then(shows => {
|
.then(shows => {
|
||||||
res.send(shows);
|
res.send(shows);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,36 +1,61 @@
|
|||||||
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 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();
|
const userRepository = new UserRepository();
|
||||||
|
|
||||||
// TODO look to move some of the token generation out of the reach of the final "catch-all"
|
// TODO look to move some of the token generation out of the reach of the final "catch-all"
|
||||||
// catch including the, maybe sensitive, error message.
|
// catch including the, maybe sensitive, error message.
|
||||||
|
|
||||||
|
const isProduction = process.env.NODE_ENV === "production";
|
||||||
|
const cookieOptions = {
|
||||||
|
httpOnly: false,
|
||||||
|
secure: isProduction,
|
||||||
|
maxAge: 90 * 24 * 3600000, // 90 days
|
||||||
|
sameSite: isProduction ? "Strict" : "Lax"
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller: Log in a user provided correct credentials.
|
* Controller: Log in a user provided correct credentials.
|
||||||
* @param {Request} req http request variable
|
* @param {Request} req http request variable
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function loginController(req, res) {
|
async function loginController(req, res) {
|
||||||
const user = new User(req.body.username);
|
const user = new User(req.body.username);
|
||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
|
|
||||||
userSecurity.login(user, password)
|
try {
|
||||||
.then(() => userRepository.checkAdmin(user))
|
const [loggedIn, isAdmin, settings] = await Promise.all([
|
||||||
.then(checkAdmin => {
|
userSecurity.login(user, password),
|
||||||
const isAdmin = checkAdmin === 1 ? true : false;
|
userRepository.checkAdmin(user),
|
||||||
const token = new Token(user, isAdmin).toString(secret);
|
userRepository.getSettings(user.username)
|
||||||
res.send({ success: true, token });
|
]);
|
||||||
})
|
|
||||||
.catch(error => {
|
if (!loggedIn) {
|
||||||
res.status(401).send({ success: false, message: error.message });
|
return res.status(503).send({
|
||||||
|
success: false,
|
||||||
|
message: "Unexpected error! Unable to create user."
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = new Token(
|
||||||
|
user,
|
||||||
|
isAdmin === 1 ? true : false,
|
||||||
|
settings
|
||||||
|
).toString(secret);
|
||||||
|
|
||||||
|
return res.cookie("authorization", token, cookieOptions).status(200).send({
|
||||||
|
success: true,
|
||||||
|
message: "Welcome to request.movie!"
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(401).send({ success: false, message: error.message });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = loginController;
|
module.exports = loginController;
|
||||||
|
|||||||
16
seasoned_api/src/webserver/controllers/user/logout.js
Normal file
16
seasoned_api/src/webserver/controllers/user/logout.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Controller: Log out a user (destroy authorization token)
|
||||||
|
* @param {Request} req http request variable
|
||||||
|
* @param {Response} res
|
||||||
|
* @returns {Callback}
|
||||||
|
*/
|
||||||
|
async function logoutController(req, res) {
|
||||||
|
res.clearCookie("authorization");
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
success: true,
|
||||||
|
message: "Logged out, see you later!"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = logoutController;
|
||||||
@@ -1,13 +1,21 @@
|
|||||||
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 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();
|
const userRepository = new UserRepository();
|
||||||
|
|
||||||
|
const isProduction = process.env.NODE_ENV === "production";
|
||||||
|
const cookieOptions = {
|
||||||
|
httpOnly: false,
|
||||||
|
secure: isProduction,
|
||||||
|
maxAge: 90 * 24 * 3600000, // 90 days
|
||||||
|
sameSite: isProduction ? "Strict" : "Lax"
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller: Register a new user
|
* Controller: Register a new user
|
||||||
* @param {Request} req http request variable
|
* @param {Request} req http request variable
|
||||||
@@ -15,21 +23,25 @@ const userRepository = new UserRepository();
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function registerController(req, res) {
|
function registerController(req, res) {
|
||||||
const user = new User(req.body.username, req.body.email);
|
const user = new User(req.body.username, req.body.email);
|
||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
|
|
||||||
userSecurity.createNewUser(user, password)
|
userSecurity
|
||||||
.then(() => userRepository.checkAdmin(user))
|
.createNewUser(user, password)
|
||||||
.then(checkAdmin => {
|
.then(() => {
|
||||||
const isAdmin = checkAdmin === 1 ? true : false;
|
const token = new Token(user, false).toString(secret);
|
||||||
const token = new Token(user, isAdmin).toString(secret);
|
|
||||||
res.send({
|
return res
|
||||||
success: true, message: 'Welcome to Seasoned!', token
|
.cookie("authorization", token, cookieOptions)
|
||||||
});
|
.status(200)
|
||||||
})
|
.send({
|
||||||
.catch(error => {
|
success: true,
|
||||||
res.status(401).send({ success: false, message: error.message });
|
message: "Welcome to Seasoned!"
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
res.status(401).send({ success: false, message: error.message });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = registerController;
|
module.exports = registerController;
|
||||||
|
|||||||
@@ -1,47 +1,52 @@
|
|||||||
const configuration = require('src/config/configuration').getInstance();
|
const configuration = require("src/config/configuration").getInstance();
|
||||||
const Tautulli = require('src/tautulli/tautulli');
|
const Tautulli = require("src/tautulli/tautulli");
|
||||||
const apiKey = configuration.get('tautulli', 'apiKey');
|
const apiKey = configuration.get("tautulli", "apiKey");
|
||||||
const ip = configuration.get('tautulli', 'ip');
|
const ip = configuration.get("tautulli", "ip");
|
||||||
const port = configuration.get('tautulli', 'port');
|
const port = configuration.get("tautulli", "port");
|
||||||
const tautulli = new Tautulli(apiKey, ip, port);
|
const tautulli = new Tautulli(apiKey, ip, port);
|
||||||
|
|
||||||
function handleError(error, res) {
|
function handleError(error, res) {
|
||||||
const { status, message } = error;
|
const { status, message } = error;
|
||||||
|
|
||||||
if (status && message) {
|
if (status && message) {
|
||||||
res.status(status).send({ success: false, message })
|
return res.status(status).send({ success: false, message });
|
||||||
} else {
|
} else {
|
||||||
console.log('caught view history controller error', error)
|
console.log("caught view history controller error", error);
|
||||||
res.status(500).send({ message: 'An unexpected error occured while fetching view history'})
|
return res.status(500).send({
|
||||||
|
message: "An unexpected error occured while fetching view history"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function watchTimeStatsController(req, res) {
|
function watchTimeStatsController(req, res) {
|
||||||
const user = req.loggedInUser;
|
const user = req.loggedInUser;
|
||||||
|
|
||||||
tautulli.watchTimeStats(user.plex_userid)
|
return tautulli
|
||||||
|
.watchTimeStats(user.plex_userid)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log('data', data, JSON.stringify(data.response.data))
|
|
||||||
|
|
||||||
return res.send({
|
return res.send({
|
||||||
success: true,
|
success: true,
|
||||||
data: data.response.data,
|
data: data.response.data,
|
||||||
message: 'watch time successfully fetched from tautulli'
|
message: "watch time successfully fetched from tautulli"
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
|
.catch(error => handleError(error, 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, y_axis } = req.query;
|
||||||
|
|
||||||
tautulli.getPlaysByDayOfWeek(user.plex_userid, days, y_axis)
|
return tautulli
|
||||||
.then(data => res.send({
|
.getPlaysByDayOfWeek(user.plex_userid, days, y_axis)
|
||||||
success: true,
|
.then(data =>
|
||||||
data: data.response.data,
|
res.send({
|
||||||
message: 'play by day of week successfully fetched from tautulli'
|
success: true,
|
||||||
})
|
data: data.response.data,
|
||||||
|
message: "play by day of week successfully fetched from tautulli"
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
.catch(error => handleError(error, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPlaysByDaysController(req, res) {
|
function getPlaysByDaysController(req, res) {
|
||||||
@@ -52,49 +57,46 @@ function getPlaysByDaysController(req, res) {
|
|||||||
return res.status(422).send({
|
return res.status(422).send({
|
||||||
success: false,
|
success: false,
|
||||||
message: "Missing parameter: days (number)"
|
message: "Missing parameter: days (number)"
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const allowedYAxisDataType = ['plays', 'duration'];
|
const allowedYAxisDataType = ["plays", "duration"];
|
||||||
if (!allowedYAxisDataType.includes(y_axis)) {
|
if (!allowedYAxisDataType.includes(y_axis)) {
|
||||||
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}]`
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tautulli.getPlaysByDays(user.plex_userid, days, y_axis)
|
return tautulli
|
||||||
.then(data => res.send({
|
.getPlaysByDays(user.plex_userid, days, y_axis)
|
||||||
|
.then(data =>
|
||||||
|
res.send({
|
||||||
success: true,
|
success: true,
|
||||||
data: data.response.data
|
data: data.response.data
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
|
.catch(error => handleError(error, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function userViewHistoryController(req, res) {
|
function userViewHistoryController(req, res) {
|
||||||
const user = req.loggedInUser;
|
const user = req.loggedInUser;
|
||||||
|
|
||||||
console.log('user', user)
|
// TODO here we should check if we can init tau
|
||||||
|
// and then return 501 Not implemented
|
||||||
|
|
||||||
|
return tautulli
|
||||||
|
.viewHistory(user.plex_userid)
|
||||||
|
.then(data => {
|
||||||
|
return res.send({
|
||||||
|
success: true,
|
||||||
|
data: data.response.data.data,
|
||||||
|
message: "view history successfully fetched from tautulli"
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => handleError(error, res));
|
||||||
|
|
||||||
// TODO here we should check if we can init tau
|
// const username = user.username;
|
||||||
// and then return 501 Not implemented
|
|
||||||
|
|
||||||
tautulli.viewHistory(user.plex_userid)
|
|
||||||
.then(data => {
|
|
||||||
console.log('data', data, JSON.stringify(data.response.data.data))
|
|
||||||
|
|
||||||
|
|
||||||
return res.send({
|
|
||||||
success: true,
|
|
||||||
data: data.response.data.data,
|
|
||||||
message: 'view history successfully fetched from tautulli'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(error => handleError(error))
|
|
||||||
|
|
||||||
|
|
||||||
// const username = user.username;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
const mustBeAuthenticated = (req, res, next) => {
|
const mustBeAuthenticated = (req, res, next) => {
|
||||||
if (req.loggedInUser === undefined) {
|
if (req.loggedInUser === undefined) {
|
||||||
return res.status(401).send({
|
return res.status(401).send({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'You must be logged in.',
|
message: "You must be logged in."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return next();
|
return next();
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = mustBeAuthenticated;
|
module.exports = mustBeAuthenticated;
|
||||||
|
|||||||
32
seasoned_api/src/webserver/middleware/reqTokenToUser.js
Normal file
32
seasoned_api/src/webserver/middleware/reqTokenToUser.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
const configuration = require("src/config/configuration").getInstance();
|
||||||
|
const Token = require("src/user/token");
|
||||||
|
|
||||||
|
const secret = configuration.get("authentication", "secret");
|
||||||
|
|
||||||
|
// Token example:
|
||||||
|
// curl -i -H "Authorization:[token]" localhost:31459/api/v1/user/history
|
||||||
|
|
||||||
|
const reqTokenToUser = (req, res, next) => {
|
||||||
|
const cookieAuthToken = req.cookies.authorization;
|
||||||
|
const headerAuthToken = req.headers.authorization;
|
||||||
|
|
||||||
|
if (cookieAuthToken || headerAuthToken) {
|
||||||
|
try {
|
||||||
|
const token = Token.fromString(
|
||||||
|
cookieAuthToken || headerAuthToken,
|
||||||
|
secret
|
||||||
|
);
|
||||||
|
req.loggedInUser = token.user;
|
||||||
|
} catch (error) {
|
||||||
|
req.loggedInUser = undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// guest session
|
||||||
|
console.debug("No auth token in header or cookie.");
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = reqTokenToUser;
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
|
||||||
const configuration = require('src/config/configuration').getInstance();
|
|
||||||
|
|
||||||
const secret = configuration.get('authentication', 'secret');
|
|
||||||
const Token = require('src/user/token');
|
|
||||||
|
|
||||||
// Token example:
|
|
||||||
// curl -i -H "Authorization:[token]" localhost:31459/api/v1/user/history
|
|
||||||
|
|
||||||
const tokenToUser = (req, res, next) => {
|
|
||||||
const rawToken = req.headers.authorization;
|
|
||||||
if (rawToken) {
|
|
||||||
try {
|
|
||||||
const token = Token.fromString(rawToken, secret);
|
|
||||||
req.loggedInUser = token.user;
|
|
||||||
} catch (error) {
|
|
||||||
req.loggedInUser = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = tokenToUser;
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user