Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API] Visit patch request to start next stage #7479

Merged
merged 8 commits into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/api/docs/LorisRESTAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ The JSON object is of the form:
}
```

A PUT of the same format but with only the Meta fields will create the VisitLabel
A PUT with only the Meta fields will create the VisitLabel
laemtl marked this conversation as resolved.
Show resolved Hide resolved
for this candidate, in an unstarted stage if the Visit label provided is valid.

PATCH is not supported for Visit Labels.
Expand Down
4 changes: 2 additions & 2 deletions modules/api/docs/LorisRESTAPI_v0.0.4-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -416,10 +416,10 @@ The JSON object is of the form:
}
```

A PUT of the same format but with only the Meta fields will create the VisitLabel
A PUT request with only the Meta fields will create the VisitLabel
for this candidate, in an unstarted stage if the Visit label provided is valid.

PATCH is not supported for Visit Labels.
A PATCH request with the Meta fields and a date NextStageDate will start the next stage, if the stage is 'Not Started' and the CandID and Visit label provided are valid.
laemtl marked this conversation as resolved.
Show resolved Hide resolved

It will return a 404 Not Found if the visit label does not exist for this candidate
(as well as anything under the /candidates/$CandID/$VisitLabel hierarchy)
Expand Down
18 changes: 13 additions & 5 deletions modules/api/php/endpoints/candidate/candidate.class.inc
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class Candidate extends Endpoint implements \LORIS\Middleware\ETagCalculator
}

// Delegate to sub-endpoints
$visit_label = array_shift($pathparts);
$visit_label = urldecode(array_shift($pathparts));
$newrequest = $request
->withAttribute('pathparts', $pathparts);

Expand All @@ -112,10 +112,18 @@ class Candidate extends Endpoint implements \LORIS\Middleware\ETagCalculator
$visit = null;
}

$handler = new Visit\Visit(
$this->_candidate,
$visit
);
$version = $request->getAttribute("LORIS-API-Version");
if ($version === 'v0.0.3') {
$handler = new Visit\Visit(
$this->_candidate,
$visit
);
} else {
$handler = new Visit\Visit_0_0_4_Dev(
$this->_candidate,
$visit
);
}
laemtl marked this conversation as resolved.
Show resolved Hide resolved

