123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- <template lang="pug">
- v-app
- .login
- v-container(grid-list-lg)
- v-layout(row, wrap)
- v-flex(
- xs12
- offset-sm1, sm10
- offset-md2, md8
- offset-lg3, lg6
- offset-xl4, xl4
- )
- transition(name='fadeUp')
- v-card.elevation-5(v-show='isShown', light)
- v-toolbar(color='primary', flat, dense, dark)
- v-spacer
- .subheading(v-if='screen === "tfa"') {{ $t('auth:tfa.subtitle') }}
- .subheading(v-if='screen === "changePwd"') {{ $t('auth:changePwd.subtitle') }}
- .subheading(v-else-if='selectedStrategy.key !== "local"') {{ $t('auth:loginUsingStrategy', { strategy: selectedStrategy.title, interpolation: { escapeValue: false } }) }}
- .subheading(v-else) {{ $t('auth:loginRequired') }}
- v-spacer
- v-card-text.text-center
- h1.display-1.primary--text.py-2 {{ siteTitle }}
- template(v-if='screen === "login"')
- v-text-field.mt-3(
- solo
- flat
- prepend-icon='mdi-clipboard-account'
- background-color='grey lighten-4'
- hide-details
- ref='iptEmail'
- v-model='username'
- :placeholder='$t("auth:fields.emailUser")'
- )
- v-text-field.mt-2(
- solo
- flat
- prepend-icon='mdi-textbox-password'
- background-color='grey lighten-4'
- hide-details
- ref='iptPassword'
- v-model='password'
- :append-icon='hidePassword ? "mdi-eye-off" : "mdi-eye"'
- @click:append='() => (hidePassword = !hidePassword)'
- :type='hidePassword ? "password" : "text"'
- :placeholder='$t("auth:fields.password")'
- @keyup.enter='login'
- )
- template(v-else-if='screen === "tfa"')
- .body-2 Enter the security code generated from your trusted device:
- v-text-field.centered.mt-2(
- solo
- flat
- background-color='grey lighten-4'
- hide-details
- ref='iptTFA'
- v-model='securityCode'
- :placeholder='$t("auth:tfa.placeholder")'
- @keyup.enter='verifySecurityCode'
- )
- template(v-else-if='screen === "changePwd"')
- .body-2 {{$t('auth:changePwd.instructions')}}
- v-text-field.mt-2(
- type='password'
- solo
- flat
- background-color='grey lighten-4'
- hide-details
- ref='iptNewPassword'
- v-model='newPassword'
- :placeholder='$t(`auth:changePwd.newPasswordPlaceholder`)'
- )
- v-text-field.mt-2(
- type='password'
- solo
- flat
- background-color='grey lighten-4'
- hide-details
- v-model='newPasswordVerify'
- :placeholder='$t(`auth:changePwd.newPasswordVerifyPlaceholder`)'
- @keyup.enter='changePassword'
- )
- template(v-else-if='screen === "forgot"')
- .body-2 {{ $t('auth:forgotPasswordSubtitle') }}
- v-text-field.mt-3(
- solo
- flat
- prepend-icon='mdi-email'
- background-color='grey lighten-4'
- hide-details
- ref='iptEmailForgot'
- v-model='username'
- :placeholder='$t("auth:fields.email")'
- )
- v-card-actions.pb-4
- v-spacer
- v-btn(
- width='100%'
- max-width='250px'
- v-if='screen === "login"'
- large
- color='teal'
- dark
- @click='login'
- rounded
- :loading='isLoading'
- ) {{ $t('auth:actions.login') }}
- v-btn(
- width='100%'
- max-width='250px'
- v-else-if='screen === "tfa"'
- large
- color='teal'
- dark
- @click='verifySecurityCode'
- rounded
- :loading='isLoading'
- ) {{ $t('auth:tfa.verifyToken') }}
- v-btn(
- width='100%'
- max-width='250px'
- v-else-if='screen === "changePwd"'
- large
- color='teal'
- dark
- @click='changePassword'
- rounded
- :loading='isLoading'
- ) {{ $t('auth:changePwd.proceed') }}
- v-btn(
- width='100%'
- max-width='250px'
- v-else-if='screen === "forgot"'
- large
- color='teal'
- dark
- @click='forgotPasswordSubmit'
- rounded
- :loading='isLoading'
- ) {{ $t('auth:sendResetPassword') }}
- v-spacer
- v-card-actions.pb-3(v-if='screen === "login" && selectedStrategy.key === "local"')
- v-spacer
- a.caption(@click.stop.prevent='forgotPassword', href='#forgot') {{ $t('auth:forgotPasswordLink') }}
- v-spacer
- v-card-actions.pb-3(v-else-if='screen === "forgot"')
- v-spacer
- a.caption(@click.stop.prevent='screen = `login`', href='#cancelforgot') {{ $t('auth:forgotPasswordCancel') }}
- v-spacer
- template(v-if='screen === "login" && isSocialShown')
- v-divider
- v-card-text.grey.lighten-4.text-center
- .pb-2.body-2.text-xs-center.grey--text.text--darken-2 {{ $t('auth:orLoginUsingStrategy') }}
- v-btn.mx-1.social-login-btn(
- v-for='strategy in strategies', :key='strategy.key'
- large
- @click='selectStrategy(strategy)'
- dark
- :color='strategy.color'
- :depressed='strategy.key === selectedStrategy.key'
- )
- v-avatar.mr-3(tile, :class='strategy.color', size='24', v-html='strategy.icon')
- span(style='text-transform: none;') {{ strategy.title }}
- template(v-if='screen === "login" && selectedStrategy.selfRegistration')
- v-divider
- v-card-actions.py-3(:class='isSocialShown ? "" : "grey lighten-4"')
- v-spacer
- i18next.caption(path='auth:switchToRegister.text', tag='div')
- a.caption(href='/register', place='link') {{ $t('auth:switchToRegister.link') }}
- v-spacer
- loader(v-model='isLoading', :color='loaderColor', :title='loaderTitle', :subtitle='$t(`auth:pleaseWait`)')
- nav-footer(color='grey darken-4')
- notify
- </template>
- <script>
- /* global siteConfig */
- import _ from 'lodash'
- import Cookies from 'js-cookie'
- import strategiesQuery from 'gql/login/login-query-strategies.gql'
- import loginMutation from 'gql/login/login-mutation-login.gql'
- import tfaMutation from 'gql/login/login-mutation-tfa.gql'
- import changePasswordMutation from 'gql/login/login-mutation-changepassword.gql'
- export default {
- i18nOptions: { namespaces: 'auth' },
- data () {
- return {
- error: false,
- strategies: [],
- selectedStrategy: { key: 'local' },
- screen: 'login',
- username: '',
- password: '',
- hidePassword: true,
- securityCode: '',
- continuationToken: '',
- isLoading: false,
- loaderColor: 'grey darken-4',
- loaderTitle: 'Working...',
- isShown: false,
- newPassword: '',
- newPasswordVerify: ''
- }
- },
- computed: {
- siteTitle () {
- return siteConfig.title
- },
- isSocialShown () {
- return this.strategies.length > 1
- }
- },
- watch: {
- strategies(newValue, oldValue) {
- this.selectedStrategy = _.find(newValue, ['key', 'local'])
- }
- },
- mounted () {
- this.isShown = true
- this.$nextTick(() => {
- this.$refs.iptEmail.focus()
- })
- },
- methods: {
- /**
- * SELECT STRATEGY
- */
- selectStrategy (strategy) {
- this.selectedStrategy = strategy
- this.screen = 'login'
- if (!strategy.useForm) {
- this.isLoading = true
- window.location.assign('/login/' + strategy.key)
- } else {
- this.$nextTick(() => {
- this.$refs.iptEmail.focus()
- })
- }
- },
- /**
- * LOGIN
- */
- async login () {
- if (this.username.length < 2) {
- this.$store.commit('showNotification', {
- style: 'red',
- message: this.$t('auth:invalidEmailUsername'),
- icon: 'alert'
- })
- this.$refs.iptEmail.focus()
- } else if (this.password.length < 2) {
- this.$store.commit('showNotification', {
- style: 'red',
- message: this.$t('auth:invalidPassword'),
- icon: 'alert'
- })
- 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({
- mutation: loginMutation,
- variables: {
- username: this.username,
- password: this.password,
- strategy: this.selectedStrategy.key
- }
- })
- if (_.has(resp, 'data.authentication.login')) {
- let 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(() => {
- window.location.replace('/') // TEMPORARY - USE RETURNURL
- }, 1000)
- }
- } else {
- throw new Error(respObj.responseResult.message)
- }
- } else {
- throw new Error(this.$t('auth:genericError'))
- }
- } catch (err) {
- console.error(err)
- this.$store.commit('showNotification', {
- style: 'red',
- message: err.message,
- icon: 'alert'
- })
- this.isLoading = false
- }
- }
- },
- /**
- * VERIFY TFA CODE
- */
- verifySecurityCode () {
- if (this.securityCode.length !== 6) {
- this.$store.commit('showNotification', {
- style: 'red',
- message: 'Enter a valid security code.',
- icon: 'warning'
- })
- this.$refs.iptTFA.focus()
- } else {
- this.isLoading = true
- this.$apollo.mutate({
- mutation: tfaMutation,
- 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(() => {
- window.location.replace('/') // TEMPORARY - USE RETURNURL
- }, 1000)
- this.isLoading = false
- } else {
- throw new Error(respObj.responseResult.message)
- }
- } else {
- throw new Error(this.$t('auth:genericError'))
- }
- }).catch(err => {
- console.error(err)
- this.$store.commit('showNotification', {
- style: 'red',
- message: err.message,
- icon: 'alert'
- })
- this.isLoading = false
- })
- }
- },
- /**
- * CHANGE PASSWORD
- */
- async changePassword () {
- this.loaderColor = 'grey darken-4'
- this.loaderTitle = this.$t('auth:changePwd.loading')
- this.isLoading = true
- const resp = await this.$apollo.mutate({
- mutation: changePasswordMutation,
- variables: {
- continuationToken: this.continuationToken,
- newPassword: this.newPassword
- }
- })
- if (_.get(resp, 'data.authentication.loginChangePassword.responseResult.succeeded', false) === true) {
- this.loaderColor = 'green darken-1'
- this.loaderTitle = this.$t('auth:loginSuccess')
- Cookies.set('jwt', _.get(resp, 'data.authentication.loginChangePassword.jwt', ''), { expires: 365 })
- _.delay(() => {
- window.location.replace('/') // TEMPORARY - USE RETURNURL
- }, 1000)
- } else {
- this.$store.commit('showNotification', {
- style: 'red',
- message: _.get(resp, 'data.authentication.loginChangePassword.responseResult.message', false),
- icon: 'alert'
- })
- this.isLoading = false
- }
- },
- /**
- * SWITCH TO FORGOT PASSWORD SCREEN
- */
- forgotPassword () {
- this.screen = 'forgot'
- this.$nextTick(() => {
- this.$refs.iptEmailForgot.focus()
- })
- },
- /**
- * FORGOT PASSWORD SUBMIT
- */
- async forgotPasswordSubmit () {
- this.$store.commit('showNotification', {
- style: 'pink',
- message: 'Coming soon!',
- icon: 'ferry'
- })
- }
- },
- apollo: {
- strategies: {
- query: strategiesQuery,
- update: (data) => data.authentication.strategies,
- watchLoading (isLoading) {
- this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'login-strategies-refresh')
- }
- }
- }
- }
- </script>
- <style lang="scss">
- .login {
- background-color: mc('grey', '900');
- background-image: url('../static/svg/motif-blocks.svg');
- background-repeat: repeat;
- background-size: 200px;
- width: 100%;
- height: 100%;
- animation: loginBgReveal 20s linear infinite;
- @include keyframes(loginBgReveal) {
- 0% {
- background-position-x: 0;
- }
- 100% {
- background-position-x: 800px;
- }
- }
- &::before {
- content: '';
- position: absolute;
- background-image: url('../static/svg/motif-overlay.svg');
- background-attachment: fixed;
- background-size: cover;
- opacity: .5;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100vh;
- }
- > .container {
- height: 100%;
- align-items: center;
- display: flex;
- }
- .social-login-btn {
- cursor: pointer;
- transition: opacity .2s ease;
- &:hover {
- opacity: .8;
- }
- margin: .25rem 0;
- svg {
- width: 24px;
- height: 24px;
- bottom: 0;
- path {
- fill: #FFF;
- }
- }
- }
- .v-text-field.centered input {
- text-align: center;
- }
- }
- </style>
|