Skip to content

Commit

Permalink
Add publicLinks count to form extended metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
matthew-white committed Jul 2, 2024
1 parent 084cbe1 commit a29c0a5
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 5 deletions.
15 changes: 14 additions & 1 deletion docs/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ info:

Here major and breaking changes to the API are listed by version.

## ODK Central v2024.2

**Added**:

- Extended metadata for Forms includes a new property `publicLinks`, which is the number of Public Links that can submit to the Form.

## ODK Central v2024.1

**Added**:
Expand Down Expand Up @@ -2964,7 +2970,7 @@ paths:

As of version 1.2, Forms that are unpublished (that only carry a draft and have never been published) will appear with full metadata detail. Previously, certain details like `name` were omitted. You can determine that a Form is unpublished by checking the `publishedAt` value: it will be `null` for unpublished forms.

This endpoint supports retrieving extended metadata; provide a header `X-Extended-Metadata: true` to additionally retrieve the `submissions` count of the number of Submissions that each Form has, the `reviewStates` object of counts of Submissions with specific review states, the `lastSubmission` most recent submission timestamp, as well as the Actor the Form was `createdBy`.
This endpoint supports retrieving extended metadata; provide a header `X-Extended-Metadata: true` to additionally retrieve the `submissions` count of the number of Submissions that each Form has, the `reviewStates` object of counts of Submissions with specific review states, the `lastSubmission` most recent submission timestamp, the Actor the Form was `createdBy`, as well as other metadata.
operationId: List all Forms
parameters:
- name: projectId
Expand Down Expand Up @@ -3026,6 +3032,7 @@ paths:
updatedAt: 2018-04-18T23:42:11.406Z
deletedAt: 2018-04-18T23:42:11.406Z
entityRelated: false
publicLinks: 4
403:
description: Forbidden
content:
Expand Down Expand Up @@ -3281,6 +3288,7 @@ paths:
updatedAt: 2018-04-18T23:42:11.406Z
deletedAt: 2018-04-18T23:42:11.406Z
entityRelated: false
publicLinks: 4
403:
description: Forbidden
content:
Expand Down Expand Up @@ -12524,6 +12532,7 @@ components:
- submissions
- reviewStates
- entityRelated
- publicLinks
properties:
submissions:
type: number
Expand All @@ -12545,6 +12554,10 @@ components:
entityRelated:
type: boolean
description: True only if this Form is related to a Dataset. In v2022.3, this means the Form's Submissions create Entities in a Dataset. In a future version, Submissions will also be able to update existing Entities.
publicLinks:
type: number
example: 4
description: The number of Public Links that can submit to the Form. This does not include Public Links that have been revoked.
ExtendedFormVersion:
allOf:
- $ref: '#/components/schemas/Form'
Expand Down
6 changes: 4 additions & 2 deletions lib/model/frames/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ Form.Extended = class extends Frame.define(
'excelContentType', readable,
// counts of submissions in various review states
'receivedCount', 'hasIssuesCount',
'editedCount', 'entityRelated', readable
'editedCount', 'entityRelated', readable,
'publicLinks', readable
) {
forApi() {
return {
Expand All @@ -160,7 +161,8 @@ Form.Extended = class extends Frame.define(
edited: this.editedCount || 0
},
lastSubmission: this.lastSubmission,
excelContentType: this.excelContentType
excelContentType: this.excelContentType,
publicLinks: this.publicLinks ?? 0
};
}
};
Expand Down
8 changes: 7 additions & 1 deletion lib/model/query/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,13 @@ ${extend|| sql`
left outer join (select id, "contentType" as "excelContentType" from blobs) as xls
on form_defs."xlsBlobId"=xls.id
left outer join (select "formDefId", count(1) > 0 "entityRelated" from dataset_form_defs group by "formDefId") as dd
on form_defs.id = dd."formDefId"`}
on form_defs.id = dd."formDefId"
left outer join
(select public_links."formId", count(1)::integer as "publicLinks"
from public_links
inner join sessions on sessions."actorId" = public_links."actorId"
group by public_links."formId") as public_link_counts
on public_link_counts."formId" = forms.id`}
${(actorId == null) ? sql`` : sql`
inner join
(select id, max(assignment."showDraft") as "showDraft", max(assignment."showNonOpen") as "showNonOpen" from projects
Expand Down
3 changes: 2 additions & 1 deletion test/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,11 @@ should.Assertion.add('ExtendedForm', function() {
this.params = { operator: 'to be a ExtendedForm' };

this.obj.should.be.a.Form();
Object.keys(this.obj).should.containDeep([ 'submissions', 'lastSubmission', 'reviewStates' ]);
Object.keys(this.obj).should.containDeep([ 'submissions', 'lastSubmission', 'reviewStates', 'publicLinks' ]);
this.obj.submissions.should.be.a.Number();
Object.keys(this.obj.reviewStates).should.containDeep([ 'received', 'hasIssues', 'edited']);
if (this.obj.lastSubmission != null) this.obj.lastSubmission.should.be.an.isoDate();
this.obj.publicLinks.should.be.a.Number();
});

should.Assertion.add('FormAttachment', function() {
Expand Down
32 changes: 32 additions & 0 deletions test/integration/api/forms/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,38 @@ describe('api: /projects/:id/forms (create, read, update)', () => {
body.excelContentType.should.equal('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
})))));

it('should return count of public links with extended metadata', testService(async (service) => {
const asAlice = await service.login('alice');
await asAlice.post('/v1/projects/1/forms/simple/public-links')
.send({ displayName: 'link1' })
.expect(200);
await asAlice.post('/v1/projects/1/forms/simple/public-links')
.send({ displayName: 'link2' })
.expect(200);
const { body: form } = await asAlice.get('/v1/projects/1/forms/simple')
.set('X-Extended-Metadata', 'true')
.expect(200);
form.publicLinks.should.equal(2);
}));

it('should exclude deleted and revoked public links', testService(async (service) => {
const asAlice = await service.login('alice');
const { body: link1 } = await asAlice.post('/v1/projects/1/forms/simple/public-links')
.send({ displayName: 'link1' })
.expect(200);
const { body: link2 } = await asAlice.post('/v1/projects/1/forms/simple/public-links')
.send({ displayName: 'link2' })
.expect(200);
await asAlice.delete(`/v1/projects/1/forms/simple/public-links/${link1.id}`)
.expect(200);
await asAlice.delete(`/v1/sessions/${link2.token}`)
.expect(200);
const { body: form } = await asAlice.get('/v1/projects/1/forms/simple')
.set('X-Extended-Metadata', 'true')
.expect(200);
form.publicLinks.should.equal(0);
}));

it('should not return a draftToken', testService((service) =>
service.login('alice', (asAlice) =>
asAlice.post('/v1/projects/1/forms/simple/draft')
Expand Down

0 comments on commit a29c0a5

Please sign in to comment.