From d4a5d4a57620891493fc5fafcbf2f9a58799f2df Mon Sep 17 00:00:00 2001 From: zaliqarosli Date: Tue, 23 Nov 2021 15:55:51 -0500 Subject: [PATCH 1/2] change candidates type to array add other sex option add Meta property to visitmeta redo remove dynamic key instrumentData is empty class if no properties set change other instances of $instrumentname move to v0.0.04 add Other sex to docs phan add switch for versions cleanup + add more version checks fixes add to v4 fix return with 204 add missing ; remove duplicated fix schema fix test for v0.0.0-4 --- modules/api/docs/LorisRESTAPI.md | 6 +- modules/api/docs/LorisRESTAPI_v0.0.4-dev.md | 8 +-- .../visit/instrument/instrument.class.inc | 47 ++++++++---- .../visit/instrument_0_0_4_dev.class.inc | 72 +++++++++++++++++++ modules/api/static/schema-v0.0.4-dev.yml | 48 ++++--------- modules/api/static/schema.yml | 16 +++-- .../test/api/LorisApiInstrumentsTest.php | 8 +-- 7 files changed, 138 insertions(+), 67 deletions(-) create mode 100644 modules/api/php/views/visit/instrument_0_0_4_dev.class.inc diff --git a/modules/api/docs/LorisRESTAPI.md b/modules/api/docs/LorisRESTAPI.md index dc0da402ee5..3f932a943ef 100644 --- a/modules/api/docs/LorisRESTAPI.md +++ b/modules/api/docs/LorisRESTAPI.md @@ -295,7 +295,7 @@ of this reference a CandidateObject. A CandidateObject is a JSON object of the f "Site" : Site, "EDC" : "YYYY-MM-DD", "DoB" : "YYYY-MM-DD", - "Sex" : "Male|Female" + "Sex" : "Male|Female|Other" } ``` @@ -326,7 +326,7 @@ The body of the POST request should be a candidate key with a JSON object of the "PSCID" : PSCID, "EDC" : "YYYY-MM-DD", "DoB" : "YYYY-MM-DD", - "Sex" : "Male|Female", + "Sex" : "Male|Female|Other", "Site" : SiteName, } } @@ -342,7 +342,7 @@ A response code of 201 Created will be returned on success, 409 Conflict if the PSCID already exists, 403 Forbidden when the user is creating a candidate at a site other than the list of sitenames the user is affiliated with, and a 400 Bad Request if any data provided is invalid (PSCID format, date format, sex -something other than Male|Female, invalid project name, invalid sitename, etc). +something other than Male|Female|Other, invalid project name, invalid sitename, etc). A successful POST request will return a CandidateObject for the newly created candidate. diff --git a/modules/api/docs/LorisRESTAPI_v0.0.4-dev.md b/modules/api/docs/LorisRESTAPI_v0.0.4-dev.md index 6e23cd4d742..4669d2a845c 100644 --- a/modules/api/docs/LorisRESTAPI_v0.0.4-dev.md +++ b/modules/api/docs/LorisRESTAPI_v0.0.4-dev.md @@ -295,7 +295,7 @@ of this reference a CandidateObject. A CandidateObject is a JSON object of the f "Site" : Site, "EDC" : "YYYY-MM-DD", "DoB" : "YYYY-MM-DD", - "Sex" : "Male|Female" + "Sex" : "Male|Female|Other" } ``` @@ -326,7 +326,7 @@ The body of the POST request should be a candidate key with a JSON object of the "PSCID" : PSCID, "EDC" : "YYYY-MM-DD", "DoB" : "YYYY-MM-DD", - "Sex" : "Male|Female", + "Sex" : "Male|Female|Other", "Site" : SiteName, } } @@ -342,7 +342,7 @@ A response code of 201 Created will be returned on success, 409 Conflict if the PSCID already exists, 403 Forbidden when the user is creating a candidate at a site other than the list of sitenames the user is affiliated with, and a 400 Bad Request if any data provided is invalid (PSCID format, date format, sex -something other than Male|Female, invalid project name, invalid sitename, etc). +something other than Male|Female|Other, invalid project name, invalid sitename, etc). A successful POST request will return a CandidateObject for the newly created candidate. @@ -504,7 +504,7 @@ The format returned by a GET request is a JSON document of the form: "Candidate" : $CandID, "DDE" : boolean }, - "$InstrumentName" : { + "Data" : { "FieldName1" : "Value1", "FieldName2" : "Value2", ... diff --git a/modules/api/php/endpoints/candidate/visit/instrument/instrument.class.inc b/modules/api/php/endpoints/candidate/visit/instrument/instrument.class.inc index 9bbd92574c1..4ddbac10fab 100644 --- a/modules/api/php/endpoints/candidate/visit/instrument/instrument.class.inc +++ b/modules/api/php/endpoints/candidate/visit/instrument/instrument.class.inc @@ -134,14 +134,27 @@ class Instrument extends Endpoint implements \LORIS\Middleware\ETagCalculator /** * Handles a GET request * + * @param ServerRequestInterface $request The incoming PSR7 request + * * @return ResponseInterface The outgoing PSR7 response */ - private function _handleGET() : ResponseInterface + private function _handleGET(ServerRequestInterface $request) : ResponseInterface { - $body = (new \LORIS\api\Views\Visit\Instrument( - $this->_visit, - $this->_instrument - ))->toArray(); + + $version = $request->getAttribute('LORIS-API-Version'); + switch ($version) { + case 'v0.0.3': + $body = (new \LORIS\api\Views\Visit\Instrument( + $this->_visit, + $this->_instrument + ))->toArray(); + break; + default: + $body = (new \LORIS\api\Views\Visit\Instrument_0_0_4_Dev( + $this->_visit, + $this->_instrument + ))->toArray(); + } return new \LORIS\Http\Response\JsonResponse( $body @@ -177,17 +190,21 @@ class Instrument extends Endpoint implements \LORIS\Middleware\ETagCalculator } try { - $instrumentname = $this->_instrument->testName; $this->_instrument->clearInstrument(); - $this->_instrument->_saveValues($data[$instrumentname]); + $version = $request->getAttribute('LORIS-API-Version'); + if ($version == 'v0.0.3') { + $instrumentname = $this->_instrument->testName; + $this->_instrument->_saveValues($data[$instrumentname]); + } else { + $this->_instrument->_saveValues($data['Data']); + } $this->_instrument->score(); $this->_instrument->updateRequiredElementsCompletedFlag(); } catch (\Throwable $e) { error_log($e->getMessage()); return new \LORIS\Http\Response\JSON\InternalServerError(); } - return (new \LORIS\Http\Response()) - ->withStatus(204); + return (new \LORIS\Http\Response\JSON\NoContent()); } /** @@ -220,16 +237,20 @@ class Instrument extends Endpoint implements \LORIS\Middleware\ETagCalculator } try { - $instrumentname = $this->_instrument->testName; - $this->_instrument->_saveValues($data[$instrumentname]); + $version = $request->getAttribute('LORIS-API-Version'); + if ($version == 'v0.0.3') { + $instrumentname = $this->_instrument->testName; + $this->_instrument->_saveValues($data[$instrumentname]); + } else { + $this->_instrument->_saveValues($data['Data']); + } $this->_instrument->score(); $this->_instrument->updateRequiredElementsCompletedFlag(); } catch (\Throwable $e) { error_log($e->getMessage()); return new \LORIS\Http\Response\JSON\InternalServerError(); } - return (new \LORIS\Http\Response()) - ->withStatus(204); + return (new \LORIS\Http\Response\JSON\NoContent()); } /** diff --git a/modules/api/php/views/visit/instrument_0_0_4_dev.class.inc b/modules/api/php/views/visit/instrument_0_0_4_dev.class.inc new file mode 100644 index 00000000000..1a732c331ac --- /dev/null +++ b/modules/api/php/views/visit/instrument_0_0_4_dev.class.inc @@ -0,0 +1,72 @@ + + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ + +namespace LORIS\api\Views\Visit; + +/** + * Creates a representation of a visit intrument following the api response + * specifications. + * + * @category ApiViews + * @package Loris + * @author Xavier Lecours Boucher + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ + +class Instrument_0_0_4_Dev +{ + private $_timepoint; + private $_instrument; + + /** + * Constructor which sets the instance variables based on the provided timepoint + * and instrument. + * + * @param \Timepoint $timepoint The timepoint to represent + * @param \NDB_BVL_Instrument $instrument The instrument. + */ + public function __construct( + \Timepoint $timepoint, + \NDB_BVL_Instrument $instrument + ) { + $this->_timepoint = $timepoint; + $this->_instrument = $instrument; + } + + /** + * Creates an serializable array of this object's data + * + * @return array + */ + public function toArray(): array + { + $instrumentname = $this->_instrument->testName; + $instrumentdata = $this->_instrument->getInstanceData(); + + $isDDE = strpos($instrumentdata['CommentID'], 'DDE_') === 0; + + $meta = [ + 'Candidate' => $this->_timepoint->getCandID(), + 'Visit' => $this->_timepoint->getVisitLabel(), + 'DDE' => $isDDE, + 'Instrument' => $instrumentname, + ]; + + $instrument = ['Data' => $instrumentdata]; + + return array_merge( + ['Meta' => $meta], + $instrument + ); + } +} + diff --git a/modules/api/static/schema-v0.0.4-dev.yml b/modules/api/static/schema-v0.0.4-dev.yml index c27cf6eea45..d371ae868ef 100644 --- a/modules/api/static/schema-v0.0.4-dev.yml +++ b/modules/api/static/schema-v0.0.4-dev.yml @@ -308,7 +308,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/VisitMetaFields' + $ref: '#/components/schemas/VisitMeta' responses: '201': description: The visit was created successfully @@ -925,7 +925,7 @@ paths: - Images summary: Get the qc values of an image parameters: - - name: candid + - name: id in: path description: The candidate identifier. Either PSCID or CandID. required: true @@ -1288,7 +1288,7 @@ paths: - Dicoms summary: List all dicoms for that timepoint parameters: - - name: candid + - name: id in: path description: ID of the candidate. Either PSCID or CandID required: true @@ -1852,7 +1852,9 @@ components: type: object properties: Candidates: - $ref: '#/components/schemas/Candidate' + type: array + items: + $ref: '#/components/schemas/Candidate' Candidate: type: object properties: @@ -1873,6 +1875,7 @@ components: enum: - Female - Male + - Other NewCandidate: type: object properties: @@ -1944,8 +1947,10 @@ components: properties: Meta: $ref: '#/components/schemas/InstrumentMeta' - $InstrumentShortName: - $ref: '#/components/schemas/InstrumentData' + Data: + type: object + additionalProperties: + type: string InstrumentMeta: type: object properties: @@ -1957,10 +1962,6 @@ components: type: string DDE: type: boolean - InstrumentData: - type: object - additionalProperties: - type: string InstrumentFlags: type: object properties: @@ -2249,6 +2250,7 @@ components: enum: - Female - Male + - Other InstrumentFlags_Flags: type: object properties: @@ -2471,19 +2473,6 @@ components: type: string EventFilePath: type: string - - VisitStage: - type: object - properties: - Date: - type: string - Status: - type: string - enum: - - Pass - - Failure - - Withdrawal - - In Progress VisitPatchFields: type: object allOf: @@ -2492,19 +2481,6 @@ components: properties: Stages: $ref: '#/components/schemas/InstrumentVisit' - - InstrumentVisit: - type: object - properties: - Visit: - $ref: '#/components/schemas/VisitStage' - - Error: - type: object - properties: - error: - type: string - securitySchemes: ApiKeyAuth: type: apiKey diff --git a/modules/api/static/schema.yml b/modules/api/static/schema.yml index 62c7b522ab1..7fc1059efaf 100644 --- a/modules/api/static/schema.yml +++ b/modules/api/static/schema.yml @@ -308,7 +308,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/VisitMetaFields' + $ref: '#/components/schemas/VisitMeta' responses: '201': description: The visit was created successfully @@ -1823,7 +1823,9 @@ components: type: object properties: Candidates: - $ref: '#/components/schemas/Candidate' + type: array + items: + $ref: '#/components/schemas/Candidate' Candidate: type: object properties: @@ -1844,6 +1846,7 @@ components: enum: - Female - Male + - Other NewCandidate: type: object properties: @@ -1916,7 +1919,9 @@ components: Meta: $ref: '#/components/schemas/InstrumentMeta' $InstrumentShortName: - $ref: '#/components/schemas/InstrumentData' + type: object + additionalProperties: + type: string InstrumentMeta: type: object properties: @@ -1928,10 +1933,6 @@ components: type: string DDE: type: boolean - InstrumentData: - type: object - additionalProperties: - type: string InstrumentFlags: type: object properties: @@ -2220,6 +2221,7 @@ components: enum: - Female - Male + - Other InstrumentFlags_Flags: type: object properties: diff --git a/raisinbread/test/api/LorisApiInstrumentsTest.php b/raisinbread/test/api/LorisApiInstrumentsTest.php index 128ff0234d2..84b8a35da7b 100644 --- a/raisinbread/test/api/LorisApiInstrumentsTest.php +++ b/raisinbread/test/api/LorisApiInstrumentsTest.php @@ -105,7 +105,7 @@ public function testGetCandidatesCandidVisitInstrumentsInstrument(): void public function testPatchCandidatesCandidVisitInstrumentsInstrument(): void { $json = [ - $this->instrumentTest => [ + 'Data' => [ 'UserID' => "2" ] ]; @@ -132,7 +132,7 @@ public function testPatchCandidatesCandidVisitInstrumentsInstrument(): void public function testPutCandidatesCandidVisitInstrumentsInstrument(): void { $json = [ - $this->instrumentTest => [ + 'Data' => [ 'UserID' => "2" ] ]; @@ -355,7 +355,7 @@ public function testPatchCandidatesCandidVisitInstrumentsInstrumentDde(): void 'DDE' => true, 'Instrument' => $this->instrumentTest ], - $this->instrumentTest => [ + 'Data' => [ 'UserID' => "2" ] ]; @@ -388,7 +388,7 @@ public function testPutCandidatesCandidVisitInstrumentsInstrumentDde(): void 'DDE' => true, 'Instrument' => $this->instrumentTest ], - $this->instrumentTest => [ + 'Data' => [ 'UserID' => "2" ] ]; From ef06d0993e908b8079e7c668e99d708db7e735cf Mon Sep 17 00:00:00 2001 From: zaliqarosli Date: Fri, 3 Mar 2023 14:25:25 -0500 Subject: [PATCH 2/2] meta key removed from handler --- modules/api/static/schema-v0.0.4-dev.yml | 2 +- modules/api/static/schema.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/api/static/schema-v0.0.4-dev.yml b/modules/api/static/schema-v0.0.4-dev.yml index d371ae868ef..ab223d229e1 100644 --- a/modules/api/static/schema-v0.0.4-dev.yml +++ b/modules/api/static/schema-v0.0.4-dev.yml @@ -308,7 +308,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/VisitMeta' + $ref: '#/components/schemas/VisitMetaFields' responses: '201': description: The visit was created successfully diff --git a/modules/api/static/schema.yml b/modules/api/static/schema.yml index 7fc1059efaf..6a989628b38 100644 --- a/modules/api/static/schema.yml +++ b/modules/api/static/schema.yml @@ -308,7 +308,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/VisitMeta' + $ref: '#/components/schemas/VisitMetaFields' responses: '201': description: The visit was created successfully