Add user settings and ability to change lang

This commit is contained in:
nemunaire 2020-11-30 08:52:58 +01:00
parent 156c894e07
commit bf5f35daf3
8 changed files with 147 additions and 5 deletions

View File

@ -58,9 +58,10 @@ func init() {
}
type DisplayUser struct {
Id int64 `json:"id"`
Email string `json:"email"`
RegistrationTime *time.Time `json:"registration_time,omitempty"`
Id int64 `json:"id"`
Email string `json:"email"`
RegistrationTime *time.Time `json:"registration_time,omitempty"`
Settings happydns.UserSettings `json:"settings,omitempty"`
}
func currentUser(u *happydns.User) *DisplayUser {
@ -68,6 +69,7 @@ func currentUser(u *happydns.User) *DisplayUser {
Id: u.Id,
Email: u.Email,
RegistrationTime: u.RegistrationTime,
Settings: u.Settings,
}
}

View File

@ -58,6 +58,8 @@ func init() {
router.POST("/api/users", ApiHandler(registerUser))
router.PATCH("/api/users", ApiHandler(specialUserOperations))
router.GET("/api/users/:uid", apiAuthHandler(sameUserHandler(getUser)))
router.GET("/api/users/:uid/settings", apiAuthHandler(sameUserHandler(getUserSettings)))
router.POST("/api/users/:uid/settings", apiAuthHandler(sameUserHandler(changeUserSettings)))
router.POST("/api/users/:uid/delete", apiAuthHandler(sameUserHandler(deleteUser)))
router.POST("/api/users/:uid/email", ApiHandler(userHandler(validateUserAddress)))
router.POST("/api/users/:uid/new_password", apiAuthHandler(sameUserHandler(changePassword)))
@ -254,6 +256,33 @@ func getUser(opts *config.Options, req *RequestResources, _ io.Reader) Response
}
}
func getUserSettings(opts *config.Options, req *RequestResources, _ io.Reader) Response {
return APIResponse{
response: req.User.Settings,
}
}
func changeUserSettings(opts *config.Options, req *RequestResources, body io.Reader) Response {
var us happydns.UserSettings
if err := json.NewDecoder(body).Decode(&us); err != nil {
return APIErrorResponse{
err: err,
}
}
req.User.Settings = us
if err := storage.MainStore.UpdateUser(req.User); err != nil {
return APIErrorResponse{
err: err,
}
}
return APIResponse{
response: req.User.Settings,
}
}
type passwordForm struct {
Current string
Password string

View File

@ -156,6 +156,9 @@ export default {
(response) => {
sessionStorage.loggedUser = JSON.stringify(response.data)
this.loggedUser = response.data
if (this.loggedUser.settings && this.loggedUser.settings.language && this.$i18n.locale !== this.loggedUser.settings.language) {
this.$i18n.locale = this.loggedUser.settings.language
}
},
(error) => {
this.loggedUser = null

View File

@ -19,5 +19,6 @@ function loadLocaleMessages () {
export default new VueI18n({
locale: process.env.VUE_APP_I18N_LOCALE || 'en',
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
messages: loadLocaleMessages()
messages: loadLocaleMessages(),
silentTranslationWarn: process.env.NODE_ENV === 'production'
})

View File

@ -157,6 +157,7 @@
"registration": "Registration problem",
"rr-add": "An error occurs when trying to add RR to the zone:",
"rr-delete": "An error occurs when trying to delete RR in the zone:",
"settings-change": "Unable to change your settings",
"source-delete": "Something went wrong during source deletion",
"session": {
"title": "Authentication timeout",
@ -216,6 +217,13 @@
"delete": "@:common.delete service",
"update": "Update service"
},
"settings": {
"language": "Language",
"save": "Save settings",
"title": "Settings",
"success": "Continue to enjoy happyDNS.",
"success-change": "Your settings has been saved."
},
"source": {
"available-types": "Resources Types available",
"delete": "@:common.delete this @:source.kind",

View File

@ -33,6 +33,26 @@
<template>
<b-container class="my-4">
<h2 id="settings">
{{ $t('settings.title') }}
</h2>
<b-row>
<b-card v-if="settings" class="offset-md-2 col-8">
<b-form @submit.stop.prevent="saveSettings">
<b-form-group
:label="$t('settings.language')"
label-for="language-select"
>
<b-form-select id="language-select" v-model="settings.language" :options="languages" />
</b-form-group>
<div class="d-flex justify-content-around">
<b-button type="submit" variant="primary">
{{ $t('settings.save') }}
</b-button>
</div>
</b-form>
</b-card>
</b-row>
<h2 id="password-change">
{{ $t('password.change') }}
</h2>
@ -151,6 +171,7 @@ export default {
return {
deletePassword: '',
loggedUser: null,
settings: null,
signupForm: {
current: '',
password: '',
@ -161,7 +182,13 @@ export default {
computed: {
isLoading () {
return this.loggedUser != null
return this.loggedUser != null || this.settings != null
},
languages () {
return {
en: 'English',
fr: 'Français'
}
}
},
@ -170,6 +197,11 @@ export default {
.then(
(response) => {
this.loggedUser = response.data
axios.get('/api/users/' + encodeURIComponent(this.loggedUser.id.toString(16)) + '/settings')
.then(
(response) => {
this.settings = response.data
})
})
},
@ -205,6 +237,31 @@ export default {
})
},
saveSettings () {
axios
.post('/api/users/' + encodeURIComponent(this.loggedUser.id.toString(16)) + '/settings', this.settings)
.then(
response => {
this.settings = response.data
this.$root.$bvToast.toast(this.$t('settings.success'), {
title: this.$t('settings.success-change'),
autoHideDelay: 5000,
variant: 'success',
toaster: 'b-toaster-content-right'
})
},
error => {
this.$bvToast.toast(
error.response.data.errmsg, {
title: this.$t('errors.settings-change'),
autoHideDelay: 5000,
variant: 'danger',
toaster: 'b-toaster-content-right'
}
)
})
},
sendChPassword () {
axios
.post('/api/users/' + encodeURIComponent(this.loggedUser.id.toString(16)) + '/new_password', this.signupForm)

View File

@ -62,6 +62,9 @@ type User struct {
// PasswordRecoveryKey is a string generated when User asks to recover its account.
PasswordRecoveryKey []byte `json:",omitempty"`
// Settings holds the settings for an account.
Settings UserSettings `json:settings,omitempty`
}
// Users is a group of User.

39
model/usersettings.go Normal file
View File

@ -0,0 +1,39 @@
// Copyright or © or Copr. happyDNS (2020)
//
// contact@happydns.org
//
// This software is a computer program whose purpose is to provide a modern
// interface to interact with DNS systems.
//
// This software is governed by the CeCILL license under French law and abiding
// by the rules of distribution of free software. You can use, modify and/or
// redistribute the software under the terms of the CeCILL license as
// circulated by CEA, CNRS and INRIA at the following URL
// "http://www.cecill.info".
//
// As a counterpart to the access to the source code and rights to copy, modify
// and redistribute granted by the license, users are provided only with a
// limited warranty and the software's author, the holder of the economic
// rights, and the successive licensors have only limited liability.
//
// In this respect, the user's attention is drawn to the risks associated with
// loading, using, modifying and/or developing or reproducing the software by
// the user in light of its specific status of free software, that may mean
// that it is complicated to manipulate, and that also therefore means that it
// is reserved for developers and experienced professionals having in-depth
// computer knowledge. Users are therefore encouraged to load and test the
// software's suitability as regards their requirements in conditions enabling
// the security of their systems and/or data to be ensured and, more generally,
// to use and operate it in the same conditions as regards security.
//
// The fact that you are presently reading this means that you have had
// knowledge of the CeCILL license and that you accept its terms.
package happydns
import ()
// UserSettings represents the settings for an account.
type UserSettings struct {
Language string `json:"language,omitempty"`
}