
Minimal data required title ( text ) abstract (text ) type_id (int) or type (string type name) track_id (int) or track ( string track name) Optional fields social_summary ( text ) attendees_expected_learnt ( text ) * provided only if event is presentation type location (id or name) level (text possible values [N/A, Beginner, Intermediate, Advanced]) * provided only if event is presentation type allow_feedback (int possible values [0,1]) to_record (int possible values [0,1]) tags ( repetitive group: values | delimited) sponsors ( repetitive group : names | delimited ) speakers ( repetitive group: emails | delimited ) start_date (mandatory if is_published is 1) Y-m-d H:i:s format ( summit time zone ) end_date (mandatory if is_published is 1) Y-m-d H:i:s format ( summit time zone ) is_published (int possible values [0,1]) , if this field is set 1 start_date and end_date are mandatories selection_plan (string selection plan name) * provided only if event is presentation type attendees_expected_learnt ( text , only presentations) problem_addressed ( text , only presentations) added endpoint POST /api/v1/summits/{summit_id}/events/csv multipart/form-data * Expected params file send_speaker_email Change-Id: I245d4e1a22e2c5e3c4120c559d0ecb4a5a021c78 Signed-off-by: smarcet <smarcet@gmail.com>
491 lines
20 KiB
PHP
491 lines
20 KiB
PHP
<?php namespace App\Services\Model;
|
|
/**
|
|
* Copyright 2018 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 App\Events\NewMember;
|
|
use App\Models\Foundation\Main\IGroup;
|
|
use App\Services\Apis\IExternalUserApi;
|
|
use Illuminate\Support\Facades\Event;
|
|
use Illuminate\Support\Facades\Log;
|
|
use libs\utils\ICacheService;
|
|
use libs\utils\ITransactionService;
|
|
use models\exceptions\EntityNotFoundException;
|
|
use models\exceptions\ValidationException;
|
|
use models\main\Affiliation;
|
|
use models\main\Group;
|
|
use models\main\IGroupRepository;
|
|
use models\main\IMemberRepository;
|
|
use models\main\IOrganizationRepository;
|
|
use models\main\Member;
|
|
use DateTime;
|
|
use models\main\Organization;
|
|
use models\summit\ISpeakerRegistrationRequestRepository;
|
|
|
|
/**
|
|
* Class MemberService
|
|
* @package App\Services\Model
|
|
*/
|
|
final class MemberService
|
|
extends AbstractService
|
|
implements IMemberService
|
|
{
|
|
|
|
// in secs
|
|
const SYNCH_GROUPS_TTL = 60;
|
|
/**
|
|
* @var ICacheService
|
|
*/
|
|
private $cache_service;
|
|
|
|
/**
|
|
* @var IOrganizationRepository
|
|
*/
|
|
private $organization_repository;
|
|
|
|
/**
|
|
* @var IMemberRepository
|
|
*/
|
|
private $member_repository;
|
|
|
|
/**
|
|
* @var IExternalUserApi
|
|
*/
|
|
private $user_ext_api;
|
|
|
|
/**
|
|
* @var IGroupRepository
|
|
*/
|
|
private $group_repository;
|
|
|
|
/**
|
|
* @var IExternalUserApi
|
|
*/
|
|
private $external_user_api;
|
|
|
|
/**
|
|
* @var ISpeakerRegistrationRequestRepository
|
|
*/
|
|
private $speaker_registration_request_repository;
|
|
|
|
/**
|
|
* MemberService constructor.
|
|
* @param IMemberRepository $member_repository
|
|
* @param IOrganizationRepository $organization_repository
|
|
* @param IExternalUserApi $user_ext_api
|
|
* @param IGroupRepository $group_repository
|
|
* @param ICacheService $cache_service
|
|
* @param IExternalUserApi $external_user_api
|
|
* @param ISpeakerRegistrationRequestRepository $speaker_registration_request_repository
|
|
* @param ITransactionService $tx_service
|
|
*/
|
|
public function __construct
|
|
(
|
|
IMemberRepository $member_repository,
|
|
IOrganizationRepository $organization_repository,
|
|
IExternalUserApi $user_ext_api,
|
|
IGroupRepository $group_repository,
|
|
ICacheService $cache_service,
|
|
IExternalUserApi $external_user_api,
|
|
ISpeakerRegistrationRequestRepository $speaker_registration_request_repository,
|
|
ITransactionService $tx_service
|
|
)
|
|
{
|
|
parent::__construct($tx_service);
|
|
$this->organization_repository = $organization_repository;
|
|
$this->member_repository = $member_repository;
|
|
$this->user_ext_api = $user_ext_api;
|
|
$this->group_repository = $group_repository;
|
|
$this->cache_service = $cache_service;
|
|
$this->external_user_api = $external_user_api;
|
|
$this->speaker_registration_request_repository = $speaker_registration_request_repository;
|
|
}
|
|
|
|
/**
|
|
* @param Member $member
|
|
* @param int $affiliation_id
|
|
* @param array $data
|
|
* @return Affiliation
|
|
*/
|
|
public function updateAffiliation(Member $member, $affiliation_id, array $data)
|
|
{
|
|
return $this->tx_service->transaction(function () use ($member, $affiliation_id, $data) {
|
|
$affiliation = $member->getAffiliationById($affiliation_id);
|
|
if (is_null($affiliation))
|
|
throw new EntityNotFoundException(sprintf("affiliation id %s does not belongs to member id %s", $affiliation_id, $member->getId()));
|
|
|
|
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 (!$affiliation->isCurrent() && 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['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']));
|
|
}
|
|
|
|
if ($affiliation->isCurrent()) {
|
|
$affiliation->clearEndDate();
|
|
}
|
|
|
|
return $affiliation;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param Member $member
|
|
* @param $affiliation_id
|
|
* @return void
|
|
*/
|
|
public function deleteAffiliation(Member $member, $affiliation_id)
|
|
{
|
|
return $this->tx_service->transaction(function () use ($member, $affiliation_id) {
|
|
$affiliation = $member->getAffiliationById($affiliation_id);
|
|
if (is_null($affiliation))
|
|
throw new EntityNotFoundException(sprintf("affiliation id %s does not belongs to member id %s", $affiliation_id, $member->getId()));
|
|
|
|
$member->removeAffiliation($affiliation);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param Member $member
|
|
* @param int $rsvp_id
|
|
* @return void
|
|
*/
|
|
public function deleteRSVP(Member $member, $rsvp_id)
|
|
{
|
|
return $this->tx_service->transaction(function () use ($member, $rsvp_id) {
|
|
$rsvp = $member->getRsvpById($rsvp_id);
|
|
if (is_null($rsvp))
|
|
throw new EntityNotFoundException(sprintf("rsvp id %s does not belongs to member id %s", $rsvp_id, $member->getId()));
|
|
|
|
$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['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']));
|
|
}
|
|
|
|
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;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param $user_external_id
|
|
* @param string $email
|
|
* @param string $first_name
|
|
* @param string $last_name
|
|
* @return Member
|
|
*/
|
|
public function registerExternalUser($user_external_id, string $email, string $first_name, string $last_name): 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));
|
|
$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);
|
|
$this->member_repository->add($member, true);
|
|
Event::fire(new NewMember($member->getId()));
|
|
return $member;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param $user_external_id
|
|
* @return Member
|
|
* @throws \Exception
|
|
*/
|
|
public function registerExternalUserById($user_external_id): Member
|
|
{
|
|
return $this->tx_service->transaction(function () use ($user_external_id) {
|
|
$user_data = $this->user_ext_api->getUserById($user_external_id);
|
|
$email = trim($user_data['email']);
|
|
// first by external id due email could be updated
|
|
Log::debug(sprintf("MemberService::registerExternalUserById trying to get user by external id %s", $user_external_id));
|
|
$member = $this->member_repository->getByExternalIdExclusiveLock(intval($user_external_id));
|
|
// if we dont registered yet a member with that external id try to get by email
|
|
if(is_null($member)) {
|
|
Log::debug(sprintf("MemberService::registerExternalUserById trying to get user by email %s", $email));
|
|
$member = $this->member_repository->getByEmail($email);
|
|
}
|
|
$is_new = false;
|
|
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->setEmail($email);
|
|
$member->setFirstName(trim($user_data['first_name']));
|
|
$member->setLastName(trim($user_data['last_name']));
|
|
$member->setBio($user_data['bio']);
|
|
$member->setUserExternalId($user_external_id);
|
|
if(isset($user_data['pic']))
|
|
$member->setExternalPic($user_data['pic']);
|
|
$this->member_repository->add($member, true);
|
|
$is_new = true;
|
|
}
|
|
else {
|
|
Log::debug(sprintf("MemberService::registerExternalUserById %s already exists", $email));
|
|
$member->setEmailVerified(true);
|
|
$member->setEmail($email);
|
|
$member->setFirstName(trim($user_data['first_name']));
|
|
$member->setLastName(trim($user_data['last_name']));
|
|
$member->setBio($user_data['bio']);
|
|
if(isset($user_data['pic']))
|
|
$member->setExternalPic($user_data['pic']);
|
|
$member->setUserExternalId($user_external_id);
|
|
}
|
|
|
|
$this->synchronizeGroups($member, $user_data['groups']);
|
|
// check speaker registration request by email and no member set
|
|
Log::debug(sprintf("MemberService::registerExternalUserById trying to get former registration request by email %s", $email));
|
|
$request = $this->speaker_registration_request_repository->getByEmail($email);
|
|
if(!is_null($request)){
|
|
Log::debug(sprintf("MemberService::registerExternalUserById got former registration request by email %s", $email));
|
|
$speaker = $request->getSpeaker();
|
|
if(!is_null($speaker))
|
|
if(!$speaker->hasMember()) {
|
|
Log::debug(sprintf("MemberService::registerExternalUserById setting current member to speaker %s", $speaker->getId()));
|
|
$speaker->setMember($member);
|
|
}
|
|
}
|
|
if($is_new)
|
|
Event::fire(new NewMember($member->getId()));
|
|
|
|
return $member;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param Member $member
|
|
* @param array $groups
|
|
* @return Member
|
|
* @throws \Exception
|
|
*/
|
|
public function synchronizeGroups(Member $member, array $groups): Member
|
|
{
|
|
return $this->tx_service->transaction(function () use ($member, $groups) {
|
|
|
|
$val = $this->cache_service->getSingleValue(sprintf("member_%s_sync_groups", $member->getId()));
|
|
|
|
if(!empty($val)){
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s synch already done", $member->getId(), $member->getEmail()));
|
|
return $member;
|
|
}
|
|
|
|
$groups2Remove = [];
|
|
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s", $member->getId(), $member->getEmail()));
|
|
|
|
foreach($member->getGroups() as $group){
|
|
// if this group was added from idp, clear it, just in case we were deleted from that group
|
|
if(!in_array($group->getCode(), $groups)){
|
|
// do not remove if we are super admins, since we do need this group too ( backward compatibility with SS CMS)
|
|
if($group->getCode() == IGroup::Administrators && in_array(IGroup::SuperAdmins, $groups))
|
|
continue;
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s marking group %s to remove (external) dues is not on member current groups", $member->getId(), $member->getEmail(), $group->getCode()));
|
|
$groups2Remove[] = $group;
|
|
}
|
|
}
|
|
|
|
// remove all groups that arent on our IDP profile anymore ...
|
|
foreach ($groups2Remove as $externalGroup){
|
|
if($externalGroup->getCode() === IGroup::SuperAdmins && $member->belongsToGroup(IGroup::Administrators)){
|
|
$group = $this->group_repository->getBySlug(IGroup::Administrators);
|
|
if(!is_null($group)) {
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s removing from group %s due is also a super admin", $member->getId(), $member->getEmail(), $group->getCode()));
|
|
$member->removeFromGroup($group);
|
|
}
|
|
}
|
|
$member->removeFromGroup($externalGroup);
|
|
}
|
|
|
|
// sync
|
|
|
|
foreach ($groups as $code) {
|
|
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s processing group code %s", $member->getId(), $member->getEmail(), $code));
|
|
|
|
if(!$member->belongsToGroup($code)){
|
|
$group = $this->group_repository->getBySlug($code);
|
|
if (is_null($group)) {
|
|
// create it
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s - group %s does not exists!, .. creating it ", $member->getId(), $member->getEmail(), $code));
|
|
$group = new Group();
|
|
$group->setCode($code);
|
|
$group->setExternal();
|
|
$group->setDescription($code);
|
|
$group->setTitle($code);
|
|
$this->group_repository->add($group, true);
|
|
}
|
|
$group->setExternal();
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s adding to group %s", $member->getId(), $member->getEmail(), $code));
|
|
$member->add2Group($group);
|
|
}
|
|
|
|
// map from super admin to admin ( special case )
|
|
if ($code === IGroup::SuperAdmins) {
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s is on group %s, should be added to group %s", $member->getId(), $member->getEmail(), $code, IGroup::Administrators));
|
|
if(!$member->belongsToGroup(IGroup::Administrators)) {
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s is not on group %s", $member->getId(), $member->getEmail(), IGroup::Administrators));
|
|
$group = $this->group_repository->getBySlug(IGroup::Administrators);
|
|
if (is_null($group)) {
|
|
// create it
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s - group %s does not exists!, .. creating it ", $member->getId(), $member->getEmail(), $code));
|
|
$group = new Group();
|
|
$group->setCode(IGroup::Administrators);
|
|
$group->setDescription(IGroup::Administrators);
|
|
$group->setTitle(IGroup::Administrators);
|
|
$this->group_repository->add($group, true);
|
|
}
|
|
$group->setExternal();
|
|
Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s adding to group %s", $member->getId(), $member->getEmail(), $group->getCode()));
|
|
$member->add2Group($group);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
$this->cache_service->setSingleValue(sprintf("member_%s_sync_groups", $member->getId()), 1, self::SYNCH_GROUPS_TTL);
|
|
return $member;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param string $email
|
|
* @return array|null
|
|
* @throws \Exception
|
|
*/
|
|
public function checkExternalUser(string $email) {
|
|
Log::debug(sprintf("MemberService::checkExternalUser - trying to get member %s from user api", $email));
|
|
$user = $this->external_user_api->getUserByEmail($email);
|
|
// check if primary email is the same if not disregard
|
|
Log::debug(sprintf("MemberService::checkExternalUser got entity %s for email %s", json_encode($user), $email));
|
|
$primary_email = $user['email'] ?? null;
|
|
if (strcmp(strtolower($primary_email), strtolower($email)) !== 0) {
|
|
Log::debug
|
|
(
|
|
sprintf
|
|
(
|
|
"MemberService::checkExternalUser primary email %s differs from original email %s",
|
|
$primary_email,
|
|
$email
|
|
)
|
|
);
|
|
|
|
// email are not equals , then is not the user bc primary emails differs ( could be a
|
|
// match on a secondary email)
|
|
$user = null; // set null on user and proceed to emit a registration request.
|
|
}
|
|
|
|
return $user;
|
|
}
|
|
|
|
/**
|
|
* @param string $email
|
|
* @param string $first_name
|
|
* @param string $last_name
|
|
* @return array
|
|
* @throws \Exception
|
|
*/
|
|
public function emitRegistrationRequest(string $email, string $first_name, string $last_name):array{
|
|
// user does not exists , emit a registration request
|
|
return $this->external_user_api->registerUser
|
|
(
|
|
$email,
|
|
$first_name,
|
|
$last_name
|
|
);
|
|
}
|
|
} |