AzuraCast/frontend/vue/components/Account.vue

264 lines
10 KiB
Vue

<template>
<div>
<h2 class="outside-card-header mb-1">
{{ $gettext('My Account') }}
</h2>
<b-row>
<b-col sm="12" md="6" lg="5">
<section class="card mb-3" role="region">
<b-card-header header-bg-variant="primary-dark">
<h2 class="card-title">{{ $gettext('Profile') }}</h2>
</b-card-header>
<b-overlay variant="card" :show="userLoading">
<b-card-body body-class="card-padding-sm">
<b-media right-align vertical-align="center">
<template v-if="user.avatar.url" #aside>
<avatar :url="user.avatar.url" :service="user.avatar.service"
:service-url="user.avatar.serviceUrl"></avatar>
</template>
<h2 v-if="user.name" class="card-title">{{ user.name }}</h2>
<h2 v-else class="card-title">
{{ $gettext('AzuraCast User') }}
</h2>
<h3 class="card-subtitle">{{ user.email }}</h3>
<div v-if="user.roles.length > 0" class="mt-2">
<span v-for="role in user.roles" :key="role.id"
class="badge badge-secondary mr-2">{{ role.name }}</span>
</div>
</b-media>
</b-card-body>
</b-overlay>
<div class="card-actions">
<b-button variant="outline-primary" @click.prevent="doEditProfile">
<icon icon="edit"></icon>
{{ $gettext('Edit Profile') }}
</b-button>
</div>
</section>
<section class="card" role="region">
<b-card-header header-bg-variant="primary-dark">
<h2 class="card-title">{{ $gettext('Security') }}</h2>
</b-card-header>
<b-overlay variant="card" :show="securityLoading">
<b-card-body>
<h5>
{{ $gettext('Two-Factor Authentication') }}
<enabled-badge :enabled="security.twoFactorEnabled"></enabled-badge>
</h5>
<p class="card-text mt-2">
{{
$gettext('Two-factor authentication improves the security of your account by requiring a second one-time access code in addition to your password when you log in.')
}}
</p>
</b-card-body>
</b-overlay>
<div class="card-actions">
<b-button variant="outline-primary" @click.prevent="doChangePassword">
<icon icon="vpn_key"></icon>
{{ $gettext('Change Password') }}
</b-button>
<b-button v-if="security.twoFactorEnabled" variant="outline-danger"
@click.prevent="disableTwoFactor">
<icon icon="lock_open"></icon>
{{ $gettext('Disable Two-Factor') }}
</b-button>
<b-button v-else variant="outline-success" @click.prevent="enableTwoFactor">
<icon icon="lock"></icon>
{{ $gettext('Enable Two-Factor') }}
</b-button>
</div>
</section>
</b-col>
<b-col sm="12" md="6" lg="7">
<b-card no-body>
<b-card-header header-bg-variant="primary-dark">
<h2 class="card-title">{{ $gettext('API Keys') }}</h2>
</b-card-header>
<info-card>
{{
$gettext('Use API keys to authenticate with the AzuraCast API using the same permissions as your user account.')
}}
<a href="/api" target="_blank">
{{ $gettext('API Documentation') }}
</a>
</info-card>
<b-card-body body-class="card-padding-sm">
<b-button variant="outline-primary" @click.prevent="createApiKey">
<icon icon="add"></icon>
{{ $gettext('Add API Key') }}
</b-button>
</b-card-body>
<data-table ref="datatable" id="account_api_keys" :show-toolbar="false" :fields="apiKeyFields"
:api-url="apiKeysApiUrl">
<template #cell(actions)="row">
<b-button-group size="sm">
<b-button size="sm" variant="danger" @click.prevent="deleteApiKey(row.item.links.self)">
{{ $gettext('Delete') }}
</b-button>
</b-button-group>
</template>
</data-table>
</b-card>
</b-col>
</b-row>
<account-edit-modal ref="editModal" :user-url="userUrl" :supported-locales="supportedLocales"
@relist="relist"></account-edit-modal>
<account-change-password-modal ref="changePasswordModal" :change-password-url="changePasswordUrl"
@relist="relist"></account-change-password-modal>
<account-two-factor-modal ref="twoFactorModal" :two-factor-url="twoFactorUrl"
@relist="relist"></account-two-factor-modal>
<account-api-key-modal ref="apiKeyModal" :create-url="apiKeysApiUrl" @relist="relist"></account-api-key-modal>
</div>
</template>
<script>
import Icon from "~/components/Common/Icon";
import DataTable from "~/components/Common/DataTable";
import AccountChangePasswordModal from "./Account/ChangePasswordModal";
import AccountApiKeyModal from "./Account/ApiKeyModal";
import AccountTwoFactorModal from "./Account/TwoFactorModal";
import AccountEditModal from "./Account/EditModal";
import Avatar from "~/components/Common/Avatar";
import InfoCard from "~/components/Common/InfoCard";
import EnabledBadge from "~/components/Stations/Profile/Common/EnabledBadge.vue";
export default {
name: 'Account',
components: {
EnabledBadge,
AccountEditModal,
AccountTwoFactorModal,
AccountApiKeyModal,
AccountChangePasswordModal,
Icon,
InfoCard,
DataTable,
Avatar
},
props: {
userUrl: String,
changePasswordUrl: String,
twoFactorUrl: String,
apiKeysApiUrl: String,
supportedLocales: Object
},
data() {
return {
userLoading: true,
user: {
name: null,
email: null,
avatar: {
url: null,
service: null,
serviceUrl: null
},
roles: [],
},
securityLoading: true,
security: {
twoFactorEnabled: false,
},
apiKeyFields: [
{
key: 'comment',
isRowHeader: true,
label: this.$gettext('API Key Description/Comments'),
sortable: false
},
{key: 'actions', label: this.$gettext('Actions'), sortable: false, class: 'shrink'}
]
}
},
mounted() {
this.relist();
},
methods: {
relist() {
this.userLoading = true;
this.$wrapWithLoading(
this.axios.get(this.userUrl)
).then((resp) => {
this.user = {
name: resp.data.name,
email: resp.data.email,
roles: resp.data.roles,
avatar: {
url: resp.data.avatar.url_64,
service: resp.data.avatar.service_name,
serviceUrl: resp.data.avatar.service_url
}
};
this.userLoading = false;
});
this.securityLoading = true;
this.$wrapWithLoading(
this.axios.get(this.twoFactorUrl)
).then((resp) => {
this.security.twoFactorEnabled = resp.data.two_factor_enabled;
this.securityLoading = false;
});
this.$refs.datatable.relist();
},
doEditProfile() {
this.$refs.editModal.open();
},
doChangePassword() {
this.$refs.changePasswordModal.open();
},
enableTwoFactor() {
this.$refs.twoFactorModal.open();
},
disableTwoFactor() {
this.$confirmDelete({
title: this.$gettext('Disable two-factor authentication?'),
}).then((result) => {
if (result.value) {
this.$wrapWithLoading(
this.axios.delete(this.twoFactorUrl)
).then((resp) => {
this.$notifySuccess(resp.data.message);
this.relist();
});
}
});
},
createApiKey() {
this.$refs.apiKeyModal.create();
},
deleteApiKey(url) {
this.$confirmDelete({
title: this.$gettext('Delete API Key?'),
}).then((result) => {
if (result.value) {
this.$wrapWithLoading(
this.axios.delete(url)
).then((resp) => {
this.$notifySuccess(resp.data.message);
this.relist();
});
}
});
}
}
}
</script>