Skip to content

Commit

Permalink
fix typeform webhook parsing
Browse files Browse the repository at this point in the history
In the case when there are some missing answers.
  • Loading branch information
ianic committed Nov 29, 2021
1 parent b0485b6 commit 196c002
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 3 deletions.
1 change: 1 addition & 0 deletions domain/signup/signup.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type RegisterRecord struct {
Position string
OrganizationSize string
Raw []byte // raw http request
Survey map[string]string
}

const (
Expand Down
87 changes: 87 additions & 0 deletions domain/signup/testdata/typeform_our_3_responses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"event_id": "01FN976JJT0J52KJZ5VWF0TXH7",
"event_type": "form_response",
"form_response": {
"form_id": "QU5wd7lQ",
"token": "mttbdnpit3v2xzvp4tklmttbdn9z64qg",
"submitted_at": "2021-11-24T14:57:07Z",
"landed_at": "2021-11-24T14:56:38Z",
"calculated": {
"score": 0
},
"variables": null,
"definition": {
"id": "QU5wd7lQ",
"title": "Beta Signup Form v1",
"fields": [
{
"id": "35xdSkzCv9q9",
"title": "First things first, what is your name?",
"type": "short_text",
"ref": "20becb5a0780be8f",
"allow_multiple_selections": false,
"allow_other_choice": false
},
{
"id": "2nNeu7xbsemx",
"title": "And your email address?",
"type": "email",
"ref": "770c0575b77b1cb8",
"allow_multiple_selections": false,
"allow_other_choice": false
},
{
"id": "9jdxqysanTG9",
"title": "Lastly, how big is your development organisation?",
"type": "multiple_choice",
"ref": "7bed2f42-f42d-4afe-9854-f9fbb932e5b4",
"allow_multiple_selections": false,
"allow_other_choice": false
}
]
},
"answers": [
{
"type": "text",
"text": "Ana",
"field": {
"id": "35xdSkzCv9q9",
"type": "short_text"
},
"choices": {
"labels": null
},
"choice": {
"label": ""
}
},
{
"type": "email",
"field": {
"id": "2nNeu7xbsemx",
"type": "email"
},
"email": "[email protected]",
"choices": {
"labels": null
},
"choice": {
"label": ""
}
},
{
"type": "choice",
"field": {
"id": "9jdxqysanTG9",
"type": "multiple_choice"
},
"choices": {
"labels": null
},
"choice": {
"label": "2-10"
}
}
]
}
}
27 changes: 24 additions & 3 deletions domain/signup/typeform.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,15 @@ func (r *TypeformWebhook) AsRecord(ip string, raw []byte) RegisterRecord {
return RegisterRecord{
ActivationCode: id,
Email: email,
Name: r.Answer(0),
Position: r.Answer(2),
OrganizationSize: r.Answer(3),
Name: r.AnswerByID("35xdSkzCv9q9"),
Position: r.AnswerByID("C4PHTxIvSRYg"),
OrganizationSize: r.AnswerByID("9jdxqysanTG9"),
Developer: isDeveloper(email),
CreatedAt: time.Now().UnixMilli(),
RemoteIP: ip,
Raw: raw,
Source: SourceTypeform,
Survey: r.Survey(),
}
}

Expand All @@ -101,6 +102,26 @@ func (t TypeformWebhook) Answer(no int) string {
if a.Choice.Label != "" {
return a.Choice.Label
}
if a.Email != "" {
return a.Email
}
}
return ""
}

func (t TypeformWebhook) AnswerByID(id string) string {
for no, a := range t.FormResponse.Answers {
if a.Field.ID == id {
return t.Answer(no)
}
}
return ""
}

func (t TypeformWebhook) Survey() map[string]string {
m := make(map[string]string)
for _, q := range t.FormResponse.Definition.Fields {
m[q.Title] = t.AnswerByID(q.ID)
}
return m
}
43 changes: 43 additions & 0 deletions domain/signup/typeform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,46 @@ func TestTypeformWithOurSignupFormPayload(t *testing.T) {
require.True(t, rec.CreatedAt > 0)
require.Len(t, rec.ActivationCode, 22)
}

