Tweak on member serializer

Change-Id: I09a44aa2cc985abfc3a4d71b23a75e26bee9eb28
Signed-off-by: smarcet <smarcet@gmail.com>
This commit is contained in:
smarcet 2021-01-18 14:30:57 -03:00
parent 83012ea9bf
commit b654c8b449
15 changed files with 298 additions and 58 deletions

View File

@ -493,14 +493,14 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController
* @param $member_id
* @return mixed
*/
public function resignFoundationMembership(){
public function signCommunityMembership(){
try{
$member = $this->resource_server_context->getCurrentUser();
if(is_null($member)) return $this->error404();
$member = $this->member_service->resignFoundationMembership($member);
$member = $this->member_service->signCommunityMembership($member);
return $this->updated(SerializerRegistry::getInstance()->getSerializer
(
@ -523,4 +523,34 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController
}
}
/**
* @param $member_id
* @return mixed
*/
public function resignMembership(){
try{
$member = $this->resource_server_context->getCurrentUser();
if(is_null($member)) return $this->error404();
$this->member_service->resignMembership($member);
return $this->deleted();
}
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);
}
}
}

View File

@ -1,5 +1,4 @@
<?php namespace App\Http\Middleware;
/**
* Copyright 2015 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
@ -12,9 +11,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Models\ResourceServer\IAccessTokenService;
use App\Models\ResourceServer\IApiEndpointRepository;
use Closure;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Response;
@ -25,8 +24,6 @@ use libs\oauth2\OAuth2ResourceServerException;
use libs\oauth2\OAuth2WWWAuthenticateErrorResponse;
use libs\utils\RequestUtils;
use models\oauth2\IResourceServerContext;
use App\Models\ResourceServer\IAccessTokenService;
use App\Models\ResourceServer\IApiEndpointRepository;
use URL\Normalizer;
/**
@ -203,6 +200,7 @@ class OAuth2BearerAccessTokenRequestValidator
$context['user_external_id'] = $token_info->getUserExternalId();
$context['user_identifier'] = $token_info->getUserIdentifier();
$context['user_email'] = $token_info->getUserEmail();
$context['user_email_verified'] = $token_info->isUserEmailVerified();
$context['user_first_name'] = $token_info->getUserFirstName();
$context['user_last_name'] = $token_info->getUserLastName();
$context['user_groups'] = $token_info->getUserGroups();

View File

@ -43,7 +43,8 @@ Route::group([
Route::group(['prefix' => 'membership'], function(){
Route::put('foundation', ['uses' => 'OAuth2MembersApiController@signFoundationMembership']);
Route::put('community', ['uses' => 'OAuth2MembersApiController@resignFoundationMembership']);
Route::put('community', ['uses' => 'OAuth2MembersApiController@signCommunityMembership']);
Route::delete('resign', ['uses' => 'OAuth2MembersApiController@resignMembership']);
});
});

View File

@ -36,6 +36,7 @@ class AbstractMemberSerializer extends SilverStripeSerializer
'Active' => 'active:json_boolean',
'EmailVerified' => 'email_verified:json_boolean',
'ProfilePhotoUrl' => 'pic:json_url',
'MembershipType' => 'membership_type:json_string',
];
protected static $allowed_relations = [

View File

@ -1841,6 +1841,15 @@ SQL;
$this->resign_date = new \DateTime('now', new \DateTimeZone(self::DefaultTimeZone));
}
public function resignMembership(){
// Remove Member's Legal Agreements
$this->legal_agreements->clear();
$this->affiliations->clear();
$this->groups->clear();
$this->membership_type = self::MembershipTypeNone;
$this->resign_date = new \DateTime('now', new \DateTimeZone(self::DefaultTimeZone));
}
public function signFoundationMembership(LegalDocument $document)
{
if (!$this->isFoundationMember()) {

View File

@ -64,6 +64,11 @@ final class AccessToken extends Token
*/
private $user_email;
/**
* @var bool
*/
private $user_email_verified;
/**
* @var string|null
*/
@ -95,6 +100,7 @@ final class AccessToken extends Token
$instance->user_external_id = self::getValueFromInfo('user_external_id', $token_info);
$instance->user_identifier = self::getValueFromInfo('user_identifier', $token_info);
$instance->user_email = self::getValueFromInfo('user_email', $token_info);
$instance->user_email_verified = boolval(self::getValueFromInfo('user_email_verified', $token_info));
$instance->user_first_name = self::getValueFromInfo('user_first_name', $token_info);
$instance->user_last_name = self::getValueFromInfo('user_last_name', $token_info);
$instance->auth_code = null;
@ -198,4 +204,13 @@ final class AccessToken extends Token
public function getUserGroups():array {
return $this->user_groups;
}
/**
* @return bool
*/
public function isUserEmailVerified(): bool
{
return $this->user_email_verified;
}
}

