From 2dcb7c559e93237ddf0767505d4b642cce60b01e Mon Sep 17 00:00:00 2001 From: Sebastian Marcet Date: Tue, 16 Oct 2018 11:34:55 -0300 Subject: [PATCH] Added new my affiliations endpoints get my affiliations GET /api/v1/members/me/affiliations scopes %s/members/read/me Add my affiliation POST /api/v1/members/me/affiliations scopes %s/members/write/me update my affiliation /api/v1/members/me/affiliations/{affiliation_id} scopes %s/members/write/me delete my affiliation /api/v1/members/me/affiliations/{affiliation_id} scopes %s/members/write/me Change-Id: I8a6e1bc7c397cc647396a4a7839b54ef29ea517e --- .../Main/OAuth2MembersApiController.php | 76 ++++++++-- app/Http/routes.php | 16 +- app/Security/MemberScopes.php | 28 ++++ app/Security/SummitScopes.php | 2 - app/Services/Model/MemberService.php | 24 +++ database/seeds/ApiEndpointsSeeder.php | 139 +++++------------- database/seeds/ApiScopesSeeder.php | 34 ++--- tests/OAuth2MembersApiTest.php | 39 +++++ tests/ProtectedApiTest.php | 6 +- 9 files changed, 221 insertions(+), 143 deletions(-) create mode 100644 app/Security/MemberScopes.php diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php index 7e3ab4d1..7c26ba9d 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php @@ -58,6 +58,9 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController $this->member_service = $member_service; } + /** + * @return mixed + */ public function getAll(){ $values = Input::all(); @@ -163,6 +166,9 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController } } + /** + * @return mixed + */ public function getMyMember(){ $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); @@ -187,6 +193,13 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController } + /** + * @return mixed + */ + public function getMyMemberAffiliations(){ + return $this->getMemberAffiliations('me'); + } + /** * @param $member_id * @return mixed @@ -194,7 +207,11 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController public function getMemberAffiliations($member_id){ try { + if(strtolower($member_id) == 'me'){ + $member_id = $this->resource_server_context->getCurrentUserExternalId(); + } $member = $this->repository->getById($member_id); + if(is_null($member)) return $this->error404(); $affiliations = $member->getAffiliations()->toArray(); @@ -228,20 +245,36 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController } } + /** + * @return mixed + */ + public function addMyAffiliation(){ + return $this->addAffiliation('me'); + } + + /** + * @param $member_id + * @return mixed + */ public function addAffiliation($member_id){ try { if(!Request::isJson()) return $this->error400(); $data = Input::json(); + if(strtolower($member_id) == 'me'){ + $member_id = $this->resource_server_context->getCurrentUserExternalId(); + } + $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|after_or_null_epoch:start_date', - 'organization_id' => 'required|integer', - 'job_title' => 'sometimes|string|max:255' + 'is_current' => 'required|boolean', + 'start_date' => 'required|date_format:U|valid_epoch', + 'end_date' => 'sometimes|after_or_null_epoch:start_date', + 'organization_id' => 'sometimes|integer|required_without:organization_name', + 'organization_name' => 'sometimes|string|max:255|required_without:organization_id', + 'job_title' => 'sometimes|string|max:255' ]; // Creates a Validator instance and validates the data. @@ -278,6 +311,15 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController } } + + /** + * @param $affiliation_id + * @return mixed + */ + public function updateMyAffiliation($affiliation_id){ + return $this->updateAffiliation('me', $affiliation_id); + } + /** * @param int $member_id * @param int $affiliation_id @@ -288,15 +330,20 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController if(!Request::isJson()) return $this->error400(); $data = Input::json(); + if(strtolower($member_id) == 'me'){ + $member_id = $this->resource_server_context->getCurrentUserExternalId(); + } + $member = $this->repository->getById($member_id); if(is_null($member)) return $this->error404(); $rules = [ - 'is_current' => 'sometimes|boolean', - 'start_date' => 'sometimes|date_format:U|valid_epoch', - 'end_date' => 'sometimes|after_or_null_epoch:start_date', - 'organization_id' => 'sometimes|integer', - 'job_title' => 'sometimes|string|max:255' + 'is_current' => 'sometimes|boolean', + 'start_date' => 'sometimes|date_format:U|valid_epoch', + 'end_date' => 'sometimes|after_or_null_epoch:start_date', + 'organization_id' => 'sometimes|integer', + 'organization_name' => 'sometimes|string|max:255', + 'job_title' => 'sometimes|string|max:255' ]; // Creates a Validator instance and validates the data. @@ -332,6 +379,11 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController } } + + public function deleteMyAffiliation($affiliation_id){ + return $this->deleteAffiliation('me', $affiliation_id); + } + /** * @param $member_id * @param $affiliation_id @@ -340,6 +392,10 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController public function deleteAffiliation($member_id, $affiliation_id){ try{ + if(strtolower($member_id) == 'me'){ + $member_id = $this->resource_server_context->getCurrentUserExternalId(); + } + $member = $this->repository->getById($member_id); if(is_null($member)) return $this->error404(); diff --git a/app/Http/routes.php b/app/Http/routes.php index dcf4bed8..3e4e637d 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -30,14 +30,14 @@ Route::group([ Route::group(['prefix'=>'me'], function(){ // get my member info Route::get('', 'OAuth2MembersApiController@getMyMember'); - // invitations - Route::group(['prefix'=>'team-invitations'], function(){ - Route::get('', 'OAuth2TeamInvitationsApiController@getMyInvitations'); - Route::get('pending', 'OAuth2TeamInvitationsApiController@getMyPendingInvitations'); - Route::get('accepted', 'OAuth2TeamInvitationsApiController@getMyAcceptedInvitations'); - Route::group(['prefix'=>'{invitation_id}'], function() { - Route::put('', 'OAuth2TeamInvitationsApiController@acceptInvitation'); - Route::delete('', 'OAuth2TeamInvitationsApiController@declineInvitation'); + + // my affiliations + Route::group(['prefix' => 'affiliations'], function(){ + Route::get('', [ 'uses' => 'OAuth2MembersApiController@getMyMemberAffiliations']); + Route::post('', [ 'uses' => 'OAuth2MembersApiController@addMyAffiliation']); + Route::group(['prefix' => '{affiliation_id}'], function(){ + Route::put('', ['uses' => 'OAuth2MembersApiController@updateMyAffiliation']); + Route::delete('', [ 'uses' => 'OAuth2MembersApiController@deleteMyAffiliation']); }); }); }); diff --git a/app/Security/MemberScopes.php b/app/Security/MemberScopes.php new file mode 100644 index 00000000..844ac853 --- /dev/null +++ b/app/Security/MemberScopes.php @@ -0,0 +1,28 @@ +setOrganization($org); } + if(isset($data['organization_name'])) { + $org = $this->organization_repository->getByName(trim($data['organization_name'])); + if(is_null($org)){ + $org = new Organization(); + $org->setName(trim($data['organization_name'])); + $this->organization_repository->add($org); + } + + $affiliation->setOrganization($org); + } + if(isset($data['job_title'])) { $affiliation->setJobTitle(trim($data['job_title'])); } @@ -145,6 +157,7 @@ final class MemberService $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)) @@ -152,6 +165,17 @@ final class MemberService $affiliation->setOrganization($org); } + if(isset($data['organization_name'])) { + $org = $this->organization_repository->getByName(trim($data['organization_name'])); + if(is_null($org)){ + $org = new Organization(); + $org->setName(trim($data['organization_name'])); + $this->organization_repository->add($org); + } + + $affiliation->setOrganization($org); + } + if(isset($data['job_title'])) { $affiliation->setJobTitle(trim($data['job_title'])); } diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index 985c0815..65817081 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -17,6 +17,7 @@ use App\Models\ResourceServer\ApiEndpoint; use LaravelDoctrine\ORM\Facades\EntityManager; use App\Security\SummitScopes; use App\Security\OrganizationScopes; +use App\Security\MemberScopes; /** * Class ApiEndpointsSeeder */ @@ -30,7 +31,6 @@ class ApiEndpointsSeeder extends Seeder $this->seedSummitEndpoints(); $this->seedMemberEndpoints(); - $this->seedTeamEndpoints(); $this->seedTagsEndpoints(); $this->seedCompaniesEndpoints(); $this->seedGroupsEndpoints(); @@ -1929,6 +1929,38 @@ class ApiEndpointsSeeder extends Seeder 'http_method' => 'GET', 'scopes' => [sprintf('%s/members/read/me', $current_realm)], ], + // my member affiliations + [ + 'name' => 'get-my-member-affiliations', + 'route' => '/api/v1/members/me/affiliations', + 'http_method' => 'GET', + 'scopes' => [sprintf(MemberScopes::ReadMyMemberData, $current_realm)], + ], + [ + 'name' => 'add-my-member-affiliation', + 'route' => '/api/v1/members/me/affiliations', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(MemberScopes::WriteMyMemberData, $current_realm) + ], + ], + [ + 'name' => 'update-my-member-affiliation', + 'route' => '/api/v1/members/me/affiliations/{affiliation_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(MemberScopes::WriteMyMemberData, $current_realm) + ], + ], + [ + 'name' => 'delete-my-member-affiliation', + 'route' => '/api/v1/members/me/affiliations/{affiliation_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(MemberScopes::WriteMyMemberData, $current_realm) + ], + ], + // member affiliations [ 'name' => 'get-member-affiliations', 'route' => '/api/v1/members/{member_id}/affiliations', @@ -1940,7 +1972,7 @@ class ApiEndpointsSeeder extends Seeder 'route' => '/api/v1/members/{member_id}/affiliations', 'http_method' => 'POST', 'scopes' => [ - sprintf(SummitScopes::WriteMemberData, $current_realm) + sprintf(MemberScopes::WriteMemberData, $current_realm) ], ], [ @@ -1948,7 +1980,7 @@ class ApiEndpointsSeeder extends Seeder 'route' => '/api/v1/members/{member_id}/affiliations/{affiliation_id}', 'http_method' => 'PUT', 'scopes' => [ - sprintf(SummitScopes::WriteMemberData, $current_realm) + sprintf(MemberScopes::WriteMemberData, $current_realm) ], ], [ @@ -1956,7 +1988,7 @@ class ApiEndpointsSeeder extends Seeder 'route' => '/api/v1/members/{member_id}/affiliations/{affiliation_id}', 'http_method' => 'DELETE', 'scopes' => [ - sprintf(SummitScopes::WriteMemberData, $current_realm) + sprintf(MemberScopes::WriteMemberData, $current_realm) ], ], [ @@ -1964,7 +1996,7 @@ class ApiEndpointsSeeder extends Seeder 'route' => '/api/v1/members/{member_id}/rsvp/{rsvp_id}', 'http_method' => 'DELETE', 'scopes' => [ - sprintf(SummitScopes::WriteMemberData, $current_realm) + sprintf(MemberScopes::WriteMemberData, $current_realm) ], ] ] @@ -2058,103 +2090,6 @@ class ApiEndpointsSeeder extends Seeder ); } - private function seedTeamEndpoints(){ - $current_realm = Config::get('app.url'); - - $this->seedApiEndpoints('teams', [ - array( - 'name' => 'add-team', - 'route' => '/api/v1/teams', - 'http_method' => 'POST', - 'scopes' => [sprintf('%s/teams/write', $current_realm)], - ), - array( - 'name' => 'update-team', - 'route' => '/api/v1/teams/{team_id}', - 'http_method' => 'PUT', - 'scopes' => [sprintf('%s/teams/write', $current_realm)], - ), - array( - 'name' => 'delete-team', - 'route' => '/api/v1/teams/{team_id}', - 'http_method' => 'DELETE', - 'scopes' => [sprintf('%s/teams/write', $current_realm)], - ), - array( - 'name' => 'get-teams', - 'route' => '/api/v1/teams', - 'http_method' => 'GET', - 'scopes' => [sprintf('%s/teams/read', $current_realm)], - ), - array( - 'name' => 'get-team', - 'route' => '/api/v1/teams/{team_id}', - 'http_method' => 'GET', - 'scopes' => [sprintf('%s/teams/read', $current_realm)], - ), - array( - 'name' => 'post-message-2-team', - 'route' => '/api/v1/teams/{team_id}/messages', - 'http_method' => 'POST', - 'scopes' => [sprintf('%s/teams/write', $current_realm)], - ), - array( - 'name' => 'get-messages-from-team', - 'route' => '/api/v1/teams/{team_id}/messages', - 'http_method' => 'GET', - 'scopes' => [sprintf('%s/teams/read', $current_realm)], - ), - - array( - 'name' => 'add-member-2-team', - 'route' => '/api/v1/teams/{team_id}/members/{member_id}', - 'http_method' => 'POST', - 'scopes' => [sprintf('%s/teams/write', $current_realm)], - ), - array( - 'name' => 'remove-member-from-team', - 'route' => '/api/v1/teams/{team_id}/members/{member_id}', - 'http_method' => 'DELETE', - 'scopes' => [sprintf('%s/teams/write', $current_realm)], - ), - ] - ); - - $this->seedApiEndpoints('members', [ - array( - 'name' => 'get-invitations', - 'route' => '/api/v1/members/me/team-invitations', - 'http_method' => 'GET', - 'scopes' => [sprintf('%s/members/invitations/read', $current_realm)], - ), - array( - 'name' => 'get-pending-invitations', - 'route' => '/api/v1/members/me/team-invitations/pending', - 'http_method' => 'GET', - 'scopes' => [sprintf('%s/members/invitations/read', $current_realm)], - ), - array( - 'name' => 'get-accepted-invitations', - 'route' => '/api/v1/members/me/team-invitations/accepted', - 'http_method' => 'GET', - 'scopes' => [sprintf('%s/members/invitations/read', $current_realm)], - ), - array( - 'name' => 'accept-invitation', - 'route' => '/api/v1/members/me/team-invitations/{invitation_id}', - 'http_method' => 'PUT', - 'scopes' => [sprintf('%s/members/invitations/write', $current_realm)], - ), - array( - 'name' => 'decline-invitation', - 'route' => '/api/v1/members/me/team-invitations/{invitation_id}', - 'http_method' => 'DELETE', - 'scopes' => [sprintf('%s/members/invitations/write', $current_realm)], - ), - ] - ); - } - public function seedTrackQuestionTemplateEndpoints(){ $current_realm = Config::get('app.url'); diff --git a/database/seeds/ApiScopesSeeder.php b/database/seeds/ApiScopesSeeder.php index 68f36237..fca0a94e 100644 --- a/database/seeds/ApiScopesSeeder.php +++ b/database/seeds/ApiScopesSeeder.php @@ -18,6 +18,7 @@ use LaravelDoctrine\ORM\Facades\EntityManager; use Illuminate\Support\Facades\DB; use App\Security\SummitScopes; use App\Security\OrganizationScopes; +use App\Security\MemberScopes; /** * Class ApiScopesSeeder */ @@ -177,31 +178,26 @@ final class ApiScopesSeeder extends Seeder $api = EntityManager::getRepository(\App\Models\ResourceServer\Api::class)->findOneBy(['name' => 'members']); $scopes = [ - array( - 'name' => sprintf('%s/members/read', $current_realm), + [ + 'name' => sprintf(MemberScopes::ReadMemberData, $current_realm), 'short_description' => 'Get Members Data', 'description' => 'Grants read only access for Members Data', - ), - array( - 'name' => sprintf('%s/members/read/me', $current_realm), + ], + [ + 'name' => sprintf(MemberScopes::ReadMyMemberData, $current_realm), 'short_description' => 'Get My Member Data', 'description' => 'Grants read only access for My Member', - ), - array( - 'name' => sprintf('%s/members/invitations/read', $current_realm), - 'short_description' => 'Allows read only access to invitations', - 'description' => 'Allows read only access to invitations', - ), - array( - 'name' => sprintf('%s/members/invitations/write', $current_realm), - 'short_description' => 'Allows write only access to invitations', - 'description' => 'Allows write only access to invitations', - ), - array( - 'name' => sprintf(SummitScopes::WriteMemberData, $current_realm), + ], + [ + 'name' => sprintf(MemberScopes::WriteMemberData, $current_realm), 'short_description' => 'Allows write only access to members', 'description' => 'Allows write only access to memberss', - ), + ], + [ + 'name' => sprintf(MemberScopes::WriteMyMemberData, $current_realm), + 'short_description' => 'Allows write only access to my Member Data', + 'description' => 'Allows write only access to my Member Data', + ], ]; foreach ($scopes as $scope_info) { diff --git a/tests/OAuth2MembersApiTest.php b/tests/OAuth2MembersApiTest.php index 148d587e..c79a8561 100644 --- a/tests/OAuth2MembersApiTest.php +++ b/tests/OAuth2MembersApiTest.php @@ -200,6 +200,45 @@ final class OAuth2MembersApiTest extends ProtectedApiTest return $affiliation; } + public function testAddMyMemberAffiliation(){ + $params = [ + + ]; + + $start_datetime = new DateTime( "2018-11-10 00:00:00"); + $start_datetime_unix = $start_datetime->getTimestamp(); + + $data = [ + 'is_current' => true, + 'start_date' => $start_datetime_unix, + 'job_title' => 'test affiliation', + 'end_date' => null, + 'organization_name' => 'test new organization' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2MembersApiController@addMyAffiliation", + $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); diff --git a/tests/ProtectedApiTest.php b/tests/ProtectedApiTest.php index 48fca5ce..aae1adda 100644 --- a/tests/ProtectedApiTest.php +++ b/tests/ProtectedApiTest.php @@ -17,6 +17,7 @@ use models\oauth2\AccessToken; use App\Models\ResourceServer\IAccessTokenService; use App\Security\SummitScopes; use App\Security\OrganizationScopes; +use App\Security\MemberScopes; /** * Class AccessTokenServiceStub */ @@ -60,7 +61,8 @@ class AccessTokenServiceStub implements IAccessTokenService sprintf(SummitScopes::WriteSpeakersData, $url), sprintf(SummitScopes::WriteMySpeakersData, $url), sprintf(SummitScopes::WriteAttendeesData, $url), - sprintf(SummitScopes::WriteMemberData, $url), + sprintf(MemberScopes::WriteMemberData, $url), + sprintf(MemberScopes::WriteMyMemberData, $url), sprintf(SummitScopes::WritePromoCodeData, $url), sprintf(OrganizationScopes::WriteOrganizationData, $url), sprintf(OrganizationScopes::ReadOrganizationData, $url), @@ -111,7 +113,7 @@ class AccessTokenServiceStub2 implements IAccessTokenService sprintf(SummitScopes::WriteSpeakersData, $url), sprintf(SummitScopes::WriteMySpeakersData, $url), sprintf(SummitScopes::WriteAttendeesData, $url), - sprintf(SummitScopes::WriteMemberData, $url), + sprintf(Mem::WriteMemberData, $url), sprintf(SummitScopes::WritePromoCodeData, $url), sprintf(OrganizationScopes::WriteOrganizationData, $url), sprintf(OrganizationScopes::ReadOrganizationData, $url),