Skip to content

Commit

Permalink
Merge pull request #19 from HDRUK/dev
Browse files Browse the repository at this point in the history
Build for Sprint 2
  • Loading branch information
tonyespley-pa authored May 22, 2020
2 parents 01c1b73 + afea3a8 commit 2a395e0
Show file tree
Hide file tree
Showing 27 changed files with 1,346 additions and 624 deletions.
21 changes: 15 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,35 @@ npm i -S mongoose express body-parser morgan cors
Create a .env file in the root of the project with this content:

```
# db user
# MongoDB connection parameters
user=
# db password
password=
# db cluster
cluster=
# db name
database=
homeURL=http://localhost:3000
# Auth parameters
googleClientID=
googleClientSecret=
JWTSecret=
homeURL=http://localhost:3000
PORT=3001
AUTH_PROVIDER_URI=
openidClientID=
openidClientSecret=
linkedinClientID=
linkedinClientSecret=
# Sendgrid API Key
SENDGRID_API_KEY=
# Datacustodian email address used for testing data access request locally, place with your email!
[email protected]
# Discourse integration
DISCOURSE_API_KEY=
DISCOURSE_URL=
DISCOURSE_CATEGORY_TOOLS_ID=
DISCOURSE_SSO_SECRET=
```

#### Step 4
Expand Down
22 changes: 11 additions & 11 deletions cloudbuild.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/hdrukrdt-tonyespley/hdruk-rdt-api:latest', '.']
args: ['build', '-t', 'gcr.io/$PROJECT_ID/${_APP_NAME}:latest', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/hdrukrdt-tonyespley/hdruk-rdt-api:latest']
args: ['push', 'gcr.io/$PROJECT_ID/${_APP_NAME}:latest']
- name: 'gcr.io/cloud-builders/gcloud'
args: ['run', 'deploy', 'latest-api', '--image', 'gcr.io/hdrukrdt-tonyespley/hdruk-rdt-api:latest', '--platform', 'managed', '--region', 'europe-west1', '--allow-unauthenticated']
- name: 'gcr.io/cloud-builders/gcloud'
args: ['run', 'deploy', 'uatbeta-api', '--image', 'gcr.io/hdrukrdt-tonyespley/hdruk-rdt-api:latest', '--platform', 'managed', '--region', 'europe-west1', '--allow-unauthenticated']
- name: 'gcr.io/cloud-builders/npm'
args: ['install']
- name: 'gcr.io/cloud-builders/npm'
args: ['test']
args: ['run', 'deploy', 'latest-api', '--image', 'gcr.io/$PROJECT_ID/${_APP_NAME}:latest', '--platform', 'managed', '--region', '${_REGION}', '--allow-unauthenticated']
- name: 'node'
args: ['npm','install']
- name: 'node'
args: ['npm','test']
env:
- 'URL=https://latest-api.healthresearch.tools'
- 'URL=https://${_TEST_URL}'
- name: 'gcr.io/cloud-builders/gcloud'
args: ['run', 'deploy', 'uatbeta-api', '--image', 'gcr.io/$PROJECT_ID/${_APP_NAME}:latest', '--platform', 'managed', '--region', '${_REGION}', '--allow-unauthenticated']
images:
- gcr.io/hdrukrdt-tonyespley/hdruk-rdt-api:latest
- gcr.io/$PROJECT_ID/${_APP_NAME}:latest
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"body-parser": "^1.19.0",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"discourse-sso": "^1.0.3",
"dotenv": "^8.2.0",
"esm": "^3.2.25",
"express": "^4.17.1",
Expand All @@ -23,6 +24,7 @@
"passport-jwt": "^4.0.0",
"passport-linkedin-oauth2": "^2.0.0",
"passport-openidconnect": "0.0.2",
"query-string": "^6.12.1",
"swagger-ui-express": "^4.1.4",
"test": "^0.6.0",
"yamljs": "^0.3.0"
Expand Down
32 changes: 16 additions & 16 deletions src/config/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,33 +47,33 @@ app.use(
app.use('/api', router);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

app.use('/api/auth', require('../resources/auth/auth.route'));
app.use('/api/v1/auth/soo/discourse', require('../resources/auth/sso/sso.discourse.router'));
app.use('/api/v1/auth', require('../resources/auth/auth.route'));
app.use('/api/v1/auth/register', require('../resources/user/user.register.route'));

app.use('/api/v1/users', require('../resources/user/user.route'));
app.use('/api/v1/messages', require('../resources/message/message.route'));
app.use('/api/v1/reviews', require('../resources/tool/review.route'));
app.use('/api/v1/tools', require('../resources/tool/tool.route'));
app.use('/api/v1/accounts', require('../resources/account/account.route'));
app.use('/api/v1/search/filter', require('../resources/search/filter.route'));
app.use('/api/v1/search', require('../resources/search/search.router')); // tools projects people

app.use('/api/search', require('../resources/search/search.router'));
app.use('/api/dataset', require('../resources/dataset/dataset.route'));
app.use('/api/v1/stats', require('../resources/stats/stats.router'));

app.use('/api/stats', require('../resources/stats/stats.router'));
app.use('/api/v1/person', require('../resources/person/person.route'));

app.use('/api/person', require('../resources/person/person.route'));
app.use('/api/v1/mytools', require('../resources/mytools/mytools.route'));
app.use('/api/v1/project', require('../resources/project/project.route'));
app.use('/api/v1/counter', require('../resources/tool/counter.route'));
app.use('/api/v1/discourse/topic', require('../resources/discourse/discourse.topic.route'));

app.use('/api/mytools', require('../resources/mytools/mytools.route'));
app.use('/api/project', require('../resources/project/project.route'));
app.use('/api/counter', require('../resources/tool/counter.route'));

app.use('/api/auth/register', require('../resources/user/user.register.route'));

app.use('/api/datasets/search', require('../resources/dataset/dataset.search.router'));
app.use('/api/datasetfilters', require('../resources/dataset/dataset.filter.router'));
app.use('/api/datasets/detail', require('../resources/dataset/dataset.detail.router'));
app.use('/api/datasets/sendgrid', require('../resources/dataset/dataset.route'));
app.use('/api/datasets/filteredsearch', require('../resources/dataset/dataset.searchwithfilters.router'));
app.use('/api/v1/datasets/search', require('../resources/dataset/dataset.search.router'));
app.use('/api/v1/datasets/filters', require('../resources/dataset/dataset.filters.router'));
app.use('/api/v1/datasets/access', require('../resources/dataset/dataset.access.router'));
app.use('/api/v1/datasets/detail', require('../resources/dataset/dataset.detail.router'));
app.use('/api/v1/datasets/filteredsearch', require('../resources/dataset/dataset.searchwithfilters.router')); //search
app.use('/api/v1/datasets', require('../resources/dataset/dataset.route'));

initialiseAuthentication(app);

Expand Down
58 changes: 31 additions & 27 deletions src/resources/account/account.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { utils } from "../auth";
import { ROLES } from '../user/user.roles'
import { Data } from '../tool/data.model';
import { MessagesModel } from '../message/message.model';
import { createDiscourseTopic } from '../discourse/discourse.service'

const router = express.Router();

Expand Down Expand Up @@ -131,34 +132,37 @@ router.get(
async (req, res) => {
const { id, activeflag } = req.body;

Data.findOneAndUpdate({ id: id },
{
activeflag: activeflag
}, (err) => {
var p = Data.find({ id: id });
p.exec((err, data) => {
for (var i = 0; i < data[0].authors.length; i++) {
let message = new MessagesModel();
message.messageID = parseInt(Math.random().toString().replace('0.', ''));
message.messageTo = data[0].authors[i];
message.messageObjectID = id;
message.messageType = 'approved';
message.messageSent = Date.now();
message.save((err) => {});
}
try {
let tool = await Data.findOneAndUpdate({ id: id }, { $set: { activeflag: activeflag }});
if (!tool) {s
return res.status(400).json({ success: false, error: 'Tool not found' });
}

if (tool.authors) {
tool.authors.forEach(async (authorId) => {
await createMessage(authorId, id);
});

let message = new MessagesModel();
message.messageID = parseInt(Math.random().toString().replace('0.', ''));
message.messageTo = 0;
message.messageObjectID = id;
message.messageType = 'approved';
message.messageSent = Date.now();
message.save((err) => {});
}
await createMessage(0, id);

await createDiscourseTopic(tool);

return res.json({ success: true });

if (err) return res.json({ success: false, error: err });
return res.json({ success: true });
});
} catch (err) {
console.log(err);
return res.status(500).json({ success: false, error: err });
}
});

module.exports = router;
module.exports = router;

async function createMessage(authorId, toolId) {
let message = new MessagesModel();
message.messageID = parseInt(Math.random().toString().replace('0.', ''));
message.messageTo = authorId;
message.messageObjectID = toolId;
message.messageType = 'approved';
message.messageSent = Date.now();
await message.save();
}
35 changes: 35 additions & 0 deletions src/resources/auth/sso/sso.discourse.router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import express from 'express';
import passport from 'passport';
import { signToken } from '../utils';
import { discourseLogin } from './sso.discourse.service';

const router = express.Router();

// @router GET /api/v1/auth/soo/discourse
// @desc Single Sign On for Discourse forum
// @access Private
router.get(
'/',
passport.authenticate('jwt'),
async (req, res) => {
let redirectUrl = null;

if (req.query.sso && req.query.sig) {
try {
redirectUrl = discourseLogin(req.query.sso, req.query.sig, req.user);
} catch (err) {
console.error(err);
return res.status(500).send('Error authenticating the user.');
}
}

return res
.status(200)
.cookie('jwt', signToken(req.user), {
httpOnly: true,
})
.json({redirectUrl: redirectUrl});
}
);

module.exports = router;
22 changes: 22 additions & 0 deletions src/resources/auth/sso/sso.discourse.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import discourse_sso from 'discourse-sso';

export function discourseLogin(payload, sig, user) {
const sso = new discourse_sso(process.env.DISCOURSE_SSO_SECRET);

if (!sso.validate(payload, sig)) {
throw Error(`Error validating Discourse SSO payload for user with id: ${user.id}.`);
}

const nonce = sso.getNonce(payload);
const userparams = {
nonce: nonce,
external_id: user.id,
email: user.email,
username: `${user.firstname.toLowerCase()}.${user.lastname.toLowerCase()}`,
name: `${user.firstname} ${user.lastname}`,
};

const q = sso.buildLoginString(userparams);

return `${process.env.DISCOURSE_URL}/session/sso_login?${q}`;
}
26 changes: 23 additions & 3 deletions src/resources/auth/strategies/google.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ import { getObjectById } from '../../tool/data.repository'
import { createUser } from '../../user/user.service'
import { signToken } from '../utils'
import { ROLES } from '../../user/user.roles'
import queryString from 'query-string';
import Url from 'url';
import { discourseLogin } from '../sso/sso.discourse.service';

const GoogleStrategy = passportGoogle.OAuth2Strategy

const strategy = app => {
const strategyOptions = {
clientID: process.env.googleClientID,
clientSecret: process.env.googleClientSecret,
callbackURL: `/auth/google/callback`
callbackURL: `/auth/google/callback`,
proxy: true
}

const verifyCallback = async (
Expand Down Expand Up @@ -69,8 +73,13 @@ const strategy = app => {
async (req, res) => {
var redirect = '/account';

let returnPage = null;
let queryStringParsed = null;

if (req.param.returnpage) {
redirect = require('url').parse(req.param.returnpage).path;
returnPage = Url.parse(req.param.returnpage);
redirect = returnPage.path;
queryStringParsed = queryString.parse(returnPage.query);
}

let [profileErr, profile] = await to(getObjectById(req.user.id))
Expand All @@ -83,13 +92,24 @@ const strategy = app => {
if (req.param.returnpage) {
delete req.param.returnpage;
}

let redirectUrl = process.env.homeURL + redirect;

if (queryStringParsed && queryStringParsed.sso && queryStringParsed.sig) {
try {
redirectUrl = discourseLogin(queryStringParsed.sso, queryStringParsed.sig, req.user);
} catch (err) {
console.error(err);
return res.status(500).send('Error authenticating the user.');
}
}

return res
.status(200)
.cookie('jwt', signToken(req.user), {
httpOnly: true
})
.redirect(process.env.homeURL+redirect)
.redirect(redirectUrl)
}
)

Expand Down
25 changes: 22 additions & 3 deletions src/resources/auth/strategies/linkedin.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ import { updateRedirectURL } from '../../user/user.service'
import { createUser } from '../../user/user.service'
import { signToken } from '../utils'
import { ROLES } from '../../user/user.roles'
import queryString from 'query-string';
import Url from 'url';
import { discourseLogin } from '../sso/sso.discourse.service';

const LinkedinStrategy = passportLinkedin.OAuth2Strategy

const strategy = app => {
const strategyOptions = {
clientID: process.env.linkedinClientID,
clientSecret: process.env.linkedinClientSecret,
callbackURL: `/auth/linkedin/callback`
callbackURL: `/auth/linkedin/callback`,
proxy: true
}

const verifyCallback = async (
Expand Down Expand Up @@ -67,8 +71,12 @@ const strategy = app => {
async (req, res) => {
var redirect = '/account';

let returnPage = null;
let queryStringParsed = null;
if (req.param.returnpage) {
redirect = require('url').parse(req.param.returnpage).path;
returnPage = Url.parse(req.param.returnpage);
redirect = returnPage.path;
queryStringParsed = queryString.parse(returnPage.query);
}

let [profileErr, profile] = await to(getObjectById(req.user.id))
Expand All @@ -81,13 +89,24 @@ const strategy = app => {
if (req.param.returnpage) {
delete req.param.returnpage;
}

let redirectUrl = process.env.homeURL + redirect;

if (queryStringParsed && queryStringParsed.sso && queryStringParsed.sig) {
try {
redirectUrl = discourseLogin(queryStringParsed.sso, queryStringParsed.sig, req.user);
} catch (err) {
console.error(err);
return res.status(500).send('Error authenticating the user.');
}
}

return res
.status(200)
.cookie('jwt', signToken(req.user), {
httpOnly: true
})
.redirect(process.env.homeURL+redirect)
.redirect(redirectUrl)
}
)

Expand Down
Loading

0 comments on commit 2a395e0

Please sign in to comment.