@sowell/quasar-app-extension-auth 0.2.0 → 0.2.4

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.
Files changed (48) hide show
  1. package/.eslintignore +4 -0
  2. package/.eslintrc.js +13 -13
  3. package/.gitattributes +2 -0
  4. package/.github/workflows/main.yml +22 -0
  5. package/README.md +378 -10
  6. package/package.json +35 -19
  7. package/src/assets/Logo.svg +6 -0
  8. package/src/boot/axios.ts +17 -0
  9. package/src/boot/register.ts +8 -0
  10. package/src/boot/router-guards.ts +25 -0
  11. package/src/boot/router.ts +20 -0
  12. package/src/boot/store.ts +10 -0
  13. package/src/components/pages/Auth.vue +265 -0
  14. package/src/components/pages/ResetPassword.vue +123 -0
  15. package/src/i18n/en-US/index.ts +24 -0
  16. package/src/i18n/fr-FR/index.ts +24 -0
  17. package/src/i18n/index.ts +7 -0
  18. package/src/index.js +29 -25
  19. package/src/injects/api.ts +10 -0
  20. package/src/injects/index.ts +4 -0
  21. package/src/injects/prompts.ts +25 -0
  22. package/src/injects/router.ts +10 -0
  23. package/src/injects/store.ts +10 -0
  24. package/src/interfaces/Boot.ts +8 -0
  25. package/src/interfaces/TokenStateInterface.ts +11 -0
  26. package/src/interfaces/index.ts +2 -0
  27. package/src/prompts.js +42 -38
  28. package/src/routes/index.ts +23 -0
  29. package/src/shims-vue.d.ts +6 -0
  30. package/src/store/index.ts +66 -0
  31. package/tsconfig.json +14 -0
  32. package/.github/workflows/publish.yml +0 -22
  33. package/.prettierrc +0 -7
  34. package/.vscode/extensions.json +0 -12
  35. package/.vscode/settings.json +0 -22
  36. package/jsconfig.json +0 -7
  37. package/package-lock.json +0 -2344
  38. package/src/boot/axios.js +0 -17
  39. package/src/boot/navigation-guards.js +0 -16
  40. package/src/boot/register.js +0 -45
  41. package/src/components/Auth.vue +0 -279
  42. package/src/components/ResetCode.vue +0 -140
  43. package/src/components/ResetPassword.vue +0 -139
  44. package/src/components/prompt.js +0 -40
  45. package/src/config/setupHeaders.js +0 -6
  46. package/src/install.js +0 -10
  47. package/src/templates/.gitkeep +0 -0
  48. package/src/uninstall.js +0 -10
