Added Membership endpoints for my member
sign foundation scopes REAL_URL/members/write/me PUT /api/v1/members/me/membership/foundation resign foundation membetship PUT /api/v1/members/me/membership/community scopes REAL_URL/members/write/me Change-Id: Ib636cf5149cb8b0f633243726c58d3e9329c7234 Signed-off-by: smarcet <smarcet@gmail.com>
This commit is contained in:
parent
9a67080bce
commit
bd94b62c12
@ -455,4 +455,72 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $member_id
|
||||
* @return mixed
|
||||
*/
|
||||
public function signFoundationMembership(){
|
||||
try{
|
||||
|
||||
$member = $this->resource_server_context->getCurrentUser();
|
||||
|
||||
if(is_null($member)) return $this->error404();
|
||||
|
||||
$member = $this->member_service->signFoundationMembership($member);
|
||||
|
||||
return $this->updated(SerializerRegistry::getInstance()->getSerializer
|
||||
(
|
||||
$member,
|
||||
SerializerRegistry::SerializerType_Private
|
||||
)->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 $member_id
|
||||
* @return mixed
|
||||
*/
|
||||
public function resignFoundationMembership(){
|
||||
try{
|
||||
|
||||
$member = $this->resource_server_context->getCurrentUser();
|
||||
|
||||
if(is_null($member)) return $this->error404();
|
||||
|
||||
$member = $this->member_service->resignFoundationMembership($member);
|
||||
|
||||
return $this->updated(SerializerRegistry::getInstance()->getSerializer
|
||||
(
|
||||
$member,
|
||||
SerializerRegistry::SerializerType_Private
|
||||
)->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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -40,6 +40,11 @@ Route::group([
|
||||
Route::delete('', [ 'uses' => 'OAuth2MembersApiController@deleteMyAffiliation']);
|
||||
});
|
||||
});
|
||||
|
||||
Route::group(['prefix' => 'membership'], function(){
|
||||
Route::put('foundation', ['uses' => 'OAuth2MembersApiController@signFoundationMembership']);
|
||||
Route::put('community', ['uses' => 'OAuth2MembersApiController@resignFoundationMembership']);
|
||||
});
|
||||
});
|
||||
|
||||
Route::group(['prefix'=>'{member_id}'], function(){
|
||||
|
120
app/Models/Foundation/Main/LegalAgreement.php
Normal file
120
app/Models/Foundation/Main/LegalAgreement.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php namespace models\main;
|
||||
/**
|
||||
* Copyright 2021 OpenStack Foundation
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
use Doctrine\ORM\Mapping AS ORM;
|
||||
use models\utils\SilverstripeBaseModel;
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="`LegalAgreement`")
|
||||
* Class LegalAgreement
|
||||
* @package models\main
|
||||
*/
|
||||
class LegalAgreement extends SilverstripeBaseModel
|
||||
{
|
||||
|
||||
const Slug = 'the-openstack-foundation-individual-member-agreement';
|
||||
/**
|
||||
* @ORM\Column(name="Signature", type="string")
|
||||
* @var string
|
||||
*/
|
||||
private $signature;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="LegalDocumentPageID", type="integer")
|
||||
* @var int
|
||||
*/
|
||||
private $document_id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="models\main\Member", inversedBy="legal_agreements")
|
||||
* @ORM\JoinColumn(name="MemberID", referencedColumnName="ID")
|
||||
* @var Member
|
||||
*/
|
||||
private $owner;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSignature(): ?string
|
||||
{
|
||||
return $this->signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $signature
|
||||
*/
|
||||
public function setSignature(string $signature): void
|
||||
{
|
||||
$this->signature = $signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getDocumentId(): int
|
||||
{
|
||||
return $this->document_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $document_id
|
||||
*/
|
||||
public function setDocumentId(int $document_id): void
|
||||
{
|
||||
$this->document_id = $document_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Member
|
||||
*/
|
||||
public function getOwner(): Member
|
||||
{
|
||||
return $this->owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Member $owner
|
||||
*/
|
||||
public function setOwner(Member $owner): void
|
||||
{
|
||||
$this->owner = $owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* this is for legacy reasons
|
||||
* @param string $slug
|
||||
* @return int|null
|
||||
*/
|
||||
public static function getLegalAgreementIDBySlug(string $slug):?int {
|
||||
try {
|
||||
$sql = <<<SQL
|
||||
select ID FROM SiteTree
|
||||
where SiteTree.URLSegment = :url_segment AND SiteTree.ClassName = :class_name
|
||||
SQL;
|
||||
$stmt = self::prepareRawSQLStatic($sql);
|
||||
$stmt->execute([
|
||||
'url_segment' => trim($slug),
|
||||
'class_name' => "LegalDocumentPage"
|
||||
]);
|
||||
$res = $stmt->fetchAll();
|
||||
if(count($res) == 0 ) return null;
|
||||
$id = intval($res[0]['ID']);
|
||||
return $id;
|
||||
|
||||
} catch (\Exception $ex) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -30,7 +30,6 @@ use models\summit\PresentationSpeaker;
|
||||
use models\summit\RSVP;
|
||||
use models\summit\Sponsor;
|
||||
use models\summit\Summit;
|
||||
use models\summit\SummitAttendee;
|
||||
use models\summit\SummitAttendeeTicket;
|
||||
use models\summit\SummitEvent;
|
||||
use models\summit\SummitEventFeedback;
|
||||
@ -40,7 +39,6 @@ use models\utils\SilverstripeBaseModel;
|
||||
use Doctrine\ORM\Mapping AS ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="`Member`")
|
||||
* @ORM\Entity(repositoryClass="App\Repositories\Summit\DoctrineMemberRepository")
|
||||
* Class Member
|
||||
@ -97,6 +95,12 @@ class Member extends SilverstripeBaseModel
|
||||
*/
|
||||
private $affiliations;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="LegalAgreement", mappedBy="owner", cascade={"persist"}, orphanRemoval=true)
|
||||
* @var LegalAgreement[]
|
||||
*/
|
||||
protected $legal_agreements;
|
||||
|
||||
/**
|
||||
* @ORM\Column(name="Active", type="boolean")
|
||||
* @var bool
|
||||
@ -170,6 +174,12 @@ class Member extends SilverstripeBaseModel
|
||||
*/
|
||||
private $user_external_id;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
* @ORM\Column(name="ResignDate", type="datetime")
|
||||
*/
|
||||
protected $resign_date;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="models\main\File")
|
||||
* @ORM\JoinColumn(name="PhotoID", referencedColumnName="ID")
|
||||
@ -313,6 +323,7 @@ class Member extends SilverstripeBaseModel
|
||||
$this->schedule_shareable_links = new ArrayCollection();
|
||||
$this->summit_permission_groups = new ArrayCollection();
|
||||
$this->summit_attendance_metrics = new ArrayCollection();
|
||||
$this->legal_agreements = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -323,6 +334,13 @@ class Member extends SilverstripeBaseModel
|
||||
return $this->affiliations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayCollection|LegalAgreement[]
|
||||
*/
|
||||
public function getLegalAgreements(){
|
||||
return $this->legal_agreements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Affiliation[]
|
||||
*/
|
||||
@ -1808,4 +1826,40 @@ SQL;
|
||||
}
|
||||
|
||||
|
||||
public function resignFoundationMembership(){
|
||||
// Remove member from Foundation group
|
||||
foreach ($this->groups as $g) {
|
||||
if ($g->getCode() === IGroup::FoundationMembers) {
|
||||
$this->removeFromGroup($g);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove Member's Legal Agreements
|
||||
$this->legal_agreements->clear();
|
||||
$this->membership_type = self::MembershipTypeCommunity;
|
||||
$this->resign_date = new \DateTime('now', new \DateTimeZone(self::DefaultTimeZone));
|
||||
}
|
||||
|
||||
public function signFoundationMembership()
|
||||
{
|
||||
if (!$this->isFoundationMember()) {
|
||||
// Set up member with legal agreement for becoming an OpenStack Foundation Member
|
||||
$legalAgreement = new LegalAgreement();
|
||||
$legalAgreement->setOwner($this);
|
||||
$documentId = LegalAgreement::getLegalAgreementIDBySlug(LegalAgreement::Slug);
|
||||
if(is_null($documentId))
|
||||
throw new ValidationException(sprintf("LegalAgreement %s does not exists.", LegalAgreement::Slug));
|
||||
$legalAgreement->setDocumentId($documentId);
|
||||
$this->legal_agreements->add($legalAgreement);
|
||||
$this->membership_type = self::MembershipTypeFoundation;
|
||||
$this->resign_date = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function isFoundationMember()
|
||||
{
|
||||
return $this->belongsToGroup(IGroup::FoundationMembers) && $this->legal_agreements->count() > 0;
|
||||
}
|
||||
|
||||
}
|
@ -155,4 +155,11 @@ class ApiScope extends ResourceServerEntity implements IApiScope
|
||||
* @var bool
|
||||
*/
|
||||
private $default;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->active = false;
|
||||
$this->default = false;
|
||||
}
|
||||
}
|
@ -11,6 +11,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
use models\exceptions\EntityNotFoundException;
|
||||
use models\exceptions\ValidationException;
|
||||
use models\main\Affiliation;
|
||||
use models\main\Member;
|
||||
/**
|
||||
@ -86,4 +89,20 @@ interface IMemberService
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function emitRegistrationRequest(string $email, string $first_name, string $last_name):array;
|
||||
|
||||
/**
|
||||
* @param Member $member
|
||||
* @return Member
|
||||
* @throws EntityNotFoundException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function signFoundationMembership(Member $member):Member;
|
||||
|
||||
/**
|
||||
* @param Member $member
|
||||
* @return Member
|
||||
* @throws EntityNotFoundException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function resignFoundationMembership(Member $member):Member;
|
||||
}
|
@ -493,4 +493,44 @@ final class MemberService
|
||||
$last_name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function signFoundationMembership(Member $member): Member
|
||||
{
|
||||
return $this->tx_service->transaction(function() use($member){
|
||||
if($member->isFoundationMember())
|
||||
throw new ValidationException(sprintf("Member %s is already a foundation member", $member->getId()));
|
||||
$group = $this->group_repository->getBySlug(IGroup::FoundationMembers);
|
||||
if(is_null($group))
|
||||
throw new EntityNotFoundException(sprintf("Group %s not found", IGroup::FoundationMembers));
|
||||
|
||||
$member->add2Group($group);
|
||||
$member->signFoundationMembership();
|
||||
|
||||
return $member;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function resignFoundationMembership(Member $member): Member
|
||||
{
|
||||
return $this->tx_service->transaction(function() use($member){
|
||||
if(!$member->isFoundationMember())
|
||||
throw new ValidationException(sprintf("Member %s is not a foundation member", $member->getId()));
|
||||
|
||||
$member->resignFoundationMembership();
|
||||
|
||||
$group = $this->group_repository->getBySlug(IGroup::CommunityMembers);
|
||||
if(is_null($group))
|
||||
throw new EntityNotFoundException(sprintf("Group %s not found", IGroup::CommunityMembers));
|
||||
|
||||
$member->add2Group($group);
|
||||
|
||||
return $member;
|
||||
});
|
||||
}
|
||||
}
|
@ -5443,6 +5443,19 @@ class ApiEndpointsSeeder extends Seeder
|
||||
'http_method' => 'GET',
|
||||
'scopes' => [sprintf('%s/members/read/me', $current_realm)],
|
||||
],
|
||||
// my membership
|
||||
[
|
||||
'name' => 'sign-foundation-membership',
|
||||
'route' => '/api/v1/members/me/membership/foundation',
|
||||
'http_method' => 'PUT',
|
||||
'scopes' => [sprintf(MemberScopes::WriteMyMemberData, $current_realm)],
|
||||
],
|
||||
[
|
||||
'name' => 'resign-foundation-membership',
|
||||
'route' => '/api/v1/members/me/membership/community',
|
||||
'http_method' => 'PUT',
|
||||
'scopes' => [sprintf(MemberScopes::WriteMyMemberData, $current_realm)],
|
||||
],
|
||||
// my member affiliations
|
||||
[
|
||||
'name' => 'get-my-member-affiliations',
|
||||
|
@ -46,8 +46,8 @@ abstract class BrowserKitTestCase extends BaseTestCase
|
||||
*/
|
||||
protected function prepareForTests()
|
||||
{
|
||||
// Artisan::call('doctrine:migrations:migrate', ["--connection" => 'config']);
|
||||
// Artisan::call('doctrine:migrations:migrate', ["--connection" => 'model']);
|
||||
Artisan::call('doctrine:migrations:migrate', ["--connection" => 'config']);
|
||||
Artisan::call('doctrine:migrations:migrate', ["--connection" => 'model']);
|
||||
//Mail::pretend(true);
|
||||
$this->seed('TestSeeder');
|
||||
}
|
||||
|
@ -14,6 +14,19 @@
|
||||
**/
|
||||
final class OAuth2MembersApiTest extends ProtectedApiTest
|
||||
{
|
||||
use InsertSummitTestData;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
self::insertTestData();
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
self::clearTestData();
|
||||
Mockery::close();
|
||||
}
|
||||
|
||||
public function testGetMembers()
|
||||
{
|
||||
@ -352,21 +365,6 @@ final class OAuth2MembersApiTest extends ProtectedApiTest
|
||||
$this->assertResponseStatus(200);
|
||||
}
|
||||
|
||||
|
||||
use InsertSummitTestData;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
self::insertTestData();
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
self::clearTestData();
|
||||
Mockery::close();
|
||||
}
|
||||
|
||||
public function testGetAllSummitPermissions(){
|
||||
self::$member2->addSummitEditPermission(self::$summit);
|
||||
self::$member2->addSummitEditPermission(self::$summit2);
|
||||
@ -391,4 +389,76 @@ final class OAuth2MembersApiTest extends ProtectedApiTest
|
||||
$this->assertTrue(!is_null($pemissions));
|
||||
$this->assertResponseStatus(200);
|
||||
}
|
||||
|
||||
public function testSignFoundationMembership(){
|
||||
$params = [
|
||||
'member_id' => 'me',
|
||||
];
|
||||
|
||||
$headers = [
|
||||
"HTTP_Authorization" => " Bearer " . $this->access_token,
|
||||
"CONTENT_TYPE" => "application/json"
|
||||
];
|
||||
|
||||
$response = $this->action(
|
||||
"PUT",
|
||||
"OAuth2MembersApiController@signFoundationMembership",
|
||||
$params,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
$headers,
|
||||
""
|
||||
);
|
||||
|
||||
$content = $response->getContent();
|
||||
$this->assertResponseStatus(201);
|
||||
$member = json_decode($content);
|
||||
$this->assertTrue(!is_null($member));
|
||||
return $member;
|
||||
}
|
||||
|
||||
public function testSignResignFoundationMembership(){
|
||||
$params = [
|
||||
'member_id' => 'me',
|
||||
];
|
||||
|
||||
$headers = [
|
||||
"HTTP_Authorization" => " Bearer " . $this->access_token,
|
||||
"CONTENT_TYPE" => "application/json"
|
||||
];
|
||||
|
||||
$response = $this->action(
|
||||
"PUT",
|
||||
"OAuth2MembersApiController@signFoundationMembership",
|
||||
$params,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
$headers,
|
||||
""
|
||||
);
|
||||
|
||||
$content = $response->getContent();
|
||||
$this->assertResponseStatus(201);
|
||||
$member = json_decode($content);
|
||||
$this->assertTrue(!is_null($member));
|
||||
|
||||
$response = $this->action(
|
||||
"PUT",
|
||||
"OAuth2MembersApiController@resignFoundationMembership",
|
||||
$params,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
$headers,
|
||||
""
|
||||
);
|
||||
|
||||
$content = $response->getContent();
|
||||
$this->assertResponseStatus(201);
|
||||
$member = json_decode($content);
|
||||
$this->assertTrue(!is_null($member));
|
||||
return $member;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user