View File

@ -12,14 +12,14 @@
* limitations under the License.
**/
use App\Models\Foundation\Main\IGroup;
use App\Services\Model\dto\ExternalUserDTO;
use App\Services\Model\IMemberService;
use Illuminate\Support\Facades\Log;
use libs\utils\ITransactionService;
use models\main\Group;
use models\main\IGroupRepository;
use models\main\IMemberRepository;
use models\main\Member;
/**
* Class ResourceServerContext
* @package models\oauth2
@ -186,6 +186,7 @@ final class ResourceServerContext implements IResourceServerContext
$user_first_name = $this->getAuthContextVar('user_first_name');
$user_last_name = $this->getAuthContextVar('user_last_name');
$user_email = $this->getAuthContextVar('user_email');
$user_email_verified = boolval($this->getAuthContextVar('user_email_verified'));
if(!empty($user_email))
$member->setEmail($user_email);
@ -194,16 +195,18 @@ final class ResourceServerContext implements IResourceServerContext
if(!empty($user_last_name))
$member->setLastName($user_last_name);
$member->setEmailVerified($user_email_verified);
return $synch_groups ? $this->checkGroups($member) : $member;
}
}
if(is_null($member)) {
// we assume that is new idp version and claims already exists on context
$user_external_id = $this->getAuthContextVar('user_id');
$user_first_name = $this->getAuthContextVar('user_first_name');
$user_last_name = $this->getAuthContextVar('user_last_name');
$user_email = $this->getAuthContextVar('user_email');
$user_external_id = $this->getAuthContextVar('user_id');
$user_first_name = $this->getAuthContextVar('user_first_name');
$user_last_name = $this->getAuthContextVar('user_last_name');
$user_email = $this->getAuthContextVar('user_email');
$user_email_verified = boolval($this->getAuthContextVar('user_email_verified'));
// at last resort try to get by email
Log::debug(sprintf("ResourceServerContext::getCurrentUser getting user by email %s", $user_email));
$member = $this->member_repository->getByEmail($user_email);
@ -223,10 +226,15 @@ final class ResourceServerContext implements IResourceServerContext
$member = $this->member_service->registerExternalUser
(
$user_external_id,
$user_email,
$user_first_name,
$user_last_name
new ExternalUserDTO
(
$user_external_id,
$user_email,
$user_first_name,
$user_last_name,
true,
$user_email_verified
)
);
}
@ -237,6 +245,7 @@ final class ResourceServerContext implements IResourceServerContext
if(!empty($user_last_name))
$member->setLastName($user_last_name);
$member->setEmailVerified(boolval($user_email_verified));
$member->setUserExternalId($user_external_id);
}

View File

@ -11,16 +11,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use libs\oauth2\InvalidGrantTypeException;
use libs\oauth2\OAuth2InvalidIntrospectionResponse;
use libs\oauth2\OAuth2Protocol;
use libs\utils\ConfigurationException;
use libs\utils\ICacheService;
use models\oauth2\AccessToken;
use Illuminate\Support\Facades\Log;
/**
* Class AccessTokenService
* @package App\Models\ResourceServer
@ -44,6 +46,7 @@ final class AccessTokenService implements IAccessTokenService
'user_first_name',
'user_last_name',
'user_groups',
'user_email_verified',
];
/**
@ -149,6 +152,10 @@ final class AccessTokenService implements IAccessTokenService
$token_info['user_email'] = null;
}
if(!array_key_exists("user_email_verified" , $token_info)){
$token_info['user_email_verified'] = false;
}
if(!array_key_exists("user_first_name" , $token_info)){
$token_info['user_first_name'] = null;
}

View File

@ -40,7 +40,7 @@ SQL;
]);
$res = $stmt->fetchAll();
if(count($res) == 0 ) return null;
new LegalDocument(
return new LegalDocument(
$res[0]['ID'],
trim($res[0]['Title']),
trim($res[0]['URLSegment']),
@ -70,7 +70,7 @@ SQL;
]);
$res = $stmt->fetchAll();
if(count($res) == 0 ) return null;
new LegalDocument(
return new LegalDocument(
$res[0]['ID'],
trim($res[0]['Title']),
trim($res[0]['URLSegment']),

View File

@ -12,10 +12,12 @@
* limitations under the License.
**/
use App\Services\Model\dto\ExternalUserDTO;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\main\Affiliation;
use models\main\Member;
/**
* Interface IMemberService
* @package App\Services\Model
@ -53,13 +55,10 @@ interface IMemberService
public function deleteRSVP(Member $member, $rsvp_id);
/**
* @param $user_external_id
* @param string $email
* @param string $first_name
* @param string $last_name
* @param ExternalUserDTO $userDTO
* @return Member
*/
public function registerExternalUser($user_external_id, string $email, string $first_name, string $last_name):Member;
public function registerExternalUser(ExternalUserDTO $userDTO):Member;
/**
* @param $user_external_id
@ -104,5 +103,11 @@ interface IMemberService
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function resignFoundationMembership(Member $member):Member;
public function signCommunityMembership(Member $member):Member;
/**
* @param Member $member
* @return void
*/
public function resignMembership(Member $member);
}

