Skip to content

Commit fd5a689

Browse files
author
Carlos Rufo Jimenez
committed
5.4-end-authentication-v2.1-tmp
1 parent 9a4d9f5 commit fd5a689

File tree

8 files changed

+222
-23
lines changed

8 files changed

+222
-23
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
"react": "^16.2.0",
1010
"react-apollo": "^2.1.0",
1111
"react-dom": "^16.2.0",
12+
"react-router": "^4.2.0",
13+
"react-router-dom": "^4.2.2",
1214
"react-scripts": "1.1.1"
1315
},
1416
"scripts": {

server/src/resolvers/Mutation.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ const jwt = require('jsonwebtoken')
33
const { APP_SECRET, getUserId } = require('../utils')
44

55
function post(parent, { url, description }, ctx, info) {
6-
return ctx.db.mutation.createLink({ data: { url, description } }, info)
6+
const userId = getUserId(ctx)
7+
return ctx.db.mutation.createLink(
8+
{ data: { url, description, postedBy: { connect: { id: userId } } } },
9+
info
10+
)
711
}
812

913
async function signup(parent, args, ctx, info) {

src/components/App.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import LinkList from './LinkList'
33
import CreateLink from './CreateLink'
44
import Header from './Header'
55
import { Switch, Route } from 'react-router-dom'
6+
import Login from './Login'
67

78
export default () => (
89
<div className="center w85">
@@ -11,6 +12,7 @@ export default () => (
1112
<Switch>
1213
<Route exact path="/" component={LinkList} />
1314
<Route exact path="/create" component={CreateLink} />
15+
<Route exact path="/login" component={Login} />
1416
</Switch>
1517
</div>
1618
</div>

src/components/Header.js

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,45 @@
11
import React from 'react'
22
import { Link } from 'react-router-dom'
33
import { withRouter } from 'react-router'
4+
import { AUTH_TOKEN } from '../constants'
45

5-
const Header = () => (
6-
<div className="flex pa1 justify-between nowrap orange">
7-
<div className="flex flex-fixed black">
8-
<div className="fw7 mr1">Hacker News</div>
9-
<Link to="/" className="ml1 no-underline black">
10-
new
11-
</Link>
12-
<div className="ml1">|</div>
13-
<Link to="/create" className="ml1 no-underline black">
14-
submit
15-
</Link>
6+
const Header = props => {
7+
const authToken = localStorage.getItem(AUTH_TOKEN)
8+
return (
9+
<div className="flex pa1 justify-between nowrap orange">
10+
<div className="flex flex-fixed black">
11+
<div className="fw7 mr1">Hacker News</div>
12+
<Link to="/" className="ml1 no-underline black">
13+
new
14+
</Link>
15+
{authToken && (
16+
<div className="flex">
17+
<div className="ml1">|</div>
18+
<Link to="/create" className="ml1 no-underline black">
19+
submit
20+
</Link>
21+
</div>
22+
)}
23+
</div>
24+
<div className="flex flex-fixed">
25+
{authToken ? (
26+
<div
27+
className="ml1 pointer black"
28+
onClick={() => {
29+
localStorage.removeItem(AUTH_TOKEN)
30+
props.history.push(`/`)
31+
}}
32+
>
33+
logout
34+
</div>
35+
) : (
36+
<Link to="/login" className="ml1 no-underline black">
37+
login
38+
</Link>
39+
)}
40+
</div>
1641
</div>
17-
</div>
18-
)
42+
)
43+
}
1944

2045
export default withRouter(Header)

src/components/Login.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React, { Component } from 'react'
2+
import { AUTH_TOKEN } from '../constants'
3+
import { Mutation } from 'react-apollo'
4+
import gql from 'graphql-tag'
5+
6+
const SIGNUP_MUTATION = gql`
7+
mutation SignupMutation($email: String!, $password: String!, $name: String!) {
8+
signup(email: $email, password: $password, name: $name) {
9+
token
10+
}
11+
}
12+
`
13+
14+
const LOGIN_MUTATION = gql`
15+
mutation LoginMutation($email: String!, $password: String!) {
16+
login(email: $email, password: $password) {
17+
token
18+
}
19+
}
20+
`
21+
22+
class Login extends Component {
23+
state = {
24+
login: true, // switch between Login and SignUp
25+
email: '',
26+
password: '',
27+
name: ''
28+
}
29+
30+
render() {
31+
const { login, email, password, name } = this.state
32+
return (
33+
<div>
34+
<h4 className="mv3">{login ? 'Login' : 'Sign Up'}</h4>
35+
<div className="flex flex-column">
36+
{!login && (
37+
<input
38+
value={name}
39+
onChange={e => this.setState({ name: e.target.value })}
40+
type="text"
41+
placeholder="Your name"
42+
/>
43+
)}
44+
<input
45+
value={email}
46+
onChange={e => this.setState({ email: e.target.value })}
47+
type="text"
48+
placeholder="Your email address"
49+
/>
50+
<input
51+
value={password}
52+
onChange={e => this.setState({ password: e.target.value })}
53+
type="password"
54+
placeholder="Choose a safe password"
55+
/>
56+
</div>
57+
<div className="flex mt3">
58+
<Mutation
59+
mutation={login ? LOGIN_MUTATION : SIGNUP_MUTATION}
60+
variables={{ email, password, name }}
61+
onCompleted={data => this._confirm(data)}
62+
>
63+
{mutation => (
64+
<div className="pointer mr2 button" onClick={mutation}>
65+
{login ? 'login' : 'create account'}
66+
</div>
67+
)}
68+
</Mutation>
69+
<div
70+
className="pointer button"
71+
onClick={() => this.setState({ login: !login })}
72+
>
73+
{login ? 'need to create an account?' : 'already have an account?'}
74+
</div>
75+
</div>
76+
</div>
77+
)
78+
}
79+
80+
_confirm = async data => {
81+
const { token } = this.state.login ? data.login : data.signup
82+
this._saveUserData(token)
83+
this.props.history.push(`/`)
84+
}
85+
86+
_saveUserData = token => {
87+
localStorage.setItem(AUTH_TOKEN, token)
88+
}
89+
}
90+
91+
export default Login

src/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const AUTH_TOKEN = 'auth-token'

src/index.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,44 @@ import ReactDOM from 'react-dom'
33
import './styles/index.css'
44
import App from './components/App'
55
import registerServiceWorker from './registerServiceWorker'
6-
// 1
76
import { ApolloProvider } from 'react-apollo'
87
import { ApolloClient } from 'apollo-client'
98
import { HttpLink } from 'apollo-link-http'
109
import { InMemoryCache } from 'apollo-cache-inmemory'
1110
import { BrowserRouter } from 'react-router-dom'
11+
import { AUTH_TOKEN } from './constants'
12+
import { ApolloLink } from 'apollo-client-preset'
13+
import { setContext } from 'apollo-link-context'
1214

13-
// 2
1415
const httpLink = new HttpLink({ uri: 'http://localhost:4000' })
16+
// const authLink = setContext((_, { headers }) => {
17+
// // get the authentication token from local storage if it exists
18+
// const token = localStorage.getItem('token')
19+
// // return the headers to the context so httpLink can read them
20+
// return {
21+
// headers: {
22+
// ...headers,
23+
// authorization: token ? `Bearer ${token}` : ''
24+
// }
25+
// }
26+
// })
27+
28+
const authLink = new ApolloLink((operation, forward) => {
29+
const token = localStorage.getItem(AUTH_TOKEN)
30+
const authorizationHeader = token ? `Bearer ${token}` : null
31+
operation.setContext({
32+
headers: {
33+
authorization: authorizationHeader
34+
}
35+
})
36+
return forward(operation)
37+
})
1538

16-
// 3
1739
const client = new ApolloClient({
18-
link: httpLink,
40+
link: authLink.concat(httpLink),
1941
cache: new InMemoryCache()
2042
})
2143

22-
// 4
2344
ReactDOM.render(
2445
<BrowserRouter>
2546
<ApolloProvider client={client}>

yarn.lock

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3258,6 +3258,16 @@ [email protected]:
32583258
version "1.1.1"
32593259
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
32603260

3261+
history@^4.7.2:
3262+
version "4.7.2"
3263+
resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b"
3264+
dependencies:
3265+
invariant "^2.2.1"
3266+
loose-envify "^1.2.0"
3267+
resolve-pathname "^2.2.0"
3268+
value-equal "^0.4.0"
3269+
warning "^3.0.0"
3270+
32613271
hmac-drbg@^1.0.0:
32623272
version "1.0.1"
32633273
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -3274,7 +3284,7 @@ [email protected]:
32743284
version "4.2.1"
32753285
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb"
32763286

3277-
hoist-non-react-statics@^2.3.1:
3287+
hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1:
32783288
version "2.5.0"
32793289
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40"
32803290

@@ -3503,6 +3513,12 @@ interpret@^1.0.0:
35033513
version "1.1.0"
35043514
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
35053515

3516+
invariant@^2.2.1:
3517+
version "2.2.4"
3518+
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
3519+
dependencies:
3520+
loose-envify "^1.0.0"
3521+
35063522
invariant@^2.2.2:
35073523
version "2.2.3"
35083524
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688"
@@ -4392,7 +4408,7 @@ longest@^1.0.1:
43924408
version "1.0.1"
43934409
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
43944410

4395-
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
4411+
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1:
43964412
version "1.3.1"
43974413
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
43984414
dependencies:
@@ -5069,7 +5085,7 @@ [email protected]:
50695085
version "0.1.7"
50705086
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
50715087

5072-
path-to-regexp@^1.0.1:
5088+
path-to-regexp@^1.0.1, path-to-regexp@^1.7.0:
50735089
version "1.7.0"
50745090
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
50755091
dependencies:
@@ -5495,7 +5511,7 @@ promise@^7.1.1:
54955511
dependencies:
54965512
asap "~2.0.3"
54975513

5498-
prop-types@^15.5.10, prop-types@^15.6.0:
5514+
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.6.0:
54995515
version "15.6.1"
55005516
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
55015517
dependencies:
@@ -5665,6 +5681,29 @@ react-error-overlay@^4.0.0:
56655681
version "4.0.0"
56665682
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4"
56675683

5684+
react-router-dom@^4.2.2:
5685+
version "4.2.2"
5686+
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.2.2.tgz#c8a81df3adc58bba8a76782e946cbd4eae649b8d"
5687+
dependencies:
5688+
history "^4.7.2"
5689+
invariant "^2.2.2"
5690+
loose-envify "^1.3.1"
5691+
prop-types "^15.5.4"
5692+
react-router "^4.2.0"
5693+
warning "^3.0.0"
5694+
5695+
react-router@^4.2.0:
5696+
version "4.2.0"
5697+
resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.2.0.tgz#61f7b3e3770daeb24062dae3eedef1b054155986"
5698+
dependencies:
5699+
history "^4.7.2"
5700+
hoist-non-react-statics "^2.3.0"
5701+
invariant "^2.2.2"
5702+
loose-envify "^1.3.1"
5703+
path-to-regexp "^1.7.0"
5704+
prop-types "^15.5.4"
5705+
warning "^3.0.0"
5706+
56685707
56695708
version "1.1.1"
56705709
resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-1.1.1.tgz#279d449f7311fed910506987a1ade014027788a8"
@@ -6003,6 +6042,10 @@ resolve-from@^3.0.0:
60036042
version "3.0.0"
60046043
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
60056044

6045+
resolve-pathname@^2.2.0:
6046+
version "2.2.0"
6047+
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879"
6048+
60066049
resolve-url@^0.2.1:
60076050
version "0.2.1"
60086051
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -6971,6 +7014,10 @@ validate-npm-package-license@^3.0.1:
69717014
spdx-correct "^3.0.0"
69727015
spdx-expression-parse "^3.0.0"
69737016

7017+
value-equal@^0.4.0:
7018+
version "0.4.0"
7019+
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7"
7020+
69747021
vary@~1.1.2:
69757022
version "1.1.2"
69767023
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
@@ -6999,6 +7046,12 @@ walker@~1.0.5:
69997046
dependencies:
70007047
makeerror "1.0.x"
70017048

7049+
warning@^3.0.0:
7050+
version "3.0.0"
7051+
resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
7052+
dependencies:
7053+
loose-envify "^1.0.0"
7054+
70027055
watch@~0.10.0:
70037056
version "0.10.0"
70047057
resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"

0 commit comments

Comments
 (0)