mirror of
https://github.com/gotson/komga.git
synced 2025-12-16 13:33:49 +01:00
feat(webui): edit user restrictions
This commit is contained in:
parent
093610e186
commit
37dfa923e9
13 changed files with 331 additions and 155 deletions
|
|
@ -33,6 +33,7 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import {ERROR} from '@/types/events'
|
||||
import { AuthenticationActivityDto } from '@/types/komga-users'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'AuthenticationActivityTable',
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@
|
|||
<v-list-item-action>
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-btn icon @click="editSharedLibraries(u)" :disabled="u.roles.includes(UserRoles.ADMIN)"
|
||||
<v-btn icon @click="editRestrictions(u)" :disabled="u.roles.includes(UserRoles.ADMIN)"
|
||||
v-on="on">
|
||||
<v-icon>mdi-book-lock</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>{{ $t('settings_user.edit_shared_libraries') }}</span>
|
||||
<span>{{ $t('settings_user.edit_restrictions') }}</span>
|
||||
</v-tooltip>
|
||||
</v-list-item-action>
|
||||
|
||||
|
|
@ -93,8 +93,8 @@
|
|||
<v-icon>mdi-plus</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<user-shared-libraries-edit-dialog v-model="modalEditSharedLibraries"
|
||||
:user="userToEditSharedLibraries"
|
||||
<user-restrictions-edit-dialog v-model="modalEditRestrictions"
|
||||
:user="userToEditRestrictions"
|
||||
/>
|
||||
|
||||
<password-change-dialog v-model="modalChangePassword"
|
||||
|
|
@ -121,18 +121,19 @@
|
|||
|
||||
<script lang="ts">
|
||||
import UserEditDialog from '@/components/dialogs/UserEditDialog.vue'
|
||||
import UserSharedLibrariesEditDialog from '@/components/dialogs/UserSharedLibrariesEditDialog.vue'
|
||||
import UserRestrictionsEditDialog from '@/components/dialogs/UserRestrictionsEditDialog.vue'
|
||||
import {UserRoles} from '@/types/enum-users'
|
||||
import Vue from 'vue'
|
||||
import PasswordChangeDialog from '@/components/dialogs/PasswordChangeDialog.vue'
|
||||
import {ERROR} from '@/types/events'
|
||||
import ConfirmationDialog from '@/components/dialogs/ConfirmationDialog.vue'
|
||||
import { UserDto } from '@/types/komga-users'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'UsersList',
|
||||
components: {
|
||||
ConfirmationDialog,
|
||||
UserSharedLibrariesEditDialog,
|
||||
UserRestrictionsEditDialog,
|
||||
UserEditDialog,
|
||||
PasswordChangeDialog,
|
||||
},
|
||||
|
|
@ -141,8 +142,8 @@ export default Vue.extend({
|
|||
modalAddUser: false,
|
||||
modalDeleteUser: false,
|
||||
userToDelete: {} as UserDto,
|
||||
modalEditSharedLibraries: false,
|
||||
userToEditSharedLibraries: {} as UserDto,
|
||||
modalEditRestrictions: false,
|
||||
userToEditRestrictions: {} as UserDto,
|
||||
modalEditUser: false,
|
||||
userToEdit: {} as UserDto,
|
||||
modalChangePassword: false,
|
||||
|
|
@ -175,9 +176,9 @@ export default Vue.extend({
|
|||
this.userToDelete = user
|
||||
this.modalDeleteUser = true
|
||||
},
|
||||
editSharedLibraries(user: UserDto) {
|
||||
this.userToEditSharedLibraries = user
|
||||
this.modalEditSharedLibraries = true
|
||||
editRestrictions(user: UserDto) {
|
||||
this.userToEditRestrictions = user
|
||||
this.modalEditRestrictions = true
|
||||
},
|
||||
editUser(user: UserDto) {
|
||||
this.userToEdit = user
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
import Vue from 'vue'
|
||||
import {required, sameAs} from 'vuelidate/lib/validators'
|
||||
import {ERROR} from '@/types/events'
|
||||
import { PasswordUpdateDto } from '@/types/komga-users'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'PasswordChangeDialog',
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import {UserRoles} from '@/types/enum-users'
|
|||
import Vue from 'vue'
|
||||
import {ERROR} from '@/types/events'
|
||||
import {LibraryDto} from '@/types/komga-libraries'
|
||||
import {UserDto, UserUpdateDto} from '@/types/komga-users'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'UserEditDialog',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,264 @@
|
|||
<template>
|
||||
<v-dialog v-model="modal"
|
||||
:fullscreen="$vuetify.breakpoint.xsOnly"
|
||||
max-width="600"
|
||||
>
|
||||
<v-card>
|
||||
<v-form v-model="form" ref="form">
|
||||
<v-toolbar class="hidden-sm-and-up">
|
||||
<v-btn icon @click="dialogCancel">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
<v-toolbar-title>
|
||||
{{ $t('dialog.edit_user_restrictions.edit_restrictions_for', {name: user.email}) }}
|
||||
</v-toolbar-title>
|
||||
<v-spacer/>
|
||||
<v-toolbar-items>
|
||||
<v-btn text
|
||||
color="primary"
|
||||
:disabled="!form"
|
||||
@click="dialogConfirm">{{ $t('common.save_changes') }}</v-btn>
|
||||
</v-toolbar-items>
|
||||
</v-toolbar>
|
||||
|
||||
<v-card-title class="hidden-xs-only">
|
||||
{{ $t('dialog.edit_user_restrictions.edit_restrictions_for', {name: user.email}) }}
|
||||
</v-card-title>
|
||||
|
||||
<v-tabs v-model="tab" grow>
|
||||
<v-tab>{{ $t('dialog.edit_user_restrictions.tab_shared_libraries') }}</v-tab>
|
||||
<v-tab>{{ $t('dialog.edit_user_restrictions.tab_content_restrictions') }}</v-tab>
|
||||
|
||||
<!-- Tab: Shared Libraries -->
|
||||
<v-tab-item>
|
||||
<v-card flat>
|
||||
<v-container fluid class="pa-6">
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-checkbox v-model="allLibraries"
|
||||
:label="$t('common.all_libraries')"
|
||||
hide-details
|
||||
class="my-0 py-0"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-divider class="my-2"/>
|
||||
|
||||
<v-row v-for="(l, index) in libraries" :key="index">
|
||||
<v-col>
|
||||
<v-checkbox v-model="selectedLibraries"
|
||||
:label="l.name"
|
||||
:value="l.id"
|
||||
:disabled="allLibraries"
|
||||
hide-details
|
||||
class="my-0 py-0"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-tab-item>
|
||||
|
||||
<!-- Tab: Content Restrictions -->
|
||||
<v-tab-item>
|
||||
<v-card flat>
|
||||
<v-container fluid class="pa-6">
|
||||
<v-row align="center">
|
||||
<v-col>
|
||||
<v-select v-model="ageRestriction"
|
||||
:label="$t('dialog.edit_user_restrictions.label_age_restriction')"
|
||||
:items="ageRestrictionsAvailable"
|
||||
filled
|
||||
>
|
||||
</v-select>
|
||||
</v-col>
|
||||
|
||||
<v-col>
|
||||
<v-text-field v-model="age"
|
||||
:disabled="ageRestriction === NONE"
|
||||
:label="$t('common.age')"
|
||||
:rules="[ageRules]"
|
||||
filled
|
||||
dense
|
||||
type="number"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<span class="text-body-2">{{ $t('dialog.edit_user_restrictions.label_allow_only_labels') }}</span>
|
||||
<v-combobox v-model="labelsAllow"
|
||||
:items="sharingLabelsAvailable"
|
||||
hide-selected
|
||||
chips
|
||||
deletable-chips
|
||||
multiple
|
||||
filled
|
||||
dense
|
||||
>
|
||||
</v-combobox>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<span class="text-body-2">{{ $t('dialog.edit_user_restrictions.label_exclude_labels') }}</span>
|
||||
<v-combobox v-model="labelsExclude"
|
||||
:items="sharingLabelsAvailable"
|
||||
hide-selected
|
||||
chips
|
||||
deletable-chips
|
||||
multiple
|
||||
filled
|
||||
dense
|
||||
>
|
||||
</v-combobox>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-tab-item>
|
||||
|
||||
</v-tabs>
|
||||
|
||||
<v-card-actions class="hidden-xs-only">
|
||||
<v-spacer/>
|
||||
<v-btn text @click="dialogCancel">{{ $t('common.cancel') }}</v-btn>
|
||||
<v-btn color="primary"
|
||||
@click="dialogConfirm"
|
||||
:disabled="!form"
|
||||
>{{ $t('common.save_changes') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-form>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import {ERROR} from '@/types/events'
|
||||
import {LibraryDto} from '@/types/komga-libraries'
|
||||
import {UserDto, UserUpdateDto} from '@/types/komga-users'
|
||||
import {AllowExclude} from '@/types/enum-users'
|
||||
|
||||
const NONE = 'NONE'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'UserRestrictionsEditDialog',
|
||||
data: () => {
|
||||
return {
|
||||
NONE,
|
||||
tab: 0,
|
||||
form: false,
|
||||
modal: false,
|
||||
allLibraries: true,
|
||||
selectedLibraries: [] as string[],
|
||||
labelsAllow: [] as string[],
|
||||
labelsExclude: [] as string[],
|
||||
sharingLabelsAvailable: [] as string[],
|
||||
ageRestriction: NONE as AllowExclude | string,
|
||||
age: 0,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: Boolean,
|
||||
user: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.modal = val
|
||||
},
|
||||
modal(val) {
|
||||
if (val) {
|
||||
this.loadAvailableSharingLabels()
|
||||
} else {
|
||||
this.dialogCancel()
|
||||
}
|
||||
},
|
||||
user(val) {
|
||||
this.dialogReset(val)
|
||||
this.loadAvailableSharingLabels()
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
libraries(): LibraryDto[] {
|
||||
return this.$store.state.komgaLibraries.libraries
|
||||
},
|
||||
ageRestrictionsAvailable(): any[] {
|
||||
return [
|
||||
{text: this.$t('dialog.edit_user_restrictions.age_restriction.none').toString(), value: NONE},
|
||||
{text: this.$t('dialog.edit_user_restrictions.age_restriction.allow_under').toString(), value: AllowExclude.ALLOW_ONLY},
|
||||
{text: this.$t('dialog.edit_user_restrictions.age_restriction.exclude_over').toString(), value: AllowExclude.EXCLUDE},
|
||||
]
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async loadAvailableSharingLabels() {
|
||||
this.sharingLabelsAvailable = await this.$komgaReferential.getSharingLabels()
|
||||
},
|
||||
ageRules(age: number): boolean | string {
|
||||
if (age < 0) return this.$t('validation.zero_or_more').toString()
|
||||
return true
|
||||
},
|
||||
dialogReset(user: UserDto) {
|
||||
(this.$refs.form as any)?.resetValidation()
|
||||
this.tab = 0
|
||||
this.allLibraries = user.sharedAllLibraries
|
||||
if (user.sharedAllLibraries) {
|
||||
this.selectedLibraries = this.libraries.map(x => x.id)
|
||||
} else {
|
||||
this.selectedLibraries = user.sharedLibrariesIds
|
||||
}
|
||||
this.labelsAllow = user.labelsAllow
|
||||
this.labelsExclude = user.labelsExclude
|
||||
this.ageRestriction = user.ageRestriction?.restriction || NONE
|
||||
this.age = user.ageRestriction?.age || 0
|
||||
},
|
||||
dialogCancel() {
|
||||
this.$emit('input', false)
|
||||
this.dialogReset(this.user)
|
||||
},
|
||||
dialogConfirm() {
|
||||
this.editUser()
|
||||
this.$emit('input', false)
|
||||
this.dialogReset(this.user)
|
||||
},
|
||||
async editUser() {
|
||||
try {
|
||||
if(!(this.$refs.form as any).validate()) return
|
||||
const patch = {
|
||||
sharedLibraries: {
|
||||
all: this.allLibraries,
|
||||
libraryIds: this.selectedLibraries,
|
||||
},
|
||||
labelsAllow: this.labelsAllow,
|
||||
labelsExclude: this.labelsExclude,
|
||||
} as UserUpdateDto
|
||||
|
||||
if (this.ageRestriction !== NONE) {
|
||||
patch.ageRestriction = {
|
||||
age: this.age,
|
||||
restriction: this.ageRestriction as AllowExclude,
|
||||
}
|
||||
} else {
|
||||
this.$_.merge(patch, {ageRestriction: null})
|
||||
}
|
||||
|
||||
await this.$store.dispatch('updateUser', {userId: this.user.id, patch: patch})
|
||||
} catch (e) {
|
||||
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
<template>
|
||||
<v-dialog v-model="modal"
|
||||
max-width="450"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('dialog.edit_user_shared_libraries.dialog_title') }}</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-container fluid>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<span class="text-subtitle-1">{{
|
||||
$t('dialog.edit_user_shared_libraries.label_shared_with', {name: user.email})
|
||||
}}</span>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-checkbox v-model="allLibraries"
|
||||
:label="$t('dialog.edit_user_shared_libraries.field_all_libraries')"
|
||||
hide-details
|
||||
class="my-0 py-0"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-divider class="my-2"/>
|
||||
|
||||
<v-row v-for="(l, index) in libraries" :key="index">
|
||||
<v-col>
|
||||
<v-checkbox v-model="selectedLibraries"
|
||||
:label="l.name"
|
||||
:value="l.id"
|
||||
:disabled="allLibraries"
|
||||
hide-details
|
||||
class="my-0 py-0"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer/>
|
||||
<v-btn text @click="dialogCancel">{{ $t('dialog.edit_user_shared_libraries.button_cancel') }}</v-btn>
|
||||
<v-btn color="primary"
|
||||
@click="dialogConfirm"
|
||||
>{{ $t('dialog.edit_user_shared_libraries.button_confirm') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import {ERROR} from '@/types/events'
|
||||
import {LibraryDto} from '@/types/komga-libraries'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'UserSharedLibrariesEditDialog',
|
||||
data: () => {
|
||||
return {
|
||||
modal: false,
|
||||
allLibraries: true,
|
||||
selectedLibraries: [] as string[],
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: Boolean,
|
||||
user: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.modal = val
|
||||
},
|
||||
modal(val) {
|
||||
!val && this.dialogCancel()
|
||||
},
|
||||
user(val) {
|
||||
this.dialogReset(val)
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
libraries(): LibraryDto[] {
|
||||
return this.$store.state.komgaLibraries.libraries
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
dialogReset(user: UserDto) {
|
||||
this.allLibraries = user.sharedAllLibraries
|
||||
if (user.sharedAllLibraries) {
|
||||
this.selectedLibraries = this.libraries.map(x => x.id)
|
||||
} else {
|
||||
this.selectedLibraries = user.sharedLibrariesIds
|
||||
}
|
||||
},
|
||||
dialogCancel() {
|
||||
this.$emit('input', false)
|
||||
this.dialogReset(this.user)
|
||||
},
|
||||
dialogConfirm() {
|
||||
this.editUser()
|
||||
this.$emit('input', false)
|
||||
this.dialogReset(this.user)
|
||||
},
|
||||
async editUser() {
|
||||
try {
|
||||
const patch = {
|
||||
sharedLibraries: {
|
||||
all: this.allLibraries,
|
||||
libraryIds: this.selectedLibraries,
|
||||
},
|
||||
} as UserUpdateDto
|
||||
|
||||
await this.$store.dispatch('updateUser', {userId: this.user.id, patch: patch})
|
||||
} catch (e) {
|
||||
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -180,6 +180,7 @@
|
|||
"title": "{name} collection"
|
||||
},
|
||||
"common": {
|
||||
"age": "Age",
|
||||
"all_libraries": "All Libraries",
|
||||
"books": "Books",
|
||||
"books_n": "No book | 1 book | {count} books",
|
||||
|
|
@ -218,6 +219,7 @@
|
|||
"required": "Required",
|
||||
"reset_filters": "Reset filters",
|
||||
"roles": "Roles",
|
||||
"save_changes": "Save changes",
|
||||
"series": "Series",
|
||||
"sidecars": "Sidecars",
|
||||
"tags": "Tags",
|
||||
|
|
@ -453,12 +455,18 @@
|
|||
"dialog_title": "Edit user",
|
||||
"label_roles_for": "Roles for {name}"
|
||||
},
|
||||
"edit_user_shared_libraries": {
|
||||
"button_cancel": "Cancel",
|
||||
"button_confirm": "Save changes",
|
||||
"dialog_title": "Edit shared libraries",
|
||||
"field_all_libraries": "All libraries",
|
||||
"label_shared_with": "Shared with {name}"
|
||||
"edit_user_restrictions": {
|
||||
"age_restriction": {
|
||||
"allow_under": "Allow only under",
|
||||
"exclude_over": "Exclude over",
|
||||
"none": "No restriction"
|
||||
},
|
||||
"edit_restrictions_for": "Edit restrictions for {name}",
|
||||
"label_age_restriction": "Age restriction",
|
||||
"label_allow_only_labels": "Allow only labels",
|
||||
"label_exclude_labels": "Exclude labels",
|
||||
"tab_content_restrictions": "Content Restrictions",
|
||||
"tab_shared_libraries": "Shared Libraries"
|
||||
},
|
||||
"empty_trash": {
|
||||
"body": "By default the media server doesn't remove information for media right away. This helps if a drive is temporarily disconnected. When you empty the trash for a library, all information about missing media is deleted.",
|
||||
|
|
@ -760,7 +768,7 @@
|
|||
},
|
||||
"settings_user": {
|
||||
"change_password": "Change password",
|
||||
"edit_shared_libraries": "Edit shared libraries",
|
||||
"edit_restrictions": "Edit restrictions",
|
||||
"edit_user": "Edit user",
|
||||
"latest_activity": "Latest activity: {date}",
|
||||
"no_recent_activity": "No recent activity",
|
||||
|
|
@ -804,6 +812,9 @@
|
|||
"authentication_activity": "Authentication Activity",
|
||||
"users": "Users"
|
||||
},
|
||||
"validation": {
|
||||
"zero_or_more": "Must be 0 or more"
|
||||
},
|
||||
"welcome": {
|
||||
"add_library": "Add library",
|
||||
"no_libraries_yet": "No libraries have been added yet!",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {UserRoles} from '@/types/enum-users'
|
|||
import {AxiosInstance} from 'axios'
|
||||
import _Vue from 'vue'
|
||||
import {Module} from 'vuex/types'
|
||||
import {UserCreationDto, UserDto, UserUpdateDto} from '@/types/komga-users'
|
||||
|
||||
let service: KomgaUsersService
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { AxiosInstance } from 'axios'
|
||||
import {UserDto} from '@/types/komga-users'
|
||||
|
||||
const API_CLAIM = '/api/v1/claim'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
import {AxiosInstance} from 'axios'
|
||||
import {
|
||||
AuthenticationActivityDto,
|
||||
PasswordUpdateDto,
|
||||
UserCreationDto,
|
||||
UserDto,
|
||||
UserUpdateDto,
|
||||
} from '@/types/komga-users'
|
||||
|
||||
const qs = require('qs')
|
||||
|
||||
|
|
|
|||
|
|
@ -3,3 +3,7 @@ export enum UserRoles {
|
|||
FILE_DOWNLOAD = 'FILE_DOWNLOAD',
|
||||
PAGE_STREAMING = 'PAGE_STREAMING'
|
||||
}
|
||||
|
||||
export enum AllowExclude {
|
||||
ALLOW_ONLY = 'ALLOW_ONLY', EXCLUDE = 'EXCLUDE'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,43 @@
|
|||
interface UserDto {
|
||||
import {AllowExclude} from '@/types/enum-users'
|
||||
|
||||
export interface UserDto {
|
||||
id: string,
|
||||
email: string,
|
||||
roles: string[],
|
||||
sharedAllLibraries: boolean,
|
||||
sharedLibrariesIds: string[]
|
||||
sharedLibrariesIds: string[],
|
||||
labelsAllow: string[],
|
||||
labelsExclude: string[],
|
||||
ageRestriction?: {
|
||||
age: number,
|
||||
restriction: AllowExclude,
|
||||
},
|
||||
}
|
||||
|
||||
interface UserCreationDto {
|
||||
export interface UserCreationDto {
|
||||
email: string,
|
||||
roles: string[]
|
||||
}
|
||||
|
||||
interface PasswordUpdateDto {
|
||||
export interface PasswordUpdateDto {
|
||||
password: string
|
||||
}
|
||||
|
||||
interface UserUpdateDto {
|
||||
export interface UserUpdateDto {
|
||||
roles?: string[],
|
||||
sharedLibraries?: {
|
||||
all: boolean,
|
||||
libraryIds: string[]
|
||||
},
|
||||
ageRestriction?: {
|
||||
age: number,
|
||||
restriction: AllowExclude,
|
||||
}
|
||||
labelsAllow?: string[],
|
||||
labelsExclude?: string[],
|
||||
}
|
||||
|
||||
interface AuthenticationActivityDto {
|
||||
export interface AuthenticationActivityDto {
|
||||
userId?: string,
|
||||
email?: string,
|
||||
ip?: string,
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
import PasswordChangeDialog from '@/components/dialogs/PasswordChangeDialog.vue'
|
||||
import Vue from 'vue'
|
||||
import AuthenticationActivityTable from '@/components/AuthenticationActivityTable.vue'
|
||||
import { UserDto } from '@/types/komga-users'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'AccountSettings',
|
||||
|
|
|
|||
Loading…
Reference in a new issue