View File

@ -16,6 +16,8 @@ use App\Events\NewMember;
use App\Models\Foundation\Main\IGroup;
use App\Models\Foundation\Main\Repositories\ILegalDocumentRepository;
use App\Services\Apis\IExternalUserApi;
use App\Services\Model\dto\ExternalUserDTO;
use DateTime;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use libs\utils\ICacheService;
@ -29,7 +31,6 @@ use models\main\IMemberRepository;
use models\main\IOrganizationRepository;
use models\main\LegalAgreement;
use models\main\Member;
use DateTime;
use models\main\Organization;
use models\summit\ISpeakerRegistrationRequestRepository;
@ -268,23 +269,32 @@ final class MemberService
}
/**
* @param $user_external_id
* @param string $email
* @param string $first_name
* @param string $last_name
* @param ExternalUserDTO $userDTO
* @return Member
* @throws \Exception
*/
public function registerExternalUser($user_external_id, string $email, string $first_name, string $last_name): Member
public function registerExternalUser(ExternalUserDTO $userDTO): Member
{
return $this->tx_service->transaction(function () use ($user_external_id, $email, $first_name, $last_name) {
Log::debug(sprintf("MemberService::registerExternalUser - user_external_id %s email %s first_name %s last_name %s", $user_external_id, $email, $first_name, $last_name));
return $this->tx_service->transaction(function () use ($userDTO) {
Log::debug
(
sprintf
(
"MemberService::registerExternalUser - user_external_id %s email %s first_name %s last_name %s",
$userDTO->getId(),
$userDTO->getEmail(),
$userDTO->getFirstName(),
$userDTO->getLastName()
)
);
$member = new Member();
$member->setActive(true);
$member->setEmailVerified(true);
$member->setEmail($email);
$member->setFirstName($first_name);
$member->setLastName($last_name);
$member->setUserExternalId($user_external_id);
$member->setActive($userDTO->isActive());
$member->setEmailVerified( $userDTO->isEmailVerified());
$member->setEmail($userDTO->getEmail());
$member->setFirstName( $userDTO->getFirstName());
$member->setLastName($userDTO->getLastName());
$member->setUserExternalId($userDTO->getId());
$this->member_repository->add($member, true);
Event::fire(new NewMember($member->getId()));
return $member;
@ -299,6 +309,7 @@ final class MemberService
public function registerExternalUserById($user_external_id): Member
{
return $this->tx_service->transaction(function () use ($user_external_id) {
// get external user from IDP
$user_data = $this->user_ext_api->getUserById($user_external_id);
$email = trim($user_data['email']);
// first by external id due email could be updated
@ -313,8 +324,8 @@ final class MemberService
if(is_null($member)) {
Log::debug(sprintf("MemberService::registerExternalUserById %s does not exists , creating it ...", $email));
$member = new Member();
$member->setActive(true);
$member->setEmailVerified(true);
$member->setActive(boolval($user_data['active']));
$member->setEmailVerified(boolval($user_data['email_verified']));
$member->setEmail($email);
$member->setFirstName(trim($user_data['first_name']));
$member->setLastName(trim($user_data['last_name']));
@ -327,7 +338,8 @@ final class MemberService
}
else {
Log::debug(sprintf("MemberService::registerExternalUserById %s already exists", $email));
$member->setEmailVerified(true);
$member->setActive(boolval($user_data['active']));
$member->setEmailVerified(boolval($user_data['email_verified']));
$member->setEmail($email);
$member->setFirstName(trim($user_data['first_name']));
$member->setLastName(trim($user_data['last_name']));
@ -529,7 +541,7 @@ final class MemberService
/**
* @inheritDoc
*/
public function resignFoundationMembership(Member $member): Member
public function signCommunityMembership(Member $member): Member
{
return $this->tx_service->transaction(function() use($member){
if(!$member->isFoundationMember())
@ -546,4 +558,18 @@ final class MemberService
return $member;
});
}
/**
* @inheritDoc
*/
public function resignMembership(Member $member)
{
return $this->tx_service->transaction(function() use($member){
$member->resignMembership();
$this->member_repository->delete($member);
});
}
}

View File

@ -26,6 +26,7 @@ use App\Models\Foundation\Summit\Factories\SummitOrderFactory;
use App\Models\Foundation\Summit\Registration\IBuildDefaultPaymentGatewayProfileStrategy;
use App\Models\Foundation\Summit\Repositories\ISummitAttendeeBadgePrintRuleRepository;
use App\Models\Foundation\Summit\Repositories\ISummitAttendeeBadgeRepository;
use App\Services\Model\dto\ExternalUserDTO;
use App\Services\Utils\CSVReader;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Event;
@ -1310,10 +1311,15 @@ final class SummitOrderService
// we have an user on idp
$member = $this->member_service->registerExternalUser
(
$user['id'],
$user['email'],
$user['first_name'],
$user['last_name']
new ExternalUserDTO
(
$user['id'],
$user['email'],
$user['first_name'],
$user['last_name'],
boolval($user['active']),
boolval($user['email_verified'])
)
);
// add the order to newly created member
@ -3334,10 +3340,15 @@ final class SummitOrderService
// we have an user on idp
$member = $this->member_service->registerExternalUser
(
$user['id'],
$user['email'],
$user['first_name'],
$user['last_name']
new ExternalUserDTO
(
$user['id'],
$user['email'],
$user['first_name'],
$user['last_name'],
boolval($user['active']),
boolval($user['email_verified'])
)
);
// add the order to newly created member
$member->addSummitRegistrationOrder($order);

View File

@ -18,6 +18,7 @@ use App\Models\Foundation\Summit\Factories\SummitRegistrationInvitationFactory;
use App\Models\Foundation\Summit\Repositories\ISummitRegistrationInvitationRepository;
use App\Services\Apis\IExternalUserApi;
use App\Services\Model\AbstractService;
use App\Services\Model\dto\ExternalUserDTO;
use App\Services\Model\IMemberService;
use App\Services\Model\ISummitRegistrationInvitationService;
use App\Services\Utils\CSVReader;
@ -241,10 +242,15 @@ final class SummitRegistrationInvitationService
// we have an user on idp
$member = $this->member_service->registerExternalUser
(
$user['id'],
$user['email'],
$user['first_name'],
$user['last_name']
new ExternalUserDTO
(
$user['id'],
$user['email'],
$user['first_name'],
$user['last_name'],
boolval($user['active']),
boolval($user['email_verified'])
)
);
}
}

View File

@ -0,0 +1,116 @@
<?php namespace App\Services\Model\dto;
/**
* 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.
**/
/**
* Class ExternalUserDTO
* @package App\Services\Model\dto
*/
class ExternalUserDTO
{
private $id;
/**
* @var string
*/
private $email;
/**
* @var string
*/
private $first_name;
/**
* @var string
*/
private $last_name;
/**
* @var bool
*/
private $active;
/**
* @var bool
*/
private $email_verified;
/**
* ExternalUserDTO constructor.
* @param $id
* @param string $email
* @param string $first_name
* @param string $last_name
* @param bool $active
* @param bool $email_verified
*/
public function __construct($id, string $email, string $first_name, string $last_name, bool $active = false, bool $email_verified = false)
{
$this->id = $id;
$this->email = $email;
$this->first_name = $first_name;
$this->last_name = $last_name;
$this->active = $active;
$this->email_verified = $email_verified;
}
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getEmail(): ?string
{
return $this->email;
}
/**
* @return string
*/
public function getFirstName(): ?string
{
return $this->first_name;
}
/**
* @return string
*/
public function getLastName(): ?string
{
return $this->last_name;
}
/**
* @return bool
*/
public function isActive(): bool
{
return $this->active;
}
/**
* @return bool
*/
public function isEmailVerified(): bool
{
return $this->email_verified;
}
}

View File

@ -5451,11 +5451,17 @@ class ApiEndpointsSeeder extends Seeder
'scopes' => [sprintf(MemberScopes::WriteMyMemberData, $current_realm)],
],
[
'name' => 'resign-foundation-membership',
'name' => 'sign-community-membership',
'route' => '/api/v1/members/me/membership/community',
'http_method' => 'PUT',
'scopes' => [sprintf(MemberScopes::WriteMyMemberData, $current_realm)],
],
[
'name' => 'resign-membership',
'route' => '/api/v1/members/me/membership/resign',
'http_method' => 'DELETE',
'scopes' => [sprintf(MemberScopes::WriteMyMemberData, $current_realm)],
],
// my member affiliations
[
'name' => 'get-my-member-affiliations',