Summit Metrics

added new endpoints

PUT /api/v1/summits/{id}/metrics/enter

required scopes

%s/me/summits/metrics/write
s/me/summits/events/enter

POST /api/v1/summits/{id}/metrics/leave

payload

type (string:in[GENERAL,LOBBY,EVENT,SPONSOR])
source_id (int[event id or sponsor id])

required scopes

%s/me/summits/events/leave
%s/me/summits/metrics/write

Change-Id: I46babe9d92832da02fe175f0d6cbcfd26bb037ad
Signed-off-by: smarcet <smarcet@gmail.com>
This commit is contained in:
smarcet 2020-10-14 15:56:12 -03:00
parent 82e7d24b33
commit f7801849f8
33 changed files with 1371 additions and 260 deletions

View File

@ -947,82 +947,4 @@ final class OAuth2SummitMembersApiController extends OAuth2ProtectedController
}
}
/**
* @param $summit_id
* @param $member_id
* @param $event_id
* @return mixed
*/
public function enterToEvent($summit_id, $member_id, $event_id){
try {
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$current_member = $this->resource_server_context->getCurrentUser();
if (is_null($current_member)) return $this->error403();
$event = $this->summit_service->enterTo($summit, $current_member, intval($event_id));
return $this->updated(SerializerRegistry::getInstance()->getSerializer($event)->serialize());
}
catch (ValidationException $ex1)
{
Log::warning($ex1);
return $this->error412(array( $ex1->getMessage()));
}
catch (EntityNotFoundException $ex2)
{
Log::warning($ex2);
return $this->error404(array('message' => $ex2->getMessage()));
}
catch(\HTTP401UnauthorizedException $ex3)
{
Log::warning($ex3);
return $this->error401();
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
/**
* @param $summit_id
* @param $member_id
* @param $event_id
* @return mixed
*/
public function leaveFromEvent($summit_id, $member_id, $event_id){
try {
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$current_member = $this->resource_server_context->getCurrentUser();
if (is_null($current_member)) return $this->error403();
$event = $this->summit_service->leaveFrom($summit, $current_member, intval($event_id));
return $this->updated(SerializerRegistry::getInstance()->getSerializer($event)->serialize());
}
catch (ValidationException $ex1)
{
Log::warning($ex1);
return $this->error412(array( $ex1->getMessage()));
}
catch (EntityNotFoundException $ex2)
{
Log::warning($ex2);
return $this->error404(array('message' => $ex2->getMessage()));
}
catch(\HTTP401UnauthorizedException $ex3)
{
Log::warning($ex3);
return $this->error401();
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
}

View File

@ -0,0 +1,233 @@
<?php namespace App\Http\Controllers;
/**
* 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 App\Services\Model\ISummitMetricService;
use Illuminate\Support\Facades\Log;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\main\IMemberRepository;
use models\oauth2\IResourceServerContext;
use models\summit\ISummitMetricType;
use models\summit\ISummitRepository;
use ModelSerializers\SerializerRegistry;
use Exception;
/**
* Class OAuth2SummitMetricsApiController
* @package App\Http\Controllers
*/
final class OAuth2SummitMetricsApiController extends OAuth2ProtectedController
{
use GetAndValidateJsonPayload;
/**
* @var ISummitRepository
*/
private $summit_repository;
/**
* @var ISummitMetricService
*/
private $service;
/**
* OAuth2SummitMembersApiController constructor.
* @param IMemberRepository $member_repository
* @param ISummitRepository $summit_repository
* @param ISummitMetricService $service
* @param IResourceServerContext $resource_server_context
*/
public function __construct
(
IMemberRepository $member_repository,
ISummitRepository $summit_repository,
ISummitMetricService $service,
IResourceServerContext $resource_server_context
) {
parent::__construct($resource_server_context);
$this->summit_repository = $summit_repository;
$this->repository = $member_repository;
$this->service = $service;
}
/**
* @param $summit_id
* @param $member_id
* @param $event_id
* @return mixed
*/
public function enter($summit_id){
try {
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$current_member = $this->resource_server_context->getCurrentUser();
if (is_null($current_member)) return $this->error403();
$payload = $this->getJsonPayload([
'type' => 'required|string',
'source_id' => 'sometimes|integer',
]);
$metric = $this->service->enter($summit, $current_member, $payload);
return $this->updated(SerializerRegistry::getInstance()->getSerializer($metric)->serialize());
}
catch (ValidationException $ex1)
{
Log::warning($ex1);
return $this->error412(array( $ex1->getMessage()));
}
catch (EntityNotFoundException $ex2)
{
Log::warning($ex2);
return $this->error404(array('message' => $ex2->getMessage()));
}
catch(\HTTP401UnauthorizedException $ex3)
{
Log::warning($ex3);
return $this->error401();
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
/**
* @param $summit_id
* @param $member_id
* @param $event_id
* @return mixed
*/
public function leave($summit_id){
try {
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$current_member = $this->resource_server_context->getCurrentUser();
if (is_null($current_member)) return $this->error403();
$payload = $this->getJsonPayload([
'type' => 'required|string|in:'.implode(",", ISummitMetricType::ValidTypes),
'source_id' => 'sometimes|integer',
]);
$metric = $this->service->leave($summit, $current_member, $payload);
return $this->updated(SerializerRegistry::getInstance()->getSerializer($metric)->serialize());
}
catch (ValidationException $ex1)
{
Log::warning($ex1);
return $this->error412(array( $ex1->getMessage()));
}
catch (EntityNotFoundException $ex2)
{
Log::warning($ex2);
return $this->error404(array('message' => $ex2->getMessage()));
}
catch(\HTTP401UnauthorizedException $ex3)
{
Log::warning($ex3);
return $this->error401();
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
/**
* @param $summit_id
* @param $member_id
* @param $event_id
* @return mixed
*/
public function enterToEvent($summit_id, $member_id, $event_id){
try {
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$current_member = $this->resource_server_context->getCurrentUser();
if (is_null($current_member)) return $this->error403();
$metric = $this->service->enter($summit, $current_member, [
'type' => 'required|string|in:'.implode(",", ISummitMetricType::ValidTypes),
'source_id' => intval($event_id)
]);
return $this->updated(SerializerRegistry::getInstance()->getSerializer($metric)->serialize());
}
catch (ValidationException $ex1)
{
Log::warning($ex1);
return $this->error412(array( $ex1->getMessage()));
}
catch (EntityNotFoundException $ex2)
{
Log::warning($ex2);
return $this->error404(array('message' => $ex2->getMessage()));
}
catch(\HTTP401UnauthorizedException $ex3)
{
Log::warning($ex3);
return $this->error401();
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
/**
* @param $summit_id
* @param $member_id
* @param $event_id
* @return mixed
*/
public function leaveFromEvent($summit_id, $member_id, $event_id){
try {
$summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id);
if (is_null($summit)) return $this->error404();
$current_member = $this->resource_server_context->getCurrentUser();
if (is_null($current_member)) return $this->error403();
$metric = $this->service->leave($summit, $current_member, [
'type' => ISummitMetricType::Event,
'source_id' => intval($event_id)
]);
return $this->updated(SerializerRegistry::getInstance()->getSerializer($metric)->serialize());
}
catch (ValidationException $ex1)
{
Log::warning($ex1);
return $this->error412(array( $ex1->getMessage()));
}
catch (EntityNotFoundException $ex2)
{
Log::warning($ex2);
return $this->error404(array('message' => $ex2->getMessage()));
}
catch(\HTTP401UnauthorizedException $ex3)
{
Log::warning($ex3);
return $this->error401();
}
catch (Exception $ex) {
Log::error($ex);
return $this->error500($ex);
}
}
}

View File

@ -170,6 +170,11 @@ Route::group([
Route::group(['prefix' => '{id}'], function () {
Route::group(['prefix' => 'metrics'], function () {
Route::put('enter', 'OAuth2SummitMetricsApiController@enter');
Route::post('leave', 'OAuth2SummitMetricsApiController@leave');
});
Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@updateSummit']);
Route::post('logo', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@addSummitLogo']);
Route::delete('logo', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@deleteSummitLogo']);
@ -964,8 +969,8 @@ Route::group([
Route::delete('', 'OAuth2SummitMembersApiController@removeEventFromMemberSchedule')->where('member_id', 'me');
Route::put('enter', 'OAuth2SummitMembersApiController@enterToEvent')->where('member_id', 'me');
Route::post('leave', 'OAuth2SummitMembersApiController@leaveFromEvent')->where('member_id', 'me');
Route::put('enter', 'OAuth2SummitMetricsApiController@enterToEvent')->where('member_id', 'me');
Route::post('leave', 'OAuth2SummitMetricsApiController@leaveFromEvent')->where('member_id', 'me');
});
});
});

View File

@ -138,9 +138,13 @@ final class SerializerRegistry
$this->registry['ApiEndpoint'] = ApiEndpointSerializer::class;
$this->registry['ApiScope'] = ApiScopeSerializer::class;
$this->registry['ApiEndpointAuthzGroup'] = ApiEndpointAuthzGroupSerializer::class;
//
// metrics
$this->registry['SummitMetric'] = SummitMetricSerializer::class;
$this->registry['SummitSponsorMetric'] = SummitSponsorMetricSerializer::class;
$this->registry['SummitEventAttendanceMetric'] = SummitEventAttendanceMetricSerializer::class;
// stripe
$this->registry['StripePaymentProfile'] = [
self::SerializerType_Public => StripePaymentProfileSerializer::class,
self::SerializerType_Private => AdminStripePaymentProfileSerializer::class,

View File

@ -11,17 +11,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use Libs\ModelSerializers\AbstractSerializer;
/**
* Class SummitEventAttendanceMetricSerializer
* @package ModelSerializers
*/
class SummitEventAttendanceMetricSerializer extends AbstractSerializer
class SummitEventAttendanceMetricSerializer extends SummitMetricSerializer
{
protected static $array_mappings = [
'MemberFirstName' => 'member_first_name:json_string',
'MemberLastName' => 'member_last_name:json_string',
'MemberProfilePhotoUrl' => 'member_pic:json_url',
'EventId' => 'event_id:json_int',
];
}

View File

@ -0,0 +1,30 @@
<?php namespace ModelSerializers;
/**
* 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.
**/
/**
* Class SummitMetricSerializer
* @package ModelSerializers
*/
class SummitMetricSerializer extends SilverStripeSerializer
{
protected static $array_mappings = [
'MemberFirstName' => 'member_first_name:json_string',
'MemberLastName' => 'member_last_name:json_string',
'MemberProfilePhotoUrl' => 'member_pic:json_url',
'Type' => 'type:json_string',
'Ip' => 'ip:json_string',
'Origin' => 'origin:json_string',
'Browser' => 'browser:json_string',
];
}

View File

@ -0,0 +1,24 @@
<?php namespace ModelSerializers;
/**
* 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.
**/
/**
* Class SummitSponsorMetricSerializer
* @package ModelSerializers
*/
class SummitSponsorMetricSerializer extends SummitMetricSerializer
{
protected static $array_mappings = [
'SponsorId' => 'sponsor_id:json_int',
];
}

View File

@ -12,7 +12,6 @@
* limitations under the License.
**/
use App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric;
use Libs\ModelSerializers\AbstractSerializer;
use models\summit\SummitEvent;
/**

View File

@ -13,7 +13,7 @@
**/
use App\Models\Foundation\Main\IGroup;
use App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric;
use models\summit\SummitMetric;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Log;
use Models\Foundation\Main\CCLA\Team;
@ -282,8 +282,8 @@ class Member extends SilverstripeBaseModel
private $summit_permission_groups;
/**
* @ORM\OneToMany(targetEntity="App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric", mappedBy="member", cascade={"persist","remove"}, orphanRemoval=true)
* @var SummitEventAttendanceMetric[]
* @ORM\OneToMany(targetEntity="models\summit\SummitMetric", mappedBy="member", cascade={"persist","remove"}, orphanRemoval=true)
* @var SummitMetric[]
*/
protected $summit_attendance_metrics;

View File

@ -16,7 +16,6 @@ use App\Models\Foundation\Summit\Events\RSVP\RSVPTemplate;
use App\Events\SummitEventCreated;
use App\Events\SummitEventDeleted;
use App\Events\SummitEventUpdated;
use App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use models\exceptions\ValidationException;
@ -206,7 +205,7 @@ class SummitEvent extends SilverstripeBaseModel
protected $tags;
/**
* @ORM\OneToMany(targetEntity="App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric", mappedBy="event", cascade={"persist","remove"}, orphanRemoval=true)
* @ORM\OneToMany(targetEntity="models\summit\SummitEventAttendanceMetric", mappedBy="event", cascade={"persist","remove"}, orphanRemoval=true)
* @var SummitEventAttendanceMetric[]
*/
protected $attendance_metrics;
@ -1143,50 +1142,6 @@ class SummitEvent extends SilverstripeBaseModel
$this->meeting_url = $meeting_url;
}
/**
* @param Member $member
* @return SummitEventAttendanceMetric
* @throws \Exception
*/
public function enter(Member $member){
// check if we have one
$criteria = Criteria::create();
$criteria = $criteria
->where(Criteria::expr()->eq('member', $member))
->andWhere(Criteria::expr()->isNull("outgress_date"));
$formerMetric = $this->attendance_metrics->matching($criteria)->first();
if($formerMetric and $formerMetric instanceof SummitEventAttendanceMetric){
// mark as leave
$formerMetric->abandon();
}
$metric = SummitEventAttendanceMetric::build($member, $this);
$this->attendance_metrics->add($metric);
return $metric;
}
/**
* @param Member $member
* @return mixed
* @throws ValidationException
*/
public function leave(Member $member){
$criteria = Criteria::create();
$criteria = $criteria
->where(Criteria::expr()->eq('member', $member))
->andWhere(Criteria::expr()->isNull("outgress_date"))
->orderBy(['ingress_date' => Criteria::DESC]);
$metric = $this->attendance_metrics->matching($criteria)->first();
if(!$metric)
throw new ValidationException(sprintf("User %s did not enter to event yet.", $member->getId()));
$metric->abandon();
return $metric;
}
/**
* @return int
*/

View File

@ -0,0 +1,63 @@
<?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\exceptions\ValidationException;
use models\main\Member;
use models\summit\ISummitMetricType;
use models\summit\SummitEventAttendanceMetric;
use models\summit\SummitMetric;
use models\summit\SummitSponsorMetric;
/**
* Class SummitMetricFactory
* @package App\Models\Foundation\Summit\Factories
*/
final class SummitMetricFactory
{
/**
* @param Member $member
* @param array $data
* @return SummitMetric
* @throws ValidationException
*/
public static function build(Member $member, array $data):SummitMetric{
if(!isset($data['type'])) throw new ValidationException("type param is mandatory");
$type = trim($data['type']);
$metric = null;
switch($type){
case ISummitMetricType::General:
$metric = SummitMetric::build($member);
break;
case ISummitMetricType::Lobby:
$metric = SummitMetric::build($member);
break;
case ISummitMetricType::Event:
$metric = SummitEventAttendanceMetric::build($member);
break;
case ISummitMetricType::Sponsor:
$metric = SummitSponsorMetric::build($member);
break;
}
return self::populate($metric, $data);
}
/**
* @param SummitMetric $metric
* @param array $data
* @return SummitMetric
*/
public static function populate(SummitMetric $metric, array $data):SummitMetric{
if(isset($data['type']))
$metric->setType($data['type']);
return $metric;
}
}

View File

@ -0,0 +1,32 @@
<?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.
**/
/**
* Interface ISummitMetricType
* @package models\summit
*/
interface ISummitMetricType
{
const General = 'GENERAL';
const Lobby = 'LOBBY';
const Event = 'EVENT';
const Sponsor = 'SPONSOR';
const ValidTypes = [
self::General,
self::Lobby,
self::Event,
self::Sponsor,
];
}

View File

@ -0,0 +1,59 @@
<?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\main\Member;
use Doctrine\ORM\Mapping AS ORM;
/**
* Class SummitEventAttendanceMetric
* @ORM\Entity
* @ORM\Table(name="SummitEventAttendanceMetric")
* @package models\summit
*/
class SummitEventAttendanceMetric extends SummitMetric
{
/**
* @ORM\ManyToOne(targetEntity="models\summit\SummitEvent", inversedBy="attendance_metrics", fetch="LAZY")
* @ORM\JoinColumn(name="SummitEventID", referencedColumnName="ID", onDelete="CASCADE")
* @var SummitEvent
*/
private $event;
/**
* @return SummitEvent
*/
public function getEvent(): ?SummitEvent
{
return $this->event;
}
/**
* @param SummitEvent $event
*/
public function setEvent(SummitEvent $event): void
{
$this->event = $event;
}
/**
* @return int
*/
public function getEventId(){
try {
return is_null($this->event) ? 0 : $this->event->getId();
}
catch(\Exception $ex){
return 0;
}
}
}

View File

@ -1,4 +1,4 @@
<?php namespace App\Models\Foundation\Summit\Events;
<?php namespace models\summit;
/**
* Copyright 2020 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
@ -11,20 +11,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
use App\Services\Utils\UserClientHelper;
use models\exceptions\ValidationException;
use models\main\Member;
use models\summit\SummitEvent;
use models\utils\SilverstripeBaseModel;
use Doctrine\ORM\Mapping AS ORM;
/**
*
* @ORM\Entity
* @ORM\Table(name="SummitEventAttendanceMetric")
* Class SummitEventAttendanceMetric
* @package App\Models\Foundation\Summit\Events
* @ORM\Entity(repositoryClass="App\Repositories\Summit\DoctrineSummitMetricRepository")
* @ORM\AssociationOverrides({
* @ORM\AssociationOverride(
* name="summit",
* inversedBy="metrics"
* )
* })
* @ORM\Table(name="SummitMetric")
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="ClassName", type="string")
* @ORM\DiscriminatorMap({
* "SummitMetric" = "SummitMetric",
* "SummitEventAttendanceMetric" = "SummitEventAttendanceMetric",
* "SummitSponsorMetric" = "SummitSponsorMetric"
* })
* Class SummitMetric
* @package models\summit
*/
class SummitEventAttendanceMetric extends SilverstripeBaseModel
class SummitMetric extends SilverstripeBaseModel
{
use SummitOwned;
/**
* @ORM\Column(name="IngressDate", type="datetime")
* @var \DateTime
@ -33,23 +47,40 @@ class SummitEventAttendanceMetric extends SilverstripeBaseModel
/**
* @ORM\Column(name="OutgressDate", type="datetime")
* @var \DateTime
* @var \DateTime|null
*/
protected $outgress_date;
/**
* @ORM\ManyToOne(targetEntity="models\main\Member", inversedBy="summit_attendance_metrics")
* @ORM\JoinColumn(name="MemberID", referencedColumnName="ID", onDelete="CASCADE")
* @var Member
* @ORM\Column(name="Ip", type="string")
* @var string|null
*/
private $member;
protected $ip;
/**
* @ORM\ManyToOne(targetEntity="models\summit\SummitEvent", inversedBy="attendance_metrics", fetch="LAZY")
* @ORM\JoinColumn(name="SummitEventID", referencedColumnName="ID", onDelete="CASCADE")
* @var SummitEvent
* @ORM\Column(name="Type", type="string")
* @var string|null
*/
private $event;
protected $type;
/**
* @ORM\Column(name="Origin", type="string")
* @var string|null
*/
protected $origin;
/**
* @ORM\Column(name="Browser", type="string")
* @var string|null
*/
protected $browser;
/**
* @ORM\ManyToOne(targetEntity="models\main\Member", inversedBy="summit_attendance_metrics")
* @ORM\JoinColumn(name="MemberID", referencedColumnName="ID", onDelete="CASCADE")
* @var Member|null
*/
protected $member;
/**
* @return \DateTime
@ -86,7 +117,7 @@ class SummitEventAttendanceMetric extends SilverstripeBaseModel
/**
* @return Member
*/
public function getMember(): Member
public function getMember(): ?Member
{
return $this->member;
}
@ -99,42 +130,6 @@ class SummitEventAttendanceMetric extends SilverstripeBaseModel
$this->member = $member;
}
/**
* @return SummitEvent
*/
public function getEvent(): SummitEvent
{
return $this->event;
}
/**
* @param SummitEvent $event
*/
public function setEvent(SummitEvent $event): void
{
$this->event = $event;
}
public function __construct()
{
parent::__construct();
}
/**
* @param Member $member
* @param SummitEvent $event
* @return SummitEventAttendanceMetric
* @throws \Exception
*/
public static function build(Member $member, SummitEvent $event){
$metric = new self();
$metric->member = $member;
$metric->event = $event;
$metric->ingress_date = new \DateTime('now', new \DateTimeZone('UTC'));
return $metric;
}
/**
* @throws ValidationException
*/
@ -155,4 +150,85 @@ class SummitEventAttendanceMetric extends SilverstripeBaseModel
public function getMemberProfilePhotoUrl():?string{
return $this->member->getProfilePhotoUrl();
}
/**
* @param Member|null $member
* @return SummitMetric
* @throws \Exception
*/
public static function build(?Member $member){
$metric = new static();
$metric->member = $member;
$metric->ingress_date = new \DateTime('now', new \DateTimeZone('UTC'));
$metric->ip = UserClientHelper::getUserIp();
$metric->origin = UserClientHelper::getUserOrigin();
$metric->browser = UserClientHelper::getUserBrowser();
return $metric;
}
/**
* @return int
*/
public function getMemberId(){
try {
return is_null($this->member) ? 0 : $this->member->getId();
}
catch(\Exception $ex){
return 0;
}
}
/**
* @return bool
*/
public function hasMember():bool{
return $this->getMemberId() > 0;
}
public function clearMember(){
$this->member = null;
}
/**
* @return string|null
*/
public function getType(): ?string
{
return $this->type;
}
/**
* @param string|null $type
* @throws ValidationException
*/
public function setType(?string $type): void
{
if(!in_array($type, ISummitMetricType::ValidTypes))
throw new ValidationException(sprintf("Type %s is not a valid one.", $type));
$this->type = $type;
}
/**
* @return string|null
*/
public function getIp(): ?string
{
return $this->ip;
}
/**
* @return string|null
*/
public function getOrigin(): ?string
{
return $this->origin;
}
/**
* @return string|null
*/
public function getBrowser(): ?string
{
return $this->browser;
}
}

View File

@ -0,0 +1,66 @@
<?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 Doctrine\ORM\Mapping AS ORM;
use models\main\Member;
/**
* Class SummitSponsorMetric
* @ORM\Entity
* @ORM\Table(name="SummitSponsorMetric")
* @package models\summit
*/
class SummitSponsorMetric extends SummitMetric
{
/**
* @ORM\ManyToOne(targetEntity="models\summit\Sponsor")
* @ORM\JoinColumn(name="SponsorID", referencedColumnName="ID", onDelete="CASCADE")
* @var Sponsor|null
*/
protected $sponsor;
/**
* @return int
*/
public function getSponsorId(){
try {
return is_null($this->sponsor) ? 0 : $this->sponsor->getId();
}
catch(\Exception $ex){
return 0;
}
}
/**
* @return bool
*/
public function hasSponsor():bool{
return $this->getSponsorId() > 0;
}
/**
* @return Sponsor|null
*/
public function getSponsor(): ?Sponsor
{
return $this->sponsor;
}
/**
* @param Sponsor|null $sponsor
*/
public function setSponsor(?Sponsor $sponsor): void
{
$this->sponsor = $sponsor;
}
}

View File

@ -0,0 +1,30 @@
<?php namespace App\Models\Foundation\Summit\Repositories;
/**
* 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\main\Member;
use models\summit\SummitMetric;
/**
* Interface ISummitMetricRepository
* @package App\Models\Foundation\Summit\Repositories
*/
interface ISummitMetricRepository
{
/**
* @param Member $member
* @param string $type
* @param int|null $source_id
* @return SummitMetric|null
*/
public function getNonAbandoned(Member $member, string $type, ?int $source_id = null):?SummitMetric;
}

View File

@ -634,7 +634,6 @@ class Summit extends SilverstripeBaseModel
/**
* @ORM\OneToMany(targetEntity="models\summit\SummitRegistrationInvitation", mappedBy="summit", cascade={"persist","remove"}, orphanRemoval=true)
* @var SummitRegistrationInvitation[]
*/
private $registration_invitations;
@ -644,6 +643,12 @@ class Summit extends SilverstripeBaseModel
*/
private $permission_groups;
/**
* @ORM\OneToMany(targetEntity="models\summit\SummitMetric", mappedBy="summit", cascade={"persist","remove"}, orphanRemoval=true)
* @var SummitMetric[]
*/
private $metrics;
/**
* @return string
*/
@ -963,6 +968,7 @@ class Summit extends SilverstripeBaseModel
$this->permission_groups = new ArrayCollection();
$this->media_upload_types = new ArrayCollection();
$this->featured_speakers = new ArrayCollection();
$this->metrics = new ArrayCollection();
}
/**
@ -5009,4 +5015,21 @@ SQL;
return $list;
}
/**
* @return SummitMetric[]
*/
public function getMetrics(): array
{
return $this->metrics;
}
/**
* @param SummitMetric $metric
*/
public function addMetric(SummitMetric $metric){
if($this->metrics->contains($metric)) return;
$this->metrics->add($metric);
$metric->setSummit($this);
}
}

View File

@ -47,6 +47,7 @@ use App\Models\Foundation\Summit\Repositories\ISummitLocationBannerRepository;
use App\Models\Foundation\Summit\Repositories\ISummitLocationRepository;
use App\Models\Foundation\Summit\Repositories\ISummitMediaFileTypeRepository;
use App\Models\Foundation\Summit\Repositories\ISummitMediaUploadTypeRepository;
use App\Models\Foundation\Summit\Repositories\ISummitMetricRepository;
use App\Models\Foundation\Summit\Repositories\ISummitOrderExtraQuestionTypeRepository;
use App\Models\Foundation\Summit\Repositories\ISummitOrderRepository;
use App\Models\Foundation\Summit\Repositories\ISummitRefundPolicyTypeRepository;
@ -96,6 +97,7 @@ use models\summit\SummitDocument;
use models\summit\SummitEventType;
use models\summit\SummitMediaFileType;
use models\summit\SummitMediaUploadType;
use models\summit\SummitMetric;
use models\summit\SummitOrder;
use models\summit\SummitOrderExtraQuestionType;
use models\summit\SummitRefundPolicyType;
@ -601,5 +603,11 @@ final class RepositoriesProvider extends ServiceProvider
}
);
App::singleton(
ISummitMetricRepository::class,
function(){
return EntityManager::getRepository(SummitMetric::class);
}
);
}
}

View File

@ -0,0 +1,77 @@
<?php namespace App\Repositories\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 App\Models\Foundation\Summit\Repositories\ISummitMetricRepository;
use App\Repositories\SilverStripeDoctrineRepository;
use models\main\Member;
use models\summit\ISummitMetricType;
use models\summit\SummitEventAttendanceMetric;
use models\summit\SummitMetric;
use models\summit\SummitSponsorMetric;
/**
* Class DoctrineSummitMetricRepository
* @package App\Repositories\Summit
*/
final class DoctrineSummitMetricRepository
extends SilverStripeDoctrineRepository
implements ISummitMetricRepository
{
/**
* @inheritDoc
*/
protected function getBaseEntity()
{
return SummitMetric::class;
}
/**
* @param Member $member
* @param string $type
* @param int|null $source_id
* @return SummitMetric|null
*/
public function getNonAbandoned(Member $member, string $type, ?int $source_id = null): ?SummitMetric
{
$query = $this->getEntityManager()
->createQueryBuilder()
->select("e")
->from($this->getBaseEntity(), "e")
->where("e.type = :type");
if(!is_null($source_id) && $source_id > 0){
if($type == ISummitMetricType::Event){
$query = $query->leftJoin(SummitEventAttendanceMetric::class, 'sam', 'WITH', 'e.id = sam.id')
->join("sam.event", "evt")
->andWhere("evt.id = :source_id")
->setParameter("source_id", $source_id);
}
if($type == ISummitMetricType::Sponsor){
$query = $query->leftJoin(SummitSponsorMetric::class, 'sm', 'WITH', 'e.id = sm.id')
->join("sm.sponsor", "sp")
->andWhere("sp.id = :source_id")
->setParameter("source_id", $source_id);
}
}
return $query
->andWhere("e.outgress_date is null")
->andWhere("e.member = :member")
->setParameter("member", $member)
->setParameter("type", trim($type))
->setMaxResults(1)
->orderBy('e.ingress_date', 'DESC')
->getQuery()
->getOneOrNullResult();
}
}

View File

@ -36,7 +36,8 @@ final class SummitScopes
const SendMyScheduleMail = '%s/me/summits/events/schedule/mail';
const EnterEvent = '%s/me/summits/events/enter';
const LeaveEvent = '%s/me/summits/events/leave';
const WriteMetrics = '%s/me/summits/metrics/write';
const ReadMetrics = '%s/me/summits/metrics/read';
// registration
const CreateRegistrationOrders = '%s/summits/registration-orders/create';

View File

@ -0,0 +1,38 @@
<?php namespace App\Services\Model;
/**
* 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\main\Member;
use models\summit\Summit;
use models\summit\SummitMetric;
/**
* Interface ISummitMetricService
* @package App\Services\Model
*/
interface ISummitMetricService
{
/**
* @param Summit $summit
* @param Member $current_member
* @param array $payload
* @return SummitMetric
*/
public function enter(Summit $summit, Member $current_member, array $payload):SummitMetric;
/**
* @param Summit $summit
* @param Member $current_member
* @param array $payload
* @return SummitMetric
*/
public function leave(Summit $summit, Member $current_member, array $payload):SummitMetric;
}

View File

@ -445,27 +445,6 @@ interface ISummitService
public function calculateFeedbackAverageForOngoingSummits():void;
/**
* @param Summit $summit
* @param Member $current_member
* @param int $event_id
* @return SummitEvent
* @throws ValidationException
* @throws EntityNotFoundException
*/
public function enterTo(Summit $summit, Member $current_member, int $event_id):SummitEvent;
/**
* @param Summit $summit
* @param Member $current_member
* @param int $event_id
* @return SummitEvent
* @throws ValidationException
* @throws EntityNotFoundException
*/
public function leaveFrom(Summit $summit, Member $current_member, int $event_id):SummitEvent;
/**
* @param Summit $summit
* @param int $event_id

View File

@ -0,0 +1,141 @@
<?php namespace App\Services\Model\Imp;
/**
* 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 App\Models\Foundation\Summit\Factories\SummitMetricFactory;
use App\Models\Foundation\Summit\Repositories\ISummitMetricRepository;
use App\Services\Model\AbstractService;
use App\Services\Model\ISummitMetricService;
use Illuminate\Support\Facades\Log;
use libs\utils\ITransactionService;
use models\exceptions\EntityNotFoundException;
use models\exceptions\ValidationException;
use models\main\Member;
use models\summit\Summit;
use models\summit\SummitEventAttendanceMetric;
use models\summit\SummitMetric;
use models\summit\SummitSponsorMetric;
use function Psy\debug;
/**
* Class SummitMetricService
* @package App\Services\Model\Imp
*/
final class SummitMetricService
extends AbstractService
implements ISummitMetricService
{
/**
* @var ISummitMetricRepository
*/
private $repository;
public function __construct
(
ISummitMetricRepository $repository,
ITransactionService $tx_service
)
{
parent::__construct($tx_service);
$this->repository = $repository;
}
/**
* @param Summit $summit
* @param Member $current_member
* @param array $payload
* @return SummitMetric
* @throws \Exception
*/
public function enter(Summit $summit, Member $current_member, array $payload): SummitMetric
{
Log::debug(sprintf("SummitMetricService::enter summit %s member %s payload %s", $summit->getId(), $current_member->getId(), json_encode($payload)));
return $this->tx_service->transaction(function () use ($summit, $current_member, $payload) {
$metric = SummitMetricFactory::build($current_member, $payload);
$metric->setMember($current_member);
$source_id = null;
if(isset($payload['source_id']))
$source_id = intval($payload['source_id']);
$formerMetric = $this->repository->getNonAbandoned($current_member, $metric->getType(), $source_id);
if(!is_null($formerMetric)){
// mark as leave
Log::debug(sprintf("SummitMetricService::enter there is a former metric (%s)", $formerMetric->getId()));
$formerMetric->abandon();
}
if($metric instanceof SummitEventAttendanceMetric){
if(!isset($payload['source_id'])){
throw new ValidationException("source_id param is missing.");
}
$event_id = intval($payload['source_id']);
$event = $summit->getEvent($event_id);
if (is_null($event)) {
throw new EntityNotFoundException(sprintf("Event %s does not belongs to summit %s.", $event_id, $summit->getId()));
}
if (!$event->isPublished()) {
throw new ValidationException(sprintf("Event %s is not published.", $event->getId()));
}
$metric->setEvent($event);
}
if($metric instanceof SummitSponsorMetric){
if(!isset($payload['source_id'])){
throw new ValidationException("source_id param is missing.");
}
$sponsor_id = intval($payload['source_id']);
$sponsor = $summit->getSummitSponsorById($sponsor_id);
if (is_null($sponsor)) {
throw new EntityNotFoundException(sprintf("Sponsor %s does not belongs to summit %s.", $sponsor_id, $summit->getId()));
}
$metric->setSponsor($sponsor);
}
$summit->addMetric($metric);
return $metric;
});
}
/**
* @param Summit $summit
* @param Member $current_member
* @param array $payload
* @return SummitMetric
* @throws \Exception
*/
public function leave(Summit $summit, Member $current_member, array $payload): SummitMetric
{
Log::debug(sprintf("SummitMetricService::leave summit %s member %s payload %s", $summit->getId(), $current_member->getId(), json_encode($payload)));
return $this->tx_service->transaction(function () use ($summit, $current_member, $payload) {
$source_id = null;
if(isset($payload['source_id']))
$source_id = intval($payload['source_id']);
$formerMetric = $this->repository->getNonAbandoned($current_member, trim($payload['type']), $source_id);
if(!$formerMetric)
throw new ValidationException(sprintf("User %s has not a pending %s metric", $current_member->getId(), $payload['type']));
$formerMetric->abandon();
return $formerMetric;
});
}
}

View File

@ -33,7 +33,6 @@ use App\Permissions\IPermissionsManager;
use App\Services\Model\AbstractService;
use App\Services\Model\IFolderService;
use App\Services\Model\IMemberService;
use App\Services\Utils\CSVReader;
use CalDAVClient\Facade\Utils\ICalTimeZoneBuilder;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use GuzzleHttp\Exception\ClientException;
@ -2503,50 +2502,6 @@ final class SummitService extends AbstractService implements ISummitService
}
}
/**
* @inheritDoc
*/
public function enterTo(Summit $summit, Member $current_member, int $event_id): SummitEvent
{
return $this->tx_service->transaction(function () use ($summit, $current_member, $event_id) {
$event = $summit->getEvent($event_id);
if (is_null($event)) {
throw new EntityNotFoundException(sprintf("Event %s does not belongs to summit %s.", $event_id, $summit->getId()));
}
if (!$event->isPublished()) {
throw new ValidationException(sprintf("Event %s is not published.", $event->getId()));
}
$event->enter($current_member);
return $event;
});
}
/**
* @inheritDoc
*/
public function leaveFrom(Summit $summit, Member $current_member, int $event_id): SummitEvent
{
return $this->tx_service->transaction(function () use ($summit, $current_member, $event_id) {
$event = $summit->getEvent($event_id);
if (is_null($event)) {
throw new EntityNotFoundException(sprintf("Event %s does not belongs to summit %s.", $event_id, $summit->getId()));
}
if (!$event->isPublished()) {
throw new ValidationException(sprintf("Event %s is not published.", $event->getId()));
}
$event->leave($current_member);
return $event;
});
}
/**
* @inheritDoc
*/

View File

@ -30,6 +30,7 @@ use App\Services\Model\Imp\SummitDocumentService;
use App\Services\Model\Imp\SummitEmailEventFlowService;
use App\Services\Model\Imp\SummitMediaFileTypeService;
use App\Services\Model\Imp\SummitMediaUploadTypeService;
use App\Services\Model\Imp\SummitMetricService;
use App\Services\Model\Imp\SummitRegistrationInvitationService;
use App\Services\Model\IOrganizationService;
use App\Services\Model\IPaymentGatewayProfileService;
@ -48,6 +49,7 @@ use App\Services\Model\ISummitEmailEventFlowService;
use App\Services\Model\ISummitEventTypeService;
use App\Services\Model\ISummitMediaFileTypeService;
use App\Services\Model\ISummitMediaUploadTypeService;
use App\Services\Model\ISummitMetricService;
use App\Services\Model\ISummitOrderExtraQuestionTypeService;
use App\Services\Model\ISummitPushNotificationService;
use App\Services\Model\ISummitRefundPolicyTypeService;
@ -385,6 +387,12 @@ final class ModelServicesProvider extends ServiceProvider
IPresentationVideoMediaUploadProcessor::class,
PresentationVideoMediaUploadProcessor::class
);
App::singleton
(
ISummitMetricService::class,
SummitMetricService::class
);
}
/**
@ -444,7 +452,8 @@ final class ModelServicesProvider extends ServiceProvider
ISummitAdministratorPermissionGroupService::class,
ISummitMediaFileTypeService::class,
ISummitMediaUploadTypeService::class,
IPresentationVideoMediaUploadProcessor::class
IPresentationVideoMediaUploadProcessor::class,
ISummitMetricService::class,
];
}
}

View File

@ -0,0 +1,40 @@
<?php namespace App\Services\Utils;
/**
* 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 Illuminate\Support\Facades\Request;
/**
* Class UserClientHelper
* @package App\Services\Utils
*/
final class UserClientHelper
{
/**
* returns user current ip address
* @return string
*/
public static function getUserIp()
{
$ip = isset($_SERVER['HTTP_CLIENT_IP']) ? $_SERVER['HTTP_CLIENT_IP'] : isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'] ?? '';
return $ip;
}
public static function getUserOrigin()
{
return $_SERVER['HTTP_REFERER']?? '';
}
public static function getUserBrowser()
{
return $_SERVER['HTTP_USER_AGENT']??'';
}
}

