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:
parent
7d4ac0f9de
commit
518feb0efb
@ -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
|
||||
*/
|
||||
|
@ -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');
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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': {
|
||||
|
@ -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',
|
||||
];
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -13,10 +13,10 @@
|
||||
**/
|
||||
use models\utils\IBaseRepository;
|
||||
/**
|
||||
* Interface ISponsorBadgeScanRepository
|
||||
* Interface ISponsorUserInfoGrantRepository
|
||||
* @package models\summit
|
||||
*/
|
||||
interface ISponsorBadgeScanRepository extends IBaseRepository
|
||||
interface ISponsorUserInfoGrantRepository extends IBaseRepository
|
||||
{
|
||||
|
||||
}
|
@ -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{
|
||||
|
@ -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);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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';
|
||||
|
@ -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
|
@ -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;
|
||||
});
|
@ -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,
|
||||
|
61
database/migrations/model/Version20201015153512.php
Normal file
61
database/migrations/model/Version20201015153512.php
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
44
database/migrations/model/Version20201015153514.php
Normal file
44
database/migrations/model/Version20201015153514.php
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
72
database/migrations/model/Version20201015153516.php
Normal file
72
database/migrations/model/Version20201015153516.php
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -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',
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user