Skip to content

Commit

Permalink
return url and registration view updates
Browse files Browse the repository at this point in the history
  • Loading branch information
utku-ozturk committed Dec 14, 2023
1 parent 3a7428c commit 174d510
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ItemDetailList } from '@hms-dbmi-bgm/shared-portal-components/es/compon
* Component that essentially handles the "callback" interaction previously done by
* the UI. The interaction in the Redis state now proceeds as follows:
* 1. The UI renders the Auth0Lock component in 'code' mode
* 2. The user logs in via the Auth0Lock and transmits the code to the back-end
* 2. The user logs in via the Auth0Lock and transmits the code to the back-end
* via GET /callback?code=abcdefg...
* 3. The back-end calls into Auth0 to get JWT and returns a session token to
* the browser, returning a success response
Expand All @@ -25,7 +25,7 @@ export default class LoginSuccessView extends React.PureComponent {
static propTypes = {
'readyToRedirect': PropTypes.bool
};

constructor(props) {
super(props);
this.state = {
Expand All @@ -35,7 +35,7 @@ export default class LoginSuccessView extends React.PureComponent {

/**
* This component is meant to be loaded upon navigating from backend on authentication to the /callback
* Once that has happened, we should have stored a jwtToken as a cookie that
* Once that has happened, we should have stored a jwtToken as a cookie that
* we can use to make authenticated requests ie: the below calls should return
* clean responses if the user successfully logged in and error out appropriately if
* they did not.
Expand All @@ -48,62 +48,62 @@ export default class LoginSuccessView extends React.PureComponent {
setTimeout(function(){ reject({ 'description' : 'timed out', 'type' : 'timed-out' }); }, 30000); /* 30 seconds */
})
])
.then((response) => {
// this may not be needed?
console.log('got response from session properties', response);
if (response.code || response.status) throw response;
return response;
})
.then((userInfoResponse) => {
const {
details: {
email: userEmail = null
} = {},
user_actions = []
} = userInfoResponse;

if (!userEmail) {
throw new Error("Did not receive user details from /session-properties, login failed.");
}

// Fetch user profile and (outdated/to-revisit-later) use their primary lab as the eventLabel.
const profileURL = (_.findWhere(user_actions, { 'id' : 'profile' }) || {}).href;
if (profileURL){
this.setState({ "isLoading" : false });
.then((response) => {
// this may not be needed?
console.log('got response from session properties', response);
if (response.code || response.status) throw response;
return response;
})
.then((userInfoResponse) => {
const {
details: {
email: userEmail = null
} = {},
user_actions = []
} = userInfoResponse;

JWT.saveUserInfoLocalStorage(userInfoResponse);
updateAppSessionState(); // <- this function (in App.js) is now expected to call `Alerts.deQueue(Alerts.LoggedOut);`
console.info('Login completed');

// Register an analytics event for UI login.
// This is used to segment public vs internal audience in Analytics dashboards.
load(profileURL, (profile)=>{
if (typeof successCallback === 'function'){
successCallback(profile);
}
if (typeof onLogin === 'function'){
onLogin(profile);
}

const { uuid: userId, groups = null } = profile;

setUserID(userId);

trackEvent('Authentication', 'UILogin', {
eventLabel : "Authenticated ClientSide",
name: userId,
userId,
userGroups: groups && (JSON.stringify(groups.sort()))
});
if (!userEmail) {
throw new Error("Did not receive user details from /session-properties, login failed.");
}

}, 'GET', ()=>{
throw new Error('Request to profile URL failed.');
});
} else {
console.log('in failed user profile fetch');
throw new Error('No profile URL found in user_actions.');
}
}).catch((error)=>{
// Fetch user profile and (outdated/to-revisit-later) use their primary lab as the eventLabel.
const profileURL = (_.findWhere(user_actions, { 'id': 'profile' }) || {}).href;
if (profileURL) {
this.setState({ "isLoading": false });

JWT.saveUserInfoLocalStorage(userInfoResponse);
updateAppSessionState(); // <- this function (in App.js) is now expected to call `Alerts.deQueue(Alerts.LoggedOut);`
console.info('Login completed');

// Register an analytics event for UI login.
// This is used to segment public vs internal audience in Analytics dashboards.
load(profileURL, (profile) => {
if (typeof successCallback === 'function') {
successCallback(profile);
}
if (typeof onLogin === 'function') {
onLogin(profile);
}

const { uuid: userId, groups = null } = profile;

setUserID(userId);

trackEvent('Authentication', 'UILogin', {
eventLabel: "Authenticated ClientSide",
name: userId,
userId,
userGroups: groups && (JSON.stringify(groups.sort()))
});

}, 'GET', () => {
throw new Error('Request to profile URL failed.');
});
} else {
console.log('in failed user profile fetch');
throw new Error('No profile URL found in user_actions.');
}
}).catch((error) => {
// Handle Errors
console.log(error);

Expand All @@ -119,16 +119,23 @@ export default class LoginSuccessView extends React.PureComponent {
});
}

getReturnUrl() {
const url = document.cookie.split("; ").find((row) => row.startsWith("returnUrl="))?.split("=")[1];
return (url && decodeURIComponent(url)) || '/';
}

render() {
var { context, schemas } = this.props;
if (this.state.readyToRedirect) {
navigate("/", {}, (resp)=>{
navigate(this.getReturnUrl(), {}, (resp)=>{
// Show alert on new Item page
Alerts.queue({
'title' : 'Success',
'message' : 'You are now logged in.',
'style' : 'success'
});
//remove return url cookie
document.cookie = `returnUrl=; expires=${new Date(0).toUTCString()}; path=/;`;
});
}
// This needs styling, maybe a spinning loader? Will look into later
Expand All @@ -138,5 +145,5 @@ export default class LoginSuccessView extends React.PureComponent {
<ItemDetailList context={context} schemas={schemas} />
</div>
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import _ from 'underscore';
import { UserRegistrationModal } from './UserRegistrationModal';
import { onLoginNavItemClick } from './LoginNavItem';
import { JWT, console, navigate } from '@hms-dbmi-bgm/shared-portal-components/es/components/util';
import { performLogout } from '@hms-dbmi-bgm/shared-portal-components/es/components/navigation/components/LoginController';
import { event as trackEvent, setUserID } from '@hms-dbmi-bgm/shared-portal-components/es/components/util/analytics';
import { load, fetch } from '@hms-dbmi-bgm/shared-portal-components/es/components/util/ajax';

Expand All @@ -20,7 +22,9 @@ export default class UserRegistrationView extends React.PureComponent {
constructor(props) {
super(props);
this.onRegistrationComplete = this.onRegistrationComplete.bind(this);
this.onRegistrationCancel = this.onRegistrationCancel.bind(this);
this.onLogin = this.onLogin.bind(this);
this.showLock = this.showLock.bind(this);
this.state = {
id: 'loginbtn',
unverifiedUserEmail: props.context['@graph'][0],
Expand Down Expand Up @@ -115,7 +119,31 @@ export default class UserRegistrationView extends React.PureComponent {
console.log("Logged in", profile);
}

onRegistrationCancel() {
// even user is not registered and logged in yet, jwtToken (having redis key) has already been created.
// performLogout clears any user-specific data stored during the oauth process.
performLogout().then(()=>{

this.setState({ "isLoading" : false });

// Remove from analytics session
setUserID(null);

// Attempt to preserve hash, if any, but don't scroll to it.
const windowHash = '/';//(window && window.location && window.location.hash) || '';
console.info("Logged out; re-loading context");
navigate(windowHash, { "inPlace" : true, "dontScrollToTop" : !!(windowHash) });
});
}

showLock(){
onLoginNavItemClick();
}

render() {
return <UserRegistrationModal {... this.state} onRegistrationComplete={this.onRegistrationComplete} onLogin={this.onLogin} />;
return (
<UserRegistrationModal {... this.state} onRegistrationComplete={this.onRegistrationComplete}
onRegistrationCancel={this.onRegistrationCancel} onLogin={this.onLogin} showLock={this.showLock} />
);
}
}

0 comments on commit 174d510

Please sign in to comment.