diff --git a/app/Http/Controllers/apis/protected/summit/OAuth2SummitEventsApiController.php b/app/Http/Controllers/apis/protected/summit/OAuth2SummitEventsApiController.php index c3d70aef..45925969 100644 --- a/app/Http/Controllers/apis/protected/summit/OAuth2SummitEventsApiController.php +++ b/app/Http/Controllers/apis/protected/summit/OAuth2SummitEventsApiController.php @@ -29,6 +29,7 @@ use models\summit\ISummitRepository; use ModelSerializers\SerializerRegistry; use services\model\ISummitService; use utils\FilterParser; +use utils\FilterParserException; use utils\OrderParser; use utils\PagingInfo; @@ -590,7 +591,12 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController return $this->ok($response->toArray(Request::input('expand', ''))); - } catch (Exception $ex) { + } + catch(FilterParserException $ex1){ + Log::warning($ex1); + return $this->error412($ex1->getMessages()); + } + catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } diff --git a/app/Http/Controllers/apis/protected/summit/OAuth2SummitLocationsApiController.php b/app/Http/Controllers/apis/protected/summit/OAuth2SummitLocationsApiController.php index 2b77771f..1bdc19c7 100644 --- a/app/Http/Controllers/apis/protected/summit/OAuth2SummitLocationsApiController.php +++ b/app/Http/Controllers/apis/protected/summit/OAuth2SummitLocationsApiController.php @@ -28,6 +28,7 @@ use ModelSerializers\SerializerRegistry; use services\model\ISummitService; use utils\Filter; use utils\FilterParser; +use utils\FilterParserException; use utils\PagingInfo; use utils\PagingResponse; @@ -206,6 +207,10 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController 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); @@ -231,6 +236,10 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController 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); diff --git a/app/Http/Controllers/apis/protected/summit/OAuth2SummitNotificationsApiController.php b/app/Http/Controllers/apis/protected/summit/OAuth2SummitNotificationsApiController.php new file mode 100644 index 00000000..42bfe476 --- /dev/null +++ b/app/Http/Controllers/apis/protected/summit/OAuth2SummitNotificationsApiController.php @@ -0,0 +1,146 @@ +repository = $notification_repository; + $this->summit_repository = $summit_repository; + } + + /** + * @param $summit_id + * @return mixed + */ + public function getAll($summit_id) + { + try + { + $summit = SummitFinderStrategyFactory::build($this->summit_repository)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $values = Input::all(); + + $rules = array + ( + 'page' => 'integer|min:1', + 'per_page' => 'required_with:page|integer|min:5|max:100', + ); + + $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'), [ + 'channel' => ['=='], + 'sent_date' => ['>', '<', '<=', '>=', '=='], + 'created' => ['>', '<', '<=', '>=', '=='], + 'is_sent' => ['=='], + 'event_id' => ['=='], + ]); + $channels = $filter->getFlatFilter("channel"); + // validate that channel filter, if present if for a public one + if(!is_null($channels) && is_array($channels)){ + foreach ($channels as $element){ + if(!SummitPushNotificationChannel::isPublicChannel($element->getValue())) + throw new ValidationException(sprintf("%s channel is not public!", $element->getValue())); + } + } + } + + $order = null; + + if (Input::has('order')) + { + $order = OrderParser::parse(Input::get('order'), array + ( + 'sent_date', + 'created', + 'id', + )); + } + + $result = $this->repository->getAllByPage($summit, new PagingInfo($page, $per_page), $filter, $order); + + return $this->ok + ( + $result->toArray(Request::input('expand', ''),[],[],['summit_id' => $summit_id]) + ); + + } + 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/summit/OAuth2SummitSpeakersApiController.php b/app/Http/Controllers/apis/protected/summit/OAuth2SummitSpeakersApiController.php index 7c28d5a3..89ba1cc5 100644 --- a/app/Http/Controllers/apis/protected/summit/OAuth2SummitSpeakersApiController.php +++ b/app/Http/Controllers/apis/protected/summit/OAuth2SummitSpeakersApiController.php @@ -25,6 +25,7 @@ use models\summit\ISummitRepository; use ModelSerializers\SerializerRegistry; use services\model\ISummitService; use utils\FilterParser; +use utils\FilterParserException; use utils\OrderParser; use utils\PagingInfo; @@ -143,6 +144,10 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController $result->toArray(Request::input('expand', ''),[],[],['summit_id' => $summit_id, 'published' => true]) ); } + catch(FilterParserException $ex1){ + Log::warning($ex1); + return $this->error412($ex1->getMessages()); + } catch (Exception $ex) { Log::error($ex); diff --git a/app/Http/Utils/AbstractFilterElement.php b/app/Http/Utils/Filters/AbstractFilterElement.php similarity index 100% rename from app/Http/Utils/AbstractFilterElement.php rename to app/Http/Utils/Filters/AbstractFilterElement.php diff --git a/app/Http/Utils/DoctrineJoinFilterMapping.php b/app/Http/Utils/Filters/DoctrineJoinFilterMapping.php similarity index 85% rename from app/Http/Utils/DoctrineJoinFilterMapping.php rename to app/Http/Utils/Filters/DoctrineJoinFilterMapping.php index 5f6d12cb..0f45a31c 100644 --- a/app/Http/Utils/DoctrineJoinFilterMapping.php +++ b/app/Http/Utils/Filters/DoctrineJoinFilterMapping.php @@ -55,7 +55,9 @@ class DoctrineJoinFilterMapping extends FilterMapping public function apply(QueryBuilder $query, FilterElement $filter){ $where = str_replace(":value", $filter->getValue(), $this->where); $where = str_replace(":operator", $filter->getOperator(), $where); - return $query->innerJoin($this->table, $this->alias, Join::WITH, $where); + if(!in_array($this->alias, $query->getAllAliases())) + $query->innerJoin($this->table, $this->alias, Join::WITH); + return $query->andWhere($where); } /** @@ -66,6 +68,8 @@ class DoctrineJoinFilterMapping extends FilterMapping public function applyOr(QueryBuilder $query, FilterElement $filter){ $where = str_replace(":value", $filter->getValue(), $this->where); $where = str_replace(":operator", $filter->getOperator(), $where); - return $query->innerJoin($this->table, $this->alias, Join::WITH)->orWhere($where); + if(!in_array($this->alias, $query->getAllAliases())) + $query->innerJoin($this->table, $this->alias, Join::WITH); + return $query->orWhere($where); } } \ No newline at end of file diff --git a/app/Http/Utils/Filter.php b/app/Http/Utils/Filters/Filter.php similarity index 84% rename from app/Http/Utils/Filter.php rename to app/Http/Utils/Filters/Filter.php index b11d6cdf..efd7bd72 100644 --- a/app/Http/Utils/Filter.php +++ b/app/Http/Utils/Filters/Filter.php @@ -48,6 +48,7 @@ final class Filter } /** + * will return an array of filter elements, OR filters are returned on a sub array * @param string $field * @return null|FilterElement[] */ @@ -55,17 +56,44 @@ final class Filter { $res = array(); foreach ($this->filters as $filter) { + if ($filter instanceof FilterElement && $filter->getField() === $field) { $res[] = $filter; - } else if (is_array($filter)) { + } + else if (is_array($filter)) { // OR $or_res = array(); foreach ($filter as $e) { if ($e instanceof FilterElement && $e->getField() === $field) { - array_push($or_res, $e); + $or_res[] = $e; } } - if (count($or_res)) array_push($res, $or_res); + if (count($or_res)) $res[] = $or_res; + } + } + return $res; + } + + /** + * @param string $field + * @return null|FilterElement[] + */ + public function getFlatFilter($field) + { + $res = array(); + foreach ($this->filters as $filter) { + + if ($filter instanceof FilterElement && $filter->getField() === $field) { + $res[] = $filter; + } + else if (is_array($filter)) { + // OR + foreach ($filter as $e) { + if ($e instanceof FilterElement && $e->getField() === $field) { + $res[] = $e; + } + } + } } return $res; @@ -88,7 +116,8 @@ final class Filter } $mapping = explode(':', $mapping); - $value = $filter->getValue(); + $value = $filter->getValue(); + if (count($mapping) > 1) { $value = $this->convertValue($value, $mapping[1]); } @@ -134,11 +163,13 @@ final class Filter } $mapping = explode(':', $mapping); - $value = $filter->getValue(); + $value = $filter->getValue(); + if (count($mapping) > 1) { $value = $this->convertValue($value, $mapping[1]); } - $query = $query->where($mapping[0] . ' ' . $filter->getOperator() . ' ' . $value); + + $query = $query->andWhere(sprintf("%s %s %s",$mapping[0], $filter->getOperator(), $value)); } else if (is_array($filter)) { // OR @@ -151,12 +182,14 @@ final class Filter continue; } - $mapping = explode(':', $mapping); - $value = $filter->getValue(); + $mapping = explode(':', $mapping); + $value = $e->getValue(); + if (count($mapping) > 1) { $value = $this->convertValue($value, $mapping[1]); } - $query->orWhere($mapping[0], $e->getOperator(), $value); + + $query->orWhere(sprintf("%s %s %s",$mapping[0], $e->getOperator(), $value)); } } } @@ -179,6 +212,9 @@ final class Filter case 'json_int': return intval($value); break; + case 'json_string': + return sprintf("'%s'",$value); + break; default: return $value; break; diff --git a/app/Http/Utils/FilterElement.php b/app/Http/Utils/Filters/FilterElement.php similarity index 100% rename from app/Http/Utils/FilterElement.php rename to app/Http/Utils/Filters/FilterElement.php diff --git a/app/Http/Utils/FilterMapping.php b/app/Http/Utils/Filters/FilterMapping.php similarity index 100% rename from app/Http/Utils/FilterMapping.php rename to app/Http/Utils/Filters/FilterMapping.php diff --git a/app/Http/Utils/FilterParser.php b/app/Http/Utils/Filters/FilterParser.php similarity index 64% rename from app/Http/Utils/FilterParser.php rename to app/Http/Utils/Filters/FilterParser.php index 2bd541eb..3b5b8104 100644 --- a/app/Http/Utils/FilterParser.php +++ b/app/Http/Utils/Filters/FilterParser.php @@ -17,63 +17,65 @@ final class FilterParser /** * @param mixed $filters * @param array $allowed_fields + * @throws FilterParserException * @return Filter */ public static function parse($filters, $allowed_fields = array()) { - $res = array(); + $res = array(); $matches = array(); - if(!is_array($filters)) + if (!is_array($filters)) $filters = array($filters); - foreach($filters as $filter) // parse AND filters + foreach ($filters as $filter) // parse AND filters { $f = null; // parse OR filters $or_filters = explode(',', $filter); - if(count($or_filters) > 1) - { + + if (count($or_filters) > 1) { $f = array(); foreach ($or_filters as $of) { //single filter preg_match('/[=<>][=>@]{0,1}/', $of, $matches); - if(count($matches) === 1) - { - $op = $matches[0]; - $operands = explode($op, $of); - $field = $operands[0]; - $value = $operands[1]; - if(!isset($allowed_fields[$field])) continue; - if(!in_array($op, $allowed_fields[$field])) continue; - $f_or = self::buildFilter($field, $op, $value); - if(!is_null($f_or)) - array_push($f, $f_or); - } - } - } - else - { - //single filter - preg_match('/[=<>][=>@]{0,1}/', $filter, $matches); - if(count($matches) === 1) - { + + if (count($matches) != 1) + throw new FilterParserException(sprintf("invalid OR filter format %s (should be [:FIELD_NAME:OPERAND:VALUE])", $of)); + $op = $matches[0]; - $operands = explode($op, $filter); + $operands = explode($op, $of); $field = $operands[0]; $value = $operands[1]; - if(!isset($allowed_fields[$field])) continue; - if(!in_array($op, $allowed_fields[$field])) continue; - $f = self::buildFilter($field, $op, $value); + if (!isset($allowed_fields[$field])) continue; + if (!in_array($op, $allowed_fields[$field])) continue; + $f_or = self::buildFilter($field, $op, $value); + if (!is_null($f_or)) + array_push($f, $f_or); } + } else { + //single filter + preg_match('/[=<>][=>@]{0,1}/', $filter, $matches); + + if (count($matches) != 1) + throw new FilterParserException(sprintf("invalid filter format %s (should be [:FIELD_NAME:OPERAND:VALUE])", $filter)); + + $op = $matches[0]; + $operands = explode($op, $filter); + $field = $operands[0]; + $value = $operands[1]; + if (!isset($allowed_fields[$field])) continue; + if (!in_array($op, $allowed_fields[$field])) continue; + $f = self::buildFilter($field, $op, $value); } - if(!is_null($f)) + + if (!is_null($f)) array_push($res, $f); } - return new Filter($res); + return new Filter($res); } /** @@ -86,8 +88,7 @@ final class FilterParser */ public static function buildFilter($field, $op, $value) { - switch($op) - { + switch ($op) { case '==': return FilterElement::makeEqual($field, $value); break; diff --git a/app/Http/Utils/Filters/FilterParserException.php b/app/Http/Utils/Filters/FilterParserException.php new file mode 100644 index 00000000..0750646b --- /dev/null +++ b/app/Http/Utils/Filters/FilterParserException.php @@ -0,0 +1,26 @@ + 'summits'), function () { Route::get('', 'OAuth2SummitApiController@getSummits'); - Route::group(array('prefix' => 'events'), function () { - Route::get('', 'OAuth2SummitApiController@getAllEvents'); - Route::get('published', 'OAuth2SummitApiController@getAllEvents'); - }); Route::group(array('prefix' => '{id}'), function () { @@ -79,6 +75,11 @@ Route::group(array( }); }); + // notifications + Route::group(array('prefix' => 'notifications'), function () { + Route::get('', 'OAuth2SummitNotificationsApiController@getAll'); + }); + // speakers Route::group(array('prefix' => 'speakers'), function () { diff --git a/app/ModelSerializers/GroupSerializer.php b/app/ModelSerializers/GroupSerializer.php new file mode 100644 index 00000000..f2e79497 --- /dev/null +++ b/app/ModelSerializers/GroupSerializer.php @@ -0,0 +1,48 @@ + 'title:json_string', + 'Description' => 'description: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() ) + { + $group = $this->object; + if(! $group instanceof Group) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + $members = []; + + foreach($group->getMembers() as $member){ + $members[] = SerializerRegistry::getInstance()->getSerializer($member)->serialize(); + } + $values['members'] = $members; + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/SerializerRegistry.php b/app/ModelSerializers/SerializerRegistry.php index 66a667ff..e3dba5f0 100644 --- a/app/ModelSerializers/SerializerRegistry.php +++ b/app/ModelSerializers/SerializerRegistry.php @@ -77,10 +77,13 @@ final class SerializerRegistry $this->registry['SummitAirport'] = SummitAirportSerializer::class; $this->registry['SummitLocationImage'] = SummitLocationImageSerializer::class; - // member $this->registry['Member'] = MemberSerializer::class; + $this->registry['Group'] = GroupSerializer::class; + + // push notification + $this->registry['SummitPushNotification'] = SummitPushNotificationSerializer::class; } /** diff --git a/app/ModelSerializers/SummitPushNotificationSerializer.php b/app/ModelSerializers/SummitPushNotificationSerializer.php new file mode 100644 index 00000000..b33fdf76 --- /dev/null +++ b/app/ModelSerializers/SummitPushNotificationSerializer.php @@ -0,0 +1,55 @@ + 'channel:json_string', + 'Message' => 'message:json_string', + 'SentDate' => 'sent_date:datetime_epoch', + 'Created' => 'created:datetime_epoch', + 'IsSent' => 'is_sent: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() ) + { + $notification = $this->object; + if(! $notification instanceof SummitPushNotification) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if($notification->getChannel() == SummitPushNotificationChannel::Event){ + $values['event'] = SerializerRegistry::getInstance()->getSerializer($notification->getSummitEvent())->serialize(); + } + + if($notification->getChannel() == SummitPushNotificationChannel::Group){ + $values['group'] = SerializerRegistry::getInstance()->getSerializer($notification->getGroup())->serialize(); + } + return $values; + } +} \ No newline at end of file diff --git a/app/Models/Exceptions/ValidationException.php b/app/Models/Exceptions/ValidationException.php index 0f5ea1e7..879c3368 100644 --- a/app/Models/Exceptions/ValidationException.php +++ b/app/Models/Exceptions/ValidationException.php @@ -22,7 +22,7 @@ class ValidationException extends Exception { private $messages; - public function __construct($message= '', $code = 0, Exception $previous = null) + public function __construct($message = '', $code = 0, Exception $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/app/Models/Foundation/Main/CustomDataObject.php b/app/Models/Foundation/Main/CustomDataObject.php new file mode 100644 index 00000000..c82066af --- /dev/null +++ b/app/Models/Foundation/Main/CustomDataObject.php @@ -0,0 +1,30 @@ +members = new ArrayCollection(); + $this->groups = new ArrayCollection(); + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param string $description + */ + public function setDescription($description) + { + $this->description = $description; + } + + /** + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * @param string $code + */ + public function setCode($code) + { + $this->code = $code; + } + + /** + * @return mixed + */ + public function getMembers() + { + return $this->members; + } + + /** + * @param mixed $members + */ + public function setMembers($members) + { + $this->members = $members; + } + + /** + * @return mixed + */ + public function getParent() + { + return $this->parent; + } + + /** + * @param mixed $parent + */ + public function setParent($parent) + { + $this->parent = $parent; + } + + /** + * @return mixed + */ + public function getGroups() + { + return $this->groups; + } + + /** + * @param mixed $groups + */ + public function setGroups($groups) + { + $this->groups = $groups; + } + + /** + * @ORM\Column(name="Title", type="string") + * @var string + */ + private $title; + + /** + * @ORM\Column(name="Description", type="string") + * @var string + */ + private $description; + + /** + * @ORM\Column(name="Code", type="string") + * @var string + */ + private $code; + + /** + * @ORM\ManyToMany(targetEntity="models\main\Member", mappedBy="groups") + */ + private $members; + + /** + * @ORM\ManyToOne(targetEntity="Group", inversedBy="groups") + * @ORM\JoinColumn(name="ParentID", referencedColumnName="ID") + */ + private $parent; + + /** + * @ORM\OneToMany(targetEntity="Group", mappedBy="parent") + */ + private $groups; +} \ No newline at end of file diff --git a/app/Models/Foundation/Main/Member.php b/app/Models/Foundation/Main/Member.php index af83d06d..2621e8e5 100644 --- a/app/Models/Foundation/Main/Member.php +++ b/app/Models/Foundation/Main/Member.php @@ -27,6 +27,37 @@ use Doctrine\ORM\Mapping AS ORM; */ class Member extends SilverstripeBaseModel { + /** + * @return mixed + */ + public function getGroups() + { + return $this->groups; + } + + /** + * @param mixed $groups + */ + public function setGroups($groups) + { + $this->groups = $groups; + } + + public function __construct(){ + parent::__construct(); + $this->feedback = new ArrayCollection(); + $this->groups = new ArrayCollection(); + } + + /** + * @ORM\ManyToMany(targetEntity="models\main\Group", inversedBy="members") + * @ORM\JoinTable(name="Group_Members", + * joinColumns={@ORM\JoinColumn(name="MemberID", referencedColumnName="ID")}, + * inverseJoinColumns={@ORM\JoinColumn(name="GroupID", referencedColumnName="ID")} + * ) + */ + private $groups; + /** * @return string */ @@ -137,12 +168,6 @@ class Member extends SilverstripeBaseModel */ private $feedback; - public function __construct() - { - parent::__construct(); - $this->feedback = new ArrayCollection(); - } - /** * @return File */ diff --git a/app/Models/Foundation/Summit/Repositories/ISummitNotificationRepository.php b/app/Models/Foundation/Summit/Repositories/ISummitNotificationRepository.php new file mode 100644 index 00000000..f30074d8 --- /dev/null +++ b/app/Models/Foundation/Summit/Repositories/ISummitNotificationRepository.php @@ -0,0 +1,35 @@ +channel; + } + + /** + * @param string $channel + */ + public function setChannel($channel) + { + $this->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 + */ + public function getSummitEvent() + { + return $this->summit_event; + } + + /** + * @param SummitEvent $summit_event + */ + public function setSummitEvent($summit_event) + { + $this->summit_event = $summit_event; + } + + /** + * @return Group + */ + public function getGroup() + { + return $this->group; + } + + /** + * @param Group $group + */ + public function setGroup($group) + { + $this->group = $group; + } + + /** + * @return ArrayCollection + */ + public function getRecipients() + { + return $this->recipients; + } + + /** + * @param ArrayCollection $recipients + */ + public function setRecipients($recipients) + { + $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") + * @var SummitEvent + */ + private $summit_event; + + /** + * @ORM\ManyToOne(targetEntity="models\main\Group") + * @ORM\JoinColumn(name="GroupID", referencedColumnName="ID") + * @var Group + */ + private $group; + + /** + * @ORM\ManyToMany(targetEntity="models\main\Member") + * @ORM\JoinTable(name="SummitPushNotification_Recipients", + * joinColumns={@ORM\JoinColumn(name="SummitPushNotificationID", referencedColumnName="ID")}, + * inverseJoinColumns={@ORM\JoinColumn(name="MemberID", referencedColumnName="ID")} + * ) + */ + private $recipients; + + /** + * SummitPushNotification constructor. + */ + public function __construct() + { + parent::__construct(); + $this->recipients = new ArrayCollection(); + } +} \ No newline at end of file diff --git a/app/Repositories/RepositoriesProvider.php b/app/Repositories/RepositoriesProvider.php index a4e10fbb..5a8b8740 100644 --- a/app/Repositories/RepositoriesProvider.php +++ b/app/Repositories/RepositoriesProvider.php @@ -98,5 +98,11 @@ class RepositoriesProvider extends ServiceProvider function(){ return EntityManager::getRepository(\models\summit\SummitAttendeeTicket::class); }); + + App::singleton( + 'models\summit\ISummitNotificationRepository', + function(){ + return EntityManager::getRepository(\models\summit\SummitPushNotification::class); + }); } } \ No newline at end of file diff --git a/app/Repositories/Summit/Doctrine/DoctrineEventFeedbackRepository.php b/app/Repositories/Summit/Doctrine/DoctrineEventFeedbackRepository.php index 6c293f35..428082a1 100644 --- a/app/Repositories/Summit/Doctrine/DoctrineEventFeedbackRepository.php +++ b/app/Repositories/Summit/Doctrine/DoctrineEventFeedbackRepository.php @@ -22,6 +22,7 @@ use utils\PagingResponse; use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\Tools\Pagination\Paginator; use Doctrine\ORM\Query\Expr\Join; + /** * Class DoctrineEventFeedbackRepository */ diff --git a/app/Repositories/Summit/Doctrine/DoctrineSummitNotificationRepository.php b/app/Repositories/Summit/Doctrine/DoctrineSummitNotificationRepository.php new file mode 100644 index 00000000..d4e65304 --- /dev/null +++ b/app/Repositories/Summit/Doctrine/DoctrineSummitNotificationRepository.php @@ -0,0 +1,97 @@ +getEntityManager()->createQueryBuilder() + ->select("n") + ->from(\models\summit\SummitPushNotification::class, "n") + ->leftJoin('n.summit_event', 'e') + ->join('n.summit', 's', Join::WITH, " s.id = :summit_id") + ->setParameter('summit_id', $summit->getId()); + + if (!is_null($filter)) { + + $filter->apply2Query($query, array + ( + 'event_id' => 'e.id:json_int', + 'channel' => 'n.channel:json_string', + 'sent_date' => 'n.sent_date:datetime_epoch', + 'created' => 'n.created:datetime_epoch', + 'is_sent' => 'n.is_sent:json_int', + )); + } + + if (!is_null($order)) { + + $order->apply2Query($query, array + ( + 'sent_date' => 'n.sent_date', + 'created' => 'n.created', + 'id' => 'n.id', + )); + } else { + //default order + $query = $query->orderBy('n.id', Criteria::DESC); + } + + $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/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index cf55f3d9..51786de5 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -573,6 +573,19 @@ class ApiEndpointsSeeder extends Seeder ) ); + // notifications + + + ApiEndpoint::create( + array( + 'name' => 'get-notifications', + 'active' => true, + 'api_id' => $summit->id, + 'route' => '/api/v1/summits/{id}/notifications', + 'http_method' => 'GET' + ) + ); + $member_read_scope = ApiScope::where('name', '=', sprintf('%s/me/read', $current_realm))->first(); $summit_read_scope = ApiScope::where('name', '=', sprintf('%s/summits/read', $current_realm))->first(); $summit_write_scope = ApiScope::where('name', '=', sprintf('%s/summits/write', $current_realm))->first(); @@ -582,6 +595,7 @@ class ApiEndpointsSeeder extends Seeder $summit_external_order_read = ApiScope::where('name', '=', sprintf('%s/summits/read-external-orders', $current_realm))->first(); $summit_external_order_confirm = ApiScope::where('name', '=', sprintf('%s/summits/confirm-external-orders', $current_realm))->first(); $write_videos_scope = ApiScope::where('name', '=', sprintf('%s/summits/write-videos', $current_realm))->first(); + $read_notifications = ApiScope::where('name', '=', sprintf('%s/summits/read-notifications', $current_realm))->first(); // read $endpoint = ApiEndpoint::where('name', '=', 'get-summits')->first(); @@ -630,11 +644,16 @@ class ApiEndpointsSeeder extends Seeder $endpoint->scopes()->attach($summit_read_scope->id); $endpoint = ApiEndpoint::where('name', '=', 'get-location-events')->first(); $endpoint->scopes()->attach($summit_read_scope->id); - //read external orders + // read external orders $endpoint = ApiEndpoint::where('name', '=', 'get-external-order')->first(); $endpoint->scopes()->attach($summit_external_order_read->id); + // read notifications + + $endpoint = ApiEndpoint::where('name', '=', 'get-notifications')->first(); + $endpoint->scopes()->attach($read_notifications->id); + // write $endpoint = ApiEndpoint::where('name', '=', 'delete-event-attendee-schedule')->first(); diff --git a/database/seeds/ApiScopesSeeder.php b/database/seeds/ApiScopesSeeder.php index 387eaa2f..2fff2f7e 100644 --- a/database/seeds/ApiScopesSeeder.php +++ b/database/seeds/ApiScopesSeeder.php @@ -180,6 +180,16 @@ class ApiScopesSeeder extends Seeder 'system' => false ) ); + + ApiScope::create( + array( + 'name' => sprintf('%s/summits/read-notifications', $current_realm), + 'short_description' => 'Allow to read summit notifications', + 'description' => 'Allow to read summit notifications', + 'api_id' => $summits->id, + 'system' => false + ) + ); } } \ No newline at end of file diff --git a/tests/OAuth2SummitApiTest.php b/tests/OAuth2SummitApiTest.php index 04545fb7..d346a139 100644 --- a/tests/OAuth2SummitApiTest.php +++ b/tests/OAuth2SummitApiTest.php @@ -1624,11 +1624,11 @@ final class OAuth2SummitApiTest extends ProtectedApiTest { $params = array ( - 'id' => 6, - 'location_id' => 25, + 'id' => 7, + 'location_id' => 143, 'filter' => array ( - 'speaker=@Alex', + 'speaker=@Morgan', ) ); @@ -1718,4 +1718,41 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $this->assertTrue(!is_null($member)); } + public function testGetSummitNotifications(){ + + $params = array + ( + 'id' => 7, + 'page' => 1, + 'per_page' => 15, + 'filter' => [ + 'channel=='.\models\summit\SummitPushNotificationChannel::Event.',channel=='.\models\summit\SummitPushNotificationChannel::Group, + ], + 'order' => '+sent_date' + ); + + $headers = array + ( + "HTTP_Authorization" => " Bearer " .$this->access_token, + "CONTENT_TYPE" => "application/json" + ); + + $response = $this->action + ( + "GET", + "OAuth2SummitNotificationsApiController@getAll", + $params, + array(), + array(), + array(), + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + + $notifications = json_decode($content); + $this->assertTrue(!is_null($notifications)); + } + } \ No newline at end of file diff --git a/tests/ProtectedApiTest.php b/tests/ProtectedApiTest.php index 5a524499..1bde12e5 100644 --- a/tests/ProtectedApiTest.php +++ b/tests/ProtectedApiTest.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Config; use models\oauth2\AccessToken; @@ -46,6 +47,7 @@ class AccessTokenServiceStub implements IAccessTokenService $url . '/summits/confirm-external-orders', $url . '/summits/write-videos', $url . '/me/read', + $url . '/summits/read-notifications', ); return AccessToken::createFromParams('123456789', implode(' ', $scopes), '1', $realm, '1','11624', 3600, 'WEB_APPLICATION', '', ''); @@ -80,6 +82,7 @@ class AccessTokenServiceStub2 implements IAccessTokenService $url . '/summits/write-videos', $url . '/summits/write-videos', $url . '/me/read', + $url . '/summits/read-notifications', ); return AccessToken::createFromParams('123456789', implode(' ', $scopes), '1', $realm, null,null, 3600, 'SERVICE', '', ''); diff --git a/update_doctrine.sh b/update_doctrine.sh new file mode 100755 index 00000000..09c6d263 --- /dev/null +++ b/update_doctrine.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +php artisan doctrine:generate:proxies +php artisan doctrine:clear:metadata:cache +php artisan doctrine:clear:query:cache +php artisan doctrine:clear:result:cache \ No newline at end of file