aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZephyrrus <[email protected]>2020-07-09 02:24:40 +0300
committerZephyrrus <[email protected]>2020-07-09 02:24:40 +0300
commitfd3f6de51a082dcd72c2ef557747e031ef7b9c4a (patch)
tree78e655286f6984b171604f3bc15e41eb52b01cef /src
parentfix: register handler as a plugin (diff)
downloadhost.fuwn.me-fd3f6de51a082dcd72c2ef557747e031ef7b9c4a.tar.xz
host.fuwn.me-fd3f6de51a082dcd72c2ef557747e031ef7b9c4a.zip
refactor: refactor most of the admin pages to use the store instead of internal states
Diffstat (limited to 'src')
-rw-r--r--src/site/pages/dashboard/account.vue22
-rw-r--r--src/site/pages/dashboard/admin/user/_id.vue66
-rw-r--r--src/site/pages/dashboard/admin/users.vue66
-rw-r--r--src/site/pages/dashboard/albums/_id.vue6
-rw-r--r--src/site/pages/dashboard/index.vue6
-rw-r--r--src/site/pages/dashboard/tags/index.vue6
-rw-r--r--src/site/pages/login.vue47
-rw-r--r--src/site/pages/register.vue57
-rw-r--r--src/site/store/admin.js93
-rw-r--r--src/site/store/alert.js18
-rw-r--r--src/site/store/auth.js10
-rw-r--r--src/site/store/images.js2
12 files changed, 263 insertions, 136 deletions
diff --git a/src/site/pages/dashboard/account.vue b/src/site/pages/dashboard/account.vue
index fb8b273..31ec8af 100644
--- a/src/site/pages/dashboard/account.vue
+++ b/src/site/pages/dashboard/account.vue
@@ -52,11 +52,11 @@
</b-field>
<div class="mb2 mt2 text-center">
- <button
- class="button is-primary"
+ <b-button
+ type="is-lolisafe"
@click="changePassword">
Change password
- </button>
+ </b-button>
</div>
<b-field
@@ -69,19 +69,21 @@
expanded
disabled />
<p class="control">
- <button class="button is-primary">
+ <b-button
+ type="is-lolisafe"
+ @click="copyKey">
Copy
- </button>
+ </b-button>
</p>
</b-field>
</b-field>
<div class="mb2 mt2 text-center">
- <button
- class="button is-primary"
+ <b-button
+ type="is-lolisafe"
@click="promptNewAPIKey">
Request new API key
- </button>
+ </b-button>
</div>
</div>
</div>
@@ -154,6 +156,10 @@ export default {
onConfirm: () => this.requestNewAPIKey(),
});
},
+ copyKey() {
+ this.$clipboard(this.apiKey);
+ this.$notifier.success('API key copied to clipboard');
+ },
async requestNewAPIKey() {
const response = await this.$store.dispatch('auth/requestAPIKey');
this.$buefy.toast.open(response.message);
diff --git a/src/site/pages/dashboard/admin/user/_id.vue b/src/site/pages/dashboard/admin/user/_id.vue
index 1755b89..7814468 100644
--- a/src/site/pages/dashboard/admin/user/_id.vue
+++ b/src/site/pages/dashboard/admin/user/_id.vue
@@ -41,20 +41,27 @@
<b-field
label="Files"
horizontal>
- <span>{{ files.length }}</span>
+ <span>{{ user.files.length }}</span>
</b-field>
<div class="mb2 mt2 text-center">
- <button
- class="button is-danger"
+ <b-button
+ v-if="user.enabled"
+ type="is-danger"
@click="promptDisableUser">
Disable user
- </button>
+ </b-button>
+ <b-button
+ v-if="!user.enabled"
+ type="is-success"
+ @click="promptEnableUser">
+ Enable user
+ </b-button>
</div>
<Grid
- v-if="files.length"
- :files="files" />
+ v-if="user.files.length"
+ :files="user.files" />
</div>
</div>
</div>
@@ -62,6 +69,7 @@
</template>
<script>
+import { mapState } from 'vuex';
import Sidebar from '~/components/sidebar/Sidebar.vue';
import Grid from '~/components/grid/Grid.vue';
@@ -70,42 +78,42 @@ export default {
Sidebar,
Grid,
},
- middleware: ['auth', 'admin'],
+ middleware: ['auth', 'admin', ({ route, store }) => {
+ try {
+ store.dispatch('admin/fetchUser', route.params.id);
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.error(e);
+ }
+ }],
data() {
return {
options: {},
- files: null,
- user: null,
};
},
- async asyncData({ $axios, route }) {
- try {
- const response = await $axios.$get(`/admin/users/${route.params.id}`);
- return {
- files: response.files ? response.files : null,
- user: response.user ? response.user : null,
- };
- } catch (error) {
- console.error(error);
- return {
- files: null,
- user: null,
- };
- }
- },
+ computed: mapState({
+ user: (state) => state.admin.user,
+ }),
methods: {
promptDisableUser() {
this.$buefy.dialog.confirm({
type: 'is-danger',
- message: 'Are you sure you want to disable the account of the user that uploaded this file?',
+ message: 'Are you sure you want to disable the account of this user?',
onConfirm: () => this.disableUser(),
});
},
- async disableUser() {
- const response = await this.$axios.$post('admin/users/disable', {
- id: this.user.id,
+ promptEnableUser() {
+ this.$buefy.dialog.confirm({
+ type: 'is-danger',
+ message: 'Are you sure you want to enable the account of this user?',
+ onConfirm: () => this.enableUser(),
});
- this.$buefy.toast.open(response.message);
+ },
+ disableUser() {
+ this.$handler.executeAction('admin/disableUser', this.user.id);
+ },
+ enableUser() {
+ this.$handler.executeAction('admin/enableUser', this.user.id);
},
},
};
diff --git a/src/site/pages/dashboard/admin/users.vue b/src/site/pages/dashboard/admin/users.vue
index 269946c..bed4c2b 100644
--- a/src/site/pages/dashboard/admin/users.vue
+++ b/src/site/pages/dashboard/admin/users.vue
@@ -13,7 +13,7 @@
<div class="view-container">
<b-table
- :data="users || []"
+ :data="users"
:mobile-cards="true">
<template slot-scope="props">
<b-table-column
@@ -37,7 +37,7 @@
label="Enabled"
centered>
<b-switch
- v-model="props.row.enabled"
+ :value="props.row.enabled"
@input="changeEnabledStatus(props.row)" />
</b-table-column>
@@ -46,18 +46,18 @@
label="Admin"
centered>
<b-switch
- v-model="props.row.isAdmin"
+ :value="props.row.isAdmin"
@input="changeIsAdmin(props.row)" />
</b-table-column>
<b-table-column
field="purge"
centered>
- <button
- class="button is-primary"
+ <b-button
+ type="is-danger"
@click="promptPurgeFiles(props.row)">
Purge files
- </button>
+ </b-button>
</b-table-column>
</template>
<template slot="empty">
@@ -82,45 +82,42 @@
</template>
<script>
+import { mapState } from 'vuex';
import Sidebar from '~/components/sidebar/Sidebar.vue';
export default {
components: {
Sidebar,
},
- middleware: ['auth', 'admin'],
- data() {
- return {
- users: [],
- };
- },
- computed: {
- config() {
- return this.$store.state.config;
- },
- },
+ middleware: ['auth', 'admin', ({ route, store }) => {
+ try {
+ store.dispatch('admin/fetchUsers', route.params.id);
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.error(e);
+ }
+ }],
+ computed: mapState({
+ users: (state) => state.admin.users,
+ config: (state) => state.config,
+ }),
metaInfo() {
return { title: 'Uploads' };
},
- mounted() {
- this.getUsers();
- },
methods: {
- async getUsers() {
- const response = await this.$axios.$get('admin/users');
- this.users = response.users;
- },
async changeEnabledStatus(row) {
- const response = await this.$axios.$post(`admin/users/${row.enabled ? 'enable' : 'disable'}`, {
- id: row.id,
- });
- this.$buefy.toast.open(response.message);
+ if (row.enabled) {
+ this.$handler.executeAction('admin/disableUser', row.id);
+ } else {
+ this.$handler.executeAction('admin/enableUser', row.id);
+ }
},
async changeIsAdmin(row) {
- const response = await this.$axios.$post(`admin/users/${row.isAdmin ? 'promote' : 'demote'}`, {
- id: row.id,
- });
- this.$buefy.toast.open(response.message);
+ if (row.isAdmin) {
+ this.$handler.executeAction('admin/demoteUser', row.id);
+ } else {
+ this.$handler.executeAction('admin/promoteUser', row.id);
+ }
},
promptPurgeFiles(row) {
this.$buefy.dialog.confirm({
@@ -129,10 +126,7 @@ export default {
});
},
async purgeFiles(row) {
- const response = await this.$axios.$post('admin/users/purge', {
- id: row.id,
- });
- this.$buefy.toast.open(response.message);
+ this.$handler.executeAction('admin/purgeUserFiles', row.id);
},
},
};
diff --git a/src/site/pages/dashboard/albums/_id.vue b/src/site/pages/dashboard/albums/_id.vue
index b25762e..a909e75 100644
--- a/src/site/pages/dashboard/albums/_id.vue
+++ b/src/site/pages/dashboard/albums/_id.vue
@@ -30,11 +30,9 @@
placeholder="Search"
type="search" />
<p class="control">
- <button
- outlined
- class="button is-primary">
+ <b-button type="is-lolisafe">
Search
- </button>
+ </b-button>
</p>
</b-field>
</div>
diff --git a/src/site/pages/dashboard/index.vue b/src/site/pages/dashboard/index.vue
index 2f06c7e..08c5166 100644
--- a/src/site/pages/dashboard/index.vue
+++ b/src/site/pages/dashboard/index.vue
@@ -21,11 +21,9 @@
placeholder="Search"
type="search" />
<p class="control">
- <button
- outlined
- class="button is-primary">
+ <b-button type="is-lolisafe">
Search
- </button>
+ </b-button>
</p>
</b-field>
</div>
diff --git a/src/site/pages/dashboard/tags/index.vue b/src/site/pages/dashboard/tags/index.vue
index 10193a8..a9c5756 100644
--- a/src/site/pages/dashboard/tags/index.vue
+++ b/src/site/pages/dashboard/tags/index.vue
@@ -144,11 +144,11 @@
type="text"
@keyup.enter.native="createTag" />
<p class="control">
- <button
- class="button is-primary"
+ <b-button
+ type="is-lolisafe"
@click="createTag">
Create tags
- </button>
+ </b-button>
</p>
</b-field>
</div>
diff --git a/src/site/pages/login.vue b/src/site/pages/login.vue
index 9e5658d..569e9d9 100644
--- a/src/site/pages/login.vue
+++ b/src/site/pages/login.vue
@@ -25,20 +25,32 @@
@keyup.enter.native="login" />
</b-field>
- <p class="control has-addons is-pulled-right">
- <router-link
- v-if="config.userAccounts"
- to="/register"
- class="is-text">
- Don't have an account?
- </router-link>
- <span v-else>Registration is closed at the moment</span>
- <button
- class="button is-primary big ml1"
- @click="login">
- login
- </button>
- </p>
+ <p class="control has-addons is-pulled-right" />
+
+ <div class="level">
+ <div class="level-left">
+ <div class="level-item">
+ <router-link
+ v-if="config.userAccounts"
+ to="/register"
+ class="is-text">
+ Don't have an account?
+ </router-link>
+ <span v-else>Registration is closed at the moment</span>
+ </div>
+ </div>
+
+ <div class="level-right">
+ <p class="level-item">
+ <b-button
+ size="is-medium"
+ type="is-lolisafe"
+ @click="login">
+ Login
+ </b-button>
+ </p>
+ </div>
+ </div>
</div>
</div>
</div>
@@ -99,10 +111,7 @@ export default {
const { username, password } = this;
if (!username || !password) {
- this.$store.dispatch('alert/set', {
- text: 'Please fill both fields before attempting to log in.',
- error: true,
- });
+ this.$notifier.error('Please fill both fields before attempting to log in.');
return;
}
@@ -113,7 +122,7 @@ export default {
this.redirect();
}
} catch (e) {
- this.$store.dispatch('alert/set', { text: e.message, error: true }, { root: true });
+ this.$notifier.error(e.message);
} finally {
this.isLoading = false;
}
diff --git a/src/site/pages/register.vue b/src/site/pages/register.vue
index 1216dc1..7cf4573 100644
--- a/src/site/pages/register.vue
+++ b/src/site/pages/register.vue
@@ -31,19 +31,30 @@
@keyup.enter.native="register" />
</b-field>
- <p class="control has-addons is-pulled-right">
- <router-link
- to="/login"
- class="is-text">
- Already have an account?
- </router-link>
- <button
- class="button is-primary big ml1"
- :disabled="isLoading"
- @click="register">
- Register
- </button>
- </p>
+ <div class="level">
+ <!-- Left side -->
+ <div class="level-left">
+ <div class="level-item">
+ <router-link
+ to="/login"
+ class="is-text">
+ Already have an account?
+ </router-link>
+ </div>
+ </div>
+ <!-- Right side -->
+ <div class="level-right">
+ <p class="level-item">
+ <b-button
+ size="is-medium"
+ type="is-lolisafe"
+ :disabled="isLoading"
+ @click="register">
+ Register
+ </b-button>
+ </p>
+ </div>
+ </div>
</div>
</div>
</div>
@@ -70,32 +81,28 @@ export default {
methods: {
async register() {
if (this.isLoading) return;
+
if (!this.username || !this.password || !this.rePassword) {
- this.$store.dispatch('alert', {
- text: 'Please fill all fields before attempting to register.',
- error: true,
- });
+ this.$notifier.error('Please fill all fields before attempting to register.');
return;
}
if (this.password !== this.rePassword) {
- this.$store.dispatch('alert', {
- text: "Passwords don't match",
- error: true,
- });
+ this.$notifier.error('Passwords don\'t match');
return;
}
this.isLoading = true;
try {
- const response = await this.$axios.$post('auth/register', {
+ const response = await this.$store.dispatch('auth/register', {
username: this.username,
password: this.password,
});
- this.$store.dispatch('alert', { text: response.message });
- return this.$router.push('/login');
+ this.$notifier.success(response.message);
+ this.$router.push('/login');
+ return;
} catch (error) {
- //
+ this.$notifier.error(error.message);
} finally {
this.isLoading = false;
}
diff --git a/src/site/store/admin.js b/src/site/store/admin.js
index e69de29..2586a18 100644
--- a/src/site/store/admin.js
+++ b/src/site/store/admin.js
@@ -0,0 +1,93 @@
+export const state = () => ({
+ users: [],
+ user: {
+ id: null,
+ username: null,
+ enabled: false,
+ createdAt: null,
+ editedAt: null,
+ apiKeyEditedAt: null,
+ isAdmin: null,
+ files: [],
+ },
+ file: {},
+ settings: {},
+});
+
+export const actions = {
+ async fetchUsers({ commit }) {
+ const response = await this.$axios.$get('admin/users');
+ commit('setUsers', response);
+
+ return response;
+ },
+ async fetchUser({ commit }, id) {
+ const response = await this.$axios.$get(`/admin/users/${id}`);
+ commit('setUserInfo', response);
+
+ return response;
+ },
+ async enableUser({ commit }, id) {
+ const response = await this.$axios.$post('admin/users/enable', { id });
+
+ commit('changeUserState', { userId: id, enabled: true });
+
+ return response;
+ },
+ async disableUser({ commit }, id) {
+ const response = await this.$axios.$post('admin/users/disable', { id });
+
+ commit('changeUserState', { userId: id, enabled: false });
+
+ return response;
+ },
+ async promoteUser({ commit }, id) {
+ const response = await this.$axios.$post('admin/users/promote', { id });
+
+ commit('changeUserState', { userId: id, isAdmin: true });
+
+ return response;
+ },
+ async demoteUser({ commit }, id) {
+ const response = await this.$axios.$post('admin/users/demote', { id });
+
+ commit('changeUserState', { userId: id, isAdmin: false });
+
+ return response;
+ },
+ async purgeUserFiles(_, id) {
+ const response = await this.$axios.$post('admin/users/purge', { id });
+
+ return response;
+ },
+};
+
+export const mutations = {
+ setUsers(state, { users }) {
+ state.users = users;
+ },
+ setUserInfo(state, { user, files }) {
+ state.user = { ...state.user, ...user };
+ state.user.files = files || [];
+ },
+ changeUserState(state, { userId, enabled, isAdmin }) {
+ const foundIndex = state.users.findIndex(({ id }) => id === userId);
+ if (foundIndex > -1) {
+ if (enabled !== undefined) {
+ state.users[foundIndex].enabled = enabled;
+ }
+ if (isAdmin !== undefined) {
+ state.users[foundIndex].isAdmin = isAdmin;
+ }
+ }
+
+ if (state.user.id === userId) {
+ if (enabled !== undefined) {
+ state.user.enabled = enabled;
+ }
+ if (isAdmin !== undefined) {
+ state.user.isAdmin = isAdmin;
+ }
+ }
+ },
+};
diff --git a/src/site/store/alert.js b/src/site/store/alert.js
index ff38e09..580dcc8 100644
--- a/src/site/store/alert.js
+++ b/src/site/store/alert.js
@@ -1,12 +1,19 @@
+import AlertTypes from '~/constants/alertTypes';
+
const getDefaultState = () => ({
- text: null,
- error: false,
+ message: null,
+ type: null,
+ snackbar: false,
});
export const state = getDefaultState;
export const actions = {
set({ commit }, data) {
+ // Only exists for backwards compatibility, remove one day
+ if (data.error === true) data.type = AlertTypes.ERROR;
+ if (data.text !== undefined) data.message = data.text;
+
commit('set', data);
},
clear({ commit }) {
@@ -15,9 +22,10 @@ export const actions = {
};
export const mutations = {
- set(state, { text, error }) {
- state.text = text;
- state.error = error;
+ set(state, { message, type, snackbar }) {
+ state.message = message;
+ state.type = type;
+ state.snackbar = snackbar || false;
},
clear(state) {
Object.assign(state, getDefaultState());
diff --git a/src/site/store/auth.js b/src/site/store/auth.js
index fcc051b..465de7d 100644
--- a/src/site/store/auth.js
+++ b/src/site/store/auth.js
@@ -30,6 +30,12 @@ export const actions = {
commit('setToken', data.token);
commit('loginSuccess', { token: data.token, user: data.user });
},
+ async register(_, { username, password }) {
+ return this.$axios.$post('auth/register', {
+ username,
+ password,
+ });
+ },
async fetchCurrentUser({ commit, dispatch }) {
try {
const data = await this.$axios.$get('users/me');
@@ -83,13 +89,13 @@ export const mutations = {
state.isLoading = true;
},
loginSuccess(state, { user }) {
- this.$cookies.set('token', state.token);
+ this.$cookies.set('token', state.token, { path: '/' });
state.user = user;
state.loggedIn = true;
state.isLoading = false;
},
logout(state) {
- this.$cookies.remove('token');
+ this.$cookies.remove('token', { path: '/' });
// reset state to default
Object.assign(state, getDefaultState());
},
diff --git a/src/site/store/images.js b/src/site/store/images.js
index 3019d85..a7581e0 100644
--- a/src/site/store/images.js
+++ b/src/site/store/images.js
@@ -10,7 +10,7 @@ export const getDefaultState = () => ({
},
name: null,
downloadEnabled: false,
- filesAlbums: {},
+ filesAlbums: {}, // map of file ids with a list of album objects the file is in
});
export const state = getDefaultState;