Page de profil #13

Manually merged
wpetit merged 3 commits from feature/user-profile into develop 2020-07-17 09:25:52 +02:00
16 changed files with 349 additions and 46 deletions
Showing only changes of commit 8b8f322630 - Show all commits

198
client/package-lock.json generated
View File

@ -1230,8 +1230,7 @@
"@types/node": { "@types/node": {
"version": "13.13.12", "version": "13.13.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.12.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.12.tgz",
"integrity": "sha512-zWz/8NEPxoXNT9YyF2osqyA9WjssZukYpgI4UYZpOjcyqwIUqWGkcCionaEb9Ki+FULyPyvNFpg/329Kd2/pbw==", "integrity": "sha512-zWz/8NEPxoXNT9YyF2osqyA9WjssZukYpgI4UYZpOjcyqwIUqWGkcCionaEb9Ki+FULyPyvNFpg/329Kd2/pbw=="
"dev": true
}, },
"@types/prop-types": { "@types/prop-types": {
"version": "15.7.3", "version": "15.7.3",
@ -1372,6 +1371,11 @@
} }
} }
}, },
"@types/zen-observable": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.0.tgz",
"integrity": "sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg=="
},
"@webassemblyjs/ast": { "@webassemblyjs/ast": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
@ -1547,6 +1551,23 @@
"@xtuc/long": "4.2.2" "@xtuc/long": "4.2.2"
} }
}, },
"@wry/context": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/@wry/context/-/context-0.4.4.tgz",
"integrity": "sha512-LrKVLove/zw6h2Md/KZyWxIkFM6AoyKp71OqpH9Hiip1csjPVoD3tPxlbQUNxEnHENks3UGgNpSBCAfq9KWuag==",
"requires": {
"@types/node": ">=6",
"tslib": "^1.9.3"
}
},
"@wry/equality": {
"version": "0.1.11",
"resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.1.11.tgz",
"integrity": "sha512-mwEVBDUVODlsQQ5dfuLUS5/Tf7jqUKyhKYHmVi4fPB6bDMOfWvUPJmKgS1Z7Za/sOI3vzWt4+O7yCiL/70MogA==",
"requires": {
"tslib": "^1.9.3"
}
},
"@xtuc/ieee754": { "@xtuc/ieee754": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@ -1723,6 +1744,93 @@
} }
} }
}, },
"apollo-cache": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.3.5.tgz",
"integrity": "sha512-1XoDy8kJnyWY/i/+gLTEbYLnoiVtS8y7ikBr/IfmML4Qb+CM7dEEbIUOjnY716WqmZ/UpXIxTfJsY7rMcqiCXA==",
"requires": {
"apollo-utilities": "^1.3.4",
"tslib": "^1.10.0"
}
},
"apollo-cache-inmemory": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.6.tgz",
"integrity": "sha512-L8pToTW/+Xru2FFAhkZ1OA9q4V4nuvfoPecBM34DecAugUZEBhI2Hmpgnzq2hTKZ60LAMrlqiASm0aqAY6F8/A==",
"requires": {
"apollo-cache": "^1.3.5",
"apollo-utilities": "^1.3.4",
"optimism": "^0.10.0",
"ts-invariant": "^0.4.0",
"tslib": "^1.10.0"
}
},
"apollo-client": {
"version": "2.6.10",
"resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-2.6.10.tgz",
"integrity": "sha512-jiPlMTN6/5CjZpJOkGeUV0mb4zxx33uXWdj/xQCfAMkuNAC3HN7CvYDyMHHEzmcQ5GV12LszWoQ/VlxET24CtA==",
"requires": {
"@types/zen-observable": "^0.8.0",
"apollo-cache": "1.3.5",
"apollo-link": "^1.0.0",
"apollo-utilities": "1.3.4",
"symbol-observable": "^1.0.2",
"ts-invariant": "^0.4.0",
"tslib": "^1.10.0",
"zen-observable": "^0.8.0"
}
},
"apollo-link": {
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.14.tgz",
"integrity": "sha512-p67CMEFP7kOG1JZ0ZkYZwRDa369w5PIjtMjvrQd/HnIV8FRsHRqLqK+oAZQnFa1DDdZtOtHTi+aMIW6EatC2jg==",
"requires": {
"apollo-utilities": "^1.3.0",
"ts-invariant": "^0.4.0",
"tslib": "^1.9.3",
"zen-observable-ts": "^0.8.21"
}
},
"apollo-link-http": {
"version": "1.5.17",
"resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.17.tgz",
"integrity": "sha512-uWcqAotbwDEU/9+Dm9e1/clO7hTB2kQ/94JYcGouBVLjoKmTeJTUPQKcJGpPwUjZcSqgYicbFqQSoJIW0yrFvg==",
"requires": {
"apollo-link": "^1.2.14",
"apollo-link-http-common": "^0.2.16",
"tslib": "^1.9.3"
}
},
"apollo-link-http-common": {
"version": "0.2.16",
"resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.16.tgz",
"integrity": "sha512-2tIhOIrnaF4UbQHf7kjeQA/EmSorB7+HyJIIrUjJOKBgnXwuexi8aMecRlqTIDWcyVXCeqLhUnztMa6bOH/jTg==",
"requires": {
"apollo-link": "^1.2.14",
"ts-invariant": "^0.4.0",
"tslib": "^1.9.3"
}
},
"apollo-link-ws": {
"version": "1.0.20",
"resolved": "https://registry.npmjs.org/apollo-link-ws/-/apollo-link-ws-1.0.20.tgz",
"integrity": "sha512-mjSFPlQxmoLArpHBeUb2Xj+2HDYeTaJqFGOqQ+I8NVJxgL9lJe84PDWcPah/yMLv3rB7QgBDSuZ0xoRFBPlySw==",
"requires": {
"apollo-link": "^1.2.14",
"tslib": "^1.9.3"
}
},
"apollo-utilities": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.4.tgz",
"integrity": "sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig==",
"requires": {
"@wry/equality": "^0.1.2",
"fast-json-stable-stringify": "^2.0.0",
"ts-invariant": "^0.4.0",
"tslib": "^1.10.0"
}
},
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@ -1875,8 +1983,7 @@
"async-limiter": { "async-limiter": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
"dev": true
}, },
"asynckit": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
@ -2724,6 +2831,11 @@
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
"dev": true "dev": true
}, },
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
},
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -5029,8 +5141,7 @@
"fast-json-stable-stringify": { "fast-json-stable-stringify": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
"dev": true
}, },
"fastparse": { "fastparse": {
"version": "1.1.2", "version": "1.1.2",
@ -5499,11 +5610,21 @@
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true "dev": true
}, },
"graphql": {
"version": "15.3.0",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-15.3.0.tgz",
"integrity": "sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w=="
},
"graphql-request": { "graphql-request": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-2.0.0.tgz", "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-2.0.0.tgz",
"integrity": "sha512-Ww3Ax+G3l2d+mPT8w7HC9LfrKjutnCKtnDq7ZZp2ghVk5IQDjwAk3/arRF1ix17Ky15rm0hrSKVKxRhIVlSuoQ==" "integrity": "sha512-Ww3Ax+G3l2d+mPT8w7HC9LfrKjutnCKtnDq7ZZp2ghVk5IQDjwAk3/arRF1ix17Ky15rm0hrSKVKxRhIVlSuoQ=="
}, },
"graphql-tag": {
"version": "2.10.4",
"resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.4.tgz",
"integrity": "sha512-O7vG5BT3w6Sotc26ybcvLKNTdfr4GfsIVMD+LdYqXCeJIYPRyp8BIsDOUtxw7S1PYvRw5vH3278J2EDezR6mfA=="
},
"handle-thing": { "handle-thing": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
@ -6308,6 +6429,11 @@
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true "dev": true
}, },
"iterall": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz",
"integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg=="
},
"js-base64": { "js-base64": {
"version": "2.5.2", "version": "2.5.2",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz",
@ -7340,6 +7466,14 @@
"is-wsl": "^1.1.0" "is-wsl": "^1.1.0"
} }
}, },
"optimism": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/optimism/-/optimism-0.10.3.tgz",
"integrity": "sha512-9A5pqGoQk49H6Vhjb9kPgAeeECfUDF6aIICbMDL23kDLStBn1MWk3YvcZ4xWF9CsSf6XEgvRLkXy4xof/56vVw==",
"requires": {
"@wry/context": "^0.4.0"
}
},
"original": { "original": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
@ -9420,6 +9554,33 @@
"resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz", "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz",
"integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==" "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw=="
}, },
"subscriptions-transport-ws": {
"version": "0.9.17",
"resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.17.tgz",
"integrity": "sha512-hNHi2N80PBz4T0V0QhnnsMGvG3XDFDS9mS6BhZ3R12T6EBywC8d/uJscsga0cVO4DKtXCkCRrWm2sOYrbOdhEA==",
"requires": {
"backo2": "^1.0.2",
"eventemitter3": "^3.1.0",
"iterall": "^1.2.1",
"symbol-observable": "^1.0.4",
"ws": "^5.2.0"
},
"dependencies": {
"eventemitter3": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
},
"ws": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
"requires": {
"async-limiter": "~1.0.0"
}
}
}
},
"supports-color": { "supports-color": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@ -9658,6 +9819,14 @@
"glob": "^7.1.2" "glob": "^7.1.2"
} }
}, },
"ts-invariant": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz",
"integrity": "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==",
"requires": {
"tslib": "^1.9.3"
}
},
"ts-loader": { "ts-loader": {
"version": "7.0.5", "version": "7.0.5",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-7.0.5.tgz", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-7.0.5.tgz",
@ -9725,8 +9894,7 @@
"tslib": { "tslib": {
"version": "1.13.0", "version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
"dev": true
}, },
"tty-browserify": { "tty-browserify": {
"version": "0.0.0", "version": "0.0.0",
@ -10833,6 +11001,20 @@
"dev": true "dev": true
} }
} }
},
"zen-observable": {
"version": "0.8.15",
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
"integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ=="
},
"zen-observable-ts": {
"version": "0.8.21",
"resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz",
"integrity": "sha512-Yj3yXweRc8LdRMrCC8nIc4kkjWecPAUVh0TI0OUrWXx6aX790vLcDlWca6I4vsyCGH3LpWxq0dJRcMOFoVqmeg==",
"requires": {
"tslib": "^1.9.3",
"zen-observable": "^0.8.0"
}
} }
} }
} }