return $handler->process(
$newrequest,
Expand Down
108 changes: 70 additions & 38 deletions modules/api/php/endpoints/candidate/visit/visit.class.inc
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,28 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
*
* @var \Candidate
*/
private $_candidate;
protected $_candidate;

/**
* The requested Visit
*
* @var ?\Timepoint
*/
private $_visit;
protected $_visit;

/**
* The visit centerID
*
* @var ?\CenterID
*/
protected $_centerID;

/**
* The visit Project
*
* @var ?\Project
*/
protected $_project;

/**
* Contructor
Expand Down Expand Up @@ -76,8 +90,7 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
protected function supportedVersions() : array
{
return [
'v0.0.3',
'v0.0.4-dev',
'v0.0.3'
];
}

Expand All @@ -95,23 +108,19 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
if (!$this->_visit->isAccessibleBy($user)) {
return new \LORIS\Http\Response\JSON\Forbidden('Permission denied');
}

}

$pathparts = $request->getAttribute('pathparts');
if (count($pathparts) === 0) {
switch ($request->getMethod()) {
case 'GET':
return $this->_handleGET();
$method = $request->getMethod();

case 'PUT':
return $this->_handlePUT($request);

case 'OPTIONS':
if (in_array($method, $this->allowedMethods())) {
$handle = 'handle'.$method;
return $this->$handle($request);
} else if ($method === 'OPTIONS') {
laemtl marked this conversation as resolved.
Show resolved Hide resolved
return (new \LORIS\Http\Response())
->withHeader('Allow', $this->allowedMethods());

default:
} else {
return new \LORIS\Http\Response\JSON\MethodNotAllowed(
$this->allowedMethods()
);
Expand Down Expand Up @@ -159,7 +168,7 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
*
* @return ResponseInterface The outgoing PSR7 response
*/
private function _handleGET(): ResponseInterface
protected function handleGET(): ResponseInterface
{
if ($this->_visit === null) {
return new \LORIS\Http\Response\JSON\NotFound('Visit not found');
Expand All @@ -172,7 +181,7 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
}

/**
* Handles a PUT request that creates or replace a candidate visit
* Validate a PUT request
*
* TODO: There is no way to validate the the visit_label in the url
* fits the json data of the request because it is removed from the
Expand All @@ -182,13 +191,13 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
*
* @param ServerRequestInterface $request The incoming PSR7 request
*
* @return ResponseInterface The outgoing PSR7 response
* @return ?ResponseInterface The outgoing PSR7 response
*/
private function _handlePUT(ServerRequestInterface $request): ResponseInterface
{
$user = $request->getAttribute('user');
$data = json_decode((string) $request->getBody(), true);
$visitinfo = $data ?? [];
protected function validatePUT(
ServerRequestInterface $request
): ?ResponseInterface {
$user = $request->getAttribute('user');
$data = json_decode((string) $request->getBody(), true) ?? [];

$requiredfields = [
'CandID',
Expand All @@ -197,7 +206,7 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
'Battery',
'Project',
];
$diff = array_diff($requiredfields, array_keys($visitinfo));
$diff = array_diff($requiredfields, array_keys($data));

if (!empty($diff)) {
return new \LORIS\Http\Response\JSON\BadRequest(
Expand All @@ -206,39 +215,61 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
}

try {
$project = \NDB_Factory::singleton()->project($visitinfo['Project']);
$this->_project = \NDB_Factory::singleton()->project($data['Project']);
} catch (\NotFound $e) {
return new \LORIS\Http\Response\JSON\BadRequest(
$e->getMessage()
);
}

if ($visitinfo['CandID'] !== $this->_candidate->getCandID()) {
if (strval($data['CandID']) !== strval($this->_candidate->getCandID())) {
return new \LORIS\Http\Response\JSON\BadRequest(
'CandID do not match this candidate'
'The CandID field does not match this candidate'
);
}

if (!$this->_candidate->isAccessibleBy($user)) {
return new \LORIS\Http\Response\JSON\Forbidden(
"You can't create or modify that candidate"
"You can't modify that candidate"
);
}

$centerid = array_search($visitinfo['Site'], \Utility::getSiteList());
$centerID = array_search($data['Site'], \Utility::getSiteList());

if ($centerid === false
|| !in_array(new \CenterID("$centerid"), $user->getCenterIDs())
if ($centerID === false || !in_array(
new \CenterID(strval($centerID)),
$user->getCenterIDs()
)
) {
return new \LORIS\Http\Response\JSON\Forbidden(
"You can't create or modify candidates visit for the site " .
$centerid
$centerID
);
}

// \Utility::getSiteList key was a string. Now that the
// validation is done, convert to an object.
$centerid = new \CenterID("$centerid");
// Now that the validation is done, convert to an object.
$this->_centerID = new \CenterID(strval($centerID));

return null;
}

/**
* Handles a PUT request that creates or replace a candidate visit
*
* @param ServerRequestInterface $request The incoming PSR7 request
*
* @return ResponseInterface The outgoing PSR7 response
*/
protected function handlePUT(ServerRequestInterface $request): ResponseInterface
{
$user = $request->getAttribute('user');
$data = json_decode((string) $request->getBody(), true);
$visitinfo = $data ?? [];

$response = $this->validatePUT($request);
if ($response !== null) {
return $response;
}

$subprojectid = array_search(
$visitinfo['Battery'],
Expand All @@ -255,6 +286,7 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
$timepoint = \NDB_Factory::singleton()->timepoint(
new \SessionID(strval($sessionid))
);

if ($timepoint->getCurrentStage() !== 'Not Started') {
return new \LORIS\Http\Response\JSON\Conflict(
'This visit is already started'
Expand All @@ -266,7 +298,7 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator

$timepoint->setData(
[
'CenterID' => $centerid,
'CenterID' => $this->_centerID,
'Visit_label' => $visitinfo['Visit'],
'SubprojectID' => $subprojectid,
'Active' => 'Y',
Expand All @@ -275,7 +307,7 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
'UserID' => $username,
'Date_registered' => $today,
'Testdate' => $today,
'ProjectID' => $project->getId(),
'ProjectID' => $this->_project->getId(),
]
);

Expand All @@ -301,8 +333,8 @@ class Visit extends Endpoint implements \LORIS\Middleware\ETagCalculator
$this->_candidate,
$subprojectid,
$visitinfo['Visit'],
\Site::singleton($centerid),
$project
\Site::singleton($this->_centerID),
$this->_project
);

$link = '/' . $request->getUri()->getPath();
Expand Down
Loading