Skip to content

Commit

Permalink
feat(tracking): wogaa tracking (#7123)
Browse files Browse the repository at this point in the history
* feat: add wogaa controller

* feat: add tracking to view, feedback, submit

* feat: add wogaa config

* feat: add pageUrl to wogaa submit

* chore: clean up

* chore: add logs
  • Loading branch information
KenLSM authored Mar 6, 2024
1 parent 0a96b28 commit 241ed33
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 1 deletion.
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ services:
- GROWTHBOOK_CLIENT_KEY
# env vars for virus scanner
- VIRUS_SCANNER_LAMBDA_FUNCTION_NAME=function
- WOGAA_SECRET_KEY
- WOGAA_START_ENDPOINT
- WOGAA_SUBMIT_ENDPOINT
- WOGAA_FEEDBACK_ENDPOINT


mockpass:
build: https://github.com/opengovsg/mockpass.git#v4.0.4
Expand Down
39 changes: 39 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@
"uid-generator": "^2.0.0",
"ulid": "^2.3.0",
"uuid": "^9.0.0",
"uuid-by-string": "^4.0.0",
"validator": "^13.7.0",
"web-streams-polyfill": "^3.2.1",
"whatwg-fetch": "^3.6.2",
Expand Down
39 changes: 39 additions & 0 deletions src/app/config/features/wogaa.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import convict, { Schema } from 'convict'

export interface IWogaa {
wogaaSecretKey: string
wogaaStartEndpoint: string
wogaaSubmitEndpoint: string
wogaaFeedbackEndpoint: string
}

const wogaaSchema: Schema<IWogaa> = {
wogaaSecretKey: {
doc: 'Wogaa shared secret key',
format: String,
default: '',
env: 'WOGAA_SECRET_KEY',
},
wogaaStartEndpoint: {
doc: 'Wogaa endpoint when a form is loaded',
format: String,
default: '',
env: 'WOGAA_START_ENDPOINT',
},
wogaaSubmitEndpoint: {
doc: 'Wogaa endpoint when a form is loaded',
format: String,
default: '',
env: 'WOGAA_SUBMIT_ENDPOINT',
},
wogaaFeedbackEndpoint: {
doc: 'Wogaa endpoint when a form is loaded',
format: String,
default: '',
env: 'WOGAA_FEEDBACK_ENDPOINT',
},
}

export const wogaaConfig = convict(wogaaSchema)
.validate({ allowed: 'strict' })
.getProperties()
160 changes: 160 additions & 0 deletions src/app/modules/wogaa/wogaa.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import Axios from 'axios'
import * as crypto from 'crypto'
import uuidGen from 'uuid-by-string'

import { wogaaConfig } from '../../config/features/wogaa'
import { createLoggerWithLabel } from '../../config/logger'
import { ControllerHandler } from '../core/core.types'

const logger = createLoggerWithLabel(module)
const generateSignature = (payload: Record<string, unknown>) => {
const signature = crypto
.createHmac('sha256', wogaaConfig.wogaaSecretKey)
.update(JSON.stringify(payload))
.digest('hex')
return signature
}

const isConfigValid = () => {
if (!wogaaConfig.wogaaSecretKey) {
return false
}
if (!wogaaConfig.wogaaStartEndpoint) {
return false
}
if (!wogaaConfig.wogaaSubmitEndpoint) {
return false
}
if (!wogaaConfig.wogaaFeedbackEndpoint) {
return false
}

return true
}

export const handleSubmit: ControllerHandler<{ formId: string }> = async (
req,
_,
next,
) => {
const { formId } = req.params

if (!req.sessionID || !formId || !isConfigValid()) {
return next()
}

const logMeta = {
action: 'wogaaHandleSubmit',
formId,
}

const payload = {
formSgId: formId,
transactionId: uuidGen(req.sessionID),
}
// fire and forget
void Axios.post(wogaaConfig.wogaaSubmitEndpoint, payload, {
headers: {
'WOGAA-Signature': generateSignature(payload),
},
})
.then(() => {
logger.info({
message: 'Successfully sent WOGAA submit endpoint',
meta: logMeta,
})
})
.catch((e) => {
logger.warn({
message: 'Error sending to WOGAA submit endpoint',
meta: { ...logMeta, wogaaRespError: e },
})
})

return next()
}

export const handleFormView: ControllerHandler<{ formId: string }> = async (
req,
_,
next,
) => {
const { formId } = req.params

if (!req.sessionID || !formId || !isConfigValid()) {
return next()
}

const logMeta = {
action: 'wogaaHandleFormView',
formId,
}
const payload = {
formSgId: formId,
pageUrl: formId,
transactionId: uuidGen(req.sessionID),
}
void Axios.post(wogaaConfig.wogaaStartEndpoint, payload, {
headers: {
'WOGAA-Signature': generateSignature(payload),
},
})
.then(() => {
logger.info({
message: 'Successfully sent WOGAA load form endpoint',
meta: logMeta,
})
})
.catch((e) => {
logger.warn({
message: 'Error sending to WOGAA load form endpoint',
meta: { ...logMeta, wogaaRespError: e },
})
})

return next()
}

export const handleFormFeedback: ControllerHandler<
{ formId: string },
unknown,
{ rating: number; comment: string }
> = async (req, _, next) => {
const { formId } = req.params
const { rating, comment } = req.body

if (!req.sessionID || !formId || !isConfigValid()) {
return next()
}

const logMeta = {
action: 'wogaaHandleFormFeedback',
formId,
}
const payload = {
formSgId: formId,
transactionId: uuidGen(req.sessionID),
rating,
comment,
}

void Axios.post(wogaaConfig.wogaaFeedbackEndpoint, payload, {
headers: {
'WOGAA-Signature': generateSignature(payload),
},
})
.then(() => {
logger.info({
message: 'Successfully sent WOGAA form feedback endpoint',
meta: logMeta,
})
})
.catch((e) => {
logger.warn({
message: 'Error sending to WOGAA form feedback endpoint',
meta: { ...logMeta, wogaaRespError: e },
})
})

return next()
}
6 changes: 5 additions & 1 deletion src/app/routes/api/v3/forms/public-forms.feedback.routes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Router } from 'express'

