Skip to content

Commit

Permalink
feat: remember urls (#523)
Browse files Browse the repository at this point in the history
* feat: oauth-refacto2

feat: ARA-124

* feat: refactor oauth urls

* feat: remember urls

feat: ACDC-193

* fix chart
  • Loading branch information
regislegrand authored Oct 29, 2021
1 parent cbd225b commit 842e964
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 105 deletions.
2 changes: 1 addition & 1 deletion charts/candidate/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
apiVersion: v2
name: ara
version: 10.0.0-rc.2
version: 10.0.0-rc.3
home: https://github.com/Decathlon/ara
description: |
ARA helps you to fight against regressions by letting it preanalyze your non-regression tests runs,
Expand Down
2 changes: 1 addition & 1 deletion charts/candidate/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ ui:
image:
registry: docker.io
repository: decathlon/ara-web-ui
tag: 9.2.0
tag: 9.3.0
imagePullPolicy: IfNotPresent
replicas: 1
annotations: {}
Expand Down
2 changes: 1 addition & 1 deletion code/web-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion code/web-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ara-client",
"version": "9.2.0",
"version": "9.3.0",
"description": "Agile Regression Analyzer front app",
"author": "Decathlon <developers@decathlon.com>",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion code/web-ui/src/components/top-menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@
},

logout () {
AuthenticationService.logout(this.configuration.authentication.logoutProcessingUrl)
AuthenticationService.logout()
}
},

Expand Down
7 changes: 7 additions & 0 deletions code/web-ui/src/libs/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,11 @@ util.copyTextToClipboard = function (textToCopy) {
})
}

// When conf changes between 2 versions, such as local storage
// keys which are removed or indexed db definitions, this function
// helps to keep the browser clean
util.cleanFromPreviousVersion = function () {
localStorage.removeItem('last_url')
}

export default util
90 changes: 3 additions & 87 deletions code/web-ui/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ import VueVirtualScroller from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import { AuthenticationService } from './service/authentication.service'
import configurationPlugin from '@/config'
import { config } from './config'
import api from './libs/api'
import VueCookies from 'vue-cookies'

import { sanitizeUrl } from '@braintree/sanitize-url'
Expand All @@ -57,95 +55,11 @@ iView.Message.config({
})

const router = new VueRouter({
mode: 'history',
routes: routes
})

const deferNext = function (next, action, message) {
console.info(`calling next:${action} / message: ${message}`)
return next(action)
}

const manageLoginRedirection = async function (to, from, next) {
const getOauthProviders = async () => {
return Vue.http.get(api.paths.authenticationConfiguration(), api.REQUEST_OPTIONS)
.then(response => response.body)
.then(content => {
const res = {
loginStartingUrl: content.loginStartingUrl,
logoutProcessingUrl: content.logoutProcessingUrl,
providers: content.providers.reduce((previous, current) => {
previous[current.providerType] = {
uri: `${content.loginStartingUrl}/${current.code}`,
display: current.displayName,
icon: current.providerType === 'custom' ? 'building' : current.providerType,
name: current.code
}
return previous
}, {})
}
console.debug(res)
return res
})
}

const isPublic = to.matched.some(record => record.meta.public)
const onlyWhenLoggedOut = to.matched.some(record => record.meta.onlyWhenLoggedOut)

if (isPublic) {
return deferNext(next, undefined, 'url is public')
}
if (config.downloadError) {
return deferNext(next, '/login', 'downloadError is defined')
}

const loggedIn = await AuthenticationService.isAlreadyLoggedIn()
const needToDownloadConfig = !(config.isComplete)
console.debug(`loggedIn? ${loggedIn} / needToDownloadConfig? ${needToDownloadConfig}`)
if (needToDownloadConfig) {
try {
config.authentication = await getOauthProviders()
console.debug('Authent conf retrieved')
config.downloadError = false
} catch (err) {
console.error(err)
config.downloadError = true
return deferNext(next, '/login', 'error while retrieving providers')
}
}

const requireLogin = !loggedIn && config.authentication.enabled
if (!loggedIn) {
iView.Notice.open({
title: 'Access denied',
desc: 'You need to login first if you want to access this page.'
})
return deferNext(next, '/login', 'access denied')
}

const loggedInButTryingToReachALoggedOutPage = loggedIn && onlyWhenLoggedOut
if (loggedInButTryingToReachALoggedOutPage) {
iView.Notice.open({
title: 'You are already connected!',
desc: 'Logged out pages (such as the login page) can\'t be viewed if you are already connected. Please logout from ARA first.',
duration: 0
})
return next('/')
}

const loginNotRequiredButTryingToAccessLogin = !requireLogin && onlyWhenLoggedOut
if (loginNotRequiredButTryingToAccessLogin) {
iView.Notice.open({
title: 'Login not required!',
desc: 'You cannot access the login page because the authentication is not enabled.<br>If you want to enable it, please check your configuration files.',
duration: 0
})
return next('/')
}
}

