@common-grants/core 0.2.2 → 0.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api.tsp +17 -1
- package/lib/core/fields/file.tsp +20 -0
- package/lib/core/models/application.tsp +99 -0
- package/lib/core/models/competition.tsp +1 -1
- package/lib/core/models/form.tsp +10 -1
- package/lib/core/routes/applications.tsp +16 -0
- package/lib/core/routes/forms.tsp +4 -2
- package/lib/main.tsp +1 -0
- package/package.json +1 -1
package/lib/api.tsp
CHANGED
|
@@ -31,9 +31,17 @@ using Versioning;
|
|
|
31
31
|
}
|
|
32
32
|
)
|
|
33
33
|
@tagMetadata("Forms", #{ description: "Endpoints related to forms" })
|
|
34
|
+
@tagMetadata(
|
|
35
|
+
"Application Reviews",
|
|
36
|
+
#{
|
|
37
|
+
description: "Endpoints related to reviewing applications for a given competition",
|
|
38
|
+
}
|
|
39
|
+
)
|
|
34
40
|
@tagMetadata(
|
|
35
41
|
"Applications",
|
|
36
|
-
#{
|
|
42
|
+
#{
|
|
43
|
+
description: "Endpoints related to submitting applications for a given competition",
|
|
44
|
+
}
|
|
37
45
|
)
|
|
38
46
|
@tagMetadata(
|
|
39
47
|
"Competitions",
|
|
@@ -122,6 +130,14 @@ namespace Applications {
|
|
|
122
130
|
|
|
123
131
|
@added(Versions.v0_2)
|
|
124
132
|
op submitApplication is ApplicationRouter.submitApplication;
|
|
133
|
+
|
|
134
|
+
// ################################
|
|
135
|
+
// Search applications
|
|
136
|
+
// ################################
|
|
137
|
+
|
|
138
|
+
@added(Versions.v0_3)
|
|
139
|
+
@tag("Application Reviews")
|
|
140
|
+
op searchApplications is ApplicationRouter.searchApplications;
|
|
125
141
|
}
|
|
126
142
|
|
|
127
143
|
// #########################################################
|
package/lib/core/fields/file.tsp
CHANGED
|
@@ -47,4 +47,24 @@ namespace Examples.File {
|
|
|
47
47
|
createdAt: utcDateTime.fromISO("2025-01-01T17:01:01"),
|
|
48
48
|
lastModifiedAt: utcDateTime.fromISO("2025-01-02T17:30:00"),
|
|
49
49
|
};
|
|
50
|
+
|
|
51
|
+
const excelFile = #{
|
|
52
|
+
downloadUrl: "https://example.com/excel.xlsx",
|
|
53
|
+
name: "excel.xlsx",
|
|
54
|
+
description: "The excel file for the application",
|
|
55
|
+
sizeInBytes: 1000,
|
|
56
|
+
mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
57
|
+
createdAt: utcDateTime.fromISO("2025-01-01T17:01:01"),
|
|
58
|
+
lastModifiedAt: utcDateTime.fromISO("2025-01-02T17:30:00"),
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const zipFile = #{
|
|
62
|
+
downloadUrl: "https://example.com/application.zip",
|
|
63
|
+
name: "application.zip",
|
|
64
|
+
description: "The zip file for the application",
|
|
65
|
+
sizeInBytes: 50000,
|
|
66
|
+
mimeType: "application/zip",
|
|
67
|
+
createdAt: utcDateTime.fromISO("2025-01-01T17:01:01"),
|
|
68
|
+
lastModifiedAt: utcDateTime.fromISO("2025-01-02T17:30:00"),
|
|
69
|
+
};
|
|
50
70
|
}
|
|
@@ -13,6 +13,10 @@ model ApplicationBase {
|
|
|
13
13
|
/** The unique identifier for the competition */
|
|
14
14
|
competitionId: Types.uuid;
|
|
15
15
|
|
|
16
|
+
/** The unique identifier for the opportunity being applied to */
|
|
17
|
+
@Versioning.added(CommonGrants.Versions.v0_3)
|
|
18
|
+
opportunityId: Types.uuid;
|
|
19
|
+
|
|
16
20
|
/** The form responses for the application */
|
|
17
21
|
formResponses: Record<AppFormResponse>;
|
|
18
22
|
|
|
@@ -84,6 +88,79 @@ model AppFormResponse {
|
|
|
84
88
|
...FormResponseBase;
|
|
85
89
|
}
|
|
86
90
|
|
|
91
|
+
// #########################################################
|
|
92
|
+
// AppFilters
|
|
93
|
+
// #########################################################
|
|
94
|
+
|
|
95
|
+
/** Filters to apply when searching for applications */
|
|
96
|
+
@Versioning.added(CommonGrants.Versions.v0_3)
|
|
97
|
+
model AppFilters {
|
|
98
|
+
/** The default filters to apply to the search */
|
|
99
|
+
...AppDefaultFilters;
|
|
100
|
+
|
|
101
|
+
/** Additional implementation-defined filters to apply to the search */
|
|
102
|
+
customFilters?: Record<Filters.DefaultFilter>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The standard set of filters supported for application searches */
|
|
106
|
+
@Versioning.added(CommonGrants.Versions.v0_3)
|
|
107
|
+
model AppDefaultFilters extends Record<Filters.DefaultFilter> {
|
|
108
|
+
/** `opportunityId` matches one of the following values */
|
|
109
|
+
@example(#{
|
|
110
|
+
operator: Filters.ArrayOperators.in,
|
|
111
|
+
value: #["ad3b469a-d89a-42d3-c439-6c1234567890"],
|
|
112
|
+
})
|
|
113
|
+
opportunityId?: Filters.StringArrayFilter;
|
|
114
|
+
|
|
115
|
+
/** `competitionId` matches one of the following values */
|
|
116
|
+
@example(#{
|
|
117
|
+
operator: Filters.ArrayOperators.in,
|
|
118
|
+
value: #["123e4567-e89b-12d3-a456-426614174000"],
|
|
119
|
+
})
|
|
120
|
+
competitionId?: Filters.StringArrayFilter;
|
|
121
|
+
|
|
122
|
+
/** `submittedAt` is between the given range */
|
|
123
|
+
@example(#{
|
|
124
|
+
operator: Filters.RangeOperators.between,
|
|
125
|
+
value: #{
|
|
126
|
+
min: Types.isoDate.fromISO("2025-01-01"),
|
|
127
|
+
max: Types.isoDate.fromISO("2025-01-30"),
|
|
128
|
+
},
|
|
129
|
+
})
|
|
130
|
+
submittedAtRange?: Filters.DateRangeFilter;
|
|
131
|
+
|
|
132
|
+
/** `status.value` matches one of the following values */
|
|
133
|
+
@example(#{
|
|
134
|
+
operator: Filters.ArrayOperators.in,
|
|
135
|
+
value: #["submitted", "accepted"],
|
|
136
|
+
})
|
|
137
|
+
status?: Filters.StringArrayFilter;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// #########################################################
|
|
141
|
+
// AppSorting
|
|
142
|
+
// #########################################################
|
|
143
|
+
|
|
144
|
+
/** The fields that can be used to sort applications */
|
|
145
|
+
@Versioning.added(CommonGrants.Versions.v0_3)
|
|
146
|
+
enum AppSortBy {
|
|
147
|
+
lastModifiedAt,
|
|
148
|
+
createdAt,
|
|
149
|
+
submittedAt,
|
|
150
|
+
status: "status.value",
|
|
151
|
+
opportunityId,
|
|
152
|
+
competitionId,
|
|
153
|
+
custom,
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Sorting parameters for applications */
|
|
157
|
+
@Versioning.added(CommonGrants.Versions.v0_3)
|
|
158
|
+
model AppSorting extends Sorting.SortBodyParams {
|
|
159
|
+
/** The field to sort by */
|
|
160
|
+
@example(AppSortBy.opportunityId)
|
|
161
|
+
sortBy: AppSortBy;
|
|
162
|
+
}
|
|
163
|
+
|
|
87
164
|
// #########################################################
|
|
88
165
|
// Examples
|
|
89
166
|
// #########################################################
|
|
@@ -110,14 +187,36 @@ namespace Examples.Application {
|
|
|
110
187
|
...Examples.FormResponse.formResponse,
|
|
111
188
|
};
|
|
112
189
|
|
|
190
|
+
const attachmentsCustomField = #{
|
|
191
|
+
name: "attachments",
|
|
192
|
+
fieldType: Fields.CustomFieldType.object,
|
|
193
|
+
value: #{
|
|
194
|
+
contacts: Fields.Examples.File.pdfFile,
|
|
195
|
+
budget: Fields.Examples.File.excelFile,
|
|
196
|
+
},
|
|
197
|
+
description: "The attachments for the application",
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const applicationZipFileCustomField = #{
|
|
201
|
+
name: "applicationZipFile",
|
|
202
|
+
fieldType: Fields.CustomFieldType.object,
|
|
203
|
+
value: Fields.Examples.File.zipFile,
|
|
204
|
+
description: "The zip file for the application",
|
|
205
|
+
};
|
|
206
|
+
|
|
113
207
|
const applicationBase = #{
|
|
114
208
|
id: "123e4567-e89b-12d3-a456-426614174000",
|
|
115
209
|
name: "My Application",
|
|
116
210
|
competitionId: "123e4567-e89b-12d3-a456-426614174000",
|
|
211
|
+
opportunityId: "ad3b469a-d89a-42d3-c439-6c1234567890",
|
|
117
212
|
formResponses: #{ formA: formResponse },
|
|
118
213
|
status: inProgressStatus,
|
|
119
214
|
submittedAt: null,
|
|
120
215
|
createdAt: utcDateTime.fromISO("2021-01-01T00:00:00Z"),
|
|
121
216
|
lastModifiedAt: utcDateTime.fromISO("2021-01-01T00:00:00Z"),
|
|
217
|
+
customFields: #{
|
|
218
|
+
attachments: attachmentsCustomField,
|
|
219
|
+
applicationZipFile: applicationZipFileCustomField,
|
|
220
|
+
},
|
|
122
221
|
};
|
|
123
222
|
}
|
|
@@ -83,7 +83,7 @@ enum CompetitionStatusOptions {
|
|
|
83
83
|
@example(Examples.Competition.forms)
|
|
84
84
|
model CompetitionForms {
|
|
85
85
|
/** The forms for the competition */
|
|
86
|
-
forms: Record<Models.
|
|
86
|
+
forms: Record<Models.FormBase>;
|
|
87
87
|
|
|
88
88
|
/** The validation rules for the competition forms */
|
|
89
89
|
validation?: Record<unknown>;
|
package/lib/core/models/form.tsp
CHANGED
|
@@ -9,7 +9,8 @@ namespace CommonGrants.Models;
|
|
|
9
9
|
/** A form for collecting data from a user. */
|
|
10
10
|
@example(Examples.Form.form)
|
|
11
11
|
@Versioning.added(CommonGrants.Versions.v0_2)
|
|
12
|
-
|
|
12
|
+
@Versioning.renamedFrom(CommonGrants.Versions.v0_3, "Form")
|
|
13
|
+
model FormBase {
|
|
13
14
|
/** The form's unique identifier. */
|
|
14
15
|
id: Types.uuid;
|
|
15
16
|
|
|
@@ -19,6 +20,9 @@ model Form {
|
|
|
19
20
|
/** The form's description. */
|
|
20
21
|
description?: string;
|
|
21
22
|
|
|
23
|
+
@Versioning.added(CommonGrants.Versions.v0_3)
|
|
24
|
+
version?: string;
|
|
25
|
+
|
|
22
26
|
/** The form's instructions. */
|
|
23
27
|
instructions?: string | Fields.File[];
|
|
24
28
|
|
|
@@ -36,6 +40,9 @@ model Form {
|
|
|
36
40
|
|
|
37
41
|
/** Custom attributes about the form itself, not custom fields within the form. */
|
|
38
42
|
customFields?: Record<Fields.CustomField>;
|
|
43
|
+
|
|
44
|
+
/** The system metadata for the form. */
|
|
45
|
+
...Fields.SystemMetadata;
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
// #########################################################
|
|
@@ -74,6 +81,8 @@ namespace Examples.Form {
|
|
|
74
81
|
uiSchema: uiSchema,
|
|
75
82
|
mappingToCommonGrants: mappingToCommonGrants,
|
|
76
83
|
mappingFromCommonGrants: mappingFromCommonGrants,
|
|
84
|
+
createdAt: utcDateTime.fromISO("2025-01-01T17:01:01"),
|
|
85
|
+
lastModifiedAt: utcDateTime.fromISO("2025-01-02T17:30:00"),
|
|
77
86
|
};
|
|
78
87
|
|
|
79
88
|
const formSchema = #{
|
|
@@ -63,4 +63,20 @@ interface Applications {
|
|
|
63
63
|
| Responses.ApplicationSubmissionError
|
|
64
64
|
| Responses.NotFound
|
|
65
65
|
| Responses.Unauthorized;
|
|
66
|
+
|
|
67
|
+
// ###############################
|
|
68
|
+
// Search applications
|
|
69
|
+
// ###############################
|
|
70
|
+
|
|
71
|
+
@summary("Search applications")
|
|
72
|
+
@doc("Search for applications. Note: The search results for a given query will depend on the scopes attached to the API token used to make the request.")
|
|
73
|
+
@get
|
|
74
|
+
@route("/search")
|
|
75
|
+
searchApplications(
|
|
76
|
+
/** The filters to apply to the search */
|
|
77
|
+
@query filters: Models.AppFilters,
|
|
78
|
+
|
|
79
|
+
/** The sorting to apply to the search */
|
|
80
|
+
@query sorting: Models.AppSorting,
|
|
81
|
+
): Responses.Filtered<Models.ApplicationBase, Models.AppFilters>;
|
|
66
82
|
}
|
|
@@ -22,7 +22,9 @@ interface Forms {
|
|
|
22
22
|
@summary("List forms")
|
|
23
23
|
@doc("Get a paginated list of forms, sorted by `lastModifiedAt` with most recent first.")
|
|
24
24
|
@get
|
|
25
|
-
list(
|
|
25
|
+
list(
|
|
26
|
+
...Pagination.PaginatedQueryParams,
|
|
27
|
+
): Responses.Paginated<Models.FormBase>;
|
|
26
28
|
|
|
27
29
|
// ###############################
|
|
28
30
|
// View form details
|
|
@@ -34,5 +36,5 @@ interface Forms {
|
|
|
34
36
|
read(
|
|
35
37
|
/** The ID of the form to view */
|
|
36
38
|
@path formId: Types.uuid,
|
|
37
|
-
): Responses.Ok<Models.
|
|
39
|
+
): Responses.Ok<Models.FormBase>;
|
|
38
40
|
}
|
package/lib/main.tsp
CHANGED