1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
# Forms Schema
Since MongoDB has no set schema, we document it here to document what our objects should look like. If you add new properties or remove them from objects **make sure to update them here**.
In this document:
- [Form](#form)
- [Form features](#form-features)
- [Form question](#form-question)
- [Form response](#form-response)
- [User details object](#user-details-object)
- [Anti-spam object](#anti-spam-object)
## Form
| Field | Type | Description | Example |
|--------------------|------------------------------------------|------------------------------------------------------------------------------------------------------------------|------------------------------------------------|
| `id` | Unique identifier | A user selected, unique, descriptive identifier (used in URL routes, so no spaces) | `"ban-appeals"` |
| `features` | List of [form features](#form-features) | A list of features to change the behaviour of the form, described in the features section | `["OPEN", "COLLECT_EMAIL"]` |
| `questions` | List of [form questions](#form-question) | The list of questions to render on a specific form | Too long! See below |
| `name` | String | Name of the form | `"Summer Code Jam 2100"` |
| `description` | String | Form description | `"This is my amazing form description."` |
| `webhook` | [Webhook object](#webhooks) | An optional discord webhook. | See webhook documentation. |
| `submitted_text` | Optional[String] | An optional string for the response upon submitting. | `"This is my amazing form response."` |
| `discord_role` | String (optional) | Discord role ID what will be assigned, required when `ASSIGN_ROLE` flag provided. | `784467518298259466` |
| `response_readers` | List[String] | Discord roles which can view the responses of the form. Can not be the everyone role. | `["267629731250176001", "825337057181696020"]` |
| `editors` | List[String] | Discord roles which have permission to edit, delete, or otherwise modify the form. Can not be the everyone role. | `["409416496733880320"]` |
### Form features
| Flag | Description |
|--------------------|-------------------------------------------------------------------------------|
| `DISCOVERABLE` | The form should be displayed on the homepage of the forms application. |
| `REQUIRES_LOGIN` | Requires the user to authenticate with Discord before completing the form. |
| `OPEN` | The form is currently accepting responses. |
| `COLLECT_EMAIL` | The form should collect the email from submissions. Requires `REQUIRES_LOGIN` |
| `DISABLE_ANTISPAM` | Disable the anti-spam checks from running on a form submission. |
| `WEBHOOK_ENABLED` | The form should notify the webhook. Has no effect if no webhook is set. |
| `ASSIGN_ROLE` | The form should assign role to user. Requires `REQUIRES_LOGIN`. |
### Webhooks
Discord webhooks to send information upon form submission.
| Field | Type | Description |
|-------------|--------|-------------------------------------------------------------------------------------------------------------|
| `url` | String | Discord webhook URL. |
| `message` | String | An optional message to include before the embed. Can use certain [context variables](#webhook-variables). |
| `thread_id` | String | An optional thread ID to post the webhook into. If not provided, the webhook will be posted in the channel. |
#### Webhook Variables
The following variables can be used in a webhook's message. The variables must be wrapped by braces (`{}`).
| Name | Description |
|---------------|------------------------------------------------------------------------------|
| `user` | A discord mention of the user submitting the form, or "User" if unavailable. |
| `response_id` | ID of the submitted response. |
| `form` | Name of the submitted form. |
| `form_id` | ID of the submitted form. |
| `time` | ISO submission timestamp. |
### Form question
| Field | Type | Description | Example |
|------------|------------------------------------------|--------------------------------------------------|----------------------|
| `id` | string | Unique identifier of the question | `"aabbcc"` |
| `name` | string | Name of the question | `"What's the time?"` |
| `type` | one of [Question types](#question-types) | The type of input for this question | `"radio"` |
| `data` | [Question specific data](#question-data) | Any specific data for the question type selected | Documented below |
| `required` | Boolean | Indicates whether the field must be filled | `True` |
#### Question types
| Name | Description |
|--------------|-------------------------------------------------------------------|
| `radio` | Radio buttons |
| `checkbox` | Checkbox toggle |
| `select` | Dropdown list |
| `short_text` | One line input field |
| `textarea` | Long text input |
| `code` | Syntax highlighted code input |
| `range` | Horizontal drag slider |
| `section` | Not an input, just a section of text to explain something |
| `timezone` | Similar to select, attempts to automatically detect user timezone |
#### Question data
Different questions require different input data to render. All data is in an object with keys and values as defined in the below tables. **All fields are required unless stated otherwise**.
##### `radio`
```js
{
// Option list for radio buttons
"options": [
"Spam",
"Eggs",
"Ham"
]
}
```
##### `checkbox`
Checkboxes require no additional configuration
##### `select`
```js
{
// Option list for select dropdown
"options": [
"United Kingdom",
"United States"
]
}
```
##### `short_text`
Short text fields require no additional configuration.
##### `textarea`
Textareas require no additional configuration.
##### `code`
```js
{
// A supported language from https://prismjs.com/#supported-languages
"language": "python",
// An optinal mapping of unit tests
"unittests": {
// Record a submission, even if the tests don't pass
// Default: false
"allow_failure": false,
"tests": {
"unit_1": "unit_code()",
...
}
}
}
```
##### `range`
```js
{
// A list of options to put on the range, from left to right
"options": [
"Not at all",
"Not much",
"A little",
"A lot"
]
}
```
##### `section`
```js
{
// REQUIRED: Additional text to place below the section header
"text": "This section will quiz you on A, B and C"
// OPTIONAL: Alignment of the section text (default: center, other options: left)
"align": "center"
}
```
##### `timezone`
Timezones require no additional options, they will automatically attempt to
select the users timezone, or allow the user to select one if it is detected
wrong/could not be detected.
## Form response
| Field | Type | Description |
|-------------|------------------------------------------------------|-----------------------------------------------------------------------------|
| `_id`/`id` | MongoDB ObjectID | Random identifier used for the response |
| `user` | Optional [user details object](#user-details-object) | An object describing the user that submitted if the form is not anonymous |
| `antispam` | Optional [anti spam object](#anti-spam-object) | An object containing information about the anti-spam on the form submission |
| `response` | Object | Object containing question IDs mapping to the users answer* |
| `form_id` | String | ID of the form that the user is submitting to |
| `timestamp` | String | ISO formatted string of submission time. |
* If the question is of type `code`, the response has the following structure:
```json
"response": {
"<QUESTION ID>": {
"value": "<USER CODE>",
"passed": bool,
"failures": ["<TEST NAME 1>", "<TEST NAME 4>", "<HIDDEN TEST 1>", ...]
},
...
}
```
* Values in `<>` are placeholders, while the rest are actual keys
* `passed` is True only if all tests in the suite passed.
### User details object
The user details contains the information returned by Discord alongside an `admin` boolean key representing that the user has admin privileges. The information returned from Discord can be found in the [Discord Developer portal](https://discord.com/developers/docs/resources/user#user-object).
### Anti-spam object
The anti-spam object contains information about the source of the form submission.
| Field | Type | Description |
|-------------------|---------|-------------------------------------------------|
| `ip_hash` | String | hash of the submitting users IP address |
| `user_agent_hash` | String | hash of the submitting users user agent |
| `captcha_pass` | Boolean | Whether the user passsed the hCaptcha |
| `dns_blacklisted` | Boolean | Whether the submitting IP is on a DNS blacklist |
|