router.beforeEach(async (to, from, next) => {
await manageLoginRedirection(to, from, next)
await AuthenticationService.manageLoginRedirection(to, from, next)

iView.LoadingBar.start()
util.title(to.meta.title)
Expand All @@ -159,6 +73,8 @@ router.afterEach(() => {
window.scrollTo(0, 0)
})

util.cleanFromPreviousVersion()

Vue.prototype.$sanitizeUrl = sanitizeUrl

/* eslint-disable no-new */
Expand Down
102 changes: 90 additions & 12 deletions code/web-ui/src/service/authentication.service.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import Vue from 'vue'
import iView from 'iview'
import api from '../libs/api'
import RememberUrlService from './rememberurl.service'
import { config } from '../config.js'

const USER_DETAILS = 'user_details'
const PROVIDER_NAME = 'provider_name'

const LAST_URL_BEFORE_LOGOUT = 'last_url'
const conf = config

let isLogged = false

Expand Down Expand Up @@ -40,21 +43,96 @@ const AuthenticationService = {
})
},

logout (url) {
this.saveUrl()
this.clearDetails()
// window.location.href = config.authentication.logoutProcessingUrl
window.location.href = url
async getOauthProviders () {
return Vue.http.get(api.paths.authenticationConfiguration(), api.REQUEST_OPTIONS)
.then(response => response.body)
.then(content => {
const res = {
loginStartingUrl: content.loginStartingUrl,
logoutProcessingUrl: content.logoutProcessingUrl,
providers: content.providers.reduce((previous, current) => {
previous[current.providerType] = {
uri: `${content.loginStartingUrl}/${current.code}`,
display: current.displayName,
icon: current.providerType === 'custom' ? 'building' : current.providerType,
name: current.code
}
return previous
}, {})
}
console.debug(res)
return res
})
},

saveUrl () {
const currentUrl = window.location.pathname
localStorage.setItem(LAST_URL_BEFORE_LOGOUT, currentUrl)
async manageLoginRedirection (to, from, next) {
// RememberUrlService.redirectToLastWantedUrlWhenLoggin(from, to, next)
RememberUrlService.keepLastUrl(to)

const isPublic = to.matched.some(record => record.meta.public)
const onlyWhenLoggedOut = to.matched.some(record => record.meta.onlyWhenLoggedOut)

if (isPublic) {
console.debug('url is public, continue')
return next()
}
if (config.downloadError) {
console.debug('downloadError is defined')
return next('/login')
}

const loggedIn = await this.isAlreadyLoggedIn()
const needToDownloadConfig = !(config.isComplete)
console.debug(`loggedIn? ${loggedIn} / needToDownloadConfig? ${needToDownloadConfig}`)
if (needToDownloadConfig) {
try {
config.authentication = await this.getOauthProviders()
console.debug('Authent conf retrieved')
config.downloadError = false
} catch (err) {
console.error(err)
config.downloadError = true
console.debug('error while retrieving providers')
return next('/login')
}
}

const requireLogin = !loggedIn && config.authentication.enabled
if (!loggedIn) {
iView.Notice.open({
title: 'Access denied',
desc: 'You need to login first if you want to access this page.'
})
console.debug('access denied')
return next('/login')
}

const loggedInButTryingToReachALoggedOutPage = loggedIn && onlyWhenLoggedOut
if (loggedInButTryingToReachALoggedOutPage) {
iView.Notice.open({
title: 'You are already connected!',
desc: 'Logged out pages (such as the login page) can\'t be viewed if you are already connected. Please logout from ARA first.',
duration: 0
})
return next('/')
}

const loginNotRequiredButTryingToAccessLogin = !requireLogin && onlyWhenLoggedOut
if (loginNotRequiredButTryingToAccessLogin) {
iView.Notice.open({
title: 'Login not required!',
desc: 'You cannot access the login page because the authentication is not enabled.<br>If you want to enable it, please check your configuration files.',
duration: 0
})
return next('/')
}
},

getLastUrlBeforeLogout () {
const url = localStorage.getItem(LAST_URL_BEFORE_LOGOUT)
return url || '/'
logout () {
this.clearDetails()
// window.location.href = config.authentication.logoutProcessingUrl
console.debug(`conf imported ? ${conf !== undefined}`)
window.location.href = conf.authentication.logoutProcessingUrl
},

getDetails () {
Expand Down
53 changes: 53 additions & 0 deletions code/web-ui/src/service/rememberurl.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@

const LAST_ROUTEPATH_KEY = 'LAST_ASKED_ROUTE'

const RememberUrlService = {

keepLastUrl (to) {
// We dont register the url in the following cases:
// login/logout is asked
// we're already going to the last saved url
// the / is asked whereas we're coming fron a server redirection
if (to.name === 'login') {
return
}
if (to.name === 'logout') {
return
}
const lastRoute = localStorage.getItem(LAST_ROUTEPATH_KEY)
if (to.path === lastRoute) {
return
}
if (this.redirectAsked()) {
return
}

// in all other cases, we just register the current asked route
localStorage.setItem(LAST_ROUTEPATH_KEY, to.path)
},

resetRedirectAsked () {
window.history.replaceState({}, document.title, window.location.pathname)
},

redirectAsked (resetRedirection = false) {
const res = new URLSearchParams(window.location.search).get('spring_redirect') === 'true'
if (resetRedirection) {
this.resetRedirectAsked()
}
return res
},

// We dont need to redirect when the target
// is already the asked url
redirectNeeded (redirectPath) {
return redirectPath !== localStorage.getItem(LAST_ROUTEPATH_KEY)
},

getRedirectPath () {
return localStorage.getItem(LAST_ROUTEPATH_KEY)
}

}

export default RememberUrlService
1 change: 1 addition & 0 deletions code/web-ui/src/views/login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
Configuration not found, you can't login to ARA.
</div>
</div>
<!--Spin fix v-if="authenticating"/-->
</div>
</template>

Expand Down
18 changes: 17 additions & 1 deletion code/web-ui/src/views/redirecter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

<script>
import { mapState } from 'vuex'
import { AuthenticationService } from '../service/authentication.service'
import RememberUrlService from '../service/rememberurl.service'

export default {
name: 'redirecter',
Expand All @@ -36,6 +38,15 @@

methods: {
redirect () {
if (RememberUrlService.redirectAsked(true) && RememberUrlService.redirectNeeded(this.$route.path)) {
const redicrectPath = RememberUrlService.getRedirectPath()
if (redicrectPath) {
this.$router.replace({
path: redicrectPath
})
return
}
}
if (!this.defaultProjectCode) {
// No project: go to project management screen
this.$router.replace({ name: 'management-projects' })
Expand All @@ -56,7 +67,12 @@
if (this.loaded) {
this.redirect()
} else {
this.$store.dispatch('projects/ensureProjectsLoaded')
AuthenticationService.isAlreadyLoggedIn()
.then((isLogged) => {
if (isLogged) {
this.$store.dispatch('projects/ensureProjectsLoaded')
}
})
}
},

Expand Down

0 comments on commit 842e964

Please sign in to comment.