Skip to content

Commit

Permalink
Added caching of Github credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
chownces committed Jun 14, 2021
1 parent 872bed5 commit 76193a2
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 14 deletions.
9 changes: 7 additions & 2 deletions src/commons/application/actions/SessionActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
LOGOUT_GOOGLE,
REAUTOGRADE_ANSWER,
REAUTOGRADE_SUBMISSION,
REMOVE_GITHUB_OCTOKIT_OBJECT,
REMOVE_GITHUB_OCTOKIT_OBJECT_AND_ACCESS_TOKEN,
SET_GITHUB_ACCESS_TOKEN,
SET_GITHUB_ASSESSMENT,
SET_GITHUB_OCTOKIT_OBJECT,
SET_GOOGLE_USER,
Expand Down Expand Up @@ -88,7 +89,11 @@ export const setGitHubAssessment = (missionRepoData: MissionRepoData) =>
export const setGitHubOctokitObject = (authToken?: string) =>
action(SET_GITHUB_OCTOKIT_OBJECT, generateOctokitInstance(authToken || ''));

export const removeGitHubOctokitObject = () => action(REMOVE_GITHUB_OCTOKIT_OBJECT);
export const setGitHubAccessToken = (authToken?: string) =>
action(SET_GITHUB_ACCESS_TOKEN, authToken);

export const removeGitHubOctokitObjectAndAccessToken = () =>
action(REMOVE_GITHUB_OCTOKIT_OBJECT_AND_ACCESS_TOKEN);

