-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Github Integration #42
base: integrations
Are you sure you want to change the base?
Changes from all commits
0fc5993
282b544
5b135d3
722e3c0
bfc6508
9164cca
5313cd2
6f2d709
1c79cd6
93e3b40
e65d214
6f819eb
bdb1751
03eebd8
ff74f67
3c54e27
f705c3c
4cf8875
3d90142
50c1be1
fadaa57
714c728
3fe159e
566c10c
b85d4cc
cafa608
e0626a9
8075fa2
c084a09
8d6bac9
8ba427c
4bfe9de
2945963
9859e7c
baa4d77
eb61325
b3f8c7c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,18 +9,22 @@ import cors from 'cors'; | |
import logger from './utils/logger'; | ||
import authorize from './thirdparty/routes/authorize'; | ||
import slackRouter from './thirdparty/routes/slackRouter'; | ||
import githubRouter from './thirdparty/routes/githubRouter'; | ||
import IntegrationService from './controller/IntegrationService'; | ||
import AuthenticationMiddleware from './middlewares/authentication'; | ||
|
||
dotenv.config(); | ||
|
||
const app = express(); | ||
const modelDirPath = path.join(__dirname, 'models'); | ||
const routeDirPath = path.join(__dirname, 'routes'); | ||
const publicFolder = path.join(__dirname, '../assets'); | ||
|
||
app.use(pino()); | ||
app.use(express.json()); | ||
app.use(express.urlencoded({ extended: false })); | ||
app.use(express.static(path.join(__dirname, 'public'))); | ||
app.use(express.static(publicFolder)); | ||
// app.use('/api/v1', AuthenticationMiddleware); | ||
app.set('view engine', 'ejs'); | ||
app.set('views', path.join(__dirname, '/thirdparty/views')); | ||
requireAll(modelDirPath); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. all require should happen before any logic. Ideally, they should be the first thing |
||
|
@@ -37,6 +41,7 @@ for (const route in routes) { | |
// authorize router | ||
app.use('/', authorize); | ||
app.use(slackRouter.path, slackRouter.router); | ||
app.use(githubRouter.path, githubRouter.router); | ||
|
||
// catch 404 and forward to error handler | ||
app.use((req, res, next) => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,19 @@ | ||
import SlackActionPerformer from '../thirdparty/controllers/SlackActionPerformer'; | ||
|
||
const ActionPerformers = {}; | ||
ActionPerformers[SlackActionPerformer.appName] = SlackActionPerformer.performer; | ||
import eventEmitter from '../lib/eventsLib'; | ||
import slackActionPerformer from '../thirdparty/controllers/SlackActionPerformer'; | ||
|
||
const ActionPerformer = async (relay, triggerEvent) => { | ||
const actionsToPerform = relay.participantApps.slice(1); | ||
for (const action of actionsToPerform) { | ||
if (action.eventType === 'Action') { | ||
ActionPerformer[action.appName](relay, action, triggerEvent); | ||
const correspondingActionPerformer = `${action.appName.toLowerCase()}ActionPerformer`; | ||
eventEmitter.emit(correspondingActionPerformer, relay, action, triggerEvent); | ||
} | ||
} | ||
}; | ||
|
||
export default ActionPerformer; | ||
const exports = { | ||
ActionPerformer, | ||
slackActionPerformer, | ||
}; | ||
|
||
export default exports; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,57 @@ | ||
import mongoose from 'mongoose'; | ||
import responseLib from '../lib/responseLib'; | ||
import * as actionStatus from '../constants/actionStatus'; | ||
import IntegrationConfig from '../thirdparty/integrationConfig'; | ||
import AuthorizedApps from '../models/AuthorizedApps'; | ||
|
||
const AppsCollection = mongoose.model('Apps'); | ||
const getApps = (req, res) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add some line breaks, it is not readable |
||
const appsAndEvents = []; | ||
for (const [appName, appData] of Object.entries(IntegrationConfig)) { | ||
const singleAppDetails = { Trigger: [], Action: [] }; | ||
singleAppDetails.appName = appName; | ||
singleAppDetails.icon = appData.icon_path; | ||
for (const event of appData.Events) { | ||
singleAppDetails[event.EventType].push(event.EventName); | ||
} | ||
appsAndEvents.push(singleAppDetails); | ||
} | ||
// const AppsCollection = mongoose.model('Apps'); | ||
|
||
const createApp = async (req, res) => { | ||
console.log(req.body); | ||
const createdApp = await AppsCollection.create(req.body); | ||
res.send(createdApp); | ||
const generatedResponse = responseLib.generateResponse(false, actionStatus.SUCCESS, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pass in an object with values instead of multiple params. It's easier to update/ changes params later. |
||
'Apps and Events', appsAndEvents); | ||
res.send(generatedResponse); | ||
}; | ||
|
||
const getEventDetails = (req, res) => { | ||
let eventDetails; | ||
for (const event of IntegrationConfig[req.params.appName].Events) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what if |
||
if (event.EventName === req.query.eventName) { | ||
eventDetails = event; | ||
} | ||
} | ||
|
||
const generatedResponse = responseLib.generateResponse(false, actionStatus.SUCCESS, | ||
'Event Details', eventDetails); | ||
res.send(generatedResponse); | ||
}; | ||
const getAllApp = async (req, res) => { | ||
const fetchedAppList = await AppsCollection.find({}); | ||
const generatedResponse = responseLib.generateResponse(false, actionStatus.SUCCESS, 'List Generated', fetchedAppList); | ||
|
||
const getAuthorizedAccounts = async (req, res) => { | ||
const authorizedAccountsForApp = await AuthorizedApps.find({ | ||
userId: req.userId, | ||
appName: req.params.appName, | ||
}).select({ | ||
_id: 0, | ||
appName: 1, | ||
email: 1, | ||
credentials: 1, | ||
}); | ||
|
||
const generatedResponse = responseLib.generateResponse(false, actionStatus.SUCCESS, | ||
'Authorized accounts for app', authorizedAccountsForApp); | ||
res.send(generatedResponse); | ||
}; | ||
|
||
module.exports = { | ||
createApp, | ||
getAllApp, | ||
getApps, | ||
getEventDetails, | ||
getAuthorizedAccounts, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ const slackWebHookListener = async (event, authedUsers) => { | |
}; | ||
|
||
const gitWebHookListener = (event) => { | ||
console.log(event); | ||
// console.log(event); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. empty function? |
||
}; | ||
|
||
const exports = { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
import jwt from 'jsonwebtoken'; | ||
import time from './timeLib'; | ||
|
||
const { JWT_SECRET } = process.env; | ||
const JWT_SECRET = 'zF9?nCmaZH&?fF9'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is absolutely wrong. |
||
|
||
const createAuthToken = (userId) => { | ||
const jwtTokenObject = { | ||
|
@@ -18,8 +18,23 @@ const verifyAuthToken = (authToken) => new Promise((resolve, reject) => { | |
resolve(decoded); | ||
}); | ||
}); | ||
|
||
const createGenericAuthToken = (body) => { | ||
const jwtTokenObject = { | ||
...body, | ||
iat: time.now(), | ||
}; | ||
const jwtToken = jwt.sign(jwtTokenObject, JWT_SECRET, { expiresIn: 3600 }); | ||
return jwtToken; | ||
}; | ||
const decodeGenericAuthToken = (authToken) => new Promise((resolve, reject) => { | ||
jwt.verify(authToken, JWT_SECRET, (err, decoded) => { | ||
if (err) reject(err); | ||
resolve(decoded); | ||
}); | ||
}); | ||
module.exports = { | ||
createAuthToken, | ||
verifyAuthToken, | ||
createGenericAuthToken, | ||
decodeGenericAuthToken, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import request from 'request'; | ||
import eventEmitter from './eventsLib'; | ||
import AuthorizedApps from '../models/AuthorizedApps'; | ||
|
||
eventEmitter.on('Github:Authorize', async (payload) => { | ||
// eslint-disable-next-line camelcase | ||
const { state, installation_id, code } = payload; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can have camelcase using |
||
const options = { | ||
url: 'https://github.com/login/oauth/access_token', | ||
method: 'POST', | ||
headers: { Accept: 'application/json' }, | ||
json: { | ||
code, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. put some line breaks please |
||
client_id: process.env.GITHUB_CLIENT_ID, | ||
client_secret: process.env.GITHUB_CLIENT_SECRET, | ||
}, | ||
}; | ||
request(options, async (err, response, body) => { | ||
const authorizedApp = await AuthorizedApps.findOne({ authAppId: state.authAppId }); | ||
const credentials = [{ | ||
attributeName: 'access_token', | ||
attributeValue: body.access_token, | ||
}, { | ||
attributeName: 'token_type', | ||
attributeValue: body.token_type, | ||
}, { | ||
attributeName: 'installation_id', | ||
attributeValue: installation_id, | ||
}]; | ||
authorizedApp.credentials = credentials; | ||
await authorizedApp.save(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,13 @@ | ||
import mongoose, { Schema } from 'mongoose'; | ||
import shortid from 'shortid'; | ||
|
||
const AttributeObject = new Schema( | ||
{ | ||
attributeName: String, | ||
attributeValue: String, | ||
}, { _id: false }, | ||
); | ||
|
||
const AuthorizedApps = new Schema({ | ||
userId: { type: String }, // required:true | ||
userId: { type: String, required: true }, | ||
authAppId: { type: String, default: shortid.generate, unique: true }, | ||
appName: { type: String, required: true }, | ||
credentials: [AttributeObject], | ||
version: { type: String, default: '' }, | ||
email: { type: String }, // required: true | ||
auth_token: { type: String }, | ||
credentials: { type: Map }, | ||
}); | ||
|
||
export default mongoose.model('AuthorizedApps', AuthorizedApps); |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you need a view engine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, as we are serving our OAuth pages from the backend server. Also, the authorization callbacks are directly handled by our backend. :)