func TestTypeformOur3Responses(t *testing.T) {
buf, err := ioutil.ReadFile("testdata/typeform_our_3_responses.json")
require.NoError(t, err)
var tf TypeformWebhook
err = json.Unmarshal(buf, &tf)
require.NoError(t, err)

//fmt.Printf("answers map: %+v\n", tf.AnswersMap())

m := tf.Survey()
require.Len(t, m, 3)

require.Equal(t, "[email protected]", tf.Email())
rec := tf.AsRecord("", nil)
require.Equal(t, "Ana", rec.Name)
require.Equal(t, "[email protected]", rec.Email)
require.Equal(t, "", rec.Position)
require.Equal(t, "2-10", rec.OrganizationSize)
}

// func TestBugReport(t *testing.T) {
// var suspiciousRequest = `eyJ2ZXJzaW9uIjoiMS4wIiwicmVzb3VyY2UiOiIvc2lnbnVwL3twcm94eSt9IiwicGF0aCI6InR5cGVmb3JtIiwiaHR0cE1ldGhvZCI6IlBPU1QiLCJoZWFkZXJzIjp7IkNvbnRlbnQtTGVuZ3RoIjoiMTMwNiIsIkNvbnRlbnQtVHlwZSI6ImFwcGxpY2F0aW9uL2pzb24iLCJIb3N0IjoieXRnNWdma2c1ay5leGVjdXRlLWFwaS5ldS1jZW50cmFsLTEuYW1hem9uYXdzLmNvbSIsIlVzZXItQWdlbnQiOiJUeXBlZm9ybSBXZWJob29rcyIsIlgtQW16bi1UcmFjZS1JZCI6IlJvb3Q9MS02MTllNTJjMy0zZjEyMjQ2MTdiYmFjNmZiMDlhMjA3YWEiLCJYLUZvcndhcmRlZC1Gb3IiOiIzNS4xNjkuMTUxLjgxIiwiWC1Gb3J3YXJkZWQtUG9ydCI6IjQ0MyIsIlgtRm9yd2FyZGVkLVByb3RvIjoiaHR0cHMiLCJhY2NlcHQtZW5jb2RpbmciOiJnemlwIn0sIm11bHRpVmFsdWVIZWFkZXJzIjp7IkNvbnRlbnQtTGVuZ3RoIjpbIjEzMDYiXSwiQ29udGVudC1UeXBlIjpbImFwcGxpY2F0aW9uL2pzb24iXSwiSG9zdCI6WyJ5dGc1Z2ZrZzVrLmV4ZWN1dGUtYXBpLmV1LWNlbnRyYWwtMS5hbWF6b25hd3MuY29tIl0sIlVzZXItQWdlbnQiOlsiVHlwZWZvcm0gV2ViaG9va3MiXSwiWC1BbXpuLVRyYWNlLUlkIjpbIlJvb3Q9MS02MTllNTJjMy0zZjEyMjQ2MTdiYmFjNmZiMDlhMjA3YWEiXSwiWC1Gb3J3YXJkZWQtRm9yIjpbIjM1LjE2OS4xNTEuODEiXSwiWC1Gb3J3YXJkZWQtUG9ydCI6WyI0NDMiXSwiWC1Gb3J3YXJkZWQtUHJvdG8iOlsiaHR0cHMiXSwiYWNjZXB0LWVuY29kaW5nIjpbImd6aXAiXX0sInF1ZXJ5U3RyaW5nUGFyYW1ldGVycyI6bnVsbCwibXVsdGlWYWx1ZVF1ZXJ5U3RyaW5nUGFyYW1ldGVycyI6bnVsbCwicmVxdWVzdENvbnRleHQiOnsiYWNjb3VudElkIjoiNDc3MzYxODc3NDQ1IiwiYXBpSWQiOiJ5dGc1Z2ZrZzVrIiwiZG9tYWluTmFtZSI6Inl0ZzVnZmtnNWsuZXhlY3V0ZS1hcGkuZXUtY2VudHJhbC0xLmFtYXpvbmF3cy5jb20iLCJkb21haW5QcmVmaXgiOiJ5dGc1Z2ZrZzVrIiwiZXh0ZW5kZWRSZXF1ZXN0SWQiOiJKVUhlbWlOWEZpQUVKeUE9IiwiaHR0cE1ldGhvZCI6IlBPU1QiLCJpZGVudGl0eSI6eyJhY2Nlc3NLZXkiOm51bGwsImFjY291bnRJZCI6bnVsbCwiY2FsbGVyIjpudWxsLCJjb2duaXRvQW1yIjpudWxsLCJjb2duaXRvQXV0aGVudGljYXRpb25Qcm92aWRlciI6bnVsbCwiY29nbml0b0F1dGhlbnRpY2F0aW9uVHlwZSI6bnVsbCwiY29nbml0b0lkZW50aXR5SWQiOm51bGwsImNvZ25pdG9JZGVudGl0eVBvb2xJZCI6bnVsbCwicHJpbmNpcGFsT3JnSWQiOm51bGwsInNvdXJjZUlwIjoiMzUuMTY5LjE1MS44MSIsInVzZXIiOm51bGwsInVzZXJBZ2VudCI6IlR5cGVmb3JtIFdlYmhvb2tzIiwidXNlckFybiI6bnVsbH0sInBhdGgiOiJ0eXBlZm9ybSIsInByb3RvY29sIjoiSFRUUC8xLjEiLCJyZXF1ZXN0SWQiOiJKVUhlbWlOWEZpQUVKeUE9IiwicmVxdWVzdFRpbWUiOiIyNC9Ob3YvMjAyMToxNDo1NzowNyArMDAwMCIsInJlcXVlc3RUaW1lRXBvY2giOjE2Mzc3NjU4Mjc2NDUsInJlc291cmNlSWQiOiJQT1NUIC9zaWdudXAve3Byb3h5K30iLCJyZXNvdXJjZVBhdGgiOiIvc2lnbnVwL3twcm94eSt9Iiwic3RhZ2UiOiIkZGVmYXVsdCJ9LCJwYXRoUGFyYW1ldGVycyI6eyJwcm94eSI6InR5cGVmb3JtIn0sInN0YWdlVmFyaWFibGVzIjpudWxsLCJib2R5Ijoie1wiZXZlbnRfaWRcIjpcIjAxRk45NzZKSlQwSjUyS0paNVZXRjBUWEg3XCIsXCJldmVudF90eXBlXCI6XCJmb3JtX3Jlc3BvbnNlXCIsXCJmb3JtX3Jlc3BvbnNlXCI6e1wiZm9ybV9pZFwiOlwiUVU1d2Q3bFFcIixcInRva2VuXCI6XCJtdHRiZG5waXQzdjJ4enZwNHRrbG10dGJkbjl6NjRxZ1wiLFwibGFuZGVkX2F0XCI6XCIyMDIxLTExLTI0VDE0OjU2OjM4WlwiLFwic3VibWl0dGVkX2F0XCI6XCIyMDIxLTExLTI0VDE0OjU3OjA3WlwiLFwiaGlkZGVuXCI6e1wic291cmNlXCI6XCJcIn0sXCJkZWZpbml0aW9uXCI6e1wiaWRcIjpcIlFVNXdkN2xRXCIsXCJ0aXRsZVwiOlwiQmV0YSBTaWdudXAgRm9ybSB2MVwiLFwiZmllbGRzXCI6W3tcImlkXCI6XCIzNXhkU2t6Q3Y5cTlcIixcInRpdGxlXCI6XCJGaXJzdCB0aGluZ3MgZmlyc3QsIHdoYXQgaXMgeW91ciBuYW1lP1wiLFwidHlwZVwiOlwic2hvcnRfdGV4dFwiLFwicmVmXCI6XCIyMGJlY2I1YTA3ODBiZThmXCIsXCJwcm9wZXJ0aWVzXCI6e319LHtcImlkXCI6XCIybk5ldTd4YnNlbXhcIixcInRpdGxlXCI6XCJBbmQgeW91ciBlbWFpbCBhZGRyZXNzP1wiLFwidHlwZVwiOlwiZW1haWxcIixcInJlZlwiOlwiNzcwYzA1NzViNzdiMWNiOFwiLFwicHJvcGVydGllc1wiOnt9fSx7XCJpZFwiOlwiOWpkeHF5c2FuVEc5XCIsXCJ0aXRsZVwiOlwiTGFzdGx5LCBob3cgYmlnIGlzIHlvdXIgZGV2ZWxvcG1lbnQgb3JnYW5pc2F0aW9uP1wiLFwidHlwZVwiOlwibXVsdGlwbGVfY2hvaWNlXCIsXCJyZWZcIjpcIjdiZWQyZjQyLWY0MmQtNGFmZS05ODU0LWY5ZmJiOTMyZTViNFwiLFwicHJvcGVydGllc1wiOnt9LFwiY2hvaWNlc1wiOlt7XCJpZFwiOlwiUzFsS1JBbW1ZUm9qXCIsXCJsYWJlbFwiOlwiSnVzdCBtZVwifSx7XCJpZFwiOlwiMDVQSUNGcVVId2xkXCIsXCJsYWJlbFwiOlwiMi0xMFwifSx7XCJpZFwiOlwiNlJjbW9JSWpIbTNLXCIsXCJsYWJlbFwiOlwiMTEtMzBcIn0se1wiaWRcIjpcIm50NlE1ZzNzVGlNcFwiLFwibGFiZWxcIjpcIjMxLTcwXCJ9LHtcImlkXCI6XCIya0dFb3ZIR0lsSDNcIixcImxhYmVsXCI6XCI3MStcIn1dfV19LFwiYW5zd2Vyc1wiOlt7XCJ0eXBlXCI6XCJ0ZXh0XCIsXCJ0ZXh0XCI6XCJBbmFcIixcImZpZWxkXCI6e1wiaWRcIjpcIjM1eGRTa3pDdjlxOVwiLFwidHlwZVwiOlwic2hvcnRfdGV4dFwiLFwicmVmXCI6XCIyMGJlY2I1YTA3ODBiZThmXCJ9fSx7XCJ0eXBlXCI6XCJlbWFpbFwiLFwiZW1haWxcIjpcImFuYUBtYW50aWwuY29tXCIsXCJmaWVsZFwiOntcImlkXCI6XCIybk5ldTd4YnNlbXhcIixcInR5cGVcIjpcImVtYWlsXCIsXCJyZWZcIjpcIjc3MGMwNTc1Yjc3YjFjYjhcIn19LHtcInR5cGVcIjpcImNob2ljZVwiLFwiY2hvaWNlXCI6e1wibGFiZWxcIjpcIjItMTBcIn0sXCJmaWVsZFwiOntcImlkXCI6XCI5amR4cXlzYW5URzlcIixcInR5cGVcIjpcIm11bHRpcGxlX2Nob2ljZVwiLFwicmVmXCI6XCI3YmVkMmY0Mi1mNDJkLTRhZmUtOTg1NC1mOWZiYjkzMmU1YjRcIn19XX19XG4iLCJpc0Jhc2U2NEVuY29kZWQiOmZhbHNlfQ==`
// dst := make([]byte, base64.StdEncoding.DecodedLen(len(suspiciousRequest)))
// _, err := base64.StdEncoding.Decode(dst, []byte(suspiciousRequest))
// require.NoError(t, err)

// dst = bytes.Trim(dst, "\x00")
// //fmt.Printf("%v", dst)
// var req events.APIGatewayProxyRequest
// err = json.Unmarshal(dst, &req)
// require.NoError(t, err)

// var tw TypeformWebhook
// err = json.Unmarshal([]byte(req.Body), &tw)
// require.NoError(t, err)

// pp, _ := json.MarshalIndent(tw, "", " ")
// fmt.Printf("%s \n", pp)

// t.Logf("%#v", tw.AsRecord("", nil))

// }

0 comments on commit 196c002

Please sign in to comment.