refactor: deps update + 2FA setup + verify
This commit is contained in:
		| @@ -309,6 +309,21 @@ export default { | ||||
|   } | ||||
| } | ||||
|  | ||||
| .admin-providerlogo { | ||||
|   width: 250px; | ||||
|   height: 50px; | ||||
|   float: right; | ||||
|   display: flex; | ||||
|   justify-content: flex-end; | ||||
|   align-items: center; | ||||
|   margin-left: 16px; | ||||
|  | ||||
|   img { | ||||
|     max-width: 100%; | ||||
|     max-height: 50px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .v-application.admin { | ||||
|   code { | ||||
|     box-shadow: none; | ||||
|   | ||||
| @@ -46,14 +46,16 @@ | ||||
|               hide-details | ||||
|               inset | ||||
|               ) | ||||
|           v-card-info(color='blue') | ||||
|             div | ||||
|               div {{provider.description}} | ||||
|               span.caption: a(:href='provider.website') {{provider.website}} | ||||
|             v-spacer | ||||
|             .admin-providerlogo | ||||
|               img(:src='provider.logo', :alt='provider.title') | ||||
|           v-card-text | ||||
|             v-form | ||||
|               .analytic-provider-logo | ||||
|                 img(:src='provider.logo', :alt='provider.title') | ||||
|               .body-2.pt-3 {{provider.description}} | ||||
|               .body-2.pt-3: a(:href='provider.website') {{provider.website}} | ||||
|               v-divider.mt-5 | ||||
|               .overline.py-5 {{$t('admin:analytics.providerConfiguration')}} | ||||
|               .overline.pb-5 {{$t('admin:analytics.providerConfiguration')}} | ||||
|               .body-1.ml-3(v-if='!provider.config || provider.config.length < 1'): em {{$t('admin:analytics.providerNoConfiguration')}} | ||||
|               template(v-else, v-for='cfg in provider.config') | ||||
|                 v-select( | ||||
| @@ -177,21 +179,3 @@ export default { | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang='scss' scoped> | ||||
|  | ||||
| .analytic-provider-logo { | ||||
|   width: 250px; | ||||
|   height: 85px; | ||||
|   float:right; | ||||
|   display: flex; | ||||
|   justify-content: flex-end; | ||||
|   align-items: center; | ||||
|  | ||||
|   img { | ||||
|     max-width: 100%; | ||||
|     max-height: 50px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -211,7 +211,7 @@ export default { | ||||
|         } else { | ||||
|           this.$store.commit('showNotification', { | ||||
|             style: 'red', | ||||
|             message: _.get(resp, 'data.authentication.createApiKey.responseResult.message', 'An unexpected error occured.'), | ||||
|             message: _.get(resp, 'data.authentication.createApiKey.responseResult.message', 'An unexpected error occurred.'), | ||||
|             icon: 'alert' | ||||
|           }) | ||||
|         } | ||||
|   | ||||
| @@ -131,7 +131,7 @@ export default { | ||||
|         } else { | ||||
|           this.$store.commit('showNotification', { | ||||
|             style: 'red', | ||||
|             message: _.get(resp, 'data.authentication.setApiState.responseResult.message', 'An unexpected error occured.'), | ||||
|             message: _.get(resp, 'data.authentication.setApiState.responseResult.message', 'An unexpected error occurred.'), | ||||
|             icon: 'alert' | ||||
|           }) | ||||
|         } | ||||
| @@ -182,7 +182,7 @@ export default { | ||||
|         } else { | ||||
|           this.$store.commit('showNotification', { | ||||
|             style: 'red', | ||||
|             message: _.get(resp, 'data.authentication.revokeApiKey.responseResult.message', 'An unexpected error occured.'), | ||||
|             message: _.get(resp, 'data.authentication.revokeApiKey.responseResult.message', 'An unexpected error occurred.'), | ||||
|             icon: 'alert' | ||||
|           }) | ||||
|         } | ||||
|   | ||||
| @@ -74,7 +74,7 @@ | ||||
|               span {{strategy.strategy.description}} | ||||
|               .caption: a(:href='strategy.strategy.website') {{strategy.strategy.website}} | ||||
|             v-spacer | ||||
|             .authlogo | ||||
|             .admin-providerlogo | ||||
|               img(:src='strategy.strategy.logo', :alt='strategy.strategy.title') | ||||
|           v-card-text | ||||
|             .overline.mb-5 {{$t('admin:auth.strategyConfiguration')}} | ||||
| @@ -423,22 +423,3 @@ export default { | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang='scss' scoped> | ||||
|  | ||||
| .authlogo { | ||||
|   width: 250px; | ||||
|   height: 60px; | ||||
|   float:right; | ||||
|   display: flex; | ||||
|   justify-content: flex-end; | ||||
|   align-items: center; | ||||
|   margin-left: 16px; | ||||
|  | ||||
|   img { | ||||
|     max-width: 100%; | ||||
|     max-height: 50px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -38,12 +38,14 @@ | ||||
|         v-card.animated.fadeInUp.wait-p2s | ||||
|           v-toolbar(color='primary', dense, flat, dark) | ||||
|             .subtitle-1 {{provider.title}} | ||||
|           v-card-text | ||||
|             .providerlogo | ||||
|           v-card-info(color='blue') | ||||
|             div | ||||
|               div {{provider.description}} | ||||
|               span.caption: a(:href='provider.website') {{provider.website}} | ||||
|             v-spacer | ||||
|             .admin-providerlogo | ||||
|               img(:src='provider.logo', :alt='provider.title') | ||||
|             .caption.pt-3 {{provider.description}} | ||||
|             .caption.pb-3: a(:href='provider.website') {{provider.website}} | ||||
|             v-divider.mt-3 | ||||
|           v-card-text | ||||
|             .overline.my-5 {{$t('admin:comments.providerConfig')}} | ||||
|             .body-2.ml-3(v-if='!provider.config || provider.config.length < 1'): em {{$t('admin:comments.providerNoConfig')}} | ||||
|             template(v-else, v-for='cfg in provider.config') | ||||
| @@ -202,21 +204,3 @@ export default { | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang='scss' scoped> | ||||
|  | ||||
| .providerlogo { | ||||
|   width: 250px; | ||||
|   height: 85px; | ||||
|   float:right; | ||||
|   display: flex; | ||||
|   justify-content: flex-end; | ||||
|   align-items: center; | ||||
|  | ||||
|   img { | ||||
|     max-width: 100%; | ||||
|     max-height: 50px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -226,7 +226,7 @@ export default { | ||||
|           } | ||||
|         }) | ||||
|         if (!_.get(resp, 'data.mail.sendTest.responseResult.succeeded', false)) { | ||||
|           throw new Error(_.get(resp, 'data.mail.sendTest.responseResult.message', 'An unexpected error occured.')) | ||||
|           throw new Error(_.get(resp, 'data.mail.sendTest.responseResult.message', 'An unexpected error occurred.')) | ||||
|         } | ||||
|  | ||||
|         this.testEmail = '' | ||||
|   | ||||
| @@ -8,7 +8,9 @@ | ||||
|             .headline.primary--text.animated.fadeInLeft {{$t('navigation.title')}} | ||||
|             .subtitle-1.grey--text.animated.fadeInLeft.wait-p4s {{$t('navigation.subtitle')}} | ||||
|           v-spacer | ||||
|           v-btn.animated.fadeInDown.wait-p2s.mr-3(icon, outlined, color='grey', @click='refresh') | ||||
|           v-btn.animated.fadeInDown.wait-p3s(icon, outlined, color='grey', href='https://docs.requarks.io/navigation', target='_blank') | ||||
|             v-icon mdi-help-circle | ||||
|           v-btn.mx-3.animated.fadeInDown.wait-p2s.mr-3(icon, outlined, color='grey', @click='refresh') | ||||
|             v-icon mdi-refresh | ||||
|           v-btn.animated.fadeInDown(color='success', depressed, @click='save', large) | ||||
|             v-icon(left) mdi-check | ||||
| @@ -30,15 +32,6 @@ | ||||
|                       v-list-item-avatar | ||||
|                         v-icon(v-if='$vuetify.theme.dark', :color='config.mode === `TREE` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle | ||||
|                         v-icon(v-else, :color='config.mode === `TREE` ? `teal` : `grey lighten-3`') mdi-check-circle | ||||
|                     v-list-item(value='MIXED') | ||||
|                       v-list-item-avatar | ||||
|                         img(src='/_assets/svg/icon-user-menu-male-dotted.svg', alt='Custom Navigation') | ||||
|                       v-list-item-content | ||||
|                         v-list-item-title {{$t('admin:navigation.modeCustom.title')}} | ||||
|                         v-list-item-subtitle {{$t('admin:navigation.modeCustom.description')}} | ||||
|                       v-list-item-avatar | ||||
|                         v-icon(v-if='$vuetify.theme.dark', :color='config.mode === `MIXED` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle | ||||
|                         v-icon(v-else, :color='config.mode === `MIXED` ? `teal` : `grey lighten-3`') mdi-check-circle | ||||
|                     v-list-item(value='STATIC') | ||||
|                       v-list-item-avatar | ||||
|                         img(src='/_assets/svg/icon-features-list.svg', alt='Static Navigation') | ||||
| @@ -48,6 +41,15 @@ | ||||
|                       v-list-item-avatar | ||||
|                         v-icon(v-if='$vuetify.theme.dark', :color='config.mode === `STATIC` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle | ||||
|                         v-icon(v-else, :color='config.mode === `STATIC` ? `teal` : `grey lighten-3`') mdi-check-circle | ||||
|                     v-list-item(value='MIXED') | ||||
|                       v-list-item-avatar | ||||
|                         img(src='/_assets/svg/icon-user-menu-male-dotted.svg', alt='Custom Navigation') | ||||
|                       v-list-item-content | ||||
|                         v-list-item-title {{$t('admin:navigation.modeCustom.title')}} | ||||
|                         v-list-item-subtitle {{$t('admin:navigation.modeCustom.description')}} | ||||
|                       v-list-item-avatar | ||||
|                         v-icon(v-if='$vuetify.theme.dark', :color='config.mode === `MIXED` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle | ||||
|                         v-icon(v-else, :color='config.mode === `MIXED` ? `teal` : `grey lighten-3`') mdi-check-circle | ||||
|                     v-list-item(value='NONE') | ||||
|                       v-list-item-avatar | ||||
|                         img(src='/_assets/svg/icon-cancel-dotted.svg', alt='None') | ||||
| @@ -421,7 +423,7 @@ export default { | ||||
|             icon: 'check' | ||||
|           }) | ||||
|         } else { | ||||
|           throw new Error(_.get(resp, 'data.navigation.updateTree.responseResult.message', 'An unexpected error occured.')) | ||||
|           throw new Error(_.get(resp, 'data.navigation.updateTree.responseResult.message', 'An unexpected error occurred.')) | ||||
|         } | ||||
|       } catch (err) { | ||||
|         this.$store.commit('pushGraphError', err) | ||||
|   | ||||
| @@ -85,18 +85,12 @@ | ||||
|               hide-details | ||||
|               inset | ||||
|               ) | ||||
|           v-card-text.py-2.pl-4 | ||||
|             .body-2.pt-3 {{currentRenderer.description}} | ||||
|             .body-2.pt-1.pb-5: a(href='https://docs.requarks.io/en/rendering', target='_blank') Documentation | ||||
|             i18next.body-2(path='admin:auth.strategyState', tag='div', v-if='currentRenderer.isEnabled') | ||||
|               v-chip(color='green', small, dark, label, place='state') {{$t('admin:auth.strategyStateActive')}} | ||||
|               span(v-if='selectedCore === `local`', place='locked') {{$t('admin:auth.strategyStateLocked')}} | ||||
|               span(v-else, place='locked', v-text='') | ||||
|             i18next.body-2(path='admin:auth.strategyState', tag='div', v-else) | ||||
|               v-chip(color='red', small, dark, label, place='state') {{$t('admin:auth.strategyStateInactive')}} | ||||
|           v-divider.mt-3 | ||||
|           v-card-text.pb-4.pt-2.pl-4 | ||||
|             .overline.my-5 Rendering Module Configuration | ||||
|           v-card-info(color='blue') | ||||
|             div | ||||
|               div {{currentRenderer.description}} | ||||
|               span.caption: a(href='https://docs.requarks.io/en/rendering', target='_blank') Documentation | ||||
|           v-card-text.pb-4.pl-4 | ||||
|             .overline.mb-5 Rendering Module Configuration | ||||
|             .body-2.ml-3(v-if='!currentRenderer.config || currentRenderer.config.length < 1'): em This rendering module has no configuration options you can modify. | ||||
|             template(v-else, v-for='(cfg, idx) in currentRenderer.config') | ||||
|               v-select( | ||||
|   | ||||
| @@ -41,13 +41,15 @@ | ||||
|         v-card.animated.fadeInUp.wait-p2s | ||||
|           v-toolbar(color='primary', dense, flat, dark) | ||||
|             .subtitle-1 {{engine.title}} | ||||
|           v-card-text | ||||
|             .enginelogo | ||||
|           v-card-info(color='blue') | ||||
|             div | ||||
|               div {{engine.description}} | ||||
|               span.caption: a(:href='engine.website') {{engine.website}} | ||||
|             v-spacer | ||||
|             .admin-providerlogo | ||||
|               img(:src='engine.logo', :alt='engine.title') | ||||
|             .caption.pt-3 {{engine.description}} | ||||
|             .caption.pb-3: a(:href='engine.website') {{engine.website}} | ||||
|             v-divider.mt-3 | ||||
|             .overline.my-5 {{$t('admin:search.engineConfig')}} | ||||
|           v-card-text | ||||
|             .overline.mb-5 {{$t('admin:search.engineConfig')}} | ||||
|             .body-2.ml-3(v-if='!engine.config || engine.config.length < 1'): em {{$t('admin:search.engineNoConfig')}} | ||||
|             template(v-else, v-for='cfg in engine.config') | ||||
|               v-select( | ||||
|   | ||||
| @@ -92,12 +92,15 @@ | ||||
|               hide-details | ||||
|               inset | ||||
|               ) | ||||
|           v-card-info(color='blue') | ||||
|             div | ||||
|               div {{target.description}} | ||||
|               span.caption: a(:href='target.website') {{target.website}} | ||||
|             v-spacer | ||||
|             .admin-providerlogo | ||||
|               img(:src='target.logo', :alt='target.title') | ||||
|           v-card-text | ||||
|             v-form | ||||
|               .targetlogo | ||||
|                 img(:src='target.logo', :alt='target.title') | ||||
|               .body-2.pt-3 {{target.description}} | ||||
|               .body-2.pt-3.pb-5: a(:href='target.website') {{target.website}} | ||||
|               i18next.body-2(path='admin:storage.targetState', tag='div', v-if='target.isEnabled') | ||||
|                 v-chip(color='green', small, dark, label, place='state') {{$t('admin:storage.targetStateActive')}} | ||||
|               i18next.body-2(path='admin:storage.targetState', tag='div', v-else) | ||||
|   | ||||
| @@ -153,7 +153,7 @@ export default { | ||||
|           }) | ||||
|           this.refresh() | ||||
|         } else { | ||||
|           throw new Error(_.get(resp, 'data.pages.deleteTag.responseResult.message', 'An unexpected error occured.')) | ||||
|           throw new Error(_.get(resp, 'data.pages.deleteTag.responseResult.message', 'An unexpected error occurred.')) | ||||
|         } | ||||
|       } catch (err) { | ||||
|         this.$store.commit('pushGraphError', err) | ||||
| @@ -193,7 +193,7 @@ export default { | ||||
|           }) | ||||
|           this.current.updatedAt = new Date() | ||||
|         } else { | ||||
|           throw new Error(_.get(resp, 'data.pages.updateTag.responseResult.message', 'An unexpected error occured.')) | ||||
|           throw new Error(_.get(resp, 'data.pages.updateTag.responseResult.message', 'An unexpected error occurred.')) | ||||
|         } | ||||
|       } catch (err) { | ||||
|         this.$store.commit('pushGraphError', err) | ||||
|   | ||||
| @@ -212,7 +212,7 @@ export default { | ||||
|         } else { | ||||
|           this.$store.commit('showNotification', { | ||||
|             style: 'red', | ||||
|             message: _.get(resp, 'data.users.create.responseResult.message', 'An unexpected error occured.'), | ||||
|             message: _.get(resp, 'data.users.create.responseResult.message', 'An unexpected error occurred.'), | ||||
|             icon: 'alert' | ||||
|           }) | ||||
|         } | ||||
|   | ||||
| @@ -174,7 +174,8 @@ | ||||
|                   v-icon mdi-two-factor-authentication | ||||
|                 v-list-item-content | ||||
|                   v-list-item-title {{$t('admin:users.tfa')}} | ||||
|                   v-list-item-subtitle.red--text Inactive | ||||
|                   v-list-item-subtitle.green--text(v-if='user.tfaIsActive') Active | ||||
|                   v-list-item-subtitle.red--text(v-else) Inactive | ||||
|                 v-list-item-action | ||||
|                   v-tooltip(top) | ||||
|                     template(v-slot:activator='{ on }') | ||||
| @@ -709,7 +710,7 @@ export default { | ||||
|       } else { | ||||
|         this.$store.commit('showNotification', { | ||||
|           style: 'red', | ||||
|           message: _.get(resp, 'data.users.activate.responseResult.message', 'An unexpected error occured.'), | ||||
|           message: _.get(resp, 'data.users.activate.responseResult.message', 'An unexpected error occurred.'), | ||||
|           icon: 'warning' | ||||
|         }) | ||||
|       } | ||||
| @@ -749,7 +750,7 @@ export default { | ||||
|       } else { | ||||
|         this.$store.commit('showNotification', { | ||||
|           style: 'red', | ||||
|           message: _.get(resp, 'data.users.deactivate.responseResult.message', 'An unexpected error occured.'), | ||||
|           message: _.get(resp, 'data.users.deactivate.responseResult.message', 'An unexpected error occurred.'), | ||||
|           icon: 'warning' | ||||
|         }) | ||||
|       } | ||||
| @@ -798,7 +799,7 @@ export default { | ||||
|       } else { | ||||
|         this.$store.commit('showNotification', { | ||||
|           style: 'red', | ||||
|           message: _.get(resp, 'data.users.delete.responseResult.message', 'An unexpected error occured.'), | ||||
|           message: _.get(resp, 'data.users.delete.responseResult.message', 'An unexpected error occurred.'), | ||||
|           icon: 'warning' | ||||
|         }) | ||||
|       } | ||||
| @@ -864,7 +865,7 @@ export default { | ||||
|       } else { | ||||
|         this.$store.commit('showNotification', { | ||||
|           style: 'red', | ||||
|           message: _.get(resp, 'data.users.update.responseResult.message', 'An unexpected error occured.'), | ||||
|           message: _.get(resp, 'data.users.update.responseResult.message', 'An unexpected error occurred.'), | ||||
|           icon: 'warning' | ||||
|         }) | ||||
|       } | ||||
| @@ -935,7 +936,7 @@ export default { | ||||
|       } else { | ||||
|         this.$store.commit('showNotification', { | ||||
|           style: 'red', | ||||
|           message: _.get(resp, 'data.users.verify.responseResult.message', 'An unexpected error occured.'), | ||||
|           message: _.get(resp, 'data.users.verify.responseResult.message', 'An unexpected error occurred.'), | ||||
|           icon: 'warning' | ||||
|         }) | ||||
|       } | ||||
| @@ -962,6 +963,7 @@ export default { | ||||
|               createdAt | ||||
|               updatedAt | ||||
|               lastLoginAt | ||||
|               tfaIsActive | ||||
|               groups { | ||||
|                 id | ||||
|                 name | ||||
|   | ||||
| @@ -345,7 +345,7 @@ export default { | ||||
|             }) | ||||
|             const respObj = _.get(resp, 'data.system.importUsersFromV1', {}) | ||||
|             if (!_.get(respObj, 'responseResult.succeeded', false)) { | ||||
|               throw new Error(_.get(respObj, 'responseResult.message', 'An unexpected error occured')) | ||||
|               throw new Error(_.get(respObj, 'responseResult.message', 'An unexpected error occurred')) | ||||
|             } | ||||
|             this.successUsers = _.get(respObj, 'usersCount', 0) | ||||
|             this.successGroups = _.get(respObj, 'groupsCount', 0) | ||||
| @@ -429,7 +429,7 @@ export default { | ||||
|               }) | ||||
|               const respObj = _.get(respSv, 'data.storage.updateTargets', {}) | ||||
|               if (!_.get(respObj, 'responseResult.succeeded', false)) { | ||||
|                 throw new Error(_.get(respObj, 'responseResult.message', 'An unexpected error occured')) | ||||
|                 throw new Error(_.get(respObj, 'responseResult.message', 'An unexpected error occurred')) | ||||
|               } | ||||
|  | ||||
|               this.progress += 10 | ||||
| @@ -480,7 +480,7 @@ export default { | ||||
|  | ||||
|               const respImportObj = _.get(respImport, 'data.storage.executeAction', {}) | ||||
|               if (!_.get(respImportObj, 'responseResult.succeeded', false)) { | ||||
|                 throw new Error(_.get(respImportObj, 'responseResult.message', 'An unexpected error occured')) | ||||
|                 throw new Error(_.get(respImportObj, 'responseResult.message', 'An unexpected error occurred')) | ||||
|               } | ||||
|  | ||||
|               this.progress += 15 | ||||
|   | ||||
| @@ -314,7 +314,7 @@ export default { | ||||
|             this.$vuetify.goTo(`#comment-post-id-${_.get(resp, 'data.comments.create.id', 0)}`, this.scrollOpts) | ||||
|           }) | ||||
|         } else { | ||||
|           throw new Error(_.get(resp, 'data.comments.create.responseResult.message', 'An unexpected error occured.')) | ||||
|           throw new Error(_.get(resp, 'data.comments.create.responseResult.message', 'An unexpected error occurred.')) | ||||
|         } | ||||
|       } catch (err) { | ||||
|         this.$store.commit('showNotification', { | ||||
| @@ -420,7 +420,7 @@ export default { | ||||
|  | ||||
|           this.editCommentCancel() | ||||
|         } else { | ||||
|           throw new Error(_.get(resp, 'data.comments.delete.responseResult.message', 'An unexpected error occured.')) | ||||
|           throw new Error(_.get(resp, 'data.comments.delete.responseResult.message', 'An unexpected error occurred.')) | ||||
|         } | ||||
|       } catch (err) { | ||||
|         console.warn(err) | ||||
| @@ -482,7 +482,7 @@ export default { | ||||
|  | ||||
|           this.comments = _.reject(this.comments, ['id', this.commentToDelete.id]) | ||||
|         } else { | ||||
|           throw new Error(_.get(resp, 'data.comments.delete.responseResult.message', 'An unexpected error occured.')) | ||||
|           throw new Error(_.get(resp, 'data.comments.delete.responseResult.message', 'An unexpected error occurred.')) | ||||
|         } | ||||
|       } catch (err) { | ||||
|         this.$store.commit('showNotification', { | ||||
|   | ||||
| @@ -172,6 +172,19 @@ | ||||
|               span {{$t('common:header.newPage')}} | ||||
|             v-divider(vertical) | ||||
|  | ||||
|           //- ADMIN | ||||
|  | ||||
|           template(v-if='isAuthenticated && isAdmin') | ||||
|             v-tooltip(bottom, v-if='mode !== `admin`') | ||||
|               template(v-slot:activator='{ on }') | ||||
|                 v-btn(icon, tile, height='64', v-on='on', href='/a', :aria-label='$t(`common:header.admin`)') | ||||
|                   v-icon(color='grey') mdi-cog | ||||
|               span {{$t('common:header.admin')}} | ||||
|             v-btn(v-else, text, tile, height='64', href='/', :aria-label='$t(`common:actions.exit`)') | ||||
|               v-icon(left, color='grey') mdi-exit-to-app | ||||
|               span {{$t('common:actions.exit')}} | ||||
|             v-divider(vertical) | ||||
|  | ||||
|           //- ACCOUNT | ||||
|  | ||||
|           v-menu(v-if='isAuthenticated', offset-y, bottom, min-width='300', transition='slide-y-transition', left) | ||||
| @@ -210,9 +223,6 @@ | ||||
|                 v-list-item-action: v-icon(color='blue-grey') mdi-face-profile | ||||
|                 v-list-item-content | ||||
|                   v-list-item-title(:class='$vuetify.theme.dark ? `blue-grey--text text--lighten-3` : `blue-grey--text`') {{$t('common:header.profile')}} | ||||
|               v-list-item(href='/a', v-if='isAuthenticated && isAdmin') | ||||
|                 v-list-item-action.btn-animate-rotate: v-icon(:color='$vuetify.theme.dark ? `blue-grey lighten-3` : `blue-grey`') mdi-cog | ||||
|                 v-list-item-title(:class='$vuetify.theme.dark ? `blue-grey--text text--lighten-3` : `blue-grey--text`') {{$t('common:header.admin')}} | ||||
|               v-list-item(@click='logout') | ||||
|                 v-list-item-action: v-icon(color='red') mdi-logout | ||||
|                 v-list-item-title.red--text {{$t('common:header.logout')}} | ||||
|   | ||||
| @@ -418,7 +418,7 @@ export default { | ||||
|             window.location.assign(`/${this.locale}/${this.path}`) | ||||
|           }, 1000) | ||||
|         } else { | ||||
|           throw new Error(_.get(resp, 'data.pages.restore.responseResult.message', 'An unexpected error occured')) | ||||
|           throw new Error(_.get(resp, 'data.pages.restore.responseResult.message', 'An unexpected error occurred')) | ||||
|         } | ||||
|       } catch (err) { | ||||
|         this.$store.commit('showNotification', { | ||||
|   | ||||
| @@ -2,17 +2,27 @@ | ||||
|   v-app | ||||
|     .login(:style='`background-image: url(` + bgUrl + `);`') | ||||
|       .login-sd | ||||
|         .d-flex | ||||
|         .d-flex.mb-5 | ||||
|           .login-logo | ||||
|             v-avatar(tile, size='34') | ||||
|               v-img(:src='logoUrl') | ||||
|           .login-title | ||||
|             .text-h6 {{ siteTitle }} | ||||
|         v-alert.mb-0( | ||||
|           v-model='errorShown' | ||||
|           transition='slide-y-reverse-transition' | ||||
|           color='red darken-2' | ||||
|           tile | ||||
|           dark | ||||
|           dense | ||||
|           icon='mdi-alert' | ||||
|           ) | ||||
|           .body-2 {{errorMessage}} | ||||
|         //------------------------------------------------- | ||||
|         //- PROVIDERS LIST | ||||
|         //------------------------------------------------- | ||||
|         template(v-if='screen === `login` && strategies.length > 1') | ||||
|           .login-subtitle.mt-5 | ||||
|           .login-subtitle | ||||
|             .text-subtitle-1 Select Authentication Provider | ||||
|           .login-list | ||||
|             v-list.elevation-1.radius-7(nav) | ||||
| @@ -176,19 +186,51 @@ | ||||
|             v-model='securityCode' | ||||
|             :placeholder='$t("auth:tfa.placeholder")' | ||||
|             autocomplete='one-time-code' | ||||
|             @keyup.enter='verifySecurityCode' | ||||
|             @keyup.enter='verifySecurityCode(false)' | ||||
|           ) | ||||
|           v-btn.mt-2.text-none( | ||||
|             width='100%' | ||||
|             large | ||||
|             color='primary' | ||||
|             dark | ||||
|             @click='verifySecurityCode' | ||||
|             @click='verifySecurityCode(false)' | ||||
|             :loading='isLoading' | ||||
|             ) {{ $t('auth:tfa.verifyToken') }} | ||||
|  | ||||
|     //------------------------------------------------- | ||||
|     //- SETUP TFA FORM | ||||
|     //------------------------------------------------- | ||||
|     v-dialog(v-model='isTFASetupShown', max-width='600', persistent) | ||||
|       v-card | ||||
|         .login-tfa.text-center.pa-5 | ||||
|           .subtitle-1.primary--text Your administrator has required Two-Factor Authentication (2FA) to be enabled on your account. | ||||
|           v-divider.my-5 | ||||
|           .subtitle-2 1) Scan the QR code below from your mobile 2FA application: | ||||
|           .caption (e.g. #[a(href='https://authy.com/', target='_blank', noopener) Authy], #[a(href='https://support.google.com/accounts/answer/1066447', target='_blank', noopener) Google Authenticator], #[a(href='https://www.microsoft.com/en-us/account/authenticator', target='_blank', noopener) Microsoft Authenticator], etc.) | ||||
|           .login-tfa-qr.mt-5(v-if='isTFASetupShown', v-html='tfaQRImage') | ||||
|           .subtitle-2.mt-5 2) Enter the security code generated from your trusted device: | ||||
|           v-text-field.login-tfa-field.mt-2( | ||||
|             solo | ||||
|             flat | ||||
|             background-color='white' | ||||
|             hide-details | ||||
|             ref='iptTFASetup' | ||||
|             v-model='securityCode' | ||||
|             :placeholder='$t("auth:tfa.placeholder")' | ||||
|             autocomplete='one-time-code' | ||||
|             @keyup.enter='verifySecurityCode(true)' | ||||
|           ) | ||||
|           v-btn.mt-2.text-none( | ||||
|             width='100%' | ||||
|             large | ||||
|             color='primary' | ||||
|             dark | ||||
|             @click='verifySecurityCode(true)' | ||||
|             :loading='isLoading' | ||||
|             ) {{ $t('auth:tfa.verifyToken') }} | ||||
|  | ||||
|     loader(v-model='isLoading', :color='loaderColor', :title='loaderTitle', :subtitle='$t(`auth:pleaseWait`)') | ||||
|     notify | ||||
|     notify(style='padding-top: 64px;') | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| @@ -231,7 +273,11 @@ export default { | ||||
|       isShown: false, | ||||
|       newPassword: '', | ||||
|       newPasswordVerify: '', | ||||
|       isTFAShown: false | ||||
|       isTFAShown: false, | ||||
|       isTFASetupShown: false, | ||||
|       tfaQRImage: '', | ||||
|       errorShown: false, | ||||
|       errorMessage: '' | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
| @@ -282,26 +328,21 @@ export default { | ||||
|      * LOGIN | ||||
|      */ | ||||
|     async login () { | ||||
|       this.errorShown = false | ||||
|       if (this.username.length < 2) { | ||||
|         this.$store.commit('showNotification', { | ||||
|           style: 'red', | ||||
|           message: this.$t('auth:invalidEmailUsername'), | ||||
|           icon: 'alert' | ||||
|         }) | ||||
|         this.errorMessage = this.$t('auth:invalidEmailUsername') | ||||
|         this.errorShown = true | ||||
|         this.$refs.iptEmail.focus() | ||||
|       } else if (this.password.length < 2) { | ||||
|         this.$store.commit('showNotification', { | ||||
|           style: 'red', | ||||
|           message: this.$t('auth:invalidPassword'), | ||||
|           icon: 'alert' | ||||
|         }) | ||||
|         this.errorMessage = this.$t('auth:invalidPassword') | ||||
|         this.errorShown = true | ||||
|         this.$refs.iptPassword.focus() | ||||
|       } else { | ||||
|         this.loaderColor = 'grey darken-4' | ||||
|         this.loaderTitle = this.$t('auth:signingIn') | ||||
|         this.isLoading = true | ||||
|         try { | ||||
|           let resp = await this.$apollo.mutate({ | ||||
|           const resp = await this.$apollo.mutate({ | ||||
|             mutation: gql` | ||||
|               mutation($username: String!, $password: String!, $strategy: String!) { | ||||
|                 authentication { | ||||
| @@ -315,8 +356,10 @@ export default { | ||||
|                     jwt | ||||
|                     mustChangePwd | ||||
|                     mustProvideTFA | ||||
|                     mustSetupTFA | ||||
|                     continuationToken | ||||
|                     redirect | ||||
|                     tfaQRImage | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
| @@ -328,38 +371,9 @@ export default { | ||||
|             } | ||||
|           }) | ||||
|           if (_.has(resp, 'data.authentication.login')) { | ||||
|             let respObj = _.get(resp, 'data.authentication.login', {}) | ||||
|             const respObj = _.get(resp, 'data.authentication.login', {}) | ||||
|             if (respObj.responseResult.succeeded === true) { | ||||
|               this.continuationToken = respObj.continuationToken | ||||
|               if (respObj.mustChangePwd === true) { | ||||
|                 this.screen = 'changePwd' | ||||
|                 this.$nextTick(() => { | ||||
|                   this.$refs.iptNewPassword.focus() | ||||
|                 }) | ||||
|                 this.isLoading = false | ||||
|               } else if (respObj.mustProvideTFA === true) { | ||||
|                 this.screen = 'tfa' | ||||
|                 this.securityCode = '' | ||||
|                 this.$nextTick(() => { | ||||
|                   this.$refs.iptTFA.focus() | ||||
|                 }) | ||||
|                 this.isLoading = false | ||||
|               } else { | ||||
|                 this.loaderColor = 'green darken-1' | ||||
|                 this.loaderTitle = this.$t('auth:loginSuccess') | ||||
|                 Cookies.set('jwt', respObj.jwt, { expires: 365 }) | ||||
|                 _.delay(() => { | ||||
|                   const loginRedirect = Cookies.get('loginRedirect') | ||||
|                   if (loginRedirect) { | ||||
|                     Cookies.remove('loginRedirect') | ||||
|                     window.location.replace(loginRedirect) | ||||
|                   } else if (respObj.redirect) { | ||||
|                     window.location.replace(respObj.redirect) | ||||
|                   } else { | ||||
|                     window.location.replace('/') | ||||
|                   } | ||||
|                 }, 1000) | ||||
|               } | ||||
|               this.handleLoginResponse(respObj) | ||||
|             } else { | ||||
|               throw new Error(respObj.responseResult.message) | ||||
|             } | ||||
| @@ -380,58 +394,70 @@ export default { | ||||
|     /** | ||||
|      * VERIFY TFA CODE | ||||
|      */ | ||||
|     verifySecurityCode () { | ||||
|     async verifySecurityCode (setup = false) { | ||||
|       if (this.securityCode.length !== 6) { | ||||
|         this.$store.commit('showNotification', { | ||||
|           style: 'red', | ||||
|           message: 'Enter a valid security code.', | ||||
|           icon: 'warning' | ||||
|           icon: 'alert' | ||||
|         }) | ||||
|         this.$refs.iptTFA.focus() | ||||
|         if (setup) { | ||||
|           this.$refs.iptTFASetup.focus() | ||||
|         } else { | ||||
|           this.$refs.iptTFA.focus() | ||||
|         } | ||||
|       } else { | ||||
|         this.loaderColor = 'grey darken-4' | ||||
|         this.loaderTitle = this.$t('auth:signingIn') | ||||
|         this.isLoading = true | ||||
|         this.$apollo.mutate({ | ||||
|           mutation: gql` | ||||
|             { | ||||
|               authentication { | ||||
|                 activeStrategies { | ||||
|                   key | ||||
|         try { | ||||
|           const resp = await this.$apollo.mutate({ | ||||
|             mutation: gql` | ||||
|               mutation( | ||||
|                 $continuationToken: String! | ||||
|                 $securityCode: String! | ||||
|                 $setup: Boolean | ||||
|                 ) { | ||||
|                 authentication { | ||||
|                   loginTFA( | ||||
|                     continuationToken: $continuationToken | ||||
|                     securityCode: $securityCode | ||||
|                     setup: $setup | ||||
|                     ) { | ||||
|                     responseResult { | ||||
|                       succeeded | ||||
|                       errorCode | ||||
|                       slug | ||||
|                       message | ||||
|                     } | ||||
|                     jwt | ||||
|                     mustChangePwd | ||||
|                     continuationToken | ||||
|                     redirect | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|             `, | ||||
|             variables: { | ||||
|               continuationToken: this.continuationToken, | ||||
|               securityCode: this.securityCode, | ||||
|               setup | ||||
|             } | ||||
|           `, | ||||
|           variables: { | ||||
|             continuationToken: this.continuationToken, | ||||
|             securityCode: this.securityCode | ||||
|           } | ||||
|         }).then(resp => { | ||||
|           }) | ||||
|           if (_.has(resp, 'data.authentication.loginTFA')) { | ||||
|             let respObj = _.get(resp, 'data.authentication.loginTFA', {}) | ||||
|             if (respObj.responseResult.succeeded === true) { | ||||
|               this.$store.commit('showNotification', { | ||||
|                 message: 'Login successful!', | ||||
|                 style: 'success', | ||||
|                 icon: 'check' | ||||
|               }) | ||||
|               _.delay(() => { | ||||
|                 const loginRedirect = Cookies.get('loginRedirect') | ||||
|                 if (loginRedirect) { | ||||
|                   Cookies.remove('loginRedirect') | ||||
|                   window.location.replace(loginRedirect) | ||||
|                 } else if (respObj.redirect) { | ||||
|                   window.location.replace(respObj.redirect) | ||||
|                 } else { | ||||
|                   window.location.replace('/') | ||||
|                 } | ||||
|               }, 1000) | ||||
|               this.isLoading = false | ||||
|               this.handleLoginResponse(respObj) | ||||
|             } else { | ||||
|               if (!setup) { | ||||
|                 this.isTFAShown = false | ||||
|               } | ||||
|               throw new Error(respObj.responseResult.message) | ||||
|             } | ||||
|           } else { | ||||
|             throw new Error(this.$t('auth:genericError')) | ||||
|           } | ||||
|         }).catch(err => { | ||||
|         } catch (err) { | ||||
|           console.error(err) | ||||
|           this.$store.commit('showNotification', { | ||||
|             style: 'red', | ||||
| @@ -439,7 +465,7 @@ export default { | ||||
|             icon: 'alert' | ||||
|           }) | ||||
|           this.isLoading = false | ||||
|         }) | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     /** | ||||
| @@ -498,6 +524,46 @@ export default { | ||||
|         message: 'Coming soon!', | ||||
|         icon: 'ferry' | ||||
|       }) | ||||
|     }, | ||||
|     handleLoginResponse (respObj) { | ||||
|       this.continuationToken = respObj.continuationToken | ||||
|       if (respObj.mustChangePwd === true) { | ||||
|         this.screen = 'changePwd' | ||||
|         this.$nextTick(() => { | ||||
|           this.$refs.iptNewPassword.focus() | ||||
|         }) | ||||
|         this.isLoading = false | ||||
|       } else if (respObj.mustProvideTFA === true) { | ||||
|         this.securityCode = '' | ||||
|         this.isTFAShown = true | ||||
|         setTimeout(() => { | ||||
|           this.$refs.iptTFA.focus() | ||||
|         }, 500) | ||||
|         this.isLoading = false | ||||
|       } else if (respObj.mustSetupTFA === true) { | ||||
|         this.securityCode = '' | ||||
|         this.isTFASetupShown = true | ||||
|         this.tfaQRImage = respObj.tfaQRImage | ||||
|         setTimeout(() => { | ||||
|           this.$refs.iptTFASetup.focus() | ||||
|         }, 500) | ||||
|         this.isLoading = false | ||||
|       } else { | ||||
|         this.loaderColor = 'green darken-1' | ||||
|         this.loaderTitle = this.$t('auth:loginSuccess') | ||||
|         Cookies.set('jwt', respObj.jwt, { expires: 365 }) | ||||
|         _.delay(() => { | ||||
|           const loginRedirect = Cookies.get('loginRedirect') | ||||
|           if (loginRedirect) { | ||||
|             Cookies.remove('loginRedirect') | ||||
|             window.location.replace(loginRedirect) | ||||
|           } else if (respObj.redirect) { | ||||
|             window.location.replace(respObj.redirect) | ||||
|           } else { | ||||
|             window.location.replace('/') | ||||
|           } | ||||
|         }, 1000) | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   apollo: { | ||||
| @@ -619,6 +685,15 @@ export default { | ||||
|       &-field input { | ||||
|         text-align: center; | ||||
|       } | ||||
|  | ||||
|       &-qr { | ||||
|         background-color: #FFF; | ||||
|         padding: 5px; | ||||
|         border-radius: 5px; | ||||
|         width: 200px; | ||||
|         height: 200px; | ||||
|         margin: 0 auto; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
|   | ||||
| @@ -33,7 +33,7 @@ | ||||
|                   v-text-field.md2.mt-2( | ||||
|                     solo | ||||
|                     flat | ||||
|                     prepend-icon='mdi-textbox-password' | ||||
|                     prepend-icon='mdi-form-textbox-password' | ||||
|                     :background-color='$vuetify.theme.dark ? `grey darken-3` : `grey lighten-4`' | ||||
|                     ref='iptPassword' | ||||
|                     v-model='password' | ||||
| @@ -49,7 +49,7 @@ | ||||
|                   v-text-field.md2.mt-2( | ||||
|                     solo | ||||
|                     flat | ||||
|                     prepend-icon='mdi-textbox-password' | ||||
|                     prepend-icon='mdi-form-textbox-password' | ||||
|                     :background-color='$vuetify.theme.dark ? `grey darken-3` : `grey lighten-4`' | ||||
|                     hide-details | ||||
|                     ref='iptVerifyPassword' | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|             v-card.elevation-20.radius-7.animated.fadeInUp | ||||
|               v-alert(v-if='isDevMode', tile, dark, color='red darken-3', icon='mdi-alert', prominent) | ||||
|                 .body-2 You are running an unstable, unreleased development version. This code base is #[strong NOT] for production use! | ||||
|                 .body-2.mt-3 Cloning the master branch directly from GitHub is #[strong NOT] the proper way to install Wiki.js! | ||||
|                 .body-2.mt-3 Cloning the dev branch directly from GitHub is #[strong NOT] the proper way to install Wiki.js! | ||||
|                 .body-2 Read the #[a(href='https://docs.requarks.io/install', style='color: #FFF;') documentation] on correctly installing the latest stable version. | ||||
|               .text-center | ||||
|                 img.setup-logo.animated.fadeInUp.wait-p2s(src='/_assets/svg/logo-wikijs-full.svg', alt='Wiki.js Logo') | ||||
| @@ -249,7 +249,7 @@ export default { | ||||
|       height: 100vh; | ||||
|       z-index: 0; | ||||
|       background-color: transparent; | ||||
|       background-image: url(/_assets/svg/motif-grid.svg) !important; | ||||
|       background-image: url(../static/svg/motif-grid.svg) !important; | ||||
|       background-size: 100px; | ||||
|       background-repeat: repeat; | ||||
|       animation: bg-anim 100s linear infinite; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user