From dfe38a8a489794e6369a90c82d5d13611748d259 Mon Sep 17 00:00:00 2001 From: sankalp Date: Fri, 5 Mar 2021 00:00:26 +0530 Subject: [PATCH 1/3] Added GitHub Oauth Login and Registration Added the code to make POST request on backend to send code and recieve access_token. Fixes #106 --- README.md | 16 +++-- package.json | 6 +- src/actions/login.js | 26 ++++++- src/components/GitHubAuth.js | 131 +++++++++++++++++++++++++++++++++++ src/components/Login.js | 5 ++ src/urls.js | 4 ++ 6 files changed, 181 insertions(+), 7 deletions(-) create mode 100644 src/components/GitHubAuth.js diff --git a/README.md b/README.md index cc5679b..86a087e 100644 --- a/README.md +++ b/README.md @@ -24,16 +24,24 @@ Documentation for the project is hosted [here](https://osp-web-docs.surge.sh/). **Note:** Before setting up the frontend make sure to have Setup the [Backend Repo](https://github.com/anitab-org/open-source-programs-backend). -1. To start the server: +1. Create a `.env` file in the project root directory and add **Client ID** and **Callback URL** of GitHub App like this: + +``` +REACT_APP_GITHUB_CLIENT_ID=< GitHub App Client ID > +REACT_APP_GITHUB_CALLBACK_URL=< GitHub App Callback URL > +``` + +To get **Client ID** and **Callback URL** of GitHub App follow [this docs](https://docs.github.com/en/developers/apps/creating-a-github-app). + +2. To start the server: ``` -cd open-source-programs-web npm install npm start ``` -2. Navigate to `http://localhost:3000/` in your browser. -3. You can terminate the process by `Ctrl+C` in your terminal. +3. Navigate to `http://localhost:3000/` in your browser. +4. You can terminate the process by `Ctrl+C` in your terminal. ## Contributing diff --git a/package.json b/package.json index 0824938..2fe4589 100644 --- a/package.json +++ b/package.json @@ -7,16 +7,18 @@ "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "aws-sdk": "^2.734.0", - "axios": "^0.19.2", + "axios": "^0.21.1", "dotenv": "^8.2.0", + "github-login": "^1.0.12", "moment": "^2.27.0", "prop-types": "^15.7.2", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-github-login": "^1.0.3", "react-redux": "^7.2.0", "react-router-dom": "^5.2.0", "react-router-redux": "^4.0.8", - "react-scripts": "3.4.1", + "react-scripts": "^4.0.3", "redux": "^4.0.5", "redux-api-middleware": "^3.2.1", "redux-persist": "^6.0.0", diff --git a/src/actions/login.js b/src/actions/login.js index c2edb5c..b2e6e36 100644 --- a/src/actions/login.js +++ b/src/actions/login.js @@ -1,5 +1,5 @@ import axios from 'axios'; -import { urlLogin, urlRegister } from '../urls'; +import { urlLogin, urlRegister, urlGithubLogin } from '../urls'; import { LOGIN, REGISTER, LOGIN_ERRORS, REGISTER_ERRORS } from './types'; export const postLogin = (data, callback) => async (dispatch) => { @@ -48,3 +48,27 @@ export const postRegister = (data, callback) => async (dispatch) => { callback(); } }; + +export const postGithubCode = (data, callback) => async (dispatch) => { + try { + const config = { + headers: { + 'content-type': 'application/json', + }, + }; + const res = await axios.post(urlGithubLogin(), data, config); + dispatch({ + type: LOGIN, + payload: res.data, + }); + + localStorage.setItem('token', res.data.access_token); + callback(); + } catch (err) { + dispatch({ + type: LOGIN_ERRORS, + payload: err.response, + }); + callback(); + } +}; diff --git a/src/components/GitHubAuth.js b/src/components/GitHubAuth.js new file mode 100644 index 0000000..8627799 --- /dev/null +++ b/src/components/GitHubAuth.js @@ -0,0 +1,131 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import GitHubLogin from 'react-github-login'; +import { postGithubCode } from '../actions/login'; +import { withRouter } from 'react-router'; +import { Icon, Message } from 'semantic-ui-react'; + +class GitHubAuth extends Component { + constructor(props) { + super(props); + this.state = { + code: '', + error: null, + posted: false, + errorText: '', + }; + this.postCode = this.postCode.bind(this); + this.GithubError = this.GithubError.bind(this); + } + + postCode = (response) => { + console.log(response.code); + this.setState({ + code: response.code, + }); + const data = { + code: this.state.code, + }; + this.props.postGithubCode(data, this.callback); + this.setState({ + code: '', + }); + }; + + callback = () => { + this.setState({ + error: this.props.loginerror ? true : false, + posted: true, + errorText: 'Server Error: try again.', + }); + console.log(this.state.error, this.state.posted); + if (!this.state.error) { + this.props.history.push('/'); + } + setTimeout(() => { + this.setState({ + error: false, + posted: false, + }); + }, 4000); + }; + + icon = () => { + return ( + + Log in with GitHub + + ); + }; + + GithubError = (response) => { + console.log(response); + this.setState({ + error: true, + posted: true, + errorText: 'GitHub API Error.', + }); + setTimeout(() => { + this.setState({ + error: false, + posted: false, + }); + }, 4000); + }; + + UNSAFE_componentWillMount() { + this.setState({ + code: '', + error: null, + posted: false, + errorText: '', + }); + } + + componentWillUnmount() { + // eslint-disable-next-line + this.setState = (state, callback) => { + return; + }; + } + + render() { + const { + REACT_APP_GITHUB_CLIENT_ID, + REACT_APP_GITHUB_CALLBACK_URL, + } = process.env; + const { error, posted, errorText } = this.state; + const onFailure = (response) => this.GithubError(response); + return ( + <> + {error && posted ? ( + + ) : ( + + {this.icon()} + + )} + + ); + } +} + +GitHubAuth.propTypes = { + postGithubCode: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => ({ + login: state.login.login, + loginerror: state.login.loginerror, +}); + +export default connect(mapStateToProps, { postGithubCode })( + withRouter(GitHubAuth) +); diff --git a/src/components/Login.js b/src/components/Login.js index 4884f45..1d255a3 100644 --- a/src/components/Login.js +++ b/src/components/Login.js @@ -10,11 +10,13 @@ import { Icon, Message, Button, + Segment, } from 'semantic-ui-react'; import PropTypes from 'prop-types'; import './../styles/Login.css'; import orgLogo from '../assets/org-logo.jpg'; import { register } from '../urls'; +import GitHubAuth from './GitHubAuth'; class Login extends Component { constructor(props) { @@ -168,6 +170,9 @@ class Login extends Component { ) : null} + + + Don't have an account?{' '} Register here. diff --git a/src/urls.js b/src/urls.js index 6831eec..f75c1c3 100644 --- a/src/urls.js +++ b/src/urls.js @@ -47,6 +47,10 @@ export function urlRegister() { return `${urlBaseBackend()}/token_auth/register/`; } +export function urlGithubLogin() { + return `${urlBaseBackend()}/token_auth/github/`; +} + export function urlInfo() { return `${urlBaseBackend()}/info/`; } From 46387d7c0fa2a759e3b66e5094036c275faa6db1 Mon Sep 17 00:00:00 2001 From: sankalp Date: Tue, 9 Mar 2021 13:08:29 +0530 Subject: [PATCH 2/3] Added tests and removed with router --- src/App.test.js | 9 --------- src/components/GitHubAuth.js | 17 +++++++---------- src/tests/GitHubAuth.test.js | 25 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 19 deletions(-) delete mode 100644 src/App.test.js create mode 100644 src/tests/GitHubAuth.test.js diff --git a/src/App.test.js b/src/App.test.js deleted file mode 100644 index 4db7ebc..0000000 --- a/src/App.test.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - const { getByText } = render(); - const linkElement = getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/components/GitHubAuth.js b/src/components/GitHubAuth.js index 8627799..d4e33bc 100644 --- a/src/components/GitHubAuth.js +++ b/src/components/GitHubAuth.js @@ -3,7 +3,6 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import GitHubLogin from 'react-github-login'; import { postGithubCode } from '../actions/login'; -import { withRouter } from 'react-router'; import { Icon, Message } from 'semantic-ui-react'; class GitHubAuth extends Component { @@ -20,7 +19,6 @@ class GitHubAuth extends Component { } postCode = (response) => { - console.log(response.code); this.setState({ code: response.code, }); @@ -39,7 +37,6 @@ class GitHubAuth extends Component { posted: true, errorText: 'Server Error: try again.', }); - console.log(this.state.error, this.state.posted); if (!this.state.error) { this.props.history.push('/'); } @@ -51,10 +48,12 @@ class GitHubAuth extends Component { }, 4000); }; - icon = () => { + githubIcon = () => { return ( - Log in with GitHub +
+ Log in with GitHub +
); }; @@ -74,7 +73,7 @@ class GitHubAuth extends Component { }, 4000); }; - UNSAFE_componentWillMount() { + componentDidMount() { this.setState({ code: '', error: null, @@ -109,7 +108,7 @@ class GitHubAuth extends Component { redirectUri={`${REACT_APP_GITHUB_CALLBACK_URL}`} className="ui fluid button" > - {this.icon()} + {this.githubIcon()} )} @@ -126,6 +125,4 @@ const mapStateToProps = (state) => ({ loginerror: state.login.loginerror, }); -export default connect(mapStateToProps, { postGithubCode })( - withRouter(GitHubAuth) -); +export default connect(mapStateToProps, { postGithubCode })(GitHubAuth); diff --git a/src/tests/GitHubAuth.test.js b/src/tests/GitHubAuth.test.js new file mode 100644 index 0000000..ce10ae0 --- /dev/null +++ b/src/tests/GitHubAuth.test.js @@ -0,0 +1,25 @@ +import React from 'react'; +import { createStore } from 'redux'; +import { Provider } from 'react-redux'; +import { render, cleanup } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import GitHubAuth from '../components/GitHubAuth'; +import loginReducer from '../reducers/login'; + +afterEach(cleanup); + +function renderWithRedux( + component, + { initialState, store = createStore(loginReducer, initialState) } = {} +) { + return { + ...render({component}), + }; +} + +it('Renders GitHub Login Button', () => { + const { getByTestId } = renderWithRedux(); + expect(getByTestId('GitHubLoginButton')).toHaveTextContent( + 'Log in with GitHub' + ); +}); From 8f2a59396d0516755e760f8d549237fb58d13287 Mon Sep 17 00:00:00 2001 From: sankalp Date: Sun, 14 Mar 2021 23:27:44 +0530 Subject: [PATCH 3/3] fixed workflow --- .github/workflows/qa-checks.yml | 9 +++------ package.json | 3 ++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/qa-checks.yml b/.github/workflows/qa-checks.yml index f69022a..fc638d5 100644 --- a/.github/workflows/qa-checks.yml +++ b/.github/workflows/qa-checks.yml @@ -21,9 +21,6 @@ jobs: run: npm install - name: Linters and Formatters Check - uses: wearerequired/lint-action@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - # Enable linters - eslint: true - prettier: true + run: | + npm run lint + npm run check diff --git a/package.json b/package.json index 2fe4589..d0ff220 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,8 @@ "eject": "react-scripts eject", "lint": "eslint .", "lint:fix": "eslint . --fix", - "format": "prettier --write \"**/*.+(js|jsx|json|css|md)\"" + "format": "prettier --write \"**/*.+(js|jsx|json|css|md)\"", + "check": "prettier -c \"**/*.+(js|jsx|json|css|md)\"" }, "browserslist": { "production": [