Fixes on member affiliation API

* added endpoint to add new affiliation
  /api/v1/members/{member_id}/affiliations
* fixed issues on delete affiliation
* fixed validation on update affiliation
* updated serializer on speaker to get all affiliations

Change-Id: I31426265ab9e57e67a6d1ae2a24b49287ab8d700
This commit is contained in:
Sebastian Marcet 2018-08-30 01:14:22 -03:00
parent 2414f6a3e9
commit 2535885128
9 changed files with 225 additions and 12 deletions

View File

@ -228,6 +228,53 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController
}
}
public function addAffiliation($member_id){
try {
if(!Request::isJson()) return $this->error400();
$data = Input::json();
$member = $this->repository->getById($member_id);
if(is_null($member)) return $this->error404();
$rules = [
'is_current' => 'required|boolean',
'start_date' => 'required|date_format:U|valid_epoch',
'end_date' => 'sometimes|date_format:U|after_or_null_epoch:start_date',
'organization_id' => 'required|integer',
'job_title' => 'sometimes|string|max:255'
];
// Creates a Validator instance and validates the data.
$validation = Validator::make($data->all(), $rules);
if ($validation->fails()) {
$messages = $validation->messages()->toArray();
return $this->error412
(
$messages
);
}
$affiliation = $this->member_service->addAffiliation($member, $data->all());
return $this->created(SerializerRegistry::getInstance()->getSerializer($affiliation)->serialize());
}
catch (ValidationException $ex1) {
Log::warning($ex1);
return $this->error412(array($ex1->getMessage()));
}
catch(EntityNotFoundException $ex2)
{
Log::warning($ex2);
return $this->error404(array('message'=> $ex2->getMessage()));
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
/**
* @param int $member_id
* @param int $affiliation_id
@ -263,7 +310,7 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController
$affiliation = $this->member_service->updateAffiliation($member, $affiliation_id, $data->all());
return $this->ok(SerializerRegistry::getInstance()->getSerializer($affiliation)->serialize());
return $this->updated(SerializerRegistry::getInstance()->getSerializer($affiliation)->serialize());
}
catch (ValidationException $ex1) {
Log::warning($ex1);

View File

@ -46,6 +46,7 @@ Route::group([
Route::group(['prefix' => 'affiliations'], function(){
Route::get('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2MembersApiController@getMemberAffiliations']);
Route::post('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2MembersApiController@addAffiliation']);
Route::group(['prefix' => '{affiliation_id}'], function(){
Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2MembersApiController@updateAffiliation']);
Route::delete('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2MembersApiController@deleteAffiliation']);

View File

@ -111,6 +111,15 @@ final class AdminPresentationSpeakerSerializer extends PresentationSpeakerSerial
}
$values['organizational_roles'] = $organizational_roles;
$affiliations = [];
if($speaker->hasMember()) {
$member = $speaker->getMember();
foreach ($member->getAllAffiliations() as $affiliation) {
$affiliations[] = SerializerRegistry::getInstance()->getSerializer($affiliation)->serialize('organization');
}
}
$values['affiliations'] = $affiliations;
if (!empty($expand)) {
foreach (explode(',', $expand) as $relation) {
switch (trim($relation)) {

View File

@ -135,6 +135,10 @@ class Affiliation extends SilverstripeBaseModel
return $this->owner;
}
public function clearOwner(){
$this->owner = null;
}
/**
* @param Member $owner
*/
@ -189,4 +193,14 @@ class Affiliation extends SilverstripeBaseModel
{
$this->job_title = $job_title;
}
public function __construct()
{
parent::__construct();
$this->is_current = false;
$this->start_date = null;
$this->end_date = null;
$this->organization = null;
$this->owner = null;
}
}

View File

@ -61,13 +61,13 @@ class Member extends SilverstripeBaseModel
private $github_user;
/**
* @ORM\OneToMany(targetEntity="models\summit\SummitEventFeedback", mappedBy="owner", cascade={"persist"})
* @ORM\OneToMany(targetEntity="models\summit\SummitEventFeedback", mappedBy="owner", cascade={"persist"}, orphanRemoval=true)
* @var SummitEventFeedback[]
*/
private $feedback;
/**
* @ORM\OneToMany(targetEntity="Affiliation", mappedBy="owner", cascade={"persist"})
* @ORM\OneToMany(targetEntity="Affiliation", mappedBy="owner", cascade={"persist"}, orphanRemoval=true)
* @var Affiliation[]
*/
private $affiliations;
@ -1019,7 +1019,7 @@ SQL;
*/
public function getAffiliationById($affiliation_id){
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->eq('id', $affiliation_id));
$criteria->where(Criteria::expr()->eq('id', intval($affiliation_id)));
$affiliation = $this->affiliations->matching($criteria)->first();
@ -1031,7 +1031,22 @@ SQL;
* @return $this
*/
public function removeAffiliation(Affiliation $affiliation){
$this->affiliations->removeElement($affiliation);
if($this->affiliations->contains($affiliation)) {
$this->affiliations->removeElement($affiliation);
$affiliation->clearOwner();
}
return $this;
}
/**
* @param Affiliation $affiliation
* @return $this
*/
public function addAffiliation(Affiliation $affiliation){
if(!$this->affiliations->contains($affiliation)) {
$this->affiliations->add($affiliation);
$affiliation->setOwner($this);
}
return $this;
}

View File

@ -19,6 +19,14 @@ use models\main\Member;
*/
interface IMemberService
{
/**
* @param Member $member
* @param array $data
* @return Affiliation
*/
public function addAffiliation(Member $member, array $data);
/**
* @param Member $member
* @param int $affiliation_id

View File

@ -63,7 +63,7 @@ final class MemberService
$affiliation->setIsCurrent(boolval($data['is_current']));
if(isset($data['start_date'])) {
$start_date = intval($data['start_date']);
$affiliation->setEndDate(new DateTime("@$start_date"));
$affiliation->setStartDate(new DateTime("@$start_date"));
}
if(isset($data['end_date'])) {
$end_date = intval($data['end_date']);
@ -125,4 +125,50 @@ final class MemberService
$member->removeRsvp($rsvp);
});
}
/**
* @param Member $member
* @param array $data
* @return Affiliation
*/
public function addAffiliation(Member $member, array $data)
{
return $this->tx_service->transaction(function() use($member, $data){
$affiliation = new Affiliation();
if(isset($data['is_current']))
$affiliation->setIsCurrent(boolval($data['is_current']));
if(isset($data['start_date'])) {
$start_date = intval($data['start_date']);
$affiliation->setStartDate(new DateTime("@$start_date"));
}
if(isset($data['end_date'])) {
$end_date = intval($data['end_date']);
$affiliation->setEndDate($end_date > 0 ? new DateTime("@$end_date") : null);
}
if(isset($data['organization_id'])) {
$org = $this->organization_repository->getById(intval($data['organization_id']));
if(is_null($org))
throw new EntityNotFoundException(sprintf("organization id %s not found", $data['organization_id']));
$affiliation->setOrganization($org);
}
if(isset($data['job_title'])) {
$affiliation->setJobTitle(trim($data['job_title']));
}
if($affiliation->isCurrent() && $affiliation->getEndDate() != null)
throw new ValidationException
(
sprintf
(
"in order to set affiliation as current end_date should be null"
)
);
$member->addAffiliation($affiliation);
return $affiliation;
});
}
}

View File

@ -1781,6 +1781,14 @@ class ApiEndpointsSeeder extends Seeder
'http_method' => 'GET',
'scopes' => [sprintf('%s/members/read', $current_realm)],
],
[
'name' => 'add-member-affiliation',
'route' => '/api/v1/members/{member_id}/affiliations',
'http_method' => 'POST',
'scopes' => [
sprintf(SummitScopes::WriteMemberData, $current_realm)
],
],
[
'name' => 'update-member-affiliation',
'route' => '/api/v1/members/{member_id}/affiliations/{affiliation_id}',

View File

@ -161,16 +161,54 @@ final class OAuth2MembersApiTest extends ProtectedApiTest
$this->assertResponseStatus(200);
}
public function testUpdateMemberAffiliation(){
public function testAddMemberAffiliation($member_id = 11624){
$params = [
'member_id' => 11624,
'affiliation_id' => 61749,
'member_id' => $member_id,
];
$start_datetime = new DateTime( "2018-11-10 00:00:00");
$start_datetime_unix = $start_datetime->getTimestamp();
$data = [
'is_current' => true,
'end_date' => 0,
'job_title' => 'test update'
'start_date' => $start_datetime_unix,
'job_title' => 'test affiliation',
'organization_id' => 1
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action(
"POST",
"OAuth2MembersApiController@addAffiliation",
$params,
[],
[],
[],
$headers,
json_encode($data)
);
$content = $response->getContent();
$this->assertResponseStatus(201);
$affiliation = json_decode($content);
$this->assertTrue(!is_null($affiliation));
return $affiliation;
}
public function testUpdateMemberAffiliation($member_id = 11624){
$new_affiliation = $this->testAddMemberAffiliation($member_id);
$params = [
'member_id' => $member_id,
'affiliation_id' => $new_affiliation->id,
];
$data = [
'job_title' => 'job title update'
];
$headers = [
@ -190,12 +228,39 @@ final class OAuth2MembersApiTest extends ProtectedApiTest
);
$content = $response->getContent();
$this->assertResponseStatus(200);
$this->assertResponseStatus(201);
$affiliation = json_decode($content);
$this->assertTrue(!is_null($affiliation));
return $affiliation;
}
public function testDeleteMemberAffiliation($member_id = 11624){
$new_affiliation = $this->testAddMemberAffiliation($member_id);
$params = [
'member_id' => $member_id,
'affiliation_id' => $new_affiliation->id,
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json"
];
$response = $this->action(
"DELETE",
"OAuth2MembersApiController@deleteAffiliation",
$params,
[],
[],
[],
$headers
);
$content = $response->getContent();
$this->assertResponseStatus(204);
}
public function testGetMemberAffiliation($member_id = 11624)
{