export const submitAnswer = (id: number, answer: string | number | ContestEntry[]) =>
action(SUBMIT_ANSWER, {
Expand Down
11 changes: 11 additions & 0 deletions src/commons/application/actions/__tests__/SessionActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
LOGIN,
REAUTOGRADE_ANSWER,
REAUTOGRADE_SUBMISSION,
SET_GITHUB_ACCESS_TOKEN,
SET_GITHUB_OCTOKIT_OBJECT,
SET_TOKENS,
SET_USER,
Expand All @@ -39,6 +40,7 @@ import {
login,
reautogradeAnswer,
reautogradeSubmission,
setGitHubAccessToken,
setGitHubOctokitObject,
setTokens,
setUser,
Expand Down Expand Up @@ -173,6 +175,15 @@ test('setGitHubOctokitInstance generates correct action object', async () => {
expect(authObject.tokenType).toBe('oauth');
});

test('setGitHubAccessToken generates correct action object', () => {
const authToken = 'testAuthToken12345';
const action = setGitHubAccessToken(authToken);
expect(action).toEqual({
type: SET_GITHUB_ACCESS_TOKEN,
payload: authToken
});
});

test('submitAnswer generates correct action object', () => {
const id = 3;
const answer = 'test-answer-here';
Expand Down
13 changes: 10 additions & 3 deletions src/commons/application/reducers/SessionsReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { SourceActionType } from '../../utils/ActionsHelper';
import { defaultSession } from '../ApplicationTypes';
import { LOG_OUT } from '../types/CommonsTypes';
import {
REMOVE_GITHUB_OCTOKIT_OBJECT,
REMOVE_GITHUB_OCTOKIT_OBJECT_AND_ACCESS_TOKEN,
SessionState,
SET_GITHUB_ACCESS_TOKEN,
SET_GITHUB_ASSESSMENT,
SET_GITHUB_OCTOKIT_OBJECT,
SET_GOOGLE_USER,
Expand Down Expand Up @@ -40,6 +41,11 @@ export const SessionsReducer: Reducer<SessionState> = (
...state,
githubOctokitObject: { octokit: action.payload }
};
case SET_GITHUB_ACCESS_TOKEN:
return {
...state,
githubAccessToken: action.payload
};
case SET_GOOGLE_USER:
return {
...state,
Expand Down Expand Up @@ -109,10 +115,11 @@ export const SessionsReducer: Reducer<SessionState> = (
...state,
remoteExecutionSession: action.payload
};
case REMOVE_GITHUB_OCTOKIT_OBJECT:
case REMOVE_GITHUB_OCTOKIT_OBJECT_AND_ACCESS_TOKEN:
return {
...state,
githubOctokitObject: { octokit: undefined }
githubOctokitObject: { octokit: undefined },
githubAccessToken: undefined
};
default:
return state;
Expand Down
15 changes: 15 additions & 0 deletions src/commons/application/reducers/__tests__/SessionReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { defaultSession, GameState, Role, Story } from '../../ApplicationTypes';
import { LOG_OUT } from '../../types/CommonsTypes';
import {
SessionState,
SET_GITHUB_ACCESS_TOKEN,
SET_TOKENS,
SET_USER,
UPDATE_ASSESSMENT,
Expand Down Expand Up @@ -82,6 +83,20 @@ test('SET_USER works correctly', () => {
});
});

test('SET_GITHUB_ACCESS_TOKEN works correctly', () => {
const token = 'githubAccessToken';
const action = {
type: SET_GITHUB_ACCESS_TOKEN,
payload: token
};
const result: SessionState = SessionsReducer(defaultSession, action);

expect(result).toEqual({
...defaultSession,
githubAccessToken: token
});
});

test('UPDATE_HISTORY_HELPERS works on non-academy location', () => {
const payload = '/playground';
const historyHelper: HistoryHelper = {
Expand Down
5 changes: 4 additions & 1 deletion src/commons/application/types/SessionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ export const SET_USER = 'SET_USER';
export const SET_GOOGLE_USER = 'SET_GOOGLE_USER';
export const SET_GITHUB_ASSESSMENT = 'SET_GITHUB_ASSESSMENT';
export const SET_GITHUB_OCTOKIT_OBJECT = 'SET_GITHUB_OCTOKIT_OBJECT';
export const SET_GITHUB_ACCESS_TOKEN = 'SET_GITHUB_ACCESS_TOKEN';
export const SUBMIT_ANSWER = 'SUBMIT_ANSWER';
export const SUBMIT_ASSESSMENT = 'SUBMIT_ASSESSMENT';
export const SUBMIT_GRADING = 'SUBMIT_GRADING';
export const SUBMIT_GRADING_AND_CONTINUE = 'SUBMIT_GRADING_AND_CONTINUE';
export const REAUTOGRADE_SUBMISSION = 'REAUTOGRADE_SUBMISSION';
export const REAUTOGRADE_ANSWER = 'REAUTOGRADE_ANSWER';
export const REMOVE_GITHUB_OCTOKIT_OBJECT = 'REMOVE_GITHUB_OCTOKIT_OBJECT';
export const REMOVE_GITHUB_OCTOKIT_OBJECT_AND_ACCESS_TOKEN =
'REMOVE_GITHUB_OCTOKIT_OBJECT_AND_ACCESS_TOKEN';
export const UNSUBMIT_SUBMISSION = 'UNSUBMIT_SUBMISSION';
export const UPDATE_HISTORY_HELPERS = 'UPDATE_HISTORY_HELPERS';
export const UPDATE_ASSESSMENT_OVERVIEWS = 'UPDATE_ASSESSMENT_OVERVIEWS';
Expand Down Expand Up @@ -64,6 +66,7 @@ export type SessionState = {
readonly googleUser?: string;
readonly githubAssessment?: MissionRepoData;
readonly githubOctokitObject: { octokit: Octokit | undefined };
readonly githubAccessToken?: string;
readonly remoteExecutionDevices?: Device[];
readonly remoteExecutionSession?: DeviceSession;
};
Expand Down
3 changes: 2 additions & 1 deletion src/commons/sagas/GitHubPersistenceSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ function* githubLoginSaga() {

broadcastChannel.onmessage = receivedMessage => {
store.dispatch(actions.setGitHubOctokitObject(receivedMessage.data));
store.dispatch(actions.setGitHubAccessToken(receivedMessage.data));
showSuccessMessage('Logged in to GitHub', 1000);
};

Expand All @@ -61,7 +62,7 @@ function* githubLogoutSaga() {
return;
}

yield put(actions.removeGitHubOctokitObject());
yield put(actions.removeGitHubOctokitObjectAndAccessToken());
yield call(showSuccessMessage, `Logged out from GitHub`, 1000);
yield call(history.push, '/githubassessments/missions');
}
Expand Down
4 changes: 2 additions & 2 deletions src/commons/sagas/__tests__/GitHubPersistenceSaga.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expectSaga } from 'redux-saga-test-plan';

import { actions } from '../../../commons/utils/ActionsHelper';
import { REMOVE_GITHUB_OCTOKIT_OBJECT } from '../../application/types/SessionTypes';
import { REMOVE_GITHUB_OCTOKIT_OBJECT_AND_ACCESS_TOKEN } from '../../application/types/SessionTypes';

// mock away the store
jest.mock('../../../pages/createStore');
Expand All @@ -12,7 +12,7 @@ const GitHubPersistenceSaga = require('../GitHubPersistenceSaga').default;
test('logoutGitHub results in REMOVE_GITHUB_OCTOKIT_OBJECT being dispatched', async () => {
await expectSaga(GitHubPersistenceSaga)
.put({
type: REMOVE_GITHUB_OCTOKIT_OBJECT,
type: REMOVE_GITHUB_OCTOKIT_OBJECT_AND_ACCESS_TOKEN,
payload: undefined,
meta: undefined,
error: undefined
Expand Down
22 changes: 19 additions & 3 deletions src/pages/__tests__/createStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ const mockChangedStoredState: SavedState = {
accessToken: 'yep',
refreshToken: 'refresherOrb',
role: undefined,
name: 'Jeff'
name: 'Jeff',
userId: 1,
githubAccessToken: 'githubAccessToken'
},
playgroundEditorValue: 'Nihao everybody',
playgroundIsEditorAutorun: true,
Expand All @@ -30,7 +32,9 @@ const mockChangedState: OverallState = {
accessToken: 'yep',
refreshToken: 'refresherOrb',
role: undefined,
name: 'Jeff'
name: 'Jeff',
userId: 1,
githubAccessToken: 'githubAccessToken'
},
workspaces: {
...defaultState.workspaces,
Expand Down Expand Up @@ -62,10 +66,22 @@ describe('createStore() function', () => {
});
test('has correct getState() when called with storedState', () => {
localStorage.setItem('storedState', compressToUTF16(JSON.stringify(mockChangedStoredState)));
expect(createStore(history).getState()).toEqual({

/**
* Jest toEqual is unable to compare equality of functions (in the Octokit object).
* Thus we simply check that it is defined when loading storedState.
*
* See https://github.com/facebook/jest/issues/8166
*/
const received = createStore(history).getState() as any;
const octokit = received.session.githubOctokitObject.octokit;
delete received.session.githubOctokitObject.octokit;

expect(received).toEqual({
...mockChangedState,
router: defaultRouter
});
expect(octokit).toBeDefined();
localStorage.removeItem('storedState');
});
});
8 changes: 7 additions & 1 deletion src/pages/createStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { History } from 'history';
import { throttle } from 'lodash';
import { applyMiddleware, compose, createStore as _createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { generateOctokitInstance } from 'src/commons/utils/GitHubPersistenceHelper';

import { defaultState } from '../commons/application/ApplicationTypes';
import createRootReducer from '../commons/application/reducers/RootReducer';
Expand Down Expand Up @@ -47,7 +48,12 @@ function loadStore(loadedStore: SavedState | undefined) {
...defaultState,
session: {
...defaultState.session,
...(loadedStore.session ? loadedStore.session : {})
...(loadedStore.session ? loadedStore.session : {}),
githubOctokitObject: {
octokit: loadedStore.session.githubAccessToken
? generateOctokitInstance(loadedStore.session.githubAccessToken)
: undefined
}
},
workspaces: {
...defaultState.workspaces,
Expand Down
3 changes: 2 additions & 1 deletion src/pages/localStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export const saveState = (state: OverallState) => {
refreshToken: state.session.refreshToken,
role: state.session.role,
name: state.session.name,
userId: state.session.userId
userId: state.session.userId,
githubAccessToken: state.session.githubAccessToken
},
achievements: state.achievement.achievements,
playgroundEditorValue: state.workspaces.playground.editorValue,
Expand Down

0 comments on commit 76193a2

Please sign in to comment.