@sowell/quasar-app-extension-auth 0.2.1 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,4 +19,4 @@ jobs:
19
19
  uses: cypress-io/github-action@v2
20
20
  with:
21
21
  working-directory: dev
22
- command: yarn test:e2e:ci
22
+ command: yarn test
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sowell/quasar-app-extension-auth",
3
- "version": "0.2.1",
3
+ "version": "0.2.5",
4
4
  "description": "A Quasar app extension to manage Authentication",
5
5
  "main": "src/index.js",
6
6
  "repository": "https://github.com/sowell-ai/quasar.extension.auth",
@@ -8,8 +8,9 @@
8
8
  "lint": "cd dev && eslint --ext .js,.ts,.vue ./",
9
9
  "dev": "cd dev && quasar dev",
10
10
  "dep": "cd dev && yarn",
11
- "test:e2e": "cd dev && yarn && cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress open\"",
12
- "test:e2e:ci": "cd dev && yarn && cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress run\""
11
+ "test:link": "cd dev && yarn test:link",
12
+ "test:browser": "cd dev && yarn test:browser",
13
+ "test": "cd dev && yarn test"
13
14
  },
14
15
  "keywords": [],
15
16
  "author": "SoWell SAS",
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="39.779" height="70.275" viewBox="0 0 39.779 70.275">
2
+ <g id="Logo_Sowell_bleu" data-name="Logo Sowell bleu" transform="translate(-403.55 -422.444)">
3
+ <path id="Tracé_455" data-name="Tracé 455" d="M440.01,457.9l-9.08-19.791a4,4,0,0,0-5.243-2.083h0a4,4,0,0,0-2.083,5.243l4.939,11.466a19.894,19.894,0,0,0-20.414,6.519,4.349,4.349,0,0,0-.21,1.945c0,2.45,2.091,4.11,4.578,4.11a4.524,4.524,0,0,0,3.021-1.149c1.98-1.693,5.1-3.689,7.905-3.689a11.327,11.327,0,1,1-11.3,12.2c.065-1.637.144-2.7.144-2.7a4.326,4.326,0,0,0-8.417-1.406l-.018-.009c-.006.039-.012.078-.019.118a4.317,4.317,0,0,0-.2,1.3c0,.072,0,.149.006.223q-.072.862-.076,1.74a19.814,19.814,0,0,0,5.441,13.66l14.429,19.43,15.461-20.608h0a21.785,21.785,0,0,0,4.413-12.484C443.729,465.218,440.01,457.9,440.01,457.9Z" transform="translate(0 -12.306)" fill="#40c4ff"/>
4
+ <path id="Tracé_456" data-name="Tracé 456" d="M802.618,443.124l-.884-17.044a4,4,0,0,0-4.326-3.622h0a3.985,3.985,0,0,0-2.968,1.771Z" transform="translate(-362.817 0)" fill="#40c4ff"/>
5
+ </g>
6
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg id="noun_Error_1688921" xmlns="http://www.w3.org/2000/svg" width="63" height="63" viewBox="0 0 63 63">
2
+ <circle id="Ellipse_90" data-name="Ellipse 90" cx="31.5" cy="31.5" r="31.5" fill="#f2d7d7"/>
3
+ <path id="Tracé_727" data-name="Tracé 727" d="M14.477,29.163h0A4.078,4.078,0,0,1,10.5,25.186V9.277A4.078,4.078,0,0,1,14.477,5.3h0a4.078,4.078,0,0,1,3.977,3.977V25.186A4.078,4.078,0,0,1,14.477,29.163Z" transform="translate(17.34 8.753)" fill="#ce0101"/>
4
+ <path id="Tracé_728" data-name="Tracé 728" d="M14.477,23.654h0A4.078,4.078,0,0,1,10.5,19.677h0A4.078,4.078,0,0,1,14.477,15.7h0a4.078,4.078,0,0,1,3.977,3.977h0A4.078,4.078,0,0,1,14.477,23.654Z" transform="translate(17.34 25.927)" fill="#ce0101"/>
5
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="62" height="62" viewBox="0 0 62 62">
2
+ <g id="noun_validation_1683882" transform="translate(0.1 -0.4)">
3
+ <circle id="Ellipse_89" data-name="Ellipse 89" cx="31" cy="31" r="31" transform="translate(-0.1 0.4)" fill="#dff2d6"/>
4
+ <path id="Tracé_724" data-name="Tracé 724" d="M36.165,13.221a1.189,1.189,0,0,0-1.868.311L21.84,31.906l-8.253-8.253a1.169,1.169,0,0,0-1.868.156,1.667,1.667,0,0,0,.156,2.18l9.5,9.342h0c.156.156.156.156.311.156a.152.152,0,0,1,.156.156c.156,0,.311.156.623.156h0c.156,0,.467,0,.467-.156l.156-.156c.156,0,.156-.156.311-.156h0L36.632,15.713A2.752,2.752,0,0,0,36.165,13.221Z" transform="translate(6.399 6.953)" fill="#3b9843"/>
5
+ </g>
6
+ </svg>
@@ -5,15 +5,17 @@ import { BootInterface } from "../interfaces";
5
5
 