View File

@ -0,0 +1,81 @@
<?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 Version20201014155708
* @package Database\Migrations\Model
*/
class Version20201014155708 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
$builder = new Builder($schema);
if(!$schema->hasTable("SummitMetric")) {
$builder->create('SummitMetric', function (Table $table) {
$table->integer("ID", true, false);
$table->primary("ID");
$table->timestamp('Created');
$table->timestamp('LastEdited');
$table->string('ClassName');
$table->string('Type')->setNotnull(true)->setDefault('GENERAL');
$table->string('Ip')->setNotnull(false);
$table->string('Origin')->setNotnull(false);
$table->string('Browser')->setNotnull(false);
$table->timestamp('IngressDate')->setNotnull(false);
$table->timestamp('OutgressDate')->setNotnull(false);
// FK
$table->integer("MemberID", false, false)->setNotnull(false)->setDefault('NULL');
$table->index("MemberID", "MemberID");
$table->foreign("Member", "MemberID", "ID", ["onDelete" => "CASCADE"]);
// FK
$table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL');
$table->index("SummitID", "SummitID");
$table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]);
});
}
if(!$schema->hasTable("SummitSponsorMetric")) {
$builder->create('SummitSponsorMetric', function (Table $table) {
$table->integer("ID", true, false);
$table->primary("ID");
$table->string('ClassName');
// 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,53 @@
<?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 Version20201014155719
* @package Database\Migrations\Model
*/
class Version20201014155719 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
// make enum
$sql = <<<SQL
ALTER TABLE SummitMetric MODIFY ClassName
enum(
'SummitMetric', 'SummitEventAttendanceMetric', 'SummitSponsorMetric'
) default 'SummitMetric';
SQL;
$this->addSql($sql);
// make enum
$sql = <<<SQL
ALTER TABLE SummitMetric MODIFY Type
enum(
'GENERAL', 'LOBBY', 'SPONSOR','EVENT'
) default 'GENERAL';
SQL;
$this->addSql($sql);
}
/**
* @param Schema $schema
*/
public function down(Schema $schema)
{
}
}

View File

@ -0,0 +1,89 @@
<?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 Version20201014161727
* @package Database\Migrations\Model
*/
final class Version20201014161727 extends AbstractMigration
{
/**
* @param Schema $schema
*/
public function up(Schema $schema)
{
// migrate data
$sql = <<<SQL
INSERT INTO SummitMetric (ID, Created, LastEdited, ClassName, IngressDate, OutgressDate, MemberID, Type, SummitID)
SELECT SummitEventAttendanceMetric.ID,
SummitEventAttendanceMetric.Created,
SummitEventAttendanceMetric.LastEdited,
SummitEventAttendanceMetric.ClassName, IngressDate, OutgressDate, MemberID, 'EVENT', SummitEvent.SummitID
FROM SummitEventAttendanceMetric
INNER JOIN SummitEvent ON SummitEvent.ID = SummitEventAttendanceMetric.SummitEventID;
SQL;
$this->addSql($sql);
$sql = <<<SQL
alter table SummitEventAttendanceMetric modify ID int not null;
SQL;
$this->addSql($sql);
$sql = <<<SQL
ALTER TABLE SummitEventAttendanceMetric ADD CONSTRAINT FK_SummitEventAttendanceMetric_SummitMetric FOREIGN KEY (ID) REFERENCES SummitMetric (ID) ON DELETE CASCADE;
SQL;
$this->addSql($sql);
$sql = <<<SQL
ALTER TABLE SummitSponsorMetric ADD CONSTRAINT FK_SummitSponsorMetricc_SummitMetric FOREIGN KEY (ID) REFERENCES SummitMetric (ID) ON DELETE CASCADE;
SQL;
$this->addSql($sql);
$sql = <<<SQL
alter table SummitEventAttendanceMetric drop column Created;
SQL;
$this->addSql($sql);
$sql = <<<SQL
alter table SummitEventAttendanceMetric drop column LastEdited;
SQL;
$this->addSql($sql);
$sql = <<<SQL
alter table SummitEventAttendanceMetric drop column IngressDate;
SQL;
$this->addSql($sql);
$sql = <<<SQL
alter table SummitEventAttendanceMetric drop column OutgressDate;
SQL;
$this->addSql($sql);
$sql = <<<SQL
alter table SummitEventAttendanceMetric drop column MemberID;
SQL;
$this->addSql($sql);
}
/**
* @param Schema $schema
*/
public function down(Schema $schema)
{
}
}

View File

@ -6044,6 +6044,24 @@ class ApiEndpointsSeeder extends Seeder
IGroup::Administrators,
]
],
[
'name' => 'metric-enter',
'route' => '/api/v1/summits/{id}/metrics/enter',
'http_method' => 'PUT',
'scopes' => [
sprintf(SummitScopes::EnterEvent, $current_realm),
sprintf(SummitScopes::WriteMetrics, $current_realm)
],
],
[
'name' => 'metric-leave',
'route' => '/api/v1/summits/{id}/metrics/leave',
'http_method' => 'POST',
'scopes' => [
sprintf(SummitScopes::LeaveEvent, $current_realm),
sprintf(SummitScopes::WriteMetrics, $current_realm)
],
],
]
);
}