@@ -0,0 +1,265 @@
1
+ <template>
2
+ <q-layout>
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>
13
+ </div>
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
+ style="color: #40c4ff; font-weight: 500; cursor: pointer"
47
+ >
48
+ {{ $t("auth.forgottenPassword") }}
49
+ </div>
50
+ <q-btn
51
+ data-cy="submit-login"
52
+ rounded
53
+ :label="$t('auth.login')"
54
+ style="background: #40c4ff"
55
+ no-caps
56
+ text-color="white"
57
+ :loading="loading"
58
+ type="submit"
59
+ class="full-width q-mt-lg"
60
+ :disable="isSubmitBtnDisabled()"
61
+ />
62
+ </q-form>
63
+ </div>
64
+ <div>
65
+ <q-dialog v-model="forgottenPassword" persistent>
66
+ <q-card style="min-width: 350px">
67
+ <q-card-section>
68
+ <p class="resetPasswordTitle">
69
+ {{ $t("auth.tapEmail") }}
70
+ </p>
71
+ </q-card-section>
72
+
73
+ <q-card-section class="q-pt-none">
74
+ <q-input
75
+ v-model="emailResetPassword"
76
+ dense
77
+ rounded
78
+ outlined
79
+ :placeholder="$t('auth.email')"
80
+ autofocus
81
+ />
82
+ </q-card-section>
83
+
84
+ <q-card-actions align="right">
85
+ <q-btn
86
+ outline
87
+ rounded
88
+ :label="$t('common.cancel')"
89
+ class="btn-min"
90
+ v-close-popup
91
+ />
92
+ <q-btn
93
+ rounded
94
+ color="primary"
95
+ :label="$t('common.send')"
96
+ class="btn-min"
97
+ @click="resetPassword"
98
+ />
99
+ </q-card-actions>
100
+ </q-card>
101
+ </q-dialog>
102
+ </div>
103
+ </q-page>
104
+ </q-layout>
105
+ </template>
106
+
107
+ <script lang="ts">
108
+ //import prompts from "app/quasar.extensions.json";
109
+ import isEmail from "validator/es/lib/isEmail";
110
+ import { defineComponent, ref, onMounted } from "vue";
111
+ import { $api, $prompts, $router, $store } from "../../injects";
112
+ import { useQuasar } from "quasar";
113
+ import { useI18n } from "vue-i18n";
114
+ import { AxiosError, AxiosResponse } from "axios";
115
+ import prompts from "app/quasar.extensions.json";
116
+
117
+ interface HeadersInterface {
118
+ headers: {
119
+ "x-requested-roles"?: string
120
+ }
121
+ }
122
+
123
+ export default defineComponent({
124
+ name: "Auth",
125
+ setup() {
126
+ const {
127
+ "@sowell/auth": { X_REQUESTED_ROLES },
128
+ } = prompts;
129
+ const email = ref("");
130
+ const password = ref("");
131
+ const loading = ref(false);
132
+ const showPassword = ref(false);
133
+ const forgottenPassword = ref(false);
134
+ const emailResetPassword = ref("");
135
+ const { post } = $api();
136
+ const {
137
+ LOCAL_SUCCESS_REDIRECTION_ROUTE,
138
+ AUTH_SERVER_SIGNING_ROUTE,
139
+ AUTH_SERVER_RESET_PASSWORD_ROUTE,
140
+ } = $prompts();
141
+ const $q = useQuasar();
142
+ const { push, replace } = $router();
143
+ const { dispatch, getters } = $store();
144
+ const { t } = useI18n();
145
+
146
+ onMounted(() => {
147
+ if (getters["token/getRaw"]) {
148
+ replace(LOCAL_SUCCESS_REDIRECTION_ROUTE);
149
+ }
150
+ });
151
+
152
+ const validations = ref({
153
+ email: [
154
+ (val: string) => !!val || t("auth.emailPresenceError"),
155
+ (val: string) => isEmail(val.trim()) || t("auth.emailValidationError"),
156
+ ],
157
+ password: [(val: string) => !!val || t("auth.passwordPresenceError")],
158
+ });
159
+
160
+ const resetPassword = () => {
161
+ const data = {
162
+ email: emailResetPassword.value,
163
+ };
164
+
165
+ post(AUTH_SERVER_RESET_PASSWORD_ROUTE, data)
166
+ .then(() => {
167
+ $q.notify({
168
+ message: t("auth.emailSent"),
169
+ color: "positive",
170
+ position: "top",
171
+ });
172
+ forgottenPassword.value = false;
173
+ })
174
+ .catch(() => {
175
+ $q.notify({
176
+ message: t("auth.emailNotRecognize"),
177
+ color: "negative",
178
+ position: "top",
179
+ });
180
+ });
181
+ };
182
+
183
+ const onSubmit = () => {
184
+ loading.value = true;
185
+ const data = {
186
+ auth: {
187
+ email: email.value,
188
+ password: password.value,
189
+ },
190
+ };
191
+ const options: HeadersInterface = {
192
+ headers:{}
193
+ };
194
+ // @ts-ignore
195
+ let requestedRoles = window.Cypress ? window.Cypress.requestedRoles : X_REQUESTED_ROLES;
196
+ if (requestedRoles) options.headers["x-requested-roles"] = requestedRoles;
197
+
198
+ post(AUTH_SERVER_SIGNING_ROUTE, data, options)
199
+ .then((response: AxiosResponse) => {
200
+ const token = response.data.jwt;
201
+ dispatch("token/updateRaw", token);
202
+ push(LOCAL_SUCCESS_REDIRECTION_ROUTE);
203
+ })
204
+ .catch((error: AxiosError) => {
205
+ loading.value = false;
206
+ switch (error.response?.status) {
207
+ case 403:
208
+ $q.notify({
209
+ message: t("auth.403"),
210
+ color: "negative",
211
+ position: "top",
212
+ });
213
+ console.log('403')
214
+ break;
215
+ case 404:
216
+ $q.notify({
217
+ message: t("auth.404"),
218
+ color: "negative",
219
+ position: "top",
220
+ });
221
+ console.log('404')
222
+ break;
223
+ default:
224
+ $q.notify({
225
+ message: t("auth.loginFailed"),
226
+ color: "negative",
227
+ position: "top",
228
+ });
229
+ console.log('default')
230
+ }
231
+ });
232
+ };
233
+
234
+ const isSubmitBtnDisabled = () => {
235
+ return !(
236
+ email.value &&
237
+ isEmail(email.value) &&
238
+ password.value &&
239
+ password.value.length > 5
240
+ );
241
+ };
242
+
243
+ return {
244
+ email,
245
+ password,
246
+ loading,
247
+ showPassword,
248
+ validations,
249
+ isSubmitBtnDisabled,
250
+ onSubmit,
251
+ forgottenPassword,
252
+ emailResetPassword,
253
+ resetPassword,
254
+ };
255
+ },
256
+ });
257
+ </script>
258
+
259
+ <style scoped>
260
+ @import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600&display=swap");
261
+
262
+ .q-page {
263
+ font-family: "Montserrat", sans-serif;
264
+ }
265
+ </style>
@@ -0,0 +1,123 @@
1
+ <template>
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"
14
+ >
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>
33
+
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>
51
+ </template>
52
+
53
+ <script lang="ts">
54
+ //@ts-ignore
55
+ import { computed, defineComponent, ref } from "vue";
56
+ import { useQuasar } from "quasar";
57
+ import { useI18n } from "vue-i18n";
58
+ import { useRouter } from "vue-router";
59
+ import { $api, $prompts } from "../../injects";
60
+
61
+ export default defineComponent({
62
+ name: "ResetPassword",
63
+
64
+ setup() {
65
+ const { patch } = $api();
66
+ const {
67
+ AUTH_SERVER_UPDATE_PASSWORD_ROUTE,
68
+ LOCAL_SUCCESS_REDIRECTION_ROUTE,
69
+ } = $prompts();
70
+ const $q = useQuasar();
71
+ const router = useRouter();
72
+ const password = ref("");
73
+ const loading = ref(false);
74
+ const { t } = useI18n();
75
+
76
+ const canSubmit = computed(() => password.value.length < 6);
77
+
78
+ const validations = {
79
+ passwordRules: [
80
+ (val: string) => !!val || t("auth.passwordPresenceError"),
81
+ (val: string) => val.length >= 6 || t("auth.passwordLengthError"),
82
+ ],
83
+ };
84
+
85
+ const onSubmit = () => {
86
+ const data = {
87
+ password: password.value,
88
+ };
89
+ patch(AUTH_SERVER_UPDATE_PASSWORD_ROUTE, data)
90
+ .then(() => {
91
+ $q.notify({
92
+ message: t("auth.passwordRecoverySuccess"),
93
+ color: "positive",
94
+ position: "top",
95
+ });
96
+ router.push(LOCAL_SUCCESS_REDIRECTION_ROUTE);
97
+ })
98
+ .catch(() => {
99
+ $q.notify({
100
+ message: t("auth.passwordRecoveryFailed"),
101
+ color: "negative",
102
+ position: "top",
103
+ });
104
+ });
105
+ };
106
+
107
+ return {
108
+ password,
109
+ validations,
110
+ loading,
111
+ onSubmit,
112
+ canSubmit,
113
+ };
114
+ },
115
+ });
116
+ </script>
117
+
118
+ <style scoped>
119
+ @import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600&display=swap");
120
+ .q-page {
121
+ font-family: "Montserrat", sans-serif;
122
+ }
123
+ </style>
@@ -0,0 +1,24 @@
1
+ export default {
2
+ auth: {
3
+ title: "Log in to access the management interface",
4
+ email: "Email",
5
+ password: "Password",
6
+ forgottenPassword: "Forgotten password",
7
+ login: "Login",
8
+ emailPresenceError: "The email must be provided",
9
+ emailValidationError: "The email is not valid",
10
+ passwordPresenceError: "The password must be provided",
11
+ passwordLengthError: "The password length be at least 6",
12
+ loginFailed: "Incorrect credentials",
13
+ emailNotRecognize: "Login failed, please check your credentials",
14
+ emailSent: "Email sent, check your inbox",
15
+ tapEmail: "Please enter your email",
16
+ 404: "No user found with the provided credentials",
17
+ 403: "Insufficient rights, your account does not allow access to this interface",
18
+ },
19
+ common: {
20
+ register: "Save",
21
+ send: "Send",
22
+ cancel: "Cancel",
23
+ },
24
+ };
@@ -0,0 +1,24 @@
1
+ export default {
2
+ auth: {
3
+ title: "Connectez vous",
4
+ email: "Email",
5
+ password: "Mot de passe",
6
+ forgottenPassword: "Mot de passe oublié",
7
+ login: "Connexion",
8
+ emailPresenceError: "L'adresse email doit être fournie",
9
+ emailValidationError: "L'adresse email fournie est invalide",
10
+ passwordPresenceError: "Le mot de passe doit être fourni",
11
+ passwordLengthError: "La longueur du mot de passe doit être au minimum 6",
12
+ loginFailed: "Identifiants incorrectes",
13
+ emailNotRecognize: "L'adresse email fournie n'est pas reconnue",
14
+ emailSent: "Email envoyé, vérifier votre boite email",
15
+ tapEmail: "Entrer votre email",
16
+ 404: "Aucun utilisateur trouvé avec les identifiants donnés",
17
+ 403: "Droits insuffisants, votre compte ne permet pas d'acceder à cette interface",
18
+ },
19
+ common: {
20
+ register: "Enregistre",
21
+ send: "Envoyer",
22
+ cancel: "Annuler",
23
+ },
24
+ };
@@ -0,0 +1,7 @@
1
+ import enUS from "./en-US";
2
+ import frFR from "./fr-FR";
3
+
4
+ export default {
5
+ "en-US": enUS,
6
+ "fr-FR": frFR,
7
+ };
package/src/index.js CHANGED
@@ -1,34 +1,38 @@
1
- const path = require("path")
2
-
1
+ "use strict";
2
+ const path = require("path");
3
3
  function extendConf(conf) {
4
- conf.boot.push("~@sowell/quasar-app-extension-auth/src/boot/register.js")
5
- conf.boot.push(
6
- "~@sowell/quasar-app-extension-auth/src/boot/navigation-guards.js"
7
- )
8
- conf.boot.push("~@sowell/quasar-app-extension-auth/src/boot/axios.js")
4
+ const requiredPlugins = ["Notify"];
9
5
 
10
- conf.build.transpileDependencies.push(/quasar-app-extension-auth[\\/]src/)
11
-
12
- const requiredPlugins = ["Notify"]
13
6
  requiredPlugins.forEach((plugin) => {
14
7
  if (!conf.framework.plugins.includes(plugin)) {
15
- conf.framework.plugins.push(plugin)
8
+ conf.framework.plugins.push(plugin);
16
9
  }
17
- })
18
- }
10
+ });
11
+
12
+ conf.boot.push("~@sowell/quasar-app-extension-auth/src/boot/register.ts");
13
+
14
+ conf.boot.push("~@sowell/quasar-app-extension-auth/src/boot/store.ts");
15
+
16
+ conf.boot.push("~@sowell/quasar-app-extension-auth/src/boot/router.ts");
19
17
 