View File

@ -52,9 +52,17 @@
}, },
"dependencies": { "dependencies": {
"@types/qs": "^6.9.3", "@types/qs": "^6.9.3",
"apollo-cache-inmemory": "^1.6.6",
"apollo-client": "^2.6.10",
"apollo-link": "^1.2.14",
"apollo-link-http": "^1.5.17",
"apollo-link-ws": "^1.0.20",
"apollo-utilities": "^1.3.4",
"bulma": "^0.7.2", "bulma": "^0.7.2",
"bulma-switch": "^2.0.0", "bulma-switch": "^2.0.0",
"graphql": "^15.3.0",
"graphql-request": "^2.0.0", "graphql-request": "^2.0.0",
"graphql-tag": "^2.10.4",
"jwt-decode": "^2.2.0", "jwt-decode": "^2.2.0",
"qs": "^6.9.4", "qs": "^6.9.4",
"react": "^16.12.0", "react": "^16.12.0",
@ -65,6 +73,7 @@
"redux": "^4.0.4", "redux": "^4.0.4",
"redux-saga": "^1.1.3", "redux-saga": "^1.1.3",
"styled-components": "^4.4.1", "styled-components": "^4.4.1",
"subscriptions-transport-ws": "^0.9.17",
"typescript": "^3.8.3" "typescript": "^3.8.3"
} }
} }

