From 1ca03fb0e2bbb8bc832065b26fe4f0b8481e86ce Mon Sep 17 00:00:00 2001 From: Alexandru Munteanu <alexandru.munt@gmail.com> Date: Fri, 13 Jul 2018 14:00:38 +0300 Subject: [PATCH] feat(link-to-orcid): link a user account to orcid --- packages/component-user-manager/package.json | 7 ++- packages/component-user-manager/src/Users.js | 4 ++ .../src/routes/users/linkOrcid.js | 61 +++++++++++++++++++ .../src/components/UserProfile/LinkOrcID.js | 13 ++-- .../components/UserProfile/UserProfilePage.js | 2 +- packages/xpub-faraday/config/default.js | 9 ++- packages/xpub-faraday/config/validations.js | 1 + yarn.lock | 49 ++++++++++++++- 8 files changed, 132 insertions(+), 14 deletions(-) create mode 100644 packages/component-user-manager/src/routes/users/linkOrcid.js diff --git a/packages/component-user-manager/package.json b/packages/component-user-manager/package.json index c65b0553d..52b907483 100644 --- a/packages/component-user-manager/package.json +++ b/packages/component-user-manager/package.json @@ -20,13 +20,14 @@ }, "dependencies": { "body-parser": "^1.17.2", - "chance": "^1.0.13" + "chance": "^1.0.13", + "passport-orcid": "^0.0.3" }, "peerDependencies": { "@pubsweet/logger": "^0.0.1", + "pubsweet-component-helper-service": "0.0.1", "pubsweet-component-mail-service": "0.0.1", - "pubsweet-server": "^1.0.1", - "pubsweet-component-helper-service": "0.0.1" + "pubsweet-server": "^1.0.1" }, "devDependencies": { "apidoc": "^0.17.6", diff --git a/packages/component-user-manager/src/Users.js b/packages/component-user-manager/src/Users.js index 1c5c159dd..993e1b428 100644 --- a/packages/component-user-manager/src/Users.js +++ b/packages/component-user-manager/src/Users.js @@ -1,4 +1,5 @@ const bodyParser = require('body-parser') +const orcidRoutes = require('./routes/users/linkOrcid') const Invite = app => { app.use(bodyParser.json()) @@ -88,6 +89,9 @@ const Invite = app => { '/api/users/forgot-password', require('./routes/users/forgotPassword')(app.locals.models), ) + + // register ORCID authentication strategy + orcidRoutes(app) } module.exports = Invite diff --git a/packages/component-user-manager/src/routes/users/linkOrcid.js b/packages/component-user-manager/src/routes/users/linkOrcid.js new file mode 100644 index 000000000..afb9a1e3d --- /dev/null +++ b/packages/component-user-manager/src/routes/users/linkOrcid.js @@ -0,0 +1,61 @@ +const OrcidStrategy = require('passport-orcid') +const config = require('config') +const get = require('lodash/get') + +const { clientID, clientSecret, callbackPath, successPath } = config.get( + 'orcid', +) + +let userId +const LinkOrcid = app => { + const { passport } = app.locals + + passport.serializeUser((user, done) => { + done(null, user) + }) + + passport.deserializeUser((user, done) => { + done(null, user) + }) + + passport.use( + new OrcidStrategy( + { + sandbox: process.env.NODE_ENV !== 'production', + callbackURL: `${config.get('pubsweet-client.baseUrl')}${callbackPath}`, + clientID, + clientSecret, + }, + (accessToken, refreshToken, params, profile, done) => { + profile = { orcid: params.orcid, name: params.name } + return done(null, profile) + }, + ), + ) + + app.get( + '/api/users/orcid', + (req, res, next) => { + userId = get(req, 'query.userId') + next() + }, + passport.authenticate('orcid'), + ) + + app.get( + callbackPath, + passport.authenticate('orcid', { + failureRedirect: successPath, + }), + linkOrcidHandler(app.locals.models), + ) +} + +const linkOrcidHandler = models => async (req, res) => { + const user = await models.User.find(userId) + user.orcid = req.user.orcid + await user.save() + res.redirect(successPath) +} + +module.exports = LinkOrcid diff --git a/packages/components-faraday/src/components/UserProfile/LinkOrcID.js b/packages/components-faraday/src/components/UserProfile/LinkOrcID.js index 827c75eda..8b8532ee3 100644 --- a/packages/components-faraday/src/components/UserProfile/LinkOrcID.js +++ b/packages/components-faraday/src/components/UserProfile/LinkOrcID.js @@ -4,12 +4,12 @@ import styled from 'styled-components' import { Row, RowItem, - LabelHeader, - LabelTitle, LinkText, + LabelTitle, + LabelHeader, } from '../UIComponents/FormItems' -const LinkOrcID = ({ orcid = '' }) => ( +const LinkOrcID = ({ orcid = '', id }) => ( <Root> <Row noMargin> <RowItem> @@ -19,14 +19,13 @@ const LinkOrcID = ({ orcid = '' }) => ( {!orcid ? ( <Row noMargin> <RowItem> - <LinkText>Link</LinkText> + <Link href={`/api/users/orcid?userId=${id}`}>Link</Link> </RowItem> </Row> ) : ( <Row noMargin> <RowItem> - <LabelTitle> {orcid} </LabelTitle> - <LinkText>Unlink</LinkText> + <LabelTitle>{orcid}</LabelTitle> </RowItem> </Row> )} @@ -41,4 +40,6 @@ const Root = styled.div` flex-direction: column; max-width: 30em; ` + +const Link = LinkText.withComponent('a') // #endregion diff --git a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js index 64dd9d28e..462abc4c4 100644 --- a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js +++ b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js @@ -21,7 +21,7 @@ const UserProfilePage = ({ history, user }) => ( /> <AccountDetails history={history} user={user} /> <EmailNotifications subscribed={get(user, 'subscription')} /> - <LinkOrcID orcid={get(user, 'orcid')} /> + <LinkOrcID id={get(user, 'id')} orcid={get(user, 'orcid')} /> </Root> ) diff --git a/packages/xpub-faraday/config/default.js b/packages/xpub-faraday/config/default.js index 19ac346db..522a8f83e 100644 --- a/packages/xpub-faraday/config/default.js +++ b/packages/xpub-faraday/config/default.js @@ -44,10 +44,17 @@ module.exports = { }, 'pubsweet-client': { API_ENDPOINT: '/api', + baseUrl: process.env.CLIENT_BASE_URL || 'http://localhost:3000', 'login-redirect': '/', - 'redux-log': true, + 'redux-log': false, theme: process.env.PUBSWEET_THEME, }, + orcid: { + clientID: process.env.ORCID_CLIENT_ID, + clientSecret: process.env.ORCID_CLIENT_SECRET, + callbackPath: '/api/users/orcid/callback', + successPath: '/profile', + }, 'mail-transport': { sendmail: true, }, diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js index 35ebdd732..45de094ef 100644 --- a/packages/xpub-faraday/config/validations.js +++ b/packages/xpub-faraday/config/validations.js @@ -116,6 +116,7 @@ module.exports = { }, ], user: { + orcid: Joi.string(), name: Joi.string(), username: Joi.string(), isConfirmed: Joi.boolean(), diff --git a/yarn.lock b/yarn.lock index efc87c5ed..3eb96e13f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -856,6 +856,13 @@ aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" +axios@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" + dependencies: + follow-redirects "^1.3.0" + is-buffer "^1.1.5" + axobject-query@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-0.1.0.tgz#62f59dbc59c9f9242759ca349960e7a2fe3c36c0" @@ -2552,6 +2559,13 @@ core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +cors@^2.8.4: + version "2.8.4" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686" + dependencies: + object-assign "^4" + vary "^1" + cosmiconfig@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-1.1.0.tgz#0dea0f9804efdfb929fbb1b188e25553ea053d37" @@ -3959,6 +3973,12 @@ flush-write-stream@^1.0.0: inherits "^2.0.1" readable-stream "^2.0.4" +follow-redirects@^1.3.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" + dependencies: + debug "^3.1.0" + font-awesome@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" @@ -6640,11 +6660,15 @@ oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" +oauth@0.9.x: + version "0.9.15" + resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + object-assign@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -6942,6 +6966,21 @@ passport-local@^1.0.0: dependencies: passport-strategy "1.x.x" +passport-oauth2@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.4.0.tgz#f62f81583cbe12609be7ce6f160b9395a27b86ad" + dependencies: + oauth "0.9.x" + passport-strategy "1.x.x" + uid2 "0.0.x" + utils-merge "1.x.x" + +passport-orcid@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/passport-orcid/-/passport-orcid-0.0.3.tgz#802126a4e0dac0dc1406b9521b29b0dd13644ec4" + dependencies: + passport-oauth2 "^1.4.0" + passport-strategy@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" @@ -9742,6 +9781,10 @@ uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +uid2@0.0.x: + version "0.0.3" + resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" + ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" @@ -9920,7 +9963,7 @@ utile@0.3.x: ncp "1.0.x" rimraf "2.x.x" -utils-merge@1.0.1: +utils-merge@1.0.1, utils-merge@1.x.x: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -9947,7 +9990,7 @@ value-equal@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" -vary@~1.1.2: +vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" -- GitLab