Created endpoint for authenticating with plex and linking your plex user to the logged in seasoned user. User database table gets a new plex_userid column. This will be used to fetch tautulli stats for your account.
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
CREATE TABLE IF NOT EXISTS user (
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
user_name varchar(127) UNIQUE,
|
user_name varchar(127) UNIQUE,
|
||||||
password varchar(127),
|
password varchar(127),
|
||||||
email varchar(127) UNIQUE,
|
|
||||||
admin boolean DEFAULT 0,
|
admin boolean DEFAULT 0,
|
||||||
|
email varchar(127) UNIQUE,
|
||||||
|
plex_userid varchar(127) DEFAULT NULL,
|
||||||
primary key (user_name)
|
primary key (user_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ class UserRepository {
|
|||||||
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 user set plex_userid = ? where user_name = ?'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,8 +20,7 @@ class UserRepository {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
create(user) {
|
create(user) {
|
||||||
return Promise.resolve()
|
return this.database.get(this.queries.read, user.username)
|
||||||
.then(() => 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 (error.name === 'AssertionError' || error.message.endsWith('user_name')) {
|
||||||
@@ -36,13 +36,13 @@ class UserRepository {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
retrieveHash(user) {
|
retrieveHash(user) {
|
||||||
return Promise.resolve()
|
console.log('retrieving hash for user', user)
|
||||||
.then(() => 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.'); })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,7 +52,30 @@ class UserRepository {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
changePassword(user, password) {
|
changePassword(user, password) {
|
||||||
return Promise.resolve(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
|
||||||
|
* @param {User} user the user you want to lunk plex userid with
|
||||||
|
* @param {Number} plexUserID plex unique id
|
||||||
|
* @returns {Promsie}
|
||||||
|
*/
|
||||||
|
linkPlexUserId(username, plexUserID) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.database.run(this.queries.link, [plexUserID, username])
|
||||||
|
.then(row => resolve(row))
|
||||||
|
.catch(error => {
|
||||||
|
// TODO log this unknown db error
|
||||||
|
console.log('db error', error)
|
||||||
|
|
||||||
|
reject({
|
||||||
|
status: 500,
|
||||||
|
message: 'An unexpected error occured while linking plex and seasoned accounts',
|
||||||
|
source: 'seasoned database'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAdmin(user) {
|
checkAdmin(user) {
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ router.post('/v1/user', require('./controllers/user/register.js'));
|
|||||||
router.post('/v1/user/login', require('./controllers/user/login.js'));
|
router.post('/v1/user/login', require('./controllers/user/login.js'));
|
||||||
router.get('/v1/user/history', mustBeAuthenticated, require('./controllers/user/history.js'));
|
router.get('/v1/user/history', mustBeAuthenticated, require('./controllers/user/history.js'));
|
||||||
router.get('/v1/user/requests', mustBeAuthenticated, require('./controllers/user/requests.js'));
|
router.get('/v1/user/requests', mustBeAuthenticated, require('./controllers/user/requests.js'));
|
||||||
|
router.post('/v1/user/authenticate', mustBeAuthenticated, require('./controllers/user/authenticatePlexAccount.js'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seasoned
|
* Seasoned
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
const UserRepository = require('src/user/userRepository');
|
||||||
|
const userRepository = new UserRepository();
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
const FormData = require('form-data');
|
||||||
|
|
||||||
|
function handleError(error, res) {
|
||||||
|
let { status, message, source } = error;
|
||||||
|
|
||||||
|
if (status && message) {
|
||||||
|
if (status === 401) {
|
||||||
|
message = 'Unauthorized. Please check plex credentials.',
|
||||||
|
source = 'plex'
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(status).send({ success: false, message, source })
|
||||||
|
} else {
|
||||||
|
console.log('caught authenticate plex account controller error', error)
|
||||||
|
res.status(500).send({
|
||||||
|
message: 'An unexpected error occured while authenticating your account with plex',
|
||||||
|
source
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleResponse(response) {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw {
|
||||||
|
success: false,
|
||||||
|
status: response.status,
|
||||||
|
message: response.statusText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
function plexAuthenticate(username, password) {
|
||||||
|
const url = 'https://plex.tv/api/v2/users/signin'
|
||||||
|
|
||||||
|
const form = new FormData()
|
||||||
|
form.append('login', username)
|
||||||
|
form.append('password', password)
|
||||||
|
form.append('rememberMe', 'false')
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
'Accept': 'application/json, text/plain, */*',
|
||||||
|
'Content-Type': form.getHeaders()['content-type'],
|
||||||
|
'X-Plex-Client-Identifier': 'seasonedRequest'
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers,
|
||||||
|
body: form
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(url, options)
|
||||||
|
.then(resp => handleResponse(resp))
|
||||||
|
}
|
||||||
|
|
||||||
|
function authenticatePlexAccountController(req, res) {
|
||||||
|
const user = req.loggedInUser;
|
||||||
|
const { username, password } = req.body;
|
||||||
|
|
||||||
|
return plexAuthenticate(username, password)
|
||||||
|
.then(plexUser => userRepository.linkPlexUserId(user.username, plexUser.id))
|
||||||
|
.then(response => res.send({
|
||||||
|
success: true,
|
||||||
|
message: "Successfully authenticated and linked plex account with seasoned request."
|
||||||
|
}))
|
||||||
|
.catch(error => handleError(error, res))
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = authenticatePlexAccountController;
|
||||||
Reference in New Issue
Block a user