View File

@ -14,8 +14,8 @@ export function HomePage() {
<div className="column is-4 is-offset-4"> <div className="column is-4 is-offset-4">
<div className="box"> <div className="box">
{ {
currentUser && currentUser.full_name ? currentUser && currentUser.email ?
<p>Bonjour <span className="has-text-weight-bold">{currentUser.full_name}</span> !</p> : <p>Bonjour <span className="has-text-weight-bold">{currentUser.email}</span> !</p> :
<p>Veuillez vous authentifier.</p> <p>Veuillez vous authentifier.</p>
} }
</div> </div>

View File

@ -2,6 +2,7 @@ export const Config = {
loginURL: get<string>("loginURL", "http://localhost:8081/login"), loginURL: get<string>("loginURL", "http://localhost:8081/login"),
logoutURL: get<string>("logoutURL", "http://localhost:8081/logout"), logoutURL: get<string>("logoutURL", "http://localhost:8081/logout"),
graphQLEndpoint: get<string>("graphQLEndpoint", "http://localhost:8081/api/v1/graphql"), graphQLEndpoint: get<string>("graphQLEndpoint", "http://localhost:8081/api/v1/graphql"),
subscriptionEndpoint: get<string>("subscriptionEndpoint", "ws://localhost:8081/api/v1/graphql"),
}; };
function get<T>(key: string, defaultValue: T):T { function get<T>(key: string, defaultValue: T):T {

View File

@ -39,7 +39,9 @@ function handleFetchProfileSuccess(state: AuthState, { profile }: fetchProfileSu
...state, ...state,
isAuthenticated: true, isAuthenticated: true,
currentUser: { currentUser: {
...profile, email: profile.email,
connectedAt: profile.connectedAt,
createdAt: profile.createdAt,
} }
}; };
}; };