20
- //Create aliases to import or require certain modules or file more easily.
18
+ conf.boot.push(
19
+ "~@sowell/quasar-app-extension-auth/src/boot/router-guards.ts"
20
+ );
21
+ conf.boot.push("~@sowell/quasar-app-extension-auth/src/boot/axios.ts");
22
+
23
+ conf.build.transpileDependencies.push(/quasar-app-extension-auth[\\/]src/);
24
+
25
+ console.log("Boot sowell auth");
26
+ }
21
27
  const chainWebpack = (ctx, chain) => {
22
28
  chain.resolve.alias.set(
23
- "setupHeaders",
24
- // eslint-disable-next-line no-undef
25
- path.resolve(__dirname, "./config/setupHeaders")
26
- )
27
- }
28
-
29
+ "@sowell/auth",
30
+ path.resolve(__dirname, "./components")
31
+ );
32
+ };
29
33
  module.exports = function (api) {
30
- api.compatibleWith("quasar", "^2.0.0-beta.12")
31
- api.compatibleWith("@quasar/app", "^3.0.0-beta.12")
32
- api.chainWebpack((chain) => chainWebpack(api.ctx, chain))
33
- api.extendQuasarConf(extendConf)
34
- }
34
+ api.compatibleWith("quasar", "^2.0.0");
35
+ api.compatibleWith("@quasar/app", "^3.0.0");
36
+ api.chainWebpack((chain) => chainWebpack(api.ctx, chain));
37
+ api.extendQuasarConf(extendConf);
38
+ };
@@ -0,0 +1,10 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { inject } from "vue";
3
+
4
+ export const $api = (): AxiosInstance => {
5
+ const $api = inject<AxiosInstance>("$api");
6
+ if ($api == undefined) {
7
+ throw Error("Could not inject api");
8
+ }
9
+ return $api;
10
+ };
@@ -0,0 +1,4 @@
1
+ export * from "./api";
2
+ export * from "./prompts";
3
+ export * from "./router";
4
+ export * from "./store";
@@ -0,0 +1,25 @@
1
+ import { inject } from "vue";
2
+ export interface PromptsInterface {
3
+ LOCAL_LOGIN_ROUTE: string;
4
+ LOCAL_SUCCESS_REDIRECTION_ROUTE: string;
5
+ LOCAL_CHECK_CODE_ROUTE: string;
6
+ LOCAL_UPDATE_PASSWORD_ROUTE: string;
7
+ AUTH_SERVER_BASE_URL: string;
8
+ AUTH_SERVER_SIGNING_ROUTE: string;
9
+ AUTH_SERVER_RESET_PASSWORD_ROUTE: string;
10
+ AUTH_SERVER_UPDATE_PASSWORD_ROUTE: string;
11
+ AUTH_TYPE: string;
12
+ VUEX_SET_TOKEN_MUTATION: string;
13
+ VUEX_CLEAR_TOKEN_MUTATION: string;
14
+ VUEX_SET_EMAIL_OR_PHONENUMBER_USER_MUTATION: string;
15
+ VUEX_SET_INFOS_USER_MUTATION: string;
16
+ VUEX_GET_TOKEN_GETTER: string;
17
+ VUEX_GET_INFOS_USER_GETTER: string;
18
+ }
19
+ export const $prompts = (): PromptsInterface => {
20
+ const $prompts = inject<Record<"@sowell/auth", PromptsInterface>>("$prompts");
21
+ if ($prompts == undefined) {
22
+ throw Error("Could not inject prompts");
23
+ }
24
+ return $prompts["@sowell/auth"];
25
+ };
@@ -0,0 +1,10 @@
1
+ import { inject } from "vue";
2
+ import { Router } from "vue-router";
3
+
4
+ export const $router = (): Router => {
5
+ const $router = inject<Router>("$router");
6
+ if ($router == undefined) {
7
+ throw Error("Could not inject router");
8
+ }
9
+ return $router;
10
+ };
@@ -0,0 +1,10 @@
1
+ import { inject } from "vue";
2
+ import { Store } from "vuex";
3
+
4
+ export const $store = (): Store<any> => {
5
+ const $store = inject<Store<any>>("$store");
6
+ if ($store == undefined) {
7
+ throw Error("Could not inject store");
8
+ }
9
+ return $store;
10
+ };
@@ -0,0 +1,8 @@
1
+ import { Router } from "vue-router";
2
+ import { Store } from "vuex";
3
+ import { App } from "vue";
4
+ export interface BootInterface {
5
+ router: Router;
6
+ store: Store<any>;
7
+ app: App<any>;
8
+ }
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./Boot";
2
+ export * from "./TokenStateInterface";