mirror of
https://github.com/Luzifer/twitch-bot.git
synced 2025-03-14 02:45:02 +00:00
778 lines
23 KiB
Vue
778 lines
23 KiB
Vue
<template>
|
|
<div>
|
|
<b-row>
|
|
<b-col>
|
|
<b-card no-body>
|
|
<b-card-header>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'hashtag']"
|
|
/>
|
|
Channels
|
|
</b-card-header>
|
|
<b-list-group flush>
|
|
<b-list-group-item
|
|
v-for="channel in sortedChannels"
|
|
:key="channel"
|
|
class="d-flex align-items-center align-middle"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'hashtag']"
|
|
/>
|
|
{{ channel }}
|
|
<span class="ml-auto mr-2">
|
|
<font-awesome-icon
|
|
v-if="!generalConfig.channel_has_token[channel]"
|
|
:id="`channelPublicWarn${channel}`"
|
|
fixed-width
|
|
class="ml-1 text-danger"
|
|
:icon="['fas', 'exclamation-triangle']"
|
|
/>
|
|
<font-awesome-icon
|
|
v-else-if="!hasAllExtendedScopes(channel)"
|
|
:id="`channelPublicWarn${channel}`"
|
|
fixed-width
|
|
class="ml-1 text-warning"
|
|
:icon="['fas', 'exclamation-triangle']"
|
|
/>
|
|
<b-tooltip
|
|
:target="`channelPublicWarn${channel}`"
|
|
triggers="hover"
|
|
>
|
|
<template v-if="!generalConfig.channel_has_token[channel]">
|
|
Bot is not authorized to access Twitch on behalf of this channels owner (tokens are missing).
|
|
Click pencil to grant permissions.
|
|
</template>
|
|
<template v-else>
|
|
Channel is missing {{ missingExtendedScopes(channel).length }} extended permissions.
|
|
Click pencil to change granted permissions.
|
|
</template>
|
|
</b-tooltip>
|
|
</span>
|
|
<b-button-group size="sm">
|
|
<b-button
|
|
variant="primary"
|
|
@click="editChannelPermissions(channel)"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
:icon="['fas', 'pencil-alt']"
|
|
/>
|
|
</b-button>
|
|
<b-button
|
|
variant="danger"
|
|
@click="removeChannel(channel)"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
:icon="['fas', 'minus']"
|
|
/>
|
|
</b-button>
|
|
</b-button-group>
|
|
</b-list-group-item>
|
|
|
|
<b-list-group-item>
|
|
<b-input-group>
|
|
<b-form-input
|
|
v-model="models.addChannel"
|
|
:state="!!validateUserName(models.addChannel)"
|
|
@keyup.enter="addChannel"
|
|
/>
|
|
<b-input-group-append>
|
|
<b-button
|
|
variant="success"
|
|
:disabled="!validateUserName(models.addChannel)"
|
|
@click="addChannel"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'plus']"
|
|
/>
|
|
Add
|
|
</b-button>
|
|
</b-input-group-append>
|
|
</b-input-group>
|
|
</b-list-group-item>
|
|
</b-list-group>
|
|
</b-card>
|
|
</b-col>
|
|
<b-col>
|
|
<b-card
|
|
no-body
|
|
class="mb-3"
|
|
>
|
|
<b-card-header>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'users']"
|
|
/>
|
|
Bot-Editors
|
|
</b-card-header>
|
|
<b-list-group flush>
|
|
<b-list-group-item
|
|
v-for="editor in sortedEditors"
|
|
:key="editor"
|
|
class="d-flex align-items-center align-middle"
|
|
>
|
|
<b-avatar
|
|
class="mr-3"
|
|
:src="userProfiles[editor] ? userProfiles[editor].profile_image_url : ''"
|
|
/>
|
|
<span class="mr-auto">{{ userProfiles[editor] ? userProfiles[editor].display_name : editor }}</span>
|
|
<b-button
|
|
size="sm"
|
|
variant="danger"
|
|
@click="removeEditor(editor)"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
:icon="['fas', 'minus']"
|
|
/>
|
|
</b-button>
|
|
</b-list-group-item>
|
|
|
|
<b-list-group-item>
|
|
<b-input-group>
|
|
<b-form-input
|
|
v-model="models.addEditor"
|
|
:state="!!validateUserName(models.addEditor)"
|
|
@keyup.enter="addEditor"
|
|
/>
|
|
<b-input-group-append>
|
|
<b-button
|
|
variant="success"
|
|
:disabled="!validateUserName(models.addEditor)"
|
|
@click="addEditor"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'plus']"
|
|
/>
|
|
Add
|
|
</b-button>
|
|
</b-input-group-append>
|
|
</b-input-group>
|
|
</b-list-group-item>
|
|
</b-list-group>
|
|
</b-card>
|
|
|
|
<b-card
|
|
no-body
|
|
>
|
|
<b-card-header
|
|
class="d-flex align-items-center align-middle"
|
|
>
|
|
<span class="mr-auto">
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'ticket-alt']"
|
|
/>
|
|
Auth-Tokens
|
|
</span>
|
|
<b-button-group size="sm">
|
|
<b-button
|
|
variant="success"
|
|
@click="newAPIToken"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
:icon="['fas', 'plus']"
|
|
/>
|
|
</b-button>
|
|
</b-button-group>
|
|
</b-card-header>
|
|
<b-list-group flush>
|
|
<b-list-group-item
|
|
v-if="createdAPIToken"
|
|
variant="success"
|
|
>
|
|
Token was created, copy it within 30s as you will not see it again:<br>
|
|
<code>{{ createdAPIToken.token }}</code>
|
|
</b-list-group-item>
|
|
|
|
<b-list-group-item
|
|
v-for="(token, uuid) in apiTokens"
|
|
:key="uuid"
|
|
class="d-flex align-items-center align-middle"
|
|
>
|
|
<span class="mr-auto">
|
|
{{ token.name }}<br>
|
|
<b-badge
|
|
v-for="module in token.modules"
|
|
:key="module"
|
|
class="mr-1"
|
|
>{{ module === '*' ? 'ANY' : module }}</b-badge>
|
|
</span>
|
|
<b-button
|
|
size="sm"
|
|
variant="danger"
|
|
@click="removeAPIToken(uuid)"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
:icon="['fas', 'minus']"
|
|
/>
|
|
</b-button>
|
|
</b-list-group-item>
|
|
</b-list-group>
|
|
</b-card>
|
|
</b-col>
|
|
<b-col>
|
|
<b-card
|
|
no-body
|
|
class="mb-3"
|
|
:border-variant="botConnectionCardVariant"
|
|
>
|
|
<b-card-header
|
|
class="d-flex align-items-center align-middle"
|
|
:header-bg-variant="botConnectionCardVariant"
|
|
>
|
|
<span class="mr-auto">
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'sign-in-alt']"
|
|
/>
|
|
Bot Connection
|
|
</span>
|
|
<template v-if="generalConfig.bot_name">
|
|
<code
|
|
id="botUserName"
|
|
>
|
|
{{ generalConfig.bot_name }}
|
|
<b-tooltip
|
|
target="botUserName"
|
|
triggers="hover"
|
|
>
|
|
Twitch Login-Name of the bot user currently authorized
|
|
</b-tooltip>
|
|
</code>
|
|
</template>
|
|
<template v-else>
|
|
<font-awesome-icon
|
|
id="botUserNameDC"
|
|
fixed-width
|
|
class="mr-1 text-danger"
|
|
:icon="['fas', 'unlink']"
|
|
/>
|
|
<b-tooltip
|
|
target="botUserNameDC"
|
|
triggers="hover"
|
|
>
|
|
Bot is not currently authorized!
|
|
</b-tooltip>
|
|
</template>
|
|
</b-card-header>
|
|
|
|
<b-card-body>
|
|
<p>
|
|
Here you can manage your bots auth-token: it's required to communicate with Twitch Chat and APIs. The access will be valid as long as you don't change the password or revoke the apps permission in your bot account.
|
|
</p>
|
|
<ul>
|
|
<li>Copy the URL provided below</li>
|
|
<li><strong>Open an inkognito tab or different browser you are not logged into Twitch or are logged in with your bot account</strong></li>
|
|
<li>Open the copied URL, sign in with the bot account and accept the permissions</li>
|
|
<li>You will see a message containing the authorized account. If this account is wrong, just start over, the token will be overwritten.</li>
|
|
</ul>
|
|
<p
|
|
v-if="botMissingScopes > 0"
|
|
class="alert alert-warning"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'exclamation-triangle']"
|
|
/>
|
|
Bot is missing {{ botMissingScopes }} of its required scopes which will cause features not to work properly. Please re-authorize the bot using the URL below.
|
|
</p>
|
|
<b-input-group>
|
|
<b-form-input
|
|
placeholder="Loading..."
|
|
readonly
|
|
:value="botAuthTokenURL"
|
|
@focus="$event.target.select()"
|
|
/>
|
|
<b-input-group-append>
|
|
<b-button
|
|
:variant="copyButtonVariant.botConnection"
|
|
@click="copyAuthURL('botConnection')"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'clipboard']"
|
|
/>
|
|
Copy
|
|
</b-button>
|
|
</b-input-group-append>
|
|
</b-input-group>
|
|
</b-card-body>
|
|
</b-card>
|
|
</b-col>
|
|
</b-row>
|
|
|
|
<!-- API-Token Editor -->
|
|
<b-modal
|
|
v-if="showAPITokenEditModal"
|
|
hide-header-close
|
|
:ok-disabled="!validateAPIToken"
|
|
ok-title="Save"
|
|
size="md"
|
|
:visible="showAPITokenEditModal"
|
|
title="New API-Token"
|
|
@hidden="showAPITokenEditModal=false"
|
|
@ok="saveAPIToken"
|
|
>
|
|
<b-form-group
|
|
label="Name"
|
|
label-for="formAPITokenName"
|
|
>
|
|
<b-form-input
|
|
id="formAPITokenName"
|
|
v-model="models.apiToken.name"
|
|
:state="Boolean(models.apiToken.name)"
|
|
type="text"
|
|
/>
|
|
</b-form-group>
|
|
|
|
<b-form-group
|
|
label="Enabled for Modules"
|
|
>
|
|
<b-form-checkbox-group
|
|
v-model="models.apiToken.modules"
|
|
class="mb-3"
|
|
:options="availableModules"
|
|
text-field="text"
|
|
value-field="value"
|
|
/>
|
|
</b-form-group>
|
|
</b-modal>
|
|
|
|
<!-- Channel Permission Editor -->
|
|
<b-modal
|
|
v-if="showPermissionEditModal"
|
|
hide-footer
|
|
size="lg"
|
|
title="Edit Permissions for Channel"
|
|
:visible="showPermissionEditModal"
|
|
@hidden="showPermissionEditModal=false"
|
|
>
|
|
<b-row>
|
|
<b-col>
|
|
<p>The bot should be able to…</p>
|
|
<b-form-checkbox-group
|
|
id="channelPermissions"
|
|
v-model="models.channelPermissions"
|
|
:options="extendedPermissions"
|
|
multiple
|
|
:select-size="extendedPermissions.length"
|
|
stacked
|
|
switches
|
|
/>
|
|
<p class="mt-3">
|
|
…on this channel.
|
|
</p>
|
|
</b-col>
|
|
<b-col>
|
|
<p>
|
|
In order to access non-public information as channel-point redemptions or take actions limited to the channel owner the bot needs additional permissions. The <strong>owner</strong> of the channel needs to grant those!
|
|
</p>
|
|
<ul>
|
|
<li>Select permissions on the left side</li>
|
|
<li>Copy the URL provided below</li>
|
|
<li>Pass the URL to the channel owner and tell them to open it with their personal account logged in</li>
|
|
<li>The bot will display a message containing the updated account</li>
|
|
</ul>
|
|
</b-col>
|
|
</b-row>
|
|
<b-row>
|
|
<b-col>
|
|
<b-input-group>
|
|
<b-form-input
|
|
placeholder="Loading..."
|
|
readonly
|
|
:value="extendedPermissionsURL"
|
|
@focus="$event.target.select()"
|
|
/>
|
|
<b-input-group-append>
|
|
<b-button
|
|
:variant="copyButtonVariant.channelPermission"
|
|
@click="copyAuthURL('channelPermission')"
|
|
>
|
|
<font-awesome-icon
|
|
fixed-width
|
|
class="mr-1"
|
|
:icon="['fas', 'clipboard']"
|
|
/>
|
|
Copy
|
|
</b-button>
|
|
</b-input-group-append>
|
|
</b-input-group>
|
|
</b-col>
|
|
</b-row>
|
|
</b-modal>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import * as constants from './const.js'
|
|
|
|
import axios from 'axios'
|
|
|
|
export default {
|
|
computed: {
|
|
availableModules() {
|
|
return [
|
|
{ text: 'ANY', value: '*' },
|
|
...[...this.modules || []].sort()
|
|
.filter(m => m !== 'config-editor')
|
|
.map(m => ({ text: m, value: m })),
|
|
]
|
|
},
|
|
|
|
botAuthTokenURL() {
|
|
if (!this.authURLs || !this.authURLs.update_bot_token) {
|
|
return ''
|
|
}
|
|
|
|
let scopes = [...this.$root.vars.DefaultBotScopes]
|
|
|
|
if (this.generalConfig && this.generalConfig.channel_scopes && this.generalConfig.channel_scopes[this.generalConfig.bot_name]) {
|
|
scopes = [
|
|
...new Set([
|
|
...scopes,
|
|
...this.generalConfig.channel_scopes[this.generalConfig.bot_name],
|
|
]),
|
|
]
|
|
}
|
|
|
|
const u = new URL(this.authURLs.update_bot_token)
|
|
u.searchParams.set('scope', scopes.join(' '))
|
|
return u.toString()
|
|
},
|
|
|
|
botConnectionCardVariant() {
|
|
if (this.$parent.status.overall_status_success) {
|
|
return 'secondary'
|
|
}
|
|
return 'warning'
|
|
},
|
|
|
|
botMissingScopes() {
|
|
let missing = 0
|
|
|
|
if (!this.generalConfig || !this.generalConfig.channel_scopes || !this.generalConfig.bot_name) {
|
|
return -1
|
|
}
|
|
|
|
const grantedScopes = [...this.generalConfig.channel_scopes[this.generalConfig.bot_name] || []]
|
|
|
|
for (const scope of this.$root.vars.DefaultBotScopes) {
|
|
if (!grantedScopes.includes(scope)) {
|
|
missing++
|
|
}
|
|
}
|
|
|
|
return missing
|
|
},
|
|
|
|
extendedPermissions() {
|
|
return Object.keys(this.authURLs.available_extended_scopes || {})
|
|
.map(v => ({ text: this.authURLs.available_extended_scopes[v], value: v }))
|
|
.sort((a, b) => a.value.localeCompare(b.value))
|
|
},
|
|
|
|
extendedPermissionsURL() {
|
|
if (!this.authURLs?.update_channel_scopes) {
|
|
return null
|
|
}
|
|
|
|
const u = new URL(this.authURLs.update_channel_scopes)
|
|
u.searchParams.set('scope', this.models.channelPermissions.join(' '))
|
|
return u.toString()
|
|
},
|
|
|
|
sortedChannels() {
|
|
return [...this.generalConfig?.channels || []].sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))
|
|
},
|
|
|
|
sortedEditors() {
|
|
return [...this.generalConfig?.bot_editors || []].sort((a, b) => {
|
|
const an = this.userProfiles[a]?.login || a
|
|
const bn = this.userProfiles[b]?.login || b
|
|
|
|
return an.localeCompare(bn)
|
|
})
|
|
},
|
|
|
|
validateAPIToken() {
|
|
return this.models.apiToken.modules.length > 0 && Boolean(this.models.apiToken.name)
|
|
},
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
apiTokens: {},
|
|
authURLs: {},
|
|
copyButtonVariant: {
|
|
botConnection: 'primary',
|
|
channelPermission: 'primary',
|
|
},
|
|
|
|
createdAPIToken: null,
|
|
generalConfig: {},
|
|
models: {
|
|
addChannel: '',
|
|
addEditor: '',
|
|
apiToken: {},
|
|
channelPermissions: [],
|
|
},
|
|
|
|
modules: [],
|
|
|
|
showAPITokenEditModal: false,
|
|
showPermissionEditModal: false,
|
|
userProfiles: {},
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
addChannel() {
|
|
if (!this.validateUserName(this.models.addChannel)) {
|
|
return
|
|
}
|
|
|
|
this.generalConfig.channels.push(this.models.addChannel.replace(/^#*/, ''))
|
|
this.models.addChannel = ''
|
|
|
|
this.updateGeneralConfig()
|
|
},
|
|
|
|
addEditor() {
|
|
if (!this.validateUserName(this.models.addEditor)) {
|
|
return
|
|
}
|
|
|
|
this.fetchProfile(this.models.addEditor)
|
|
this.generalConfig.bot_editors.push(this.models.addEditor)
|
|
this.models.addEditor = ''
|
|
|
|
this.updateGeneralConfig()
|
|
},
|
|
|
|
copyAuthURL(type) {
|
|
let prom = null
|
|
let btnField = null
|
|
|
|
switch (type) {
|
|
case 'botConnection':
|
|
prom = navigator.clipboard.writeText(this.botAuthTokenURL)
|
|
btnField = 'botConnection'
|
|
break
|
|
case 'channelPermission':
|
|
prom = navigator.clipboard.writeText(this.extendedPermissionsURL)
|
|
btnField = 'channelPermission'
|
|
break
|
|
}
|
|
|
|
return prom
|
|
.then(() => {
|
|
this.copyButtonVariant[btnField] = 'success'
|
|
})
|
|
.catch(() => {
|
|
this.copyButtonVariant[btnField] = 'danger'
|
|
})
|
|
.finally(() => {
|
|
window.setTimeout(() => {
|
|
this.copyButtonVariant[btnField] = 'primary'
|
|
}, 2000)
|
|
})
|
|
},
|
|
|
|
editChannelPermissions(channel) {
|
|
let permissionSet = [...this.generalConfig.channel_scopes[channel] || []]
|
|
|
|
if (channel === this.generalConfig.bot_name) {
|
|
permissionSet = [
|
|
...permissionSet,
|
|
...this.$root.vars.DefaultBotScopes,
|
|
]
|
|
}
|
|
|
|
this.models.channelPermissions = [...new Set(permissionSet)]
|
|
this.showPermissionEditModal = true
|
|
},
|
|
|
|
fetchAPITokens() {
|
|
this.$bus.$emit(constants.NOTIFY_LOADING_DATA, true)
|
|
return axios.get('config-editor/auth-tokens', this.$root.axiosOptions)
|
|
.then(resp => {
|
|
this.apiTokens = resp.data
|
|
})
|
|
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
|
},
|
|
|
|
fetchAuthURLs() {
|
|
this.$bus.$emit(constants.NOTIFY_LOADING_DATA, true)
|
|
return axios.get('config-editor/auth-urls', this.$root.axiosOptions)
|
|
.then(resp => {
|
|
this.authURLs = resp.data
|
|
})
|
|
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
|
},
|
|
|
|
fetchGeneralConfig() {
|
|
this.$bus.$emit(constants.NOTIFY_LOADING_DATA, true)
|
|
return axios.get('config-editor/general', this.$root.axiosOptions)
|
|
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
|
.then(resp => {
|
|
this.generalConfig = resp.data
|
|
|
|
const promises = []
|
|
for (const editor of this.generalConfig.bot_editors) {
|
|
promises.push(this.fetchProfile(editor))
|
|
}
|
|
|
|
return Promise.all(promises)
|
|
})
|
|
},
|
|
|
|
fetchModules() {
|
|
this.$bus.$emit(constants.NOTIFY_LOADING_DATA, true)
|
|
return axios.get('config-editor/modules')
|
|
.then(resp => {
|
|
this.modules = resp.data
|
|
})
|
|
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
|
},
|
|
|
|
fetchProfile(user) {
|
|
this.$bus.$emit(constants.NOTIFY_LOADING_DATA, true)
|
|
return axios.get(`config-editor/user?user=${user}`, this.$root.axiosOptions)
|
|
.then(resp => {
|
|
this.$set(this.userProfiles, user, resp.data)
|
|
this.$bus.$emit(constants.NOTIFY_LOADING_DATA, false)
|
|
})
|
|
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
|
},
|
|
|
|
hasAllExtendedScopes(channel) {
|
|
if (!this.generalConfig.channel_scopes[channel]) {
|
|
return false
|
|
}
|
|
|
|
for (const scope in this.authURLs.available_extended_scopes) {
|
|
if (!this.generalConfig.channel_scopes[channel].includes(scope)) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
},
|
|
|
|
missingExtendedScopes(channel) {
|
|
if (!this.generalConfig.channel_scopes[channel]) {
|
|
return Object.keys(this.authURLs.available_extended_scopes || {})
|
|
}
|
|
|
|
const missing = []
|
|
|
|
for (const scope in this.authURLs.available_extended_scopes) {
|
|
if (!this.generalConfig.channel_scopes[channel].includes(scope)) {
|
|
missing.push(scope)
|
|
}
|
|
}
|
|
|
|
return missing
|
|
},
|
|
|
|
newAPIToken() {
|
|
this.$set(this.models, 'apiToken', {
|
|
modules: [],
|
|
name: '',
|
|
})
|
|
this.showAPITokenEditModal = true
|
|
},
|
|
|
|
removeAPIToken(uuid) {
|
|
axios.delete(`config-editor/auth-tokens/${uuid}`, this.$root.axiosOptions)
|
|
.then(() => {
|
|
this.$bus.$emit(constants.NOTIFY_CHANGE_PENDING, true)
|
|
})
|
|
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
|
},
|
|
|
|
removeChannel(channel) {
|
|
this.generalConfig.channels = this.generalConfig.channels
|
|
.filter(ch => ch !== channel)
|
|
|
|
this.updateGeneralConfig()
|
|
},
|
|
|
|
removeEditor(editor) {
|
|
this.generalConfig.bot_editors = this.generalConfig.bot_editors
|
|
.filter(ed => ed !== editor)
|
|
|
|
this.updateGeneralConfig()
|
|
},
|
|
|
|
saveAPIToken(evt) {
|
|
if (!this.validateAPIToken) {
|
|
evt.preventDefault()
|
|
return
|
|
}
|
|
|
|
axios.post(`config-editor/auth-tokens`, this.models.apiToken, this.$root.axiosOptions)
|
|
.then(resp => {
|
|
this.createdAPIToken = resp.data
|
|
this.$bus.$emit(constants.NOTIFY_CHANGE_PENDING, true)
|
|
window.setTimeout(() => {
|
|
this.createdAPIToken = null
|
|
}, 30000)
|
|
})
|
|
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
|
},
|
|
|
|
updateGeneralConfig() {
|
|
axios.put('config-editor/general', this.generalConfig, this.$root.axiosOptions)
|
|
.then(() => {
|
|
this.$bus.$emit(constants.NOTIFY_CHANGE_PENDING, true)
|
|
})
|
|
.catch(err => this.$bus.$emit(constants.NOTIFY_FETCH_ERROR, err))
|
|
},
|
|
|
|
validateUserName(user) {
|
|
return user.match(constants.REGEXP_USER)
|
|
},
|
|
},
|
|
|
|
mounted() {
|
|
this.$bus.$on(constants.NOTIFY_CONFIG_RELOAD, () => {
|
|
Promise.all([
|
|
this.fetchGeneralConfig(),
|
|
this.fetchAPITokens(),
|
|
this.fetchAuthURLs(),
|
|
]).then(() => {
|
|
this.$bus.$emit(constants.NOTIFY_CHANGE_PENDING, false)
|
|
this.$bus.$emit(constants.NOTIFY_LOADING_DATA, false)
|
|
})
|
|
})
|
|
|
|
Promise.all([
|
|
this.fetchGeneralConfig(),
|
|
this.fetchAPITokens(),
|
|
this.fetchAuthURLs(),
|
|
this.fetchModules(),
|
|
]).then(() => this.$bus.$emit(constants.NOTIFY_LOADING_DATA, false))
|
|
},
|
|
|
|
name: 'TwitchBotEditorAppGeneralConfig',
|
|
}
|
|
</script>
|