commit 518feb0efb06b916fb57d989ee791270c46828db Author: smarcet Date: Thu Oct 15 16:41:43 2020 -0300 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 diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeScanApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeScanApiController.php index 1486858..4d82f1c 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeScanApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeScanApiController.php @@ -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); @@ -90,6 +93,49 @@ final class OAuth2SummitBadgeScanApiController } /** + * @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 */ protected function getSummitRepository(): ISummitRepository diff --git a/app/Http/routes.php b/app/Http/routes.php index 4bb6f1e..cbd205c 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -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'); diff --git a/app/ModelSerializers/SerializerRegistry.php b/app/ModelSerializers/SerializerRegistry.php index 9bea4e5..3bf31d4 100644 --- a/app/ModelSerializers/SerializerRegistry.php +++ b/app/ModelSerializers/SerializerRegistry.php @@ -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 diff --git a/app/ModelSerializers/Summit/Registration/SponsorBadgeScanCSVSerializer.php b/app/ModelSerializers/Summit/Registration/SponsorBadgeScanCSVSerializer.php index 16602e6..e2dbd84 100644 --- a/app/ModelSerializers/Summit/Registration/SponsorBadgeScanCSVSerializer.php +++ b/app/ModelSerializers/Summit/Registration/SponsorBadgeScanCSVSerializer.php @@ -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; } } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SponsorBadgeScanSerializer.php b/app/ModelSerializers/Summit/Registration/SponsorBadgeScanSerializer.php index 02fa3d7..c9874fd 100644 --- a/app/ModelSerializers/Summit/Registration/SponsorBadgeScanSerializer.php +++ b/app/ModelSerializers/Summit/Registration/SponsorBadgeScanSerializer.php @@ -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': { diff --git a/app/ModelSerializers/Summit/Registration/SponsorUserInfoGrantSerializer.php b/app/ModelSerializers/Summit/Registration/SponsorUserInfoGrantSerializer.php new file mode 100644 index 0000000..fb968e4 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SponsorUserInfoGrantSerializer.php @@ -0,0 +1,30 @@ + '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', + ]; +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SponsorUserInfoGrantFactory.php b/app/Models/Foundation/Summit/Factories/SponsorUserInfoGrantFactory.php new file mode 100644 index 0000000..7cc874f --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SponsorUserInfoGrantFactory.php @@ -0,0 +1,56 @@ + 'sponsor', 'getUserId' => 'user', 'getBadgeId' => 'badge', ]; protected $hasPropertyMappings = [ - 'hasSponsor' => 'sponsor', 'hasUser' => 'user', 'hasBadge' => 'badge', ]; @@ -46,13 +44,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(); + } + } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SponsorUserInfoGrant.php b/app/Models/Foundation/Summit/Registration/SponsorUserInfoGrant.php new file mode 100644 index 0000000..e3c4d40 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SponsorUserInfoGrant.php @@ -0,0 +1,102 @@ + '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(); + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Repositories/ISponsorBadgeScanRepository.php b/app/Models/Foundation/Summit/Repositories/ISponsorBadgeScanRepository.php deleted file mode 100644 index c47a928..0000000 --- a/app/Models/Foundation/Summit/Repositories/ISponsorBadgeScanRepository.php +++ /dev/null @@ -1,22 +0,0 @@ -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{ diff --git a/app/Repositories/RepositoriesProvider.php b/app/Repositories/RepositoriesProvider.php index 792c255..910a200 100644 --- a/app/Repositories/RepositoriesProvider.php +++ b/app/Repositories/RepositoriesProvider.php @@ -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); } ); diff --git a/app/Repositories/Summit/DoctrineSponsorBadgeScanRepository.php b/app/Repositories/Summit/DoctrineSponsorBadgeScanRepository.php deleted file mode 100644 index ed5d7ff..0000000 --- a/app/Repositories/Summit/DoctrineSponsorBadgeScanRepository.php +++ /dev/null @@ -1,105 +0,0 @@ - new DoctrineFilterMapping("t.number :operator :value"), - 'summit_id' => new DoctrineFilterMapping("s.id :operator :value"), - 'user_id' => new DoctrineFilterMapping("u.id :operator :value"), - 'sponsor_id' => new DoctrineFilterMapping("sp.id :operator :value"), - 'company_id' => new DoctrineFilterMapping("c.id :operator :value"), - 'order_number' => new DoctrineFilterMapping("ord.number :operator :value"), - 'attendee_first_name' => [ - "m.first_name :operator :value", - "o.first_name :operator :value" - ], - 'attendee_last_name' => [ - "m.last_name :operator :value", - "o.surname :operator :value" - ], - 'attendee_full_name' => [ - "concat(m.first_name, ' ', m.last_name) :operator :value", - "concat(o.first_name, ' ', o.surname) :operator :value" - ], - 'attendee_email' => [ - "m.email :operator :value", - "o.email :operator :value" - ], - 'attendee_company' => new DoctrineFilterMapping("o.company_name :operator :value"), - ]; - } - - /** - * @return array - */ - protected function getOrderMappings() - { - return [ - 'id' => 'e.id', - 'scan_date' => 'e.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', - ]; - } - - /** - * @param QueryBuilder $query - * @return QueryBuilder - */ - protected function applyExtraJoins(QueryBuilder $query){ - $query = $query->join('e.sponsor', 'sp') - ->join('sp.summit', 's') - ->join('sp.company', 'c') - ->join('e.user', 'u') - ->join('e.badge', 'b') - ->join('b.ticket', 't') - ->join('t.order', 'ord') - ->leftJoin('t.owner', 'o') - ->leftJoin('o.member', 'm'); - return $query; - } - - /** - * @return string - */ - protected function getBaseEntity() - { - return SponsorBadgeScan::class; - } -} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSponsorUserInfoGrantRepository.php b/app/Repositories/Summit/DoctrineSponsorUserInfoGrantRepository.php new file mode 100644 index 0000000..f99be08 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSponsorUserInfoGrantRepository.php @@ -0,0 +1,107 @@ + new DoctrineFilterMapping("t.number :operator :value"), + 'summit_id' => new DoctrineFilterMapping("s.id :operator :value"), + 'user_id' => new DoctrineFilterMapping("u.id :operator :value"), + 'sponsor_id' => new DoctrineFilterMapping("sp.id :operator :value"), + 'company_id' => new DoctrineFilterMapping("c.id :operator :value"), + 'order_number' => new DoctrineFilterMapping("ord.number :operator :value"), + 'attendee_first_name' => [ + "m.first_name :operator :value", + "o.first_name :operator :value" + ], + 'attendee_last_name' => [ + "m.last_name :operator :value", + "o.surname :operator :value" + ], + 'attendee_full_name' => [ + "concat(m.first_name, ' ', m.last_name) :operator :value", + "concat(o.first_name, ' ', o.surname) :operator :value" + ], + 'attendee_email' => [ + "m.email :operator :value", + "o.email :operator :value" + ], + 'attendee_company' => new DoctrineFilterMapping("o.company_name :operator :value"), + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + '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)) 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', + ]; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query){ + $query = $query->join('e.sponsor', 'sp') + ->join('sp.summit', 's') + ->join('sp.company', 'c') + ->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') + ->leftJoin('o.member', 'm'); + return $query; + } + + /** + * @return string + */ + protected function getBaseEntity() + { + return SponsorUserInfoGrant::class; + } +} \ No newline at end of file diff --git a/app/Security/SummitScopes.php b/app/Security/SummitScopes.php index 0ae3d0e..6fb8e42 100644 --- a/app/Security/SummitScopes.php +++ b/app/Security/SummitScopes.php @@ -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'; diff --git a/app/Services/Model/ISponsorBadgeScanService.php b/app/Services/Model/ISponsorBadgeScanService.php deleted file mode 100644 index d3616f6..0000000 --- a/app/Services/Model/ISponsorBadgeScanService.php +++ /dev/null @@ -1,35 +0,0 @@ -repository = $repository; - $this->badge_repository = $badge_repository; - } - - /** - * @param Summit $summit - * @param Member $current_member - * @param array $data - * @return SponsorBadgeScan - * @throws \Exception - */ - public function addBadgeScan(Summit $summit, Member $current_member, array $data): SponsorBadgeScan - { - return $this->tx_service->transaction(function() use($summit, $current_member, $data){ - - $qr_code = trim($data['qr_code']); - $fields = SummitAttendeeBadge::parseQRCode($qr_code); - $prefix = $fields['prefix']; - $scan_date_epoch = intval($data['scan_date']); - $scan_date = new \DateTime("@$scan_date_epoch"); - $begin_date = $summit->getBeginDate(); - $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"); - - if($summit->getBadgeQRPrefix() != $prefix) - throw new ValidationException - ( - sprintf - ( - "%s qr code is not valid for summit %s", - $qr_code, - $summit->getId() - ) - ); - - $ticket_number = $fields['ticket_number']; - - $badge = $this->badge_repository->getBadgeByTicketNumber($ticket_number); - - if(is_null($badge)) - throw new EntityNotFoundException("badge not found"); - - $sponsor = $current_member->getSponsorBySummit($summit); - - if(is_null($sponsor)) - throw new ValidationException("current member does not belongs to any summit sponsor"); - - $scan = new SponsorBadgeScan(); - - $scan->setScanDate($scan_date); - $scan->setQRCode($qr_code); - $scan->setUser($current_member); - $scan->setBadge($badge); - $sponsor->addBadgeScan($scan); - - return $scan; - }); - } -} \ No newline at end of file diff --git a/app/Services/Model/Imp/SponsorUserInfoGrantService.php b/app/Services/Model/Imp/SponsorUserInfoGrantService.php new file mode 100644 index 0000000..b94263d --- /dev/null +++ b/app/Services/Model/Imp/SponsorUserInfoGrantService.php @@ -0,0 +1,143 @@ +repository = $repository; + $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 + * @param array $data + * @return SponsorBadgeScan + * @throws \Exception + */ + public function addBadgeScan(Summit $summit, Member $current_member, array $data): SponsorBadgeScan + { + return $this->tx_service->transaction(function() use($summit, $current_member, $data){ + + $qr_code = trim($data['qr_code']); + $fields = SummitAttendeeBadge::parseQRCode($qr_code); + $prefix = $fields['prefix']; + $scan_date_epoch = intval($data['scan_date']); + $scan_date = new \DateTime("@$scan_date_epoch"); + $begin_date = $summit->getBeginDate(); + $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."); + + if($summit->getBadgeQRPrefix() != $prefix) + throw new ValidationException + ( + sprintf + ( + "%s qr code is not valid for summit %s", + $qr_code, + $summit->getId() + ) + ); + + $ticket_number = $fields['ticket_number']; + + $badge = $this->badge_repository->getBadgeByTicketNumber($ticket_number); + + if(is_null($badge)) + throw new EntityNotFoundException("badge not found"); + + $sponsor = $current_member->getSponsorBySummit($summit); + + if(is_null($sponsor)) + 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->addUserInfoGrant($scan); + + return $scan; + }); + } +} \ No newline at end of file diff --git a/app/Services/ModelServicesProvider.php b/app/Services/ModelServicesProvider.php index f8ee1bc..a0d1f0c 100644 --- a/app/Services/ModelServicesProvider.php +++ b/app/Services/ModelServicesProvider.php @@ -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, diff --git a/database/migrations/model/Version20201015153512.php b/database/migrations/model/Version20201015153512.php new file mode 100644 index 0000000..302bc2d --- /dev/null +++ b/database/migrations/model/Version20201015153512.php @@ -0,0 +1,61 @@ +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) + { + + } +} diff --git a/database/migrations/model/Version20201015153514.php b/database/migrations/model/Version20201015153514.php new file mode 100644 index 0000000..c80fbfb --- /dev/null +++ b/database/migrations/model/Version20201015153514.php @@ -0,0 +1,44 @@ +addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20201015153516.php b/database/migrations/model/Version20201015153516.php new file mode 100644 index 0000000..6af0ba8 --- /dev/null +++ b/database/migrations/model/Version20201015153516.php @@ -0,0 +1,72 @@ +addSql($sql); + + // update PK + $sql = <<addSql($sql); + + // FK inheritance + $sql = <<addSql($sql); + + // DROP IDX + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index 272f118..25d1e1e 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -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', diff --git a/database/seeds/ApiScopesSeeder.php b/database/seeds/ApiScopesSeeder.php index 336be4c..06f0fe1 100644 --- a/database/seeds/ApiScopesSeeder.php +++ b/database/seeds/ApiScopesSeeder.php @@ -326,6 +326,11 @@ final class ApiScopesSeeder extends Seeder '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', 'description' => 'read badge scans',