aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/api/routes/service/configPOST.js27
-rw-r--r--src/api/structures/Setting.js6
-rw-r--r--src/api/utils/Util.js2
-rw-r--r--src/site/components/settings/JoiObject.vue16
-rw-r--r--src/site/pages/dashboard/admin/settings.vue23
-rw-r--r--src/site/store/admin.js1
-rw-r--r--src/site/store/config.js18
7 files changed, 67 insertions, 26 deletions
diff --git a/src/api/routes/service/configPOST.js b/src/api/routes/service/configPOST.js
index 28d034d..9129950 100644
--- a/src/api/routes/service/configPOST.js
+++ b/src/api/routes/service/configPOST.js
@@ -1,19 +1,36 @@
-const Joi = require('joi');
-
const Route = require('../../structures/Route');
const Util = require('../../utils/Util');
const { schema } = require('../../structures/Setting');
+const joiOptions = {
+ abortEarly: false, // include all errors
+ allowUnknown: true, // ignore unknown props
+ stripUnknown: true // remove unknown props
+};
+
class configGET extends Route {
constructor() {
super('/service/config', 'post', { adminOnly: true });
}
- run(req, res) {
+ async run(req, res) {
const { settings } = req.body;
- const validationRes = schema.validate(settings, { abortEarly: false });
- console.log(JSON.stringify(validationRes));
+ const { error, value } = schema.validate(settings, joiOptions);
+ if (error) {
+ return res.status(400).json({
+ errors: error.details.reduce((acc, v) => {
+ for (const p of v.path) {
+ acc[p] = (acc[p] || []).concat(v.message);
+ }
+ return acc;
+ }, {})
+ });
+ }
+
+ await Util.writeConfigToDb(value);
+
+ return res.status(200).json({ value });
}
}
diff --git a/src/api/structures/Setting.js b/src/api/structures/Setting.js
index ff98339..7650ccb 100644
--- a/src/api/structures/Setting.js
+++ b/src/api/structures/Setting.js
@@ -116,9 +116,9 @@ const schema = Joi.object({
.description('Allows people to create new accounts'),
// Social and sharing
- metaThemeColor: Joi.string().hex().min(3)
- .max(6)
- .default('20222b')
+ metaThemeColor: Joi.string().pattern(/^#([0-9a-f]{6}|[0-9a-f]{3})$/i).min(4)
+ .max(7)
+ .default('#20222b')
.meta({
section: Sections.SOCIAL_AND_SHARING
})
diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js
index 3780460..628be82 100644
--- a/src/api/utils/Util.js
+++ b/src/api/utils/Util.js
@@ -64,7 +64,7 @@ class Util {
static async writeConfigToDb(config) {
// TODO: Check that the config passes the joi schema validation
- if (!config || !config.key || !config.key) return;
+ if (!config || !config.key) return;
try {
config.value = JSON.stringify(config.value);
await db.table('settings').insert(config);
diff --git a/src/site/components/settings/JoiObject.vue b/src/site/components/settings/JoiObject.vue
index f77b249..8d3a803 100644
--- a/src/site/components/settings/JoiObject.vue
+++ b/src/site/components/settings/JoiObject.vue
@@ -3,7 +3,8 @@
<div v-for="[key, field] in Object.entries(settings)" :key="key">
<b-field
:label="field.flags.label"
- :message="field.flags.description"
+ :message="getErrorMessage(key) || field.flags.description"
+ :type="getValidationType(key)"
class="field"
horizontal>
<b-input
@@ -43,7 +44,6 @@
</b-field>
<!--
TODO: Add asterisk to required fields
- TODO: Implement showing errors returned by backend/joi
-->
</div>
</div>
@@ -108,6 +108,14 @@ export default {
return [...acc, ...item.allow];
}, []);
},
+ getValidationType(fieldName) {
+ if (Array.isArray(this.errors[fieldName])) return 'is-danger';
+ return null;
+ },
+ getErrorMessage(fieldName) {
+ if (Array.isArray(this.errors[fieldName])) return this.errors[fieldName].join('\n');
+ return null;
+ },
getValues() {
return this.values;
}
@@ -119,6 +127,10 @@ export default {
.field {
margin-bottom: 1em;
+
+ ::v-deep .help.is-danger {
+ white-space: pre-line;
+ }
}
.taginp {
diff --git a/src/site/pages/dashboard/admin/settings.vue b/src/site/pages/dashboard/admin/settings.vue
index 7346729..51e5ea8 100644
--- a/src/site/pages/dashboard/admin/settings.vue
+++ b/src/site/pages/dashboard/admin/settings.vue
@@ -15,7 +15,7 @@
<h5 class="title is-5 has-text-grey-lighter">
{{ sectionName }}
</h5>
- <JoiObject ref="jois" :settings="fields" />
+ <JoiObject ref="jois" :settings="fields" :errors="validationErrors" />
</div>
<div class="mb2 mt2 text-center">
@@ -42,6 +42,11 @@ export default {
JoiObject
},
middleware: ['auth', 'admin'],
+ data() {
+ return {
+ validationErrors: {}
+ };
+ },
computed: {
...mapState({
settings: state => state.admin.settings,
@@ -74,16 +79,24 @@ export default {
onConfirm: () => this.saveSettings()
});
},
- saveSettings() {
+ async saveSettings() {
// handle refs
let settings = {};
for (const joiComponent of this.$refs.jois) {
settings = { ...settings, ...joiComponent.getValues() };
}
- this.$handler.executeAction('admin/saveSettings', settings);
- // restart service
- // this.$handler.executeAction('admin/restartService');
+ try {
+ await this.$store.dispatch('admin/saveSettings', settings);
+ this.$set(this, 'validationErrors', {});
+
+ await this.$store.dispatch('config/fetchSettings');
+ this.$handler.executeAction('admin/restartService');
+ } catch (e) {
+ if (e.response?.data?.errors) {
+ this.$set(this, 'validationErrors', e.response.data.errors);
+ }
+ }
}
},
head() {
diff --git a/src/site/store/admin.js b/src/site/store/admin.js
index 0f946e9..9b1d591 100644
--- a/src/site/store/admin.js
+++ b/src/site/store/admin.js
@@ -28,7 +28,6 @@ export const actions = {
},
async saveSettings({ commit }, settings) {
const response = await this.$axios.$post('service/config', { settings });
- commit('setSettings', response);
return response;
},
diff --git a/src/site/store/config.js b/src/site/store/config.js
index 7f6bcae..124b778 100644
--- a/src/site/store/config.js
+++ b/src/site/store/config.js
@@ -10,6 +10,15 @@ export const state = () => ({
userAccounts: false
});
+export const actions = {
+ async fetchSettings({ commit }) {
+ const response = await this.$axios.$get('service/config');
+ commit('setSettings', response);
+
+ return response;
+ }
+};
+
export const mutations = {
setSettings(state, { config }) {
state.version = `v${config.version}`;
@@ -22,12 +31,3 @@ export const mutations = {
state.userAccounts = config.userAccounts;
}
};
-
-export const actions = {
- async fetchSettings({ commit }) {
- const response = await this.$axios.$get('service/config');
- commit('setSettings', response);
-
- return response;
- }
-};