View File

@ -85,6 +85,16 @@ final class ApiScopesSeeder extends Seeder
'short_description' => '',
'description' => '',
],
[
'name' => sprintf(SummitScopes::WriteMetrics, $current_realm),
'short_description' => '',
'description' => '',
],
[
'name' => sprintf(SummitScopes::ReadMetrics, $current_realm),
'short_description' => '',
'description' => '',
],
[
'name' => sprintf(SummitScopes::AddMyRSVP, $current_realm),
'short_description' => 'Allows to add Summit events as RSVP',

View File

@ -0,0 +1,91 @@
<?php
/**
* 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.
**/
class OAuth2SummitMetricsApiControllerTest extends ProtectedApiTest
{
/**
* @param int $summit_id
* @return mixed
*/
public function testEnter($summit_id = 18){
$params = [
'id' => $summit_id,
];
$data = [
'type' => \models\summit\ISummitMetricType::General,
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json",
'REMOTE_ADDR' => '10.1.0.1',
'HTTP_REFERER' => 'https://www.test.com'
];
$response = $this->action(
"PUT",
"OAuth2SummitMetricsApiController@enter",
$params,
[],
[],
[],
$headers,
json_encode($data)
);
$content = $response->getContent();
$this->assertResponseStatus(201);
$metric = json_decode($content);
$this->assertTrue(!is_null($metric));
return $metric;
}
/**
* @param int $summit_id
* @return mixed
*/
public function testEnterEvent($summit_id = 18, $event_id = 706){
$params = [
'id' => $summit_id,
'event_id' => $event_id,
'member_id' => 'me'
];
$headers = [
"HTTP_Authorization" => " Bearer " . $this->access_token,
"CONTENT_TYPE" => "application/json",
'REMOTE_ADDR' => '10.1.0.1',
'HTTP_REFERER' => 'https://www.test.com'
];
$response = $this->action(
"PUT",
"OAuth2SummitMetricsApiController@enterToEvent",
$params,
[],
[],
[],
$headers
);
$content = $response->getContent();
$this->assertResponseStatus(201);
$metric = json_decode($content);
$this->assertTrue(!is_null($metric));
return $metric;
}
}

View File

@ -109,6 +109,8 @@ class AccessTokenServiceStub implements IAccessTokenService
sprintf(SummitScopes::WriteSummitMediaFileTypes, $url),
sprintf(CompanyScopes::Write, $url),
sprintf(CompanyScopes::Read, $url),
sprintf(SummitScopes::WriteMetrics, $url),
sprintf(SummitScopes::ReadMetrics, $url),
);
return AccessToken::createFromParams(
@ -202,6 +204,8 @@ class AccessTokenServiceStub2 implements IAccessTokenService
sprintf(SummitScopes::LeaveEvent, $url),
sprintf(SummitScopes::ReadSummitMediaFileTypes, $url),
sprintf(SummitScopes::WriteSummitMediaFileTypes, $url),
sprintf(SummitScopes::WriteMetrics, $url),
sprintf(SummitScopes::ReadMetrics, $url),
sprintf(CompanyScopes::Write, $url),
sprintf(CompanyScopes::Read, $url),
);