mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-08 00:08:14 +01:00
Editing accounts, change root account username, removed token expiration
This commit is contained in:
parent
838d188504
commit
4f094df0b2
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<modals-modal v-model="show" :width="800" :height="500" :processing="processing">
|
<modals-modal v-model="show" :width="800" :height="'unset'" :processing="processing">
|
||||||
<template #outer>
|
<template #outer>
|
||||||
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
|
||||||
<p class="font-book text-3xl text-white truncate">{{ title }}</p>
|
<p class="font-book text-3xl text-white truncate">{{ title }}</p>
|
||||||
@ -8,18 +8,22 @@
|
|||||||
<form @submit.prevent="submitForm">
|
<form @submit.prevent="submitForm">
|
||||||
<div class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
|
<div class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
|
||||||
<div class="w-full p-8">
|
<div class="w-full p-8">
|
||||||
<div class="flex py-2">
|
<div class="flex py-2 -mx-2">
|
||||||
|
<div class="w-1/2 px-2">
|
||||||
<ui-text-input-with-label v-model="newUser.username" label="Username" class="mx-2" />
|
<ui-text-input-with-label v-model="newUser.username" label="Username" class="mx-2" />
|
||||||
<ui-text-input-with-label v-model="newUser.password" label="Password" type="password" class="mx-2" />
|
</div>
|
||||||
|
<div class="w-1/2 px-2">
|
||||||
|
<ui-text-input-with-label v-if="!isEditingRoot" v-model="newUser.password" :label="isNew ? 'Password' : 'Change Password'" type="password" class="mx-2" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex py-2">
|
<div class="flex py-2">
|
||||||
<div class="px-2">
|
<div class="px-2">
|
||||||
<ui-input-dropdown v-model="newUser.type" label="Account Type" :editable="false" :items="accountTypes" />
|
<ui-input-dropdown v-model="newUser.type" label="Account Type" :disabled="isEditingRoot" :editable="false" :items="accountTypes" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow" />
|
<div class="flex-grow" />
|
||||||
<div class="flex items-center pt-4 px-2">
|
<div v-show="!isEditingRoot" class="flex items-center pt-4 px-2">
|
||||||
<p class="px-3 font-semibold">Is Active</p>
|
<p class="px-3 font-semibold" :class="isEditingRoot ? 'text-gray-300' : ''">Is Active</p>
|
||||||
<ui-toggle-switch v-model="newUser.isActive" />
|
<ui-toggle-switch v-model="newUser.isActive" :disabled="isEditingRoot" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex pt-4">
|
<div class="flex pt-4">
|
||||||
@ -68,7 +72,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
title() {
|
title() {
|
||||||
return this.isNew ? 'Add New Account' : `Update "${(this.account || {}).username}" Account`
|
return this.isNew ? 'Add New Account' : `Update Account: ${(this.account || {}).username}`
|
||||||
|
},
|
||||||
|
isEditingRoot() {
|
||||||
|
return this.account && this.account.type === 'root'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -77,6 +84,39 @@ export default {
|
|||||||
this.$toast.error('Enter a username')
|
this.$toast.error('Enter a username')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isNew) {
|
||||||
|
this.submitCreateAccount()
|
||||||
|
} else {
|
||||||
|
this.submitUpdateAccount()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
submitUpdateAccount() {
|
||||||
|
var account = { ...this.newUser }
|
||||||
|
if (!account.password || account.type === 'root') {
|
||||||
|
delete account.password
|
||||||
|
}
|
||||||
|
if (account.type === 'root' && !account.isActive) return
|
||||||
|
|
||||||
|
this.processing = true
|
||||||
|
this.$axios
|
||||||
|
.$patch(`/api/user/${this.account.id}`, account)
|
||||||
|
.then((data) => {
|
||||||
|
this.processing = false
|
||||||
|
if (data.error) {
|
||||||
|
this.$toast.error(`Failed to update account: ${data.error}`)
|
||||||
|
} else {
|
||||||
|
this.$toast.success('Account updated')
|
||||||
|
this.show = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to update account', error)
|
||||||
|
this.processing = false
|
||||||
|
this.$toast.error('Failed to update account')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
submitCreateAccount() {
|
||||||
if (!this.newUser.password) {
|
if (!this.newUser.password) {
|
||||||
this.$toast.error('Must have a password, only root user can have an empty password')
|
this.$toast.error('Must have a password, only root user can have an empty password')
|
||||||
return
|
return
|
||||||
@ -84,7 +124,6 @@ export default {
|
|||||||
|
|
||||||
var account = { ...this.newUser }
|
var account = { ...this.newUser }
|
||||||
this.processing = true
|
this.processing = true
|
||||||
if (this.isNew) {
|
|
||||||
this.$axios
|
this.$axios
|
||||||
.$post('/api/user', account)
|
.$post('/api/user', account)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
@ -92,7 +131,6 @@ export default {
|
|||||||
if (data.error) {
|
if (data.error) {
|
||||||
this.$toast.error(`Failed to create account: ${data.error}`)
|
this.$toast.error(`Failed to create account: ${data.error}`)
|
||||||
} else {
|
} else {
|
||||||
console.log('New Account:', data.user)
|
|
||||||
this.$toast.success('New account created')
|
this.$toast.success('New account created')
|
||||||
this.show = false
|
this.show = false
|
||||||
}
|
}
|
||||||
@ -100,9 +138,8 @@ export default {
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Failed to create account', error)
|
console.error('Failed to create account', error)
|
||||||
this.processing = false
|
this.processing = false
|
||||||
this.$toast.success('New account created')
|
this.$toast.error('Failed to create account')
|
||||||
})
|
})
|
||||||
}
|
|
||||||
},
|
},
|
||||||
toggleActive() {
|
toggleActive() {
|
||||||
this.newUser.isActive = !this.newUser.isActive
|
this.newUser.isActive = !this.newUser.isActive
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full">
|
<div class="w-full" :class="disabled ? 'cursor-not-allowed' : ''">
|
||||||
<p class="px-1 text-sm font-semibold">{{ label }}</p>
|
<p class="px-1 text-sm font-semibold" :class="disabled ? 'text-gray-300' : ''">{{ label }}</p>
|
||||||
<div ref="wrapper" class="relative">
|
<div ref="wrapper" class="relative">
|
||||||
<form @submit.prevent="submitForm">
|
<form @submit.prevent="submitForm">
|
||||||
<div ref="inputWrapper" class="flex-wrap relative w-full shadow-sm flex items-center bg-primary border border-gray-600 rounded px-2 py-2">
|
<div ref="inputWrapper" class="flex-wrap relative w-full shadow-sm flex items-center border border-gray-600 rounded px-2 py-2" :class="disabled ? 'bg-bg pointer-events-none text-gray-400' : 'bg-primary'">
|
||||||
<input ref="input" v-model="textInput" :readonly="!editable" class="h-full w-full bg-primary focus:outline-none px-1" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" />
|
<input ref="input" v-model="textInput" :disabled="disabled" :readonly="!editable" class="h-full w-full bg-transparent focus:outline-none px-1" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@ -33,6 +33,7 @@
|
|||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: [String, Number],
|
value: [String, Number],
|
||||||
|
disabled: Boolean,
|
||||||
label: String,
|
label: String,
|
||||||
items: {
|
items: {
|
||||||
type: Array,
|
type: Array,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="border rounded-full border-black-100 flex items-center cursor-pointer w-12 justify-end" :class="toggleColor" @click="clickToggle">
|
<div class="border rounded-full border-black-100 flex items-center cursor-pointer w-12 justify-start" :class="className" @click="clickToggle">
|
||||||
<span class="rounded-full border w-6 h-6 border-black-50 bg-white shadow transform transition-transform duration-100" :class="!toggleValue ? '-translate-x-6' : ''"> </span>
|
<span class="rounded-full border w-6 h-6 border-black-50 shadow transform transition-transform duration-100" :class="switchClassName"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -17,7 +17,8 @@ export default {
|
|||||||
offColor: {
|
offColor: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'primary'
|
default: 'primary'
|
||||||
}
|
},
|
||||||
|
disabled: Boolean
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
toggleValue: {
|
toggleValue: {
|
||||||
@ -28,12 +29,18 @@ export default {
|
|||||||
this.$emit('input', val)
|
this.$emit('input', val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleColor() {
|
className() {
|
||||||
|
if (this.disabled) return 'bg-bg cursor-not-allowed'
|
||||||
return this.toggleValue ? `bg-${this.onColor}` : `bg-${this.offColor}`
|
return this.toggleValue ? `bg-${this.onColor}` : `bg-${this.offColor}`
|
||||||
|
},
|
||||||
|
switchClassName() {
|
||||||
|
var bgColor = this.disabled ? 'bg-gray-300' : 'bg-white'
|
||||||
|
return this.toggleValue ? 'translate-x-6 ' + bgColor : bgColor
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
clickToggle() {
|
clickToggle() {
|
||||||
|
if (this.disabled) return
|
||||||
this.toggleValue = !this.toggleValue
|
this.toggleValue = !this.toggleValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"description": "Audiobook manager and player",
|
"description": "Audiobook manager and player",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="w-full flex justify-center">
|
<div class="w-full flex justify-center">
|
||||||
|
<span class="material-icons hover:text-gray-400 cursor-pointer text-base pr-2" @click="editUser(user)">edit</span>
|
||||||
<span v-show="user.type !== 'root'" class="material-icons text-base hover:text-error cursor-pointer" @click="deleteUserClick(user)">delete</span>
|
<span v-show="user.type !== 'root'" class="material-icons text-base hover:text-error cursor-pointer" @click="deleteUserClick(user)">delete</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -76,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="fixed bottom-0 left-0 w-10 h-10" @dblclick="setDeveloperMode"></div>
|
<div class="fixed bottom-0 left-0 w-10 h-10" @dblclick="setDeveloperMode"></div>
|
||||||
|
|
||||||
<modals-account-modal v-model="showAccountModal" />
|
<modals-account-modal v-model="showAccountModal" :account="selectedAccount" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -91,6 +92,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
isResettingAudiobooks: false,
|
isResettingAudiobooks: false,
|
||||||
users: [],
|
users: [],
|
||||||
|
selectedAccount: null,
|
||||||
showAccountModal: false,
|
showAccountModal: false,
|
||||||
isDeletingUser: false,
|
isDeletingUser: false,
|
||||||
newServerSettings: {}
|
newServerSettings: {}
|
||||||
@ -145,10 +147,6 @@ export default {
|
|||||||
scanCovers() {
|
scanCovers() {
|
||||||
this.$root.socket.emit('scan_covers')
|
this.$root.socket.emit('scan_covers')
|
||||||
},
|
},
|
||||||
clickAddUser() {
|
|
||||||
this.showAccountModal = true
|
|
||||||
// this.$toast.info('Under Construction: User management coming soon.')
|
|
||||||
},
|
|
||||||
loadUsers() {
|
loadUsers() {
|
||||||
this.$axios
|
this.$axios
|
||||||
.$get('/api/users')
|
.$get('/api/users')
|
||||||
@ -175,6 +173,14 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
clickAddUser() {
|
||||||
|
this.selectedAccount = null
|
||||||
|
this.showAccountModal = true
|
||||||
|
},
|
||||||
|
editUser(user) {
|
||||||
|
this.selectedAccount = user
|
||||||
|
this.showAccountModal = true
|
||||||
|
},
|
||||||
deleteUserClick(user) {
|
deleteUserClick(user) {
|
||||||
if (this.isDeletingUser) return
|
if (this.isDeletingUser) return
|
||||||
if (confirm(`Are you sure you want to permanently delete user "${user.username}"?`)) {
|
if (confirm(`Are you sure you want to permanently delete user "${user.username}"?`)) {
|
||||||
@ -198,7 +204,7 @@ export default {
|
|||||||
},
|
},
|
||||||
addUpdateUser(user) {
|
addUpdateUser(user) {
|
||||||
if (!this.users) return
|
if (!this.users) return
|
||||||
var index = this.users.find((u) => u.id === user.id)
|
var index = this.users.findIndex((u) => u.id === user.id)
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
this.users.splice(index, 1, user)
|
this.users.splice(index, 1, user)
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,7 +27,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
error: null,
|
error: null,
|
||||||
processing: false,
|
processing: false,
|
||||||
username: 'root',
|
username: '',
|
||||||
password: null
|
password: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
export default function ({ $axios, store }) {
|
export default function ({ $axios, store }) {
|
||||||
$axios.onRequest(config => {
|
$axios.onRequest(config => {
|
||||||
// console.log('Making request to ' + config.url)
|
|
||||||
if (config.url.startsWith('http:') || config.url.startsWith('https:')) {
|
if (config.url.startsWith('http:') || config.url.startsWith('https:')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -11,6 +10,7 @@ export default function ({ $axios, store }) {
|
|||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
config.url = `/dev${config.url}`
|
config.url = `/dev${config.url}`
|
||||||
|
console.log('Making request to ' + config.url)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"description": "Self-hosted audiobook server for managing and playing audiobooks.",
|
"description": "Self-hosted audiobook server for managing and playing audiobooks.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -4,7 +4,7 @@ const User = require('./objects/User')
|
|||||||
const { isObject } = require('./utils/index')
|
const { isObject } = require('./utils/index')
|
||||||
|
|
||||||
class ApiController {
|
class ApiController {
|
||||||
constructor(db, scanner, auth, streamManager, rssFeeds, downloadManager, emitter) {
|
constructor(db, scanner, auth, streamManager, rssFeeds, downloadManager, emitter, clientEmitter) {
|
||||||
this.db = db
|
this.db = db
|
||||||
this.scanner = scanner
|
this.scanner = scanner
|
||||||
this.auth = auth
|
this.auth = auth
|
||||||
@ -12,6 +12,7 @@ class ApiController {
|
|||||||
this.rssFeeds = rssFeeds
|
this.rssFeeds = rssFeeds
|
||||||
this.downloadManager = downloadManager
|
this.downloadManager = downloadManager
|
||||||
this.emitter = emitter
|
this.emitter = emitter
|
||||||
|
this.clientEmitter = clientEmitter
|
||||||
|
|
||||||
this.router = express()
|
this.router = express()
|
||||||
this.init()
|
this.init()
|
||||||
@ -34,12 +35,13 @@ class ApiController {
|
|||||||
this.router.get('/metadata/:id/:trackIndex', this.getMetadata.bind(this))
|
this.router.get('/metadata/:id/:trackIndex', this.getMetadata.bind(this))
|
||||||
this.router.patch('/match/:id', this.match.bind(this))
|
this.router.patch('/match/:id', this.match.bind(this))
|
||||||
|
|
||||||
this.router.get('/users', this.getUsers.bind(this))
|
|
||||||
this.router.post('/user', this.createUser.bind(this))
|
|
||||||
this.router.delete('/user/:id', this.deleteUser.bind(this))
|
|
||||||
this.router.delete('/user/audiobook/:id', this.resetUserAudiobookProgress.bind(this))
|
this.router.delete('/user/audiobook/:id', this.resetUserAudiobookProgress.bind(this))
|
||||||
this.router.patch('/user/password', this.userChangePassword.bind(this))
|
this.router.patch('/user/password', this.userChangePassword.bind(this))
|
||||||
this.router.patch('/user/settings', this.userUpdateSettings.bind(this))
|
this.router.patch('/user/settings', this.userUpdateSettings.bind(this))
|
||||||
|
this.router.get('/users', this.getUsers.bind(this))
|
||||||
|
this.router.post('/user', this.createUser.bind(this))
|
||||||
|
this.router.patch('/user/:id', this.updateUser.bind(this))
|
||||||
|
this.router.delete('/user/:id', this.deleteUser.bind(this))
|
||||||
|
|
||||||
this.router.patch('/serverSettings', this.updateServerSettings.bind(this))
|
this.router.patch('/serverSettings', this.updateServerSettings.bind(this))
|
||||||
|
|
||||||
@ -273,7 +275,7 @@ class ApiController {
|
|||||||
var newUser = new User(account)
|
var newUser = new User(account)
|
||||||
var success = await this.db.insertUser(newUser)
|
var success = await this.db.insertUser(newUser)
|
||||||
if (success) {
|
if (success) {
|
||||||
this.emitter('user_added', newUser)
|
this.clientEmitter(req.user.id, 'user_added', newUser)
|
||||||
res.json({
|
res.json({
|
||||||
user: newUser.toJSONForBrowser()
|
user: newUser.toJSONForBrowser()
|
||||||
})
|
})
|
||||||
@ -284,6 +286,36 @@ class ApiController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateUser(req, res) {
|
||||||
|
if (req.user.type !== 'root') {
|
||||||
|
Logger.error('User other than root attempting to update user', req.user)
|
||||||
|
return res.sendStatus(403)
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = this.db.users.find(u => u.id === req.params.id)
|
||||||
|
if (!user) {
|
||||||
|
return res.sendStatus(404)
|
||||||
|
}
|
||||||
|
|
||||||
|
var account = req.body
|
||||||
|
// Updating password
|
||||||
|
if (account.password) {
|
||||||
|
account.pash = await this.auth.hashPass(account.password)
|
||||||
|
delete account.password
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasUpdated = user.update(account)
|
||||||
|
if (hasUpdated) {
|
||||||
|
await this.db.updateEntity('user', user)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clientEmitter(req.user.id, 'user_updated', user.toJSONForBrowser())
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
user: user.toJSONForBrowser()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async deleteUser(req, res) {
|
async deleteUser(req, res) {
|
||||||
if (req.params.id === 'root') {
|
if (req.params.id === 'root') {
|
||||||
return res.sendStatus(500)
|
return res.sendStatus(500)
|
||||||
@ -304,7 +336,7 @@ class ApiController {
|
|||||||
|
|
||||||
var userJson = user.toJSONForBrowser()
|
var userJson = user.toJSONForBrowser()
|
||||||
await this.db.removeEntity('user', user.id)
|
await this.db.removeEntity('user', user.id)
|
||||||
this.emitter('user_removed', userJson)
|
this.clientEmitter(req.user.id, 'user_removed', userJson)
|
||||||
res.json({
|
res.json({
|
||||||
success: true
|
success: true
|
||||||
})
|
})
|
||||||
|
@ -68,7 +68,7 @@ class Auth {
|
|||||||
}
|
}
|
||||||
|
|
||||||
generateAccessToken(payload) {
|
generateAccessToken(payload) {
|
||||||
return jwt.sign(payload, process.env.TOKEN_SECRET, { expiresIn: '1800s' });
|
return jwt.sign(payload, process.env.TOKEN_SECRET);
|
||||||
}
|
}
|
||||||
|
|
||||||
verifyToken(token) {
|
verifyToken(token) {
|
||||||
|
@ -94,7 +94,7 @@ class Db {
|
|||||||
}
|
}
|
||||||
|
|
||||||
insertSettings(settings) {
|
insertSettings(settings) {
|
||||||
return this.settingsDb.insert(settings).then((results) => {
|
return this.settingsDb.insert([settings]).then((results) => {
|
||||||
Logger.debug(`[DB] Inserted ${results.inserted} settings`)
|
Logger.debug(`[DB] Inserted ${results.inserted} settings`)
|
||||||
this.settings = this.settings.concat(settings)
|
this.settings = this.settings.concat(settings)
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
|
@ -34,7 +34,7 @@ class Server {
|
|||||||
this.streamManager = new StreamManager(this.db, this.MetadataPath)
|
this.streamManager = new StreamManager(this.db, this.MetadataPath)
|
||||||
this.rssFeeds = new RssFeeds(this.Port, this.db)
|
this.rssFeeds = new RssFeeds(this.Port, this.db)
|
||||||
this.downloadManager = new DownloadManager(this.db, this.MetadataPath, this.emitter.bind(this))
|
this.downloadManager = new DownloadManager(this.db, this.MetadataPath, this.emitter.bind(this))
|
||||||
this.apiController = new ApiController(this.db, this.scanner, this.auth, this.streamManager, this.rssFeeds, this.downloadManager, this.emitter.bind(this))
|
this.apiController = new ApiController(this.db, this.scanner, this.auth, this.streamManager, this.rssFeeds, this.downloadManager, this.emitter.bind(this), this.clientEmitter.bind(this))
|
||||||
this.hlsController = new HlsController(this.db, this.scanner, this.auth, this.streamManager, this.emitter.bind(this), this.MetadataPath)
|
this.hlsController = new HlsController(this.db, this.scanner, this.auth, this.streamManager, this.emitter.bind(this), this.MetadataPath)
|
||||||
|
|
||||||
this.server = null
|
this.server = null
|
||||||
@ -54,11 +54,27 @@ class Server {
|
|||||||
return this.db.serverSettings
|
return this.db.serverSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getClientsForUser(userId) {
|
||||||
|
return Object.values(this.clients).filter(c => c.user && c.user.id === userId)
|
||||||
|
}
|
||||||
|
|
||||||
emitter(ev, data) {
|
emitter(ev, data) {
|
||||||
// Logger.debug('EMITTER', ev)
|
// Logger.debug('EMITTER', ev)
|
||||||
this.io.emit(ev, data)
|
this.io.emit(ev, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clientEmitter(userId, ev, data) {
|
||||||
|
var clients = this.getClientsForUser(userId)
|
||||||
|
if (!clients.length) {
|
||||||
|
return Logger.error(`[Server] clientEmitter - no clients found for user ${userId}`)
|
||||||
|
}
|
||||||
|
clients.forEach((client) => {
|
||||||
|
if (client.socket) {
|
||||||
|
client.socket.emit(ev, data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async fileAddedUpdated({ path, fullPath }) { }
|
async fileAddedUpdated({ path, fullPath }) { }
|
||||||
async fileRemoved({ path, fullPath }) { }
|
async fileRemoved({ path, fullPath }) { }
|
||||||
|
|
||||||
|
@ -68,6 +68,22 @@ class User {
|
|||||||
this.settings = user.settings || this.getDefaultUserSettings()
|
this.settings = user.settings || this.getDefaultUserSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update(payload) {
|
||||||
|
var hasUpdates = false
|
||||||
|
const keysToCheck = ['pash', 'type', 'username', 'isActive']
|
||||||
|
keysToCheck.forEach((key) => {
|
||||||
|
if (payload[key] !== undefined) {
|
||||||
|
if (key === 'isActive' || payload[key]) { // pash, type, username must evaluate to true (cannot be null or empty)
|
||||||
|
if (payload[key] !== this[key]) {
|
||||||
|
hasUpdates = true
|
||||||
|
this[key] = payload[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return hasUpdates
|
||||||
|
}
|
||||||
|
|
||||||
updateAudiobookProgress(stream) {
|
updateAudiobookProgress(stream) {
|
||||||
if (!this.audiobooks) this.audiobooks = {}
|
if (!this.audiobooks) this.audiobooks = {}
|
||||||
if (!this.audiobooks[stream.audiobookId]) {
|
if (!this.audiobooks[stream.audiobookId]) {
|
||||||
|
Loading…
Reference in New Issue
Block a user