diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php index f59f3aee..e3c5f7e9 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php @@ -23,6 +23,7 @@ use Illuminate\Support\Facades\Validator; use libs\utils\HTMLCleaner; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; +use models\main\IMemberRepository; use models\oauth2\IResourceServerContext; use models\summit\IEventFeedbackRepository; use models\summit\ISpeakerRepository; @@ -62,6 +63,11 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController */ private $event_feedback_repository; + /** + * @var IMemberRepository + */ + private $member_repository; + public function __construct ( @@ -69,6 +75,7 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController ISummitEventRepository $event_repository, ISpeakerRepository $speaker_repository, IEventFeedbackRepository $event_feedback_repository, + IMemberRepository $member_repository, ISummitService $service, IResourceServerContext $resource_server_context ) { @@ -77,6 +84,7 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController $this->speaker_repository = $speaker_repository; $this->event_repository = $event_repository; $this->event_feedback_repository = $event_feedback_repository; + $this->member_repository = $member_repository; $this->service = $service; } @@ -408,6 +416,12 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController if(!Request::isJson()) return $this->error400(); $data = Input::json(); + $current_member = null; + $member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (!is_null($member_id)){ + $current_member = $this->member_repository->getById($member_id); + } + $rules = [ // summit event rules 'title' => 'sometimes|string|max:100', @@ -427,13 +441,14 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController 'tags' => 'sometimes|string_array', 'sponsors' => 'sometimes|int_array', // presentation rules - 'attendees_expected_learnt' => 'sometimes|string|max:1000', - 'attending_media' => 'sometimes|boolean', - 'to_record' => 'sometimes|boolean', - 'speakers' => 'sometimes|int_array', - 'moderator_speaker_id' => 'sometimes|integer', + 'attendees_expected_learnt' => 'sometimes|string|max:1000', + 'attending_media' => 'sometimes|boolean', + 'to_record' => 'sometimes|boolean', + 'speakers' => 'sometimes|int_array', + 'moderator_speaker_id' => 'sometimes|integer', // group event - 'groups' => 'sometimes|int_array', + 'groups' => 'sometimes|int_array', + 'occupancy' => 'sometimes|in:EMPTY,25%,50%,75%,FULL' ]; // Creates a Validator instance and validates the data. @@ -454,7 +469,7 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController 'social_summary', ]; - $event = $this->service->updateEvent($summit, $event_id, HTMLCleaner::cleanData($data->all(), $fields)); + $event = $this->service->updateEvent($summit, $event_id, HTMLCleaner::cleanData($data->all(), $fields), $current_member); return $this->ok(SerializerRegistry::getInstance()->getSerializer($event)->serialize()); diff --git a/app/Http/routes.php b/app/Http/routes.php index 443c829c..f7a0191d 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -258,7 +258,7 @@ Route::group([ Route::get('', 'OAuth2SummitEventsApiController@getEvent'); Route::get('/published', [ 'middleware' => 'cache:'.Config::get('cache_api_response.get_published_event_response_lifetime', 300), 'uses' => 'OAuth2SummitEventsApiController@getScheduledEvent']); - Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitEventsApiController@updateEvent' ]); + Route::put('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators|summit-room-administrators', 'uses' => 'OAuth2SummitEventsApiController@updateEvent' ]); Route::delete('', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitEventsApiController@deleteEvent' ]); Route::put('/publish', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitEventsApiController@publishEvent']); Route::delete('/publish', [ 'middleware' => 'auth.user:administrators|summit-front-end-administrators', 'uses' => 'OAuth2SummitEventsApiController@unPublishEvent']); diff --git a/app/ModelSerializers/BaseSerializerTypeSelector.php b/app/ModelSerializers/BaseSerializerTypeSelector.php index 63c9eff0..b023b46e 100644 --- a/app/ModelSerializers/BaseSerializerTypeSelector.php +++ b/app/ModelSerializers/BaseSerializerTypeSelector.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use App\Models\Foundation\Main\IGroup; use models\main\IMemberRepository; use models\oauth2\IResourceServerContext; use models\main\Group; @@ -54,7 +55,7 @@ final class BaseSerializerTypeSelector implements ISerializerTypeSelector $serializer_type = SerializerRegistry::SerializerType_Public; $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); if(!is_null($current_member_id) && $member = $this->member_repository->getById($current_member_id)){ - if($member->isOnGroup(Group::SummitAdministrators)){ + if($member->isOnGroup(IGroup::SummitAdministrators)){ $serializer_type = SerializerRegistry::SerializerType_Private; } } diff --git a/app/Models/Foundation/Main/Group.php b/app/Models/Foundation/Main/Group.php index 3fcc5a3c..9c00255b 100644 --- a/app/Models/Foundation/Main/Group.php +++ b/app/Models/Foundation/Main/Group.php @@ -23,10 +23,6 @@ use models\utils\SilverstripeBaseModel; */ class Group extends SilverstripeBaseModel { - const AdminGroupCode = 'administrators'; - const CommunityMembersCode = 'community-members'; - const FoundationMembersCode = 'foundation-members'; - const SummitAdministrators = 'summit-front-end-administrators'; public function __construct(){ parent::__construct(); diff --git a/app/Models/Foundation/Main/IGroup.php b/app/Models/Foundation/Main/IGroup.php new file mode 100644 index 00000000..f98314e3 --- /dev/null +++ b/app/Models/Foundation/Main/IGroup.php @@ -0,0 +1,28 @@ +getGroupByCode(Group::AdminGroupCode); + $admin_group = $this->getGroupByCode(IGroup::Administrators); return $admin_group != false && !is_null($admin_group); } diff --git a/app/Models/Foundation/Summit/Events/SummitEvent.php b/app/Models/Foundation/Summit/Events/SummitEvent.php index 00bd4810..c86dea9c 100644 --- a/app/Models/Foundation/Summit/Events/SummitEvent.php +++ b/app/Models/Foundation/Summit/Events/SummitEvent.php @@ -58,6 +58,12 @@ class SummitEvent extends SilverstripeBaseModel */ protected $social_summary; + /** + * @ORM\Column(name="Occupancy", type="string") + * @var string + */ + protected $occupancy; + /** * @ORM\Column(name="StartDate", type="datetime") * @var \DateTime @@ -907,4 +913,21 @@ class SummitEvent extends SilverstripeBaseModel $this->rsvp_max_user_wait_list_number = $rsvp_max_user_wait_list_number; } + /** + * @return string + */ + public function getOccupancy() + { + return $this->occupancy; + } + + /** + * @param string $occupancy + */ + public function setOccupancy($occupancy) + { + $this->occupancy = $occupancy; + } + + } \ No newline at end of file diff --git a/app/Permissions/IPermissionsManager.php b/app/Permissions/IPermissionsManager.php new file mode 100644 index 00000000..f2dc0f92 --- /dev/null +++ b/app/Permissions/IPermissionsManager.php @@ -0,0 +1,28 @@ +config) > 0 ) return; + + $path = sprintf("%s/permissions.yml", dirname(__FILE__)); + $yaml = Yaml::parse(file_get_contents($path)); + if(!is_null($yaml) && count($yaml)) + { + foreach($yaml as $entities => $entity){ + foreach ($entity as $permissions_per_role){ + $entity_name = array_keys($entity)[0]; + $entity_config = []; + foreach ($permissions_per_role as $permission_per_role){ + $role = array_keys($permission_per_role)[0]; + $entity_config[$role] = []; + foreach($permission_per_role as $permissions){ + foreach($permissions as $permission) + $entity_config[$role][] = $permission; + } + } + $this->config[$entity_name] = $entity_config; + } + }} + + } + /** + * @param Member $current_user + * @param string $entity_name + * @param array $data + * @return bool + */ + public function canEditFields(Member $current_user, $entity_name, array $data){ + $this->loadConfiguration(); + $groups = $current_user->getGroupsCodes(); + + if(!isset($this->config[$entity_name])) + throw new \InvalidArgumentException(sprintf("entity %s does not has a configuration set", $entity_name)); + + $entity_config = $this->config[$entity_name]; + + foreach($groups as $group_code) { + if(!isset($entity_config[$group_code])) continue; + $allowed_fields = $entity_config[$group_code]; + if(count($allowed_fields) == 0) return false; + if(in_array(self::AllFieldsWillCard, $allowed_fields)) return true; + $fields = array_keys($data); + $diff = array_diff($fields, $allowed_fields); + if(count($diff) > 0) + return false; + return true; + } + return false; + } +} \ No newline at end of file diff --git a/app/Permissions/permissions.yml b/app/Permissions/permissions.yml new file mode 100644 index 00000000..01865856 --- /dev/null +++ b/app/Permissions/permissions.yml @@ -0,0 +1,13 @@ +# here you define per Entity ClassName allowed fields to edit per user role +- SummitEvent: + - administrators: + - __all__ + - summit-front-end-administrators: + - __all__ + - summit-room-administrators: + - occupancy +- Presentation: + - administrators: + - __all__ + - summit-front-end-administrators: + - __all__ diff --git a/app/Repositories/Summit/DoctrineSummitEventRepository.php b/app/Repositories/Summit/DoctrineSummitEventRepository.php index cf190d27..840a2b3c 100644 --- a/app/Repositories/Summit/DoctrineSummitEventRepository.php +++ b/app/Repositories/Summit/DoctrineSummitEventRepository.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use App\Models\Foundation\Main\IGroup; use Doctrine\ORM\Tools\Pagination\Paginator; use models\main\Group; use models\summit\ISummitEventRepository; @@ -214,7 +215,7 @@ final class DoctrineSummitEventRepository $query = $query->leftJoin('sp.registration_request', "sprr", Join::LEFT_JOIN); } - $can_view_private_events = self::isCurrentMemberOnGroup(Group::SummitAdministrators); + $can_view_private_events = self::isCurrentMemberOnGroup(IGroup::SummitAdministrators); if(!$can_view_private_events){ $query = $query @@ -305,7 +306,7 @@ final class DoctrineSummitEventRepository } - $can_view_private_events = self::isCurrentMemberOnGroup(Group::SummitAdministrators); + $can_view_private_events = self::isCurrentMemberOnGroup(IGroup::SummitAdministrators); if(!$can_view_private_events){ $query = $query diff --git a/app/Services/Model/ISummitService.php b/app/Services/Model/ISummitService.php index c40dee57..66b8a3f5 100644 --- a/app/Services/Model/ISummitService.php +++ b/app/Services/Model/ISummitService.php @@ -40,9 +40,10 @@ interface ISummitService * @param Summit $summit * @param int $event_id * @param array $data + * @param null|Member $current_member * @return SummitEvent */ - public function updateEvent(Summit $summit, $event_id, array $data); + public function updateEvent(Summit $summit, $event_id, array $data, Member $current_member = null); /** * @param Summit $summit diff --git a/app/Services/Model/SummitService.php b/app/Services/Model/SummitService.php index 873d7dcb..a7ea4029 100644 --- a/app/Services/Model/SummitService.php +++ b/app/Services/Model/SummitService.php @@ -21,6 +21,7 @@ use App\Http\Utils\FileUploader; use App\Models\Foundation\Summit\Factories\SummitFactory; use App\Models\Foundation\Summit\Repositories\IDefaultSummitEventTypeRepository; use App\Models\Utils\IntervalParser; +use App\Permissions\IPermissionsManager; use App\Services\Model\AbstractService; use App\Services\Model\IFolderService; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; @@ -161,6 +162,11 @@ final class SummitService extends AbstractService implements ISummitService */ private $default_event_types_repository; + /** + * @var IPermissionsManager + */ + private $permissions_manager; + /** * SummitService constructor. * @param ISummitRepository $summit_repository @@ -178,6 +184,7 @@ final class SummitService extends AbstractService implements ISummitService * @param ICompanyRepository $company_repository * @param IGroupRepository $group_repository, * @param IDefaultSummitEventTypeRepository $default_event_types_repository + * @param IPermissionsManager $permissions_manager * @param ITransactionService $tx_service */ public function __construct @@ -197,6 +204,7 @@ final class SummitService extends AbstractService implements ISummitService ICompanyRepository $company_repository, IGroupRepository $group_repository, IDefaultSummitEventTypeRepository $default_event_types_repository, + IPermissionsManager $permissions_manager, ITransactionService $tx_service ) { @@ -216,6 +224,7 @@ final class SummitService extends AbstractService implements ISummitService $this->company_repository = $company_repository; $this->group_repository = $group_repository; $this->default_event_types_repository = $default_event_types_repository; + $this->permissions_manager = $permissions_manager; } /** @@ -529,11 +538,12 @@ final class SummitService extends AbstractService implements ISummitService * @param Summit $summit * @param int $event_id * @param array $data + * @param null|Member $current_member * @return SummitEvent */ - public function updateEvent(Summit $summit, $event_id, array $data) + public function updateEvent(Summit $summit, $event_id, array $data, Member $current_member = null) { - return $this->saveOrUpdateEvent($summit, $data, $event_id); + return $this->saveOrUpdateEvent($summit, $data, $event_id, $current_member); } /** @@ -616,16 +626,25 @@ final class SummitService extends AbstractService implements ISummitService return true; } + /** * @param Summit $summit * @param array $data * @param null|int $event_id + * @param Member|null $current_member * @return SummitEvent + * @throws EntityNotFoundException + * @throws ValidationException + * @throws Exception */ - private function saveOrUpdateEvent(Summit $summit, array $data, $event_id = null) + private function saveOrUpdateEvent(Summit $summit, array $data, $event_id = null, Member $current_member = null) { - return $this->tx_service->transaction(function () use ($summit, $data, $event_id) { + return $this->tx_service->transaction(function () use ($summit, $data, $event_id, $current_member) { + + if(!is_null($current_member) && !$this->permissions_manager->canEditFields($current_member, 'SummitEvent', $data)){ + throw new ValidationException(sprintf("user %s cant set requested summit event fields", $current_member->getId())); + } $event_type = null; @@ -721,6 +740,9 @@ final class SummitService extends AbstractService implements ISummitService if (isset($data['social_description'])) $event->setSocialSummary(strip_tags(trim($data['social_description']))); + if (isset($data['occupancy'])) + $event->setOccupancy($data['occupancy']); + $event->setAllowFeedBack(isset($data['allow_feedback'])? filter_var($data['allow_feedback'], FILTER_VALIDATE_BOOLEAN) : false); diff --git a/app/Services/ServicesProvider.php b/app/Services/ServicesProvider.php index 281a29c4..5e56f261 100644 --- a/app/Services/ServicesProvider.php +++ b/app/Services/ServicesProvider.php @@ -11,6 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use App\Permissions\IPermissionsManager; +use App\Permissions\PermissionsManager; use App\Services\Apis\CalendarSync\ICalendarSyncRemoteFacadeFactory; use App\Services\Apis\GoogleGeoCodingAPI; use App\Services\Apis\IGeoCodingAPI; @@ -72,6 +74,8 @@ final class ServicesProvider extends ServiceProvider { App::singleton(ICacheService::class, RedisCacheService::class); + App::singleton(IPermissionsManager::class, PermissionsManager::class); + App::singleton(\libs\utils\ITransactionService::class, function(){ return new \services\utils\DoctrineTransactionService('ss'); }); diff --git a/tests/OAuth2SummitEventsApiTest.php b/tests/OAuth2SummitEventsApiTest.php index 02020807..581c7991 100644 --- a/tests/OAuth2SummitEventsApiTest.php +++ b/tests/OAuth2SummitEventsApiTest.php @@ -335,6 +335,43 @@ final class OAuth2SummitEventsApiTest extends ProtectedApiTest return $event; } + public function testUpdateEventOccupancy(){ + + $params = array + ( + 'id' => 23, + 'event_id' => 20345, + ); + + $data = [ + 'occupancy' => '25%' + ]; + + $headers = array + ( + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ); + + $response = $this->action + ( + "PUT", + "OAuth2SummitEventsApiController@updateEvent", + $params, + array(), + array(), + array(), + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $event = json_decode($content); + $this->assertTrue($event->id > 0); + return $event; + } + public function testUnPublishEvent() { $event = $this->testPublishEvent(1461529800, 1461533400);