Added Virtual badge scan feature

endpoint

POST api/v1/summits/{id}/sponsors/{sponsor_id}/user-info-grants/me

scopes

REALM_URL/%s/summits/badge-scans/write/me

Change-Id: I693fc0ff69e21f44849946b83e0df22a03d904a5
Signed-off-by: smarcet <smarcet@gmail.com>
This commit is contained in:
smarcet 2020-10-15 16:41:43 -03:00
parent 7d4ac0f9de
commit 518feb0efb
22 changed files with 575 additions and 80 deletions

View File

@ -13,11 +13,14 @@
**/
use App\Http\Exceptions\HTTP403ForbiddenException;
use App\Http\Utils\EpochCellFormatter;
use App\Services\Model\ISponsorBadgeScanService;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use models\exceptions\EntityNotFoundException;
use models\summit\ISponsorUserInfoGrantRepository;
use Illuminate\Support\Facades\Input;
use models\exceptions\ValidationException;
use models\oauth2\IResourceServerContext;
use models\summit\ISponsorBadgeScanRepository;
use App\Services\Model\ISponsorUserInfoGrantService;
use models\summit\ISummitRepository;
use models\summit\Summit;
use models\utils\IEntity;
@ -32,7 +35,7 @@ final class OAuth2SummitBadgeScanApiController
extends OAuth2ProtectedController
{
/**
* @var ISponsorBadgeScanService
* @var ISponsorUserInfoGrantService
*/
private $service;
@ -43,17 +46,17 @@ final class OAuth2SummitBadgeScanApiController
/**
* OAuth2SummitBadgeScanApiController constructor.
* @param ISponsorBadgeScanRepository $repository
* @param ISponsorUserInfoGrantRepository $repository
* @param ISummitRepository $summit_repository
* @param IResourceServerContext $resource_server_context
* @param ISponsorBadgeScanService $service
* @param ISponsorUserInfoGrantService $service
*/
public function __construct
(
ISponsorBadgeScanRepository $repository,
ISponsorUserInfoGrantRepository $repository,
ISummitRepository $summit_repository,
IResourceServerContext $resource_server_context,
ISponsorBadgeScanService $service
ISponsorUserInfoGrantService $service
)
{
parent::__construct($resource_server_context);
@ -89,6 +92,49 @@ final class OAuth2SummitBadgeScanApiController
return $this->service->addBadgeScan($summit, $current_member, $payload);
}
/**
* @param $summit_id
* @param $sponsor_id
* @return \Illuminate\Http\JsonResponse|mixed
*/
public function addGrant($summit_id, $sponsor_id){
try{
$summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id);
if (is_null($summit)) return $this->error404();
$current_member = $this->resource_server_context->getCurrentUser();
if (is_null($current_member)) throw new HTTP403ForbiddenException();
$grant = $this->service->addGrant($summit, intval($sponsor_id), $current_member);
return $this->created(SerializerRegistry::getInstance()->getSerializer
(
$grant,
$this->addSerializerType()
)->serialize(Request::input('expand', '')));
}
catch (ValidationException $ex) {
Log::warning($ex);
return $this->error412(array($ex->getMessage()));
}
catch(EntityNotFoundException $ex)
{
Log::warning($ex);
return $this->error404(array('message'=> $ex->getMessage()));
}
catch (\HTTP401UnauthorizedException $ex) {
Log::warning($ex);
return $this->error401();
}
catch (HTTP403ForbiddenException $ex) {
Log::warning($ex);
return $this->error403();
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
/**
* @return ISummitRepository
*/

View File

@ -692,6 +692,9 @@ Route::group([
Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@getAllBySummit']);
Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@add']);
Route::group(['prefix' => '{sponsor_id}'], function () {
Route::group(['prefix' => 'user-info-grants'], function () {
Route::post('me', ['uses' => 'OAuth2SummitBadgeScanApiController@addGrant']);
});
Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@get']);
Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@update']);
Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@delete']);
@ -745,9 +748,8 @@ Route::group([
});
});
// badge-feature-types
// badge-scans
Route::group(['prefix' => 'badge-scans'], function () {
Route::get('me','OAuth2SummitBadgeScanApiController@getAllMyBadgeScans' );
Route::get('', 'OAuth2SummitBadgeScanApiController@getAllBySummit');
Route::get('csv','OAuth2SummitBadgeScanApiController@getAllBySummitCSV');

View File

@ -11,7 +11,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\ModelSerializers\CCLA\TeamSerializer;
use App\ModelSerializers\FileSerializer;
use App\ModelSerializers\ISummitAttendeeTicketSerializerTypes;
@ -65,6 +64,7 @@ use App\ModelSerializers\Summit\Registration\SummitAttendeeCSVSerializer;
use App\ModelSerializers\Summit\Registration\SummitAttendeeTicketCSVSerializer;
use App\ModelSerializers\Summit\SponsorBadgeScanCSVSerializer;
use App\ModelSerializers\Summit\SponsorBadgeScanSerializer;
use App\ModelSerializers\Summit\SponsorUserInfoGrantSerializer;
use App\ModelSerializers\Summit\StripePaymentProfileSerializer;
use App\ModelSerializers\Summit\SummitAttendeeBadgeSerializer;
use App\ModelSerializers\Summit\RSVP\Templates\RSVPDropDownQuestionTemplateSerializer;
@ -298,11 +298,17 @@ final class SerializerRegistry
];
$this->registry['SummitAttendeeBadge'] = SummitAttendeeBadgeSerializer::class;
$this->registry['SponsorBadgeScan'] = [
self::SerializerType_Public => SponsorBadgeScanSerializer::class,
self::SerializerType_CSV => SponsorBadgeScanCSVSerializer::class,
];
$this->registry['SponsorUserInfoGrant'] = [
self::SerializerType_Public => SponsorUserInfoGrantSerializer::class,
self::SerializerType_CSV => SponsorUserInfoGrantSerializer::class,
];
$this->registry['SummitAttendeeTicketTax'] = SummitAttendeeTicketTaxSerializer::class;
// summit sponsors

View File

@ -25,8 +25,12 @@ final class SponsorBadgeScanCSVSerializer extends AbstractSerializer
'ScanDate' => 'scan_date:datetime_epoch',
'QRCode' => 'qr_code:json_string',
'SponsorId' => 'sponsor_id:json_int',
'UserId' => 'user_id:json_int',
'UserId' => 'scanned_by_id:json_int',
'BadgeId' => 'badge_id:json_int',
'AttendeeFirstName' => 'attendee_first_name:json_string',
'AttendeeLastName' => 'attendee_last_name:json_string',
'AttendeeEmail' => 'attendee_email:json_string',
'AttendeeCompany' => 'attendee_company:json_string',
];
/**
@ -41,13 +45,6 @@ final class SponsorBadgeScanCSVSerializer extends AbstractSerializer
$scan = $this->object;
if (!$scan instanceof SponsorBadgeScan) return [];
$values = parent::serialize($expand, $fields, $relations, $params);
$attendee = $scan->getBadge()->getTicket()->getOwner();
$values['attendee_first_name'] = $attendee->hasMember() ? $attendee->getMember()->getFirstName() : $attendee->getFirstName();
$values['attendee_last_name'] = $attendee->hasMember() ? $attendee->getMember()->getLastName() :$attendee->getSurname();
$values['attendee_email'] = $attendee->getEmail();
$values['attendee_company'] = $attendee->getCompanyName();
return $values;
}
}

View File

@ -22,11 +22,12 @@ use ModelSerializers\SilverStripeSerializer;
final class SponsorBadgeScanSerializer extends SilverStripeSerializer
{
protected static $array_mappings = [
'ScanDate' => 'scan_date:datetime_epoch',
'QRCode' => 'qr_code:json_string',
'SponsorId' => 'sponsor_id:json_int',
'UserId' => 'user_id:json_int',
'UserId' => 'scanned_by_id:json_int',
'BadgeId' => 'badge_id:json_int',
];
@ -53,10 +54,10 @@ final class SponsorBadgeScanSerializer extends SilverStripeSerializer
$values['sponsor'] = SerializerRegistry::getInstance()->getSerializer($scan->getSponsor())->serialize(AbstractSerializer::filterExpandByPrefix($expand, "sponsor"));
}
break;
case 'user': {
case 'scanned_by_id': {
if(!$scan->hasUser()) continue;
unset($values['user_id']);
$values['user'] = SerializerRegistry::getInstance()->getSerializer($scan->getUser())->serialize(AbstractSerializer::filterExpandByPrefix($expand, "user"));
unset($values['scanned_by_id']);
$values['scanned_by'] = SerializerRegistry::getInstance()->getSerializer($scan->getUser())->serialize(AbstractSerializer::filterExpandByPrefix($expand, "user"));
}
break;
case 'badge': {

View File

@ -0,0 +1,30 @@
<?php namespace App\ModelSerializers\Summit;
/**
* Copyright 2020 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 ModelSerializers\SilverStripeSerializer;
/**
* Class SponsorUserInfoGrantSerializer
* @package App\ModelSerializers\Summit
*/
class SponsorUserInfoGrantSerializer extends SilverStripeSerializer
{
protected static $array_mappings = [
'CreatedDate' => 'scan_date:datetime_epoch',
'SponsorId' => 'sponsor_id:json_int',
'AllowedUserId' => 'allowed_user_id:json_int',
'AttendeeFirstName' => 'attendee_first_name:json_string',
'AttendeeLastName' => 'attendee_last_name:json_string',
'AttendeeEmail' => 'attendee_email:json_string',
'AttendeeCompany' => 'attendee_company:json_string',
];
}

View File

@ -0,0 +1,56 @@
<?php namespace App\Models\Foundation\Summit\Factories;
/**
* Copyright 2020 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 models\summit\SponsorBadgeScan;
use models\summit\SponsorUserInfoGrant;
/**
* Class SponsorUserInfoGrant
* @package App\Models\Foundation\Summit\SponsorUserInfoGrantFactory
*/
final class SponsorUserInfoGrantFactory
{
/**
* @param array $payload
* @return SponsorUserInfoGrant
*/
public static function build(array $payload):SponsorUserInfoGrant {
$grant = null;
$class_name = $payload['class_name'];
switch($class_name){
case SponsorUserInfoGrant::class:
$grant = self::populate(new SponsorUserInfoGrant, $payload);
break;
case SponsorBadgeScan::class:
$grant = self::populate(new SponsorBadgeScan, $payload);
break;
}
return $grant;
}
/**
* @param SponsorUserInfoGrant $grant
* @param array $payload
* @return SponsorUserInfoGrant
*/
public static function populate(SponsorUserInfoGrant $grant, array $payload):SponsorUserInfoGrant{
$class_name = $payload['class_name'];
switch($class_name){
case SponsorUserInfoGrant::class:
break;
case SponsorBadgeScan::class:
break;
}
return $grant;
}
}

View File

@ -13,28 +13,26 @@
**/
use models\main\Member;
use models\utils\One2ManyPropertyTrait;
use models\utils\SilverstripeBaseModel;
use Doctrine\ORM\Mapping AS ORM;
/**
* @ORM\Entity(repositoryClass="App\Repositories\Summit\DoctrineSponsorBadgeScanRepository")
* @ORM\Entity
* @ORM\Table(name="SponsorBadgeScan")
* Class SponsorBadgeScan
* @package models\summit
*/
class SponsorBadgeScan extends SilverstripeBaseModel
class SponsorBadgeScan extends SponsorUserInfoGrant
{
const ClassName = 'SponsorBadgeScan';
use One2ManyPropertyTrait;
protected $getIdMappings = [
'getSponsorId' => 'sponsor',
'getUserId' => 'user',
'getBadgeId' => 'badge',
];
protected $hasPropertyMappings = [
'hasSponsor' => 'sponsor',
'hasUser' => 'user',
'hasBadge' => 'badge',
];
@ -45,13 +43,6 @@ class SponsorBadgeScan extends SilverstripeBaseModel
*/
private $qr_code;
/**
* @ORM\ManyToOne(targetEntity="models\summit\Sponsor", inversedBy="badge_scans")
* @ORM\JoinColumn(name="SponsorID", referencedColumnName="ID")
* @var Sponsor
*/
private $sponsor;
/**
* @var \DateTime
* @ORM\Column(name="ScanDate", type="datetime")
@ -152,4 +143,24 @@ class SponsorBadgeScan extends SilverstripeBaseModel
$this->scan_date = $scan_date;
}
public function getAttendeeFirstName():?string{
$attendee = $this->getBadge()->getTicket()->getOwner();
return $attendee->hasMember() ? $attendee->getMember()->getFirstName() : $attendee->getFirstName();
}
public function getAttendeeLastName():?string{
$attendee = $this->getBadge()->getTicket()->getOwner();
return $attendee->hasMember() ? $attendee->getMember()->getLastName() :$attendee->getSurname();
}
public function getAttendeeEmail():?string{
$attendee = $this->getBadge()->getTicket()->getOwner();
return $attendee->getEmail();
}
public function getAttendeeCompany():?string{
$attendee = $this->getBadge()->getTicket()->getOwner();
$attendee->getCompanyName();
}
}

View File

@ -0,0 +1,102 @@
<?php namespace models\summit;
/**
* Copyright 2020 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 models\utils\SilverstripeBaseModel;
use models\main\Member;
use models\utils\One2ManyPropertyTrait;
use Doctrine\ORM\Mapping AS ORM;
/**
* @ORM\Entity(repositoryClass="App\Repositories\Summit\DoctrineSponsorUserInfoGrantRepository")
* @ORM\Table(name="SponsorUserInfoGrant")
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="ClassName", type="string")
* @ORM\DiscriminatorMap({
* "SponsorUserInfoGrant" = "SponsorUserInfoGrant",
* "SponsorBadgeScan" = "SponsorBadgeScan"
* })
* Class SponsorUserInfoGrant
* @package models\summit
*/
class SponsorUserInfoGrant extends SilverstripeBaseModel
{
use One2ManyPropertyTrait;
const ClassName = 'SponsorUserInfoGrant';
/**
* @ORM\ManyToOne(targetEntity="models\summit\Sponsor", inversedBy="badge_scans")
* @ORM\JoinColumn(name="SponsorID", referencedColumnName="ID")
* @var Sponsor
*/
protected $sponsor;
/**
* @ORM\ManyToOne(targetEntity="models\main\Member")
* @ORM\JoinColumn(name="AllowedUserID", referencedColumnName="ID")
* @var Member|null
*/
protected $allowed_user;
protected $getIdMappings = [
'getSponsorId' => 'sponsor',
'getAllowedUserId' => 'allowed_user',
];
protected $hasPropertyMappings = [
'hasSponsor' => 'sponsor',
'hasAllowedUser' => 'allowed_user',
];
/**
* @return Sponsor
*/
public function getSponsor(): Sponsor
{
return $this->sponsor;
}
/**
* @param Sponsor $sponsor
*/
public function setSponsor(Sponsor $sponsor): void
{
$this->sponsor = $sponsor;
}
/**
* @return Member|null
*/
public function getAllowedUser(): ?Member
{
return $this->allowed_user;
}
/**
* @param Member|null $allowed_user
*/
public function setAllowedUser(?Member $allowed_user): void
{
$this->allowed_user = $allowed_user;
}
public function getAttendeeFirstName():?string{
return $this->allowed_user->getFirstName();
}
public function getAttendeeLastName():?string{
return $this->allowed_user->getLastName();
}
public function getAttendeeEmail():?string{
return $this->allowed_user->getEmail();
}
}

View File

@ -13,10 +13,10 @@
**/
use models\utils\IBaseRepository;
/**
* Interface ISponsorBadgeScanRepository
* Interface ISponsorUserInfoGrantRepository
* @package models\summit
*/
interface ISponsorBadgeScanRepository extends IBaseRepository
interface ISponsorUserInfoGrantRepository extends IBaseRepository
{
}

View File

@ -13,6 +13,7 @@
**/
use App\Models\Foundation\Main\IOrderable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping AS ORM;
use models\main\Company;
use models\main\Member;
@ -54,10 +55,10 @@ class Sponsor extends SilverstripeBaseModel implements IOrderable
protected $sponsorship;
/**
* @ORM\OneToMany(targetEntity="SponsorBadgeScan", mappedBy="sponsor", cascade={"persist"}, orphanRemoval=true)
* @var SponsorBadgeScan[]
* @ORM\OneToMany(targetEntity="SponsorUserInfoGrant", mappedBy="sponsor", cascade={"persist"}, orphanRemoval=true)
* @var SponsorUserInfoGrant[]
*/
protected $badge_scans;
protected $user_info_grants;
/**
* @ORM\ManyToMany(targetEntity="models\main\Member", inversedBy="sponsor_memberships")
@ -76,7 +77,7 @@ class Sponsor extends SilverstripeBaseModel implements IOrderable
{
parent::__construct();
$this->members = new ArrayCollection();
$this->badge_scans = new ArrayCollection();
$this->user_info_grants = new ArrayCollection();
}
/**
@ -164,16 +165,27 @@ class Sponsor extends SilverstripeBaseModel implements IOrderable
}
/**
* @param SponsorBadgeScan $scan
* @param SponsorUserInfoGrant $grant
*/
public function addBadgeScan(SponsorBadgeScan $scan){
if($this->badge_scans->contains($scan)) return;
$this->badge_scans->add($scan);
$scan->setSponsor($this);
public function addUserInfoGrant(SponsorUserInfoGrant $grant){
if($this->user_info_grants->contains($grant)) return;
$this->user_info_grants->add($grant);
$grant->setSponsor($this);
}
public function getScans(){
return $this->badge_scans;
public function getUserInfoGrants(){
return $this->user_info_grants;
}
/**
* @param Member $member
* @return bool
*/
public function hasGrant(Member $member):bool {
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->eq('allowed_user', $member));
$grant = $this->user_info_grants->matching($criteria)->first();
return $grant !== false;
}
public function hasCompany():bool{

View File

@ -71,7 +71,7 @@ use models\main\Group;
use models\main\IOrganizationRepository;
use models\main\Organization;
use models\main\SummitAdministratorPermissionGroup;
use models\summit\ISponsorBadgeScanRepository;
use models\summit\ISponsorUserInfoGrantRepository;
use models\summit\ISummitRegistrationPromoCodeRepository;
use models\summit\ISummitTicketTypeRepository;
use models\summit\PaymentGatewayProfile;
@ -85,6 +85,7 @@ use models\summit\SpeakerSummitRegistrationPromoCode;
use models\summit\Sponsor;
use models\summit\SponsorBadgeScan;
use models\summit\SponsorshipType;
use models\summit\SponsorUserInfoGrant;
use models\summit\SummitAbstractLocation;
use models\summit\SummitAccessLevelType;
use models\summit\SummitAttendeeBadge;
@ -541,9 +542,9 @@ final class RepositoriesProvider extends ServiceProvider
);
App::singleton(
ISponsorBadgeScanRepository::class,
ISponsorUserInfoGrantRepository::class,
function(){
return EntityManager::getRepository(SponsorBadgeScan::class);
return EntityManager::getRepository(SponsorUserInfoGrant::class);
}
);

View File

@ -13,17 +13,17 @@
**/
use App\Repositories\SilverStripeDoctrineRepository;
use Doctrine\ORM\QueryBuilder;
use models\summit\ISponsorBadgeScanRepository;
use models\summit\ISponsorUserInfoGrantRepository;
use models\summit\SponsorBadgeScan;
use models\summit\SponsorUserInfoGrant;
use utils\DoctrineFilterMapping;
/**
* Class DoctrineSponsorBadgeScanRepository
* Class DoctrineSponsorUserInfoGrantRepository
* @package App\Repositories\Summit
*/
final class DoctrineSponsorBadgeScanRepository
final class DoctrineSponsorUserInfoGrantRepository
extends SilverStripeDoctrineRepository
implements ISponsorBadgeScanRepository
implements ISponsorUserInfoGrantRepository
{
/**
@ -65,16 +65,16 @@ final class DoctrineSponsorBadgeScanRepository
{
return [
'id' => 'e.id',
'scan_date' => 'e.scan_date',
'scan_date' => 'sbs.scan_date',
'created' => 'e.created',
'ticket_number' => "t.number",
'order_number' => "ord.order_number",
'sponsor_id' => "sp.id",
'attendee_company' => 'o.company_name',
"attendee_full_name" => "LOWER(CONCAT(o.first_name, ' ', o.surname))",
'attendee_first_name' => 'o.first_name',
'attendee_last_name' => 'o.surname',
'attendee_email' => 'o.email',
"attendee_full_name" => "(LOWER(CONCAT(o.first_name, ' ', o.surname)) OR LOWER(CONCAT(au.first_name, ' ', au.last_name)))",
'attendee_first_name' => 'o.first_name OR au.first_name',
'attendee_last_name' => 'o.surname OR au.last_name',
'attendee_email' => 'o.email OR au.email',
];
}
@ -86,8 +86,10 @@ final class DoctrineSponsorBadgeScanRepository
$query = $query->join('e.sponsor', 'sp')
->join('sp.summit', 's')
->join('sp.company', 'c')
->join('e.user', 'u')
->join('e.badge', 'b')
->leftJoin('e.allowed_user', 'au')
->leftJoin(SponsorBadgeScan::class, 'sbs', 'WITH', 'e.id = sbs.id')
->join('sbs.user', 'u')
->join('sbs.badge', 'b')
->join('b.ticket', 't')
->join('t.order', 'ord')
->leftJoin('t.owner', 'o')
@ -100,6 +102,6 @@ final class DoctrineSponsorBadgeScanRepository
*/
protected function getBaseEntity()
{
return SponsorBadgeScan::class;
return SponsorUserInfoGrant::class;
}
}

View File

@ -51,6 +51,7 @@ final class SummitScopes
const ReadMyRegistrationOrders = '%s/summits/registration-orders/read/me';
const ReadRegistrationOrders = '%s/summits/registration-orders/read';
const WriteBadgeScan = '%s/summits/badge-scans/write';
const WriteMyBadgeScan = '%s/summits/badge-scans/write/me';
const ReadBadgeScan = '%s/summits/badge-scans/read';
const ReadMyBadgeScan = '%s/summits/badge-scans/read/me';
const WriteRegistrationData = '%s/summits/registration/write';

View File

@ -15,13 +15,25 @@ use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\main\Member;
use models\summit\SponsorBadgeScan;
use models\summit\SponsorUserInfoGrant;
use models\summit\Summit;
/**
* Interface ISponsorBadgeScanService
* @package App\Services\Model
*/
interface ISponsorBadgeScanService
interface ISponsorUserInfoGrantService
{
/**
* @param Summit $summit
* @param int $sponsor_id
* @param Member $current_member
* @return SponsorUserInfoGrant
* @throws EntityNotFoundException
* @throws ValidationException
*/
public function addGrant(Summit $summit, int $sponsor_id, Member $current_member):SponsorUserInfoGrant;
/**
* @param Summit $summit
* @param Member $current_member

View File

@ -11,28 +11,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Models\Foundation\Summit\Factories\SponsorUserInfoGrantFactory;
use App\Models\Foundation\Summit\Repositories\ISummitAttendeeBadgeRepository;
use App\Services\Model\AbstractService;
use App\Services\Model\ISponsorBadgeScanService;
use App\Services\Model\ISponsorUserInfoGrantService;
use libs\utils\ITransactionService;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\main\Member;
use models\summit\ISponsorBadgeScanRepository;
use models\summit\ISponsorUserInfoGrantRepository;
use models\summit\SponsorBadgeScan;
use models\summit\SponsorUserInfoGrant;
use models\summit\Summit;
use models\summit\SummitAttendeeBadge;
/**
* Class SponsorBadgeScanService
* Class SponsorUserInfoGrantService
* @package App\Services\Model\Imp
*/
final class SponsorBadgeScanService
final class SponsorUserInfoGrantService
extends AbstractService
implements ISponsorBadgeScanService
implements ISponsorUserInfoGrantService
{
/**
* @var ISponsorBadgeScanRepository
* @var ISponsorUserInfoGrantRepository
*/
private $repository;
@ -43,13 +45,13 @@ final class SponsorBadgeScanService
/**
* SponsorBadgeScanService constructor.
* @param ISponsorBadgeScanRepository $repository
* @param ISponsorUserInfoGrantRepository $repository
* @param ISummitAttendeeBadgeRepository $badge_repository
* @param ITransactionService $tx_service
*/
public function __construct
(
ISponsorBadgeScanRepository $repository,
ISponsorUserInfoGrantRepository $repository,
ISummitAttendeeBadgeRepository $badge_repository,
ITransactionService $tx_service
)
@ -59,6 +61,29 @@ final class SponsorBadgeScanService
$this->badge_repository = $badge_repository;
}
/**
* @param Summit $summit
* @param int $sponsor_id
* @param Member $current_member
* @return SponsorUserInfoGrant
* @throws \Exception
*/
public function addGrant(Summit $summit, int $sponsor_id, Member $current_member):SponsorUserInfoGrant {
return $this->tx_service->transaction(function() use($summit, $sponsor_id, $current_member){
$grant = SponsorUserInfoGrantFactory::build(['class_name' => SponsorUserInfoGrant::ClassName]);
$sponsor = $summit->getSummitSponsorById($sponsor_id);
if(is_null($sponsor)){
throw new EntityNotFoundException(sprintf("Sponsor not found."));
}
if($sponsor->hasGrant($current_member)){
throw new ValidationException(sprintf("User %s already gave grant to sponsor %s", $current_member->getEmail(), $sponsor_id));
}
$grant->setAllowedUser($current_member);
$sponsor->addUserInfoGrant($grant);
return $grant;
});
}
/**
* @param Summit $summit
* @param Member $current_member
@ -79,7 +104,7 @@ final class SponsorBadgeScanService
$end_date = $summit->getEndDate();
if(!($scan_date >= $begin_date && $scan_date <= $end_date))
throw new ValidationException("scan_date is does not belong to summit period");
throw new ValidationException("scan_date is does not belong to summit period.");
if($summit->getBadgeQRPrefix() != $prefix)
throw new ValidationException
@ -102,15 +127,15 @@ final class SponsorBadgeScanService
$sponsor = $current_member->getSponsorBySummit($summit);
if(is_null($sponsor))
throw new ValidationException("current member does not belongs to any summit sponsor");
$scan = new SponsorBadgeScan();
throw new ValidationException("Current member does not belongs to any summit sponsor.");
$scan = SponsorUserInfoGrantFactory::build(['class_name' => SponsorBadgeScan::ClassName]);
$scan->setScanDate($scan_date);
$scan->setQRCode($qr_code);
$scan->setUser($current_member);
$scan->setBadge($badge);
$sponsor->addBadgeScan($scan);
$sponsor->addUserInfoGrant($scan);
return $scan;
});

View File

@ -24,7 +24,7 @@ use App\Services\Model\IMemberService;
use App\Services\Model\Imp\CompanyService;
use App\Services\Model\Imp\PaymentGatewayProfileService;
use App\Services\Model\Imp\RegistrationIngestionService;
use App\Services\Model\Imp\SponsorBadgeScanService;
use App\Services\Model\Imp\SponsorUserInfoGrantService;
use App\Services\Model\Imp\SummitAdministratorPermissionGroupService;
use App\Services\Model\Imp\SummitDocumentService;
use App\Services\Model\Imp\SummitEmailEventFlowService;
@ -38,7 +38,7 @@ use App\Services\Model\IPresentationCategoryGroupService;
use App\Services\Model\IRegistrationIngestionService;
use App\Services\Model\IRSVPTemplateService;
use App\Services\Model\IScheduleIngestionService;
use App\Services\Model\ISponsorBadgeScanService;
use App\Services\Model\ISponsorUserInfoGrantService;
use App\Services\Model\ISponsorshipTypeService;
use App\Services\Model\ISummitAccessLevelTypeService;
use App\Services\Model\ISummitAdministratorPermissionGroupService;
@ -326,7 +326,8 @@ final class ModelServicesProvider extends ServiceProvider
App::singleton(ISummitOrderService::class, SummitOrderService::class);
App::singleton(ISponsorBadgeScanService::class, SponsorBadgeScanService::class);
App::singleton(ISponsorUserInfoGrantService::class,
SponsorUserInfoGrantService::class);
App::singleton(
IRegistrationIngestionService::class,

View File

@ -0,0 +1,61 @@
<?php namespace Database\Migrations\Model;
/**
* Copyright 2019 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\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema as Schema;
use LaravelDoctrine\Migrations\Schema\Builder;
use LaravelDoctrine\Migrations\Schema\Table;
/**
* Class Version20201015153512
* @package Database\Migrations\Model
*/
class Version20201015153512 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
$builder = new Builder($schema);
if(!$schema->hasTable("SponsorUserInfoGrant")) {
$builder->create('SponsorUserInfoGrant', function (Table $table) {
$table->integer("ID", true, false);
$table->primary("ID");
$table->timestamp('Created');
$table->timestamp('LastEdited');
$table->string('ClassName');
// FK
$table->integer("AllowedUserID", false, false)->setNotnull(false)->setDefault('NULL');
$table->index("AllowedUserID", "AllowedUserID");
$table->foreign("Member", "AllowedUserID", "ID", ["onDelete" => "CASCADE"]);
// FK
$table->integer("SponsorID", false, false)->setNotnull(false)->setDefault('NULL');
$table->index("SponsorID", "SponsorID");
$table->foreign("Sponsor", "SponsorID", "ID", ["onDelete" => "CASCADE"]);
});
}
}
/**
* @param Schema $schema
*/
public function down(Schema $schema)
{
}
}

View File

@ -0,0 +1,44 @@
<?php namespace Database\Migrations\Model;
/**
* Copyright 2019 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\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema as Schema;
/**
* Class Version20201015153514
* @package Database\Migrations\Model
*/
class Version20201015153514 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
// make enum
$sql = <<<SQL
ALTER TABLE SponsorUserInfoGrant MODIFY ClassName
enum(
'SponsorUserInfoGrant', 'SponsorBadgeScan'
) default 'SponsorUserInfoGrant';
SQL;
$this->addSql($sql);
}
/**
* @param Schema $schema
*/
public function down(Schema $schema)
{
}
}

View File

@ -0,0 +1,72 @@
<?php namespace Database\Migrations\Model;
/**
* Copyright 2019 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\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema as Schema;
/**
* Class Version20201015153516
* @package Database\Migrations\Model
*/
class Version20201015153516 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
// migrate data
$sql = <<<SQL
INSERT INTO SponsorUserInfoGrant (ID, Created, LastEdited, ClassName, AllowedUserID, SponsorID)
SELECT SponsorBadgeScan.ID,
SponsorBadgeScan.Created,
SponsorBadgeScan.LastEdited,
SponsorBadgeScan.ClassName,
NULL,
SponsorBadgeScan.SponsorID
FROM SponsorBadgeScan;
SQL;
$this->addSql($sql);
// update PK
$sql = <<<SQL
alter table SponsorBadgeScan modify ID int not null;
SQL;
$this->addSql($sql);
// FK inheritance
$sql = <<<SQL
ALTER TABLE SponsorBadgeScan ADD CONSTRAINT FK_SponsorBadgeScan_SponsorUserInfoGrant FOREIGN KEY (ID) REFERENCES SponsorUserInfoGrant (ID) ON DELETE CASCADE;
SQL;
$this->addSql($sql);
// DROP IDX
$sql = <<<SQL
drop index SponsorID on SponsorBadgeScan;
SQL;
$this->addSql($sql);
$sql = <<<SQL
alter table SponsorBadgeScan drop column SponsorID;
SQL;
$this->addSql($sql);
}
/**
* @param Schema $schema
*/
public function down(Schema $schema)
{
}
}

View File

@ -1451,6 +1451,14 @@ class ApiEndpointsSeeder extends Seeder
IGroup::SummitAdministrators,
]
],
[
'name' => 'share-my-user-info-with-sponsor',
'route' => '/api/v1/summits/{id}/sponsors/{sponsor_id}/user-info-grants/me',
'http_method' => 'POST',
'scopes' => [
sprintf(SummitScopes::WriteMyBadgeScan, $current_realm),
]
],
// sponsorship-types
[
'name' => 'get-sponsorship-types',

View File

@ -325,6 +325,11 @@ final class ApiScopesSeeder extends Seeder
'short_description' => 'read my badge scans',
'description' => 'read my badge scans',
],
[
'name' => sprintf(SummitScopes::WriteMyBadgeScan, $current_realm),
'short_description' => 'allow to share my badge with sponsors',
'description' => 'allow to share my badge with sponsors',
],
[
'name' => sprintf(SummitScopes::ReadBadgeScan, $current_realm),
'short_description' => 'read badge scans',