diff --git a/app/Console/Commands/ChatTeamMessagesSender.php b/app/Console/Commands/ChatTeamMessagesSender.php new file mode 100644 index 00000000..94c9c496 --- /dev/null +++ b/app/Console/Commands/ChatTeamMessagesSender.php @@ -0,0 +1,70 @@ +service = $service; + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $bach_size = $this->argument('bach_size'); + if(is_null($bach_size)) $bach_size = 100; + $res = $this->service->sendMessages($bach_size); + $this->info(sprintf("total messages sent %s", $res)); + } +} \ No newline at end of file diff --git a/app/Console/Commands/SummitJsonGenerator.php b/app/Console/Commands/SummitJsonGenerator.php index 5cfa9eb0..7f68f9be 100644 --- a/app/Console/Commands/SummitJsonGenerator.php +++ b/app/Console/Commands/SummitJsonGenerator.php @@ -17,8 +17,6 @@ use libs\utils\ICacheService; use models\summit\ISummitRepository; use ModelSerializers\SerializerRegistry; use services\model\ISummitService; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Input\InputArgument; use Illuminate\Support\Facades\Config; /** @@ -42,6 +40,12 @@ final class SummitJsonGenerator extends Command { */ private $cache_service; + /** + * SummitJsonGenerator constructor. + * @param ISummitRepository $repository + * @param ISummitService $service + * @param ICacheService $cache_service + */ public function __construct( ISummitRepository $repository, ISummitService $service, @@ -102,8 +106,8 @@ final class SummitJsonGenerator extends Command { $delta = $end - $start; $this->info(sprintf("execution call %s seconds", $delta)); $current_time = time(); - $key_current = sprintf('/api/v1/summits/%s.expand=%s','current', urlencode($expand)); - $key_id = sprintf('/api/v1/summits/%s.expand=%s',$summit->getIdentifier(), urlencode($expand)); + $key_current = sprintf('/api/v1/summits/%s.expand=%s','current', urlencode($expand)); + $key_id = sprintf('/api/v1/summits/%s.expand=%s', $summit->getIdentifier(), urlencode($expand)); $cache_lifetime = intval(Config::get('server.response_cache_lifetime', 300)); diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 951ba586..55e25f52 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -14,6 +14,7 @@ class Kernel extends ConsoleKernel */ protected $commands = [ \App\Console\Commands\SummitJsonGenerator::class, + \App\Console\Commands\ChatTeamMessagesSender::class, ]; /** @@ -24,9 +25,15 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - // current + //Current $schedule->command('summit:json-generator')->everyTenMinutes()->withoutOverlapping(); - //austin + //Austin $schedule->command('summit:json-generator 6')->everyTenMinutes()->withoutOverlapping(); + //BCN + $schedule->command('summit:json-generator 7')->everyTenMinutes()->withoutOverlapping(); + //Boston + $schedule->command('summit:json-generator 22')->everyTenMinutes()->withoutOverlapping(); + // teams messages + $schedule->command('teams:message-sender 100')->everyMinute()->withoutOverlapping(); } } diff --git a/app/Http/Controllers/apis/protected/main/OAuth2MembersApiController.php b/app/Http/Controllers/apis/protected/main/OAuth2MembersApiController.php new file mode 100644 index 00000000..6dcbcde5 --- /dev/null +++ b/app/Http/Controllers/apis/protected/main/OAuth2MembersApiController.php @@ -0,0 +1,123 @@ +repository = $member_repository; + } + + public function getMembers(){ + $values = Input::all(); + + $rules = array + ( + 'page' => 'integer|min:1', + 'per_page' => 'required_with:page|integer|min:5|max:100', + ); + + try { + + $validation = Validator::make($values, $rules); + + if ($validation->fails()) { + $ex = new ValidationException(); + throw $ex->setMessages($validation->messages()->toArray()); + } + + // default values + $page = 1; + $per_page = 5; + + if (Input::has('page')) { + $page = intval(Input::get('page')); + $per_page = intval(Input::get('per_page')); + } + + $filter = null; + + if (Input::has('filter')) { + $filter = FilterParser::parse(Input::get('filter'), array + ( + 'irc' => ['=@', '=='], + 'twitter' => ['=@', '=='], + 'first_name' => ['=@', '=='], + 'last_name' => ['=@', '=='], + )); + } + + $order = null; + + if (Input::has('order')) + { + $order = OrderParser::parse(Input::get('order'), array + ( + 'first_name', + 'last_name', + 'id', + )); + } + + if(is_null($filter)) $filter = new Filter(); + + $data = $this->repository->getAllByPage(new PagingInfo($page, $per_page), $filter, $order); + return $this->ok($data->toArray(Request::input('expand', ''))); + } + catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412($ex2->getMessages()); + } + catch(FilterParserException $ex3){ + Log::warning($ex3); + return $this->error412($ex3->getMessages()); + } + catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/apis/protected/main/OAuth2TeamInvitationsApiController.php b/app/Http/Controllers/apis/protected/main/OAuth2TeamInvitationsApiController.php new file mode 100644 index 00000000..7518453b --- /dev/null +++ b/app/Http/Controllers/apis/protected/main/OAuth2TeamInvitationsApiController.php @@ -0,0 +1,137 @@ +repository = $repository; + $this->service = $service; + } + + public function getMyInvitations(){ + + try { + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $invitations = $this->repository->getInvitationsByInvitee($current_member_id); + + $response = new PagingResponse + ( + count($invitations), + count($invitations), + 1, + 1, + $invitations + ); + + return $this->ok($response->toArray($expand = Input::get('expand',''))); + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $invitation_id + * @return mixed + */ + public function acceptInvitation($invitation_id){ + try { + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $team_member = $this->service->acceptInvitation($invitation_id, $current_member_id); + return $this->created(SerializerRegistry::getInstance()->getSerializer($team_member)->serialize($expand = '')); + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $invitation_id + * @return mixed + */ + public function declineInvitation($invitation_id){ + try { + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + $this->service->declineInvitation($invitation_id, $current_member_id); + return $this->deleted(); + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/apis/protected/main/OAuth2TeamsApiController.php b/app/Http/Controllers/apis/protected/main/OAuth2TeamsApiController.php new file mode 100644 index 00000000..0349ddc9 --- /dev/null +++ b/app/Http/Controllers/apis/protected/main/OAuth2TeamsApiController.php @@ -0,0 +1,540 @@ +service = $service; + $this->repository = $repository; + $this->message_repository = $message_repository; + $this->member_repository = $member_repository; + } + + /** + * @return mixed + */ + public function getMyTeams(){ + try { + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $current_member = $this->member_repository->getById($current_member_id); + if (is_null($current_member)) return $this->error404(); + + $teams = $this->repository->getTeamsByMember($current_member); + + $response = new PagingResponse + ( + count($teams), + count($teams), + 1, + 1, + $teams + ); + + return $this->ok($response->toArray($expand = Input::get('expand',''))); + + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $team_id + * @return mixed + */ + public function getMyTeam($team_id){ + try { + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $current_member = $this->member_repository->getById($current_member_id); + if (is_null($current_member)) return $this->error403(); + + $team = $this->repository->getById($team_id); + + if(is_null($team)) throw new EntityNotFoundException(); + + if(!$team->isMember($current_member)) + throw new EntityNotFoundException(); + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($team)->serialize($expand = Input::get('expand',''))); + + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @return mixed + */ + public function addTeam(){ + try { + + if(!Request::isJson()) + return $this->error403(); + + $data = Input::json(); + + $rules = array + ( + 'name' => 'required|string|max:255', + 'description' => 'required|sometimes|string', + ); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($data->all(), $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $fields = array + ( + 'name', + 'description', + ); + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $current_member = $this->member_repository->getById($current_member_id); + if (is_null($current_member)) return $this->error404(); + + $team = $this->service->addTeam(HTMLCleaner::cleanData($data->all(), $fields), $current_member); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($team)->serialize($expand = 'owner,members,member')); + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $team_id + * @return mixed + */ + public function deleteTeam($team_id){ + try { + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $this->service->deleteTeam($team_id); + + return $this->deleted(); + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $team_id + * @return mixed + */ + public function updateTeam($team_id){ + try { + + if(!Request::isJson()) + return $this->error403(); + + $data = Input::json(); + + $rules = array + ( + 'name' => 'required|string|max:255', + 'description' => 'required|sometimes|string', + ); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($data->all(), $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $fields = array + ( + 'name', + 'description', + ); + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $team = $this->service->updateTeam(HTMLCleaner::cleanData($data->all(), $fields), $team_id); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($team)->serialize($expand = 'owner,members,member')); + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + + } + + /** + * @param $team_id + * @return mixed + */ + public function getMyTeamMessages($team_id){ + + $values = Input::all(); + + $rules = array + ( + 'page' => 'integer|min:1', + 'per_page' => 'required_with:page|integer|min:5|max:100', + ); + + try { + + + $validation = Validator::make($values, $rules); + + if ($validation->fails()) { + $ex = new ValidationException(); + throw $ex->setMessages($validation->messages()->toArray()); + } + + // default values + $page = 1; + $per_page = 5; + + if (Input::has('page')) { + $page = intval(Input::get('page')); + $per_page = intval(Input::get('per_page')); + } + + $filter = null; + + if (Input::has('filter')) { + $filter = FilterParser::parse(Input::get('filter'), array + ( + 'owner_id' => ['=='], + 'sent_date' => ['>', '<', '<=', '>=', '=='], + )); + } + + $order = null; + + if (Input::has('order')) + { + $order = OrderParser::parse(Input::get('order'), array + ( + 'sent_date', + 'id', + )); + } + + if(is_null($filter)) $filter = new Filter(); + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $current_member = $this->member_repository->getById($current_member_id); + if (is_null($current_member)) return $this->error403(); + + $team = $this->repository->getById($team_id); + + if(is_null($team)) throw new EntityNotFoundException(); + + if(!$team->isMember($current_member)) + throw new EntityNotFoundException(); + + $data = $this->message_repository->getAllSentByTeamPaginated + ( + $team_id, + new PagingInfo($page, $per_page), + $filter, + $order + ); + + return $this->ok($data->toArray(Request::input('expand', ''))); + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $team_id + * @return mixed + */ + public function postTeamMessage($team_id){ + try { + + if(!Request::isJson()) + return $this->error403(); + + $data = Input::json(); + + $rules = array + ( + 'body' => 'required|string', + 'priority' => 'required|sometimes|string|chat_message_priority', + ); + + $values = $data->all(); + // Creates a Validator instance and validates the data. + $validation = Validator::make($values, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + if(!isset($values['priority'])) + $values['priority'] = PushNotificationMessagePriority::Normal; + + $message = $this->service->postMessage($team_id, $values); + return $this->created(SerializerRegistry::getInstance()->getSerializer($message)->serialize($expand = 'team,owner')); + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $team_id + * @param $member_id + * @return mixed + */ + public function addMember2MyTeam($team_id, $member_id){ + try { + + if(!Request::isJson()) + return $this->error403(); + + $data = Input::json(); + + $rules = array + ( + 'permission' => 'required|string|team_permission', + ); + + $values = $data->all(); + // Creates a Validator instance and validates the data. + $validation = Validator::make($values, $rules); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $invitation = $this->service->addMember2Team($team_id, $member_id, $values['permission']); + return $this->created(SerializerRegistry::getInstance()->getSerializer($invitation)->serialize($expand = 'team,inviter,invitee')); + + } + 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 (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $team_id + * @param $member_id + * @return mixed + */ + public function removedMemberFromMyTeam($team_id, $member_id){ + try { + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) return $this->error403(); + + $this->service->removeMemberFromTeam($team_id, $member_id); + + return $this->deleted(); + } + 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 (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/apis/protected/summit/OAuth2SummitMembersApiController.php b/app/Http/Controllers/apis/protected/summit/OAuth2SummitMembersApiController.php index d2efb600..8dd7417c 100644 --- a/app/Http/Controllers/apis/protected/summit/OAuth2SummitMembersApiController.php +++ b/app/Http/Controllers/apis/protected/summit/OAuth2SummitMembersApiController.php @@ -46,7 +46,6 @@ final class OAuth2SummitMembersApiController extends OAuth2ProtectedController $this->repository = $member_repository; } - public function getMyMember($summit_id){ $summit = SummitFinderStrategyFactory::build($this->summit_repository)->find($summit_id); diff --git a/app/Http/routes.php b/app/Http/routes.php index 90297d84..f1660538 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -44,6 +44,47 @@ Route::group(array( }); + // members + Route::group(['prefix'=>'members'], function(){ + Route::get('', 'OAuth2MembersApiController@getMembers'); + + Route::group(['prefix'=>'me'], function(){ + + // invitations + Route::group(['prefix'=>'team-invitations'], function(){ + Route::get('', 'OAuth2TeamInvitationsApiController@getMyInvitations'); + Route::group(['prefix'=>'{invitation_id}'], function() { + Route::patch('', 'OAuth2TeamInvitationsApiController@acceptInvitation'); + Route::delete('', 'OAuth2TeamInvitationsApiController@declineInvitation'); + }); + }); + }); + }); + + // teams + Route::group(['prefix'=>'teams'], function(){ + Route::get('', 'OAuth2TeamsApiController@getMyTeams'); + Route::post('', 'OAuth2TeamsApiController@addTeam'); + + Route::group(['prefix' => '{team_id}'], function () { + Route::get('', 'OAuth2TeamsApiController@getMyTeam'); + Route::put('', 'OAuth2TeamsApiController@updateTeam'); + Route::delete('', 'OAuth2TeamsApiController@deleteTeam'); + + Route::group(array('prefix' => 'messages'), function () { + Route::get('', 'OAuth2TeamsApiController@getMyTeamMessages'); + Route::post('', 'OAuth2TeamsApiController@postTeamMessage'); + }); + + Route::group(array('prefix' => 'members'), function () { + Route::group(['prefix' => '{member_id}'], function () { + Route::post('', 'OAuth2TeamsApiController@addMember2MyTeam'); + Route::delete('', 'OAuth2TeamsApiController@removedMemberFromMyTeam'); + }); + }); + }); + }); + // summits Route::group(array('prefix' => 'summits'), function () { diff --git a/app/ModelSerializers/ChatTeams/ChatTeamInvitationSerializer.php b/app/ModelSerializers/ChatTeams/ChatTeamInvitationSerializer.php new file mode 100644 index 00000000..f91af86d --- /dev/null +++ b/app/ModelSerializers/ChatTeams/ChatTeamInvitationSerializer.php @@ -0,0 +1,79 @@ + 'team_id:json_int', + 'InviteeId' => 'invitee_id:json_int', + 'InviterId' => 'inviter_id:json_int', + 'Permission' => 'permission:json_string', + 'IsAccepted' => 'is_accepted:json_boolean', + ); + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = array(), array $relations = array(), array $params = array() ) + { + $invitation = $this->object; + if(! $invitation instanceof ChatTeamInvitation) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + if (!empty($expand)) { + $expand = explode(',', $expand); + foreach ($expand as $relation) { + switch (trim($relation)) { + case 'inviter':{ + if(isset($values['inviter_id'])) + { + unset($values['inviter_id']); + $values['inviter'] = SerializerRegistry::getInstance()->getSerializer($invitation->getInviter())->serialize(); + } + } + break; + case 'invitee':{ + if(isset($values['invitee_id'])) + { + unset($values['invitee_id']); + $values['invitee'] = SerializerRegistry::getInstance()->getSerializer($invitation->getInvitee())->serialize(); + } + } + break; + case 'team':{ + if(isset($values['team_id'])) + { + unset($values['team_id']); + $values['team'] = SerializerRegistry::getInstance()->getSerializer($invitation->getTeam())->serialize(); + } + } + break; + } + } + } + return $values; + } + +} \ No newline at end of file diff --git a/app/ModelSerializers/ChatTeams/ChatTeamMemberSerializer.php b/app/ModelSerializers/ChatTeams/ChatTeamMemberSerializer.php new file mode 100644 index 00000000..f56ea6c7 --- /dev/null +++ b/app/ModelSerializers/ChatTeams/ChatTeamMemberSerializer.php @@ -0,0 +1,63 @@ + 'team_id:json_int', + 'MemberId' => 'member_id:json_int', + 'Permission' => 'permission:json_string', + ); + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = array(), array $relations = array(), array $params = array() ) + { + $team_member = $this->object; + if(! $team_member instanceof ChatTeamMember) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if (!empty($expand)) { + $expand = explode(',', $expand); + foreach ($expand as $relation) { + switch (trim($relation)) { + case 'member':{ + if(isset($values['member_id'])) + { + unset($values['member_id']); + $values['member'] = SerializerRegistry::getInstance()->getSerializer($team_member->getMember())->serialize(); + } + } + break; + } + } + } + + return $values; + } + +} \ No newline at end of file diff --git a/app/ModelSerializers/ChatTeams/ChatTeamPushNotificationMessageSerializer.php b/app/ModelSerializers/ChatTeams/ChatTeamPushNotificationMessageSerializer.php new file mode 100644 index 00000000..da8f8666 --- /dev/null +++ b/app/ModelSerializers/ChatTeams/ChatTeamPushNotificationMessageSerializer.php @@ -0,0 +1,75 @@ + 'team_id:json_int', + 'OwnerId' => 'owner_id:json_int', + 'Priority' => 'priority:json_string', + 'Message' => 'body:json_string', + ); + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = array(), array $relations = array(), array $params = array() ) + { + $message = $this->object; + if(! $message instanceof ChatTeamPushNotificationMessage) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if($message->isSent()){ + $values['sent_date'] = $message->getSentDate()->getTimestamp(); + } + + if (!empty($expand)) { + $expand = explode(',', $expand); + foreach ($expand as $relation) { + switch (trim($relation)) { + case 'owner':{ + if(isset($values['owner_id'])) + { + unset($values['owner_id']); + $values['owner'] = SerializerRegistry::getInstance()->getSerializer($message->getOwner())->serialize(); + } + } + break; + case 'team':{ + if(isset($values['team_id'])) + { + unset($values['team_id']); + $values['team'] = SerializerRegistry::getInstance()->getSerializer($message->getTeam())->serialize(); + } + } + break; + } + } + } + + return $values; + } + +} \ No newline at end of file diff --git a/app/ModelSerializers/ChatTeams/ChatTeamSerializer.php b/app/ModelSerializers/ChatTeams/ChatTeamSerializer.php new file mode 100644 index 00000000..e3440bbe --- /dev/null +++ b/app/ModelSerializers/ChatTeams/ChatTeamSerializer.php @@ -0,0 +1,70 @@ + 'name:json_string', + 'Description' => 'description:json_string', + 'OwnerId' => 'owner_id:json_int', + ); + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = array(), array $relations = array(), array $params = array() ) + { + $team = $this->object; + if(! $team instanceof ChatTeam) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + $members = []; + + foreach($team->getMembers() as $member){ + $members[] = SerializerRegistry::getInstance()->getSerializer($member)->serialize($expand); + } + + $values['members'] = $members; + + if (!empty($expand)) { + $expand = explode(',', $expand); + foreach ($expand as $relation) { + switch (trim($relation)) { + case 'owner':{ + if(isset($values['owner_id'])) + { + unset($values['owner_id']); + $values['owner'] = SerializerRegistry::getInstance()->getSerializer($team->getOwner())->serialize(); + } + } + break; + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/SerializerRegistry.php b/app/ModelSerializers/SerializerRegistry.php index e3dba5f0..6d60aee0 100644 --- a/app/ModelSerializers/SerializerRegistry.php +++ b/app/ModelSerializers/SerializerRegistry.php @@ -1,5 +1,12 @@ registry['SummitPushNotification'] = SummitPushNotificationSerializer::class; + + // teams + $this->registry['ChatTeam'] = ChatTeamSerializer::class; + $this->registry['ChatTeamMember'] = ChatTeamMemberSerializer::class; + $this->registry['ChatTeamInvitation'] = ChatTeamInvitationSerializer::class; + $this->registry['ChatTeamPushNotificationMessage'] = ChatTeamPushNotificationMessageSerializer::class; } /** diff --git a/app/Models/Foundation/Main/ChatTeams/ChatTeam.php b/app/Models/Foundation/Main/ChatTeams/ChatTeam.php new file mode 100644 index 00000000..aeca5de2 --- /dev/null +++ b/app/Models/Foundation/Main/ChatTeams/ChatTeam.php @@ -0,0 +1,285 @@ +members = new ArrayCollection(); + $this->messages = new ArrayCollection(); + $this->invitations = new ArrayCollection(); + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param string $description + */ + public function setDescription($description) + { + $this->description = $description; + } + + /** + * @return ChatTeamMember[] + */ + public function getMembers() + { + return $this->members; + } + + /** + * @param ChatTeamMember[] $members + */ + public function setMembers($members) + { + $this->members = $members; + } + + /** + * @ORM\Column(name="Name", type="string") + * @var string + */ + private $name; + + /** + * @ORM\Column(name="Description", type="string") + * @var string + */ + private $description; + + + /** + * @ORM\OneToMany(targetEntity="ChatTeamMember", mappedBy="team", cascade={"persist"}, orphanRemoval=true) + * @var ChatTeamMember[] + */ + private $members; + + /** + * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\JoinColumn(name="OwnerID", referencedColumnName="ID") + * @var Member + */ + private $owner; + + /** + * @ORM\OneToMany(targetEntity="ChatTeamPushNotificationMessage", mappedBy="team", cascade={"persist"}, orphanRemoval=true) + * @var ChatTeamPushNotificationMessage[] + */ + private $messages; + + /** + * @ORM\OneToMany(targetEntity="ChatTeamInvitation", mappedBy="team", cascade={"persist"}, orphanRemoval=true) + * @var ChatTeamInvitation[] + */ + private $invitations; + + /** + * @return Member + */ + public function getOwner() + { + return $this->owner; + } + + /** + * @return int + */ + public function getOwnerId(){ + try{ + return $this->owner->getId(); + } + catch (\Exception $ex){ + return 0; + } + } + + /** + * @param mixed $owner + */ + public function setOwner($owner) + { + $this->owner = $owner; + } + + /** + * @return ChatTeamPushNotificationMessage[] + */ + public function getMessages() + { + return $this->messages; + } + + /** + * @return ChatTeamInvitation[] + */ + public function getInvitations() + { + return $this->invitations; + } + + /** + * @param ChatTeamInvitation $invitation + */ + public function addInvitation(ChatTeamInvitation $invitation){ + $this->invitations->add($invitation); + $invitation->setTeam($this); + } + + /** + * @param ChatTeamPushNotificationMessage $message + */ + public function addMessage(ChatTeamPushNotificationMessage $message){ + $this->messages->add($message); + $message->setTeam($this); + } + + /** + * @param ChatTeamMember $team_member + */ + public function addMember(ChatTeamMember $team_member){ + $this->members->add($team_member); + $team_member->setTeam($this); + } + + /** + * @param Member $inviter + * @param Member $invitee + * @param string $permission + * @return ChatTeamInvitation + */ + public function createInvitation(Member $inviter, Member $invitee, $permission = ChatTeamPermission::Read){ + $invitation = new ChatTeamInvitation(); + $invitation->setTeam($this); + $invitation->setInviter($inviter); + $invitation->setInvitee($invitee); + $invitation->setPermission($permission); + return $invitation; + } + + public function createMember(Member $member, $permission = ChatTeamPermission::Read){ + $team_member = new ChatTeamMember(); + $team_member->setTeam($this); + $team_member->setPermission($permission); + $team_member->setMember($member); + return $team_member; + } + + /** + * @param Member $owner + * @param string $body + * @param string $priority + * @return ChatTeamPushNotificationMessage + */ + public function createMessage(Member $owner, $body, $priority = PushNotificationMessagePriority::Normal){ + $message = new ChatTeamPushNotificationMessage(); + $message->setTeam($this); + $message->setOwner($owner); + $message->setMessage($body); + $message->setPriority($priority); + return $message; + } + + /** + * @param Member $member + * @return bool + */ + public function isMember(Member $member){ + $res = $this->members->filter(function ($e) use($member){ + return $e->getMember()->getId() == $member->getId(); + }); + return $res->count() > 0; + } + + /** + * @param Member $member + * @return bool + */ + public function canPostMessages(Member $member){ + $res = $this->members->filter(function ($e) use($member){ + return $e->getMember()->getId() == $member->getId(); + }); + if($res->count() == 0) return false; + + $team_member = $res->first(); + + return $team_member->canPostMessages(); + } + + /** + * @param Member $member + * @return bool + */ + public function isOwner(Member $member){ + return $this->getOwnerId() == $member->getId(); + } + + /** + * @param Member $member + * @return bool + */ + public function isAdmin(Member $member){ + $res = $this->members->filter(function ($e) use($member){ + return $e->getMember()->getId() == $member->getId() && $e->isAdmin(); + }); + return $res->count() > 0; + } + + /** + * @param Member $member + */ + public function removeMember(Member $member){ + $res = $this->members->filter(function ($e) use($member){ + return $e->getMember()->getId() == $member->getId(); + }); + if($res->count() == 0) return; + + $team_member = $res->first(); + $this->members->removeElement($team_member); + $team_member->setTeam(null); + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Main/ChatTeams/ChatTeamInvitation.php b/app/Models/Foundation/Main/ChatTeams/ChatTeamInvitation.php new file mode 100644 index 00000000..f930e85b --- /dev/null +++ b/app/Models/Foundation/Main/ChatTeams/ChatTeamInvitation.php @@ -0,0 +1,210 @@ +is_accepted = false; + } + + /** + * @ORM\Column(name="Permission", type="string") + * @var string + */ + private $permission; + + /** + * @return string + */ + public function getPermission() + { + return $this->permission; + } + + /** + * @param string $permission + */ + public function setPermission($permission) + { + $this->permission = $permission; + } + + /** + * @return ChatTeam + */ + public function getTeam() + { + return $this->team; + } + + /** + * @return int + */ + public function getTeamId(){ + try{ + return $this->team->getId(); + } + catch (\Exception $ex){ + return 0; + } + } + + /** + * @param ChatTeam $team + */ + public function setTeam($team) + { + $this->team = $team; + } + + /** + * @return Member + */ + public function getInvitee() + { + return $this->invitee; + } + + /** + * @return int + */ + public function getInviteeId(){ + try{ + return $this->invitee->getId(); + } + catch (\Exception $ex){ + return 0; + } + } + + /** + * @param Member $invitee + */ + public function setInvitee($invitee) + { + $this->invitee = $invitee; + } + + /** + * @return Member + */ + public function getInviter() + { + return $this->inviter; + } + + /** + * @return int + */ + public function getInviterId(){ + try{ + return $this->inviter->getId(); + } + catch (\Exception $ex){ + return 0; + } + } + + /** + * @param Member $inviter + */ + public function setInviter($inviter) + { + $this->inviter = $inviter; + } + + /** + * @ORM\Column(name="Accepted", type="boolean") + * @var bool + */ + private $is_accepted; + + /** + * @ORM\Column(name="AcceptedDate", type="datetime") + * @var \DateTime + */ + private $accepted_date; + + /** + * @return bool + */ + public function getIsAccepted() + { + return $this->is_accepted; + } + + /** + * @return bool + */ + public function isAccepted(){ + return $this->getIsAccepted(); + } + + public function accept() + { + $this->is_accepted = true; + $now = new \DateTime('now', new \DateTimeZone(SilverstripeBaseModel::DefaultTimeZone)); + $this->accepted_date = $now; + } + + /** + * @return \DateTime + */ + public function getAcceptedDate() + { + return $this->accepted_date; + } + + /** + * @param \DateTime $accepted_date + */ + public function setAcceptedDate($accepted_date) + { + $this->accepted_date = $accepted_date; + } + + /** + * @ORM\ManyToOne(targetEntity="models\main\ChatTeam") + * @ORM\JoinColumn(name="TeamID", referencedColumnName="ID") + * @var ChatTeam + */ + private $team; + + /** + * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\JoinColumn(name="InviteeID", referencedColumnName="ID") + * @var Member + */ + private $invitee; + + /** + * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\JoinColumn(name="InviterID", referencedColumnName="ID") + * @var Member + */ + private $inviter; +} \ No newline at end of file diff --git a/app/Models/Foundation/Main/ChatTeams/ChatTeamMember.php b/app/Models/Foundation/Main/ChatTeams/ChatTeamMember.php new file mode 100644 index 00000000..61b0336f --- /dev/null +++ b/app/Models/Foundation/Main/ChatTeams/ChatTeamMember.php @@ -0,0 +1,145 @@ +member; + } + + /** + * @param Member $member + */ + public function setMember($member) + { + $this->member = $member; + } + + /** + * @return ChatTeam + */ + public function getTeam() + { + return $this->team; + } + + /** + * @param ChatTeam $team + */ + public function setTeam($team) + { + $this->team = $team; + } + + /** + * @return string + */ + public function getPermission() + { + return $this->permission; + } + + /** + * @return bool + */ + public function isAdmin(){ + return $this->permission == ChatTeamPermission::Admin; + } + + /** + * @return bool + */ + public function canPostMessages(){ + return $this->isAdmin() || $this->permission == ChatTeamPermission::Write; + } + + /** + * @return bool + */ + public function canDeleteMembers(){ + return $this->isAdmin(); + } + + /** + * @param mixed $permission + */ + public function setPermission($permission) + { + $this->permission = $permission; + } + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(name="ID", type="integer", unique=true, nullable=false) + */ + private $id; + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + public function getMemberId(){ + try{ + return $this->member->getId(); + } + catch (\Exception $ex){ + return 0; + } + } + + public function getTeamId(){ + try{ + return $this->team->getId(); + } + catch (\Exception $ex){ + return 0; + } + } + + /** + * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\JoinColumn(name="MemberID", referencedColumnName="ID") + * @var Member + */ + private $member; + + /** + * @ORM\ManyToOne(targetEntity="models\main\ChatTeam") + * @ORM\JoinColumn(name="ChatTeamID", referencedColumnName="ID") + * @var ChatTeam + */ + private $team; + + /** + * @ORM\Column(name="Permission", type="string") + * @var string + */ + private $permission; + +} \ No newline at end of file diff --git a/app/Models/Foundation/Main/ChatTeams/ChatTeamPermission.php b/app/Models/Foundation/Main/ChatTeams/ChatTeamPermission.php new file mode 100644 index 00000000..779b24cc --- /dev/null +++ b/app/Models/Foundation/Main/ChatTeams/ChatTeamPermission.php @@ -0,0 +1,24 @@ +team; + } + + /** + * @return int + */ + public function getTeamId(){ + try{ + return $this->team->getId(); + } + catch (\Exception $ex){ + return 0; + } + } + + /** + * @param ChatTeam $team + */ + public function setTeam($team) + { + $this->team = $team; + } + /** + * @ORM\ManyToOne(targetEntity="models\main\ChatTeam") + * @ORM\JoinColumn(name="ChatTeamID", referencedColumnName="ID") + * @var ChatTeam + */ + private $team; +} \ No newline at end of file diff --git a/app/Models/Foundation/Main/PushNotificationMessage.php b/app/Models/Foundation/Main/PushNotificationMessage.php new file mode 100644 index 00000000..4e223ec9 --- /dev/null +++ b/app/Models/Foundation/Main/PushNotificationMessage.php @@ -0,0 +1,176 @@ +is_sent = false; + } + + /** + * @ORM\Column(name="Message", type="string") + * @var string + */ + protected $message; + + /** + * @return string + */ + public function getPriority() + { + return $this->priority; + } + + /** + * @param string $priority + */ + public function setPriority($priority) + { + $this->priority = $priority; + } + + /** + * @ORM\Column(name="Priority", type="string") + * @var string + */ + protected $priority; + + /** + * @ORM\Column(name="SentDate", type="datetime") + * @var \DateTime + */ + protected $sent_date; + + /** + * @ORM\Column(name="IsSent", type="boolean") + * @var bool + */ + protected $is_sent; + + /** + * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\JoinColumn(name="OwnerID", referencedColumnName="ID") + * @var Member + */ + protected $owner; + + /** + * @return int + */ + public function getOwnerId(){ + try{ + return $this->owner->getId(); + } + catch (\Exception $ex){ + return 0; + } + } + + /** + * @return string + */ + public function getMessage() + { + return $this->message; + } + + /** + * @return $this + */ + public function markSent(){ + $this->is_sent = true; + $now = new \DateTime('now', new \DateTimeZone(SilverstripeBaseModel::DefaultTimeZone)); + $this->sent_date = $now; + return $this; + } + + /** + * @param string $message + */ + public function setMessage($message) + { + $this->message = $message; + } + + /** + * @return \DateTime + */ + public function getSentDate() + { + return $this->sent_date; + } + + /** + * @param \DateTime $sent_date + */ + public function setSentDate($sent_date) + { + $this->sent_date = $sent_date; + } + + /** + * @return boolean + */ + public function isSent() + { + return $this->is_sent; + } + + /** + * @return boolean + */ + public function getIsSent() + { + return $this->isSent(); + } + + /** + * @param boolean $is_sent + */ + public function setIsSent($is_sent) + { + $this->is_sent = $is_sent; + } + + /** + * @return Member + */ + public function getOwner() + { + return $this->owner; + } + + /** + * @param Member $owner + */ + public function setOwner($owner) + { + $this->owner = $owner; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Main/PushNotificationMessagePriority.php b/app/Models/Foundation/Main/PushNotificationMessagePriority.php new file mode 100644 index 00000000..1ba6affd --- /dev/null +++ b/app/Models/Foundation/Main/PushNotificationMessagePriority.php @@ -0,0 +1,23 @@ +channel = $channel; } - /** - * @return string - */ - public function getMessage() - { - return $this->message; - } - - /** - * @param string $message - */ - public function setMessage($message) - { - $this->message = $message; - } - - /** - * @return \DateTime - */ - public function getSentDate() - { - return $this->sent_date; - } - - /** - * @param \DateTime $sent_date - */ - public function setSentDate($sent_date) - { - $this->sent_date = $sent_date; - } - - /** - * @return boolean - */ - public function isSent() - { - return $this->is_sent; - } - - /** - * @return boolean - */ - public function getIsSent() - { - return $this->isSent(); - } - - /** - * @param boolean $is_sent - */ - public function setIsSent($is_sent) - { - $this->is_sent = $is_sent; - } - - /** - * @return Member - */ - public function getOwner() - { - return $this->owner; - } - - /** - * @param Member $owner - */ - public function setOwner($owner) - { - $this->owner = $owner; - } - /** * @return SummitEvent */ @@ -200,31 +128,6 @@ class SummitPushNotification extends CustomDataObject $this->recipients = $recipients; } - /** - * @ORM\Column(name="Message", type="string") - * @var string - */ - private $message; - - /** - * @ORM\Column(name="SentDate", type="datetime") - * @var \DateTime - */ - private $sent_date; - - /** - * @ORM\Column(name="IsSent", type="boolean") - * @var bool - */ - private $is_sent; - - /** - * @ORM\ManyToOne(targetEntity="models\main\Member") - * @ORM\JoinColumn(name="OwnerID", referencedColumnName="ID") - * @var Member - */ - private $owner; - /** * @ORM\ManyToOne(targetEntity="models\summit\SummitEvent") * @ORM\JoinColumn(name="EventID", referencedColumnName="ID") diff --git a/app/Models/Utils/SilverstripeBaseModel.php b/app/Models/Utils/SilverstripeBaseModel.php index a55bf454..d3ae9526 100644 --- a/app/Models/Utils/SilverstripeBaseModel.php +++ b/app/Models/Utils/SilverstripeBaseModel.php @@ -16,7 +16,7 @@ use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping AS ORM; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; -use Registry; +use LaravelDoctrine\ORM\Facades\Registry; /*** * @ORM\MappedSuperclass @@ -90,7 +90,6 @@ class SilverstripeBaseModel implements IEntity public function __construct() { - $now = new \DateTime('now', new \DateTimeZone(self::DefaultTimeZone)); $this->created = $now; $this->last_edited = $now; @@ -116,7 +115,6 @@ class SilverstripeBaseModel implements IEntity * @return mixed */ protected function prepareRawSQL($sql){ - return Registry::getManager(self::EntityManager)->getConnection()->prepare($sql); } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index c837ce16..567d17f1 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -5,6 +5,8 @@ use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Validator; +use models\main\ChatTeamPermission; +use models\main\PushNotificationMessagePriority; use Monolog\Handler\NativeMailerHandler; /** @@ -70,6 +72,22 @@ class AppServiceProvider extends ServiceProvider } return true; }); + + Validator::extend('team_permission', function($attribute, $value, $parameters, $validator) + { + $validator->addReplacer('team_permission', function($message, $attribute, $rule, $parameters) use ($validator) { + return sprintf("%s should be a valid permission value (ADMIN, WRITE, READ)", $attribute); + }); + return in_array($value, [ChatTeamPermission::Read, ChatTeamPermission::Write, ChatTeamPermission::Admin]); + }); + + Validator::extend('chat_message_priority', function($attribute, $value, $parameters, $validator) + { + $validator->addReplacer('chat_message_priority', function($message, $attribute, $rule, $parameters) use ($validator) { + return sprintf("%s should be a valid message priority value (NORMAL, HIGH)", $attribute); + }); + return in_array($value, [ PushNotificationMessagePriority::Normal, PushNotificationMessagePriority::High]); + }); } /** diff --git a/app/Repositories/Main/Doctrine/DoctrineChatTeamInvitationRepository.php b/app/Repositories/Main/Doctrine/DoctrineChatTeamInvitationRepository.php new file mode 100644 index 00000000..c5e790d9 --- /dev/null +++ b/app/Repositories/Main/Doctrine/DoctrineChatTeamInvitationRepository.php @@ -0,0 +1,40 @@ +getEntityManager() + ->createQueryBuilder() + ->select("i") + ->from(\models\main\ChatTeamInvitation::class, "i") + ->innerJoin('i.invitee', 'iv') + ->innerJoin('iv.id', 'm', Join::WITH, "m.id = :member_id") + ->setParameter('member_id', $invitee_id)->getQuery()->getResult(); + } +} \ No newline at end of file diff --git a/app/Repositories/Main/Doctrine/DoctrineChatTeamPushNotificationMessageRepository.php b/app/Repositories/Main/Doctrine/DoctrineChatTeamPushNotificationMessageRepository.php new file mode 100644 index 00000000..1232b626 --- /dev/null +++ b/app/Repositories/Main/Doctrine/DoctrineChatTeamPushNotificationMessageRepository.php @@ -0,0 +1,137 @@ +getEntityManager()->createQueryBuilder() + ->select("m") + ->from(\models\main\ChatTeamPushNotificationMessage::class, "m") + ->join('m.team', 't') + ->where('m.is_sent = 1') + ->andWhere('t.id = :team_id') + ->setParameter('team_id', $team_id); + + if(!is_null($filter)){ + + $filter->apply2Query($query, array + ( + 'sent_date' => 'm.sent_date:datetime_epoch', + 'owner_id' => new DoctrineJoinFilterMapping + ( + 'm.owner', + 'mb', + "mb.id :operator :value" + ), + )); + } + + if (!is_null($order)) { + + $order->apply2Query($query, array + ( + 'sent_date' => 'm.sent_date', + 'id' => 'm.id', + )); + } else { + //default order + $query = $query->addOrderBy("m.sent_date",'ASC'); + $query = $query->addOrderBy("m.id", 'ASC'); + } + + $query = + $query + ->setFirstResult($paging_info->getOffset()) + ->setMaxResults($paging_info->getPerPage()); + + $paginator = new Paginator($query, $fetchJoinCollection = true); + $total = $paginator->count(); + $data = array(); + + foreach($paginator as $entity) + array_push($data, $entity); + + return new PagingResponse + ( + $total, + $paging_info->getPerPage(), + $paging_info->getCurrentPage(), + $paging_info->getLastPage($total), + $data + ); + } + + /** + * @param int $team_id + * @param PagingInfo $paging_info + * @return PagingResponse + */ + function getAllNotSentByTeamPaginated + ( + $team_id, + PagingInfo $paging_info + ) + { + $query = $this->getEntityManager()->createQueryBuilder() + ->select("m") + ->from(\models\main\ChatTeamPushNotificationMessage::class, "m") + ->join('m.team', 't') + ->where('m.is_sent = 0') + ->andWhere('t.id = :team_id') + ->setParameter('team_id', $team_id); + + $query = + $query + ->setFirstResult($paging_info->getOffset()) + ->setMaxResults($paging_info->getPerPage()); + + $paginator = new Paginator($query, $fetchJoinCollection = true); + $total = $paginator->count(); + $data = array(); + + foreach($paginator as $entity) + array_push($data, $entity); + + return new PagingResponse + ( + $total, + $paging_info->getPerPage(), + $paging_info->getCurrentPage(), + $paging_info->getLastPage($total), + $data + ); + } +} \ No newline at end of file diff --git a/app/Repositories/Main/Doctrine/DoctrineChatTeamRepository.php b/app/Repositories/Main/Doctrine/DoctrineChatTeamRepository.php new file mode 100644 index 00000000..1cda3048 --- /dev/null +++ b/app/Repositories/Main/Doctrine/DoctrineChatTeamRepository.php @@ -0,0 +1,53 @@ +getEntityManager() + ->createQueryBuilder() + ->select("t") + ->from(\models\main\ChatTeam::class, "t") + ->innerJoin('t.members', 'tm') + ->innerJoin('tm.member', 'm', Join::WITH, "m.id = :member_id") + ->setParameter('member_id', $member->getId())->getQuery()->getResult(); + } + + /** + * @return int[] + */ + function getAllTeamsIdsWithPendingMessages2Sent() + { + $result = $this + ->getEntityManager() + ->createQuery("select t.id from \models\main\ChatTeam t join t.messages m where exists (select m2.id from \models\main\ChatTeamPushNotificationMessage m2 where m2.id = m.id and m2.is_sent = 0 )") + ->getScalarResult(); + $ids = array_map('current', $result); + return $ids; + } +} \ No newline at end of file diff --git a/app/Repositories/RepositoriesProvider.php b/app/Repositories/RepositoriesProvider.php index 5f60db9d..2807c70d 100644 --- a/app/Repositories/RepositoriesProvider.php +++ b/app/Repositories/RepositoriesProvider.php @@ -1,5 +1,4 @@ getEntityManager()->createQueryBuilder() + ->select("m") + ->from(\models\main\Member::class, "m"); + + if(!is_null($filter)){ + + $filter->apply2Query($query, array + ( + 'irc' => 'm.irc_handle:json_string', + 'twitter' => 'm.twitter_handle:json_string', + 'first_name' => 'm.first_name:json_string', + 'last_name' => 'm.last_name:json_string', + )); + } + + if (!is_null($order)) { + + $order->apply2Query($query, array + ( + 'id' => 'm.id', + 'first_name' => 'm.first_name', + 'last_name' => 'm.last_name', + )); + } else { + //default order + $query = $query->addOrderBy("m.first_name",'ASC'); + $query = $query->addOrderBy("m.last_name", 'ASC'); + } + + $query= $query + ->setFirstResult($paging_info->getOffset()) + ->setMaxResults($paging_info->getPerPage()); + + $paginator = new Paginator($query, $fetchJoinCollection = true); + $total = $paginator->count(); + $data = array(); + + foreach($paginator as $entity) + array_push($data, $entity); + + return new PagingResponse + ( + $total, + $paging_info->getPerPage(), + $paging_info->getCurrentPage(), + $paging_info->getLastPage($total), + $data + ); + } } \ No newline at end of file diff --git a/app/Services/Apis/FireBaseGCMApi.php b/app/Services/Apis/FireBaseGCMApi.php new file mode 100644 index 00000000..d50ede45 --- /dev/null +++ b/app/Services/Apis/FireBaseGCMApi.php @@ -0,0 +1,77 @@ +api_server_key = $api_server_key; + } + + /** + * https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages + * @param string $to + * @param array $data + * @param string $priority + * @param null|int $ttl + * @return bool + */ + function sendPush($to, array $data, $priority = PushNotificationMessagePriority::Normal, $ttl = null) + { + $endpoint = self::BaseUrl.'/fcm/send'; + $client = new Client(); + $res = true; + + try { + foreach ($to as $recipient) { + + $message = [ + 'to' => '/topics/' . $recipient, + 'data' => $data, + ]; + + $response = $client->post($endpoint, [ + 'headers' => [ + 'Authorization' => sprintf('key=%s', $this->api_server_key), + 'Content-Type' => 'application/json' + ], + 'body' => json_encode($message) + ]); + + if ($response->getStatusCode() !== 200) $res = $res && false; + } + return $res; + } + catch (\GuzzleHttp\Exception\ClientException $ex1){ + Log::error($ex1->getMessage()); + return false; + } + catch(\Exception $ex){ + Log::error($ex->getMessage()); + return false; + } + } +} \ No newline at end of file diff --git a/app/Services/Apis/IPushNotificationApi.php b/app/Services/Apis/IPushNotificationApi.php new file mode 100644 index 00000000..0cafdbdb --- /dev/null +++ b/app/Services/Apis/IPushNotificationApi.php @@ -0,0 +1,29 @@ +invitation_repository = $invitation_repository; + $this->chat_message_repository = $chat_message_repository; + $this->repository = $repository; + $this->member_repository = $member_repository; + $this->resource_server_context = $resource_server_context; + $this->push_sender_service = $push_sender_service; + $this->tx_service = $tx_service; + } + + /** + * @param array $data + * @param Member $owner + * @return ChatTeam + */ + function addTeam(array $data, Member $owner) + { + return $this->tx_service->transaction(function () use($data, $owner){ + $team = new ChatTeam(); + $team->setName($data['name']); + if(isset($data['description'])) + $team->setDescription($data['description']); + $team->setOwner($owner); + $team_member = $team->createMember($owner, ChatTeamPermission::Admin); + $team->addMember($team_member); + $this->repository->add($team); + return $team; + }); + } + + /** + * @param array $data + * @param int $team_id + * @return ChatTeam + */ + function updateTeam(array $data, $team_id){ + return $this->tx_service->transaction(function () use($data, $team_id){ + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) throw new EntityNotFoundException(); + + $current_member = $this->member_repository->getById($current_member_id); + if (is_null($current_member)) throw new EntityNotFoundException(); + + $team = $this->repository->getById($team_id); + if(is_null($team)) throw new EntityNotFoundException(); + + if(!$team->isAdmin($current_member)) + throw new EntityNotFoundException(); + + $team->setName($data['name']); + if(isset($data['description'])) + $team->setDescription($data['description']); + $this->repository->add($team); + return $team; + }); + } + + /** + * @param int $team_id + * @return void + * @throws EntityNotFoundException + */ + function deleteTeam($team_id) + { + $this->tx_service->transaction(function() use($team_id){ + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) throw new EntityNotFoundException(); + + $current_member = $this->member_repository->getById($current_member_id); + if (is_null($current_member)) throw new EntityNotFoundException(); + + $team = $this->repository->getById($team_id); + if(is_null($team)) throw new EntityNotFoundException(); + if(!$team->isAdmin($current_member)) + throw new EntityNotFoundException(); + + $this->repository->delete($team); + }); + } + + /** + * @param int $team_id + * @param int $invitee_id + * @param string $permission + * @throws EntityNotFoundException + * @throws ValidationException + * @return ChatTeamInvitation + */ + function addMember2Team($team_id, $invitee_id, $permission = ChatTeamPermission::Read) + { + return $this->tx_service->transaction(function() use($team_id, $invitee_id, $permission){ + $team = $this->repository->getById($team_id); + if(is_null($team)) throw new EntityNotFoundException(); + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) throw new EntityNotFoundException(); + + $inviter = $this->member_repository->getById($current_member_id); + if (is_null($inviter)) throw new EntityNotFoundException(); + + $invitee = $this->member_repository->getById($invitee_id); + if(is_null($invitee)) + throw new EntityNotFoundException(); + + if(!$team->isAdmin($inviter)) + throw new EntityNotFoundException(); + + if($team->isMember($invitee)) + throw new ValidationException(sprintf('member id %s already is a member of team id %s', $invitee_id, $team_id)); + + $invitation = $team->createInvitation($inviter, $invitee, $permission); + + $team->addInvitation($invitation); + + $this->repository->add($team); + + return $invitation; + + }); + } + + /** + * @param int $invitation_id + * @param int $invitee_id + * @return ChatTeamMember + * @throws EntityNotFoundException + * @throws ValidationException + */ + function acceptInvitation($invitation_id, $invitee_id) + { + return $this->tx_service->transaction(function() use($invitation_id, $invitee_id){ + + $invitee = $this->member_repository->getById($invitee_id); + if(is_null($invitee)) + throw new EntityNotFoundException(); + + $invitation = $this->invitation_repository->getById($invitation_id); + if(is_null($invitation)) + throw new EntityNotFoundException(); + + if($invitation->getInviteeId() != $invitee_id) + throw new EntityNotFoundException(); + + if($invitation->isAccepted()) + throw new ValidationException(sprintf('invitation id %s is already accepted!', $invitee_id)); + + $invitation->accept(); + + $team = $invitation->getTeam(); + + if($team->isMember($invitee)) + throw new ValidationException(sprintf('invitee id %s is already member of team id %s!', $invitee_id, $team->getId())); + + $team_member = $team->createMember($invitee, $invitation->getPermission()); + + $team->addMember($team_member); + + return $team_member; + }); + } + + /** + * @param int $invitation_id + * @param int $invitee_id + * @return void + * @throws EntityNotFoundException + * @throws ValidationException + */ + function declineInvitation($invitation_id, $invitee_id) + { + $this->tx_service->transaction(function() use($invitation_id, $invitee_id){ + + $invitee = $this->member_repository->getById($invitee_id); + if(is_null($invitee)) + throw new EntityNotFoundException(); + + $invitation = $this->invitation_repository->getById($invitation_id); + if(is_null($invitation)) + throw new EntityNotFoundException(); + + if($invitation->getInviteeId() != $invitee_id) + throw new EntityNotFoundException(); + + if($invitation->isAccepted()) + throw new ValidationException(sprintf('invitation id %s is already accepted!', $invitee_id)); + + $this->invitation_repository->delete($invitation); + }); + } + + /** + * @param int $team_id + * @param int $member_id + * @return void + * @throws EntityNotFoundException + * @throws ValidationException + */ + function removeMemberFromTeam($team_id, $member_id) + { + $this->tx_service->transaction(function() use($member_id, $team_id){ + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) throw new EntityNotFoundException(); + + $current_member = $this->member_repository->getById($current_member_id); + if (is_null($current_member)) throw new EntityNotFoundException(); + + $team_member = $this->member_repository->getById($member_id); + if (is_null($team_member)) throw new EntityNotFoundException(); + + $team = $this->repository->getById($team_id); + if(is_null($team)) throw new EntityNotFoundException(); + + if(!$team->isAdmin($current_member)) + throw new EntityNotFoundException(); + + if(!$team->isMember($team_member)) + throw new ValidationException(sprintf('member id %s is not a member of team id %s', $member_id, $team_id)); + + $team->removeMember($team_member); + + }); + } + + /** + * @param int $team_id + * @param array $values + * @return ChatTeamPushNotificationMessage + * @throws EntityNotFoundException + * @throws ValidationException + */ + function postMessage($team_id, array $values) + { + return $this->tx_service->transaction(function() use($team_id, $values){ + + $current_member_id = $this->resource_server_context->getCurrentUserExternalId(); + if (is_null($current_member_id)) throw new EntityNotFoundException(); + + $current_member = $this->member_repository->getById($current_member_id); + if (is_null($current_member)) throw new EntityNotFoundException(); + + $team = $this->repository->getById($team_id); + if(is_null($team)) throw new EntityNotFoundException(); + + if(!$team->canPostMessages($current_member)) + throw new ValidationException(sprintf('you do not have permissions to post messages to team id %s', $team_id)); + + $message = $team->createMessage($current_member, $values['body'], $values['priority']); + + $team->addMessage($message) ; + + return $message; + }); + } + + /** + * @param int $batch_size + * @return int + */ + function sendMessages($batch_size = 1000) + { + return $this->tx_service->transaction(function() use($batch_size){ + + $teams_ids = $this->repository->getAllTeamsIdsWithPendingMessages2Sent(); + $qty = 0; + foreach($teams_ids as $team_id) { + + $messages = $this->chat_message_repository->getAllNotSentByTeamPaginated + ( + $team_id, + new PagingInfo(1, $batch_size) + ); + + foreach ($messages->getItems() as $message){ + + $data = [ + 'id' => intval($message->getId()), + 'type' => ChatTeamPushNotificationMessage::PushType, + 'body' => $message->getMessage(), + 'from_id' => intval($message->getOwner()->getId()), + 'from_first_name' => $message->getOwner()->getFirstName(), + 'from_last_name' => $message->getOwner()->getLastName(), + 'created_at' => intval($message->getCreated()->getTimestamp()), + ]; + + $this->push_sender_service->sendPush([sprintf('team_%s', $team_id)], $data); + $message->markSent(); + ++$qty; + } + } + return $qty; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/IChatTeamService.php b/app/Services/Model/IChatTeamService.php new file mode 100644 index 00000000..de3cf087 --- /dev/null +++ b/app/Services/Model/IChatTeamService.php @@ -0,0 +1,102 @@ +setCredentials(array('token' => Config::get("server.eventbrite_oauth2_personal_token", null))); return $api; }); + App::singleton('services\apis\IPushNotificationApi', function(){ + $api = new FireBaseGCMApi(Config::get("server.firebase_gcm_server_key", null)); + return $api; + }); } } \ No newline at end of file diff --git a/config/server.php b/config/server.php index 46b6fd5b..141d70a9 100644 --- a/config/server.php +++ b/config/server.php @@ -21,4 +21,5 @@ return array 'assets_base_url' => env('ASSETS_BASE_URL', null), 'response_cache_lifetime' => env('API_RESPONSE_CACHE_LIFETIME', 300), 'eventbrite_oauth2_personal_token' => env('EVENTBRITE_OAUTH2_PERSONAL_TOKEN', ''), + 'firebase_gcm_server_key' => env('FIREBASE_GCM_SERVER_KEY', ''), ); \ No newline at end of file diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index 996a4ffa..bae25afc 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -27,10 +27,13 @@ class ApiEndpointsSeeder extends Seeder { DB::table('endpoint_api_scopes')->delete(); DB::table('api_endpoints')->delete(); + $this->seedPublicCloudsEndpoints(); $this->seedPrivateCloudsEndpoints(); $this->seedConsultantsEndpoints(); $this->seedSummitEndpoints(); + $this->seedMemberEndpoints(); + $this->seedTeamEndpoints(); } /** @@ -465,4 +468,98 @@ class ApiEndpointsSeeder extends Seeder } + private function seedMemberEndpoints(){ + $current_realm = Config::get('app.url'); + + $this->seedApiEndpoints('members', [ + // members + array( + 'name' => 'get-members', + 'route' => '/api/v1/members', + 'http_method' => 'GET', + 'scopes' => [sprintf('%s/members/read', $current_realm)], + ) + ] + ); + } + + private function seedTeamEndpoints(){ + $current_realm = Config::get('app.url'); + + $this->seedApiEndpoints('teams', [ + array( + 'name' => 'add-team', + 'route' => '/api/v1/teams', + 'http_method' => 'POST', + 'scopes' => [sprintf('%s/teams/write', $current_realm)], + ), + array( + 'name' => 'delete-team', + 'route' => '/api/v1/teams/{team_id}', + 'http_method' => 'DELETE', + 'scopes' => [sprintf('%s/teams/write', $current_realm)], + ), + array( + 'name' => 'get-teams', + 'route' => '/api/v1/teams', + 'http_method' => 'GET', + 'scopes' => [sprintf('%s/teams/read', $current_realm)], + ), + array( + 'name' => 'get-team', + 'route' => '/api/v1/teams/{team_id}', + 'http_method' => 'GET', + 'scopes' => [sprintf('%s/teams/read', $current_realm)], + ), + array( + 'name' => 'post-message-2-team', + 'route' => '/api/v1/teams/{team_id}/messages', + 'http_method' => 'POST', + 'scopes' => [sprintf('%s/teams/write', $current_realm)], + ), + array( + 'name' => 'get-messages-from-team', + 'route' => '/api/v1/teams/{team_id}/messages', + 'http_method' => 'GET', + 'scopes' => [sprintf('%s/teams/read', $current_realm)], + ), + + array( + 'name' => 'add-member-2-team', + 'route' => '/api/v1/teams/{team_id}/members/{member_id}', + 'http_method' => 'POST', + 'scopes' => [sprintf('%s/teams/write', $current_realm)], + ), + array( + 'name' => 'remove-member-from-team', + 'route' => '/api/v1/teams/{team_id}/members/{member_id}', + 'http_method' => 'DELETE', + 'scopes' => [sprintf('%s/teams/write', $current_realm)], + ), + ] + ); + + $this->seedApiEndpoints('members', [ + array( + 'name' => 'get-invitations', + 'route' => '/api/v1/members/me/team-invitations', + 'http_method' => 'GET', + 'scopes' => [sprintf('%s/teams/read', $current_realm)], + ), + array( + 'name' => 'accept-invitation', + 'route' => '/api/v1/members/me/team-invitations/{invitation_id}', + 'http_method' => 'PATCH', + 'scopes' => [sprintf('%s/teams/write', $current_realm)], + ), + array( + 'name' => 'decline-invitation', + 'route' => '/api/v1/members/me/team-invitations/{invitation_id}', + 'http_method' => 'DELETE', + 'scopes' => [sprintf('%s/teams/write', $current_realm)], + ), + ] + ); + } + } \ No newline at end of file diff --git a/database/seeds/ApiScopesSeeder.php b/database/seeds/ApiScopesSeeder.php index 3c82b0d5..d2476550 100644 --- a/database/seeds/ApiScopesSeeder.php +++ b/database/seeds/ApiScopesSeeder.php @@ -33,6 +33,8 @@ final class ApiScopesSeeder extends Seeder $this->seedPrivateCloudScopes(); $this->seedConsultantScopes(); $this->seedSummitScopes(); + $this->seedMembersScopes(); + $this->seedTeamsScopes(); } private function seedPublicCloudScopes() @@ -163,4 +165,61 @@ final class ApiScopesSeeder extends Seeder } + private function seedMembersScopes(){ + $current_realm = Config::get('app.url'); + $api = EntityManager::getRepository(\App\Models\ResourceServer\Api::class)->findOneBy(['name' => 'members']); + + $scopes = [ + array( + 'name' => sprintf('%s/members/read', $current_realm), + 'short_description' => 'Get Members Data', + 'description' => 'Grants read only access for Members Data', + ), + ]; + + foreach ($scopes as $scope_info) { + $scope = new ApiScope(); + $scope->setName($scope_info['name']); + $scope->setShortDescription($scope_info['short_description']); + $scope->setDescription($scope_info['description']); + $scope->setActive(true); + $scope->setDefault(false); + $scope->setApi($api); + EntityManager::persist($scope); + } + + EntityManager::flush(); + } + + private function seedTeamsScopes(){ + $current_realm = Config::get('app.url'); + $api = EntityManager::getRepository(\App\Models\ResourceServer\Api::class)->findOneBy(['name' => 'teams']); + + $scopes = [ + array( + 'name' => sprintf('%s/teams/read', $current_realm), + 'short_description' => 'Get Teams Data', + 'description' => 'Grants read only access for Teams Data', + ), + array( + 'name' => sprintf('%s/teams/write', $current_realm), + 'short_description' => 'Write Teams Data', + 'description' => 'Grants write access for Teams Data', + ), + ]; + + foreach ($scopes as $scope_info) { + $scope = new ApiScope(); + $scope->setName($scope_info['name']); + $scope->setShortDescription($scope_info['short_description']); + $scope->setDescription($scope_info['description']); + $scope->setActive(true); + $scope->setDefault(false); + $scope->setApi($api); + EntityManager::persist($scope); + } + + EntityManager::flush(); + } + } \ No newline at end of file diff --git a/database/seeds/ApiSeeder.php b/database/seeds/ApiSeeder.php index db331193..3cca34c8 100644 --- a/database/seeds/ApiSeeder.php +++ b/database/seeds/ApiSeeder.php @@ -68,5 +68,27 @@ final class ApiSeeder extends Seeder EntityManager::flush(); + // members + + $api = new Api(); + $api->setName('members'); + $api->setActive(true); + $api->setDescription('Members API'); + + EntityManager::persist($api); + + EntityManager::flush(); + + // teams + + $api = new Api(); + $api->setName('teams'); + $api->setActive(true); + $api->setDescription('Teams API'); + + EntityManager::persist($api); + + EntityManager::flush(); + } } \ No newline at end of file diff --git a/tests/OAuth2ChatTeamApiTest.php b/tests/OAuth2ChatTeamApiTest.php new file mode 100644 index 00000000..23d13d69 --- /dev/null +++ b/tests/OAuth2ChatTeamApiTest.php @@ -0,0 +1,277 @@ + 'team test #1', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2TeamsApiController@addTeam", + $params, + array(), + array(), + array(), + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $team = json_decode($content); + $this->assertTrue(!is_null($team)); + $this->assertResponseStatus(201); + return $team; + } + + public function testDeleteMyTeam(){ + $team = $this->testAddTeam(); + + $params = ['team_id' => $team->id]; + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "DELETE", + "OAuth2TeamsApiController@deleteTeam", + $params, + array(), + array(), + array(), + $headers + ); + + $this->assertResponseStatus(204); + } + + public function testGetMyTeams(){ + $params = ['expand' => 'owner, member']; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "GET", + "OAuth2TeamsApiController@getMyTeams", + $params, + array(), + array(), + array(), + $headers + ); + + $content = $response->getContent(); + $teams = json_decode($content); + $this->assertTrue(!is_null($teams)); + $this->assertResponseStatus(200); + } + + public function testGetMyTeam($team_id = null, $expected_http_response = 200){ + + if($team_id == null) { + $team = $this->testAddTeam(); + $team_id = $team->id; + } + + $params = ['team_id' => $team_id]; + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "GET", + "OAuth2TeamsApiController@getMyTeam", + $params, + array(), + array(), + array(), + $headers + ); + + $content = $response->getContent(); + $team = json_decode($content); + $this->assertTrue(!is_null($team)); + $this->assertResponseStatus($expected_http_response); + } + + public function testAddMemberToTeam(){ + $team = $this->testAddTeam(); + + $params = [ + 'member_id' => 11624, + 'team_id' => $team->id, + ]; + + $data = [ + 'permission' => \models\main\ChatTeamPermission::Read, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2TeamsApiController@addMember2MyTeam", + $params, + array(), + array(), + array(), + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $invitation = json_decode($content); + $this->assertTrue(!is_null($invitation)); + $this->assertResponseStatus(201); + return $invitation; + } + + public function testAcceptInvitation(){ + $invitation = $this->testAddMemberToTeam(); + + $params = [ + 'invitation_id' => $invitation->id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "PATCH", + "OAuth2TeamInvitationsApiController@acceptInvitation", + $params, + array(), + array(), + array(), + $headers + ); + + $content = $response->getContent(); + $team_member = json_decode($content); + $this->assertTrue(!is_null($team_member)); + $this->assertResponseStatus(201); + return $team_member; + } + + public function testPostMessage($team = null){ + + if(is_null($team)) + $team = $this->testAddTeam(); + + $params = [ + 'team_id' => $team->id, + ]; + + $data = [ + 'body' => 'test message', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2TeamsApiController@postTeamMessage", + $params, + array(), + array(), + array(), + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $message = json_decode($content); + $this->assertTrue(!is_null($message)); + $this->assertResponseStatus(201); + return $message; + } + + public function testGetMessagesFromTeam(){ + + $team = $this->testAddTeam(); + $message = $this->testPostMessage($team); + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $params = [ + 'team_id' => $team->id, + 'expand' => 'team,owner', + ]; + + $response = $this->action( + "GET", + "OAuth2TeamsApiController@getMyTeamMessages", + $params, + array(), + array(), + array(), + $headers + ); + + $content = $response->getContent(); + $messages = json_decode($content); + $this->assertTrue(!is_null($messages)); + $this->assertResponseStatus(200); + return $messages; + } + + public function testRemoveMemberFromTeam(){ + $team = $this->testAddTeam(); + + $params = [ + 'team_id' => $team->id, + 'member_id' => $team->owner->id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "DELETE", + "OAuth2TeamsApiController@removedMemberFromMyTeam", + $params, + array(), + array(), + array(), + $headers + ); + + $this->assertResponseStatus(204); + // try to get team again, we are not longer members , so will return 404 + $this->testGetMyTeam($team->id, 404); + } +} \ No newline at end of file diff --git a/tests/OAuth2MembersApiTest.php b/tests/OAuth2MembersApiTest.php new file mode 100644 index 00000000..29298aac --- /dev/null +++ b/tests/OAuth2MembersApiTest.php @@ -0,0 +1,45 @@ + 'first_name=@Seba', + 'filter' => 'last_name=@Marcet', + 'order' => '+first_name,-last_name' + ]; + + $headers = array("HTTP_Authorization" => " Bearer " . $this->access_token); + $response = $this->action( + "GET", + "OAuth2MembersApiController@getMembers", + $params, + array(), + array(), + array(), + $headers + ); + + $content = $response->getContent(); + $members = json_decode($content); + $this->assertTrue(!is_null($members)); + $this->assertResponseStatus(200); + } + +} \ No newline at end of file diff --git a/tests/ProtectedApiTest.php b/tests/ProtectedApiTest.php index 1e492c4e..ad880173 100644 --- a/tests/ProtectedApiTest.php +++ b/tests/ProtectedApiTest.php @@ -48,6 +48,9 @@ class AccessTokenServiceStub implements IAccessTokenService $url . '/summits/write-videos', $url . '/me/read', $url . '/summits/read-notifications', + $url . '/members/read', + $url . '/teams/read', + $url . '/teams/write', ); return AccessToken::createFromParams('123456789', implode(' ', $scopes), '1', $realm, '1','13867', 3600, 'WEB_APPLICATION', '', ''); @@ -83,6 +86,9 @@ class AccessTokenServiceStub2 implements IAccessTokenService $url . '/summits/write-videos', $url . '/me/read', $url . '/summits/read-notifications', + $url . '/members/read', + $url . '/teams/read', + $url . '/teams/write', ); return AccessToken::createFromParams('123456789', implode(' ', $scopes), '1', $realm, null,null, 3600, 'SERVICE', '', '');