View File

@ -1,7 +1,12 @@
import { all, put } from "redux-saga/effects"; import { all, put } from "redux-saga/effects";
import { fetchProfile } from "../actions/profile";
export function* initRootSaga() { export function* initRootSaga() {
yield all([ yield all([
fetchUserProfileSaga(),
]); ]);
}
export function* fetchUserProfileSaga() {
yield put(fetchProfile());
} }

View File

@ -7,5 +7,6 @@ export function* rootSaga() {
yield all([ yield all([
initRootSaga(), initRootSaga(),
failureRootSaga(), failureRootSaga(),
usersRootSaga(),
]); ]);
} }

View File

@ -1,4 +1,4 @@
import { DaddyClient } from "../../util/daddy"; import { DaddyClient, getClient } from "../../util/daddy";
import { Config } from "../../config"; import { Config } from "../../config";
import { all, takeLatest, put, select } from "redux-saga/effects"; import { all, takeLatest, put, select } from "redux-saga/effects";
import { FETCH_PROFILE_REQUEST, fetchProfile, FETCH_PROFILE_FAILURE, FETCH_PROFILE_SUCCESS } from "../actions/profile"; import { FETCH_PROFILE_REQUEST, fetchProfile, FETCH_PROFILE_FAILURE, FETCH_PROFILE_SUCCESS } from "../actions/profile";
@ -18,12 +18,12 @@ export function* onCurrentUserChangeSaga() {
} }
export function* fetchProfileSaga() { export function* fetchProfileSaga() {
const client = new DaddyClient(Config.graphQLEndpoint); const client = getClient(Config.graphQLEndpoint, Config.subscriptionEndpoint);
let profile: User; let profile: User;
try { try {
const currentUser: User = yield select((state: RootState) => state.auth.currentUser); profile = yield client.fetchProfile().then(result => result.userProfile);
profile = yield client.fetchUser(currentUser.email).then(result => result.user); console.log(profile);
} catch(err) { } catch(err) {
yield put({ type: FETCH_PROFILE_FAILURE, err }); yield put({ type: FETCH_PROFILE_FAILURE, err });
return; return;

View File

@ -1,6 +1,5 @@
export interface User { export interface User {
email: string email: string
full_name?: string connectedAt?: Date
updated_at?: Date createdAt?: Date
created_at?: Date
} }

View File

@ -1,5 +1,10 @@
import { GraphQLClient } from 'graphql-request' import ApolloClient from 'apollo-client';
import { Config } from "../config"; import { InMemoryCache } from 'apollo-cache-inmemory';
import { split } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import { WebSocketLink } from 'apollo-link-ws';
import { getMainDefinition } from 'apollo-utilities';
import gql from 'graphql-tag';
export class UnauthorizedError extends Error { export class UnauthorizedError extends Error {
constructor(...args: any[]) { constructor(...args: any[]) {
@ -8,30 +13,65 @@ export class UnauthorizedError extends Error {
} }
} }
let client: DaddyClient
export function getClient(graphQLEndpoint: string, subscriptionEndpoint: string): DaddyClient {
if (!client) {
client = new DaddyClient(graphQLEndpoint, subscriptionEndpoint);
}
return client;
}
export class DaddyClient { export class DaddyClient {
gql: GraphQLClient gql: ApolloClient<InMemoryCache>
constructor(endpoint: string) { constructor(graphQLEndpoint: string, subscriptionEndpoint: string) {
this.gql = new GraphQLClient(endpoint, { const wsLink = new WebSocketLink({
headers: { uri: subscriptionEndpoint,
mode: 'cors', options: {
reconnect: true
} }
}); });
const httpLink = new HttpLink({
uri: graphQLEndpoint,
fetchOptions: {
mode: 'cors',
credentials: 'include',
}
});
const link = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink,
);
this.gql = new ApolloClient<any>({
link: link,
cache: new InMemoryCache(),
});
} }
fetchUser(email: string) { fetchProfile() {
return this.gql.rawRequest(` return this.gql.query({
query fetchUser { query: gql`
user(where: {email: {eq: $email}}) { query {
id userProfile {
created_at
updated_at
email, email,
full_name createdAt,
connectedAt
} }
} }`
`, { email }) })
.then(this.assertAuthorization) .then(this.assertAuthorization)
} }

2
go.mod
View File

@ -9,9 +9,11 @@ require (
github.com/cortesi/modd v0.0.0-20200630120222-8983974e5450 // indirect github.com/cortesi/modd v0.0.0-20200630120222-8983974e5450 // indirect
github.com/go-chi/chi v4.1.0+incompatible github.com/go-chi/chi v4.1.0+incompatible
github.com/gorilla/sessions v1.2.0 github.com/gorilla/sessions v1.2.0
github.com/gorilla/websocket v1.2.0
github.com/jackc/pgx v3.6.2+incompatible github.com/jackc/pgx v3.6.2+incompatible
github.com/jackc/pgx/v4 v4.7.1 github.com/jackc/pgx/v4 v4.7.1
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/rs/cors v1.7.0
github.com/vektah/gqlparser/v2 v2.0.1 github.com/vektah/gqlparser/v2 v2.0.1
gitlab.com/wpetit/goweb v0.0.0-20200707070104-985ce3eba3c2 gitlab.com/wpetit/goweb v0.0.0-20200707070104-985ce3eba3c2
gopkg.in/yaml.v2 v2.2.8 gopkg.in/yaml.v2 v2.2.8

2
go.sum
View File

@ -248,6 +248,8 @@ github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1 h1:FLWDC+iIP9BWgY
github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= github.com/rjeczalik/notify v0.0.0-20181126183243-629144ba06a1/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=

View File

@ -37,13 +37,19 @@ func NewFromFile(filepath string) (*Config, error) {
} }
type HTTPConfig struct { type HTTPConfig struct {
Address string `yaml:"address" env:"HTTP_ADDRESS"` Address string `yaml:"address" env:"HTTP_ADDRESS"`
CookieAuthenticationKey string `yaml:"cookieAuthenticationKey" env:"HTTP_COOKIE_AUTHENTICATION_KEY"` CookieAuthenticationKey string `yaml:"cookieAuthenticationKey" env:"HTTP_COOKIE_AUTHENTICATION_KEY"`
CookieEncryptionKey string `yaml:"cookieEncryptionKey" env:"HTTP_COOKIE_ENCRYPTION_KEY"` CookieEncryptionKey string `yaml:"cookieEncryptionKey" env:"HTTP_COOKIE_ENCRYPTION_KEY"`
CookieMaxAge int `yaml:"cookieMaxAge" env:"HTTP_COOKIE_MAX_AGE"` CookieMaxAge int `yaml:"cookieMaxAge" env:"HTTP_COOKIE_MAX_AGE"`
TemplateDir string `yaml:"templateDir" env:"HTTP_TEMPLATE_DIR"` TemplateDir string `yaml:"templateDir" env:"HTTP_TEMPLATE_DIR"`
PublicDir string `yaml:"publicDir" env:"HTTP_PUBLIC_DIR"` PublicDir string `yaml:"publicDir" env:"HTTP_PUBLIC_DIR"`
FrontendURL string `yaml:"frontendURL" env:"HTTP_FRONTEND_URL"` FrontendURL string `yaml:"frontendURL" env:"HTTP_FRONTEND_URL"`
CORS CORSConfig `yaml:"cors"`
}
type CORSConfig struct {
AllowedOrigins []string `yaml:"allowedOrigins" env:"HTTP_CORS_ALLOWED_ORIGINS"`
AllowCredentials bool `yaml:"allowCredentials" env:"HTTP_CORS_ALLOW_CREDENTIALS"`
} }
type OIDCConfig struct { type OIDCConfig struct {
@ -83,6 +89,10 @@ func NewDefault() *Config {
TemplateDir: "template", TemplateDir: "template",
PublicDir: "public", PublicDir: "public",
FrontendURL: "http://localhost:8080", FrontendURL: "http://localhost:8080",
CORS: CORSConfig{
AllowedOrigins: []string{"http://localhost:8080"},
AllowCredentials: true,
},
}, },
OIDC: OIDCConfig{ OIDC: OIDCConfig{
IssuerURL: "http://localhost:4444/", IssuerURL: "http://localhost:4444/",

View File

@ -3,6 +3,9 @@ package route
import ( import (
"net/http" "net/http"
"forge.cadoles.com/Cadoles/daddy/internal/session"
"github.com/pkg/errors"
"forge.cadoles.com/Cadoles/daddy/internal/config" "forge.cadoles.com/Cadoles/daddy/internal/config"
oidc "forge.cadoles.com/wpetit/goweb-oidc" oidc "forge.cadoles.com/wpetit/goweb-oidc"
"gitlab.com/wpetit/goweb/logger" "gitlab.com/wpetit/goweb/logger"
@ -21,6 +24,10 @@ func handleLogout(w http.ResponseWriter, r *http.Request) {
logger.F("postLogoutURL", conf.OIDC.PostLogoutRedirectURL), logger.F("postLogoutURL", conf.OIDC.PostLogoutRedirectURL),
) )
if err := session.ClearUserEmail(w, r, false); err != nil {
panic(errors.WithStack(err))
}
client.Logout(w, r, conf.OIDC.PostLogoutRedirectURL) client.Logout(w, r, conf.OIDC.PostLogoutRedirectURL)
} }

View File

@ -1,15 +1,22 @@
package route package route
import ( import (
"net/http"
"time"
"forge.cadoles.com/Cadoles/daddy/internal/config" "forge.cadoles.com/Cadoles/daddy/internal/config"
"forge.cadoles.com/Cadoles/daddy/internal/graph" "forge.cadoles.com/Cadoles/daddy/internal/graph"
"forge.cadoles.com/Cadoles/daddy/internal/graph/generated" "forge.cadoles.com/Cadoles/daddy/internal/graph/generated"
"forge.cadoles.com/Cadoles/daddy/internal/session" "forge.cadoles.com/Cadoles/daddy/internal/session"
oidc "forge.cadoles.com/wpetit/goweb-oidc" oidc "forge.cadoles.com/wpetit/goweb-oidc"
"github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/99designs/gqlgen/graphql/playground" "github.com/99designs/gqlgen/graphql/playground"
"github.com/gorilla/websocket"
"github.com/go-chi/chi" "github.com/go-chi/chi"
"github.com/rs/cors"
"gitlab.com/wpetit/goweb/static" "gitlab.com/wpetit/goweb/static"
) )
@ -21,20 +28,39 @@ func Mount(r *chi.Mux, config *config.Config) error {
r.Get("/logout/redirect", handleLogoutRedirect) r.Get("/logout/redirect", handleLogoutRedirect)
r.Route("/api", func(r chi.Router) { r.Route("/api", func(r chi.Router) {
r.Use(cors.New(cors.Options{
AllowedOrigins: config.HTTP.CORS.AllowedOrigins,
AllowCredentials: config.HTTP.CORS.AllowCredentials,
Debug: config.Debug,
}).Handler)
r.Use(oidc.Middleware) r.Use(oidc.Middleware)
r.Use(session.UserEmailMiddleware) r.Use(session.UserEmailMiddleware)
gql := handler.NewDefaultServer( gql := handler.New(
generated.NewExecutableSchema(generated.Config{ generated.NewExecutableSchema(generated.Config{
Resolvers: &graph.Resolver{}, Resolvers: &graph.Resolver{},
}), }),
) )
gql.AddTransport(transport.POST{})
gql.AddTransport(&transport.Websocket{
KeepAlivePingInterval: 10 * time.Second,
Upgrader: websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
// TODO Check WS connection origin
return true
},
ReadBufferSize: 1024,
WriteBufferSize: 1024,
},
})
if config.Debug { if config.Debug {
r.Get("/v1/graphql", playground.Handler("GraphQL playground", "/api/v1/graphql")) gql.Use(extension.Introspection{})
r.Get("/v1/playground", playground.Handler("GraphQL playground", "/api/v1/graphql"))
} }
r.Post("/v1/graphql", gql.ServeHTTP) r.Handle("/v1/graphql", gql)
}) })
notFoundHandler := r.NotFoundHandler() notFoundHandler := r.NotFoundHandler()

View File

@ -61,6 +61,23 @@ func SaveUserEmail(w http.ResponseWriter, r *http.Request, email string) error {
return nil return nil
} }
func ClearUserEmail(w http.ResponseWriter, r *http.Request, saveSession bool) error {
sess, err := getSession(w, r)
if err != nil {
return errors.WithStack(err)
}
sess.Unset(string(userEmailKey))
if saveSession {
if err := sess.Save(w, r); err != nil {
return errors.WithStack(err)
}
}
return nil
}
func GetUserEmail(w http.ResponseWriter, r *http.Request) (string, error) { func GetUserEmail(w http.ResponseWriter, r *http.Request) (string, error) {
sess, err := getSession(w, r) sess, err := getSession(w, r)
if err != nil { if err != nil {