import * as FeedbackController from '../../../../modules/feedback/feedback.controller'
import * as WogaaController from '../../../../modules/wogaa/wogaa.controller'

export const PublicFormsFeedbackRouter = Router()

Expand All @@ -22,4 +23,7 @@ export const PublicFormsFeedbackRouter = Router()
*/
PublicFormsFeedbackRouter.route(
'/:formId([a-fA-F0-9]{24})/submissions/:submissionId([a-fA-F0-9]{24})/feedback',
).post(FeedbackController.handleSubmitFormFeedback)
).post(
WogaaController.handleFormFeedback,
FeedbackController.handleSubmitFormFeedback,
)
2 changes: 2 additions & 0 deletions src/app/routes/api/v3/forms/public-forms.form.routes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Router } from 'express'

import * as PublicFormController from '../../../../modules/form/public-form/public-form.controller'
import * as WogaaController from '../../../../modules/wogaa/wogaa.controller'

export const PublicFormsFormRouter = Router()

Expand All @@ -19,6 +20,7 @@ export const PublicFormsFormRouter = Router()
* @returns 500 when database error occurs
*/
PublicFormsFormRouter.route('/:formId([a-fA-F0-9]{24})').get(
WogaaController.handleFormView,
PublicFormController.handleGetPublicForm,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as EmailSubmissionController from '../../../../modules/submission/email
import * as EncryptSubmissionController from '../../../../modules/submission/encrypt-submission/encrypt-submission.controller'
import * as MultirespondentSubmissionController from '../../../../modules/submission/multirespondent-submission/multirespondent-submission.controller'
import * as SubmissionController from '../../../../modules/submission/submission.controller'
import * as WogaaController from '../../../../modules/wogaa/wogaa.controller'
import { limitRate } from '../../../../utils/limit-rate'

export const PublicFormsSubmissionsRouter = Router()
Expand All @@ -29,6 +30,7 @@ PublicFormsSubmissionsRouter.route(
'/:formId([a-fA-F0-9]{24})/submissions/email',
).post(
limitRate({ max: rateLimitConfig.submissions }),
WogaaController.handleSubmit,
EmailSubmissionController.handleEmailSubmission,
)

Expand All @@ -45,6 +47,7 @@ PublicFormsSubmissionsRouter.route(
'/:formId([a-fA-F0-9]{24})/submissions/storage',
).post(
limitRate({ max: rateLimitConfig.submissions }),
WogaaController.handleSubmit,
EncryptSubmissionController.handleStorageSubmission,
)

Expand All @@ -61,6 +64,7 @@ PublicFormsSubmissionsRouter.route(
'/:formId([a-fA-F0-9]{24})/submissions/multirespondent',
).post(
limitRate({ max: rateLimitConfig.submissions }),
WogaaController.handleSubmit,
MultirespondentSubmissionController.handleMultirespondentSubmission,
)

Expand Down

0 comments on commit 241ed33

Please sign in to comment.