Mercurial > gemma
comparison client/src/components/usermanagement/Userdetail.vue @ 1558:0ded4c56978e
refac: component filestructure. remove admin/map hierarchy
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Wed, 12 Dec 2018 09:22:20 +0100 |
parents | client/src/components/admin/usermanagement/Userdetail.vue@a679f765d7b0 |
children | f2d24dceecc7 |
comparison
equal
deleted
inserted
replaced
1557:62171cd9a42b | 1558:0ded4c56978e |
---|---|
1 <template> | |
2 <div class="userdetails mt-3 shadow fadeIn animated card"> | |
3 <h6 | |
4 class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center" | |
5 > | |
6 {{ this.cardHeader }} | |
7 <span @click="closeDetailview" class="closebutton"> | |
8 <font-awesome-icon icon="times"></font-awesome-icon> | |
9 </span> | |
10 </h6> | |
11 <div class="card-body"> | |
12 <form @submit.prevent="save" class="ml-3"> | |
13 <div class="formfields"> | |
14 <div v-if="currentUser.isNew" class="form-group row"> | |
15 <label for="user"> <translate>Username</translate> </label> | |
16 <input | |
17 type="user" | |
18 :placeholder="userNamePlaceholder" | |
19 class="form-control form-control-sm" | |
20 id="user" | |
21 aria-describedby="userHelp" | |
22 v-model="currentUser.user" | |
23 /> | |
24 <div v-show="errors.user" class="text-danger"> | |
25 <small> | |
26 <font-awesome-icon | |
27 icon="exclamation-triangle" | |
28 ></font-awesome-icon> | |
29 {{ errors.user }} | |
30 </small> | |
31 </div> | |
32 </div> | |
33 <div class="form-group row"> | |
34 <label for="country"> <translate>Country</translate> </label> | |
35 <select | |
36 class="form-control form-control-sm" | |
37 v-on:change="validateCountry" | |
38 v-model="currentUser.country" | |
39 > | |
40 <option disabled value> | |
41 <translate>Please select one</translate> | |
42 </option> | |
43 <option | |
44 v-for="country in countries" | |
45 v-bind:value="country" | |
46 v-bind:key="country" | |
47 >{{ country }}</option | |
48 > | |
49 </select> | |
50 <div v-show="errors.country" class="text-danger"> | |
51 <small> | |
52 <font-awesome-icon | |
53 icon="exclamation-triangle" | |
54 ></font-awesome-icon> | |
55 {{ errors.country }} | |
56 </small> | |
57 </div> | |
58 </div> | |
59 <div class="form-group row"> | |
60 <label for="email"> <translate>Email address</translate> </label> | |
61 <input | |
62 type="email" | |
63 v-on:change="validateEmailaddress" | |
64 class="form-control form-control-sm" | |
65 id="email" | |
66 aria-describedby="emailHelp" | |
67 v-model="currentUser.email" | |
68 /> | |
69 <div v-show="errors.email" class="text-danger"> | |
70 <small> | |
71 <font-awesome-icon | |
72 icon="exclamation-triangle" | |
73 ></font-awesome-icon> | |
74 {{ errors.email }} | |
75 </small> | |
76 </div> | |
77 </div> | |
78 <div class="form-group row"> | |
79 <label for="role"> <translate>Role</translate> </label> | |
80 <select | |
81 class="form-control form-control-sm" | |
82 v-on:change="validateRole" | |
83 v-model="currentUser.role" | |
84 > | |
85 <option disabled value> | |
86 <translate>Please select one</translate> | |
87 </option> | |
88 <option value="sys_admin"> | |
89 <translate>Sysadmin</translate> | |
90 </option> | |
91 <option value="waterway_admin"> | |
92 <translate>Waterway Admin</translate> | |
93 </option> | |
94 <option value="waterway_user"> | |
95 <translate>Waterway User</translate> | |
96 </option> | |
97 </select> | |
98 <div v-show="errors.role" class="text-danger"> | |
99 <small> | |
100 <font-awesome-icon | |
101 icon="exclamation-triangle" | |
102 ></font-awesome-icon> | |
103 {{ errors.role }} | |
104 </small> | |
105 </div> | |
106 </div> | |
107 <div class="form-group row"> | |
108 <PasswordField | |
109 @fieldchange="passwordChanged" | |
110 :placeholder="passwordPlaceholder" | |
111 :label="passwordLabel" | |
112 :passworderrors="errors.password" | |
113 ></PasswordField> | |
114 </div> | |
115 <div class="form-group row"> | |
116 <PasswordField | |
117 @fieldchange="passwordReChanged" | |
118 :placeholder="passwordRePlaceholder" | |
119 :label="passwordReLabel" | |
120 :passworderrors="errors.passwordre" | |
121 ></PasswordField> | |
122 </div> | |
123 </div> | |
124 <div> | |
125 <button | |
126 type="submit" | |
127 :disabled="submitted" | |
128 class="shadow-sm btn btn-info submit-button" | |
129 > | |
130 <translate>Submit</translate> | |
131 </button> | |
132 </div> | |
133 <div | |
134 v-if="currentUser.role != 'waterway_user'" | |
135 class="form-group row d-flex flex-row justify-content-start mailbutton" | |
136 > | |
137 <a @click="sendTestMail" class="btn btn-light"> | |
138 <font-awesome-icon icon="paper-plane"></font-awesome-icon> | |
139 <translate>Send testmail</translate> | |
140 </a> | |
141 <div v-if="mailsent"><translate>Mail was sent</translate></div> | |
142 </div> | |
143 </form> | |
144 </div> | |
145 </div> | |
146 </template> | |
147 | |
148 <style lang="scss" scoped> | |
149 .submit-button { | |
150 position: absolute; | |
151 right: $offset; | |
152 bottom: $offset; | |
153 } | |
154 .mailbutton { | |
155 width: 12vw; | |
156 position: absolute; | |
157 left: $large-offset; | |
158 bottom: 0; | |
159 } | |
160 | |
161 .formfields { | |
162 width: 60%; | |
163 } | |
164 | |
165 .userdetails { | |
166 height: 600px; | |
167 margin-top: $offset; | |
168 margin-left: $offset; | |
169 margin-right: $offset; | |
170 } | |
171 | |
172 form { | |
173 font-size: $smaller; | |
174 } | |
175 </style> | |
176 | |
177 <script> | |
178 /* This is Free Software under GNU Affero General Public License v >= 3.0 | |
179 * without warranty, see README.md and license for details. | |
180 * | |
181 * SPDX-License-Identifier: AGPL-3.0-or-later | |
182 * License-Filename: LICENSES/AGPL-3.0.txt | |
183 * | |
184 * Copyright (C) 2018 by via donau | |
185 * – Österreichische Wasserstraßen-Gesellschaft mbH | |
186 * Software engineering by Intevation GmbH | |
187 * | |
188 * Author(s): | |
189 * Thomas Junk <thomas.junk@intevation.de> | |
190 */ | |
191 import { HTTP } from "../../lib/http"; | |
192 import { displayError } from "../../lib/errors.js"; | |
193 import { mapState } from "vuex"; | |
194 import PasswordField from "./Passwordfield"; | |
195 | |
196 const emptyErrormessages = () => { | |
197 return { | |
198 email: "", | |
199 country: "", | |
200 role: "", | |
201 password: "", | |
202 passwordre: "" | |
203 }; | |
204 }; | |
205 | |
206 const isEmailValid = email => { | |
207 /** | |
208 * | |
209 * For convenience purposes the same regex used as in the go code | |
210 * cf. types.go | |
211 * | |
212 */ | |
213 // eslint-disable-next-line | |
214 return /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/.test( | |
215 email | |
216 ); | |
217 }; | |
218 | |
219 const violatedPasswordRules = password => { | |
220 return ( | |
221 // rules according to issue 70 | |
222 password.length < 7 || | |
223 /\W/.test(password) == false || | |
224 /\d/.test(password) == false | |
225 ); | |
226 }; | |
227 | |
228 export default { | |
229 name: "userdetail", | |
230 components: { | |
231 PasswordField | |
232 }, | |
233 data() { | |
234 return { | |
235 mailsent: false, | |
236 passwordLabel: this.$gettext("Password"), | |
237 passwordReLabel: this.$gettext("Repeat Password"), | |
238 passwordPlaceholder: this.$gettext("password"), | |
239 passwordRePlaceholder: this.$gettext("password again"), | |
240 password: "", | |
241 passwordre: "", | |
242 currentUser: {}, | |
243 path: null, | |
244 submitted: false, | |
245 errors: { | |
246 email: "", | |
247 country: "", | |
248 role: "", | |
249 password: "", | |
250 passwordre: "" | |
251 } | |
252 }; | |
253 }, | |
254 mounted() { | |
255 this.currentUser = { ...this.user }; | |
256 this.path = this.user.name; | |
257 }, | |
258 watch: { | |
259 user() { | |
260 this.currentUser = { ...this.user }; | |
261 this.path = this.user.name; | |
262 this.clearPassword(); | |
263 this.clearErrors(); | |
264 } | |
265 }, | |
266 computed: { | |
267 cardHeader() { | |
268 if (this.currentUser.isNew) return "N.N"; | |
269 return this.currentUser.user; | |
270 }, | |
271 userNamePlaceholder() { | |
272 if (this.currentUser.isNew) return "N.N"; | |
273 return ""; | |
274 }, | |
275 ...mapState("application", ["countries"]), | |
276 user() { | |
277 return this.$store.getters["usermanagement/currentUser"]; | |
278 }, | |
279 isFormValid() { | |
280 return ( | |
281 isEmailValid(this.currentUser.email) && | |
282 this.currentUser.country && | |
283 this.password === this.passwordre && | |
284 (this.password === "" || !violatedPasswordRules(this.password)) | |
285 ); | |
286 } | |
287 }, | |
288 methods: { | |
289 sendTestMail() { | |
290 if (this.mailsent) return; | |
291 HTTP.get("/testmail/" + this.currentUser.user, { | |
292 headers: { | |
293 "X-Gemma-Auth": localStorage.getItem("token"), | |
294 "Content-type": "text/xml; charset=UTF-8" | |
295 } | |
296 }) | |
297 .then(() => { | |
298 this.mailsent = true; | |
299 }) | |
300 .catch(error => { | |
301 this.loginFailed = true; | |
302 this.submitted = false; | |
303 const { status, data } = error.response; | |
304 displayError({ | |
305 title: this.$gettext("Backend Error"), | |
306 message: `${status}: ${data.message || data}` | |
307 }); | |
308 }); | |
309 }, | |
310 passwordChanged(value) { | |
311 this.password = value; | |
312 this.validatePassword(); | |
313 }, | |
314 passwordReChanged(value) { | |
315 this.passwordre = value; | |
316 this.validatePassword(); | |
317 }, | |
318 clearErrors() { | |
319 this.errors = emptyErrormessages(); | |
320 }, | |
321 clearPassword() { | |
322 this.password = ""; | |
323 this.passwordre = ""; | |
324 }, | |
325 closeDetailview() { | |
326 this.$store.commit("usermanagement/clearCurrentUser"); | |
327 this.$store.commit("usermanagement/setUserDetailsInvisible"); | |
328 }, | |
329 validateCountry() { | |
330 this.errors.country = this.currentUser.country | |
331 ? "" | |
332 : this.$gettext("Please choose a country"); | |
333 }, | |
334 validateRole() { | |
335 this.errors.role = this.currentUser.role | |
336 ? "" | |
337 : this.$gettext("Please choose a role"); | |
338 }, | |
339 validatePassword() { | |
340 this.errors.passwordre = | |
341 this.password === this.passwordre | |
342 ? "" | |
343 : this.$gettext("Passwords do not match!"); | |
344 this.errors.password = | |
345 this.password === "" || !violatedPasswordRules(this.password) | |
346 ? "" | |
347 : this.$gettext( | |
348 "Password should at least be 8 char long including 1 digit and 1 special char like $" | |
349 ); | |
350 }, | |
351 validateEmailaddress() { | |
352 this.errors.email = isEmailValid(this.currentUser.email) | |
353 ? "" | |
354 : this.$gettext("invalid email"); | |
355 }, | |
356 validate() { | |
357 this.validateCountry(); | |
358 this.validateRole(); | |
359 this.validatePassword(); | |
360 this.validateEmailaddress(); | |
361 }, | |
362 save() { | |
363 this.validate(); | |
364 if (!this.isFormValid) return; | |
365 if (this.password) this.currentUser.password = this.password; | |
366 this.submitted = true; | |
367 this.$store | |
368 .dispatch("usermanagement/saveCurrentUser", { | |
369 path: this.user.user, | |
370 user: this.currentUser | |
371 }) | |
372 .then(() => { | |
373 this.submitted = false; | |
374 this.$store.dispatch("usermanagement/loadUsers").catch(error => { | |
375 const { status, data } = error.response; | |
376 displayError({ | |
377 title: this.$gettext("Backend Error"), | |
378 message: `${status}: ${data.message || data}` | |
379 }); | |
380 }); | |
381 }) | |
382 .catch(error => { | |
383 this.submitted = false; | |
384 const { status, data } = error.response; | |
385 displayError({ | |
386 title: this.$gettext("Error while saving user"), | |
387 message: `${status}: ${data.message || data}` | |
388 }); | |
389 }); | |
390 } | |
391 } | |
392 }; | |
393 </script> |