6
6
  export default boot(({ router, store }: BootInterface) => {
7
7
  const {
8
- "@sowell/auth": { LOCAL_LOGIN_ROUTE, LOCAL_CHECK_CODE_ROUTE },
8
+ "@sowell/auth": { LOCAL_LOGIN_ROUTE },
9
9
  } = prompts;
10
10
 
11
11
  router.beforeEach((to, from, next) => {
12
- const token = store.state.auth.token;
12
+ let isValid = store.getters["token/getIsValid"];
13
+ let token = store.getters["token/getRaw"];
13
14
  if (
14
- !token &&
15
+ (!isValid ||
16
+ !token ) &&
15
17
  to.path !== LOCAL_LOGIN_ROUTE &&
16
- to.path !== LOCAL_CHECK_CODE_ROUTE
18
+ to.name !== "update_password"
17
19
  ) {
18
20
  next(LOCAL_LOGIN_ROUTE);
19
21
  } else {
package/src/boot/store.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  //@ts-ignore
2
2
  import { boot } from "quasar/wrappers";
3
3
  import { BootInterface } from "../interfaces";
4
- import authModule from "../store";
4
+ import tokenModule from "../store";
5
5
 
6
6
  export default boot(({ app, store }: BootInterface) => {
7
7
  // Register store module
8
- store.registerModule("auth", authModule);
8
+ store.registerModule("token", tokenModule);
9
9
  app.provide("$store", store);
10
10
  });
@@ -0,0 +1,81 @@
1
+ <template>
2
+ <q-card style="min-width: 350px; border-radius: 30px">
3
+ <q-toolbar>
4
+ <q-space />
5
+ <q-btn
6
+ class="q-pt-md"
7
+ flat
8
+ dense
9
+ color="primary"
10
+ icon="close"
11
+ v-close-popup
12
+ />
13
+ </q-toolbar>
14
+ <q-card-section class="text-center">
15
+ <img v-if="sendEmailSuccess" src="../../assets/success.svg" />
16
+ <img v-else src="../../assets/error.svg" />
17
+ </q-card-section>
18
+
19
+ <q-card-section class="q-pt-none q-pl-lg q-pr-lg">
20
+ <div
21
+ class="text-subtitle1 q-mt-sm text-center"
22
+ style="font-size: 14px; font-weigth: 300; line-height: 20px"
23
+ data-cy="resetMessage"
24
+ >
25
+ {{
26
+ sendEmailSuccess ? $t("auth.emailSent") : $t("auth.emailNotRecognize")
27
+ }}
28
+ </div>
29
+ <div
30
+ class="q-mt-sm text-center q-mb-xl"
31
+ style="font-size: 15px; color: #737676"
32
+ v-if="sendEmailSuccess"
33
+ >
34
+ {{ emailResetPassword }}
35
+ </div>
36
+ </q-card-section>
37
+ <q-card-actions class="q-ml-lg q-mr-lg q-mb-lg">
38
+ <q-btn
39
+ v-if="!sendEmailSuccess"
40
+ data-cy="submit-login"
41
+ rounded
42
+ :label="$t('auth.reSend')"
43
+ color="primary"
44
+ padding="10px 5px 10px 5px"
45
+ :loading="loading"
46
+ no-caps
47
+ type="submit"
48
+ @click="reSendEmail"
49
+ class="full-width"
50
+ />
51
+ </q-card-actions>
52
+ </q-card>
53
+ </template>
54
+
55
+ <script lang="ts">
56
+ import { defineComponent } from "vue";
57
+
58
+ export default defineComponent({
59
+ props: {
60
+ emailResetPassword: {
61
+ type: String,
62
+ required: true,
63
+ },
64
+ sendEmailSuccess: {
65
+ type: Boolean,
66
+ required: true,
67
+ },
68
+ loading: {
69
+ type: Boolean,
70
+ required: true,
71
+ },
72
+ },
73
+ emit: ["resetPassword"],
74
+ setup(props: any, { emit }: any) {
75
+ const reSendEmail = () => {
76
+ emit("reSendEmail");
77
+ };
78
+ return { reSendEmail };
79
+ },
80
+ });
81
+ </script>
@@ -0,0 +1,69 @@
1
+ <template>
2
+ <q-card style="min-width: 350px; border-radius: 30px">
3
+ <q-toolbar>
4
+ <q-space />
5
+ <q-btn
6
+ class="q-pt-md"
7
+ flat
8
+ dense
9
+ color="primary"
10
+ icon="close"
11
+ v-close-popup
12
+ />
13
+ </q-toolbar>
14
+ <q-card-section>
15
+ <p
16
+ class="resetPasswordTitle text-center"
17
+ style="font-size: 20px; font-weigth: 600"
18
+ >
19
+ {{ $t("auth.tapEmail") }}
20
+ </p>
21
+ </q-card-section>
22
+
23
+ <q-card-section class="q-pt-none q-pl-lg q-pr-lg">
24
+ <q-input
25
+ v-model="email"
26
+ dense
27
+ outlined
28
+ data-cy="emailReset"
29
+ :placeholder="$t('auth.email')"
30
+ autofocus
31
+ />
32
+ <div
33
+ class="text-subtitle1 q-mt-sm"
34
+ style="font-size: 13px; font-weigth: 300; line-height: 20px"
35
+ >
36
+ {{ $t("auth.resetText") }}
37
+ </div>
38
+ </q-card-section>
39
+
40
+ <q-card-actions align="center" class="q-ml-lg q-mr-lg q-mb-lg">
41
+ <q-btn
42
+ rounded
43
+ color="primary"
44
+ data-cy="sendEmails"
45
+ no-caps
46
+ :label="$t('common.reset')"
47
+ class="btn-min full-width"
48
+ @click="sendEmail"
49
+ v-close-popup
50
+ />
51
+ </q-card-actions>
52
+ </q-card>
53
+ </template>
54
+
55
+ <script lang="ts">
56
+ // @ts-ignore
57
+ import { defineComponent, ref } from "vue";
58
+
59
+ export default defineComponent({
60
+ emit: ["resetPassword"],
61
+ setup(props: any, { emit }: any) {
62
+ const email = ref("");
63
+ const sendEmail = () => {
64
+ emit("resetPassword", email.value);
65
+ };
66
+ return { sendEmail, email };
67
+ },
68
+ });
69
+ </script>
@@ -1,146 +1,130 @@
1
1
  <template>
2
2
  <q-layout>
3
- <q-page-container>
4
- <q-page class="flex flex-center">
5
- <q-card square>
6
- <q-card-section>
7
- <div class="text-h5 text-center head">
8
- {{ $t("auth.title") }}
9
- </div>
10
- </q-card-section>
11
-
12
- <q-form class="q-gutter-md" @submit="onSubmit">
13
- <q-card-section>
14
- <q-input
15
- data-cy="email"
16
- v-model.trim="email"
17
- type="email"
18
- :label="$t('auth.email')"
19
- :rules="validations['email']"
20
- lazy-rules
21
- autofocus
22
- rounded
23
- outlined
24
- dense
25
- class="full-width q-mb-md"
26
- />
27
- <q-input
28
- data-cy="password"
29
- v-model="password"
30
- :type="showPassword ? 'text' : 'password'"
31
- :label="$t('auth.password')"
32
- :rules="validations['password']"
33
- lazy-rules
34
- rounded
35
- outlined
36
- dense
37
- class="full-width q-mb-md"
38
- >
39
- <template #append>
40
- <q-icon
41
- :name="showPassword ? 'visibility' : 'visibility_off'"
42
- class="cursor-pointer"
43
- @click="showPassword = !showPassword"
44
- />
45
- </template>
46
- </q-input>
47
- </q-card-section>
48
- <div class="forgottenPass">
49
- <q-btn
50
- @click="forgottenPassword = true"
51
- no-caps
52
- flat
53
- :label="$t('auth.forgottenPassword')"
54
- />
55
- </div>
56
- <q-card-actions>
57
- <q-btn
58
- data-cy="submit-login"
59
- rounded
60
- :label="$t('auth.login')"
61
- color="primary"
62
- :loading="loading"
63
- type="submit"
64
- class="full-width"
65
- :disable="isSubmitBtnDisabled()"
66
- />
67
- </q-card-actions>
68
- </q-form>
69
- </q-card>
70
- <div>
71
- <q-dialog v-model="forgottenPassword" persistent>
72
- <q-card style="min-width: 350px">
73
- <q-card-section>
74
- <p class="resetPasswordTitle">
75
- {{ $t("auth.tapEmail") }}
76
- </p>
77
- </q-card-section>
78
-
79
- <q-card-section class="q-pt-none">
80
- <q-input
81
- v-model="emailResetPassword"
82
- dense
83
- rounded
84
- outlined
85
- :placeholder="$t('auth.email')"
86
- autofocus
87
- />
88
- </q-card-section>
89
-
90
- <q-card-actions align="right">
91
- <q-btn
92
- outline
93
- rounded
94
- :label="$t('common.cancel')"
95
- class="btn-min"
96
- v-close-popup
97
- />
98
- <q-btn
99
- rounded
100
- color="primary"
101
- :label="$t('common.send')"
102
- class="btn-min"
103
- @click="resetPassword"
104
- />
105
- </q-card-actions>
106
- </q-card>
107
- </q-dialog>
3
+ <q-page class="column justify-center items-center">
4
+ <div class="q-pa-xl">
5
+ <div class="column justify-ceter">
6
+ <img src="../../assets/Logo.svg" class="q-mb-sm" />
7
+ <div class="text-subtitle1 text-center head" style="font-weight: 600">
8
+ {{ $t("auth.title") }}
9
+ </div>
10
+ <div class="q-mt-xl q-mb-lg text-subtitle1" style="font-size: 14px">
11
+ {{ $t("auth.loginHelp") }}
12
+ </div>
108
13
  </div>
109
- </q-page>
110
- </q-page-container>
14
+ <q-form @submit="onSubmit">
15
+ <q-input
16
+ data-cy="email"
17
+ v-model.trim="email"
18
+ type="email"
19
+ :label="$t('auth.email')"
20
+ :rules="validations['email']"
21
+ lazy-rules
22
+ dense
23
+ :input-style="{ fontSize: '14px', fontWeight: '500' }"
24
+ />
25
+ <q-input
26
+ data-cy="password"
27
+ v-model="password"
28
+ :type="showPassword ? 'text' : 'password'"
29
+ :label="$t('auth.password')"
30
+ :rules="validations['password']"
31
+ lazy-rules
32
+ dense
33
+ :input-style="{ fontSize: '14px', fontWeight: '600' }"
34
+ >
35
+ <template #append>
36
+ <q-icon
37
+ :name="showPassword ? 'visibility' : 'visibility_off'"
38
+ class="cursor-pointer"
39
+ @click="showPassword = !showPassword"
40
+ />
41
+ </template>
42
+ </q-input>
43
+ <div
44
+ class="q-mb-xl"
45
+ @click="forgottenPassword = true"
46
+ data-cy="forgot-password"
47
+ style="color: #40c4ff; font-weight: 500; cursor: pointer"
48
+ >
49
+ {{ $t("auth.forgottenPassword") }}
50
+ </div>
51
+ <q-btn
52
+ data-cy="submit-login"
53
+ rounded
54
+ :label="$t('auth.login')"
55
+ style="background: #40c4ff"
56
+ no-caps
57
+ text-color="white"
58
+ :loading="loading"
59
+ type="submit"
60
+ class="full-width q-mt-lg"
61
+ :disable="isSubmitBtnDisabled()"
62
+ />
63
+ </q-form>
64
+ </div>
65
+ <div>
66
+ <q-dialog v-model="forgottenPassword" persistent>
67
+ <send-email @resetPassword="resetPassword" />
68
+ </q-dialog>
69
+ <q-dialog v-model="isReset" persistent>
70
+ <sowell-message
71
+ :emailResetPassword="emailResetPassword"
72
+ :sendEmailSuccess="sendEmailSuccess"
73
+ :loading="loading"
74
+ @reSendEmail="resetPassword"
75
+ />
76
+ </q-dialog>
77
+ </div>
78
+ </q-page>
111
79
  </q-layout>
112
80
  </template>
113
81
 
114
82
  <script lang="ts">
115
- //import prompts from "app/quasar.extensions.json";
116
83
  import isEmail from "validator/es/lib/isEmail";
117
84
  import { defineComponent, ref, onMounted } from "vue";
118
85
  import { $api, $prompts, $router, $store } from "../../injects";
119
86
  import { useQuasar } from "quasar";
120
87
  import { useI18n } from "vue-i18n";
121
88
  import { AxiosError, AxiosResponse } from "axios";
89
+ import prompts from "app/quasar.extensions.json";
90
+ import SendEmail from "../dialogs/SendEmail.vue";
91
+ import SowellMessage from "../dialogs/Message.vue";
92
+
93
+ interface HeadersInterface {
94
+ headers: {
95
+ "x-requested-roles"?: string
96
+ }
97
+ }
98
+
122
99
  export default defineComponent({
123
100
  name: "Auth",
101
+ components: { SendEmail, SowellMessage },
124
102
  setup() {
103
+ const {
104
+ "@sowell/auth": { X_REQUESTED_ROLES },
105
+ } = prompts;
125
106
  const email = ref("");
126
107
  const password = ref("");
127
108
  const loading = ref(false);
128
109
  const showPassword = ref(false);
129
110
  const forgottenPassword = ref(false);
111
+ const isReset = ref(false);
112
+ const sendEmailSuccess = ref(false);
130
113
  const emailResetPassword = ref("");
131
114
  const { post } = $api();
132
115
  const {
133
116
  LOCAL_SUCCESS_REDIRECTION_ROUTE,
134
117
  AUTH_SERVER_SIGNING_ROUTE,
135
118
  AUTH_SERVER_RESET_PASSWORD_ROUTE,
119
+ APP_SERVER_BASE_URL,
136
120
  } = $prompts();
137
121
  const $q = useQuasar();
138
122
  const { push, replace } = $router();
139
- const { state, dispatch } = $store();
123
+ const { dispatch, getters } = $store();
140
124
  const { t } = useI18n();
141
125
 
142
126
  onMounted(() => {
143
- if (state.auth.token) {
127
+ if (getters["token/getRaw"]) {
144
128
  replace(LOCAL_SUCCESS_REDIRECTION_ROUTE);
145
129
  }
146
130
  });
@@ -153,26 +137,22 @@ export default defineComponent({
153
137
  password: [(val: string) => !!val || t("auth.passwordPresenceError")],
154
138
  });
155
139
 
156
- const resetPassword = () => {
140
+ const resetPassword = (email: string) => {
157
141
  const data = {
158
- email: emailResetPassword.value,
142
+ auth: {
143
+ email,
144
+ base: APP_SERVER_BASE_URL,
145
+ },
159
146
  };
160
147
 
161
148
  post(AUTH_SERVER_RESET_PASSWORD_ROUTE, data)
162
149
  .then(() => {
163
- $q.notify({
164
- message: t("auth.emailSent"),
165
- color: "positive",
166
- position: "top",
167
- });
168
150
  forgottenPassword.value = false;
151
+ isReset.value = true;
152
+ sendEmailSuccess.value = true;
169
153
  })
170
154
  .catch(() => {
171
- $q.notify({
172
- message: t("auth.emailNotRecognize"),
173
- color: "negative",
174
- position: "top",
175
- });
155
+ isReset.value = true;
176
156
  });
177
157
  };
178
158
 
@@ -184,24 +164,46 @@ export default defineComponent({
184
164
  password: password.value,
185
165
  },
186
166
  };
167
+ const options: HeadersInterface = {
168
+ headers:{}
169
+ };
170
+ // @ts-ignore
171
+ let requestedRoles = window.Cypress ? window.Cypress.requestedRoles : X_REQUESTED_ROLES;
172
+ if (requestedRoles) options.headers["x-requested-roles"] = requestedRoles;
187
173
 
188
- post(AUTH_SERVER_SIGNING_ROUTE, data)
174
+ post(AUTH_SERVER_SIGNING_ROUTE, data, options)
189
175
  .then((response: AxiosResponse) => {
190
176
  const token = response.data.jwt;
191
- dispatch("auth/updateToken", token);
192
- const payload = parseJwt(token);
193
- const user = { roles: payload.roles };
194
- dispatch("auth/updateUser", user);
195
-
177
+ dispatch("token/updateRaw", token);
196
178
  push(LOCAL_SUCCESS_REDIRECTION_ROUTE);
197
179
  })
198
180
  .catch((error: AxiosError) => {
199
181
  loading.value = false;
200
- $q.notify({
201
- message: t("auth.loginFailed"),
202
- color: "negative",
203
- position: "top",
204
- });
182
+ switch (error.response?.status) {
183
+ case 403:
184
+ $q.notify({
185
+ message: t("auth.403"),
186
+ color: "negative",
187
+ position: "top",
188
+ });
189
+ console.log('403')
190
+ break;
191
+ case 404:
192
+ $q.notify({
193
+ message: t("auth.404"),
194
+ color: "negative",
195
+ position: "top",
196
+ });
197
+ console.log('404')
198
+ break;
199
+ default:
200
+ $q.notify({
201
+ message: t("auth.loginFailed"),
202
+ color: "negative",
203
+ position: "top",
204
+ });
205
+ console.log('default')
206
+ }
205
207
  });
206
208
  };
207
209
 
@@ -214,10 +216,6 @@ export default defineComponent({
214
216
  );
215
217
  };
216
218
 
217
- const parseJwt = (token: string) => {
218
- return JSON.parse(window.atob(token.split(".")[1]));
219
- };
220
-
221
219
  return {
222
220
  email,
223
221
  password,
@@ -229,7 +227,17 @@ export default defineComponent({
229
227
  forgottenPassword,
230
228
  emailResetPassword,
231
229
  resetPassword,
230
+ isReset,
231
+ sendEmailSuccess,
232
232
  };
233
233
  },
234
234
  });
235
235
  </script>
236
+
237
+ <style scoped>
238
+ @import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600&display=swap");
239
+
240
+ .q-page {
241
+ font-family: "Montserrat", sans-serif;
242
+ }
243
+ </style>
@@ -1,59 +1,59 @@
1
1
  <template>
2
- <q-page class="flex flex-center">
3
- <q-card square>
4
- <q-card-section>
5
- <div class="text-h5 text-center head">
6
- {{ $t("auth.passwordRecovery") }}
7
- </div>
8
- </q-card-section>
9
-
10
- <q-form class="q-gutter-md" @submit="onSubmit">
11
- <q-card-section>
12
- <q-input
13
- id="password"
14
- v-model="password"
15
- type="password"
16
- :label="$t('auth.newPassword')"
17
- :rules="validations['passwordRules']"
18
- rounded
19
- outlined
20
- dense
21
- class="full-width q-mb-md"
22
- >
23
- </q-input>
24
- <q-input
25
- id="passwordConfirmation"
26
- v-model="passwordConfirmation"
27
- type="password"
28
- :label="$t('auth.newPasswordConfirmation')"
29
- :rules="validations['passwordConfirmationRules']"
30
- rounded
31
- outlined
32
- dense
33
- class="full-width q-mb-md"
2
+ <q-layout>
3
+ <q-page class="flex flex-center">
4
+ <div>
5
+ <div class="column items-center q-mb-xl">
6
+ <img
7
+ style="width: 40px"
8
+ src="../../assets/Logo.svg"
9
+ class="q-mb-sm"
10
+ />
11
+ <div
12
+ class="text-h5 text-center head q-mt-sm"
13
+ style="font-size: 17px; font-weight: 500"
34
14
  >
35
- </q-input>
36
- </q-card-section>
15
+ {{ $t("auth.passwordRecovery") }}
16
+ </div>
17
+ </div>
18
+ <q-form class="column items-center" @submit="onSubmit">
19
+ <div>
20
+ <div class="q-mb-sm" style="font-size: 14px; font-weight: 400">
21
+ {{ $t("auth.newPassword") }}
22
+ </div>
23
+ <q-input
24
+ id="password"
25
+ v-model="password"
26
+ data-cy="reset-password"
27
+ :rules="validations['passwordRules']"
28
+ outlined
29
+ dense
30
+ class="full-width q-mb-md"
31
+ />
32
+ </div>
37
33
 
38
- <q-card-actions>
39
- <q-btn
40
- rounded
41
- :label="$t('common.register')"
42
- color="primary"
43
- :loading="loading"
44
- type="submit"
45
- class="full-width"
46
- :disable="canSubmit"
47
- />
48
- </q-card-actions>
49
- </q-form>
50
- </q-card>
51
- </q-page>
34
+ <div class="full-width">
35
+ <q-btn
36
+ rounded
37
+ :label="$t('common.register')"
38
+ color="primary"
39
+ :loading="loading"
40
+ type="submit"
41
+ no-caps
42
+ data-cy="send-new-password"
43
+ class="full-width"
44
+ :disable="canSubmit"
45
+ />
46
+ </div>
47
+ </q-form>
48
+ </div>
49
+ </q-page>
50
+ </q-layout>
52
51
  </template>
53
52
 
54
53
  <script lang="ts">
55
- import { useQuasar } from "quasar";
54
+ //@ts-ignore
56
55
  import { computed, defineComponent, ref } from "vue";
56
+ import { useQuasar } from "quasar";
57
57
  import { useI18n } from "vue-i18n";
58
58
  import { useRouter } from "vue-router";
59
59
  import { $api, $prompts } from "../../injects";
@@ -70,31 +70,21 @@ export default defineComponent({
70
70
  const $q = useQuasar();
71
71
  const router = useRouter();
72
72
  const password = ref("");
73
- const passwordConfirmation = ref("");
74
73
  const loading = ref(false);
75
74
  const { t } = useI18n();
76
75
 
77
- const canSubmit = computed(() => {
78
- return password.value != "" &&
79
- password.value === passwordConfirmation.value
80
- ? false
81
- : true;
82
- });
76
+ const canSubmit = computed(() => password.value.length < 6);
83
77
 
84
78
  const validations = {
85
79
  passwordRules: [
86
- (val: string) => !!val || t("auth.newPasswordPresenceError"),
87
- ],
88
- passwordConfirmationRules: [
89
- (val: string) =>
90
- val === password.value || t("auth.newPasswordConfirmationFailed"),
80
+ (val: string) => !!val || t("auth.passwordPresenceError"),
81
+ (val: string) => val.length >= 6 || t("auth.passwordLengthError"),
91
82
  ],
92
83
  };
93
84
 
94
85
  const onSubmit = () => {
95
86
  const data = {
96
87
  password: password.value,
97
- password_confirmation: passwordConfirmation.value,
98
88
  };
99
89
  patch(AUTH_SERVER_UPDATE_PASSWORD_ROUTE, data)
100
90
  .then(() => {
@@ -116,7 +106,6 @@ export default defineComponent({
116
106
 
117
107
  return {
118
108
  password,
119
- passwordConfirmation,
120
109
  validations,
121
110
  loading,
122
111
  onSubmit,
@@ -127,13 +116,8 @@ export default defineComponent({
127
116
  </script>
128
117
 
129
118
  <style scoped>
130
- .head,
119
+ @import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600&display=swap");
131
120
  .q-page {
132
- opacity: 0.7;
133
- }
134
-
135
- .q-card {
136
- width: 400px;
137
- padding: 50px;
121
+ font-family: "Montserrat", sans-serif;
138
122
  }
139
123
  </style>
@@ -14,6 +14,7 @@ export default {
14
14
  emailSent: "Email sent, check your inbox",
15
15
  tapEmail: "Please enter your email",
16
16
  404: "No user found with the provided credentials",
17
+ 403: "Insufficient rights, your account does not allow access to this interface",
17
18
  },
18
19
  common: {
19
20
  register: "Save",
@@ -14,6 +14,7 @@ export default {
14
14
  emailSent: "Email envoyé, vérifier votre boite email",
15
15
  tapEmail: "Entrer votre email",
16
16
  404: "Aucun utilisateur trouvé avec les identifiants donnés",
17
+ 403: "Droits insuffisants, votre compte ne permet pas d'acceder à cette interface",
17
18
  },
18
19
  common: {
19
20
  register: "Enregistre",
@@ -1,5 +1,6 @@
1
1
  import { inject } from "vue";
2
2
  export interface PromptsInterface {
3
+ APP_SERVER_BASE_URL: string;
3
4
  LOCAL_LOGIN_ROUTE: string;
4
5
  LOCAL_SUCCESS_REDIRECTION_ROUTE: string;
5
6
  LOCAL_CHECK_CODE_ROUTE: string;
@@ -0,0 +1,11 @@
1
+ export interface payload {
2
+ company_hp?: number
3
+ exp?: number
4
+ gm_key: string
5
+ roles: string[] | []
6
+ sub: number | null
7
+ }
8
+ export interface tokenStateInterface {
9
+ raw: string
10
+ payload: payload
11
+ }
@@ -1,2 +1,2 @@
1
1
  export * from "./Boot";
2
- export * from "./AuthState";
2
+ export * from "./TokenStateInterface";
package/src/prompts.js CHANGED
@@ -82,9 +82,8 @@ module.exports = function () {
82
82
  name: "VUEX_SET_EMAIL_MUTATION",
83
83
  type: "input",
84
84
  required: true,
85
- message:
86
- "Vuex mutation to store user email when authenticated",
87
- default: "auth/set_email_user"
85
+ message: "Vuex mutation to store user email when authenticated",
86
+ default: "auth/set_email_user",
88
87
  },
89
88
  {
90
89
  name: "VUEX_SET_INFOS_USER_MUTATION",
@@ -107,5 +106,12 @@ module.exports = function () {
107
106
  message: "Vuex getter user information",
108
107
  default: "auth/get_infos_user",
109
108
  },
109
+ {
110
+ name: "X_REQUESTED_ROLES",
111
+ type: "input",
112
+ required: true,
113
+ message: "Role required for the application",
114
+ default: "",
115
+ },
110
116
  ];
111
117
  };
@@ -14,6 +14,7 @@ const routes: RouteRecordRaw[] = [
14
14
  },
15
15
  {
16
16
  path: LOCAL_UPDATE_PASSWORD_ROUTE,
17
+ name:"update_password",
17
18
  // @ts-ignore
18
19
  component: () => import("@sowell/auth/pages/ResetPassword.vue"),
19
20
  },
@@ -1,16 +1,71 @@
1
- import { Module } from "vuex";
2
- import state from "./state";
3
- import actions from "./actions";
4
- import getters from "./getters";
5
- import mutations from "./mutations";
6
- import { AuthStateInterface } from "../interfaces";
1
+ import { Module, GetterTree, MutationTree, ActionTree } from "vuex";
2
+ import { tokenStateInterface, payload } from "../interfaces";
7
3
 
8
- const authModule: Module<AuthStateInterface, any> = {
4
+ const state: tokenStateInterface = {
5
+ raw: "",
6
+ payload: {
7
+ company_hp: undefined,
8
+ exp: undefined,
9
+ gm_key: "",
10
+ roles: [],
11
+ sub: null
12
+ }
13
+ }
14
+
15
+ const getters: GetterTree<tokenStateInterface, any> = {
16
+ getRaw(state) {
17
+ return state.raw
18
+ },
19
+ getPayload(state) {
20
+ return state.payload
21
+ },
22
+ getIsValid(state) {
23
+ if (state.payload.exp) {
24
+ return new Date(state.payload.exp * 1000) >= new Date() ? true : false;
25
+ } else {
26
+ return false
27
+ }
28
+ }
29
+ }
30
+
31
+ const mutations: MutationTree<tokenStateInterface> = {
32
+ setRaw(state, value: string) {
33
+ state.raw = value
34
+ },
35
+ setPayload(state, value: payload) {
36
+ state.payload = {...value}
37
+ },
38
+ reset(state) {
39
+ state.raw = ""
40
+ state.payload = {
41
+ company_hp: undefined,
42
+ exp: undefined,
43
+ gm_key: "",
44
+ roles: [],
45
+ sub: null
46
+ }
47
+ }
48
+ }
49
+
50
+ const actions: ActionTree<tokenStateInterface, any> = {
51
+ updateRaw({ commit }, value: string) {
52
+ commit("setRaw", value);
53
+ let parseJwt: string
54
+ try {
55
+ parseJwt = JSON.parse(window.atob(value.split(".")[1]));
56
+ } catch (error) {
57
+ parseJwt = ""
58
+ }
59
+ commit("setPayload", parseJwt)
60
+ }
61
+ }
62
+
63
+ const tokenModule: Module<tokenStateInterface, any> = {
9
64
  namespaced: true,
10
- actions,
11
65
  getters,
12
66
  mutations,
13
- state,
14
- };
67
+ actions,
68
+ state
69
+ }
15
70
 
16
- export default authModule;
71
+ export default tokenModule;
@@ -1,7 +0,0 @@
1
- export interface UserInterface {
2
- roles: string[];
3
- }
4
- export interface AuthStateInterface {
5
- token: string | null;
6
- user: UserInterface;
7
- }
@@ -1,13 +0,0 @@
1
- import { ActionTree } from "vuex";
2
- import { AuthStateInterface, UserInterface } from "../interfaces";
3
-
4
- const actions: ActionTree<AuthStateInterface, any> = {
5
- updateToken({ commit }, value: string) {
6
- commit("setToken", value);
7
- },
8
- updateUser({ commit }, value: UserInterface) {
9
- commit("setUser", value);
10
- },
11
- };
12
-
13
- export default actions;
@@ -1,13 +0,0 @@
1
- import { GetterTree } from "vuex";
2
- import { AuthStateInterface } from "../interfaces";
3
-
4
- const getters: GetterTree<AuthStateInterface, any> = {
5
- getToken(state) {
6
- return state.token;
7
- },
8
- getUser(state) {
9
- return state.user;
10
- },
11
- };
12
-
13
- export default getters;
@@ -1,13 +0,0 @@
1
- import { MutationTree } from "vuex";
2
- import { AuthStateInterface, UserInterface } from "../interfaces";
3
-
4
- const mutation: MutationTree<AuthStateInterface> = {
5
- setToken(state, value: string) {
6
- return (state.token = value);
7
- },
8
- setUser(state, value: UserInterface) {
9
- return (state.user = value);
10
- },
11
- };
12
-
13
- export default mutation;
@@ -1,12 +0,0 @@
1
- import { AuthStateInterface } from "../interfaces";
2
-
3
- function state(): AuthStateInterface {
4
- return {
5
- token: "",
6
- user: {
7
- roles: [],
8
- },
9
- };
10
- }
11
-
12
- export default state;