Skip to content
This repository has been archived by the owner on Dec 9, 2021. It is now read-only.

User authentication using OAuth2 #211

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SERVER_URL = "http://localhost:8000"
OAUTH_CLIENT_ID = "clientId"
SENTRY_DSN = "https://[email protected]/123"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ project.xcworkspace
ios/Pods
ios/Podfile.lock

google-play.json
releaseSigning.properties

# Android/IntelliJ
#
build/
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,12 @@ Getting started
6. Setup the Sentry integration using `npx @sentry/wizard -i reactNative -p ios android`
- To be able to do this you need access to our Sentry organisation, we use SSO with our Github organisation for this
- Alternatively you can setup Sentry using the example files below. The wizard will do these steps for you.
7. Start the development server using `yarn start`
8. Deploy the app on a running emulator or connected device by running `yarn start:android` or `yarn start:ios`
7. Setup your local environment
- Create a `.env` file in the root of the repository based on `.env.example`
- Set the server and client id to those of your local concrexit installation or [the staging server](https://staging.thalia.nu/admin/oauth2_provider/application/)
- A client id can be obtained by creating an OAuth2 application in the concrexit admin
8. Start the development server using `yarn start`
9. Deploy the app on a running emulator or connected device by running `yarn start:android` or `yarn start:ios`


Logging and debugging
Expand Down
10 changes: 0 additions & 10 deletions __mocks__/react-i18next.js

This file was deleted.

3 changes: 3 additions & 0 deletions __mocks__/react-native-app-auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {

}
3 changes: 0 additions & 3 deletions __mocks__/react-native-localize.js

This file was deleted.

9 changes: 3 additions & 6 deletions __tests__/actions/__snapshots__/session.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
exports[`session actions should create an action for a successful login 1`] = `
Object {
"payload": Object {
"token": "token",
"username": "username",
"accessToken": "accessToken",
"refreshToken": "refreshToken",
"tokenExpiration": undefined,
},
"type": "SESSION_SIGNED_IN",
}
Expand All @@ -24,10 +25,6 @@ Object {

exports[`session actions should create an action to log the user in 1`] = `
Object {
"payload": Object {
"pass": "password",
"user": "username",
},
"type": "SESSION_SIGN_IN",
}
`;
Expand Down
4 changes: 2 additions & 2 deletions __tests__/actions/session.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ describe('session actions', () => {
});

it('should create an action to log the user in', () => {
expect(actions.signIn('username', 'password')).toMatchSnapshot();
expect(actions.signIn()).toMatchSnapshot();
});

it('should create an action for a successful login', () => {
expect(actions.signedIn('username', 'token')).toMatchSnapshot();
expect(actions.signedIn('accessToken', 'refreshToken')).toMatchSnapshot();
});

it('should create an action to log the user out', () => {
Expand Down
8 changes: 4 additions & 4 deletions __tests__/reducers/__snapshots__/profile.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ Object {
"profile": Object {
"achievements": Array [],
"avatar": Object {
"full": "http://localhost:8000/static/members/images/default-avatar.jpg",
"large": "http://localhost:8000/static/members/images/default-avatar.jpg",
"medium": "http://localhost:8000/static/members/images/default-avatar.jpg",
"small": "http://localhost:8000/static/members/images/default-avatar.jpg",
"full": "https://thalia.localhost/static/members/images/default-avatar.jpg",
"large": "https://thalia.localhost/static/members/images/default-avatar.jpg",
"medium": "https://thalia.localhost/static/members/images/default-avatar.jpg",
"small": "https://thalia.localhost/static/members/images/default-avatar.jpg",
},
"birthday": "",
"display_name": "",
Expand Down
3 changes: 1 addition & 2 deletions __tests__/reducers/__snapshots__/session.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
exports[`session reducer initially should return the initial state 1`] = `
Object {
"displayName": "",
"photo": "http://localhost:8000/static/members/images/default-avatar.jpg",
"photo": "https://thalia.localhost/static/members/images/default-avatar.jpg",
"pk": -1,
"status": "SIGNED_OUT",
"token": "",
"username": "",
}
`;
4 changes: 2 additions & 2 deletions __tests__/reducers/members.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('members reducer', () => {
expect(state).toHaveProperty('memberList', [{ pk: 1 }]);
});

it('should have the url for more results', () => {
it('should have the SERVER_URL for more results', () => {
expect(state).toHaveProperty('more', 'nextUrl');
});

Expand Down Expand Up @@ -79,7 +79,7 @@ describe('members reducer', () => {
expect(state).toHaveProperty('memberList', [{ pk: 1 }, { pk: 2 }]);
});

it('should have the url for more results', () => {
it('should have the SERVER_URL for more results', () => {
expect(state).toHaveProperty('more', 'nextUrl');
});
});
Expand Down
10 changes: 5 additions & 5 deletions __tests__/reducers/session.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ describe('session reducer', () => {
expect(state).toHaveProperty('status', STATUS_SIGNED_IN);
});

it('should contain the username', () => {
expect(state).toHaveProperty('username', 'user');
it('should contain the refreshToken', () => {
expect(state).toHaveProperty('refreshToken', 'token');
});

it("should contain the user's token", () => {
expect(state).toHaveProperty('token', 'token');
it("should contain the user's accessToken", () => {
expect(state).toHaveProperty('accessToken', 'user');
});
});

Expand All @@ -59,7 +59,7 @@ describe('session reducer', () => {
expect(state).toHaveProperty('displayName', 'John Doe');
});

it('should contain the url for the profile picture', () => {
it('should contain the SERVER_URL for the profile picture', () => {
expect(state).toHaveProperty('photo', 'imageUrl');
});
});
Expand Down
61 changes: 12 additions & 49 deletions __tests__/sagas/calendar.spec.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,39 @@
import { select } from 'redux-saga/effects';
import { expectSaga } from 'redux-saga-test-plan';
import * as matchers from 'redux-saga-test-plan/matchers';
import { throwError } from 'redux-saga-test-plan/providers';

import { apiRequest } from '../../app/utils/url';
import calendarSaga from '../../app/sagas/calendar';

import * as calendarActions from '../../app/actions/calendar';
import { tokenSelector } from '../../app/selectors/session';

jest.mock('../../app/utils/url', () => ({
apiRequest: jest.fn(() => {}),
}));
import calendarSaga from '../../app/sagas/calendar';
import { getRequest } from '../../app/sagas/utils/api';

jest.mock('../../app/selectors/session', () => ({
tokenSelector: () => 'token',
jest.mock('../../app/sagas/utils/api', () => ({
getRequest: jest.fn(() => {}),
}));

describe('calendar saga', () => {
const error = new Error('error');

it('should start fetching on refresh', () =>
expectSaga(calendarSaga)
.provide([
[select(tokenSelector), 'token'],
[matchers.call.fn(apiRequest), []],
])
.provide([[matchers.call.fn(getRequest), []]])
.dispatch(calendarActions.events())
.put(calendarActions.fetching())
.silentRun());

it('should put an error when the api request fails', () =>
expectSaga(calendarSaga)
.provide([
[select(tokenSelector), 'token'],
[matchers.call.fn(apiRequest), throwError(error)],
])
.provide([[matchers.call.fn(getRequest), throwError(error)]])
.dispatch(calendarActions.events())
.put(calendarActions.failure())
.silentRun());

it('should put the result data when the request succeeds', () =>
expectSaga(calendarSaga)
.provide([
[select(tokenSelector), 'token'],
[matchers.call.like({ fn: apiRequest, args: ['events'] }), [{ pk: 1 }]],
[matchers.call.like({ fn: getRequest, args: ['events'] }), [{ pk: 1 }]],
[
matchers.call.like({ fn: apiRequest, args: ['partners/events'] }),
matchers.call.like({ fn: getRequest, args: ['partners/events'] }),
[{ pk: 2 }],
],
])
Expand All @@ -57,10 +44,9 @@ describe('calendar saga', () => {
it('should put keywords if they were passed', () =>
expectSaga(calendarSaga)
.provide([
[select(tokenSelector), 'token'],
[matchers.call.like({ fn: apiRequest, args: ['events'] }), [{ pk: 1 }]],
[matchers.call.like({ fn: getRequest, args: ['events'] }), [{ pk: 1 }]],
[
matchers.call.like({ fn: apiRequest, args: ['partners/events'] }),
matchers.call.like({ fn: getRequest, args: ['partners/events'] }),
[{ pk: 2 }],
],
])
Expand All @@ -70,33 +56,10 @@ describe('calendar saga', () => {

it('should do two GET requests', () =>
expectSaga(calendarSaga)
.provide([[select(tokenSelector), 'usertoken']])
.dispatch(calendarActions.events())
.silentRun()
.then(() => {
expect(apiRequest).toBeCalledWith(
'events',
{
headers: {
Accept: 'application/json',
Authorization: 'Token usertoken',
'Content-Type': 'application/json',
},
method: 'GET',
},
null
);
expect(apiRequest).toBeCalledWith(
'partners/events',
{
headers: {
Accept: 'application/json',
Authorization: 'Token usertoken',
'Content-Type': 'application/json',
},
method: 'GET',
},
null
);
expect(getRequest).toBeCalledWith('events', undefined);
expect(getRequest).toBeCalledWith('partners/events', undefined);
}));
});
10 changes: 5 additions & 5 deletions __tests__/sagas/deepLinking.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { select } from 'redux-saga/effects';
import { expectSaga } from 'redux-saga-test-plan';

import deepLinkingSaga, { parseURL } from '../../app/sagas/deepLinking';
import { url as siteURL } from '../../app/utils/url';
import { SERVER_URL as siteURL } from '../../app/constants';

import * as actions from '../../app/actions/deepLinking';
import * as sessionActions from '../../app/actions/session';
Expand Down Expand Up @@ -44,7 +44,7 @@ describe('deeplinking saga', () => {
.take(sessionActions.SIGNED_IN)
.silentRun());

it('should not open an unknown url outside the app if stayInApp is true', () =>
it('should not open an unknown SERVER_URL outside the app if stayInApp is true', () =>
expectSaga(deepLinkingSaga)
.provide([[select(loggedInSelector), true]])
.dispatch(actions.deepLink('http://example.org/', true))
Expand All @@ -53,7 +53,7 @@ describe('deeplinking saga', () => {
expect(Linking.openURL).not.toBeCalled();
}));

it('should open an unknown url outside the app if specified', () =>
it('should open an unknown SERVER_URL outside the app if specified', () =>
expectSaga(deepLinkingSaga)
.provide([[select(loggedInSelector), true]])
.dispatch(actions.deepLink('http://example.org/', false))
Expand All @@ -62,14 +62,14 @@ describe('deeplinking saga', () => {
expect(Linking.openURL).toBeCalledWith('http://example.org/');
}));

it('should open the pizza url', () =>
it('should open the pizza SERVER_URL', () =>
expectSaga(deepLinkingSaga)
.provide([[select(loggedInSelector), true]])
.dispatch(actions.deepLink(`${siteURL}/pizzas/`))
.put(pizzaActions.retrievePizzaInfo())
.silentRun());

it('should open the events calendar url', () =>
it('should open the events calendar SERVER_URL', () =>
expectSaga(deepLinkingSaga)
.provide([[select(loggedInSelector), true]])
.dispatch(actions.deepLink(`${siteURL}/events/`))
Expand Down
Loading