Skip to content

Commit

Permalink
Merge pull request #76 from googleinterns/authenticate-user-for-trip
Browse files Browse the repository at this point in the history
Authenticate user for trip
  • Loading branch information
keiffer01 authored Jul 28, 2020
2 parents 0b04c09 + f3a68e7 commit e213e4f
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 9 deletions.
89 changes: 81 additions & 8 deletions frontend/src/components/ViewActivities/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,92 @@
import React from 'react';
import ActivityList from './activitylist.js';

import app from '../Firebase';

import { getUserUid } from '../AuthUtils';
import ActivityList from './activitylist.js';
import * as DB from '../../constants/database.js';

/**
* The whole view activities page.
*
* The view activities page. First checks that the current user is authorized to
* view the current trip (i.e. they are a collaborator for it). If so, the
* ActivityList component is displayed as normal. If not, an error is displayed
* instead.
*
* @param {Object} props This component expects the following props:
* - `tripId` {string} The trip's ID. This is sent to the component through the URL.
* - `tripId` {string} The trip's ID. This is sent to the component through the URL.
*/
class ViewActivities extends React.Component {
/** @inheritdoc */
constructor(props) {
super(props);
this.tripId = props.match.params.tripId;
this.state = {
collaborators: undefined,
isLoading: true,
error: undefined
}
}

/** @inheritdoc */
componentDidMount() {
app.firestore()
.collection(DB.COLLECTION_TRIPS)
.doc(this.tripId)
.get()
.then(doc => {
this.setState({
collaborators: doc.get(DB.TRIPS_COLLABORATORS),
isLoading: false,
error: undefined
});
})
.catch(e => {
this.setState({
collaborators: undefined,
isLoading: true,
error: e
})
});
}

/** @inheritdoc */
render() {
return (
<div className='activity-page'>
<ActivityList tripId={this.props.match.params.tripId}/>
</div>
)
// Case where there was a Firebase error.
if (this.state.error !== undefined) {
// TODO (Issue #74): Redirect to an error page instead.
return (
<div>
Oops, looks like something went wrong. Please wait a few minutes and
try again.
</div>
);
}
// Case where the trip details are still being fetched.
if (this.state.isLoading) {
// TODO (Issue #25): Please remember to make this a blank div in the
// deployed build lol.
return <div>Loading Part 2: Electric Boogaloo</div>;
}
// Case where the trip could not be found. A field is returned undefined if
// the trip does not exist, so we check that the retrieved collaborators is
// undefined.
else if (this.state.collaborators === undefined) {
// TODO (Issue #74): Redirect to an error page instead.
return <div>Sorry, we couldn't find the trip you were looking for.</div>;
}
// Case where the current user is not authorized to view the page
else if (!this.state.collaborators.includes(getUserUid())) {
// TODO (Issue #74): Redirect to an error page instead.
return <div>Sorry, you're not authorized to view this trip.</div>;
}
else {
return (
<div className='activity-page'>
<ActivityList tripId={this.tripId}/>
</div>
);
}
}
}

Expand Down
73 changes: 73 additions & 0 deletions frontend/src/components/ViewActivities/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import { render, screen, cleanup } from '@testing-library/react';
import ViewActivities from './index.js';
import authUtils from '../AuthUtils';

const FAKE_USER = 'totally-legit-user';
const FAKE_TRIPID = '12345';
const RESULT_AUTHORIZED = FAKE_TRIPID;
const RESULT_NOT_AUTHORIZED =
'Sorry, you\'re not authorized to view this trip.';
const RESULT_TRIP_DOESNT_EXIST =
'Sorry, we couldn\'t find the trip you were looking for.';

// Mock the getUserUid auth utility function to return a fake UID as given by
// FAKE_USER.
jest.mock('../AuthUtils');
authUtils.getUserUid.mockReturnValue(FAKE_USER);

// Mock the ActivityList component to simply render the passed-in tripId.
jest.mock('./activitylist.js', () => (props) => (
<div>{props.tripId}</div>
));

// Mock the different collaborator fields that can be returned from Firebase
// Firestore. The first time, it returns an array containing the fake user. The
// second time, it returns an array that does not contain the fake user. The
// third time, it returns undefined (imitating Firebase being unable to find the
// trip).
const mockGet = jest.fn()
.mockResolvedValueOnce({ get: function() {return [FAKE_USER]} })
.mockResolvedValueOnce({ get: function() {return []} })
.mockResolvedValueOnce({ get: function() {return undefined} });
jest.mock('firebase/app', () => {
return {
initializeApp: () => {
return {
firestore: () => {
return {
collection: (collectionPath) => {
return {
doc: (documentPath) => {
return {
get: mockGet
};
}
};
}
};
}
};
}
};
});

describe('ViewActivities page', () => {
beforeEach(() => {
render(<ViewActivities match={{params: {tripId: FAKE_TRIPID}}}/>);
});

afterEach(cleanup);

it('Displays ActivityList when the user is a collaborator', () => {
expect(screen.getByText(RESULT_AUTHORIZED)).toBeInTheDocument();
});

it('Displays the relevant error when the user is not a collaborator', () => {
expect(screen.getByText(RESULT_NOT_AUTHORIZED)).toBeInTheDocument();
});

it('Displays the relevant error when the trip could not be found', () => {
expect(screen.getByText(RESULT_TRIP_DOESNT_EXIST)).toBeInTheDocument();
})
});
2 changes: 1 addition & 1 deletion frontend/src/constants/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ export const ACTIVITIES_END_TIME = 'end_time';
export const ACTIVITIES_TITLE = 'title';
export const ACTIVITIES_DESCRIPTION = 'description';
export const ACTIVITIES_START_COUNTRY = 'start_country';
export const ACTIVITIES_END_COUNTRY = 'end_country';
export const ACTIVITIES_END_COUNTRY = 'end_country';

0 comments on commit e213e4f

Please sign in to comment.