diff --git a/.env.example b/.env.example index 4fda13d5..a881d4d6 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ APP_ENV=local APP_DEBUG=true +APP_DEBUG_EMAIL= APP_KEY=SomeRandomString APP_URL=http://localhost APP_SCOPE_BASE_REALM=http://localhost @@ -28,7 +29,9 @@ SESSION_DRIVER=redis SESSION_COOKIE_DOMAIN= SESSION_COOKIE_SECURE=false -QUEUE_DRIVER=sync +QUEUE_DRIVER=database +QUEUE_CONN= +QUEUE_DATABASE= MAIL_DRIVER=sendgrid SENDGRID_API_KEY='YOUR_SENDGRID_API_KEY' @@ -51,7 +54,7 @@ API_RESPONSE_CACHE_LIFETIME=600 LOG_EMAIL_TO=smarcet@gmail.com LOG_EMAIL_FROM=smarcet@gmail.com -LOG_LEVEL=info +LOG_LEVEL=debug EVENTBRITE_OAUTH2_PERSONAL_TOKEN= SS_ENCRYPT_KEY= @@ -69,15 +72,99 @@ SCP_REMOTE_BASE_PATH=/tmp GOOGLE_GEO_CODING_API_KEY= +# swift configuration CLOUD_STORAGE_BASE_URL= -CLOUD_STORAGE_ASSETS_CONTAINER= -CLOUD_STORAGE_IMAGES_CONTAINER= CLOUD_STORAGE_AUTH_URL= CLOUD_STORAGE_USERNAME= CLOUD_STORAGE_APIKEY= CLOUD_STORAGE_PROJECT_NAME= CLOUD_STORAGE_REGION= +CLOUD_STORAGE_ASSETS_CONTAINER= +CLOUD_STORAGE_IMAGES_CONTAINER= +CLOUD_STORAGE_MEDIA_UPLOADS_CONTAINER= # enable/disable cal sync background task ENABLE_CAL_SYNC=true # enable/disable bookable rooms reservation revocation task -ENABLE_BOOKABLE_ROOMS_RESERVATION_REVOCATION=false \ No newline at end of file +ENABLE_BOOKABLE_ROOMS_RESERVATION_REVOCATION=false + +MAIL_FROM_NAME= +MAIL_FROM_EMAIL= + +#stripe + +STRIPE_BOOKING_PRIVATE_KEY= +STRIPE_BOOKING_ENDPOINT_SECRET= +STRIPE_REGISTRATION_PRIVATE_KEY= +STRIPE_REGISTRATION_ENDPOINT_SECRET= + +#registration +REGISTRATION_SERVICE_OAUTH2_CLIENT_ID= +REGISTRATION_SERVICE_OAUTH2_CLIENT_SECRET= +REGISTRATION_SERVICE_OAUTH2_SCOPES= +REGISTRATION_DASHBOARD_OAUTH2_CLIENT_ID= +REGISTRATION_FROM_EMAIL= +REGISTRATION_DASHBOARD_BASE_URL= +REGISTRATION_DASHBOARD_BACK_URL=%s/a/orders +REGISTRATION_DASHBOARD_INVITATION_FORM_URL=%s/a/invitations/%s +REGISTRATION_DASHBOARD_ATTENDEE_EDIT_FORM_URL=%s/a/guests/%s +REGISTRATION_REMINDER_EMAIL_DAYS_INTERVAL=7 +REGISTRATION_SUPPORT_EMAIL= +#IDP +# CHECK /.well-known/openid-configuration at idp +IDP_BASE_URI= +IDP_AUTHORIZATION_ENDPOINT= +IDP_TOKEN_ENDPOINT= +IDP_INTROSPECTION_ENDPOINT= +IDP_USERINFO_ENDPOINT= + +REGISTRATION_VALIDATE_TICKET_TYPE_REMOVAL=true + +# default stripe config +# if not set at summit level this will be used ( if set by default) +# *_WEBHOOK_SECRET variables should be populated by manually created webhooks at set stripe account +# and should be pointed to $API_BASE_URL/api/public/v1/summits/all/payments/Registration/confirm +# and set to attended following events types +# * payment_intent.payment_failed +# payment_intent.succeeded + +REGISTRATION_DEFAULT_PAYMENT_PROVIDER=Stripe +REGISTRATION_DEFAULT_STRIPE_TEST_MODE= +REGISTRATION_DEFAULT_LIVE_STRIPE_PRIVATE_KEY= +REGISTRATION_DEFAULT_LIVE_STRIPE_PUBLISHABLE_KEY= +REGISTRATION_DEFAULT_LIVE_WEBHOOK_SECRET= +REGISTRATION_DEFAULT_TEST_STRIPE_PRIVATE_KEY= +REGISTRATION_DEFAULT_TEST_STRIPE_PUBLISHABLE_KEY= +REGISTRATION_DEFAULT_TEST_WEBHOOK_SECRET= + +BOOKABLE_ROOMS_DEFAULT_PAYMENT_PROVIDER=Stripe +BOOKABLE_ROOMS_DEFAULT_STRIPE_TEST_MODE= +BOOKABLE_ROOMS_DEFAULT_LIVE_STRIPE_PRIVATE_KEY= +BOOKABLE_ROOMS_DEFAULT_LIVE_STRIPE_PUBLISHABLE_KEY= +BOOKABLE_ROOMS_DEFAULT_LIVE_WEBHOOK_SECRET= +BOOKABLE_ROOMS_DEFAULT_TEST_STRIPE_PRIVATE_KEY= +BOOKABLE_ROOMS_DEFAULT_TEST_STRIPE_PUBLISHABLE_KEY= +BOOKABLE_ROOMS_DEFAULT_TEST_WEBHOOK_SECRET= + +MAIL_API_BASE_URL= +MAIL_API_OAUTH2_CLIENT_ID= +MAIL_API_OAUTH2_CLIENT_SECRET= +MAIL_API_OAUTH2_CLIENT_SCOPES= + +CFP_APP_BASE_URL= +CFP_SUPPORT_EMAIL= + +## RABBIT MQ +RABBITMQ_EXCHANGE_NAME=databus-exchange +RABBITMQ_HOST= +RABBITMQ_PORT=5671 +RABBITMQ_VHOST=databus +RABBITMQ_LOGIN=admin +RABBITMQ_PASSWORD=1qaz2wsx +RABBITMQ_QUEUE=default +RABBITMQ_SSL=true +RABBITMQ_SSL_CAFILE=/certs/rabbit/ca-osf.pem +RABBITMQ_SSL_LOCALCERT=/certs/rabbit/client-cert-osf.pem +RABBITMQ_SSL_LOCALKEY=/certs/rabbit/client-key-osf.pem +RABBITMQ_SSL_VERIFY_PEER=false + +DROPBOX_ACCESS_TOKEN= \ No newline at end of file diff --git a/.gitignore b/.gitignore index cd396b39..6b3e6e66 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ storage/* routes.txt /storage/logs/ /ss.sql +phpunit.xml \ No newline at end of file diff --git a/Libs/ModelSerializers/AbstractSerializer.php b/Libs/ModelSerializers/AbstractSerializer.php index a9dea4d0..4f2bf1ef 100644 --- a/Libs/ModelSerializers/AbstractSerializer.php +++ b/Libs/ModelSerializers/AbstractSerializer.php @@ -11,6 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use Illuminate\Support\Facades\Log; use libs\utils\JsonUtils; use models\oauth2\IResourceServerContext; use models\utils\IEntity; @@ -123,7 +125,7 @@ abstract class AbstractSerializer implements IModelSerializer return array_merge(array($class_name), $parents); } - const BoolType = 'json_boolean'; + const BoolType = 'json_boolean'; const EpochType = 'datetime_epoch'; const StringType = 'json_string'; const IntType = 'json_int'; @@ -191,40 +193,40 @@ abstract class AbstractSerializer implements IModelSerializer switch(strtolower($mapping[1])) { case 'datetime_epoch': - { - if(!is_null($value)) { - $value = $value->getTimestamp(); - } + { + if(!is_null($value)) { + $value = $value->getTimestamp(); } + } break; case 'json_string': - { - $value = JsonUtils::toJsonString($value); - } + { + $value = JsonUtils::toJsonString($value); + } break; case 'json_boolean': - { - $value = JsonUtils::toJsonBoolean($value); - } + { + $value = JsonUtils::toJsonBoolean($value); + } break; case 'json_int': - { - $value = JsonUtils::toJsonInt($value); - } + { + $value = JsonUtils::toJsonInt($value); + } break; case 'json_float': - { - $value = JsonUtils::toJsonFloat($value); - } + { + $value = JsonUtils::toJsonFloat($value); + } break; case 'json_obfuscated_email': - { - $value = JsonUtils::toObfuscatedEmail($value); - } + { + $value = JsonUtils::toObfuscatedEmail($value); + } case 'json_url':{ $value = JsonUtils::encodeUrl($value); } - break; + break; } } $new_values[$mapping[0]] = $value; @@ -259,12 +261,16 @@ abstract class AbstractSerializer implements IModelSerializer * @param string $expand * @return string */ - protected static function getExpandForPrefix(string $prefix, string $expand):string{ + protected static function getExpandForPrefix(string $prefix, string $expand):string { + + Log::debug(sprintf("AbstractSerializer::getExpandForPrefix prefix %s expand %s", $prefix, $expand)); + $prefix_expand = []; foreach(explode(',', $expand) as $e){ if(strstr($e, $prefix.".")!==false) $prefix_expand[] = str_replace($prefix.".","", $e); } + return implode(',', $prefix_expand); } } \ No newline at end of file diff --git a/Libs/Utils/JsonUtils.php b/Libs/Utils/JsonUtils.php index f18c427e..9c6cc5f9 100644 --- a/Libs/Utils/JsonUtils.php +++ b/Libs/Utils/JsonUtils.php @@ -86,7 +86,7 @@ abstract class JsonUtils public static function toJsonFloat($value) { if(empty($value)) return 0.00; - return floatval(number_format(floatval($value),2)); + return floatval($value); } /** diff --git a/app/Console/Commands/RegistrationSummitOrderReminderEmailCommand.php b/app/Console/Commands/RegistrationSummitOrderReminderEmailCommand.php new file mode 100644 index 00000000..08457522 --- /dev/null +++ b/app/Console/Commands/RegistrationSummitOrderReminderEmailCommand.php @@ -0,0 +1,84 @@ +order_service = $order_service; + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + + try { + $this->info("processing summit orders without action"); + $start = time(); + Log::debug("RegistrationSummitOrderReminderEmailCommand::handle"); + $this->order_service->processAllOrderReminder(); + + $end = time(); + $delta = $end - $start; + $this->info(sprintf("execution call %s seconds", $delta)); + } + catch (Exception $ex) { + Log::error($ex); + } + } +} \ No newline at end of file diff --git a/app/Console/Commands/RegistrationSummitOrderRevocationCommand.php b/app/Console/Commands/RegistrationSummitOrderRevocationCommand.php new file mode 100644 index 00000000..6388fbe1 --- /dev/null +++ b/app/Console/Commands/RegistrationSummitOrderRevocationCommand.php @@ -0,0 +1,102 @@ +order_service = $order_service; + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + + $enabled = Config::get("registration.enable_orders_reservation_revocation", true); + if (!$enabled) { + $this->info("task is not enabled!"); + return false; + } + + try { + $this->info("processing summit orders reservations"); + $start = time(); + $lifetime = intval(Config::get("registration.reservation_lifetime", 30)); + Log::info(sprintf("RegistrationSummitOrderRevocationCommand: using lifetime of %s ", $lifetime)); + + Log::info("RegistrationSummitOrderRevocationCommand: invoking revokeReservedOrdersOlderThanNMinutes"); + $this->order_service->revokeReservedOrdersOlderThanNMinutes($lifetime); + + $end = time(); + $delta = $end - $start; + $this->info(sprintf("execution call %s seconds", $delta)); + + $start = time(); + Log::info("RegistrationSummitOrderRevocationCommand: invoking confirmOrdersOlderThanNMinutes"); + $this->order_service->confirmOrdersOlderThanNMinutes($lifetime); + + $end = time(); + $delta = $end - $start; + $this->info(sprintf("execution call %s seconds", $delta)); + } catch (Exception $ex) { + Log::error($ex); + } + } +} diff --git a/app/Console/Commands/SummitForwardXDays.php b/app/Console/Commands/SummitForwardXDays.php new file mode 100644 index 00000000..73a5a56e --- /dev/null +++ b/app/Console/Commands/SummitForwardXDays.php @@ -0,0 +1,98 @@ +summit_service = $summit_service; + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + try { + $summit_id = $this->argument('summit_id'); + if(empty($summit_id)) + throw new \InvalidArgumentException("summit_id is required"); + + $days = $this->argument('days'); + if(empty($days)) + throw new \InvalidArgumentException("days is required"); + + $negative = $this->option('negative'); + $check_summit_ends = $this->option('check-ended'); + $this->info("processing SummitForwardXDays"); + $start = time(); + + $days = intval($days); + + $this->summit_service->advanceSummit(intval($summit_id), $days, $negative, $check_summit_ends); + $end = time(); + $delta = $end - $start; + $this->info(sprintf("execution call %s seconds", $delta)); + } + catch (Exception $ex) { + Log::warning($ex); + } + } +} \ No newline at end of file diff --git a/app/Console/Commands/SummitRoomReservationRevocationCommand.php b/app/Console/Commands/SummitRoomReservationRevocationCommand.php index 38038a14..505fc6e6 100644 --- a/app/Console/Commands/SummitRoomReservationRevocationCommand.php +++ b/app/Console/Commands/SummitRoomReservationRevocationCommand.php @@ -11,15 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -use App\Models\Foundation\Summit\Repositories\ISummitRoomReservationRepository; use App\Services\Model\ILocationService; use Illuminate\Support\Facades\Log; -use libs\utils\ITransactionService; -use models\summit\SummitRoomReservation; -use models\utils\SilverstripeBaseModel; -use utils\Filter; -use utils\FilterElement; -use utils\PagingInfo; use Illuminate\Console\Command; use Illuminate\Support\Facades\Config; use Exception; diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 2e698492..4862e6ae 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -11,10 +11,9 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - -use App\Console\Commands\SummitEventSetAvgRateProcessor; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; +use Illuminate\Support\Facades\App; use models\summit\CalendarSync\CalendarSyncInfo; /** * Class Kernel @@ -37,6 +36,9 @@ class Kernel extends ConsoleKernel \App\Console\Commands\SummitRoomReservationRevocationCommand::class, \App\Console\Commands\ExternalScheduleFeedIngestionCommand::class, \App\Console\Commands\SummitEventSetAvgRateProcessor::class, + \App\Console\Commands\RegistrationSummitOrderRevocationCommand::class, + \App\Console\Commands\RegistrationSummitOrderReminderEmailCommand::class, + \App\Console\Commands\SummitForwardXDays::class, ]; /** @@ -49,6 +51,8 @@ class Kernel extends ConsoleKernel { // regenerate available summits cache + $env = App::environment(); + $schedule->command('summit:json-generator')->everyFiveMinutes()->withoutOverlapping(); // list of available summits @@ -79,5 +83,18 @@ class Kernel extends ConsoleKernel // AVG schedule feedback rate $schedule->command("summit:feedback-avg-rate-processor")->everyFifteenMinutes()->withoutOverlapping(); + // registration orders + + $schedule->command('summit:order-reservation-revocation')->everyFiveMinutes()->withoutOverlapping(); + + // reminder emails + + $schedule->command('summit:registration-order-reminder-action-email')->everyThirtyMinutes()->timezone(new \DateTimeZone('UTC'))->withoutOverlapping(); + + // production YOCO (13) advance AT 0700 AM ( 12:00 AM PST) + + if ($env == 'production') { + $schedule->command("summit:forward-x-days", [13, 2, '--check-ended'])->dailyAt("07:00")->timezone('UTC')->withoutOverlapping(); + } } } diff --git a/app/Events/NewMember.php b/app/Events/NewMember.php new file mode 100644 index 00000000..bcac6090 --- /dev/null +++ b/app/Events/NewMember.php @@ -0,0 +1,45 @@ +member_id = $member_id; + } + + /** + * @return int + */ + public function getMemberId(): int + { + return $this->member_id; + } + +} \ No newline at end of file diff --git a/app/Events/Registration/CreatedSummitRegistrationOrder.php b/app/Events/Registration/CreatedSummitRegistrationOrder.php new file mode 100644 index 00000000..a03d3e00 --- /dev/null +++ b/app/Events/Registration/CreatedSummitRegistrationOrder.php @@ -0,0 +1,22 @@ +summit_id = $summit_id; + $this->tickets_to_return = $tickets_to_return; + $this->promo_codes_to_return = $promo_codes_to_return; + } + + /** + * @return array + */ + public function getTicketsToReturn(): array + { + return $this->tickets_to_return; + } + + /** + * @return array + */ + public function getPromoCodesToReturn(): array + { + return $this->promo_codes_to_return; + } + + /** + * @return int + */ + public function getSummitId(): int + { + return $this->summit_id; + } + + +} \ No newline at end of file diff --git a/app/Events/Registration/PaymentSummitRegistrationOrderConfirmed.php b/app/Events/Registration/PaymentSummitRegistrationOrderConfirmed.php new file mode 100644 index 00000000..6b0f7236 --- /dev/null +++ b/app/Events/Registration/PaymentSummitRegistrationOrderConfirmed.php @@ -0,0 +1,22 @@ +days_before_event_starts = $days_before_event_starts; + } + + /** + * @return int + */ + public function getDaysBeforeEventStarts(): int + { + return $this->days_before_event_starts; + } + +} \ No newline at end of file diff --git a/app/Events/Registration/RequestedSummitOrderRefund.php b/app/Events/Registration/RequestedSummitOrderRefund.php new file mode 100644 index 00000000..2006d26b --- /dev/null +++ b/app/Events/Registration/RequestedSummitOrderRefund.php @@ -0,0 +1,45 @@ +days_before_event_starts = $days_before_event_starts; + } + + /** + * @return int + */ + public function getDaysBeforeEventStarts(): int + { + return $this->days_before_event_starts; + } + +} \ No newline at end of file diff --git a/app/Events/Registration/SummitAttendeeTicketAction.php b/app/Events/Registration/SummitAttendeeTicketAction.php new file mode 100644 index 00000000..03b828d6 --- /dev/null +++ b/app/Events/Registration/SummitAttendeeTicketAction.php @@ -0,0 +1,44 @@ +ticket_id = $ticket_id; + } + + /** + * @return int + */ + public function getTicketId(): int + { + return $this->ticket_id; + } +} \ No newline at end of file diff --git a/app/Events/Registration/SummitAttendeeTicketRefundAccepted.php b/app/Events/Registration/SummitAttendeeTicketRefundAccepted.php new file mode 100644 index 00000000..c69852af --- /dev/null +++ b/app/Events/Registration/SummitAttendeeTicketRefundAccepted.php @@ -0,0 +1,59 @@ +tickets_to_return = $tickets_to_return; + $this->promo_codes_to_return = $promo_codes_to_return; + } + + /** + * @return array + */ + public function getTicketsToReturn(): array + { + return $this->tickets_to_return; + } + + /** + * @return array + */ + public function getPromoCodesToReturn(): array + { + return $this->promo_codes_to_return; + } + +} \ No newline at end of file diff --git a/app/Events/Registration/SummitOrderCanceled.php b/app/Events/Registration/SummitOrderCanceled.php new file mode 100644 index 00000000..b705ffea --- /dev/null +++ b/app/Events/Registration/SummitOrderCanceled.php @@ -0,0 +1,79 @@ +send_email = $send_email; + $this->tickets_to_return = $tickets_to_return; + $this->promo_codes_to_return = $promo_codes_to_return; + } + + /** + * @return bool + */ + public function shouldSendEmail(): bool + { + return $this->send_email; + } + + /** + * @return array + */ + public function getTicketsToReturn(): array + { + return $this->tickets_to_return; + } + + /** + * @return array + */ + public function getPromoCodesToReturn(): array + { + return $this->promo_codes_to_return; + } + + + +} \ No newline at end of file diff --git a/app/Events/Registration/SummitOrderRefundAccepted.php b/app/Events/Registration/SummitOrderRefundAccepted.php new file mode 100644 index 00000000..4f63b5c0 --- /dev/null +++ b/app/Events/Registration/SummitOrderRefundAccepted.php @@ -0,0 +1,59 @@ +promo_codes_to_return = $promo_codes_to_return; + $this->tickets_to_return = $tickets_to_return; + } + + /** + * @return array + */ + public function getTicketsToReturn(): array + { + return $this->tickets_to_return; + } + + /** + * @return array + */ + public function getPromoCodesToReturn(): array + { + return $this->promo_codes_to_return; + } + +} \ No newline at end of file diff --git a/app/Events/Registration/SummitRegistrationOrderAction.php b/app/Events/Registration/SummitRegistrationOrderAction.php new file mode 100644 index 00000000..af7c4a76 --- /dev/null +++ b/app/Events/Registration/SummitRegistrationOrderAction.php @@ -0,0 +1,44 @@ +order_id = $order_id; + } + + /** + * @return int + */ + public function getOrderId(): int + { + return $this->order_id; + } +} \ No newline at end of file diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 95870b65..394054da 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -1,14 +1,27 @@ -repository = $company_repository; + $this->service = $service; } - public function getAll(){ + use ParametrizedGetAll; - $values = Input::all(); + /** + * @return mixed + */ + public function getAllCompanies(){ - $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 - ( + return $this->_getAll( + function(){ + return [ 'name' => ['=@', '=='], - )); - } - - $order = null; - - if (Input::has('order')) + ]; + }, + function(){ + return [ + 'name' => 'sometimes|string', + ]; + }, + function() { - $order = OrderParser::parse(Input::get('order'), array - ( + return [ 'name', 'id', - )); + ]; + }, + function($filter){ + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_Public; } - - if(is_null($filter)) $filter = new Filter(); - - $data = $this->repository->getAllByPage(new PagingInfo($page, $per_page), $filter, $order); - $fields = Request::input('fields', ''); - $fields = !empty($fields) ? explode(',', $fields) : []; - $relations = Request::input('relations', ''); - $relations = !empty($relations) ? explode(',', $relations) : []; - - return $this->ok - ( - $data->toArray - ( - Request::input('expand', ''), - $fields, - $relations - ) - ); - } - 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); - } + ); } + use AddEntity; + + /** + * @param array $payload + * @return array + */ + function getAddValidationRules(array $payload): array + { + return [ + 'name' => 'required|string', + 'description' => 'nullable|string', + 'url' => 'nullable|url', + 'industry' => 'nullable|string', + 'city' => 'nullable|string', + 'state' => 'nullable|string', + 'country' => 'nullable|string', + ]; + } + + /** + * @param array $payload + * @return IEntity + * @throws ValidationException + */ + protected function addEntity(array $payload): IEntity + { + return $this->service->addCompany($payload); + } } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php index 5fa22eaf..8533bfdf 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2MembersApiController.php @@ -28,7 +28,7 @@ use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\Log; use utils\PagingInfo; use utils\PagingResponse; - +use Exception; /** * Class OAuth2MembersApiController * @package App\Http\Controllers @@ -63,6 +63,9 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController */ public function getAll(){ + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error404(); + $values = Input::all(); $rules = [ @@ -152,7 +155,9 @@ final class OAuth2MembersApiController extends OAuth2ProtectedController ( Request::input('expand', ''), $fields, - $relations + $relations, + [], + $current_member->isAdmin() ? SerializerRegistry::SerializerType_Admin : SerializerRegistry::SerializerType_Public ) ); } diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2SummitAdministratorPermissionGroupApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2SummitAdministratorPermissionGroupApiController.php new file mode 100644 index 00000000..45c486dd --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2SummitAdministratorPermissionGroupApiController.php @@ -0,0 +1,269 @@ +service = $service; + $this->repository = $repository; + } + + use ParametrizedGetAll; + + use AddEntity; + + use DeleteEntity; + + use UpdateEntity; + + use GetEntity; + + function getAll() + { + return $this->_getAll( + function () { + return [ + 'title' => ['=@', '=='], + 'member_first_name' => ['=@', '=='], + 'member_last_name' => ['=@', '=='], + 'member_full_name' => ['=@', '=='], + 'member_email' => ['=@', '=='], + 'summit_id' => ['=='], + 'member_id' => ['=='], + ]; + }, + function () { + return [ + 'title' => 'sometimes|string', + 'member_first_name' => 'sometimes|string', + 'member_last_name' => 'sometimes|string', + 'member_full_name' => 'sometimes|string', + 'member_email' => 'sometimes|string', + 'summit_id' => 'sometimes|integer', + 'member_id' => 'sometimes|integer', + ]; + }, + function () { + return [ + 'id', + 'title', + ]; + }, + function ($filter) { + return $filter; + }, + function () { + return SerializerRegistry::SerializerType_Public; + } + ); + } + + /** + * @inheritDoc + */ + function getAddValidationRules(array $payload): array + { + return [ + 'title' => 'required|string', + 'summits' => 'required|int_array', + 'members' => 'required|int_array', + ]; + } + + /** + * @inheritDoc + */ + protected function addEntity(array $payload): IEntity + { + return $this->service->create($payload); + } + + /** + * @inheritDoc + */ + protected function deleteEntity(int $id): void + { + $this->service->delete($id); + } + + /** + * @inheritDoc + */ + protected function getEntity(int $id): IEntity + { + return $this->repository->getById($id); + } + + /** + * @inheritDoc + */ + function getUpdateValidationRules(array $payload): array + { + return [ + 'title' => 'sometimes|string', + 'summits' => 'sometimes|int_array', + 'members' => 'sometimes|int_array', + ]; + } + + /** + * @inheritDoc + */ + protected function updateEntity($id, array $payload): IEntity + { + return $this->service->update($id, $payload); + } + + public function addMember($id, $member_id) + { + try { + $group = $this->repository->getById($id); + if (is_null($group)) + throw new EntityNotFoundException(); + $group = $this->service->addMemberTo($group, $member_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($group)->serialize()); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + public function removeMember($id, $member_id) + { + try { + $group = $this->repository->getById($id); + if (is_null($group)) + throw new EntityNotFoundException(); + $group = $this->service->removeMemberFrom($group, $member_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($group)->serialize()); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + public function addSummit($id, $summit_id) + { + try { + $group = $this->repository->getById($id); + if (is_null($group)) + throw new EntityNotFoundException(); + $group = $this->service->addSummitTo($group, $summit_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($group)->serialize()); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + public function removeSummit($id, $summit_id) + { + try { + $group = $this->repository->getById($id); + if (is_null($group)) + throw new EntityNotFoundException(); + $group = $this->service->removeSummitFrom($group, $summit_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($group)->serialize()); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/PaymentGatewayProfileValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/PaymentGatewayProfileValidationRulesFactory.php new file mode 100644 index 00000000..220985f9 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/PaymentGatewayProfileValidationRulesFactory.php @@ -0,0 +1,67 @@ + 'sometimes|boolean', + 'application_type' => 'sometimes|string|in:'.implode(',',IPaymentConstants::ValidApplicationTypes), + 'provider' => 'required|string|in:'.implode(',',IPaymentConstants::ValidProviderTypes), + ]; + if(isset($data['provider']) && $data['provider'] == IPaymentConstants::ProviderStripe){ + $rules = array_merge($rules, [ + 'test_mode_enabled' => 'required|boolean', + 'live_secret_key' => 'sometimes|string', + 'live_publishable_key' => 'required_with:live_secret_key|string', + 'test_secret_key' => 'required_with:test_mode_enabled|string', + 'test_publishable_key' => 'required_with:test_secret_key|string', + ]); + } + return $rules; + } + + $rules = [ + 'active' => 'required|boolean', + 'application_type' => 'required|string|in:'.implode(',',IPaymentConstants::ValidApplicationTypes), + 'provider' => 'required|string|in:'.implode(',',IPaymentConstants::ValidProviderTypes), + ]; + + if(isset($data['provider']) && $data['provider'] == IPaymentConstants::ProviderStripe){ + $rules = array_merge($rules, [ + 'test_mode_enabled' => 'required|boolean', + 'live_secret_key' => 'sometimes|string', + 'live_publishable_key' => 'required_with:live_secret_key|string', + 'test_secret_key' => 'required_with:test_mode_enabled|string', + 'test_publishable_key' => 'required_with:test_secret_key|string', + ]); + } + return $rules; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/AccessLevelTypeValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/AccessLevelTypeValidationRulesFactory.php new file mode 100644 index 00000000..1da084af --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/AccessLevelTypeValidationRulesFactory.php @@ -0,0 +1,43 @@ + 'sometimes|string', + 'description' => 'sometimes|string', + 'template_content' => 'sometimes|string', + 'is_default' => 'sometimes|boolean', + ]; + } + return [ + 'name' => 'required|string', + 'description' => 'sometimes|string', + 'template_content' => 'nullable|string', + 'is_default' => 'required|boolean', + ]; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/PromoCodesValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/PromoCodesValidationRulesFactory.php similarity index 52% rename from app/Http/Controllers/Apis/Protected/Summit/Factories/PromoCodesValidationRulesFactory.php rename to app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/PromoCodesValidationRulesFactory.php index 68df76c9..f87f1d9f 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/Factories/PromoCodesValidationRulesFactory.php +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/PromoCodesValidationRulesFactory.php @@ -13,8 +13,11 @@ **/ use App\Models\Foundation\Summit\PromoCodes\PromoCodesConstants; use models\exceptions\ValidationException; +use models\summit\MemberSummitRegistrationDiscountCode; use models\summit\MemberSummitRegistrationPromoCode; +use models\summit\SpeakerSummitRegistrationDiscountCode; use models\summit\SpeakerSummitRegistrationPromoCode; +use models\summit\SponsorSummitRegistrationDiscountCode; use models\summit\SponsorSummitRegistrationPromoCode; /** * Class PromoCodesValidationRulesFactory @@ -24,10 +27,11 @@ final class PromoCodesValidationRulesFactory { /** * @param array $data + * @param bool $update * @return array * @throws ValidationException */ - public static function build(array $data){ + public static function build(array $data, $update = false){ if(!isset($data['class_name'])) throw new ValidationException("class_name parameter is mandatory"); @@ -44,10 +48,20 @@ final class PromoCodesValidationRulesFactory } $base_rules = [ - 'code' => 'required|string', + 'code' => $update ? 'sometimes|string|max:255' : 'required|string|max:255', + 'quantity_available' => 'sometimes|integer|min:0', + 'valid_since_date' => 'nullable|date_format:U', + 'valid_until_date' => 'nullable|required_with:valid_since_date|date_format:U|after:valid_since_date', + 'badge_type_id' => 'nullable|integer', + 'allowed_ticket_types' => 'sometimes|int_array', + 'badge_features' => 'sometimes|int_array', ]; $specific_rules = []; + $discount_code_rules = [ + 'amount' => 'sometimes|numeric|min:0', + 'rate' => 'sometimes|numeric|min:0', + ]; switch ($class_name){ case MemberSummitRegistrationPromoCode::ClassName:{ @@ -55,7 +69,7 @@ final class PromoCodesValidationRulesFactory 'first_name' => 'required_without:owner_id|string', 'last_name' => 'required_without:owner_id|string', 'email' => 'required_without:owner_id|email|max:254', - 'type' => 'required|string|in:'.join(",",MemberSummitRegistrationPromoCode::$valid_type_values), + 'type' => 'required|string|in:'.join(",", PromoCodesConstants::MemberSummitRegistrationPromoCodeTypes), 'owner_id' => 'required_without:first_name,last_name,email|integer' ]; } @@ -63,7 +77,7 @@ final class PromoCodesValidationRulesFactory case SpeakerSummitRegistrationPromoCode::ClassName: { $specific_rules = [ - 'type' => 'required|string|in:'.join(",",SpeakerSummitRegistrationPromoCode::$valid_type_values), + 'type' => 'required|string|in:'.join(",", PromoCodesConstants::SpeakerSummitRegistrationPromoCodeTypes), 'speaker_id' => 'required|integer' ]; } @@ -75,6 +89,35 @@ final class PromoCodesValidationRulesFactory ]; } break; + case MemberSummitRegistrationDiscountCode::ClassName: + { + $specific_rules = array_merge([ + 'first_name' => 'required_without:owner_id|string', + 'last_name' => 'required_without:owner_id|string', + 'email' => 'required_without:owner_id|email|max:254', + 'type' => 'required|string|in:'.join(",", PromoCodesConstants::MemberSummitRegistrationPromoCodeTypes), + 'owner_id' => 'required_without:first_name,last_name,email|integer', + ], $discount_code_rules); + } + break; + case SpeakerSummitRegistrationDiscountCode::ClassName: + { + $specific_rules = array_merge([ + 'type' => 'required|string|in:'.join(",", PromoCodesConstants::SpeakerSummitRegistrationPromoCodeTypes), + 'speaker_id' => 'required|integer', + 'amount' => 'sometimes|required_without:rate', + 'rate' => 'sometimes|required_without:amount', + ], $discount_code_rules); + } + break; + case SponsorSummitRegistrationDiscountCode::ClassName: + { + $specific_rules = array_merge([ + 'sponsor_id' => 'required|integer' + ],$discount_code_rules); + + } + break; } return array_merge($base_rules, $specific_rules); diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/SummitTicketTypeValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitBadgeFeatureTypeValidationRulesFactory.php similarity index 72% rename from app/Http/Controllers/Apis/Protected/Summit/Factories/SummitTicketTypeValidationRulesFactory.php rename to app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitBadgeFeatureTypeValidationRulesFactory.php index a5427a9a..fc20c706 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/Factories/SummitTicketTypeValidationRulesFactory.php +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitBadgeFeatureTypeValidationRulesFactory.php @@ -1,6 +1,6 @@ 'sometimes|string', + 'name' => 'sometimes|string', 'description' => 'sometimes|string', - 'external_id' => 'sometimes|string|max:255', + 'template_content' => 'nullable|string', ]; } - return [ - 'name' => 'required|string', + 'name' => 'required|string', 'description' => 'sometimes|string', - 'external_id' => 'required|string|max:255', + 'template_content' => 'nullable|string', ]; } - } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitBadgeTypeValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitBadgeTypeValidationRulesFactory.php new file mode 100644 index 00000000..adb243ae --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitBadgeTypeValidationRulesFactory.php @@ -0,0 +1,43 @@ + 'sometimes|string', + 'description' => 'sometimes|string', + 'template_content' => 'nullable|string', + 'is_default' => 'sometimes|boolean', + ]; + } + return [ + 'name' => 'required|string', + 'description' => 'required|string', + 'template_content' => 'nullable|string', + 'is_default' => 'required|boolean', + ]; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitOrderExtraQuestionTypeValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitOrderExtraQuestionTypeValidationRulesFactory.php new file mode 100644 index 00000000..b4c72e30 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitOrderExtraQuestionTypeValidationRulesFactory.php @@ -0,0 +1,51 @@ + 'sometimes|string', + 'type' => 'sometimes|string|in:'.implode(",", SummitOrderExtraQuestionTypeConstants::ValidQuestionTypes), + 'label' => 'sometimes|string', + 'mandatory' => 'sometimes|boolean', + 'usage' => 'sometimes|string|in:'.implode(",", SummitOrderExtraQuestionTypeConstants::ValidQuestionUsages), + 'printable' => 'sometimes|boolean', + 'placeholder' => 'sometimes|string', + 'order' => 'sometimes|integer|min:1', + ]; + } + + return [ + 'name' => 'required|string', + 'type' => 'required|string|in:'.implode(",", SummitOrderExtraQuestionTypeConstants::ValidQuestionTypes), + 'label' => 'required|string', + 'mandatory' => 'required|boolean', + 'usage' => 'required|string|in:'.implode(",", SummitOrderExtraQuestionTypeConstants::ValidQuestionUsages), + 'printable' => 'sometimes|boolean', + 'placeholder' => 'sometimes|string', + ]; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitRefundPolicyTypeValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitRefundPolicyTypeValidationRulesFactory.php new file mode 100644 index 00000000..66bb6bfe --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitRefundPolicyTypeValidationRulesFactory.php @@ -0,0 +1,41 @@ + 'sometimes|string', + 'refund_rate' => 'sometimes|numeric|min:0|max:100', + 'until_x_days_before_event_starts' => 'sometimes|integer|min:1', + ]; + } + return [ + 'name' => 'required|string', + 'refund_rate' => 'required|numeric|min:0|max:100', + 'until_x_days_before_event_starts' => 'required|integer|min:1', + ]; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitTicketTypeValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitTicketTypeValidationRulesFactory.php new file mode 100644 index 00000000..abfd614a --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/SummitTicketTypeValidationRulesFactory.php @@ -0,0 +1,55 @@ + 'sometimes|string', + 'description' => 'sometimes|string', + 'badge_type_id' => 'sometimes|integer', + 'external_id' => 'sometimes|string|max:255', + 'currency' => 'sometimes|string|currency_iso', + 'quantity_2_sell' => 'sometimes|integer|greater_than:0', + 'max_quantity_per_order' => 'sometimes|integer', + 'sales_start_date' => 'nullable|date_format:U', + 'sales_end_date' => 'nullable:sales_start_date|date_format:U|after:sales_start_date', + 'cost' => 'sometimes|numeric|greater_than_or_equal:0', + ]; + } + + return [ + 'name' => 'required|string', + 'cost' => 'sometimes|numeric|greater_than_or_equal:0', + 'currency' => 'required_with:cost|string|currency_iso', + 'quantity_2_sell' => 'sometimes|integer|greater_than:0', + 'max_quantity_per_order' => 'sometimes|integer', + 'sales_start_date' => 'nullable|date_format:U', + 'sales_end_date' => 'nullable:sales_start_date|date_format:U|after:sales_start_date', + 'description' => 'sometimes|string', + 'external_id' => 'sometimes|string|max:255', + 'badge_type_id' => 'sometimes|integer', + ]; + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/TaxTypeValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/TaxTypeValidationRulesFactory.php new file mode 100644 index 00000000..198b6eb3 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/Registration/TaxTypeValidationRulesFactory.php @@ -0,0 +1,41 @@ + 'sometimes|string', + 'tax_id' => 'sometimes|string', + 'rate' => 'sometimes|numeric|greater_than:0' + ]; + } + return [ + 'name' => 'required|string', + 'tax_id' => 'sometimes|string', + 'rate' => 'required|numeric|greater_than:0' + ]; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/SponsorValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/SponsorValidationRulesFactory.php new file mode 100644 index 00000000..4ab7b1a2 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/SponsorValidationRulesFactory.php @@ -0,0 +1,41 @@ + 'sometimes|integer', + 'sponsorship_id' => 'sometimes|integer', + 'order' => 'sometimes|integer|min:1', + ]; + } + return [ + 'company_id' => 'required|integer', + 'sponsorship_id' => 'required|integer', + ]; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/SponsorshipTypeValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/SponsorshipTypeValidationRulesFactory.php new file mode 100644 index 00000000..f6ea6478 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/SponsorshipTypeValidationRulesFactory.php @@ -0,0 +1,45 @@ + 'sometimes|string', + 'label' => 'sometimes|string', + 'size' => 'sometimes|string|in:'.implode(",", ISponsorshipTypeConstants::AllowedSizes), + 'order' => 'sometimes|integer|min:1', + ]; + } + return [ + 'name' => 'required|string', + 'label' => 'required|string', + 'size' => 'required|string|in:'.implode(",", ISponsorshipTypeConstants::AllowedSizes), + ]; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Factories/SummitValidationRulesFactory.php b/app/Http/Controllers/Apis/Protected/Summit/Factories/SummitValidationRulesFactory.php index 3471051e..cfe8a49d 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/Factories/SummitValidationRulesFactory.php +++ b/app/Http/Controllers/Apis/Protected/Summit/Factories/SummitValidationRulesFactory.php @@ -11,113 +11,141 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -use models\summit\Summit; +use App\Models\Foundation\Summit\ISummitExternalScheduleFeedType; +use App\Models\Foundation\Summit\Registration\ISummitExternalRegistrationFeedType; /** * Class SummitValidationRulesFactory * @package App\Http\Controllers */ final class SummitValidationRulesFactory { - public static function build(array $data, $update = false){ + public static function build(array $data, $update = false) + { - if($update){ + if ($update) { return [ - 'name' => 'sometimes|string|max:50', - 'start_date' => 'sometimes|date_format:U', - 'end_date' => 'required_with:start_date|date_format:U|after_or_equal:start_date', - 'registration_begin_date' => 'nullable|date_format:U', - 'registration_end_date' => 'nullable|required_with:registration_begin_date|date_format:U|after_or_equal:registration_begin_date', + 'name' => 'sometimes|string|max:50', + 'start_date' => 'sometimes|date_format:U', + 'end_date' => 'required_with:start_date|date_format:U|after_or_equal:start_date', + 'registration_begin_date' => 'nullable|date_format:U', + 'registration_end_date' => 'nullable|required_with:registration_begin_date|date_format:U|after_or_equal:registration_begin_date', 'start_showing_venues_date' => 'nullable|date_format:U|before_or_equal:start_date', - 'schedule_start_date' => 'nullable|date_format:U|after_or_equal:start_date|before_or_equal:end_date', - 'active' => 'sometimes|boolean', - 'dates_label' => 'sometimes|string', - 'time_zone_id' => 'sometimes|timezone', - 'external_summit_id' => 'sometimes|string', - 'available_on_api' => 'sometimes|boolean', - 'calendar_sync_name' => 'sometimes|string|max:255', - 'calendar_sync_desc' => 'sometimes|string', - 'link' => 'sometimes|url', - 'registration_link' => 'sometimes|url', - 'max_submission_allowed_per_user' => 'sometimes|integer|min:1', - 'secondary_registration_link' => 'sometimes|url', - 'secondary_registration_label' => 'sometimes|string', - 'slug' => 'nullable|string', - 'meeting_room_booking_start_time' => 'nullable|date_format:U', - 'meeting_room_booking_end_time' => 'nullable|required_with:meeting_room_booking_start_time|date_format:U|after_or_equal:meeting_room_booking_start_time', + 'schedule_start_date' => 'nullable|date_format:U|after_or_equal:start_date|before_or_equal:end_date', + 'active' => 'sometimes|boolean', + 'dates_label' => 'sometimes|string', + 'time_zone_id' => 'sometimes|timezone', + 'available_on_api' => 'sometimes|boolean', + 'calendar_sync_name' => 'sometimes|string|max:255', + 'calendar_sync_desc' => 'sometimes|string', + 'link' => 'sometimes|url', + 'registration_link' => 'sometimes|url', + 'max_submission_allowed_per_user' => 'sometimes|integer|min:1', + 'secondary_registration_link' => 'sometimes|url', + 'secondary_registration_label' => 'sometimes|string', + 'slug' => 'required|string', + 'meeting_room_booking_start_time' => 'nullable|date_format:U', + 'meeting_room_booking_end_time' => 'nullable|required_with:meeting_room_booking_start_time|date_format:U|after_or_equal:meeting_room_booking_start_time', 'meeting_room_booking_slot_length' => 'nullable|integer', 'meeting_room_booking_max_allowed' => 'nullable|integer|min:1', - 'api_feed_type' => sprintf('nullable|in:%s',implode(',', Summit::$valid_feed_types)), - 'api_feed_url' => 'nullable|string|url|required_with:api_feed_type', - 'api_feed_key' => 'nullable|string|required_with:api_feed_type', - 'begin_allow_booking_date' => 'nullable|date_format:U', - 'end_allow_booking_date' => 'nullable|required_with:begin_allow_booking_date|date_format:U|after_or_equal:begin_allow_booking_date', + 'api_feed_type' => sprintf('nullable|in:%s', implode(',', ISummitExternalScheduleFeedType::ValidFeedTypes)), + 'api_feed_url' => 'nullable|string|url|required_with:api_feed_type', + 'api_feed_key' => 'nullable|string|required_with:api_feed_type', + 'begin_allow_booking_date' => 'nullable|date_format:U', + 'end_allow_booking_date' => 'nullable|required_with:begin_allow_booking_date|date_format:U|after_or_equal:begin_allow_booking_date', + 'reassign_ticket_till_date' => 'nullable|date_format:U', + 'registration_disclaimer_content' => 'nullable|string', + 'registration_disclaimer_mandatory' => 'nullable|boolean', + 'registration_reminder_email_days_interval' => 'nullable|integer|min:1', + 'external_summit_id' => 'nullable|string', + 'external_registration_feed_type' => sprintf('nullable|in:%s', implode(',', ISummitExternalRegistrationFeedType::ValidFeedTypes)), + 'external_registration_feed_api_key' => 'nullable|string|required_with:external_registration_feed_type', // schedule - 'schedule_default_page_url' => 'nullable|url', - 'schedule_default_event_detail_url' => 'nullable|url', - 'schedule_og_site_name' => 'nullable|string', - 'schedule_og_image_url' => 'nullable|url', - 'schedule_og_image_secure_url' => 'nullable|url', - 'schedule_og_image_width' => 'nullable|integer', - 'schedule_og_image_height' => 'nullable|integer', - 'schedule_facebook_app_id' => 'nullable|string', - 'schedule_ios_app_name' => 'nullable|string', - 'schedule_ios_app_store_id' => 'nullable|string', - 'schedule_ios_app_custom_schema' => 'nullable|string', - 'schedule_android_app_name' => 'nullable|string', - 'schedule_android_app_package' => 'nullable|string', - 'schedule_android_custom_schema' => 'nullable|string', - 'schedule_twitter_app_name' => 'nullable|string', - 'schedule_twitter_text' => 'nullable|string', + 'schedule_default_page_url' => 'nullable|url', + 'schedule_default_event_detail_url' => 'nullable|url', + 'schedule_og_site_name' => 'nullable|string', + 'schedule_og_image_url' => 'nullable|url', + 'schedule_og_image_secure_url' => 'nullable|url', + 'schedule_og_image_width' => 'nullable|integer', + 'schedule_og_image_height' => 'nullable|integer', + 'schedule_facebook_app_id' => 'nullable|string', + 'schedule_ios_app_name' => 'nullable|string', + 'schedule_ios_app_store_id' => 'nullable|string', + 'schedule_ios_app_custom_schema' => 'nullable|string', + 'schedule_android_app_name' => 'nullable|string', + 'schedule_android_app_package' => 'nullable|string', + 'schedule_android_custom_schema' => 'nullable|string', + 'schedule_twitter_app_name' => 'nullable|string', + 'schedule_twitter_text' => 'nullable|string', + 'default_page_url' => 'nullable|url', + 'speaker_confirmation_default_page_url' => 'nullable|url', + 'virtual_site_url' => 'nullable|url', + 'marketing_site_url' => 'nullable|url', + 'virtual_site_oauth2_client_id' => 'nullable|string', + 'marketing_site_oauth2_client_id' => 'nullable|string', + 'support_email' => 'nullable|email', ]; } return [ - 'name' => 'required|string|max:50', - 'start_date' => 'required|date_format:U', - 'end_date' => 'required_with:start_date|date_format:U|after_or_equal:start_date', - 'registration_begin_date' => 'nullable|date_format:U', - 'registration_end_date' => 'nullable|required_with:registration_begin_date|date_format:U|after_or_equal:registration_begin_date', - 'start_showing_venues_date' => 'nullable|date_format:U|before_or_equal:start_date', - 'schedule_start_date' => 'nullable|date_format:U|after_or_equal:start_date|before_or_equal:end_date', - 'active' => 'sometimes|boolean', - 'dates_label' => 'sometimes|string', - 'time_zone_id' => 'required|timezone', - 'external_summit_id' => 'nullable|string', - 'available_on_api' => 'sometimes|boolean', - 'calendar_sync_name' => 'sometimes|string|max:255', - 'calendar_sync_desc' => 'sometimes|string', - 'link' => 'sometimes|url', - 'registration_link' => 'sometimes|url', - 'max_submission_allowed_per_user' => 'sometimes|integer|min:1', - 'secondary_registration_link' => 'sometimes|url', - 'secondary_registration_label' => 'sometimes|string', - 'slug' => 'nullable|string', - 'meeting_room_booking_start_time' => 'nullable|date_format:U', - 'meeting_room_booking_end_time' => 'nullable|required_with:meeting_room_booking_start_time|date_format:U|after_or_equal:meeting_room_booking_start_time', - 'meeting_room_booking_slot_length' => 'nullable|integer', - 'meeting_room_booking_max_allowed' => 'nullable|integer|min:1', - 'api_feed_type' => sprintf('nullable|in:%s',implode(',', Summit::$valid_feed_types)), - 'api_feed_url' => 'nullable|string|url|required_with:api_feed_type', - 'api_feed_key' => 'nullable|string|required_with:api_feed_type', - 'begin_allow_booking_date' => 'nullable|date_format:U', - 'end_allow_booking_date' => 'nullable|required_with:begin_allow_booking_date|date_format:U|after_or_equal:begin_allow_booking_date', + 'name' => 'required|string|max:50', + 'start_date' => 'required|date_format:U', + 'end_date' => 'required_with:start_date|date_format:U|after_or_equal:start_date', + 'registration_begin_date' => 'nullable|date_format:U', + 'registration_end_date' => 'nullable|required_with:registration_begin_date|date_format:U|after_or_equal:registration_begin_date', + 'start_showing_venues_date' => 'nullable|date_format:U|before_or_equal:start_date', + 'schedule_start_date' => 'nullable|date_format:U|after_or_equal:start_date|before_or_equal:end_date', + 'active' => 'sometimes|boolean', + 'dates_label' => 'sometimes|string', + 'time_zone_id' => 'required|timezone', + 'available_on_api' => 'sometimes|boolean', + 'calendar_sync_name' => 'sometimes|string|max:255', + 'calendar_sync_desc' => 'sometimes|string', + 'link' => 'sometimes|url', + 'registration_link' => 'sometimes|url', + 'max_submission_allowed_per_user' => 'sometimes|integer|min:1', + 'secondary_registration_link' => 'sometimes|url', + 'secondary_registration_label' => 'sometimes|string', + 'slug' => 'required|string', + 'meeting_room_booking_start_time' => 'nullable|date_format:U', + 'meeting_room_booking_end_time' => 'nullable|required_with:meeting_room_booking_start_time|date_format:U|after_or_equal:meeting_room_booking_start_time', + 'meeting_room_booking_slot_length' => 'nullable|integer', + 'meeting_room_booking_max_allowed' => 'nullable|integer|min:1', + 'api_feed_type' => sprintf('nullable|in:%s', implode(',', ISummitExternalScheduleFeedType::ValidFeedTypes)), + 'api_feed_url' => 'nullable|string|url|required_with:api_feed_type', + 'api_feed_key' => 'nullable|string|required_with:api_feed_type', + 'begin_allow_booking_date' => 'nullable|date_format:U', + 'end_allow_booking_date' => 'nullable|required_with:begin_allow_booking_date|date_format:U|after_or_equal:begin_allow_booking_date', + 'reassign_ticket_till_date' => 'nullable|date_format:U', + 'registration_disclaimer_content' => 'nullable|string', + 'registration_disclaimer_mandatory' => 'nullable|boolean', + 'registration_reminder_email_days_interval' => 'nullable|integer|min:1', + 'external_summit_id' => 'nullable|string', + 'external_registration_feed_type' => sprintf('nullable|in:%s', implode(',', ISummitExternalRegistrationFeedType::ValidFeedTypes)), + 'external_registration_feed_api_key' => 'nullable|string|required_with:external_registration_feed_type', // schedule - 'schedule_default_page_url' => 'nullable|url', - 'schedule_default_event_detail_url' => 'nullable|url', - 'schedule_og_site_name' => 'nullable|string', - 'schedule_og_image_url' => 'nullable|url', - 'schedule_og_image_secure_url' => 'nullable|url', - 'schedule_og_image_width' => 'nullable|integer', - 'schedule_og_image_height' => 'nullable|integer', - 'schedule_facebook_app_id' => 'nullable|string', - 'schedule_ios_app_name' => 'nullable|string', - 'schedule_ios_app_store_id' => 'nullable|string', - 'schedule_ios_app_custom_schema' => 'nullable|string', - 'schedule_android_app_name' => 'nullable|string', - 'schedule_android_app_package' => 'nullable|string', - 'schedule_android_custom_schema' => 'nullable|string', - 'schedule_twitter_app_name' => 'nullable|string', - 'schedule_twitter_text' => 'nullable|string', + 'schedule_default_page_url' => 'nullable|url', + 'schedule_default_event_detail_url' => 'nullable|url', + 'schedule_og_site_name' => 'nullable|string', + 'schedule_og_image_url' => 'nullable|url', + 'schedule_og_image_secure_url' => 'nullable|url', + 'schedule_og_image_width' => 'nullable|integer', + 'schedule_og_image_height' => 'nullable|integer', + 'schedule_facebook_app_id' => 'nullable|string', + 'schedule_ios_app_name' => 'nullable|string', + 'schedule_ios_app_store_id' => 'nullable|string', + 'schedule_ios_app_custom_schema' => 'nullable|string', + 'schedule_android_app_name' => 'nullable|string', + 'schedule_android_app_package' => 'nullable|string', + 'schedule_android_custom_schema' => 'nullable|string', + 'schedule_twitter_app_name' => 'nullable|string', + 'schedule_twitter_text' => 'nullable|string', + 'default_page_url' => 'nullable|url', + 'speaker_confirmation_default_page_url' => 'nullable|url', + 'virtual_site_url' => 'nullable|url', + 'marketing_site_url' => 'nullable|url', + 'virtual_site_oauth2_client_id' => 'nullable|string', + 'marketing_site_oauth2_client_id' => 'nullable|string', + 'support_email' => 'nullable|email', ]; } } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2PaymentGatewayProfileApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2PaymentGatewayProfileApiController.php new file mode 100644 index 00000000..22056d93 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2PaymentGatewayProfileApiController.php @@ -0,0 +1,171 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + use GetAllBySummit; + + use GetSummitChildElementById; + + use AddSummitChildElement; + + use UpdateSummitChildElement; + + use DeleteSummitChildElement; + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @inheritDoc + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->addPaymentProfile($summit, $payload); + } + + /** + * @inheritDoc + */ + function getAddValidationRules(array $payload): array + { + return PaymentGatewayProfileValidationRulesFactory::build($payload, false); + } + + /** + * @inheritDoc + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deletePaymentProfile($summit, $child_id); + } + + /** + * @inheritDoc + */ + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getPaymentProfileById($child_id); + } + + /** + * @inheritDoc + */ + function getUpdateValidationRules(array $payload): array + { + return PaymentGatewayProfileValidationRulesFactory::build($payload, true); + } + + /** + * @inheritDoc + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updatePaymentProfile($summit, $child_id, $payload); + } + + /** + * @return array + */ + protected function getFilterRules():array + { + return [ + 'application_type' => ['=@', '=='], + 'active' => ['=='], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'application_type' => 'sometimes|required|string', + 'active' => 'sometimes|required|boolean', + ]; + } + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'application_type', + ]; + } + + protected function serializerType():string{ + return SerializerRegistry::SerializerType_Private; + } + + protected function addSerializerType():string{ + return SerializerRegistry::SerializerType_Private; + } + + protected function updateSerializerType():string{ + return SerializerRegistry::SerializerType_Private; + } + + public function getChildSerializer(){ + return SerializerRegistry::SerializerType_Private; + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2PresentationApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2PresentationApiController.php index 10ab8e32..eda225e3 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2PresentationApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2PresentationApiController.php @@ -11,14 +11,12 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - use App\Http\Utils\FileTypes; use App\Http\Utils\MultipartFormDataCleaner; use libs\utils\HTMLCleaner; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; use models\main\IMemberRepository; -use models\main\Member; use models\oauth2\IResourceServerContext; use models\summit\ISummitEventRepository; use models\summit\ISummitRepository; @@ -32,7 +30,6 @@ use models\summit\Presentation; use models\utils\IEntity; use ModelSerializers\SerializerRegistry; use services\model\IPresentationService; -use utils\ParseMultiPartFormDataInputStream; /** * Class OAuth2PresentationApiController * @package App\Http\Controllers @@ -131,7 +128,7 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController if (is_null($presentation)) return $this->error404(); - $video = $presentation-getVideoBy($video_id); + $video = $presentation->getVideoBy($video_id); if (is_null($video)) return $this->error404(); @@ -350,7 +347,7 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController $presentation = $this->presentation_service->submitPresentation($summit, $current_member, HTMLCleaner::cleanData($data, $fields)); - return $this->created(SerializerRegistry::getInstance()->getSerializer($presentation)->serialize()); + return $this->created(SerializerRegistry::getInstance()->getSerializer($presentation)->serialize(Request::input('expand', ''))); } catch (EntityNotFoundException $ex1) { @@ -426,7 +423,7 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController HTMLCleaner::cleanData($data, $fields) ); - return $this->updated(SerializerRegistry::getInstance()->getSerializer($presentation)->serialize()); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($presentation)->serialize(Request::input('expand', ''))); } catch (EntityNotFoundException $ex1) { @@ -466,7 +463,7 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController $current_member ); - return $this->updated(SerializerRegistry::getInstance()->getSerializer($presentation)->serialize()); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($presentation)->serialize(Request::input('expand', ''))); } catch (EntityNotFoundException $ex1) { @@ -532,7 +529,7 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController if (is_null($presentation)) return $this->error404(); - $slides = $presentation-getSlides(); + $slides = $presentation->getSlides(); $items = []; foreach($slides as $i) @@ -573,7 +570,7 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController if (is_null($presentation)) return $this->error404(); - $slide = $presentation-getSlideBy($slide_id); + $slide = $presentation->getSlideBy($slide_id); if (is_null($slide)) return $this->error404(); @@ -794,7 +791,7 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController if (is_null($presentation)) return $this->error404(); - $links = $presentation-getLinks(); + $links = $presentation->getLinks(); $items = []; foreach($links as $i) @@ -835,7 +832,7 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController if (is_null($presentation)) return $this->error404(); - $link = $presentation-getLinkBy($link_id); + $link = $presentation->getLinkBy($link_id); if (is_null($link)) return $this->error404(); @@ -1000,4 +997,260 @@ final class OAuth2PresentationApiController extends OAuth2ProtectedController return $this->error500($ex); } } + + // MediaUploads + + /** + * @param $summit_id + * @param $presentation_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getPresentationMediaUploads($summit_id, $presentation_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $presentation = $this->presentation_repository->getById($presentation_id); + + if (is_null($presentation) || !$presentation instanceof Presentation) return $this->error404(); + + $mediaUploads = $presentation->getMediaUploads(); + + $items = []; + foreach($mediaUploads as $i) + { + if($i instanceof IEntity) + { + $i = SerializerRegistry::getInstance()->getSerializer($i)->serialize(); + } + $items[] = $i; + } + + return $this->ok($items); + + } 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 $summit_id + * @param $presentation_id + * @param $media_upload_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getPresentationMediaUpload($summit_id, $presentation_id, $media_upload_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $presentation = $this->presentation_repository->getById($presentation_id); + + if (is_null($presentation) || !$presentation instanceof Presentation) return $this->error404(); + + $mediaUpload = $presentation->getMediaUploadBy($media_upload_id); + + if (is_null($mediaUpload)) return $this->error404(); + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($mediaUpload)->serialize()); + + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param LaravelRequest $request + * @param $summit_id + * @param $presentation_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addPresentationMediaUpload(LaravelRequest $request, $summit_id, $presentation_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + $serializeType = SerializerRegistry::SerializerType_Private; + if(!$current_member->isAdmin()){ + $serializeType = SerializerRegistry::SerializerType_Public; + // check if we could edit presentation + $presentation = $summit->getEvent($presentation_id); + if(is_null($presentation) || !$presentation instanceof Presentation) + return $this->error404(); + if(!$current_member->hasSpeaker() || !$presentation->canEdit($current_member->getSpeaker())) + return $this->error403(); + } + + $data = $request->all(); + + $rules = [ + 'media_upload_type_id' => 'required|integer', + ]; + + // Creates a Validator instance and validates the data. + $validation = Validator::make($data, $rules); + + if ($validation->fails()) { + $ex = new ValidationException; + $ex->setMessages($validation->messages()->toArray()); + throw $ex; + } + + $mediaUpload = $this->presentation_service->addMediaUploadTo + ( + $request, + $summit, + intval($presentation_id), + $data + ); + + $fields = Request::input('fields', ''); + $relations = Request::input('relations', ''); + + $relations = !empty($relations) ? explode(',', $relations) : []; + $fields = !empty($fields) ? explode(',', $fields) : []; + + return $this->created(SerializerRegistry::getInstance()->getSerializer + ( + $mediaUpload, $serializeType) + ->serialize + ( + Request::input('expand', ''), + $fields, + $relations + ) + ); + } + catch (EntityNotFoundException $ex1) + { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) + { + Log::warning($ex2); + return $this->error412($ex2->getMessages()); + } + catch (Exception $ex) + { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param LaravelRequest $request + * @param $summit_id + * @param $presentation_id + * @param $media_upload_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function updatePresentationMediaUpload(LaravelRequest $request, $summit_id, $presentation_id, $media_upload_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + $serializeType = SerializerRegistry::SerializerType_Private; + + if(!$current_member->isAdmin()){ + $serializeType = SerializerRegistry::SerializerType_Public; + // check if we could edit presentation + $presentation = $summit->getEvent($presentation_id); + if(is_null($presentation) || !$presentation instanceof Presentation) + return $this->error404(); + if(!$current_member->hasSpeaker() || !$presentation->canEdit($current_member->getSpeaker())) + return $this->error403(); + } + + + $mediaUpload = $this->presentation_service->updateMediaUploadFrom + ( + $request, + $summit, + intval($presentation_id), + intval($media_upload_id) + ); + + $fields = Request::input('fields', ''); + $relations = Request::input('relations', ''); + + $relations = !empty($relations) ? explode(',', $relations) : []; + $fields = !empty($fields) ? explode(',', $fields) : []; + + return $this->updated(SerializerRegistry::getInstance()->getSerializer + ( + $mediaUpload, $serializeType) + ->serialize + ( + Request::input('expand', ''), + $fields, + $relations + ) + ); + } + catch (EntityNotFoundException $ex1) + { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) + { + Log::warning($ex2); + return $this->error412($ex2->getMessages()); + } + catch (Exception $ex) + { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $presentation_id + * @param $media_upload_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function deletePresentationMediaUpload($summit_id, $presentation_id, $media_upload_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $this->presentation_service->deleteMediaUpload($summit, intval($presentation_id), intval($media_upload_id)); + + return $this->deleted(); + } + catch (EntityNotFoundException $ex1) + { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) + { + Log::warning($ex2); + return $this->error412($ex2->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/OAuth2SponsorshipTypeApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SponsorshipTypeApiController.php new file mode 100644 index 00000000..3ccb4303 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SponsorshipTypeApiController.php @@ -0,0 +1,225 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + use GetAll; + + /** + * @return array + */ + protected function getFilterRules(): array + { + return [ + 'name' => ['==', '=@'], + 'label' => ['==', '=@'], + 'size' => ['==', '=@'], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules(): array + { + return [ + 'name' => 'sometimes|required|string', + 'label' => 'sometimes|required|string', + 'size' => 'sometimes|required|string', + ]; + } + + /** + * @return array + */ + protected function getOrderRules(): array + { + return [ + 'id', + 'name', + 'order', + 'label', + 'size', + ]; + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function add() + { + try { + if (!Request::isJson()) return $this->error400(); + $data = Input::json(); + $payload = $data->all(); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, SponsorshipTypeValidationRulesFactory::build($payload)); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $sponsorship_type = $this->service->addSponsorShipType($payload); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($sponsorship_type)->serialize()); + } catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } catch (EntityNotFoundException $ex2) { + Log::warning($ex2); + return $this->error404(array('message' => $ex2->getMessage())); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function get($id) + { + try { + $sponsorship_type = $this->repository->getById($id); + if(is_null($sponsorship_type)) + return $this->error404(); + return $this->ok(SerializerRegistry::getInstance()->getSerializer($sponsorship_type)->serialize( 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 $id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function update($id) + { + try { + if (!Request::isJson()) return $this->error400(); + $data = Input::json(); + $payload = $data->all(); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, SponsorshipTypeValidationRulesFactory::build($payload, true)); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $sponsorship_type = $this->service->updateSponsorShipType($id, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($sponsorship_type)->serialize()); + } catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } catch (EntityNotFoundException $ex2) { + Log::warning($ex2); + return $this->error404(array('message' => $ex2->getMessage())); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function delete($id) + { + try { + $this->service->deleteSponsorShipType($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/OAuth2SummitAccessLevelTypeApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitAccessLevelTypeApiController.php new file mode 100644 index 00000000..30188607 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitAccessLevelTypeApiController.php @@ -0,0 +1,181 @@ + ['=@', '=='], + 'is_default' => [ '=='], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'name' => 'sometimes|required|string', + 'is_default' => 'sometimes|required|boolean', + ]; + } + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'name', + ]; + } + + public function __construct + ( + ISummitAccessLevelTypeRepository $repository, + ISummitRepository $summit_repository, + ISummitAccessLevelTypeService $service, + IResourceServerContext $resource_server_context + ) + { + parent::__construct($resource_server_context); + $this->repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @return IResourceServerContext + */ + protected function getResourceServerContext(): IResourceServerContext + { + return $this->resource_server_context; + } + + /** + * @return IBaseRepository + */ + protected function getRepository(): IBaseRepository + { + return $this->repository; + } + + /** + * @param array $payload + * @return array + */ + protected function getAddValidationRules(array $payload): array + { + return AccessLevelTypeValidationRulesFactory::build($payload); + } + + /** + * @param Summit $summit + * @param array $payload + * @return IEntity + * @throws EntityNotFoundException + * @throws ValidationException + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->addAccessLevelType($summit, $payload); + } + + /** + * @param Summit $summit + * @param $child_id + * @return IEntity|null + */ + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getBadgeAccessLevelTypeById($child_id); + } + + /** + * @param array $payload + * @return array + */ + function getUpdateValidationRules(array $payload): array + { + return AccessLevelTypeValidationRulesFactory::build($payload, true); + } + + /** + * @param Summit $summit + * @param int $child_id + * @param array $payload + * @return IEntity + * @throws EntityNotFoundException + * @throws ValidationException + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updateAccessLevelType($summit, $child_id, $payload); + } + + /** + * @param Summit $summit + * @param $child_id + * @throws EntityNotFoundException + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deleteAccessLevelType($summit, $child_id); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitApiController.php index 3998d8e4..fd921964 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitApiController.php @@ -11,7 +11,10 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\Http\Exceptions\HTTP403ForbiddenException; +use App\Models\Foundation\Main\IGroup; +use App\Models\Foundation\Summit\Registration\IBuildDefaultPaymentGatewayProfileStrategy; use Exception; use Illuminate\Support\Facades\Input; use Illuminate\Support\Facades\Log; @@ -19,6 +22,7 @@ use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\Validator; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; +use models\main\SummitAdministratorPermissionGroup; use models\oauth2\IResourceServerContext; use models\summit\ConfirmationExternalOrderRequest; use models\summit\IEventFeedbackRepository; @@ -28,8 +32,13 @@ use models\summit\ISummitRepository; use ModelSerializers\ISerializerTypeSelector; use ModelSerializers\SerializerRegistry; use services\model\ISummitService; -use utils\PagingResponse; +use utils\Filter; +use utils\FilterElement; +use utils\Order; +use utils\OrderElement; use Illuminate\Http\Request as LaravelRequest; + + /** * Class OAuth2SummitApiController * @package App\Http\Controllers @@ -37,6 +46,11 @@ use Illuminate\Http\Request as LaravelRequest; final class OAuth2SummitApiController extends OAuth2ProtectedController { + /** + * @var IBuildDefaultPaymentGatewayProfileStrategy + */ + private $build_default_payment_gateway_profile_strategy; + /** * @var ISummitService */ @@ -70,6 +84,7 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController * @param IEventFeedbackRepository $event_feedback_repository * @param ISummitService $summit_service * @param ISerializerTypeSelector $serializer_type_selector + * @param IBuildDefaultPaymentGatewayProfileStrategy $build_default_payment_gateway_profile_strategy * @param IResourceServerContext $resource_server_context */ public function __construct @@ -80,89 +95,185 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController IEventFeedbackRepository $event_feedback_repository, ISummitService $summit_service, ISerializerTypeSelector $serializer_type_selector, + IBuildDefaultPaymentGatewayProfileStrategy $build_default_payment_gateway_profile_strategy, IResourceServerContext $resource_server_context - ) { + ) + { parent::__construct($resource_server_context); - $this->repository = $summit_repository; - $this->speaker_repository = $speaker_repository; - $this->event_repository = $event_repository; + $this->repository = $summit_repository; + $this->speaker_repository = $speaker_repository; + $this->event_repository = $event_repository; $this->event_feedback_repository = $event_feedback_repository; - $this->serializer_type_selector = $serializer_type_selector; - $this->summit_service = $summit_service; + $this->serializer_type_selector = $serializer_type_selector; + $this->build_default_payment_gateway_profile_strategy = $build_default_payment_gateway_profile_strategy; + $this->summit_service = $summit_service; } + use ParametrizedGetAll; + + /** * @return mixed */ public function getSummits() { - try { + $current_member = $this->resource_server_context->getCurrentUser(); - $expand = Request::input('expand', ''); - $fields = Request::input('fields', ''); - $relations = Request::input('relations', ''); - - $relations = !empty($relations) ? explode(',', $relations) : []; - $fields = !empty($fields) ? explode(',', $fields) : []; - - $summits = []; - - foreach($this->repository->getAvailables() as $summit){ - $summits[] = SerializerRegistry::getInstance()->getSerializer($summit)->serialize($expand, $fields, $relations); - } - - $response = new PagingResponse - ( - count($summits), - count($summits), - 1, - 1, - $summits - ); - - return $this->ok($response->toArray()); - } - catch (Exception $ex) { - Log::error($ex); - return $this->error500($ex); + if (!is_null($current_member) && !$current_member->isAdmin() && $current_member->isSummitAdmin() && !$current_member->hasAllowedSummits()) { + return $this->error403(['message' => sprintf("Member %s has not permission for any Summit", $current_member->getId())]); } + + return $this->_getAll( + function () { + return [ + 'name' => ['=@', '=='], + 'start_date' => ['==', '<', '>', '<=', '>='], + 'end_date' => ['==', '<', '>', '<=', '>='], + 'registration_begin_date' => ['==', '<', '>', '<=', '>='], + 'registration_end_date' => ['==', '<', '>', '<=', '>='], + 'ticket_types_count' => ['==', '<', '>', '<=', '>=', '<>'], + ]; + }, + function () { + return [ + 'name' => 'sometimes|required|string', + 'start_date' => 'sometimes|required|date_format:U', + 'end_date' => 'sometimes|required_with:start_date|date_format:U|after:start_date', + 'registration_begin_date' => 'sometimes|required|date_format:U', + 'registration_end_date' => 'sometimes|required_with:start_date|date_format:U|after:registration_begin_date', + 'ticket_types_count' => 'sometimes|required|integer' + ]; + }, + function () { + return [ + 'id', + 'name', + 'begin_date', + 'registration_begin_date' + ]; + }, + function ($filter) use ($current_member) { + if ($filter instanceof Filter) { + $filter->addFilterCondition(FilterElement::makeEqual('available_on_api', '1')); + if (!is_null($current_member) && !$current_member->isAdmin() && $current_member->isSummitAdmin()) { + // filter only the ones that we are allowed to see + $filter->addFilterCondition + ( + FilterElement::makeEqual + ( + 'summit_id', + $current_member->getAllAllowedSummitsIds(), + "OR" + + ) + ); + + } + } + return $filter; + }, + function () { + return $this->serializer_type_selector->getSerializerType(); + }, + function () { + return new Order([ + OrderElement::buildAscFor("begin_date"), + ]); + }, + function () { + return PHP_INT_MAX; + }, + null, + [ + 'build_default_payment_gateway_profile_strategy' => $this->build_default_payment_gateway_profile_strategy + ] + ); } /** * @return mixed */ - public function getAllSummits(){ - try { + public function getAllSummits() + { - $expand = Request::input('expand', ''); - $fields = Request::input('fields', ''); - $relations = Request::input('relations', ''); + $current_member = $this->resource_server_context->getCurrentUser(); - $relations = !empty($relations) ? explode(',', $relations) : []; - $fields = !empty($fields) ? explode(',', $fields) : []; + if (!is_null($current_member) && !$current_member->isAdmin() && $current_member->isSummitAdmin() && !$current_member->hasAllowedSummits()) { + return $this->error403(['message' => sprintf("Member %s has not permission for any Summit", $current_member->getId())]); + } - $summits = []; + return $this->_getAll( + function () { + return [ + 'name' => ['=@', '=='], + 'start_date' => ['==', '<', '>', '=>', '>='], + 'end_date' => ['==', '<', '>', '=>', '>='], + 'registration_begin_date' => ['==', '<', '>', '=>', '>='], + 'registration_end_date' => ['==', '<', '>', '=>', '>='], + 'ticket_types_count' => ['==', '<', '>', '=>', '>=', '<>'], + 'submission_begin_date' => ['==', '<', '>', '=>', '>='], + 'submission_end_date' => ['==', '<', '>', '=>', '>='], + 'selection_plan_enabled' => ['=='], + ]; + }, + function () { + return [ + 'name' => 'sometimes|required|string', + 'start_date' => 'sometimes|required|date_format:U', + 'end_date' => 'sometimes|required_with:start_date|date_format:U|after:start_date', + 'registration_begin_date' => 'sometimes|required|date_format:U', + 'registration_end_date' => 'sometimes|required_with:start_date|date_format:U|after:registration_begin_date', + 'ticket_types_count' => 'sometimes|required|integer', + 'submission_begin_date' => 'sometimes|required|date_format:U', + 'submission_end_date' => 'sometimes|required_with:submission_begin_date|date_format:U', + 'selection_plan_enabled' => 'sometimes|required|boolean', + ]; + }, + function () { + return [ + 'id', + 'name', + 'start_date', + 'registration_begin_date' + ]; + }, + function ($filter) use ($current_member) { + if ($filter instanceof Filter) { + if (!is_null($current_member) && !$current_member->isAdmin() && $current_member->isSummitAdmin()) { + // filter only the ones that we are allowed to see + $filter->addFilterCondition + ( + FilterElement::makeEqual + ( + 'summit_id', + $current_member->getAllAllowedSummitsIds(), + "OR" - foreach($this->repository->getAllOrderedByBeginDate()as $summit){ - $summits[] = SerializerRegistry::getInstance()->getSerializer($summit)->serialize($expand, $fields, $relations); + ) + ); + + } + } + return $filter; + }, + function () { + return $this->serializer_type_selector->getSerializerType(); } - - $response = new PagingResponse - ( - count($summits), - count($summits), - 1, - 1, - $summits - ); - - return $this->ok($response->toArray()); - } - catch (Exception $ex) { - Log::error($ex); - return $this->error500($ex); - } + , + function () { + return new Order([ + OrderElement::buildAscFor("begin_date"), + ]); + }, + function () { + return PHP_INT_MAX; + }, + null, + [ + 'build_default_payment_gateway_profile_strategy' => $this->build_default_payment_gateway_profile_strategy + ] + ); } /** @@ -175,22 +286,29 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController try { $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); + $current_member = $this->resource_server_context->getCurrentUser(); + if (!is_null($current_member) && !$current_member->isAdmin() && !$current_member->hasPermissionForOnGroup($summit, IGroup::SummitAdministrators)) + return $this->error403(['message' => sprintf("Member %s has not permission for this Summit", $current_member->getId())]); $serializer_type = $this->serializer_type_selector->getSerializerType(); - return $this->ok(SerializerRegistry::getInstance()->getSerializer($summit, $serializer_type)->serialize($expand)); - } - catch(HTTP403ForbiddenException $ex1){ + return $this->ok + ( + SerializerRegistry::getInstance() + ->getSerializer($summit, $serializer_type) + ->serialize($expand, [], [], [ + 'build_default_payment_gateway_profile_strategy' => $this->build_default_payment_gateway_profile_strategy + ]) + ); + } catch (HTTP403ForbiddenException $ex1) { Log::warning($ex1); return $this->error403(); - } - catch (Exception $ex) { + } catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } } - /** - * @return mixed + * @return \Illuminate\Http\JsonResponse|mixed */ public function getAllCurrentSummit() { @@ -199,36 +317,62 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController try { $summit = $this->repository->getCurrent(); if (is_null($summit)) return $this->error404(); + $current_member = $this->resource_server_context->getCurrentUser(); + if (!is_null($current_member) && !$current_member->isAdmin() && !$current_member->hasPermissionForOnGroup($summit, IGroup::SummitAdministrators)) + return $this->error403(['message' => sprintf("Member %s has not permission for this Summit", $current_member->getId())]); $serializer_type = $this->serializer_type_selector->getSerializerType(); - return $this->ok(SerializerRegistry::getInstance()->getSerializer($summit, $serializer_type)->serialize($expand)); - } - catch(HTTP403ForbiddenException $ex1){ + return $this->ok + ( + SerializerRegistry::getInstance() + ->getSerializer($summit, $serializer_type) + ->serialize($expand, [], [], [ + 'build_default_payment_gateway_profile_strategy' => $this->build_default_payment_gateway_profile_strategy + ]) + ); + } catch (HTTP403ForbiddenException $ex1) { Log::warning($ex1); return $this->error403(); - } - catch (Exception $ex) { + } catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } } - public function getAllSummitByIdOrSlug($id){ + /** + * @param $id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getAllSummitByIdOrSlug($id) + { $expand = Request::input('expand', ''); try { $summit = $this->repository->getById(intval($id)); - if(is_null($summit)) + if (is_null($summit)) $summit = $this->repository->getBySlug(trim($id)); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (!is_null($current_member) && !$current_member->isAdmin() && !$current_member->hasPermissionForOnGroup($summit, IGroup::SummitAdministrators)) + return $this->error403(['message' => sprintf("Member %s has not permission for this Summit", $current_member->getId())]); + $serializer_type = $this->serializer_type_selector->getSerializerType(); - return $this->ok(SerializerRegistry::getInstance()->getSerializer($summit, $serializer_type)->serialize($expand)); - } - catch(HTTP403ForbiddenException $ex1){ + + return $this->ok + ( + SerializerRegistry::getInstance() + ->getSerializer($summit, $serializer_type) + ->serialize($expand, [], [], + [ + 'build_default_payment_gateway_profile_strategy' => $this->build_default_payment_gateway_profile_strategy + ]) + ); + } catch (HTTP403ForbiddenException $ex1) { Log::warning($ex1); return $this->error403(); - } - catch (Exception $ex) { + } catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } @@ -237,15 +381,19 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController /** * @return mixed */ - public function addSummit(){ + public function addSummit() + { try { - if(!Request::isJson()) return $this->error400(); + if (!Request::isJson()) return $this->error400(); $payload = Input::json()->all(); $rules = SummitValidationRulesFactory::build($payload); // Creates a Validator instance and validates the data. - $validation = Validator::make($payload, $rules); + $validation = Validator::make($payload, $rules, $messages = [ + 'slug.required' => 'A Slug is required.', + 'schedule_start_date.before_or_equal' => 'Show on schedule page needs to be after the start of the Show And Before of the Show End.', + ]); if ($validation->fails()) { $messages = $validation->messages()->toArray(); @@ -259,17 +407,13 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController $summit = $this->summit_service->addSummit($payload); $serializer_type = $this->serializer_type_selector->getSerializerType(); return $this->created(SerializerRegistry::getInstance()->getSerializer($summit, $serializer_type)->serialize()); - } - catch (ValidationException $ex1) { + } catch (ValidationException $ex1) { Log::warning($ex1); return $this->error412([$ex1->getMessage()]); - } - catch(EntityNotFoundException $ex2) - { + } catch (EntityNotFoundException $ex2) { Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); - } - catch (Exception $ex) { + return $this->error404(['message' => $ex2->getMessage()]); + } catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } @@ -279,10 +423,11 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController * @param $summit_id * @return mixed */ - public function updateSummit($summit_id){ + public function updateSummit($summit_id) + { try { - if(!Request::isJson()) return $this->error400(); + if (!Request::isJson()) return $this->error400(); $payload = Input::json()->all(); $rules = SummitValidationRulesFactory::build($payload, true); @@ -298,20 +443,23 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController ); } + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (!is_null($current_member) && !$current_member->isAdmin() && !$current_member->hasPermissionForOnGroup($summit, IGroup::SummitAdministrators)) + return $this->error403(['message' => sprintf("Member %s has not permission for this Summit", $current_member->getId())]); + $summit = $this->summit_service->updateSummit($summit_id, $payload); $serializer_type = $this->serializer_type_selector->getSerializerType(); return $this->updated(SerializerRegistry::getInstance()->getSerializer($summit, $serializer_type)->serialize()); - } - catch (ValidationException $ex1) { + } catch (ValidationException $ex1) { Log::warning($ex1); return $this->error412([$ex1->getMessage()]); - } - catch(EntityNotFoundException $ex2) - { + } catch (EntityNotFoundException $ex2) { Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); - } - catch (Exception $ex) { + return $this->error404(['message' => $ex2->getMessage()]); + } catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } @@ -321,23 +469,20 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController * @param $summit_id * @return mixed */ - public function deleteSummit($summit_id){ + public function deleteSummit($summit_id) + { try { $this->summit_service->deleteSummit($summit_id); return $this->deleted(); - } - catch (ValidationException $ex1) { + } catch (ValidationException $ex1) { Log::warning($ex1); return $this->error412([$ex1->getMessage()]); - } - catch(EntityNotFoundException $ex2) - { + } catch (EntityNotFoundException $ex2) { Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); - } - catch (Exception $ex) { + return $this->error404(['message' => $ex2->getMessage()]); + } catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } @@ -354,40 +499,37 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $current_member = $this->resource_server_context->getCurrentUser(); - $current_member_id = is_null($current_member)? null : $current_member->getId(); + $current_member = $this->resource_server_context->getCurrentUser(); + $current_member_id = is_null($current_member) ? null : $current_member->getId(); $last_event_id = Request::input('last_event_id', null); - $from_date = Request::input('from_date', null); - $limit = Request::input('limit', 25); + $from_date = Request::input('from_date', null); + $limit = Request::input('limit', 25); $rules = [ 'last_event_id' => 'sometimes|required|integer', - 'from_date' => 'sometimes|required|integer', - 'limit' => 'sometimes|required|integer', + 'from_date' => 'sometimes|required|integer', + 'limit' => 'sometimes|required|integer', ]; $data = []; - if (!is_null($last_event_id)) - { + if (!is_null($last_event_id)) { $data['last_event_id'] = $last_event_id; } - if (!is_null($from_date)) - { + if (!is_null($from_date)) { $data['from_date'] = $from_date; } - if(!is_null($limit)){ + if (!is_null($limit)) { $data['limit'] = $limit; } // Creates a Validator instance and validates the data. $validation = Validator::make($data, $rules); - if ($validation->fails()) - { + if ($validation->fails()) { $messages = $validation->messages()->toArray(); return $this->error412 @@ -396,8 +538,7 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController ); } - if (!is_null($from_date)) - { + if (!is_null($from_date)) { $from_date = new \DateTime("@$from_date", new \DateTimeZone("UTC")); } @@ -421,9 +562,7 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController )*/ $list ); - } - catch (Exception $ex) - { + } catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } @@ -434,22 +573,20 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController * @param $external_order_id * @return mixed */ - public function getExternalOrder($summit_id, $external_order_id){ + public function getExternalOrder($summit_id, $external_order_id) + { try { $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); $order = $this->summit_service->getExternalOrder($summit, $external_order_id); return $this->ok($order); - } - catch (EntityNotFoundException $ex1) { + } catch (EntityNotFoundException $ex1) { Log::warning($ex1); return $this->error404(array('message' => $ex1->getMessage())); - } - catch (ValidationException $ex2) { + } catch (ValidationException $ex2) { Log::warning($ex2); return $this->error412($ex2->getMessages()); - } - catch (Exception $ex) { + } catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } @@ -461,7 +598,8 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController * @param $external_attendee_id * @return mixed */ - public function confirmExternalOrderAttendee($summit_id, $external_order_id, $external_attendee_id){ + public function confirmExternalOrderAttendee($summit_id, $external_order_id, $external_attendee_id) + { try { $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); @@ -480,31 +618,36 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController ); return $this->ok(SerializerRegistry::getInstance()->getSerializer($attendee)->serialize()); - } - catch (EntityNotFoundException $ex1) { + } catch (EntityNotFoundException $ex1) { Log::warning($ex1); return $this->error404(array('message' => $ex1->getMessage())); - } - catch (ValidationException $ex2) { + } catch (ValidationException $ex2) { Log::warning($ex2); return $this->error412($ex2->getMessages()); - } - catch (\HTTP401UnauthorizedException $ex3) { + } catch (\HTTP401UnauthorizedException $ex3) { Log::warning($ex3); return $this->error401(); - } - catch (Exception $ex) { + } catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } } + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->repository; + } + /** * @param LaravelRequest $request * @param $summit_id * @return \Illuminate\Http\JsonResponse|mixed */ - public function addSummitLogo(LaravelRequest $request, $summit_id){ + public function addSummitLogo(LaravelRequest $request, $summit_id) + { try { $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); @@ -515,6 +658,10 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController return $this->error412(array('file param not set!')); } + $current_member = $this->resource_server_context->getCurrentUser(); + if (!is_null($current_member) && !$current_member->isAdmin() && !$current_member->hasPermissionForOnGroup($summit, IGroup::SummitAdministrators)) + return $this->error403(['message' => sprintf("Member %s has not permission for this Summit", $current_member->getId())]); + $photo = $this->summit_service->addSummitLogo($summit_id, $file); return $this->created(SerializerRegistry::getInstance()->getSerializer($photo)->serialize()); @@ -538,12 +685,17 @@ final class OAuth2SummitApiController extends OAuth2ProtectedController * @param $summit_id * @return \Illuminate\Http\JsonResponse|mixed */ - public function deleteSummitLogo($summit_id){ + public function deleteSummitLogo($summit_id) + { try { $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); + $current_member = $this->resource_server_context->getCurrentUser(); + if (!is_null($current_member) && !$current_member->isAdmin() && !$current_member->hasPermissionForOnGroup($summit, IGroup::SummitAdministrators)) + return $this->error403(['message' => sprintf("Member %s has not permission for this Summit", $current_member->getId())]); + $this->summit_service->deleteSummitLogo($summit_id); return $this->deleted(); diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitAttendeesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitAttendeesApiController.php index 36fdb11f..1e89695a 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitAttendeesApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitAttendeesApiController.php @@ -12,21 +12,25 @@ * limitations under the License. **/ use App\Services\Model\IAttendeeService; +use App\Services\Model\ISummitOrderService; use Exception; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Request; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; use models\main\IMemberRepository; +use models\main\Member; use models\oauth2\IResourceServerContext; use models\summit\IEventFeedbackRepository; use models\summit\ISpeakerRepository; use models\summit\ISummitAttendeeRepository; use models\summit\ISummitEventRepository; use models\summit\ISummitRepository; +use models\summit\SummitAttendee; use ModelSerializers\SerializerRegistry; use services\model\ISummitService; use utils\Filter; +use utils\FilterElement; use utils\FilterParser; use utils\OrderParser; use Illuminate\Support\Facades\Input; @@ -38,6 +42,8 @@ use utils\PagingInfo; */ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController { + use GetAndValidateJsonPayload; + /** * @var ISummitService */ @@ -64,15 +70,23 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController private $event_feedback_repository; /** - * @var ISummitAttendeeRepository + * @var ISummitRepository */ - private $attendee_repository; + private $summit_repository; /** * @var IMemberRepository */ private $member_repository; + /** + * @var ISummitOrderService + */ + private $summit_order_service; + + + use ParametrizedGetAll; + /** * OAuth2SummitAttendeesApiController constructor. * @param ISummitAttendeeRepository $attendee_repository @@ -83,6 +97,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController * @param IMemberRepository $member_repository * @param ISummitService $summit_service * @param IAttendeeService $attendee_service + * @param ISummitOrderService $summit_order_service * @param IResourceServerContext $resource_server_context */ public function __construct @@ -95,17 +110,19 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController IMemberRepository $member_repository, ISummitService $summit_service, IAttendeeService $attendee_service, + ISummitOrderService $summit_order_service, IResourceServerContext $resource_server_context ) { parent::__construct($resource_server_context); - $this->attendee_repository = $attendee_repository; - $this->repository = $summit_repository; + $this->summit_repository = $summit_repository; + $this->repository = $attendee_repository; $this->speaker_repository = $speaker_repository; $this->event_repository = $event_repository; $this->event_feedback_repository = $event_feedback_repository; $this->member_repository = $member_repository; $this->summit_service = $summit_service; $this->attendee_service = $attendee_service; + $this->summit_order_service = $summit_order_service; } /** @@ -121,7 +138,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController try { - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); $type = CheckAttendeeStrategyFactory::Me; @@ -150,10 +167,10 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController try { - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $attendee = $this->attendee_repository->getById($attendee_id); + $attendee = $this->repository->getById($attendee_id); if(is_null($attendee)) return $this->error404(); return $this->ok @@ -189,7 +206,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController { try { - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); $attendee = CheckAttendeeStrategyFactory::build(CheckAttendeeStrategyFactory::Own, $this->resource_server_context)->check($attendee_id, $summit); @@ -225,7 +242,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController { try { - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); $attendee = CheckAttendeeStrategyFactory::build(CheckAttendeeStrategyFactory::Own, $this->resource_server_context)->check($attendee_id, $summit); @@ -238,7 +255,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController catch (ValidationException $ex1) { Log::warning($ex1); - return $this->error412(array( $ex1->getMessage())); + return $this->error412($ex1->getMessages()); } catch (EntityNotFoundException $ex2) { @@ -267,7 +284,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController { try { - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); $attendee = CheckAttendeeStrategyFactory::build(CheckAttendeeStrategyFactory::Own, $this->resource_server_context)->check($attendee_id, $summit); @@ -281,7 +298,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController catch (ValidationException $ex1) { Log::warning($ex1); - return $this->error412(array( $ex1->getMessage())); + return $this->error412($ex1->getMessages()); } catch (EntityNotFoundException $ex2) { @@ -309,7 +326,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController public function deleteEventRSVP($summit_id, $attendee_id, $event_id){ try { - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); $event = $summit->getScheduleEvent(intval($event_id)); @@ -329,7 +346,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController catch (ValidationException $ex1) { Log::warning($ex1); - return $this->error412(array( $ex1->getMessage())); + return $this->error412($ex1->getMessages()); } catch (EntityNotFoundException $ex2) { @@ -353,94 +370,114 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController */ public function getAttendeesBySummit($summit_id){ - $values = Input::all(); - $rules = [ - - 'page' => 'integer|min:1', - 'per_page' => 'required_with:page|integer|min:5|max:100', - ]; - - try { - - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); - - $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'), [ + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + return $this->_getAll( + function(){ + return [ 'first_name' => ['=@', '=='], 'last_name' => ['=@', '=='], + 'full_name' => ['=@', '=='], + 'company' => ['=@', '=='], 'email' => ['=@', '=='], 'external_order_id' => ['=@', '=='], 'external_attendee_id' => ['=@', '=='], - ]); - } - - $order = null; - - if (Input::has('order')) + ]; + }, + function(){ + return [ + 'first_name' => 'sometimes|string', + 'last_name' => 'sometimes|string', + 'full_name' => 'sometimes|string', + 'company' => 'sometimes|string', + 'email' => 'sometimes|string', + 'external_order_id' => 'sometimes|string', + 'external_attendee_id' => 'sometimes|string', + ]; + }, + function() { - $order = OrderParser::parse(Input::get('order'), [ + return [ + 'first_name', + 'last_name', + 'company', + 'id', + 'external_order_id', + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_Private; + } + ); + } + + /** + * @param $summit_id + * @return mixed + */ + public function getAttendeesBySummitCSV($summit_id){ + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAllCSV( + function(){ + return [ + 'first_name' => ['=@', '=='], + 'last_name' => ['=@', '=='], + 'full_name' => ['=@', '=='], + 'email' => ['=@', '=='], + 'external_order_id' => ['=@', '=='], + 'company' => ['=@', '=='], + 'external_attendee_id' => ['=@', '=='], + ]; + }, + function(){ + return [ + 'first_name' => 'sometimes|string', + 'last_name' => 'sometimes|string', + 'full_name' => 'sometimes|string', + 'email' => 'sometimes|string', + 'external_order_id' => 'sometimes|string', + 'external_attendee_id' => 'sometimes|string', + 'company' => 'sometimes|string', + ]; + }, + function() + { + return [ 'first_name', 'last_name', 'id', 'external_order_id', - ]); - } - - if(is_null($filter)) $filter = new Filter(); - - $data = $this->attendee_repository->getBySummit($summit, new PagingInfo($page, $per_page), $filter, $order); - - return $this->ok - ( - $data->toArray - ( - Request::input('expand', ''), - [], - [], - [ 'serializer_type' => SerializerRegistry::SerializerType_Private ] - ) - ); - } - catch (ValidationException $ex1) - { - Log::warning($ex1); - return $this->error412(array( $ex1->getMessage())); - } - catch (EntityNotFoundException $ex2) - { - Log::warning($ex2); - return $this->error404(array('message' => $ex2->getMessage())); - } - catch(\HTTP401UnauthorizedException $ex3) - { - Log::warning($ex3); - return $this->error401(); - } - catch (Exception $ex) { - Log::error($ex); - return $this->error500($ex); - } + 'company', + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_CSV; + }, + function(){ + return []; + }, + function(){ + return []; + }, + 'attendees-' + ); } /** @@ -452,15 +489,19 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController if(!Request::isJson()) return $this->error400(); $data = Input::json(); - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); $rules = [ - - 'member_id' => 'required|integer', 'shared_contact_info' => 'sometimes|boolean', 'summit_hall_checked_in' => 'sometimes|boolean', 'summit_hall_checked_in_date' => 'sometimes|date_format:U', + 'first_name' => 'required_without:member_id|string|max:255', + 'surname' => 'required_without:member_id|string|max:255', + 'company' => 'sometimes|string|max:255', + 'email' => 'required_without:member_id|string|max:255|email', + 'member_id' => 'required_without_all:email|integer', + 'extra_questions' => 'sometimes|order_extra_question_dto_array', ]; // Creates a Validator instance and validates the data. @@ -481,7 +522,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController } catch (ValidationException $ex1) { Log::warning($ex1); - return $this->error412(array($ex1->getMessage())); + return $this->error412($ex1->getMessages()); } catch(EntityNotFoundException $ex2) { @@ -503,10 +544,10 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController { try { - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $attendee = $this->attendee_repository->getById($attendee_id); + $attendee = $this->repository->getById($attendee_id); if(is_null($attendee)) return $this->error404(); $this->attendee_service->deleteAttendee($summit, $attendee->getIdentifier()); @@ -534,17 +575,23 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController if(!Request::isJson()) return $this->error400(); $data = Input::json(); - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $attendee = $this->attendee_repository->getById($attendee_id); + $attendee = $this->repository->getById($attendee_id); if(is_null($attendee)) return $this->error404(); $rules = [ - 'member_id' => 'required|integer', 'shared_contact_info' => 'sometimes|boolean', 'summit_hall_checked_in' => 'sometimes|boolean', 'summit_hall_checked_in_date' => 'sometimes|date_format:U', + 'disclaimer_accepted_date' => 'sometimes|date_format:U', + 'first_name' => 'required_without:member_id|string|max:255', + 'surname' => 'required_without:member_id|string|max:255', + 'company' => 'sometimes|string|max:255', + 'email' => 'required_without:member_id|string|max:255|email', + 'member_id' => 'required_without_all:first_name,surname,email|integer', + 'extra_questions' => 'sometimes|order_extra_question_dto_array', ]; // Creates a Validator instance and validates the data. @@ -565,7 +612,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController } catch (ValidationException $ex1) { Log::warning($ex1); - return $this->error412(array($ex1->getMessage())); + return $this->error412($ex1->getMessages()); } catch(EntityNotFoundException $ex2) { @@ -588,20 +635,22 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController if(!Request::isJson()) return $this->error400(); $data = Input::json(); - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $attendee = $this->attendee_repository->getById($attendee_id); - if(is_null($attendee)) return $this->error404(); + $attendee = $this->repository->getById($attendee_id); + if(is_null($attendee) || !$attendee instanceof SummitAttendee) return $this->error404(); $rules = [ 'ticket_type_id' => 'required|integer', - 'external_order_id' => 'required|string', - 'external_attendee_id' => 'required|string', + 'promo_code' => 'nullable|string', + 'external_order_id' => 'nullable|string', + 'external_attendee_id' => 'nullable|string', ]; + $payload = $data->all(); // Creates a Validator instance and validates the data. - $validation = Validator::make($data->all(), $rules); + $validation = Validator::make($payload, $rules); if ($validation->fails()) { $messages = $validation->messages()->toArray(); @@ -612,13 +661,21 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController ); } - $ticket = $this->attendee_service->addAttendeeTicket($attendee, $data->all()); + $payload['owner_email'] = $attendee->getEmail(); + $payload['owner_first_name'] = $attendee->getFirstName(); + $payload['owner_last_name'] = $attendee->getSurname(); + $payload['owner_company'] = $attendee->getCompanyName(); + + if($attendee->hasMember()) + $payload['owner_id'] = $attendee->getMemberId(); + + $ticket = $this->summit_order_service->createOrderSingleTicket($summit, $payload); return $this->created(SerializerRegistry::getInstance()->getSerializer($ticket)->serialize()); } catch (ValidationException $ex1) { Log::warning($ex1); - return $this->error412(array($ex1->getMessage())); + return $this->error412($ex1->getMessages()); } catch(EntityNotFoundException $ex2) { @@ -639,10 +696,10 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController */ public function deleteAttendeeTicket($summit_id, $attendee_id, $ticket_id){ try { - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $attendee = $this->attendee_repository->getById($attendee_id); + $attendee = $this->repository->getById($attendee_id); if(is_null($attendee)) return $this->error404(); $ticket = $this->attendee_service->deleteAttendeeTicket($attendee, $ticket_id); @@ -651,7 +708,7 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController } catch (ValidationException $ex1) { Log::warning($ex1); - return $this->error412(array($ex1->getMessage())); + return $this->error412($ex1->getMessages()); } catch(EntityNotFoundException $ex2) { @@ -671,25 +728,25 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController * @param $other_member_id * @return mixed */ - public function reassignAttendeeTicket($summit_id, $attendee_id, $ticket_id, $other_member_id){ + public function reassignAttendeeTicketByMember($summit_id, $attendee_id, $ticket_id, $other_member_id){ try { - $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $attendee = $this->attendee_repository->getById($attendee_id); - if(is_null($attendee)) return $this->error404(); + $attendee = $this->repository->getById($attendee_id); + if(is_null($attendee) || !$attendee instanceof SummitAttendee) return $this->error404(); $other_member = $this->member_repository->getById($other_member_id); - if(is_null($other_member)) return $this->error404(); + if(is_null($other_member) || !$other_member instanceof Member) return $this->error404(); - $ticket = $this->attendee_service->reassignAttendeeTicket($summit, $attendee, $other_member, $ticket_id); + $ticket = $this->attendee_service->reassignAttendeeTicketByMember($summit, $attendee, $other_member, intval($ticket_id)); return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket)->serialize()); } catch (ValidationException $ex1) { Log::warning($ex1); - return $this->error412(array($ex1->getMessage())); + return $this->error412($ex1->getMessages()); } catch(EntityNotFoundException $ex2) { @@ -701,4 +758,53 @@ final class OAuth2SummitAttendeesApiController extends OAuth2ProtectedController return $this->error500($ex); } } + + /** + * @param $summit_id + * @param $attendee_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function reassignAttendeeTicket($summit_id, $attendee_id, $ticket_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $attendee = $this->repository->getById($attendee_id); + if(is_null($attendee) || !$attendee instanceof SummitAttendee) return $this->error404(); + + $payload = $this->getJsonPayload([ + 'attendee_first_name' => 'nullable|string|max:255', + 'attendee_last_name' => 'nullable|string|max:255', + 'attendee_email' => 'required|string|max:255|email', + 'attendee_company' => 'nullable|string|max:255', + 'extra_questions' => 'sometimes|order_extra_question_dto_array' + ]); + + $ticket = $this->attendee_service->reassignAttendeeTicket($summit, $attendee, intval($ticket_id), $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412($ex1->getMessages()); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeFeatureTypeApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeFeatureTypeApiController.php new file mode 100644 index 00000000..27078711 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeFeatureTypeApiController.php @@ -0,0 +1,181 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + + /** + * @return array + */ + protected function getFilterRules():array + { + return [ + 'name' => ['=@', '=='], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'name' => 'sometimes|required|string', + ]; + } + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'name', + ]; + } + + use GetAllBySummit; + + use GetSummitChildElementById; + + use AddSummitChildElement; + + use UpdateSummitChildElement; + + use DeleteSummitChildElement; + + /** + * @param array $payload + * @return array + */ + function getAddValidationRules(array $payload): array + { + return SummitBadgeFeatureTypeValidationRulesFactory::build($payload); + } + + /** + * @param Summit $summit + * @param array $payload + * @return IEntity + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->addBadgeFeatureType($summit, $payload); + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @return IResourceServerContext + */ + protected function getResourceServerContext(): IResourceServerContext + { + return $this->resource_server_context; + } + + /** + * @return IBaseRepository + */ + protected function getRepository(): IBaseRepository + { + return $this->repository; + } + + /** + * @param Summit $summit + * @param $child_id + * @return void + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deleteBadgeFeatureType($summit, $child_id); + } + + /** + * @param Summit $summit + * @param $child_id + * @return IEntity|null + */ + protected function getChildFromSummit(Summit $summit,$child_id): ?IEntity + { + return $summit->getFeatureTypeById($child_id); + } + + /** + * @param array $payload + * @return array + */ + function getUpdateValidationRules(array $payload): array + { + return SummitBadgeFeatureTypeValidationRulesFactory::build($payload, true); + } + + /** + * @param Summit $summit + * @param int $child_id + * @param array $payload + * @return IEntity + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updateBadgeFeatureType($summit, $child_id, $payload); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeScanApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeScanApiController.php new file mode 100644 index 00000000..1486858b --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeScanApiController.php @@ -0,0 +1,330 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + use AddSummitChildElement; + + /** + * @param array $payload + * @return array + */ + function getAddValidationRules(array $payload): array + { + return [ + 'qr_code' => 'required|string', + 'scan_date' => 'required|date_format:U', + ]; + } + + /** + * @param Summit $summit + * @param array $payload + * @return IEntity + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) throw new HTTP403ForbiddenException(); + + return $this->service->addBadgeScan($summit, $current_member, $payload); + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + // traits + use ParametrizedGetAll; + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getAllMyBadgeScans($summit_id){ + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + return $this->_getAll( + function(){ + return [ + 'attendee_first_name' => ['=@', '=='], + 'attendee_last_name' => ['=@', '=='], + 'attendee_full_name' => ['=@', '=='], + 'attendee_email' => ['=@', '=='], + 'ticket_number' => ['=@', '=='], + 'order_number' => ['=@', '=='], + ]; + }, + function(){ + return [ + 'attendee_first_name' => 'sometimes|string', + 'attendee_last_name' => 'sometimes|string', + 'attendee_full_name' => 'sometimes|string', + 'attendee_email' => 'sometimes|string', + 'ticket_number' => 'sometimes|string', + 'order_number' => 'sometimes|string', + ]; + }, + function() + { + return [ + 'id', + 'scan_date' + ]; + }, + function($filter) use($summit, $current_member){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + $filter->addFilterCondition(FilterElement::makeEqual('user_id', $current_member->getId())); + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_Public; + } + ); + } + + /** + * @param $summit_id + * @return mixed + */ + public function getAllBySummit($summit_id){ + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $sponsor = null; + if(!$current_member->isAdmin()){ + $sponsor = $current_member->getSponsorBySummit($summit); + if(is_null($sponsor)){ + return $this->error403(); + } + } + + return $this->_getAll( + function(){ + return [ + 'attendee_first_name' => ['=@', '=='], + 'attendee_last_name' => ['=@', '=='], + 'attendee_full_name' => ['=@', '=='], + 'attendee_email' => ['=@', '=='], + 'ticket_number' => ['=@', '=='], + 'order_number' => ['=@', '=='], + 'sponsor_id' => ['=='], + 'attendee_company' => ['=@', '=='], + ]; + }, + function(){ + return [ + 'attendee_first_name' => 'sometimes|string', + 'attendee_last_name' => 'sometimes|string', + 'attendee_full_name' => 'sometimes|string', + 'attendee_email' => 'sometimes|string', + 'ticket_number' => 'sometimes|string', + 'order_number' => 'sometimes|string', + 'sponsor_id' => 'sometimes|integer', + 'attendee_company' => 'sometimes|string', + ]; + }, + function() + { + return [ + 'id', + 'attendee_full_name', + 'attendee_email', + 'attendee_first_name', + 'attendee_last_name', + 'attendee_company', + 'scan_date' + ]; + }, + function($filter) use($summit, $sponsor){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + if(!is_null($sponsor)){ + $filter->addFilterCondition(FilterElement::makeEqual('sponsor_id', $sponsor->getId())); + } + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_Public; + } + ); + } + + /** + * @param $summit_id + * @return mixed + */ + public function getAllBySummitCSV($summit_id){ + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $sponsor = null; + if(!$current_member->isAdmin()){ + $sponsor = $current_member->getSponsorBySummit($summit); + if(is_null($sponsor)){ + return $this->error403(); + } + } + + return $this->_getAllCSV( + function(){ + return [ + 'attendee_first_name' => ['=@', '=='], + 'attendee_last_name' => ['=@', '=='], + 'attendee_full_name' => ['=@', '=='], + 'attendee_email' => ['=@', '=='], + 'ticket_number' => ['=@', '=='], + 'order_number' => ['=@', '=='], + 'sponsor_id' => ['=='], + 'attendee_company' => ['=@', '=='], + ]; + }, + function(){ + return [ + 'attendee_first_name' => 'sometimes|string', + 'attendee_last_name' => 'sometimes|string', + 'attendee_full_name' => 'sometimes|string', + 'attendee_email' => 'sometimes|string', + 'ticket_number' => 'sometimes|string', + 'order_number' => 'sometimes|string', + 'sponsor_id' => 'sometimes|integer', + 'attendee_company' => 'sometimes|string', + ]; + }, + function() + { + return [ + 'id', + 'attendee_full_name', + 'attendee_email', + 'attendee_first_name', + 'attendee_last_name', + 'attendee_company', + 'scan_date' + ]; + }, + function($filter) use($summit, $sponsor){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + if(!is_null($sponsor)){ + $filter->addFilterCondition(FilterElement::makeEqual('sponsor_id', $sponsor->getId())); + } + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_CSV; + }, + function(){ + return [ + 'scan_date' => new EpochCellFormatter(), + ]; + }, + function(){ + + $allowed_columns = [ + 'scan_date', + 'qr_code', + 'sponsor_id', + 'user_id', + 'badge_id', + 'attendee_first_name', + 'attendee_last_name', + 'attendee_email', + 'attendee_company' + ]; + + $columns_param = Input::get("columns", ""); + $columns = []; + if(!empty($columns_param)) + $columns = explode(',', $columns_param); + $diff = array_diff($columns, $allowed_columns); + if(count($diff) > 0){ + throw new ValidationException(sprintf("columns %s are not allowed!", implode(",", $diff))); + } + if(empty($columns)) + $columns = $allowed_columns; + return $columns; + }, + 'attendees-badge-scans-' + ); + } +} diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeTypeApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeTypeApiController.php new file mode 100644 index 00000000..08a336a7 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgeTypeApiController.php @@ -0,0 +1,301 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + /** + * @return array + */ + protected function getFilterRules():array + { + return [ + 'name' => ['=@', '=='], + 'is_default' => [ '=='], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'name' => 'sometimes|required|string', + 'is_default' => 'sometimes|required|boolean', + ]; + } + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'name', + ]; + } + + use GetAllBySummit; + + use GetSummitChildElementById; + + use AddSummitChildElement; + + use UpdateSummitChildElement; + + use DeleteSummitChildElement; + + /** + * @param array $payload + * @return array + */ + function getAddValidationRules(array $payload): array + { + return SummitBadgeTypeValidationRulesFactory::build($payload); + } + + /** + * @param Summit $summit + * @param array $payload + * @return IEntity + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->addBadgeType($summit, $payload); + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @return IResourceServerContext + */ + protected function getResourceServerContext(): IResourceServerContext + { + return $this->resource_server_context; + } + + /** + * @return IBaseRepository + */ + protected function getRepository(): IBaseRepository + { + return $this->repository; + } + + /** + * @param Summit $summit + * @param $child_id + * @return void + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deleteBadgeType($summit, $child_id); + } + + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getBadgeTypeById($child_id); + } + + /** + * @param array $payload + * @return array + */ + function getUpdateValidationRules(array $payload): array + { + return SummitBadgeTypeValidationRulesFactory::build($payload, true); + } + + /** + * @param Summit $summit + * @param int $child_id + * @param array $payload + * @return IEntity + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updateBadgeType($summit, $child_id, $payload); + } + + /** + * @param $summit_id + * @param $badge_type_id + * @param $access_level_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addAccessLevelToBadgeType($summit_id, $badge_type_id, $access_level_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $child = $this->service->addAccessLevelToBadgeType($summit, $badge_type_id, $access_level_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($child)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $badge_type_id + * @param $access_level_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeAccessLevelFromBadgeType($summit_id, $badge_type_id, $access_level_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $child = $this->service->removeAccessLevelFromBadgeType($summit, $badge_type_id, $access_level_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($child)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $badge_type_id + * @param $feature_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addFeatureToBadgeType($summit_id, $badge_type_id, $feature_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $child = $this->service->addFeatureToBadgeType($summit, $badge_type_id, $feature_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($child)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $badge_type_id + * @param $feature_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeFeatureFromBadgeType($summit_id, $badge_type_id, $feature_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $child = $this->service->removeFeatureFromBadgeType($summit, $badge_type_id, $feature_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($child)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgesApiController.php new file mode 100644 index 00000000..55cac8eb --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitBadgesApiController.php @@ -0,0 +1,166 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @param $summit_id + * @return mixed + */ + public function getAllBySummit($summit_id){ + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAll( + function(){ + return [ + 'owner_first_name' => ['=@', '=='], + 'owner_last_name' => ['=@', '=='], + 'owner_full_name' => ['=@', '=='], + 'owner_email' => ['=@', '=='], + 'ticket_number' => ['=@', '=='], + 'order_number' => ['=@', '=='], + ]; + }, + function(){ + return [ + 'owner_first_name' => 'sometimes|string', + 'owner_last_name' => 'sometimes|string', + 'owner_full_name' => 'sometimes|string', + 'owner_email' => 'sometimes|string', + 'ticket_number' => 'sometimes|string', + 'order_number' => 'sometimes|string', + ]; + }, + function() + { + return [ + 'id', + 'ticket_number', + 'order_number', + 'created' + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_Private; + } + ); + } + + /** + * @param $summit_id + * @return mixed + */ + public function getAllBySummitCSV($summit_id){ + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAllCSV( + function(){ + return [ + 'owner_first_name' => ['=@', '=='], + 'owner_last_name' => ['=@', '=='], + 'owner_full_name' => ['=@', '=='], + 'owner_email' => ['=@', '=='], + 'ticket_number' => ['=@', '=='], + 'order_number' => ['=@', '=='], + ]; + }, + function(){ + return [ + 'owner_first_name' => 'sometimes|string', + 'owner_last_name' => 'sometimes|string', + 'owner_full_name' => 'sometimes|string', + 'owner_email' => 'sometimes|string', + 'ticket_number' => 'sometimes|string', + 'order_number' => 'sometimes|string', + ]; + }, + function() + { + return [ + 'id', + 'ticket_number', + 'order_number', + 'created' + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_Private; + }, + function(){ + return []; + }, + function(){ + return []; + }, + 'attendees-badges-' + ); + } + + + +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitDocumentsApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitDocumentsApiController.php new file mode 100644 index 00000000..73578c81 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitDocumentsApiController.php @@ -0,0 +1,330 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + /** + * @param LaravelRequest $request + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function add(LaravelRequest $request, $summit_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $request->all(); + + $rules = [ + 'file' => 'required', + 'name' => 'required|string:512', + 'label' => 'required|string:512', + 'description' => 'nullable|string', + 'event_types' => 'sometimes|int_array', + ]; + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $rules); + + if ($validation->fails()) { + $ex = new ValidationException; + $ex->setMessages($validation->messages()->toArray()); + throw $ex; + } + + $fields = [ + 'name', + 'description', + 'label', + ]; + + $document = $this->service->addSummitDocument + ( + $summit, + HTMLCleaner::cleanData($payload, $fields) + + ); + return $this->created(SerializerRegistry::getInstance()->getSerializer($document)->serialize()); + } + catch (EntityNotFoundException $ex1) + { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) + { + Log::warning($ex2); + return $this->error412($ex2->getMessages()); + } + catch (\Exception $ex) + { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param LaravelRequest $request + * @param $summit_id + * @param $document_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function update(LaravelRequest $request, $summit_id, $document_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $request->all(); + + $rules = [ + 'file' => 'sometimes', + 'name' => 'nullable|string:512', + 'label' => 'nullable|string:512', + 'description' => 'nullable|string', + 'event_types' => 'sometimes|int_array', + ]; + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $rules); + + if ($validation->fails()) { + $ex = new ValidationException; + $ex->setMessages($validation->messages()->toArray()); + throw $ex; + } + + $fields = [ + 'name', + 'description', + 'label', + ]; + + $document = $this->service->updateSummitDocument + ( + $summit, + $document_id, + HTMLCleaner::cleanData($payload, $fields) + ); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($document)->serialize()); + } + catch (EntityNotFoundException $ex1) + { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) + { + Log::warning($ex2); + return $this->error412($ex2->getMessages()); + } + catch (\Exception $ex) + { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @inheritDoc + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @inheritDoc + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deleteSummitDocument($summit, $child_id); + } + + /** + * @inheritDoc + */ + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getSummitDocumentById($child_id); + } + + /** + * @return array + */ + protected function getFilterRules():array + { + return [ + 'name' => ['=@', '=='], + 'description' => ['=@', '=='], + 'label' => ['=@', '=='], + 'event_type' => ['=@', '=='], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'name' => 'sometimes|required|string', + 'description' => 'sometimes|required|string', + 'label' => 'sometimes|required|string', + 'event_type' => 'sometimes|required|string', + ]; + } + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'name', + 'label', + ]; + } + + /** + * @param $summit_id + * @param $document_id + * @param $event_type_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addEventType($summit_id, $document_id, $event_type_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + + $document = $this->service->addEventTypeToSummitDocument + ( + $summit, + $document_id, + $event_type_id + ); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($document)->serialize()); + } + catch (EntityNotFoundException $ex1) + { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) + { + Log::warning($ex2); + return $this->error412($ex2->getMessages()); + } + catch (\Exception $ex) + { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $document_id + * @param $event_type_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeEventType($summit_id, $document_id, $event_type_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + + $document = $this->service->removeEventTypeFromSummitDocument + ( + $summit, + $document_id, + $event_type_id + ); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($document)->serialize()); + } + catch (EntityNotFoundException $ex1) + { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) + { + Log::warning($ex2); + return $this->error412($ex2->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/OAuth2SummitEmailEventFlowApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEmailEventFlowApiController.php new file mode 100644 index 00000000..b064f589 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEmailEventFlowApiController.php @@ -0,0 +1,143 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + /** + * @inheritDoc + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @inheritDoc + */ + function getUpdateValidationRules(array $payload): array + { + return [ + 'email_template_identifier' => 'sometimes|required|string', + ]; + } + + /** + * @inheritDoc + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updateEmailEventFlow($summit, $child_id, $payload); + } + + /** + * @inheritDoc + */ + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getEmailEventById($child_id); + } + + /** + * @return array + */ + protected function getFilterRules():array + { + return [ + 'email_template_identifier' => ['=@', '=='], + 'event_type_name' => ['=@', '=='], + 'flow_name' => ['=@', '=='], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'email_template_identifier' => 'sometimes|required|string', + 'event_type_name' => 'sometimes|required|string', + 'flow_name' => 'sometimes|required|string', + ]; + } + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'email_template_identifier', + ]; + } + + /** + * @param Summit $summit + * @param $child_id + * @throws \models\exceptions\EntityNotFoundException + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deleteEmailEventFlow($summit, $child_id); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php index 294461e6..16bba82b 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitEventsApiController.php @@ -435,6 +435,9 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController 'end_date' => 'sometimes|required_with:start_date|date_format:U|after:start_date', 'track_id' => 'required|integer', 'rsvp_link' => 'sometimes|url', + 'streaming_url' => 'sometimes|url', + 'etherpad_link' => 'sometimes|url', + 'meeting_url' => 'sometimes|url', 'rsvp_template_id' => 'sometimes|integer', 'rsvp_max_user_number' => 'required_with:rsvp_template_id|integer|min:0', 'rsvp_max_user_wait_list_number' => 'required_with:rsvp_template_id|integer|min:0', @@ -451,6 +454,7 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController 'moderator_speaker_id' => 'sometimes|integer', // group event 'groups' => 'sometimes|int_array', + 'selection_plan_id' => 'sometimes|integer', ]; // Creates a Validator instance and validates the data. @@ -512,6 +516,9 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController 'title' => 'sometimes|string|max:255', 'description' => 'sometimes|string|max:1100', 'rsvp_link' => 'sometimes|url', + 'streaming_url' => 'sometimes|url', + 'etherpad_link' => 'sometimes|url', + 'meeting_url' => 'sometimes|url', 'rsvp_template_id' => 'sometimes|integer', 'rsvp_max_user_number' => 'required_with:rsvp_template_id|integer|min:0', 'rsvp_max_user_wait_list_number' => 'required_with:rsvp_template_id|integer|min:0', @@ -533,7 +540,8 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController 'moderator_speaker_id' => 'sometimes|integer', // group event 'groups' => 'sometimes|int_array', - 'occupancy' => 'sometimes|in:EMPTY,25%,50%,75%,FULL' + 'occupancy' => 'sometimes|in:EMPTY,25%,50%,75%,FULL', + 'selection_plan_id' => 'sometimes|integer', ]; // Creates a Validator instance and validates the data. @@ -1296,4 +1304,58 @@ final class OAuth2SummitEventsApiController extends OAuth2ProtectedController } } + public function addEventImage(LaravelRequest $request, $summit_id, $event_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $file = $request->file('file'); + if (is_null($file)) { + return $this->error412(array('file param not set!')); + } + + $image = $this->service->addEventImage($summit, $event_id, $file); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($image)->serialize()); + + } + catch (ValidationException $ex1) + { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + public function deleteEventImage($summit_id, $event_id) { + try { + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $this->service->removeEventImage($summit, $event_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/OAuth2SummitLocationsApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php index d43295f9..f4bd19b4 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitLocationsApiController.php @@ -17,7 +17,6 @@ use App\Models\Foundation\Summit\Locations\SummitLocationConstants; use App\Models\Foundation\Summit\Repositories\ISummitLocationBannerRepository; use App\Models\Foundation\Summit\Repositories\ISummitLocationRepository; use App\Models\Foundation\Summit\Repositories\ISummitRoomReservationRepository; -use App\Services\Apis\IPaymentGatewayAPI; use App\Services\Model\ILocationService; use Exception; use Illuminate\Http\Request as LaravelRequest; @@ -95,11 +94,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController */ private $location_banners_repository; - /** - * @var IPaymentGatewayAPI - */ - private $payment_gateway; - /** * @var ISummitRoomReservationRepository */ @@ -117,7 +111,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController * @param ISummitRoomReservationRepository $reservation_repository * @param ISummitService $summit_service * @param ILocationService $location_service - * @param IPaymentGatewayAPI $payment_gateway * @param IResourceServerContext $resource_server_context */ public function __construct @@ -132,7 +125,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController ISummitRoomReservationRepository $reservation_repository, ISummitService $summit_service, ILocationService $location_service, - IPaymentGatewayAPI $payment_gateway, IResourceServerContext $resource_server_context ) { parent::__construct($resource_server_context); @@ -145,7 +137,6 @@ final class OAuth2SummitLocationsApiController extends OAuth2ProtectedController $this->location_banners_repository = $location_banners_repository; $this->location_service = $location_service; $this->summit_service = $summit_service; - $this->payment_gateway = $payment_gateway; $this->reservation_repository = $reservation_repository; } diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitMediaFileTypeApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitMediaFileTypeApiController.php new file mode 100644 index 00000000..4fe2a710 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitMediaFileTypeApiController.php @@ -0,0 +1,142 @@ +service = $service; + $this->repository = $repository; + } + + + /** + * @inheritDoc + */ + function getAddValidationRules(array $payload): array + { + return [ + 'name' => 'required|string|max:255', + 'description' => 'sometimes|string|max:255', + 'allowed_extensions'=> 'required|string_array', + ]; + } + + /** + * @inheritDoc + */ + protected function addEntity(array $payload): IEntity + { + return $this->service->add($payload); + } + + /** + * @inheritDoc + */ + protected function deleteEntity(int $id): void + { + $this->service->delete($id); + } + + /** + * @inheritDoc + */ + protected function getEntity(int $id): IEntity + { + return $this->repository->getById($id); + } + + /** + * @inheritDoc + */ + function getUpdateValidationRules(array $payload): array + { + return [ + 'name' => 'sometimes|string|max:255', + 'description' => 'sometimes|string|max:255', + 'allowed_extensions'=> 'required|string_array', + ]; + } + + /** + * @inheritDoc + */ + protected function updateEntity($id, array $payload): IEntity + { + return $this->service->update($id, $payload); + } + + public function getAll(){ + return $this->_getAll( + function(){ + return [ + 'name' => ['=@', '=='], + ]; + }, + function(){ + return [ + 'name' => 'sometimes|string', + ]; + }, + function() + { + return [ + 'name', + 'id', + ]; + }, + function($filter){ + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_Public; + } + ); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitMediaUploadTypeApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitMediaUploadTypeApiController.php new file mode 100644 index 00000000..8c522bf1 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitMediaUploadTypeApiController.php @@ -0,0 +1,297 @@ +service = $service; + $this->summit_repository = $summit_repository; + $this->repository = $repository; + } + + /** + * @return array + */ + protected function getFilterRules():array + { + return [ + 'name' => ['=@', '=='], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'name' => 'sometimes|required|string', + ]; + } + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'name', + ]; + } + + /** + * @inheritDoc + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->add($summit, $payload); + } + + /** + * @inheritDoc + */ + function getAddValidationRules(array $payload): array + { + return [ + 'name' => 'required|string|max:255', + 'description' => 'sometimes|string|max:255', + 'is_mandatory' => 'required|boolean', + 'max_size' => 'required|int|megabyte_aligned', + 'private_storage_type' => 'required|string|in:'.implode(",", IStorageTypesConstants::ValidTypes), + 'public_storage_type' => 'required|string|in:'.implode(",", IStorageTypesConstants::ValidTypes), + 'type_id' => 'required|int', + 'presentation_types' => 'sometimes|int_array', + ]; + } + + /** + * @inheritDoc + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @inheritDoc + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->delete($summit, $child_id); + } + + /** + * @inheritDoc + */ + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getMediaUploadTypeById($child_id); + } + + /** + * @inheritDoc + */ + function getUpdateValidationRules(array $payload): array + { + return [ + 'name' => 'sometimes|string|max:255', + 'description' => 'sometimes|string|max:255', + 'is_mandatory' => 'sometimes|boolean', + // KB + 'max_size' => 'sometimes|int|megabyte_aligned', + 'private_storage_type' => 'sometimes|string|in:'.implode(",", IStorageTypesConstants::ValidTypes), + 'public_storage_type' => 'sometimes|string|in:'.implode(",", IStorageTypesConstants::ValidTypes), + 'type_id' => 'sometimes|int', + 'presentation_types' => 'sometimes|int_array', + ]; + } + + /** + * @inheritDoc + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->update($summit, $child_id, $payload); + } + + /** + * @param $summit_id + * @param $media_upload_type_id + * @param $presentation_type_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addToPresentationType($summit_id, $media_upload_type_id, $presentation_type_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $presentation_type = $this->service->addToPresentationType($summit, intval($media_upload_type_id), intval($presentation_type_id)); + return $this->updated(SerializerRegistry::getInstance()->getSerializer + ( + $presentation_type + )->serialize()); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } + catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $media_upload_type_id + * @param $presentation_type_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function deleteFromPresentationType($summit_id, $media_upload_type_id, $presentation_type_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $presentation_type = $this->service->deleteFromPresentationType($summit, intval($media_upload_type_id), intval($presentation_type_id)); + return $this->updated(SerializerRegistry::getInstance()->getSerializer + ( + $presentation_type + )->serialize()); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } + catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $to_summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function cloneMediaUploadTypes($summit_id, $to_summit_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $to_summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($to_summit_id); + if (is_null($to_summit)) return $this->error404(); + + $to_summit = $this->service->cloneMediaUploadTypes($summit, $to_summit); + + return $this->created( + SerializerRegistry::getInstance()->getSerializer + ( + $to_summit + )->serialize() + ); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } + catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + +} \ 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 7fa8a198..4b4d7c41 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitMembersApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitMembersApiController.php @@ -947,4 +947,82 @@ final class OAuth2SummitMembersApiController extends OAuth2ProtectedController } } + /** + * @param $summit_id + * @param $member_id + * @param $event_id + * @return mixed + */ + public function enterToEvent($summit_id, $member_id, $event_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $event = $this->summit_service->enterTo($summit, $current_member, intval($event_id)); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($event)->serialize()); + } + catch (ValidationException $ex1) + { + Log::warning($ex1); + return $this->error412(array( $ex1->getMessage())); + } + catch (EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message' => $ex2->getMessage())); + } + catch(\HTTP401UnauthorizedException $ex3) + { + Log::warning($ex3); + return $this->error401(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $member_id + * @param $event_id + * @return mixed + */ + public function leaveFromEvent($summit_id, $member_id, $event_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $event = $this->summit_service->leaveFrom($summit, $current_member, intval($event_id)); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($event)->serialize()); + } + catch (ValidationException $ex1) + { + Log::warning($ex1); + return $this->error412(array( $ex1->getMessage())); + } + catch (EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message' => $ex2->getMessage())); + } + catch(\HTTP401UnauthorizedException $ex3) + { + Log::warning($ex3); + return $this->error401(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrderExtraQuestionTypeApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrderExtraQuestionTypeApiController.php new file mode 100644 index 00000000..d0e43043 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrderExtraQuestionTypeApiController.php @@ -0,0 +1,320 @@ +summit_repository = $summit_repository; + $this->service = $service; + $this->repository = $repository; + } + + use GetAllBySummit; + + use GetSummitChildElementById; + + use AddSummitChildElement; + + use UpdateSummitChildElement; + + use DeleteSummitChildElement; + + /** + * @param $summit_id + * @return mixed + */ + public function getMetadata($summit_id){ + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->ok + ( + $this->repository->getQuestionsMetadata($summit) + ); + } + + /** + * @return array + */ + protected function getFilterRules():array{ + return [ + 'name' => ['==', '=@'], + 'type' => ['==', '=@'], + 'usage' => ['==', '=@'], + 'label' => ['==', '=@'], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'name' => 'sometimes|required|string', + 'type' => 'sometimes|required|string', + 'usage' => 'sometimes|required|string', + 'label' => 'sometimes|required|string', + ]; + } + + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'name', + 'label', + 'order', + ]; + } + + /** + * @param array $payload + * @return array + */ + function getAddValidationRules(array $payload): array + { + return SummitOrderExtraQuestionTypeValidationRulesFactory::build($payload); + } + + /** + * @param Summit $summit + * @param array $payload + * @return IEntity + * @throws EntityNotFoundException + * @throws ValidationException + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->addOrderExtraQuestion($summit, $payload); + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @param Summit $summit + * @param $child_id + * @throws EntityNotFoundException + * @throws ValidationException + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deleteOrderExtraQuestion($summit, $child_id); + } + + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getOrderExtraQuestionById($child_id); + } + + /** + * @param array $payload + * @return array + */ + function getUpdateValidationRules(array $payload): array + { + return SummitOrderExtraQuestionTypeValidationRulesFactory::build($payload, true); + } + + /** + * @param Summit $summit + * @param int $child_id + * @param array $payload + * @return IEntity + * @throws \models\exceptions\EntityNotFoundException + * @throws \models\exceptions\ValidationException + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updateOrderExtraQuestion($summit, $child_id, $payload); + } + + /** + * @param $summit_id + * @param $question_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addQuestionValue($summit_id, $question_id){ + try { + if(!Request::isJson()) return $this->error400(); + $data = Input::json(); + $payload = $data->all(); + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, [ + 'label' => 'sometimes|string', + 'value' => 'required|string', + ]); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $value = $this->service->addOrderExtraQuestionValue($summit, $question_id, $payload); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($value)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $question_id + * @param $value_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function updateQuestionValue($summit_id, $question_id, $value_id){ + + try { + if(!Request::isJson()) return $this->error400(); + $data = Input::json(); + $payload = $data->all(); + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, [ + 'label' => 'sometimes|string', + 'value' => 'sometimes|string', + 'order' => 'sometimes|integer|min:1' + ]); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $value = $this->service->updateOrderExtraQuestionValue($summit, $question_id, $value_id, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($value)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $question_id + * @param $value_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function deleteQuestionValue($summit_id, $question_id, $value_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $this->service->deleteOrderExtraQuestionValue($summit, $question_id, $value_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/OAuth2SummitOrdersApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php new file mode 100644 index 00000000..31a448dd --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php @@ -0,0 +1,1156 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + $this->ticket_repository = $ticket_repository; + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function reserve($summit_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $owner = $this->getResourceServerContext()->getCurrentUser(); + + $validation_rules = [ + 'tickets' => 'required|ticket_dto_array', + 'extra_questions' => 'sometimes|order_extra_question_dto_array', + 'owner_company' => 'nullable|string|max:255', + ]; + + if(is_null($owner)){ + $validation_rules = array_merge([ + 'owner_first_name' => 'required|string|max:255', + 'owner_last_name' => 'required|string|max:255', + 'owner_email' => 'required|string|max:255|email', + ], $validation_rules); + } + + $payload = $this->getJsonPayload($validation_rules); + if(!is_null($owner)){ + $payload_ex = [ + 'owner_first_name' => $owner->getFirstName(), + 'owner_last_name' => $owner->getLastName(), + 'owner_email' => $owner->getEmail(), + ]; + $payload = array_merge($payload, $payload_ex); + } + + $order = $this->service->reserve($owner, $summit, $payload); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($order, ISummitOrderSerializerTypes::ReservationType)->serialize(Request::input('expand', ''))); + + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $hash + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function checkout($summit_id, $hash){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $this->getJsonPayload([ + 'billing_address_1' => 'required|string|max:255', + 'billing_address_2' => 'sometimes|string|max:255', + 'billing_address_zip_code' => 'required|string|max:255', + 'billing_address_city' => 'required|string|max:255', + 'billing_address_state' => 'required|string|max:255', + 'billing_address_country' => 'required|string|country_iso_alpha2_code', + ]); + + $order = $this->service->checkout($summit, $hash, $payload); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($order, ISummitOrderSerializerTypes::CheckOutType)->serialize( Request::input('expand', ''))); + + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + + /** + * @param $summit_id + * @param $hash + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getMyTicketByOrderHash($summit_id, $hash){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $ticket = $this->service->getMyTicketByOrderHash($summit, $hash); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($ticket, ISummitAttendeeTicketSerializerTypes::GuestEdition)->serialize( Request::input('expand', ''))); + + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $hash + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function cancel($summit_id, $hash){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + $this->service->cancel($summit, $hash); + return $this->deleted(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getAllBySummit($summit_id){ + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAll( + function(){ + return [ + 'number' => ['=@', '=='], + 'owner_name' => ['=@', '=='], + 'owner_email' => ['=@', '=='], + 'owner_company' => ['=@', '=='], + 'ticket_owner_name' => ['=@', '=='], + 'ticket_owner_email' => ['=@', '=='], + 'ticket_number' => ['=@', '=='], + 'summit_id' => ['=='], + 'owner_id' => ['=='], + 'status' => ['==','<>'], + ]; + }, + function(){ + return [ + 'status' => sprintf('sometimes|in:%s',implode(',', IOrderConstants::ValidStatus)), + 'number' => 'sometimes|string', + 'owner_name' => 'sometimes|string', + 'owner_email' => 'sometimes|string', + 'owner_company' => 'sometimes|string', + 'ticket_owner_name' => 'sometimes|string', + 'ticket_owner_email' => 'sometimes|string', + 'ticket_number' => 'sometimes|string', + 'summit_id' => 'sometimes|integer', + 'owner_id' => 'sometimes|integer', + + ]; + }, + function() + { + return [ + 'id', + 'number', + 'status', + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return ISummitOrderSerializerTypes::AdminType; + } + ); + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getAllBySummitCSV($summit_id){ + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAllCSV( + function(){ + return [ + 'number' => ['=@', '=='], + 'owner_name' => ['=@', '=='], + 'owner_email' => ['=@', '=='], + 'owner_company' => ['=@', '=='], + 'summit_id' => ['=='], + 'owner_id' => ['=='], + 'status' => ['=='], + 'ticket_owner_name' => ['=@', '=='], + 'ticket_owner_email' => ['=@', '=='], + 'ticket_number' => ['=@', '=='], + ]; + }, + function(){ + return [ + 'status' => sprintf('sometimes|in:%s',implode(',', IOrderConstants::ValidStatus)), + 'number' => 'sometimes|string', + 'owner_name' => 'sometimes|string', + 'owner_email' => 'sometimes|string', + 'owner_company' => 'sometimes|string', + 'summit_id' => 'sometimes|integer', + 'owner_id' => 'sometimes|integer', + 'ticket_owner_name' => 'sometimes|string', + 'ticket_owner_email' => 'sometimes|string', + 'ticket_number' => 'sometimes|string', + + ]; + }, + function() + { + return [ + 'id', + 'number', + 'status', + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return ISummitOrderSerializerTypes::AdminType; + }, + function (){ + return []; + }, + function(){ + return []; + }, + 'orders-' + ); + } + + /** + * @return mixed + */ + public function getAllMyOrders(){ + $owner = $this->getResourceServerContext()->getCurrentUser(); + return $this->_getAll( + function(){ + return [ + 'number' => ['=@', '=='], + 'summit_id' => ['=='], + 'status' => ['==','<>'], + ]; + }, + function(){ + return [ + 'status' => sprintf('sometimes|in:%s',implode(',', IOrderConstants::ValidStatus)), + 'number' => 'sometimes|string', + 'summit_id' => 'sometimes|integer', + ]; + }, + function() + { + return [ + 'id', + 'number', + 'status', + ]; + }, + function($filter) use($owner){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('owner_id', $owner->getId())); + } + return $filter; + }, + function(){ + return ISummitOrderSerializerTypes::AdminType; + } + ); + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @param $order_id + */ + public function updateMyOrder($order_id){ + try { + $current_user = $this->getResourceServerContext()->getCurrentUser(); + $payload = $this->getJsonPayload([ + 'extra_questions' => 'sometimes|order_extra_question_dto_array', + 'owner_company' => 'sometimes|string|max:255', + 'billing_address_1' => 'sometimes|string|max:255', + 'billing_address_2' => 'sometimes|string|max:255', + 'billing_address_zip_code' => 'sometimes|string|max:255', + 'billing_address_city' => 'sometimes|string|max:255', + 'billing_address_state' => 'sometimes|string|max:255', + 'billing_address_country' => 'sometimes|string|country_iso_alpha2_code', + ]); + + $order = $this->service->updateMyOrder($current_user, intval($order_id), $payload); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($order, ISummitOrderSerializerTypes::CheckOutType)->serialize( Request::input('expand', ''))); + + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $order_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function requestRefundMyOrder($order_id){ + try { + $current_user = $this->getResourceServerContext()->getCurrentUser(); + + $order = $this->service->requestRefundOrder($current_user, intval($order_id)); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($order)->serialize( Request::input('expand', ''))); + + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $order_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function requestRefundMyTicket($order_id, $ticket_id){ + try { + $current_user = $this->getResourceServerContext()->getCurrentUser(); + + $ticket = $this->service->requestRefundTicket($current_user, intval($order_id), intval($ticket_id)); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket)->serialize( Request::input('expand', ''))); + + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $order_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function assignAttendee($order_id, $ticket_id){ + try { + $current_user = $this->getResourceServerContext()->getCurrentUser(); + + $payload = $this->getJsonPayload([ + 'attendee_first_name' => 'nullable|string|max:255', + 'attendee_last_name' => 'nullable|string|max:255', + 'attendee_email' => 'required|string|max:255|email', + 'attendee_company' => 'nullable|string|max:255', + 'extra_questions' => 'sometimes|order_extra_question_dto_array' + ]); + + $ticket = $this->service->ownerAssignTicket($current_user, intval($order_id), intval($ticket_id), $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket)->serialize( Request::input('expand', ''))); + + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + + /** + * @param $order_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function reSendOrderEmail($order_id){ + try { + + $order = $this->service->reSendOrderEmail(intval($order_id)); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($order)->serialize( Request::input('expand', ''))); + + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $order_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function reInviteAttendee($order_id, $ticket_id){ + try { + $current_user = $this->resource_server_context->getCurrentUser(); + if(is_null($current_user)) + return $this->error403(); + $ticket = $this->ticket_repository->getById(intval($ticket_id)); + + if(is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException('ticket not found'); + + if(!$ticket->canEditTicket($current_user)){ + return $this->error403(); + } + + $ticket = $this->service->reInviteAttendee(intval($order_id), intval($ticket_id)); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket)->serialize( Request::input('expand', ''))); + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $order_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function updateTicket($summit_id, $order_id, $ticket_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $this->getJsonPayload([ + 'ticket_type_id' => 'nullable|integer', + 'badge_type_id' => 'nullable|integer', + 'attendee_first_name' => 'nullable|string|max:255', + 'attendee_last_name' => 'nullable|string|max:255', + 'attendee_email' => 'required|string|max:255|email', + 'attendee_company' => 'nullable|string|max:255', + 'extra_questions' => 'sometimes|order_extra_question_dto_array' + ]); + + $ticket = $this->service->updateTicket($summit, intval($order_id), intval($ticket_id), $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket, ISummitAttendeeTicketSerializerTypes::AdminType)->serialize( Request::input('expand', ''))); + + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $order_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addTicket($summit_id, $order_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $this->getJsonPayload([ + 'ticket_type_id' => 'required|integer', + 'badge_type_id' => 'nullable|integer', + 'attendee_first_name' => 'nullable|string|max:255', + 'attendee_last_name' => 'nullable|string|max:255', + 'attendee_email' => 'required|string|max:255|email', + 'attendee_company' => 'nullable|string|max:255', + 'extra_questions' => 'sometimes|order_extra_question_dto_array' + ]); + + $ticket = $this->service->addTicket($summit, intval($order_id), $payload); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($ticket)->serialize( Request::input('expand', ''))); + + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + + /** + * @param $order_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeAttendee($order_id, $ticket_id){ + try { + $current_user = $this->getResourceServerContext()->getCurrentUser(); + $ticket = $this->service->revokeTicket($current_user, intval($order_id), intval($ticket_id)); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket)->serialize( Request::input('expand', ''))); + + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $order_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|mixed + */ + public function getTicketPDFBySummit($summit_id, $order_id, $ticket_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + $content = $this->service->renderTicketByFormat(intval($ticket_id), IRenderersFormats::PDFFormat,null, intval($order_id), $summit); + return $this->pdf('ticket_'.$ticket_id.'.pdf', $content); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $order_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|mixed + */ + public function getTicketPDFByOrderId($order_id, $ticket_id){ + try { + $current_user = $this->getResourceServerContext()->getCurrentUser(); + $content = $this->service->renderTicketByFormat(intval($ticket_id),IRenderersFormats::PDFFormat, $current_user, intval($order_id)); + return $this->pdf('ticket_'.$ticket_id.'.pdf', $content); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|mixed + */ + public function getTicketPDFById($ticket_id){ + try { + $current_user = $this->getResourceServerContext()->getCurrentUser(); + $content = $this->service->renderTicketByFormat(intval($ticket_id),IRenderersFormats::PDFFormat, $current_user); + return $this->pdf('ticket_'.$ticket_id.'.pdf', $content); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /// public endpoints + + /** + * @param $hash + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getTicketByHash($hash){ + try { + $ticket = $this->service->getTicketByHash($hash); + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($ticket, ISummitAttendeeTicketSerializerTypes::PublicEdition)->serialize(Request::input('expand', ''))); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $hash + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function updateTicketByHash($hash){ + try { + + $payload = $this->getJsonPayload([ + 'attendee_first_name' => 'nullable|string|max:255', + 'attendee_last_name' => 'nullable|string|max:255', + 'attendee_company' => 'nullable|string|max:255', + 'disclaimer_accepted' => 'nullable|boolean', + 'share_contact_info' => 'nullable|boolean', + 'extra_questions' => 'sometimes|order_extra_question_dto_array' + ]); + + $ticket = $this->service->updateTicketByHash($hash, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket, ISummitAttendeeTicketSerializerTypes::PublicEdition)->serialize( Request::input('expand', ''))); + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + + /** + * @param $order_hash + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function updateTicketsByOrderHash($order_hash) + { + try { + + $payload = $this->getJsonPayload([ + 'tickets' => 'required|ticket_dto_array', + ]); + + $order = $this->service->updateTicketsByOrderHash($order_hash, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($order, ISummitOrderSerializerTypes::CheckOutType)->serialize(Request::input('expand', ''))); + + } catch (\InvalidArgumentException $ex) { + Log::warning($ex); + return $this->error400(); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + /** + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function updateTicketById($ticket_id){ + try { + + $current_user = $this->getResourceServerContext()->getCurrentUser(); + if(is_null($current_user)) + return $this->error403(); + + $payload = $this->getJsonPayload([ + 'attendee_first_name' => 'nullable|string|max:255', + 'attendee_last_name' => 'nullable|string|max:255', + 'attendee_company' => 'nullable|string|max:255', + 'disclaimer_accepted' => 'nullable|boolean', + 'share_contact_info' => 'nullable|boolean', + 'extra_questions' => 'sometimes|order_extra_question_dto_array' + ]); + + $ticket = $this->service->updateTicketById($current_user, $ticket_id, $payload); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket, ISummitAttendeeTicketSerializerTypes::PublicEdition)->serialize( Request::input('expand', ''))); + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $hash + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function regenerateTicketHash($hash){ + try { + + $this->service->regenerateTicketHash($hash); + + return $this->ok(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $hash + * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|mixed + */ + public function getTicketPDFByHash($hash){ + try { + $content = $this->service->renderTicketByFormat($hash, IRenderersFormats::PDFFormat); + return $this->pdf('ticket_'.$hash.'.pdf', $content); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param array $payload + * @return array + */ + function getAddValidationRules(array $payload): array + { + return [ + 'owner_first_name' => 'required_without:owner_id|string|max:255', + 'owner_last_name' => 'required_without:owner_id|string|max:255', + 'owner_email' => 'required_without:owner_id|string|max:255|email', + 'owner_id' => 'required_without:owner_first_name,owner_last_name,owner_email|int', + 'ticket_type_id' => 'required|int', + 'promo_code' => 'sometimes|string', + 'extra_questions' => 'sometimes|order_extra_question_dto_array', + 'owner_company' => 'required|string|max:255', + 'billing_address_1' => 'sometimes|string|max:255', + 'billing_address_2' => 'sometimes|string|max:255', + 'billing_address_zip_code' => 'sometimes|string|max:255', + 'billing_address_city' => 'sometimes|string|max:255', + 'billing_address_state' => 'sometimes|string|max:255', + 'billing_address_country' => 'sometimes|string|country_iso_alpha2_code', + ]; + } + + /** + * @param Summit $summit + * @param array $payload + * @return IEntity + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->createOrderSingleTicket($summit, $payload); + } + + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getOrderById($child_id); + } + + /** + * @return string + */ + public function getChildSerializer(){ + return ISummitOrderSerializerTypes::AdminType; + } + + /** + * @param array $payload + * @return array + */ + function getUpdateValidationRules(array $payload): array + { + return [ + 'owner_first_name' => 'required_without:owner_id|string|max:255', + 'owner_last_name' => 'required_without:owner_id|string|max:255', + 'owner_email' => 'required_without:owner_id|string|max:255|email', + 'owner_id' => 'required_without:owner_first_name,owner_last_name,owner_email|int', + 'extra_questions' => 'sometimes|order_extra_question_dto_array', + 'owner_company' => 'required|string|max:255', + 'billing_address_1' => 'sometimes|string|max:255', + 'billing_address_2' => 'sometimes|string|max:255', + 'billing_address_zip_code' => 'sometimes|string|max:255', + 'billing_address_city' => 'sometimes|string|max:255', + 'billing_address_state' => 'sometimes|string|max:255', + 'billing_address_country' => 'sometimes|string|country_iso_alpha2_code', + ]; + } + + /** + * @param Summit $summit + * @param int $child_id + * @param array $payload + * @return IEntity + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updateOrder($summit, $child_id, $payload); + } + + /** + * @param Summit $summit + * @param $child_id + * @return void + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deleteOrder($summit, intval($child_id)); + } + + /** + * @param $summit_id + * @param $order_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function refundOrder($summit_id, $order_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $this->getJsonPayload([ + 'amount' => 'required|numeric|greater_than:0', + ]); + + $order = $this->service->refundOrder($summit, intval($order_id), floatval($payload['amount'])); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($order)->serialize( Request::input('expand', ''))); + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->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/OAuth2SummitPromoCodesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitPromoCodesApiController.php index b7870f5c..cb05ba3b 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitPromoCodesApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitPromoCodesApiController.php @@ -26,12 +26,12 @@ use models\summit\ISummitRepository; use ModelSerializers\SerializerRegistry; use services\model\ISummitPromoCodeService; use utils\Filter; -use utils\FilterElement; use utils\FilterParser; use utils\OrderParser; use Illuminate\Support\Facades\Input; use Illuminate\Support\Facades\Validator; use utils\PagingInfo; +use Exception; /** * Class OAuth2SummitPromoCodesApiController * @package App\Http\Controllers @@ -417,7 +417,7 @@ final class OAuth2SummitPromoCodesApiController extends OAuth2ProtectedControlle $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $rules = PromoCodesValidationRulesFactory::build($data->all()); + $rules = PromoCodesValidationRulesFactory::build($data->all(), true); // Creates a Validator instance and validates the data. $validation = Validator::make($data->all(), $rules); @@ -430,7 +430,7 @@ final class OAuth2SummitPromoCodesApiController extends OAuth2ProtectedControlle ); } - $promo_code = $this->promo_code_service->updatePromoCode($summit, $promo_code_id, $data->all(), $this->resource_server_context->getCurrentUser()); + $promo_code = $this->promo_code_service->updatePromoCode($summit, intval($promo_code_id), $data->all(), $this->resource_server_context->getCurrentUser()); return $this->updated(SerializerRegistry::getInstance()->getSerializer($promo_code)->serialize()); @@ -458,7 +458,7 @@ final class OAuth2SummitPromoCodesApiController extends OAuth2ProtectedControlle $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $this->promo_code_service->deletePromoCode($summit, $promo_code_id); + $this->promo_code_service->deletePromoCode($summit, intval($promo_code_id)); return $this->deleted(); } catch (ValidationException $ex1) { @@ -483,8 +483,8 @@ final class OAuth2SummitPromoCodesApiController extends OAuth2ProtectedControlle try { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $mail_request = $this->promo_code_service->sendPromoCodeMail($summit, $promo_code_id); - return $this->created($mail_request->getId()); + $this->promo_code_service->sendPromoCodeMail($summit, intval($promo_code_id)); + return $this->ok(); } catch (ValidationException $ex1) { Log::warning($ex1); return $this->error412(array($ex1->getMessage())); @@ -507,7 +507,7 @@ final class OAuth2SummitPromoCodesApiController extends OAuth2ProtectedControlle try { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $promo_code = $summit->getPromoCodeById($promo_code_id); + $promo_code = $summit->getPromoCodeById(intval($promo_code_id)); if(is_null($promo_code)) return $this->error404(); return $this->ok(SerializerRegistry::getInstance()->getSerializer($promo_code)->serialize( Request::input('expand', ''))); @@ -523,4 +523,125 @@ final class OAuth2SummitPromoCodesApiController extends OAuth2ProtectedControlle } } + /** + * @param $summit_id + * @param $promo_code_id + * @param $badge_feature_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addBadgeFeatureToPromoCode($summit_id, $promo_code_id, $badge_feature_id){ + + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $promo_code = $this->promo_code_service->addPromoCodeBadgeFeature($summit, intval($promo_code_id), intval($badge_feature_id)); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($promo_code)->serialize( 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 $summit_id + * @param $promo_code_id + * @param $badge_feature_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeBadgeFeatureFromPromoCode($summit_id, $promo_code_id, $badge_feature_id){ + + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $promo_code = $this->promo_code_service->removePromoCodeBadgeFeature($summit, intval($promo_code_id), intval($badge_feature_id)); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($promo_code)->serialize( 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 $summit_id + * @param $promo_code_id + * @param $ticket_type_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addTicketTypeToPromoCode($summit_id, $promo_code_id, $ticket_type_id){ + + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $payload = []; + if (Request::isJson()) { + $data = Input::json(); + $payload = $data->all(); + $discount_code_rules = [ + 'amount' => 'sometimes|required_without:rate|numeric|min:0', + 'rate' => 'sometimes|required_without:amount|numeric|min:0', + ]; + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $discount_code_rules); + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + return $this->error412 + ( + $messages + ); + } + } + + $promo_code = $this->promo_code_service->addPromoCodeTicketTypeRule($summit, intval($promo_code_id), intval($ticket_type_id), $payload); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($promo_code)->serialize( 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 $summit_id + * @param $promo_code_id + * @param $ticket_type_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeTicketTypeFromPromoCode($summit_id, $promo_code_id, $ticket_type_id){ + + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $promo_code = $this->promo_code_service->removePromoCodeTicketTypeRule($summit, intval($promo_code_id), intval($ticket_type_id)); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($promo_code)->serialize( 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); + } + } + } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRefundPolicyTypeApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRefundPolicyTypeApiController.php new file mode 100644 index 00000000..06ee8693 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRefundPolicyTypeApiController.php @@ -0,0 +1,161 @@ +summit_repository = $summit_repository; + $this->service = $service; + $this->repository = $repository; + } + + use GetAllBySummit; + + use GetSummitChildElementById; + + use AddSummitChildElement; + + use UpdateSummitChildElement; + + use DeleteSummitChildElement; + + /** + * @param array $payload + * @return array + */ + function getAddValidationRules(array $payload): array + { + return SummitRefundPolicyTypeValidationRulesFactory::build($payload); + } + + /** + * @param array $payload + * @return array + */ + function getUpdateValidationRules(array $payload): array + { + return SummitRefundPolicyTypeValidationRulesFactory::build($payload, true); + } + + /** + * @return array + */ + protected function getFilterRules():array + { + return [ + 'name' => ['=@', '=='], + 'until_x_days_before_event_starts' => ['>=', '==', '>', '>=', '<', '<='], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'name' => 'sometimes|required|string', + ]; + } + + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'name', + 'until_x_days_before_event_starts', + ]; + } + + /** + * @param Summit $summit + * @param array $payload + * @return IEntity + * @throws \models\exceptions\EntityNotFoundException + * @throws \models\exceptions\ValidationException + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->addPolicy($summit, $payload); + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @param Summit $summit + * @param $child_id + * @return void + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deletePolicy($summit, $child_id); + } + + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getRefundPolicyById($child_id); + } + + /** + * @param Summit $summit + * @param int $child_id + * @param array $payload + * @return IEntity + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updatePolicy($summit, $child_id, $payload); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRegistrationInvitationApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRegistrationInvitationApiController.php new file mode 100644 index 00000000..67e20f8d --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitRegistrationInvitationApiController.php @@ -0,0 +1,474 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + /** + * @param LaravelRequest $request + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function ingestInvitations(LaravelRequest $request, $summit_id){ + + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $file = $request->file('file'); + if (is_null($file)) { + return $this->error412(array('file param not set!')); + } + + $this->service->importInvitationData($summit, $file); + return $this->ok(); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $token + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getInvitationByToken($token){ + + try { + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $invitation = $this->service->getInvitationByToken($current_member, $token); + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($invitation)->serialize(Request::input('expand', ''))); + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $email + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getByEmail($summit_id, $email){ + + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $invitation = $this->service->getInvitationByEmail($summit,$email); + if(is_null($invitation)) + throw new EntityNotFoundException(); + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($invitation)->serialize(Request::input('expand', ''))); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + // traits + use ParametrizedGetAll; + + use GetSummitChildElementById; + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @inheritDoc + */ + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getSummitRegistrationInvitationById($child_id); + } + + /** + * @param $summit_id + * @return mixed + */ + public function getAllBySummit($summit_id){ + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAll( + function(){ + return [ + 'email' => ['=@', '=='], + 'first_name' => ['=@', '=='], + 'last_name' => ['=@', '=='], + 'is_accepted' => ['=='], + 'is_sent' => ['=='], + ]; + }, + function(){ + return [ + 'email' => 'sometimes|required|string', + 'first_name' => 'sometimes|required|string', + 'last_name' => 'sometimes|required|string', + 'is_accepted' => 'sometimes|required|string|in:true,false', + 'is_sent' => 'sometimes|required|string|in:true,false', + ]; + }, + function() + { + return [ + 'id', + 'email', + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_Public; + } + ); + } + + /** + * @param $summit_id + * @return mixed + */ + public function getAllBySummitCSV($summit_id){ + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAllCSV( + function(){ + return [ + 'email' => ['=@', '=='], + 'first_name' => ['=@', '=='], + 'last_name' => ['=@', '=='], + 'is_accepted' => ['=='], + 'is_sent' => ['=='], + ]; + }, + function(){ + return [ + 'email' => 'sometimes|required|string', + 'first_name' => 'sometimes|required|string', + 'last_name' => 'sometimes|required|string', + 'is_accepted' => 'sometimes|required|string|in:true,false', + 'is_sent' => 'sometimes|required|string|in:true,false', + ]; + }, + function() + { + return [ + 'id', + 'email', + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_CSV; + }, + function(){ + return [ + 'accepted_date' => new EpochCellFormatter(), + 'is_accepted' => new BooleanCellFormatter(), + 'is_sent' => new BooleanCellFormatter(), + ]; + }, + function(){ + + $allowed_columns = [ + 'id', + 'email', + 'first_name', + 'last_name', + 'member_id', + 'order_id', + 'summit_id', + 'accepted_date', + 'is_accepted', + 'is_sent', + ]; + + $columns_param = Input::get("columns", ""); + $columns = []; + if(!empty($columns_param)) + $columns = explode(',', $columns_param); + $diff = array_diff($columns, $allowed_columns); + if(count($diff) > 0){ + throw new ValidationException(sprintf("columns %s are not allowed!", implode(",", $diff))); + } + if(empty($columns)) + $columns = $allowed_columns; + return $columns; + }, + 'summit-registration-invitations-' + ); + } + + + use DeleteSummitChildElement; + + /** + * @inheritDoc + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->delete($summit, $child_id); + } + + use AddSummitChildElement; + + /** + * @inheritDoc + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->add($summit, $payload); + } + + /** + * @inheritDoc + */ + function getAddValidationRules(array $payload): array + { + return [ + 'email' => 'required|email|max:255', + 'first_name' => 'required|string|max:255', + 'last_name' => 'required|string|max:255', + ]; + } + + use UpdateSummitChildElement; + + /** + * @inheritDoc + */ + function getUpdateValidationRules(array $payload): array + { + return [ + 'email' => 'sometimes|email|max:255', + 'first_name' => 'sometimes|string|max:255', + 'last_name' => 'sometimes|string|max:255', + ]; + } + + /** + * @inheritDoc + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->update($summit, $child_id, $payload); + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function deleteAll($summit_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + $this->service->deleteAll($summit); + return $this->deleted(); + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function send($summit_id){ + try { + + if(!Request::isJson()) return $this->error400(); + $data = Input::json(); + + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $data->all(); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, [ + 'email_flow_event' => 'required|string|in:'.join(',', [ + InviteSummitRegistrationEmail::EVENT_SLUG, + ReInviteSummitRegistrationEmail::EVENT_SLUG, + ]), + 'invitations_ids' => 'sometimes|int_array', + ]); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $filter = null; + + if (Input::has('filter')) { + $filter = FilterParser::parse(Input::get('filter'), [ + 'is_accepted' => ['=='], + 'is_sent' => ['=='], + ]); + } + + if (is_null($filter)) + $filter = new Filter(); + + $filter->validate([ + 'is_accepted' => 'sometimes|required|string|in:true,false', + 'is_sent' => 'sometimes|required|string|in:true,false', + ]); + + $this->service->triggerSend($summit, $payload, Input::get('filter')); + + return $this->ok(); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSelectionPlansApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSelectionPlansApiController.php index 9bbd820e..1bdd8290 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSelectionPlansApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSelectionPlansApiController.php @@ -73,14 +73,14 @@ final class OAuth2SummitSelectionPlansApiController extends OAuth2ProtectedContr return $this->ok(SerializerRegistry::getInstance()->getSerializer($selection_plan)->serialize(Request::input('expand', ''))); } - catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412([$ex1->getMessage()]); + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); } - catch(EntityNotFoundException $ex2) + catch(EntityNotFoundException $ex) { - Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); + Log::warning($ex); + return $this->error404($ex->getMessage()); } catch (Exception $ex) { Log::error($ex); @@ -119,14 +119,14 @@ final class OAuth2SummitSelectionPlansApiController extends OAuth2ProtectedContr return $this->updated(SerializerRegistry::getInstance()->getSerializer($selection_plan)->serialize()); } - catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412([$ex1->getMessage()]); + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); } - catch(EntityNotFoundException $ex2) + catch(EntityNotFoundException $ex) { - Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); + Log::warning($ex); + return $this->error404($ex->getMessage()); } catch (Exception $ex) { Log::error($ex); @@ -164,14 +164,14 @@ final class OAuth2SummitSelectionPlansApiController extends OAuth2ProtectedContr return $this->created(SerializerRegistry::getInstance()->getSerializer($selection_plan)->serialize()); } - catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412([$ex1->getMessage()]); + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); } - catch(EntityNotFoundException $ex2) + catch(EntityNotFoundException $ex) { - Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); + Log::warning($ex); + return $this->error404($ex->getMessage()); } catch (Exception $ex) { Log::error($ex); @@ -194,14 +194,14 @@ final class OAuth2SummitSelectionPlansApiController extends OAuth2ProtectedContr return $this->deleted(); } - catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412([$ex1->getMessage()]); + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); } - catch(EntityNotFoundException $ex2) + catch(EntityNotFoundException $ex) { - Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); + Log::warning($ex); + return $this->error404($ex->getMessage()); } catch (Exception $ex) { Log::error($ex); @@ -225,14 +225,14 @@ final class OAuth2SummitSelectionPlansApiController extends OAuth2ProtectedContr return $this->deleted(); } - catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412([$ex1->getMessage()]); + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); } - catch(EntityNotFoundException $ex2) + catch(EntityNotFoundException $ex) { - Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); + Log::warning($ex); + return $this->error404($ex->getMessage()); } catch (Exception $ex) { Log::error($ex); @@ -256,14 +256,14 @@ final class OAuth2SummitSelectionPlansApiController extends OAuth2ProtectedContr return $this->deleted(); } - catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412([$ex1->getMessage()]); + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); } - catch(EntityNotFoundException $ex2) + catch(EntityNotFoundException $ex) { - Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); + Log::warning($ex); + return $this->error404($ex->getMessage()); } catch (Exception $ex) { Log::error($ex); @@ -272,26 +272,30 @@ final class OAuth2SummitSelectionPlansApiController extends OAuth2ProtectedContr } /** - * @param string $status - * @return mixed + * @param $summit_id + * @param $status + * @return \Illuminate\Http\JsonResponse|mixed */ - public function getCurrentSelectionPlanByStatus($status){ + public function getCurrentSelectionPlanByStatus($summit_id, $status){ try { - $selection_plan = $this->selection_plan_service->getCurrentSelectionPlanByStatus($status); + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $selection_plan = $this->selection_plan_service->getCurrentSelectionPlanByStatus($summit, $status); if (is_null($selection_plan)) return $this->error404(); return $this->ok(SerializerRegistry::getInstance()->getSerializer($selection_plan)->serialize(Request::input('expand', ''))); } - catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412([$ex1->getMessage()]); + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); } - catch(EntityNotFoundException $ex2) + catch(EntityNotFoundException $ex) { - Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); + Log::warning($ex); + return $this->error404($ex->getMessage()); } catch (Exception $ex) { Log::error($ex); diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersApiController.php index 85077ef7..a016892a 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersApiController.php @@ -31,10 +31,6 @@ use ModelSerializers\ISerializerTypeSelector; use ModelSerializers\SerializerRegistry; use services\model\ISpeakerService; use services\model\ISummitService; -use utils\Filter; -use utils\FilterElement; -use utils\FilterParser; -use utils\OrderParser; use utils\PagingInfo; use Illuminate\Http\Request as LaravelRequest; use utils\PagingResponse; @@ -191,6 +187,72 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController ); } + /** + * @param $summit_id + * @return mixed + */ + public function getSpeakersOnSchedule($summit_id) + { + $summit = SummitFinderStrategyFactory::build($this->getRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAll( + function(){ + return [ + 'first_name' => ['=@', '=='], + 'last_name' => ['=@', '=='], + 'email' => ['=@', '=='], + 'id' => ['=='], + 'full_name' => ['=@', '=='], + 'event_start_date' => ['>', '<', '<=', '>=', '=='], + 'event_end_date' => ['>', '<', '<=', '>=', '=='], + ]; + }, + function(){ + return [ + 'first_name' => 'sometimes|string', + 'last_name' => 'sometimes|string', + 'email' => 'sometimes|string', + 'id' => 'sometimes|integer', + 'full_name' => 'sometimes|string', + 'event_start_date' => 'sometimes|date_format:U', + 'event_end_date' => 'sometimes|date_format:U', + ]; + }, + function() + { + return [ + 'first_name', + 'last_name', + 'id', + 'email', + ]; + }, + function($filter) use($summit){ + return $filter; + }, + function(){ + return $this->serializer_type_selector->getSerializerType(); + }, + null, + null, + function ($page, $per_page, $filter, $order, $applyExtraFilters) use($summit) { + return $this->speaker_repository->getSpeakersBySummitAndOnSchedule + ( + $summit, + new PagingInfo($page, $per_page), + call_user_func($applyExtraFilters, $filter), + $order + ); + }, + [ + 'summit_id' => $summit_id, + 'published' => true, + 'summit' => $summit + ] + ); + } + /** * get all speakers without summit * @return mixed @@ -500,7 +562,7 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController 'irc' => 'sometimes|string|max:50', 'twitter' => 'sometimes|string|max:50', 'member_id' => 'sometimes|integer', - 'email' => 'sometimes|email:rfc,dns|max:50', + 'email' => 'sometimes|email:rfc|max:50', 'on_site_phone' => 'sometimes|string|max:50', 'registered' => 'sometimes|boolean', 'is_confirmed' => 'sometimes|boolean', @@ -579,7 +641,7 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController 'irc' => 'sometimes|string|max:50', 'twitter' => 'sometimes|string|max:50', 'member_id' => 'sometimes|integer', - 'email' => 'sometimes|email:rfc,dns|max:50', + 'email' => 'sometimes|email:rfc|max:50', 'on_site_phone' => 'sometimes|string|max:50', 'registered' => 'sometimes|boolean', 'is_confirmed' => 'sometimes|boolean', @@ -655,50 +717,6 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController } } - /** - * @param LaravelRequest $request - * @param $speaker_id - * @return mixed - */ - public function addSpeakerPhoto(LaravelRequest $request, $speaker_id) - { - - try { - - $current_member = $this->resource_server_context->getCurrentUser(); - if (is_null($current_member)) return $this->error403(); - - $speaker = $this->speaker_repository->getById($speaker_id); - if (is_null($speaker)) return $this->error404(); - - if(!$speaker->canBeEditedBy($current_member)){ - return $this->error403(); - } - - $file = $request->file('file'); - if (is_null($file)) { - return $this->error412(array('file param not set!')); - } - - $photo = $this->service->addSpeakerPhoto($speaker_id, $file); - - return $this->created(SerializerRegistry::getInstance()->getSerializer($photo)->serialize()); - - } catch (EntityNotFoundException $ex1) { - Log::warning($ex1); - return $this->error404(); - } catch (ValidationException $ex2) { - Log::warning($ex2); - return $this->error412(array($ex2->getMessage())); - } catch (\HTTP401UnauthorizedException $ex3) { - Log::warning($ex3); - return $this->error401(); - } catch (Exception $ex) { - Log::error($ex); - return $this->error500($ex); - } - } - /** * @param $speaker_from_id * @param $speaker_to_id @@ -752,7 +770,7 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController 'irc' => 'sometimes|string|max:50', 'twitter' => 'sometimes|string|max:50', 'member_id' => 'sometimes|integer', - 'email' => 'sometimes|email:rfc,dns|max:50', + 'email' => 'sometimes|email:rfc|max:50', 'funded_travel' => 'sometimes|boolean', 'willing_to_travel' => 'sometimes|boolean', 'willing_to_present_video' => 'sometimes|boolean', @@ -767,6 +785,8 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController 'organizational_roles' => 'sometimes|int_array', 'other_organizational_rol' => 'sometimes|string|max:255', 'active_involvements' => 'sometimes|int_array', + 'company' => 'sometimes|string|max:255', + 'phone_number' => 'sometimes|string|max:255', ]; // Creates a Validator instance and validates the data. @@ -831,7 +851,7 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController 'irc' => 'sometimes|string|max:50', 'twitter' => 'sometimes|string|max:50', 'member_id' => 'sometimes|integer', - 'email' => 'sometimes|email:rfc,dns|max:50', + 'email' => 'sometimes|email:rfc|max:50', 'available_for_bureau' => 'sometimes|boolean', 'funded_travel' => 'sometimes|boolean', 'willing_to_travel' => 'sometimes|boolean', @@ -846,6 +866,8 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController 'organizational_roles' => 'sometimes|int_array', 'other_organizational_rol' => 'sometimes|string|max:255', 'active_involvements' => 'sometimes|int_array', + 'company' => 'sometimes|string|max:255', + 'phone_number' => 'sometimes|string|max:255', ]; // Creates a Validator instance and validates the data. @@ -1214,4 +1236,149 @@ final class OAuth2SummitSpeakersApiController extends OAuth2ProtectedController } } + /** + * @param LaravelRequest $request + * @param $speaker_id + * @return mixed + */ + public function addSpeakerPhoto(LaravelRequest $request, $speaker_id) + { + try { + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $speaker = $this->speaker_repository->getById($speaker_id); + if (is_null($speaker)) return $this->error404(); + + if(!$speaker->canBeEditedBy($current_member)){ + return $this->error403(); + } + + $file = $request->file('file'); + if (is_null($file)) { + return $this->error412(array('file param not set!')); + } + + $photo = $this->service->addSpeakerPhoto($speaker_id, $file); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($photo)->serialize()); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + public function deleteSpeakerPhoto($speaker_id){ + try { + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $speaker = $this->speaker_repository->getById($speaker_id); + if (is_null($speaker)) return $this->error404(); + + if(!$speaker->canBeEditedBy($current_member)){ + return $this->error403(); + } + + $this->service->deleteSpeakerPhoto($speaker_id); + + return $this->deleted(); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + public function addSpeakerBigPhoto(LaravelRequest $request, $speaker_id){ + try { + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $speaker = $this->speaker_repository->getById($speaker_id); + if (is_null($speaker)) return $this->error404(); + + if(!$speaker->canBeEditedBy($current_member)){ + return $this->error403(); + } + + $file = $request->file('file'); + if (is_null($file)) { + return $this->error412(array('file param not set!')); + } + + $photo = $this->service->addSpeakerBigPhoto($speaker_id, $file); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($photo)->serialize()); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + public function deleteSpeakerBigPhoto($speaker_id){ + try { + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $speaker = $this->speaker_repository->getById($speaker_id); + if (is_null($speaker)) return $this->error404(); + + if(!$speaker->canBeEditedBy($current_member)){ + return $this->error403(); + } + + $this->service->deleteSpeakerBigPhoto($speaker_id); + + return $this->deleted(); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } 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/OAuth2SummitSpeakersAssistanceApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersAssistanceApiController.php index 65c91354..2654bada 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersAssistanceApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSpeakersAssistanceApiController.php @@ -412,8 +412,8 @@ final class OAuth2SummitSpeakersAssistanceApiController extends OAuth2ProtectedC $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $mail_request = $this->service->sendSpeakerSummitAssistanceAnnouncementMail($summit, $assistance_id); - return $this->created($mail_request->getId()); + $this->service->sendSpeakerSummitAssistanceAnnouncementMail($summit, $assistance_id); + return $this->created(); } catch (ValidationException $ex1) { Log::warning($ex1); diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorApiController.php new file mode 100644 index 00000000..cbde6e80 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorApiController.php @@ -0,0 +1,224 @@ +summit_repository = $summit_repository; + $this->service = $service; + $this->repository = $repository; + } + + + /** + * @return array + */ + protected function getFilterRules():array{ + return [ + 'company_name' => ['==', '=@'], + 'sponsorship_name' => ['==', '=@'], + 'sponsorship_size' => ['==', '=@'], + 'badge_scans_count' => ['==', '<','>','<=','>=','<>'], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'company_name' => 'sometimes|required|string', + 'sponsorship_name' => 'sometimes|required|string', + 'sponsorship_size' => 'sometimes|required|string', + 'badge_scans_count' => 'sometimes|required|integer', + ]; + } + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'order', + ]; + } + + use GetAllBySummit; + + use GetSummitChildElementById; + + use AddSummitChildElement; + + use UpdateSummitChildElement; + + use DeleteSummitChildElement; + + /** + * @param array $payload + * @return array + */ + function getAddValidationRules(array $payload): array + { + return SponsorValidationRulesFactory::build($payload); + } + + /** + * @param Summit $summit + * @param array $payload + * @return IEntity + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->addSponsor($summit, $payload); + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @param Summit $summit + * @param $child_id + * @return void + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deleteSponsor($summit, $child_id); + } + + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getSummitSponsorById($child_id); + } + + /** + * @param array $payload + * @return array + */ + function getUpdateValidationRules(array $payload): array + { + return SponsorValidationRulesFactory::build($payload, true); + } + + /** + * @param Summit $summit + * @param int $child_id + * @param array $payload + * @return IEntity + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updateSponsor($summit, $child_id, $payload); + } + + /** + * @param $summit_id + * @param $sponsor_id + * @param $member_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addSponsorUser($summit_id, $sponsor_id, $member_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $sponsor = $this->service->addSponsorUser($summit, $sponsor_id, $member_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($sponsor)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $sponsor_id + * @param $member_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeSponsorUser($summit_id, $sponsor_id, $member_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $sponsor = $this->service->removeSponsorUser($summit, $sponsor_id, $member_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($sponsor)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTaxTypeApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTaxTypeApiController.php new file mode 100644 index 00000000..052ad581 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTaxTypeApiController.php @@ -0,0 +1,220 @@ + ['=@', '=='], + ]; + } + + /** + * @return array + */ + protected function getFilterValidatorRules():array{ + return [ + 'name' => 'sometimes|required|string', + ]; + } + /** + * @return array + */ + protected function getOrderRules():array{ + return [ + 'id', + 'name', + ]; + } + + public function __construct + ( + ISummitTaxTypeRepository $repository, + ISummitRepository $summit_repository, + ISummitTaxTypeService $service, + IResourceServerContext $resource_server_context + ) + { + parent::__construct($resource_server_context); + $this->repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @param array $payload + * @return array + */ + protected function getAddValidationRules(array $payload): array + { + return TaxTypeValidationRulesFactory::build($payload); + } + + /** + * @param Summit $summit + * @param array $payload + * @return IEntity + * @throws EntityNotFoundException + * @throws ValidationException + */ + protected function addChild(Summit $summit, array $payload): IEntity + { + return $this->service->addTaxType($summit, $payload); + } + + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $summit->getTaxTypeById($child_id); + } + + /** + * @param array $payload + * @return array + */ + function getUpdateValidationRules(array $payload): array + { + return TaxTypeValidationRulesFactory::build($payload, true); + } + + /** + * @param Summit $summit + * @param int $child_id + * @param array $payload + * @return IEntity + * @throws EntityNotFoundException + * @throws ValidationException + */ + protected function updateChild(Summit $summit, int $child_id, array $payload): IEntity + { + return $this->service->updateTaxType($summit, $child_id, $payload); + } + + /** + * @param Summit $summit + * @param $child_id + * @throws EntityNotFoundException + */ + protected function deleteChild(Summit $summit, $child_id): void + { + $this->service->deleteTaxType($summit, $child_id); + } + + /** + * @param $summit_id + * @param $tax_id + * @param $ticket_type_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addTaxToTicketType($summit_id, $tax_id, $ticket_type_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $child = $this->service->addTaxTypeToTicketType($summit, $tax_id, $ticket_type_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($child)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $tax_id + * @param $ticket_type_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeTaxFromTicketType($summit_id, $tax_id, $ticket_type_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $child = $this->service->removeTaxTypeFromTicketType($summit, $tax_id, $ticket_type_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($child)->serialize()); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412(array($ex1->getMessage())); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message'=> $ex2->getMessage())); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTicketApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTicketApiController.php new file mode 100644 index 00000000..50239614 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTicketApiController.php @@ -0,0 +1,693 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->service = $service; + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getAllBySummit($summit_id){ + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAll( + function(){ + return [ + 'number' => ['=@', '=='], + 'order_number' => ['=@', '=='], + 'owner_name' => ['=@', '=='], + 'owner_first_name' => ['=@', '=='], + 'owner_last_name' => ['=@', '=='], + 'owner_email' => ['=@', '=='], + 'owner_company' => ['=@', '=='], + 'summit_id' => ['=='], + 'owner_id' => ['=='], + 'order_id' => ['=='], + 'status' => ['==','<>'], + ]; + }, + function(){ + return [ + 'status' => sprintf('sometimes|in:%s',implode(',', IOrderConstants::ValidStatus)), + 'number' => 'sometimes|string', + 'order_number' => 'sometimes|string', + 'owner_name' => 'sometimes|string', + 'owner_first_name' => 'sometimes|string', + 'owner_last_name' => 'sometimes|string', + 'owner_email' => 'sometimes|string', + 'owner_company' => 'sometimes|string', + 'summit_id' => 'sometimes|integer', + 'owner_id' => 'sometimes|integer', + 'order_id' => 'sometimes|integer', + ]; + }, + function() + { + return [ + 'id', + 'number', + 'status', + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return ISummitAttendeeTicketSerializerTypes::AdminType; + } + ); + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getAllBySummitCSV($summit_id){ + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + return $this->_getAllCSV( + function(){ + return [ + 'number' => ['=@', '=='], + 'order_number' => ['=@', '=='], + 'owner_name' => ['=@', '=='], + 'owner_first_name' => ['=@', '=='], + 'owner_last_name' => ['=@', '=='], + 'owner_email' => ['=@', '=='], + 'owner_company' => ['=@', '=='], + 'summit_id' => ['=='], + 'owner_id' => ['=='], + 'order_id' => ['=='], + 'status' => ['=='], + ]; + }, + function(){ + return [ + 'status' => sprintf('sometimes|in:%s',implode(',', IOrderConstants::ValidStatus)), + 'number' => 'sometimes|string', + 'order_number' => 'sometimes|string', + 'owner_name' => 'sometimes|string', + 'owner_first_name' => 'sometimes|string', + 'owner_last_name' => 'sometimes|string', + 'owner_email' => 'sometimes|string', + 'owner_company' => 'sometimes|string', + 'summit_id' => 'sometimes|integer', + 'owner_id' => 'sometimes|integer', + 'order_id' => 'sometimes|integer', + ]; + }, + function() + { + return [ + 'id', + 'number', + 'status', + ]; + }, + function($filter) use($summit){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit->getId())); + } + return $filter; + }, + function(){ + return SerializerRegistry::SerializerType_CSV; + }, + function(){ + return [ + 'created' => new EpochCellFormatter(), + 'last_edited' => new EpochCellFormatter(), + 'bought_date' => new EpochCellFormatter(), + ]; + }, + function() use($summit){ + $allowed_columns = [ + 'id', + 'created', + 'last_edited', + 'number', + 'status', + 'attendee_id', + 'attendee_first_name', + 'attendee_last_name', + 'attendee_email', + 'attendee_company', + 'external_order_id', + 'external_attendee_id', + 'bought_date', + 'ticket_type_id', + 'ticket_type_name', + 'order_id', + 'badge_id', + 'promo_code_id', + 'promo_code', + 'raw_cost', + 'final_amount', + 'discount', + 'refunded_amount', + 'currency', + 'badge_type_id', + 'badge_type_name', + ]; + + foreach ($summit->getBadgeFeaturesTypes() as $featuresType){ + $allowed_columns[] = $featuresType->getName(); + } + + foreach ($summit->getOrderExtraQuestionsByUsage(SummitOrderExtraQuestionTypeConstants::TicketQuestionUsage) as $question){ + $allowed_columns[] = $question->getLabel(); + } + + $columns_param = Input::get("columns", ""); + $columns = []; + if(!empty($columns_param)) + $columns = explode(',', $columns_param); + $diff = array_diff($columns, $allowed_columns); + if(count($diff) > 0){ + throw new ValidationException(sprintf("columns %s are not allowed!", implode(",", $diff))); + } + if(empty($columns)) + $columns = $allowed_columns; + return $columns; + }, + sprintf('tickets-%s-', $summit_id), + [ + 'features_types' => $summit->getBadgeFeaturesTypes(), + 'ticket_questions' => $summit->getOrderExtraQuestionsByUsage(SummitOrderExtraQuestionTypeConstants::TicketQuestionUsage) + ] + ); + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function ingestExternalTicketData($summit_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $payload = $this->getJsonPayload([ + 'email_to' => 'nullable|email', + ]); + + $this->service->ingestExternalTicketData($summit, $payload); + + return $this->ok(); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getImportTicketDataTemplate($summit_id){ + try { + /** + * id + * number + * attendee_email ( mandatory if id and number are missing) + * attendee_first_name (optional) + * attendee_last_name (optional) + * attendee_company (optional) + * ticket_type_name ( mandatory if id and number are missing) + * ticket_type_id ( mandatory if id and number are missing) + * badge_type_id (optional) + * badge_type_name (optional) + * badge_features (optional) + */ + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $row = [ + 'id' => '', + 'number' => '', + 'attendee_email' => '', + 'attendee_first_name' => '', + 'attendee_last_name' => '', + 'attendee_company' => '', + 'ticket_type_name' => '', + 'ticket_type_id' => '', + 'badge_type_id' => '', + 'badge_type_name' => '', + ]; + + // badge features for summit + foreach ($summit->getBadgeFeaturesTypes() as $featuresType){ + $row[$featuresType->getName()] = '' ; + } + + $template = [ + $row + ]; + + return $this->export + ( + 'csv', + 'ticket-data-import-template', + $template, + [], + [] + ); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param LaravelRequest $request + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function importTicketData(LaravelRequest $request, $summit_id){ + + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $file = $request->file('file'); + if (is_null($file)) { + return $this->error412(array('file param not set!')); + } + + $this->service->importTicketData($summit, $file); + + return $this->ok(); + + } catch (EntityNotFoundException $ex1) { + Log::warning($ex1); + return $this->error404(); + } catch (ValidationException $ex2) { + Log::warning($ex2); + return $this->error412(array($ex2->getMessage())); + } catch (\HTTP401UnauthorizedException $ex3) { + Log::warning($ex3); + return $this->error401(); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @return mixed + */ + public function getAllMyTickets(){ + $owner = $this->getResourceServerContext()->getCurrentUser(); + return $this->_getAll( + function(){ + return [ + 'number' => ['=@', '=='], + 'order_number' => ['=@', '=='], + 'summit_id' => ['=='], + 'order_id' => ['=='], + 'status' => ['==','<>'], + ]; + }, + function(){ + return [ + 'number' => 'sometimes|string', + 'order_number' => 'sometimes|string', + 'summit_id' => 'sometimes|integer', + 'order_id' => 'sometimes|integer', + 'status' => sprintf('sometimes|in:%s',implode(',', IOrderConstants::ValidStatus)), + ]; + }, + function() + { + return [ + 'id', + 'number', + 'status', + ]; + }, + function($filter) use($owner){ + if($filter instanceof Filter){ + $filter->addFilterCondition(FilterElement::makeEqual('member_id', $owner->getId())); + } + return $filter; + }, + function(){ + return ISummitAttendeeTicketSerializerTypes::AdminType; + } + ); + } + + /** + * @return ISummitRepository + */ + protected function getSummitRepository(): ISummitRepository + { + return $this->summit_repository; + } + + /** + * @param Summit $summit + * @param $child_id + * @return IEntity|null + * @throws \Exception + */ + protected function getChildFromSummit(Summit $summit, $child_id): ?IEntity + { + return $this->service->getTicket($summit, $child_id); + } + + /** + * @param $summit_id + * @param $ticket_id + * @return mixed + */ + public function refundTicket($summit_id, $ticket_id) + { + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $this->getJsonPayload([ + 'amount' => 'required|numeric|greater_than:0', + ]); + + $ticket = $this->service->refundTicket($summit, $ticket_id, floatval($payload['amount'])); + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($ticket)->serialize( Request::input('expand', ''))); + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getAttendeeBadge($summit_id, $ticket_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $ticket = is_int($ticket_id) ? $this->repository->getById(intval($ticket_id)) : $this->repository->getByNumber($ticket_id); + if(is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) return $this->error404();; + if($ticket->getOrder()->getSummitId() != $summit->getId()) return $this->error404(); + if(!$ticket->hasBadge()) return $this->error404(); + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($ticket->getBadge())->serialize( Request::input('expand', ''))); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function createAttendeeBadge($summit_id, $ticket_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $this->getJsonPayload([ + 'badge_type_id' => 'sometimes|integer', + 'features' => 'sometimes|int_array', + ]); + + $badge = $this->service->createBadge($summit, $ticket_id, $payload); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($badge)->serialize( Request::input('expand', ''))); + } + catch(\InvalidArgumentException $ex){ + Log::warning($ex); + return $this->error400(); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function deleteAttendeeBadge($summit_id, $ticket_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + $this->service->deleteBadge($summit, $ticket_id); + return $this->deleted(); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $ticket_id + * @param $type_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function updateAttendeeBadgeType($summit_id, $ticket_id, $type_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $badge = $this->service->updateBadgeType($summit, $ticket_id, $type_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($badge)->serialize( Request::input('expand', ''))); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $ticket_id + * @param $feature_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addAttendeeBadgeFeature($summit_id, $ticket_id, $feature_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $badge = $this->service->addAttendeeBadgeFeature($summit, $ticket_id, $feature_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($badge)->serialize( Request::input('expand', ''))); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $ticket_id + * @param $feature_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeAttendeeBadgeFeature($summit_id, $ticket_id, $feature_id){ + try { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $badge = $this->service->removeAttendeeBadgeFeature($summit, $ticket_id, $feature_id); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($badge)->serialize( Request::input('expand', ''))); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $ticket_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function printAttendeeBadge($summit_id, $ticket_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $current_member = $this->resource_server_context->getCurrentUser(); + if (is_null($current_member)) return $this->error403(); + + $badge = $this->service->printAttendeeBadge($summit, $ticket_id, $current_member); + + return $this->updated + ( + SerializerRegistry::getInstance()->getSerializer($badge)->serialize( Request::input('expand', '')) + ); + + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->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/OAuth2SummitTracksApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTracksApiController.php index 04a2148a..fbd5f495 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTracksApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTracksApiController.php @@ -439,6 +439,7 @@ final class OAuth2SummitTracksApiController extends OAuth2ProtectedController 'name' => 'required|string|max:50', 'description' => 'required|string|max:500', 'code' => 'sometimes|string|max:5', + 'color' => 'sometimes|hex_color|max:50', 'session_count' => 'sometimes|integer', 'alternate_count' => 'sometimes|integer', 'lightning_count' => 'sometimes|integer', @@ -537,6 +538,7 @@ final class OAuth2SummitTracksApiController extends OAuth2ProtectedController $rules = [ 'name' => 'sometimes|string|max:50', 'description' => 'sometimes|string|max:500', + 'color' => 'sometimes|hex_color|max:50', 'code' => 'sometimes|string|max:5', 'session_count' => 'sometimes|integer', 'alternate_count' => 'sometimes|integer', diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsEventTypesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsEventTypesApiController.php index f7cadc86..0435c026 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsEventTypesApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsEventTypesApiController.php @@ -494,4 +494,80 @@ final class OAuth2SummitsEventTypesApiController extends OAuth2ProtectedControll return $this->error500($ex); } } + + /** + * @param $summit_id + * @param $event_type_id + * @param $document_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function addSummitDocument($summit_id, $event_type_id, $document_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + + $document = $this->event_type_service->addSummitDocumentToEventType + ( + $summit, + $event_type_id, + $document_id + ); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($document)->serialize()); + } + catch (EntityNotFoundException $ex1) + { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) + { + Log::warning($ex2); + return $this->error412($ex2->getMessages()); + } + catch (\Exception $ex) + { + Log::error($ex); + return $this->error500($ex); + } + } + + /** + * @param $summit_id + * @param $event_type_id + * @param $document_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function removeSummitDocument($summit_id, $event_type_id, $document_id){ + try { + + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + + $document = $this->event_type_service->removeSummitDocumentFromEventType + ( + $summit, + $event_type_id, + $document_id + ); + return $this->updated(SerializerRegistry::getInstance()->getSerializer($document)->serialize()); + } + catch (EntityNotFoundException $ex1) + { + Log::warning($ex1); + return $this->error404(); + } + catch (ValidationException $ex2) + { + Log::warning($ex2); + return $this->error412($ex2->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/Strategies/CurrentSummitFinderStrategy.php b/app/Http/Controllers/Apis/Protected/Summit/Strategies/CurrentSummitFinderStrategy.php index ff013d65..32d9d3d3 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/Strategies/CurrentSummitFinderStrategy.php +++ b/app/Http/Controllers/Apis/Protected/Summit/Strategies/CurrentSummitFinderStrategy.php @@ -12,6 +12,7 @@ * limitations under the License. **/ use App\Http\Utils\FilterAvailableSummitsStrategy; +use function GuzzleHttp\Psr7\str; use models\oauth2\IResourceServerContext; use models\summit\ISummitRepository; use models\summit\Summit; @@ -54,10 +55,8 @@ class CurrentSummitFinderStrategy implements ISummitFinderStrategy public function find($summit_id) { $summit = $summit_id === 'current' ? $this->repository->getCurrent() : $this->repository->getById(intval($summit_id)); - if(is_null($summit)) return null; - $show_all = FilterAvailableSummitsStrategy::shouldReturnAllSummits($this->resource_server_ctx); - if($show_all) return $summit; - if(!$summit->isAvailableOnApi()) return null; + if(is_null($summit)) + $summit = $this->repository->getBySlug(strval($summit_id)); return $summit; } } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Strategies/events/RetrieveAllUnPublishedSummitEventsStrategy.php b/app/Http/Controllers/Apis/Protected/Summit/Strategies/events/RetrieveAllUnPublishedSummitEventsStrategy.php index f9f3218f..2577056d 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/Strategies/events/RetrieveAllUnPublishedSummitEventsStrategy.php +++ b/app/Http/Controllers/Apis/Protected/Summit/Strategies/events/RetrieveAllUnPublishedSummitEventsStrategy.php @@ -30,7 +30,7 @@ class RetrieveAllUnPublishedSummitEventsStrategy extends RetrieveAllSummitEvents protected function getValidFilters() { $valid_filters = parent::getValidFilters(); - $valid_filters['published'] = ['==']; + $valid_filters['published'] = ['==']; return $valid_filters; } diff --git a/app/Http/Controllers/Apis/Protected/Summit/Strategies/events/RetrieveSummitEventsStrategy.php b/app/Http/Controllers/Apis/Protected/Summit/Strategies/events/RetrieveSummitEventsStrategy.php index 2321434d..386d222c 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/Strategies/events/RetrieveSummitEventsStrategy.php +++ b/app/Http/Controllers/Apis/Protected/Summit/Strategies/events/RetrieveSummitEventsStrategy.php @@ -141,6 +141,7 @@ abstract class RetrieveSummitEventsStrategy 'speaker_email' => ['=@', '=='], 'selection_status' => ['=='], 'id' => ['=='], + 'selection_plan_id' => ['=='], ]; } @@ -164,6 +165,7 @@ abstract class RetrieveSummitEventsStrategy 'speaker_id' => 'sometimes|integer', 'location_id' => 'sometimes|integer', 'id' => 'sometimes|integer', + 'selection_plan_id' => 'sometimes|integer', ]; } } \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Traits/AddEntity.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/AddEntity.php new file mode 100644 index 00000000..7d97f116 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/AddEntity.php @@ -0,0 +1,102 @@ +error400(); + $data = Input::json(); + $payload = $data->all(); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $this->getAddValidationRules($payload)); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $fields = Request::input('fields', ''); + $relations = Request::input('relations', ''); + + $relations = !empty($relations) ? explode(',', $relations) : []; + $fields = !empty($fields) ? explode(',', $fields) : []; + + $entity = $this->addEntity($payload); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($entity)->serialize + ( + Request::input('expand', ''), + $fields, + $relations + )); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } + catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Traits/AddSummitChildElement.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/AddSummitChildElement.php new file mode 100644 index 00000000..f736df06 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/AddSummitChildElement.php @@ -0,0 +1,115 @@ +error400(); + $data = Input::json(); + $payload = $data->all(); + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $this->getAddValidationRules($payload)); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $child = $this->addChild($summit, $payload); + + $fields = Request::input('fields', ''); + $relations = Request::input('relations', ''); + + $relations = !empty($relations) ? explode(',', $relations) : []; + $fields = !empty($fields) ? explode(',', $fields) : []; + + return $this->created(SerializerRegistry::getInstance()->getSerializer + ( + $child, + $this->addSerializerType() + )->serialize( + Request::input('expand', ''), + $fields, + $relations + )); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } + catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + +} \ No newline at end of file diff --git a/app/Http/Utils/IBucket.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/BaseSummitAPI.php similarity index 64% rename from app/Http/Utils/IBucket.php rename to app/Http/Controllers/Apis/Protected/Summit/Traits/BaseSummitAPI.php index aaaa82e4..835676b2 100644 --- a/app/Http/Utils/IBucket.php +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/BaseSummitAPI.php @@ -1,6 +1,6 @@ -deleteEntity($id); + return $this->deleted(); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Traits/DeleteSummitChildElement.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/DeleteSummitChildElement.php new file mode 100644 index 00000000..08d8fb55 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/DeleteSummitChildElement.php @@ -0,0 +1,59 @@ +getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $this->deleteChild($summit, $child_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/Traits/GetAll.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/GetAll.php new file mode 100644 index 00000000..ca70b6b0 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/GetAll.php @@ -0,0 +1,146 @@ + 'integer|min:1', + 'per_page' => sprintf('required_with:page|integer|min:%s|max:%s', PagingConstants::MinPageSize, PagingConstants::MaxPageSize), + ]; + + try { + + $validation = Validator::make($values, $rules); + + if ($validation->fails()) { + $ex = new ValidationException(); + throw $ex->setMessages($validation->messages()->toArray()); + } + + // default values + $page = 1; + $per_page = PagingConstants::DefaultPageSize;; + + 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'), $this->getFilterRules()); + } + + if(is_null($filter)) $filter = new Filter(); + + $filter_validator_rules = $this->getFilterValidatorRules(); + if(count($filter_validator_rules)) { + $filter->validate($filter_validator_rules); + } + + $order = null; + + if (Input::has('order')) + { + $order = OrderParser::parse(Input::get('order'), $this->getOrderRules()); + } + + $data = $this->getRepository()->getAllByPage(new PagingInfo($page, $per_page), $this->applyExtraFilters($filter), $order); + + return $this->ok + ( + $data->toArray + ( + Request::input('expand', ''), + [], + [], + [ 'serializer_type' => $this->serializerType() ], + $this->serializerType() + ) + ); + } + catch (ValidationException $ex1) + { + Log::warning($ex1); + return $this->error412(array( $ex1->getMessage())); + } + catch (EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(array('message' => $ex2->getMessage())); + } + catch(\HTTP401UnauthorizedException $ex3) + { + Log::warning($ex3); + return $this->error401(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Traits/GetAllBySummit.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/GetAllBySummit.php new file mode 100644 index 00000000..fb6b77f0 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/GetAllBySummit.php @@ -0,0 +1,49 @@ +addFilterCondition(FilterElement::makeEqual("summit_id", intval($this->summit_id))); + return $filter; + } + + /** + * @param $summit_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getAllBySummit($summit_id){ + $this->summit_id = $summit_id; + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($this->summit_id); + if (is_null($summit)) return $this->error404(); + return $this->getAll(); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Traits/GetEntity.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/GetEntity.php new file mode 100644 index 00000000..1a6ae7f2 --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/GetEntity.php @@ -0,0 +1,73 @@ +getEntity($id); + $fields = Request::input('fields', ''); + $relations = Request::input('relations', ''); + + $relations = !empty($relations) ? explode(',', $relations) : []; + $fields = !empty($fields) ? explode(',', $fields) : []; + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($entity)->serialize( + Request::input('expand', ''), + $fields, + $relations + )); + + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Traits/GetSummitChildElementById.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/GetSummitChildElementById.php new file mode 100644 index 00000000..5ad024ac --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/GetSummitChildElementById.php @@ -0,0 +1,69 @@ +getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + $child = $this->getChildFromSummit($summit, $child_id); + if(is_null($child)) + return $this->error404(); + return $this->ok(SerializerRegistry::getInstance()->getSerializer($child, $this->getChildSerializer())->serialize( Request::input('expand', ''))); + } catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412($ex1->getMessages()); + } catch (EntityNotFoundException $ex2) { + Log::warning($ex2); + return $this->error404(['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/Traits/ParametrizedGetAll.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/ParametrizedGetAll.php index c6a15c1d..162ec885 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/Traits/ParametrizedGetAll.php +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/ParametrizedGetAll.php @@ -12,6 +12,7 @@ * limitations under the License. **/ +use App\Http\Exceptions\HTTP403ForbiddenException; use Illuminate\Support\Facades\Input; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Request; @@ -166,16 +167,24 @@ trait ParametrizedGetAll call_user_func($serializerType) ) ); - } catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412(array($ex1->getMessage())); - } catch (EntityNotFoundException $ex2) { - Log::warning($ex2); - return $this->error404(array('message' => $ex2->getMessage())); - } catch (\HTTP401UnauthorizedException $ex3) { - Log::warning($ex3); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } + catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } + catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); return $this->error401(); - } catch (Exception $ex) { + } + catch(HTTP403ForbiddenException $ex){ + Log::warning($ex); + return $this->error403(); + } + catch (Exception $ex) { Log::error($ex); return $this->error500($ex); } @@ -297,14 +306,14 @@ trait ParametrizedGetAll call_user_func($getFormatters), call_user_func($getColumns) ); - } catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412($ex1->getMessages()); - } catch (EntityNotFoundException $ex2) { - Log::warning($ex2); - return $this->error404(array('message' => $ex2->getMessage())); - } catch (\HTTP401UnauthorizedException $ex3) { - Log::warning($ex3); + } catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412($ex->getMessages()); + } catch (EntityNotFoundException $ex) { + Log::warning($ex); + return $this->error404(array('message' => $ex->getMessage())); + } catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); return $this->error401(); } catch (Exception $ex) { Log::error($ex); diff --git a/app/Http/Controllers/Apis/Protected/Summit/Traits/SummitBookableVenueRoomApi.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/SummitBookableVenueRoomApi.php index df7c6fe3..854e8d90 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/Traits/SummitBookableVenueRoomApi.php +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/SummitBookableVenueRoomApi.php @@ -405,7 +405,7 @@ trait SummitBookableVenueRoomApi * @param $room_id * @return mixed */ - public function getBookableVenueRoom($summit_id, $venue_id, $room_id){ + public function getBookableVenueRoomByVenue($summit_id, $venue_id, $room_id){ try { $expand = Request::input('expand', ''); @@ -415,7 +415,7 @@ trait SummitBookableVenueRoomApi $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); if (is_null($summit)) return $this->error404(); - $venue = $summit->getLocation($venue_id); + $venue = $summit->getLocation(intval($venue_id)); if (is_null($venue)) { return $this->error404(); @@ -425,7 +425,7 @@ trait SummitBookableVenueRoomApi return $this->error404(); } - $room = $venue->getRoom($room_id); + $room = $venue->getRoom(intval($room_id)); if (is_null($room) || !$room instanceof SummitBookableVenueRoom) { return $this->error404(); @@ -448,6 +448,45 @@ trait SummitBookableVenueRoomApi } } + /** + * @param $summit_id + * @param $venue_id + * @param $room_id + * @return mixed + */ + public function getBookableVenueRoom($summit_id, $room_id){ + try { + + $expand = Request::input('expand', ''); + $relations = Request::input('relations', ''); + $relations = !empty($relations) ? explode(',', $relations) : []; + + $summit = SummitFinderStrategyFactory::build($this->repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + + + $room = $summit->getLocation(intval($room_id)); + + if (is_null($room) || !$room instanceof SummitBookableVenueRoom) { + return $this->error404(); + } + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($room)->serialize($expand,[], $relations)); + } + 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 $summit_id * @param $room_id @@ -668,31 +707,6 @@ trait SummitBookableVenueRoomApi } } - /** - * @param LaravelRequest $request - * @return mixed - */ - public function confirmBookableVenueRoomReservation(LaravelRequest $request){ - - if(!Request::isJson()) - return $this->error400(); - - try { - $response = $this->payment_gateway->processCallback($request); - $this->location_service->processBookableRoomPayment($response); - return $this->ok(); - } - catch(EntityNotFoundException $ex){ - Log::warning($ex); - return $this->error400(["error" => 'payload error']); - } - catch (Exception $ex){ - Log::error($ex); - return $this->error400(["error" => 'payload error']); - } - return $this->error400(["error" => 'invalid event type']); - } - /** * @param $summit_id * @param $venue_id diff --git a/app/Http/Controllers/Apis/Protected/Summit/Traits/UpdateEntity.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/UpdateEntity.php new file mode 100644 index 00000000..405b768b --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/UpdateEntity.php @@ -0,0 +1,105 @@ +error400(); + $data = Input::json(); + $payload = $data->all(); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $this->getUpdateValidationRules($payload)); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $entity = $this->updateEntity($id, $payload); + + $fields = Request::input('fields', ''); + $relations = Request::input('relations', ''); + + $relations = !empty($relations) ? explode(',', $relations) : []; + $fields = !empty($fields) ? explode(',', $fields) : []; + + return $this->updated(SerializerRegistry::getInstance()->getSerializer($entity)->serialize + ( + Request::input('expand', ''), + $fields, + $relations + )); + } + catch (ValidationException $ex) { + Log::warning($ex); + return $this->error412(array($ex->getMessage())); + } + catch(EntityNotFoundException $ex) + { + Log::warning($ex); + return $this->error404(array('message'=> $ex->getMessage())); + } + catch (\HTTP401UnauthorizedException $ex) { + Log::warning($ex); + return $this->error401(); + } + catch (HTTP403ForbiddenException $ex) { + Log::warning($ex); + return $this->error403(); + } + catch (Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Apis/Protected/Summit/Traits/UpdateSummitChildElement.php b/app/Http/Controllers/Apis/Protected/Summit/Traits/UpdateSummitChildElement.php new file mode 100644 index 00000000..20e89e4d --- /dev/null +++ b/app/Http/Controllers/Apis/Protected/Summit/Traits/UpdateSummitChildElement.php @@ -0,0 +1,110 @@ +error400(); + $data = Input::json(); + + $summit = SummitFinderStrategyFactory::build($this->getSummitRepository(), $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $payload = $data->all(); + + // Creates a Validator instance and validates the data. + $validation = Validator::make($payload, $this->getUpdateValidationRules($payload)); + + if ($validation->fails()) { + $messages = $validation->messages()->toArray(); + + return $this->error412 + ( + $messages + ); + } + + $child = $this->updateChild($summit, $child_id, $payload); + + $fields = Request::input('fields', ''); + $relations = Request::input('relations', ''); + + $relations = !empty($relations) ? explode(',', $relations) : []; + $fields = !empty($fields) ? explode(',', $fields) : []; + + return $this->updated(SerializerRegistry::getInstance()->getSerializer + ( + $child, + $this->updateSerializerType() + )->serialize( + Request::input('expand', ''), + $fields, + $relations + )); + } + 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/JsonController.php b/app/Http/Controllers/JsonController.php index 9be21cba..43532086 100644 --- a/app/Http/Controllers/JsonController.php +++ b/app/Http/Controllers/JsonController.php @@ -23,8 +23,6 @@ use Illuminate\Support\Facades\Response; abstract class JsonController extends Controller { - protected $log_service; - public function __construct() { } @@ -76,7 +74,8 @@ abstract class JsonController extends Controller */ protected function ok($data = 'ok') { - $res = Response::json($data, 200); + $res = $this->response2XX(200, $data); + //jsonp if (Input::has('callback')) { $res->setCallback(Input::get('callback')); @@ -92,19 +91,33 @@ abstract class JsonController extends Controller protected function error404($data = ['message' => 'Entity Not Found']) { + if(!is_array($data)){ + $data = ['message' => $data]; + } return Response::json($data, 404); } protected function error403($data = ['message' => 'Forbidden']) { + if(!is_array($data)){ + $data = ['message' => $data]; + } return Response::json($data, 403); } protected function error401($data = ['message' => 'You don\'t have access to this item through the API.']) { + if(!is_array($data)){ + $data = ['message' => $data]; + } return Response::json($data, 401); } + protected function response2XX($code = 200, $data = '') + { + return Response::json($data, $code); + } + /** * { * "message": "Validation Failed", @@ -121,6 +134,9 @@ abstract class JsonController extends Controller */ protected function error412($messages) { + if(!is_array($messages)){ + $messages = [$messages]; + } return Response::json(array('message' => 'Validation Failed', 'errors' => $messages), 412); } @@ -145,12 +161,13 @@ abstract class JsonController extends Controller * @param array $columns * @return \Illuminate\Http\Response */ - private function csv($filename, array $items, array $formatters = [], $field_separator = ",", $mime_type = 'application/vnd.ms-excel', array $columns = []){ + protected function csv($filename, array $items, array $formatters = [], $field_separator = ",", $mime_type = 'application/vnd.ms-excel', array $columns = []){ $headers = [ 'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0', 'Content-type' => $mime_type, 'Content-Transfer-Encoding' => 'binary', 'Content-Disposition' => 'attachment; filename='.$filename.".csv", + 'Last-Modified: ' => gmdate('D, d M Y H:i:s').' GMT', 'Expires' => '0', 'Pragma' => 'public', ]; @@ -175,4 +192,23 @@ abstract class JsonController extends Controller $headers ); } + + /** + * @param string $filename + * @param string $content + * @return \Illuminate\Http\Response + */ + protected function pdf(string $filename, string $content){ + $headers = [ + 'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0', + 'Content-type' => "application/pdf", + 'Content-Transfer-Encoding' => 'binary', + 'Content-Disposition' => 'attachment; filename='.basename($filename), + 'Expires' => '0', + 'Last-Modified: ' => gmdate('D, d M Y H:i:s').' GMT', + 'Pragma' => 'public', + ]; + + return Response::make($content, 200, $headers); + } } \ No newline at end of file diff --git a/app/Http/Controllers/OAuth2ProtectedController.php b/app/Http/Controllers/OAuth2ProtectedController.php index 7425b01f..be72a77e 100644 --- a/app/Http/Controllers/OAuth2ProtectedController.php +++ b/app/Http/Controllers/OAuth2ProtectedController.php @@ -54,4 +54,5 @@ abstract class OAuth2ProtectedController extends JsonController { return $this->repository; } + } \ No newline at end of file diff --git a/app/Http/Controllers/PaymentGatewayWebHookController.php b/app/Http/Controllers/PaymentGatewayWebHookController.php new file mode 100644 index 00000000..76b2111c --- /dev/null +++ b/app/Http/Controllers/PaymentGatewayWebHookController.php @@ -0,0 +1,196 @@ +summit_repository = $summit_repository; + $this->resource_server_context = $resource_server_context; + $this->location_service = $location_service; + $this->order_service = $order_service; + $this->default_payment_gateway_strategy = $default_payment_gateway_strategy;; + } + + /** + * @param string $application_type + * @return IProcessPaymentService|null + */ + private function getProcessPaymentService(string $application_type):?IProcessPaymentService { + if($application_type == IPaymentConstants::ApplicationTypeRegistration) + return $this->order_service; + if($application_type == IPaymentConstants::ApplicationTypeBookableRooms) + return $this->location_service; + return null; + } + + /** + * @param $application_type + * @param LaravelRequest $request + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function genericConfirm($application_type, LaravelRequest $request){ + try { + + Log::debug(sprintf("PaymentGatewayWebHookController::genericConfirm application_type %s ", $application_type)); + + // get api + $paymentGatewayApi = $this->default_payment_gateway_strategy->build($application_type); + + if(is_null($paymentGatewayApi)) { + Log::debug(sprintf("PaymentGatewayWebHookController::genericConfirm application_type %s profile payment not found.", $application_type)); + return $this->error412([sprintf("application_type %s profile payment not found.", $application_type)]); + } + + $service = $this->getProcessPaymentService($application_type); + + if(is_null($service)) { + Log::debug(sprintf("PaymentGatewayWebHookController::genericConfirm application_type %s service not found.", $application_type)); + return $this->error412([sprintf("application_type %s service not found.", $application_type)]); + } + + $service->processPayment($paymentGatewayApi->buildPaymentGatewayApi()->processCallback($request)); + + return $this->ok(); + } + catch(EntityNotFoundException $ex){ + Log::warning($ex); + return $this->response2XX(208, ['error' => 'already reported']); + } + catch(ValidationException $ex){ + Log::warning($ex); + return $this->error412(["error" => 'payload error']); + } + catch (Exception $ex){ + Log::error($ex); + return $this->error400(["error" => 'payload error']); + } + return $this->error400(["error" => 'invalid event type']); + } + + /** + * @param $summit_id + * @param $application_type + * @param LaravelRequest $request + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function confirm($summit_id, $application_type, LaravelRequest $request){ + + try { + + Log::debug(sprintf("PaymentGatewayWebHookController::confirm summit %s application_type %s ", $summit_id, $application_type)); + + // get current summit + $summit = SummitFinderStrategyFactory::build + ( + $this->summit_repository, + $this->resource_server_context + )->find($summit_id); + + if (is_null($summit) || !$summit instanceof Summit){ + Log::debug(sprintf("PaymentGatewayWebHookController::confirm summit %s not found.", $summit_id)); + return $this->error412([sprintf("application_type %s summit not found.", $application_type)]); + } + + // get api + $paymentGatewayApi = $summit->getPaymentGateWayPerApp($application_type, $this->default_payment_gateway_strategy); + + if(is_null($paymentGatewayApi)) { + Log::debug(sprintf("PaymentGatewayWebHookController::confirm summit %s profile payment not found.", $summit_id)); + return $this->error412([sprintf("application_type %s summit not found.", $application_type)]); + } + + $service = $this->getProcessPaymentService($application_type); + + if(is_null($service)) { + Log::debug(sprintf("PaymentGatewayWebHookController::confirm summit %s service not found.", $summit_id)); + return $this->error412([sprintf("application_type %s service not found.", $application_type)]); + } + + $service->processPayment($paymentGatewayApi->processCallback($request), $summit); + + return $this->ok(); + } + catch(EntityNotFoundException $ex){ + Log::warning($ex); + return $this->response2XX(208, ['error' => 'already reported']); + } + catch(ValidationException $ex){ + Log::warning($ex); + return $this->error412(["error" => 'payload error']); + } + catch (Exception $ex){ + Log::error($ex); + return $this->error400(["error" => 'payload error']); + } + return $this->error400(["error" => 'invalid event type']); + } + +} \ No newline at end of file diff --git a/app/Http/Middleware/CORSMiddleware.php b/app/Http/Middleware/CORSMiddleware.php index 3e36dd5a..8343e6ae 100644 --- a/app/Http/Middleware/CORSMiddleware.php +++ b/app/Http/Middleware/CORSMiddleware.php @@ -1,16 +1,16 @@ endpoint_repository = $endpoint_repository; - $this->cache_service = $cache_service; - $this->allowed_headers = Config::get('cors.allowed_headers', self::DefaultAllowedHeaders); - $this->allowed_methods = Config::get('cors.allowed_methods', self::DefaultAllowedMethods); - } + public function __construct(IApiEndpointRepository $endpoint_repository, ICacheService $cache_service) + { + $this->endpoint_repository = $endpoint_repository; + $this->cache_service = $cache_service; + $this->allowed_headers = Config::get('cors.allowed_headers', self::DefaultAllowedHeaders); + $this->allowed_methods = Config::get('cors.allowed_methods', self::DefaultAllowedMethods); + } - /** - * Handle an incoming request. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed - */ - public function handle($request, Closure $next) - { - if ($response = $this->preProcess($request)) - { - return $response; - } - //normal processing - $response = $next($request); - $this->postProcess($request, $response); - return $response; - } + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle($request, Closure $next) + { + if ($response = $this->preProcess($request)) + { + return $response; + } + //normal processing + $response = $next($request); + $this->postProcess($request, $response); + return $response; + } - private function generatePreflightCacheKey($request) - { - $cache_id = 'pre-flight-'. $request->getClientIp(). '-' . $request->getRequestUri(). '-' . $request->getMethod(); - return $cache_id; - } + private function generatePreflightCacheKey($request) + { + $cache_id = 'pre-flight-'. $request->getClientIp(). '-' . $request->getRequestUri(). '-' . $request->getMethod(); + return $cache_id; + } - /** - * @param Request $request - * @return Response - */ - public function preProcess(Request $request) - { - $actual_request = false; + /** + * @param Request $request + * @return Response + */ + public function preProcess(Request $request) + { + $actual_request = false; - if ($this->isValidCORSRequest($request)) - { - if (!$this->testOriginHeaderScrutiny($request)) - { - $response = new Response(); - $response->setStatusCode(403); - return $response; - } - /* Step 01 : Determine the type of the incoming request */ - $type = $this->getRequestType($request); - /* Step 02 : Process request according to is type */ - switch($type) - { - case CORSRequestPreflightType::REQUEST_FOR_PREFLIGHT: - { - // HTTP request send by client to preflight a further 'Complex' request - // sets the original method on request in order to be able to find the - // correct route - $real_method = $request->headers->get('Access-Control-Request-Method'); - $request->setMethod($real_method); + if ($this->isValidCORSRequest($request)) + { + /* Step 01 : Determine the type of the incoming request */ + $type = $this->getRequestType($request); + /* Step 02 : Process request according to is type */ + switch($type) + { + case CORSRequestPreflightType::REQUEST_FOR_PREFLIGHT: + { + // HTTP request send by client to preflight a further 'Complex' request + // sets the original method on request in order to be able to find the + // correct route + $real_method = $request->headers->get('Access-Control-Request-Method'); + $request->setMethod($real_method); - $route_path = RequestUtils::getCurrentRoutePath($request); - if (!$route_path || !$this->checkEndPoint($route_path, $real_method)) - { - $response = new Response(); - $response->setStatusCode(403); - return $response; - } - // ----Step 2b: Store pre-flight request data in the Cache to keep (mark) the request as correctly followed the request pre-flight process - $data = new CORSRequestPreflightData($request, $this->current_endpoint->isAllowCredentials()); - $cache_id = $this->generatePreflightCacheKey($request); - $this->cache_service->storeHash($cache_id, $data->toArray(), CORSRequestPreflightData::$cache_lifetime); - // ----Step 2c: Return corresponding response - This part should be customized with application specific constraints..... - return $this->makePreflightResponse($request); - } - break; - case CORSRequestPreflightType::COMPLEX_REQUEST: - { - $cache_id = $this->generatePreflightCacheKey($request); - // ----Step 2a: Check if the current request has an entry into the preflighted requests Cache - $data = $this->cache_service->getHash($cache_id, CORSRequestPreflightData::$cache_attributes); - if (!count($data)) - { - // there wasnt preflight so just regular processing - return null; - } - // ----Step 2b: Check that pre-flight information declared during the pre-flight request match the current request on key information - $match = false; - // ------Start with comparison of "Origin" HTTP header (according to utility method impl. used to retrieve header reference cannot be null)... - if ($request->headers->get('Origin') === $data['origin']) - { - // ------Continue with HTTP method... - if ($request->getMethod() === $data['expected_method']) - { - // ------Finish with custom HTTP headers (use an method to avoid manual iteration on collection to increase the speed)... - $x_headers = self::getCustomHeaders($request); - $x_headers_pre = explode(',', $data['expected_custom_headers']); - sort($x_headers); - sort($x_headers_pre); - if (count(array_diff($x_headers, $x_headers_pre)) === 0) - { - $match = true; - } - } - } - if (!$match) - { - $response = new Response(); - $response->setStatusCode(403); - return $response; - } - $actual_request = true; - } - break; - case CORSRequestPreflightType::SIMPLE_REQUEST: - { - // origins, do not set any additional headers and terminate this set of steps. - if (!$this->isAllowedOrigin($request)) { - $response = new Response(); - $response->setStatusCode(403); + $route_path = RequestUtils::getCurrentRoutePath($request); + if (!$route_path || !$this->checkEndPoint($route_path, $real_method)) + { + $response = new Response(); + $response->setStatusCode(403); + return $response; + } + // ----Step 2b: Store pre-flight request data in the Cache to keep (mark) the request as correctly followed the request pre-flight process + $data = new CORSRequestPreflightData($request, $this->current_endpoint->isAllowCredentials()); + $cache_id = $this->generatePreflightCacheKey($request); + $this->cache_service->storeHash($cache_id, $data->toArray(), CORSRequestPreflightData::$cache_lifetime); + // ----Step 2c: Return corresponding response - This part should be customized with application specific constraints..... + return $this->makePreflightResponse($request); + } + break; + case CORSRequestPreflightType::COMPLEX_REQUEST: + { + $cache_id = $this->generatePreflightCacheKey($request); + // ----Step 2a: Check if the current request has an entry into the preflighted requests Cache + $data = $this->cache_service->getHash($cache_id, CORSRequestPreflightData::$cache_attributes); + if (!count($data)) + { + // there wasnt preflight so just regular processing + return null; + } + // ----Step 2b: Check that pre-flight information declared during the pre-flight request match the current request on key information + $match = false; + // ------Start with comparison of "Origin" HTTP header (according to utility method impl. used to retrieve header reference cannot be null)... + if ($request->headers->get('Origin') === $data['origin']) + { + // ------Continue with HTTP method... + if ($request->getMethod() === $data['expected_method']) + { + // ------Finish with custom HTTP headers (use an method to avoid manual iteration on collection to increase the speed)... + $x_headers = self::getCustomHeaders($request); + $x_headers_pre = explode(',', $data['expected_custom_headers']); + sort($x_headers); + sort($x_headers_pre); + if (count(array_diff($x_headers, $x_headers_pre)) === 0) + { + $match = true; + } + } + } + if (!$match) + { + $response = new Response(); + $response->setStatusCode(403); + return $response; + } + $actual_request = true; + } + break; + case CORSRequestPreflightType::SIMPLE_REQUEST: + { + // origins, do not set any additional headers and terminate this set of steps. + if (!$this->isAllowedOrigin($request)) { + $response = new Response(); + $response->setStatusCode(403); - return $response; - } - $actual_request = true; - // If the resource supports credentials add a single Access-Control-Allow-Origin header, with the value - // of the Origin header as value, and add a single Access-Control-Allow-Credentials header with the - // case-sensitive string "true" as value. - // Otherwise, add a single Access-Control-Allow-Origin header, with either the value of the Origin header - // or the string "*" as value. - } - break; - } - } - if ($actual_request) - { - // Save response headers - $cache_id = $this->generatePreflightCacheKey($request); - // ----Step 2a: Check if the current request has an entry into the preflighted requests Cache - $data = $this->cache_service->getHash($cache_id, CORSRequestPreflightData::$cache_attributes); - $this->headers['Access-Control-Allow-Origin'] = $request->headers->get('Origin'); - if (isset($data['allows_credentials']) && $data['allows_credentials'] == true) - { - $this->headers['Access-Control-Allow-Credentials'] = 'true'; - } - /** - * During a CORS request, the getResponseHeader() method can only access simple response headers. - * Simple response headers are defined as follows: - ** Cache-Control - ** Content-Language - ** Content-Type - ** Expires - ** Last-Modified - ** Pragma - * If you want clients to be able to access other headers, - * you have to use the Access-Control-Expose-Headers header. - * The value of this header is a comma-delimited list of response headers you want to expose - * to the client. - */ - $exposed_headers = Config::get('cors.exposed_headers', 'Content-Type, Expires'); - if (!empty($exposed_headers)) - { - $this->headers['Access-Control-Expose-Headers'] = $exposed_headers ; - } - } - } + return $response; + } + $actual_request = true; + // If the resource supports credentials add a single Access-Control-Allow-Origin header, with the value + // of the Origin header as value, and add a single Access-Control-Allow-Credentials header with the + // case-sensitive string "true" as value. + // Otherwise, add a single Access-Control-Allow-Origin header, with either the value of the Origin header + // or the string "*" as value. + } + break; + } + } + if ($actual_request) + { + // Save response headers + $cache_id = $this->generatePreflightCacheKey($request); + // ----Step 2a: Check if the current request has an entry into the preflighted requests Cache + $data = $this->cache_service->getHash($cache_id, CORSRequestPreflightData::$cache_attributes); + $this->headers['Access-Control-Allow-Origin'] = $request->headers->get('Origin'); + if (isset($data['allows_credentials']) && $data['allows_credentials'] == true) + { + $this->headers['Access-Control-Allow-Credentials'] = 'true'; + } + /** + * During a CORS request, the getResponseHeader() method can only access simple response headers. + * Simple response headers are defined as follows: + ** Cache-Control + ** Content-Language + ** Content-Type + ** Expires + ** Last-Modified + ** Pragma + * If you want clients to be able to access other headers, + * you have to use the Access-Control-Expose-Headers header. + * The value of this header is a comma-delimited list of response headers you want to expose + * to the client. + */ + $exposed_headers = Config::get('cors.exposed_headers', 'Content-Type, Expires'); + if (!empty($exposed_headers)) + { + $this->headers['Access-Control-Expose-Headers'] = $exposed_headers ; + } + } + } - public function postProcess(Request $request, Response $response) - { - // add CORS response headers - if (count($this->headers) > 0) - { - $response->headers->add($this->headers); - } - return $response; - } + public function postProcess(Request $request, Response $response) + { + // add CORS response headers + if (count($this->headers) > 0) + { + $response->headers->add($this->headers); + } + return $response; + } - /** - * @param Request $request - * @return Response - */ - private function makePreflightResponse(Request $request) - { - $response = new Response(); - if (!$this->isAllowedOrigin($request)) - { - $response->headers->set('Access-Control-Allow-Origin', 'null'); - $response->setStatusCode(403); - return $response; - } - $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin')); - // The Access-Control-Request-Method header indicates which method will be used in the actual - // request as part of the preflight request - // check request method - if ($request->headers->get('Access-Control-Request-Method') != $this->current_endpoint->getHttpMethod()) - { - $response->setStatusCode(405); - return $response; - } - // The Access-Control-Allow-Credentials header indicates whether the response to request - // can be exposed when the omit credentials flag is unset. When part of the response to a preflight request - // it indicates that the actual request can include user credentials. - if ( $this->current_endpoint->isAllowCredentials()) - { - $response->headers->set('Access-Control-Allow-Credentials', 'true'); - } - if (Config::get('cors.use_pre_flight_caching', false)) - { - // The Access-Control-Max-Age header indicates how long the response can be cached, so that for - // subsequent requests, within the specified time, no preflight request has to be made. - $response->headers->set('Access-Control-Max-Age', Config::get('cors.max_age', 32000)); - } - // The Access-Control-Allow-Headers header indicates, as part of the response to a preflight request, - // which header field names can be used during the actual request - $response->headers->set('Access-Control-Allow-Headers', $this->allowed_headers); + /** + * @param Request $request + * @return Response + */ + private function makePreflightResponse(Request $request) + { + $response = new Response(); + if (!$this->isAllowedOrigin($request)) + { + $response->headers->set('Access-Control-Allow-Origin', 'null'); + $response->setStatusCode(403); + return $response; + } + $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin')); + // The Access-Control-Request-Method header indicates which method will be used in the actual + // request as part of the preflight request + // check request method + if ($request->headers->get('Access-Control-Request-Method') != $this->current_endpoint->getHttpMethod()) + { + $response->setStatusCode(405); + return $response; + } + // The Access-Control-Allow-Credentials header indicates whether the response to request + // can be exposed when the omit credentials flag is unset. When part of the response to a preflight request + // it indicates that the actual request can include user credentials. + if ( $this->current_endpoint->isAllowCredentials()) + { + $response->headers->set('Access-Control-Allow-Credentials', 'true'); + } + if (Config::get('cors.use_pre_flight_caching', false)) + { + // The Access-Control-Max-Age header indicates how long the response can be cached, so that for + // subsequent requests, within the specified time, no preflight request has to be made. + $response->headers->set('Access-Control-Max-Age', Config::get('cors.max_age', 32000)); + } + // The Access-Control-Allow-Headers header indicates, as part of the response to a preflight request, + // which header field names can be used during the actual request + $response->headers->set('Access-Control-Allow-Headers', $this->allowed_headers); - //The Access-Control-Allow-Methods header indicates, as part of the response to a preflight request, - // which methods can be used during the actual request. - $response->headers->set('Access-Control-Allow-Methods', $this->allowed_methods); - // The Access-Control-Request-Headers header indicates which headers will be used in the actual request - // as part of the preflight request. - $headers = $request->headers->get('Access-Control-Request-Headers'); - if ($headers) - { - $headers = trim(strtolower($headers)); - $allow_headers = explode(', ', $this->allowed_headers); - foreach (preg_split('{, *}', $headers) as $header) - { - //if they are simple headers then skip them - if (in_array($header, self::$simple_headers, true)) - { - continue; - } - //check is the requested header is on the list of allowed headers - if (!in_array($header, $allow_headers, true)) - { - $response->setStatusCode(400); - $response->setContent('Unauthorized header '.$header); - break; - } - } - } - //OK - No Content - $response->setStatusCode(204); - return $response; - } + //The Access-Control-Allow-Methods header indicates, as part of the response to a preflight request, + // which methods can be used during the actual request. + $response->headers->set('Access-Control-Allow-Methods', $this->allowed_methods); + // The Access-Control-Request-Headers header indicates which headers will be used in the actual request + // as part of the preflight request. + $headers = $request->headers->get('Access-Control-Request-Headers'); + if ($headers) + { + $headers = trim(strtolower($headers)); + $allow_headers = explode(', ', $this->allowed_headers); + foreach (preg_split('{, *}', $headers) as $header) + { + //if they are simple headers then skip them + if (in_array($header, self::$simple_headers, true)) + { + continue; + } + //check is the requested header is on the list of allowed headers + if (!in_array($header, $allow_headers, true)) + { + $response->setStatusCode(400); + $response->setContent('Unauthorized header '.$header); + break; + } + } + } + //OK - No Content + $response->setStatusCode(204); + return $response; + } - /** - * @param Request $request - * @returns bool - */ - private function isValidCORSRequest(Request $request) - { - /** - * The presence of the Origin header does not necessarily mean that the request is a cross-origin request. - * While all cross-origin requests will contain an Origin header, + /** + * @param Request $request + * @returns bool + */ + private function isValidCORSRequest(Request $request) + { + /** + * The presence of the Origin header does not necessarily mean that the request is a cross-origin request. + * While all cross-origin requests will contain an Origin header, - * Origin header on same-origin requests. But Chrome and Safari include an Origin header on - * same-origin POST/PUT/DELETE requests (same-origin GET requests will not have an Origin header). - */ - return $request->headers->has('Origin'); - } + * Origin header on same-origin requests. But Chrome and Safari include an Origin header on + * same-origin POST/PUT/DELETE requests (same-origin GET requests will not have an Origin header). + */ + return $request->headers->has('Origin'); + } - /** - * https://www.owasp.org/index.php/CORS_OriginHeaderScrutiny - * Filter that will ensure the following points for each incoming HTTP CORS requests: - * - Have only one and non empty instance of the origin header, - * - Have only one and non empty instance of the host header, - * - The value of the origin header is present in a internal allowed domains list (white list). As we act before the - * step 2 of the CORS HTTP requests/responses exchange process, allowed domains list is yet provided to client, - * - Cache IP of the sender for 1 hour. If the sender send one time a origin domain that is not in the white list - * then all is requests will return an HTTP 403 response (protract allowed domain guessing). - * We use the method above because it's not possible to identify up to 100% that the request come from one expected - * client application, since: - * - All information of a HTTP request can be faked, - * - It's the browser (or others tools) that send the HTTP request then the IP address that we have access to is the - * client IP address. - * @param Request $request - * @return bool - */ - private function testOriginHeaderScrutiny(Request $request) - { - /* Step 0 : Check presence of client IP in black list */ - $client_ip = $request->getClientIp(); - if (Cache::has(self::CORS_IP_BLACKLIST_PREFIX . $client_ip)) - { - return false; - } - /* Step 1 : Check that we have only one and non empty instance of the "Origin" header */ - $origin = $request->headers->get('Origin', null, false); - if (is_array($origin) && count($origin) > 1) - { - // If we reach this point it means that we have multiple instance of the "Origin" header - // Add client IP address to black listed client - $expiresAt = Carbon::now()->addMinutes(60); - Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); - return false; - } - /* Step 2 : Check that we have only one and non empty instance of the "Host" header */ - $host = $request->headers->get('Host', null, false); - //Have only one and non empty instance of the host header, - if (is_array($host) && count($host) > 1) - { - // If we reach this point it means that we have multiple instance of the "Host" header - $expiresAt = Carbon::now()->addMinutes(60); - Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); - return false; - } - /* Step 3 : Perform analysis - Origin header is required */ + /** + * https://www.owasp.org/index.php/CORS_OriginHeaderScrutiny + * Filter that will ensure the following points for each incoming HTTP CORS requests: + * - Have only one and non empty instance of the origin header, + * - Have only one and non empty instance of the host header, + * - The value of the origin header is present in a internal allowed domains list (white list). As we act before the + * step 2 of the CORS HTTP requests/responses exchange process, allowed domains list is yet provided to client, + * - Cache IP of the sender for 1 hour. If the sender send one time a origin domain that is not in the white list + * then all is requests will return an HTTP 403 response (protract allowed domain guessing). + * We use the method above because it's not possible to identify up to 100% that the request come from one expected + * client application, since: + * - All information of a HTTP request can be faked, + * - It's the browser (or others tools) that send the HTTP request then the IP address that we have access to is the + * client IP address. + * @param Request $request + * @return bool + */ + private function testOriginHeaderScrutiny(Request $request) + { + /* Step 0 : Check presence of client IP in black list */ + $client_ip = $request->getClientIp(); + if (Cache::has(self::CORS_IP_BLACKLIST_PREFIX . $client_ip)) + { + return false; + } + /* Step 1 : Check that we have only one and non empty instance of the "Origin" header */ + $origin = $request->headers->get('Origin', null, false); + if (is_array($origin) && count($origin) > 1) + { + // If we reach this point it means that we have multiple instance of the "Origin" header + // Add client IP address to black listed client + $expiresAt = Carbon::now()->addMinutes(60); + Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); + return false; + } + /* Step 2 : Check that we have only one and non empty instance of the "Host" header */ + $host = $request->headers->get('Host', null, false); + //Have only one and non empty instance of the host header, + if (is_array($host) && count($host) > 1) + { + // If we reach this point it means that we have multiple instance of the "Host" header + $expiresAt = Carbon::now()->addMinutes(60); + Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); + return false; + } + /* Step 3 : Perform analysis - Origin header is required */ - $origin = $request->headers->get('Origin'); - $host = $request->headers->get('Host'); - $server_name = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; - $origin_host = @parse_url($origin, PHP_URL_HOST); + $origin = $request->headers->get('Origin'); + $host = $request->headers->get('Host'); + $server_name = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; + $origin_host = @parse_url($origin, PHP_URL_HOST); - // check origin not empty and allowed + // check origin not empty and allowed - if (!$this->isAllowedOrigin($origin)) - { - $expiresAt = Carbon::now()->addMinutes(60); - Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); - return false; - } + if (!$this->isAllowedOrigin($origin)) + { + $expiresAt = Carbon::now()->addMinutes(60); + Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); + return false; + } - if (is_null($host) || $server_name != $host || is_null($origin_host) || $origin_host == $server_name) - { - $expiresAt = Carbon::now()->addMinutes(60); - Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); - return false; - } + if (is_null($host) || $server_name != $host || is_null($origin_host) || $origin_host == $server_name) + { + $expiresAt = Carbon::now()->addMinutes(60); + Cache::put(self::CORS_IP_BLACKLIST_PREFIX . $client_ip, self::CORS_IP_BLACKLIST_PREFIX . $client_ip, $expiresAt); + return false; + } - /* Step 4 : Finalize request next step */ - return true; - } + /* Step 4 : Finalize request next step */ + return true; + } - private function checkEndPoint($endpoint_path, $http_method) - { - $this->current_endpoint = $this->endpoint_repository->getApiEndpointByUrlAndMethod($endpoint_path, $http_method); - if (is_null($this->current_endpoint)) - { - return false; - } - if (!$this->current_endpoint->isAllowCors() || !$this->current_endpoint->isActive()) - { - return false; - } - return true; - } + private function checkEndPoint($endpoint_path, $http_method) + { + $this->current_endpoint = $this->endpoint_repository->getApiEndpointByUrlAndMethod($endpoint_path, $http_method); + if (is_null($this->current_endpoint)) + { + return false; + } + if (!$this->current_endpoint->isAllowCors() || !$this->current_endpoint->isActive()) + { + return false; + } + return true; + } - /** - * @param string $origin - * @return bool - */ - private function isAllowedOrigin($origin) - { - return true; - } + /** + * @param string $origin + * @return bool + */ + private function isAllowedOrigin($origin) + { + return true; + } - private static function getRequestType(Request $request) - { + private static function getRequestType(Request $request) + { - $type = CORSRequestPreflightType::UNKNOWN; - $http_method = $request->getMethod(); - $content_type = $request->headers->has('Content-Type') ? strtolower( $request->headers->get('Content-Type')) : null; + $type = CORSRequestPreflightType::UNKNOWN; + $http_method = $request->getMethod(); + $content_type = $request->headers->has('Content-Type') ? strtolower( $request->headers->get('Content-Type')) : null; - if (false !== $pos = strpos($content_type, ';')) { + if (false !== $pos = strpos($content_type, ';')) { $content_type = substr($content_type, 0, $pos); } - $http_method = strtoupper($http_method); + $http_method = strtoupper($http_method); - if ($http_method === 'OPTIONS' && $request->headers->has('Access-Control-Request-Method')) - { - $type = CORSRequestPreflightType::REQUEST_FOR_PREFLIGHT; - } - else - { - if (self::hasCustomHeaders($request)) - { - $type = CORSRequestPreflightType::COMPLEX_REQUEST; - } - elseif ($http_method === 'POST' && !in_array($content_type, self::$simple_content_header_values, true)) - { - $type = CORSRequestPreflightType::COMPLEX_REQUEST; - } - elseif (!in_array($http_method, self::$simple_http_methods, true)) - { - $type = CORSRequestPreflightType::COMPLEX_REQUEST; - } - else - { - $type = CORSRequestPreflightType::SIMPLE_REQUEST; - } - } - return $type; - } + if ($http_method === 'OPTIONS' && $request->headers->has('Access-Control-Request-Method')) + { + $type = CORSRequestPreflightType::REQUEST_FOR_PREFLIGHT; + } + else + { + if (self::hasCustomHeaders($request)) + { + $type = CORSRequestPreflightType::COMPLEX_REQUEST; + } + elseif ($http_method === 'POST' && !in_array($content_type, self::$simple_content_header_values, true)) + { + $type = CORSRequestPreflightType::COMPLEX_REQUEST; + } + elseif (!in_array($http_method, self::$simple_http_methods, true)) + { + $type = CORSRequestPreflightType::COMPLEX_REQUEST; + } + else + { + $type = CORSRequestPreflightType::SIMPLE_REQUEST; + } + } + return $type; + } - private static function getCustomHeaders(Request $request) - { - $custom_headers = array(); - foreach ($request->headers->all() as $k => $h) - { - if (starts_with('X-', strtoupper(trim($k)))) - { - array_push($custom_headers, strtoupper(trim($k))); - } - } - return $custom_headers; - } + private static function getCustomHeaders(Request $request) + { + $custom_headers = array(); + foreach ($request->headers->all() as $k => $h) + { + if (starts_with('X-', strtoupper(trim($k)))) + { + array_push($custom_headers, strtoupper(trim($k))); + } + } + return $custom_headers; + } - private static function hasCustomHeaders(Request $request) - { - return count(self::getCustomHeaders($request)) > 0; - } + private static function hasCustomHeaders(Request $request) + { + return count(self::getCustomHeaders($request)) > 0; + } } \ No newline at end of file diff --git a/app/Http/Middleware/CORSRequestPreflightData.php b/app/Http/Middleware/CORSRequestPreflightData.php index 899dad76..ffeb1bac 100644 --- a/app/Http/Middleware/CORSRequestPreflightData.php +++ b/app/Http/Middleware/CORSRequestPreflightData.php @@ -23,7 +23,7 @@ class CORSRequestPreflightData // ttl on seconds public static $cache_lifetime = 10; - public static $cache_attributes = array('sender', 'uri', 'origin', 'expected_method', 'expected_custom_headers', 'allows_credentials'); + public static $cache_attributes = ['sender', 'uri', 'origin', 'expected_method', 'expected_custom_headers', 'allows_credentials']; /** Final HTTP request expected method */ private $expected_method = null; @@ -69,7 +69,7 @@ class CORSRequestPreflightData */ public function toArray() { - $res = array(); + $res = []; $res['sender'] = $this->sender; $res['uri'] = $this->uri; $res['origin'] = $this->origin; diff --git a/app/Http/Middleware/OAuth2BearerAccessTokenRequestValidator.php b/app/Http/Middleware/OAuth2BearerAccessTokenRequestValidator.php index 1ba01178..432a5d04 100644 --- a/app/Http/Middleware/OAuth2BearerAccessTokenRequestValidator.php +++ b/app/Http/Middleware/OAuth2BearerAccessTokenRequestValidator.php @@ -148,8 +148,9 @@ class OAuth2BearerAccessTokenRequestValidator if ((!in_array($realm, $audience))) { throw new InvalidGrantTypeException(OAuth2Protocol::OAuth2Protocol_Error_InvalidToken); } - if ($token_info->getApplicationType() === 'JS_CLIENT' && str_contains($token_info->getAllowedOrigins(), - $origin) === false + if ( + $token_info->getApplicationType() === 'JS_CLIENT' + && (is_null($origin) || empty($origin)|| str_contains($token_info->getAllowedOrigins(), $origin) === false ) ) { //check origins throw new OAuth2ResourceServerException( @@ -197,6 +198,7 @@ class OAuth2BearerAccessTokenRequestValidator if (!is_null($token_info->getUserId())) { + Log::debug(sprintf("OAuth2BearerAccessTokenRequestValidator::handle user id is not null (%s)", $token_info->getUserId())); $context['user_id'] = $token_info->getUserId(); $context['user_external_id'] = $token_info->getUserExternalId(); $context['user_identifier'] = $token_info->getUserIdentifier(); diff --git a/app/Http/Middleware/RateLimitMiddleware.php b/app/Http/Middleware/RateLimitMiddleware.php index 92cebcab..c003b2ad 100644 --- a/app/Http/Middleware/RateLimitMiddleware.php +++ b/app/Http/Middleware/RateLimitMiddleware.php @@ -93,8 +93,8 @@ final class RateLimitMiddleware extends ThrottleRequests return $next($request); } - if ($this->limiter->tooManyAttempts($key, $max_attempts, $decay_minutes)) { - return $this->buildResponse($key, $max_attempts); + if ($this->limiter->tooManyAttempts($key, $max_attempts)) { + return $this->buildException($key, $max_attempts); } $this->limiter->hit($key, $decay_minutes); diff --git a/app/Http/Middleware/UserAuthEndpoint.php b/app/Http/Middleware/UserAuthEndpoint.php index 55443068..a2dbf79f 100644 --- a/app/Http/Middleware/UserAuthEndpoint.php +++ b/app/Http/Middleware/UserAuthEndpoint.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\Models\ResourceServer\ApiEndpoint; use App\Models\ResourceServer\IApiEndpointRepository; use Closure; diff --git a/app/Http/Renderers/IRenderer.php b/app/Http/Renderers/IRenderer.php new file mode 100644 index 00000000..709b8e8e --- /dev/null +++ b/app/Http/Renderers/IRenderer.php @@ -0,0 +1,23 @@ +ticket = $ticket; + } + + public function render(): string + { + $order = $this->ticket->getOrder(); + $summit = $order->getSummit(); + $summit_name = $summit->getName(); + $main_venues = $summit->getMainVenues(); + $price = $this->ticket->getRawCost().' '.$this->ticket->getCurrency(); + $ticket_number = $this->ticket->getNumber(); + $location_name = ""; + if(count($main_venues) > 0){ + $location_name = $main_venues[0]->getName().', '.$main_venues[0]->getFullAddress(); + } + $order_number = $order->getNumber(); + $dates = $summit->getDatesLabel(); + $owner_full_name = $order->getOwnerFullName(); + $order_creation_date = $order->getCreatedUTC()->format("Y-m-d H:i:s"); + $ticket_type = $this->ticket->getTicketType()->getName(); + $attendee_name = $this->ticket->hasOwner() ? $this->ticket->getOwner()->getFullName() : 'TBD'; + // create new PDF document + $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); + + // set document information + $pdf->SetCreator(PDF_CREATOR); + $pdf->SetTitle($summit_name. ' '.$this->ticket->getNumber()); + + // remove default header/footer + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + + // set header and footer fonts + $pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN)); + $pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA)); + + // set default monospaced font + $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); + + // set margins + $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); + $pdf->SetHeaderMargin(PDF_MARGIN_HEADER); + $pdf->SetFooterMargin(PDF_MARGIN_FOOTER); + + // set auto page breaks + $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM); + + // set image scale factor + $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + + // set font + $pdf->SetFont('helvetica', '', 8); + + // add a page + $pdf->AddPage(); + + $html = view('tickets.raw',[ + 'summit_name' => $summit_name, + 'ticket_type' => $ticket_type, + 'price' => $price, + 'location_name' => $location_name, + 'dates' => $dates, + 'order_number' => $order_number, + 'owner_full_name' => $owner_full_name, + 'order_creation_date' => $order_creation_date, + 'attendee_name' => $attendee_name, + ])->render(); + + $pdf->writeHTMLCell(100, 80, 10, 25 , $html, $border=1, $ln=0, $fill=0, $reseth=true, $align='', $autopadding=true); + + $pdf->SetFont('helvetica', '', 5.7); + + // set style for barcode + $style = [ + 'border' => 2, + 'vpadding' => 'auto', + 'hpadding' => 'auto', + 'fgcolor' => [0, 0, 0], + 'bgcolor' => false, //array(255,255,255) + 'module_width' => 1, // width of a single module in points + 'module_height' => 1 // height of a single module in points + ]; + + // QRCODE,L : QR-CODE Low error correction + $this->ticket->generateQRCode(); + $pdf->write2DBarcode($this->ticket->getQRCode(), 'QRCODE,L', 125, 25, 50, 50, $style, 'N'); + $pdf->Text(124, 85, $ticket_number); + + //Close and output PDF document + return $pdf->Output($ticket_number.'.pdf', 'S'); + } +} \ No newline at end of file diff --git a/app/Http/Routes/public.php b/app/Http/Routes/public.php index 4cfb26a8..4793b967 100644 --- a/app/Http/Routes/public.php +++ b/app/Http/Routes/public.php @@ -11,30 +11,33 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Route; + // public api ( without AUTHZ [OAUTH2.0]) Route::group([ 'namespace' => 'App\Http\Controllers', - 'prefix' => 'api/public/v1', - 'before' => [], - 'after' => [], + 'prefix' => 'api/public/v1', + 'before' => [], + 'after' => [], 'middleware' => [ 'ssl', - 'rate.limit:1000,1', // 1000 request per minute + 'rate.limit:10000,1', // 10000 request per minute 'etags' ] -], function(){ +], function () { + // members - Route::group(['prefix'=>'members'], function() { + Route::group(['prefix' => 'members'], function () { Route::get('', 'OAuth2MembersApiController@getAll'); }); // speakers - Route::group(['prefix'=>'speakers'], function() { - Route::group(['prefix'=>'{speaker_id}'], function(){ - Route::group(['prefix'=>'edit-permission'], function(){ - Route::group(['prefix'=>'{token}'], function(){ + Route::group(['prefix' => 'speakers'], function () { + Route::group(['prefix' => '{speaker_id}'], function () { + Route::group(['prefix' => 'edit-permission'], function () { + Route::group(['prefix' => '{token}'], function () { Route::get('approve', 'OAuth2SummitSpeakersApiController@approveSpeakerEditPermission'); Route::get('decline', 'OAuth2SummitSpeakersApiController@declineSpeakerEditPermission'); }); @@ -43,26 +46,54 @@ Route::group([ }); // summits - Route::group(['prefix'=>'summits'], function() { - Route::get('', [ 'middleware' => 'cache:'.Config::get('cache_api_response.get_summit_response_lifetime', 600), 'uses' => 'OAuth2SummitApiController@getSummits']); + Route::group(['prefix' => 'summits'], function () { + Route::get('', ['middleware' => 'cache:' . Config::get('cache_api_response.get_summit_response_lifetime', 600), 'uses' => 'OAuth2SummitApiController@getSummits']); Route::group(['prefix' => 'all'], function () { - Route::get('current', 'OAuth2SummitApiController@getAllCurrentSummit'); - Route::group(['prefix' => 'selection-plans'], function () { - Route::get('current/{status}', 'OAuth2SummitSelectionPlansApiController@getCurrentSelectionPlanByStatus')->where('status', 'submission|selection|voting'); + + Route::get('', 'OAuth2SummitApiController@getAllSummits'); + Route::get('current', 'OAuth2SummitApiController@getAllCurrentSummit'); + Route::get('{id}', 'OAuth2SummitApiController@getAllSummitByIdOrSlug'); + + Route::group(['prefix' => 'payments'], function () { + Route::group(['prefix' => '{application_name}'], function () { + Route::post('confirm', 'PaymentGatewayWebHookController@genericConfirm'); + }); }); - Route::group(['prefix' => 'bookable-rooms'], function () { + Route::group(['prefix' => 'orders'], function () { + Route::group(['prefix' => '{order_hash}'], function () { + Route::group(['prefix' => 'tickets'], function () { + Route::put('', "OAuth2SummitOrdersApiController@updateTicketsByOrderHash"); + }); + }); + Route::group(['prefix' => 'all'], function () { - Route::group(['prefix' => 'reservations'], function () { - // api/public/v1/summits/all/bookable-rooms/all/reservations/confirm ( open endpoint for payment gateway callbacks) - Route::post("confirm", "OAuth2SummitLocationsApiController@confirmBookableVenueRoomReservation"); + Route::group(['prefix' => 'tickets'], function () { + Route::group(['prefix' => '{hash}'], function () { + Route::get('', "OAuth2SummitOrdersApiController@getTicketByHash"); + Route::put('', "OAuth2SummitOrdersApiController@updateTicketByHash"); + Route::put('regenerate', "OAuth2SummitOrdersApiController@regenerateTicketHash"); + Route::get('pdf', "OAuth2SummitOrdersApiController@getTicketPDFByHash"); + }); }); }); }); }); Route::group(['prefix' => '{id}'], function () { + + Route::group(['prefix' => 'payments'], function () { + Route::group(['prefix' => '{application_name}'], function () { + Route::post('confirm', 'PaymentGatewayWebHookController@confirm'); + }); + }); + + Route::group(['prefix' => 'selection-plans'], function () { + Route::get('current/{status}', 'OAuth2SummitSelectionPlansApiController@getCurrentSelectionPlanByStatus')->where('status', 'submission|selection|voting'); + }); + + Route::get('', [ 'middleware' => 'cache:'.Config::get('cache_api_response.get_summit_response_lifetime', 1200), 'uses' => 'OAuth2SummitApiController@getSummit'])->where('id', 'current|[0-9]+'); // members Route::group(['prefix' => 'members'], function () { @@ -97,7 +128,7 @@ Route::group([ Route::group(['prefix' => 'locations'], function () { Route::group(['prefix' => '{location_id}'], function () { Route::get('', 'OAuth2SummitLocationsApiController@getLocation'); - Route::get('/events/published','OAuth2SummitLocationsApiController@getLocationPublishedEvents'); + Route::get('/events/published', 'OAuth2SummitLocationsApiController@getLocationPublishedEvents'); Route::group(['prefix' => 'banners'], function () { Route::get('', 'OAuth2SummitLocationsApiController@getLocationBanners'); }); @@ -109,8 +140,6 @@ Route::group([ Route::get('sent', 'OAuth2SummitNotificationsApiController@getAllApprovedByUser'); }); - // speakers - // speakers Route::group(['prefix' => 'speakers'], function () { Route::get('', 'OAuth2SummitSpeakersApiController@getSpeakers'); @@ -119,6 +148,24 @@ Route::group([ }); }); + // orders + Route::group(['prefix' => 'orders'], function () { + Route::post('reserve', 'OAuth2SummitOrdersApiController@reserve'); + Route::group(['prefix' => '{hash}'], function () { + Route::put('checkout', 'OAuth2SummitOrdersApiController@checkout'); + Route::group(['prefix' => 'tickets'], function () { + Route::get('mine', 'OAuth2SummitOrdersApiController@getMyTicketByOrderHash'); + }); + Route::delete('', 'OAuth2SummitOrdersApiController@cancel'); + }); + }); + + // registration invitations + Route::group(['prefix' => 'registration-invitations'], function () { + Route::group(['prefix' => '{email}'], function () { + Route::get('', 'OAuth2SummitOrdersApiController@getByEmail'); + }); + }); }); }); @@ -162,7 +209,6 @@ Route::group([ }); - Route::group([ 'namespace' => 'App\Http\Controllers', 'prefix' => '.well-known', diff --git a/app/Http/Utils/CSV/CSVExporter.php b/app/Http/Utils/CSV/CSVExporter.php index 0e373e82..54fe4d1b 100644 --- a/app/Http/Utils/CSV/CSVExporter.php +++ b/app/Http/Utils/CSV/CSVExporter.php @@ -48,21 +48,24 @@ final class CSVExporter * @return string */ public function export(array $items, $field_separator = ",", array $header = [], array $formatters){ - $flag = false; - $output = ''; + $flag = false; + $output = ''; + $header = []; + $originalHeader = []; + foreach ($items as $row) { if (!$flag) { // display field/column names as first row if(!count($header)) - $header = array_keys($row); + $originalHeader = $header = array_keys($row); array_walk($header, array($this, 'cleanData')); $output .= implode($field_separator, $header) . PHP_EOL;; $flag = true; } array_walk($row, array($this, 'cleanData')); $values = []; - foreach ($header as $key){ - $val = isset($row[$key])? $row[$key] : ''; + foreach ($originalHeader as $key){ + $val = $row[$key] ?? ''; if(isset($formatters[$key])) $val = $formatters[$key]->format($val); if(is_array($val)) $val = ''; diff --git a/app/Http/Utils/FileUploader.php b/app/Http/Utils/FileUploader.php index 0fd15fe7..840a755d 100644 --- a/app/Http/Utils/FileUploader.php +++ b/app/Http/Utils/FileUploader.php @@ -11,15 +11,14 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use App\Services\FileSystem\FileNameSanitizer; use App\Services\Model\IFolderService; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; use models\exceptions\ValidationException; use models\main\File; -use Behat\Transliterator\Transliterator; use models\main\IFolderRepository; - /** * Class FileUploader * @package App\Http\Utils @@ -31,11 +30,6 @@ final class FileUploader implements IFileUploader */ private $folder_service; - /** - * @var IBucket - */ - private $bucket; - /** * @var IFolderRepository */ @@ -45,21 +39,17 @@ final class FileUploader implements IFileUploader * FileUploader constructor. * @param IFolderService $folder_service * @param IFolderRepository $folder_repository - * @param IBucket $bucket */ public function __construct ( IFolderService $folder_service, - IFolderRepository $folder_repository, - IBucket $bucket + IFolderRepository $folder_repository ) { $this->folder_service = $folder_service; $this->folder_repository = $folder_repository; - $this->bucket = $bucket; } - private static $default_replacements = [ '/\s/' => '-', // remove whitespace '/_/' => '-', // underscores to dashes @@ -70,22 +60,18 @@ final class FileUploader implements IFileUploader /** * @param UploadedFile $file - * @param $folder_name + * @param string $path * @param bool $is_image * @return File * @throws \Exception */ - public function build(UploadedFile $file, $folder_name, $is_image = false){ + public function build(UploadedFile $file, string $path, bool $is_image = false){ $attachment = new File(); try { $client_original_name = $file->getClientOriginalName(); $ext = pathinfo($client_original_name, PATHINFO_EXTENSION); - $client_original_name = trim(Transliterator::utf8ToAscii($client_original_name)); - - foreach(self::$default_replacements as $regex => $replace) { - $client_original_name = preg_replace($regex, $replace, $client_original_name); - } + $client_original_name = FileNameSanitizer::sanitize($client_original_name); $idx = 1; $name = pathinfo($client_original_name, PATHINFO_FILENAME); @@ -105,18 +91,23 @@ final class FileUploader implements IFileUploader throw new ValidationException("empty file name is not valid"); } - Log::debug(sprintf("FileUploader::build: folder_name %s client original name %s", $folder_name, $client_original_name)); + Log::debug(sprintf("FileUploader::build: folder_name %s client original name %s", $path, $client_original_name)); - $local_path = Storage::putFileAs(sprintf('/public/%s', $folder_name), $file, $client_original_name); + $local_path = Storage::disk('public')->putFileAs + ( + $path, + $file, + $client_original_name + ); Log::debug(sprintf("FileUploader::build: saved to local path %s", $local_path)); - Log::debug(sprintf("FileUploader::build: invoking folder service findOrMake folder_name %s", $folder_name)); - $folder = $this->folder_service->findOrMake($folder_name); - $local_path = Storage::disk()->path($local_path); + Log::debug(sprintf("FileUploader::build: invoking folder service findOrMake folder_name %s", $path)); + $folder = $this->folder_service->findOrMake($path); + $local_path = Storage::disk('public')->path($local_path); $attachment->setParent($folder); $attachment->setName($client_original_name); - $file_name = sprintf("assets/%s/%s", $folder_name, $client_original_name); + $file_name = sprintf("assets/%s/%s", $path, $client_original_name); Log::debug(sprintf("FileUploader::build file_name %s", $file_name)); $attachment->setFilename($file_name); $title = str_replace(['-','_'],' ', preg_replace('/\.[^.]+$/', '', $title)); @@ -126,7 +117,13 @@ final class FileUploader implements IFileUploader if ($is_image) // set className $attachment->setImage(); Log::debug(sprintf("FileUploader::build uploading to bucket %s", $local_path)); - $this->bucket->put($attachment, $local_path); + // store at cloud + Storage::disk('assets')->putFileAs + ( + $path, + $file, + $client_original_name + ); $attachment->setCloudMeta('LastPut', time()); $attachment->setCloudStatus('Live'); $attachment->setCloudSize(filesize($local_path)); diff --git a/app/Http/Utils/Filters/DoctrineFilterMapping.php b/app/Http/Utils/Filters/DoctrineFilterMapping.php index ed469200..99ed4dce 100644 --- a/app/Http/Utils/Filters/DoctrineFilterMapping.php +++ b/app/Http/Utils/Filters/DoctrineFilterMapping.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; @@ -44,23 +45,52 @@ class DoctrineFilterMapping extends FilterMapping * @param FilterElement $filter * @return QueryBuilder */ - public function apply(QueryBuilder $query, FilterElement $filter){ - $param_count = $query->getParameters()->count() + 1; - $where = $this->where; - $has_param = false; + public function apply(QueryBuilder $query, FilterElement $filter) + { + $value = $filter->getValue(); + if (is_array($value)) { + $inner_where = '( '; - if(strstr($where,":value")) { - $where = str_replace(":value", ":value_" . $param_count, $where); - $has_param = true; - } + foreach ($value as $val) { + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; - if(strstr($where,":operator")) - $where = str_replace(":operator", $filter->getOperator(), $where); + if (strstr($where, ":value")) { + $where = str_replace(":value", ":value_" . $param_count, $where); + $has_param = true; + } - $query = $query->andWhere($where); + if (strstr($where, ":operator")) + $where = str_replace(":operator", $filter->getOperator(), $where); - if($has_param){ - $query = $query->setParameter(":value_".$param_count, $filter->getValue()); + if ($has_param) { + $query = $query->setParameter(":value_" . $param_count, $val); + } + $inner_where .= $where . " " . $filter->getSameFieldOp() . " "; + } + $inner_where = substr($inner_where, 0, (strlen($filter->getSameFieldOp()) + 1) * -1); + $inner_where .= ' )'; + + $query = $query->andWhere($inner_where); + } else { + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; + + if (strstr($where, ":value")) { + $where = str_replace(":value", ":value_" . $param_count, $where); + $has_param = true; + } + + if (strstr($where, ":operator")) + $where = str_replace(":operator", $filter->getOperator(), $where); + + $query = $query->andWhere($where); + + if ($has_param) { + $query = $query->setParameter(":value_" . $param_count, $filter->getValue()); + } } return $query; } @@ -70,23 +100,53 @@ class DoctrineFilterMapping extends FilterMapping * @param FilterElement $filter * @return string */ - public function applyOr(QueryBuilder $query, FilterElement $filter){ - $param_count = $query->getParameters()->count() + 1; - $where = $this->where; - $has_param = false; + public function applyOr(QueryBuilder $query, FilterElement $filter) + { + $value = $filter->getValue(); + if (is_array($value)) { - if(strstr($where,":value")) { + $inner_where = '( '; + + foreach ($value as $val) { + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; + + if (strstr($where, ":value")) { + $where = str_replace(":value", ":value_" . $param_count, $where); + $has_param = true; + } + + if (strstr($where, ":operator")) + $where = str_replace(":operator", $filter->getOperator(), $where); + + if ($has_param) { + $query->setParameter(":value_" . $param_count, $value); + } + + $inner_where .= $where . " " . $filter->getSameFieldOp() . " "; + } + + $inner_where = substr($inner_where, 0, (strlen($filter->getSameFieldOp()) + 1) * -1); + $inner_where .= ' )'; + + return $inner_where; + } + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; + + if (strstr($where, ":value")) { $where = str_replace(":value", ":value_" . $param_count, $where); $has_param = true; } - if(strstr($where,":operator")) + if (strstr($where, ":operator")) $where = str_replace(":operator", $filter->getOperator(), $where); - if($has_param){ - $query->setParameter(":value_".$param_count, $filter->getValue()); + if ($has_param) { + $query->setParameter(":value_" . $param_count, $filter->getValue()); } - return $where; } } \ No newline at end of file diff --git a/app/Http/Utils/Filters/DoctrineJoinFilterMapping.php b/app/Http/Utils/Filters/DoctrineJoinFilterMapping.php index 779590b8..04ca97da 100644 --- a/app/Http/Utils/Filters/DoctrineJoinFilterMapping.php +++ b/app/Http/Utils/Filters/DoctrineJoinFilterMapping.php @@ -11,8 +11,10 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; + /** * Class DoctrineJoinFilterMapping * @package utils @@ -50,26 +52,60 @@ class DoctrineJoinFilterMapping extends FilterMapping * @param FilterElement $filter * @return QueryBuilder */ - public function apply(QueryBuilder $query, FilterElement $filter){ - $param_count = $query->getParameters()->count() + 1; - $where = $this->where; - $has_param = false; + public function apply(QueryBuilder $query, FilterElement $filter) + { + $value = $filter->getValue(); - if(strstr($where,":value")) { - $where = str_replace(":value", ":value_" . $param_count, $where); - $has_param = true; - } + if (is_array($value)) { + $inner_where = '( '; - if(strstr($where,":operator")) - $where = str_replace(":operator", $filter->getOperator(), $where); + foreach ($value as $val) { + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; - if(!in_array($this->alias, $query->getAllAliases())) - $query->innerJoin($this->table, $this->alias, Join::WITH); + if (strstr($where, ":value")) { + $where = str_replace(":value", ":value_" . $param_count, $where); + $has_param = true; + } - $query = $query->andWhere($where); + if (strstr($where, ":operator")) + $where = str_replace(":operator", $filter->getOperator(), $where); - if($has_param){ - $query = $query->setParameter(":value_".$param_count, $filter->getValue()); + if ($has_param) { + $query = $query->setParameter(":value_" . $param_count, $val); + } + $inner_where .= $where . " " . $filter->getSameFieldOp() . " "; + } + $inner_where = substr($inner_where, 0, (strlen($filter->getSameFieldOp()) + 1) * -1); + $inner_where .= ' )'; + + if (!in_array($this->alias, $query->getAllAliases())) + $query->innerJoin($this->table, $this->alias, Join::WITH); + + $query = $query->andWhere($inner_where); + + } else { + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; + + if (strstr($where, ":value")) { + $where = str_replace(":value", ":value_" . $param_count, $where); + $has_param = true; + } + + if (strstr($where, ":operator")) + $where = str_replace(":operator", $filter->getOperator(), $where); + + if (!in_array($this->alias, $query->getAllAliases())) + $query->innerJoin($this->table, $this->alias, Join::WITH); + + $query = $query->andWhere($where); + + if ($has_param) { + $query = $query->setParameter(":value_" . $param_count, $filter->getValue()); + } } return $query; @@ -81,25 +117,60 @@ class DoctrineJoinFilterMapping extends FilterMapping * @param FilterElement $filter * @return string */ - public function applyOr(QueryBuilder $query, FilterElement $filter){ - $param_count = $query->getParameters()->count() + 1; - $where = $this->where; - $has_param = false; + public function applyOr(QueryBuilder $query, FilterElement $filter) + { + $value = $filter->getValue(); + if (is_array($value)) { + $inner_where = '( '; - if(strstr($where,":value")) { + foreach ($value as $val) { + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; + + if (strstr($where, ":value")) { + $where = str_replace(":value", ":value_" . $param_count, $where); + $has_param = true; + } + + if (strstr($where, ":operator")) + $where = str_replace(":operator", $filter->getOperator(), $where); + + if ($has_param) { + $query->setParameter(":value_" . $param_count, $value); + } + + $inner_where .= $where . " " . $filter->getSameFieldOp() . " "; + } + + $inner_where = substr($inner_where, 0, (strlen($filter->getSameFieldOp()) + 1) * -1); + $inner_where .= ' )'; + + if (!in_array($this->alias, $query->getAllAliases())) + $query->innerJoin($this->table, $this->alias, Join::WITH); + + return $inner_where; + } + + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; + + if (strstr($where, ":value")) { $where = str_replace(":value", ":value_" . $param_count, $where); $has_param = true; } - if(strstr($where,":operator")) + if (strstr($where, ":operator")) $where = str_replace(":operator", $filter->getOperator(), $where); - if(!in_array($this->alias, $query->getAllAliases())) + if (!in_array($this->alias, $query->getAllAliases())) $query->innerJoin($this->table, $this->alias, Join::WITH); - if($has_param){ - $query->setParameter(":value_".$param_count, $filter->getValue()); + if ($has_param) { + $query->setParameter(":value_" . $param_count, $value); } + return $where; } diff --git a/app/Http/Utils/Filters/DoctrineLeftJoinFilterMapping.php b/app/Http/Utils/Filters/DoctrineLeftJoinFilterMapping.php index 89982311..cce29e2b 100644 --- a/app/Http/Utils/Filters/DoctrineLeftJoinFilterMapping.php +++ b/app/Http/Utils/Filters/DoctrineLeftJoinFilterMapping.php @@ -25,6 +25,41 @@ class DoctrineLeftJoinFilterMapping extends DoctrineJoinFilterMapping * @return QueryBuilder */ public function apply(QueryBuilder $query, FilterElement $filter){ + $value = $filter->getValue(); + if(is_array($value)){ + + $inner_where = '( '; + + foreach ($value as $val) { + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; + + if (strstr($where, ":value")) { + $where = str_replace(":value", ":value_" . $param_count, $where); + $has_param = true; + } + + if (strstr($where, ":operator")) + $where = str_replace(":operator", $filter->getOperator(), $where); + + if ($has_param) { + $query = $query->setParameter(":value_" . $param_count, $val); + } + $inner_where .= $where . " " . $filter->getSameFieldOp() . " "; + } + $inner_where = substr($inner_where, 0, (strlen($filter->getSameFieldOp()) + 1) * -1); + $inner_where .= ' )'; + + $query = $query->andWhere($inner_where); + + if(!in_array($this->alias, $query->getAllAliases())) + $query->leftJoin($this->table, $this->alias, Join::WITH); + + return $query; + + } + $param_count = $query->getParameters()->count() + 1; $where = $this->where; $has_param = false; @@ -37,15 +72,15 @@ class DoctrineLeftJoinFilterMapping extends DoctrineJoinFilterMapping if(strstr($where,":operator")) $where = str_replace(":operator", $filter->getOperator(), $where); - if(!in_array($this->alias, $query->getAllAliases())) - $query->leftJoin($this->table, $this->alias, Join::WITH); - $query = $query->andWhere($where); if($has_param){ - $query = $query->setParameter(":value_".$param_count, $filter->getValue()); + $query = $query->setParameter(":value_".$param_count, $value); } + if(!in_array($this->alias, $query->getAllAliases())) + $query->leftJoin($this->table, $this->alias, Join::WITH); + return $query; } @@ -55,6 +90,39 @@ class DoctrineLeftJoinFilterMapping extends DoctrineJoinFilterMapping * @return string */ public function applyOr(QueryBuilder $query, FilterElement $filter){ + $value = $filter->getValue(); + if(is_array($value)){ + $inner_where = '( '; + + foreach ($value as $val) { + $param_count = $query->getParameters()->count() + 1; + $where = $this->where; + $has_param = false; + + if (strstr($where, ":value")) { + $where = str_replace(":value", ":value_" . $param_count, $where); + $has_param = true; + } + + if (strstr($where, ":operator")) + $where = str_replace(":operator", $filter->getOperator(), $where); + + if ($has_param) { + $query->setParameter(":value_" . $param_count, $value); + } + + $inner_where .= $where . " " . $filter->getSameFieldOp() . " "; + } + + $inner_where = substr($inner_where, 0, (strlen($filter->getSameFieldOp()) + 1) * -1); + $inner_where .= ' )'; + + if(!in_array($this->alias, $query->getAllAliases())) + $query->leftJoin($this->table, $this->alias, Join::WITH); + + return $inner_where; + } + $param_count = $query->getParameters()->count() + 1; $where = $this->where; $has_param = false; @@ -67,15 +135,13 @@ class DoctrineLeftJoinFilterMapping extends DoctrineJoinFilterMapping if(strstr($where,":operator")) $where = str_replace(":operator", $filter->getOperator(), $where); - if(!in_array($this->alias, $query->getAllAliases())) - $query->leftJoin($this->table, $this->alias, Join::WITH); - - if(!in_array($this->alias, $query->getAllAliases())) - $query->leftJoin($this->table, $this->alias, Join::WITH); - if($has_param){ - $query->setParameter(":value_".$param_count, $filter->getValue()); + $query->setParameter(":value_".$param_count, $value); } + + if(!in_array($this->alias, $query->getAllAliases())) + $query->leftJoin($this->table, $this->alias, Join::WITH); + return $where; } } \ No newline at end of file diff --git a/app/Http/Utils/Filters/Filter.php b/app/Http/Utils/Filters/Filter.php index 4f603334..cb5243c6 100644 --- a/app/Http/Utils/Filters/Filter.php +++ b/app/Http/Utils/Filters/Filter.php @@ -154,20 +154,31 @@ final class Filter $values = $filter_key_values[$field]; if(!is_array($values)) $values = [$values]; foreach ($values as $val) { - $validation = Validator::make - ( - [$field => $val], - [$field => $rule], - $messages - ); - if ($validation->fails()) { - $ex = new ValidationException(); - throw $ex->setMessages($validation->messages()->toArray()); + if(is_array($val)){ + foreach($val as $sub_val){ + self::_validate($field, $sub_val, $rule, $messages); + } + } + else { + self::_validate($field, $val, $rule, $messages); } } } } + private static function _validate($field, $val, $rule, $messages){ + $validation = Validator::make + ( + [$field => $val], + [$field => $rule], + $messages + ); + if ($validation->fails()) { + $ex = new ValidationException(); + throw $ex->setMessages($validation->messages()->toArray()); + } + } + /** * @param Criteria $criteria * @param array $mappings @@ -257,22 +268,55 @@ final class Filter } if(!empty($condition)) $condition .= ' OR '; - $bindings[sprintf($param_prefix, $param_idx)] = $value; - $condition .= sprintf("%s %s :%s", $mapping_or[0], $filter->getOperator(), sprintf($param_prefix, $param_idx)); - ++$param_idx; + /**********************/ + if(is_array($value)){ + $inner_condition = '( '; + foreach ($value as $val) { + $inner_condition .= sprintf(" %s %s :%s %s ", $mapping[0], $filter->getOperator(), sprintf($param_prefix, $param_idx), $filter->getSameFieldOp()); + $bindings[sprintf($param_prefix, $param_idx)] = $val; + ++$param_idx; + } + $inner_condition = substr($inner_condition, 0, (strlen($filter->getSameFieldOp())+1) * -1); + $inner_condition .= ' )'; + $condition .= $inner_condition; + } + else { + $bindings[sprintf($param_prefix, $param_idx)] = $value; + $condition .= sprintf("%s %s :%s", $mapping_or[0], $filter->getOperator(), sprintf($param_prefix, $param_idx)); + ++$param_idx; + } + /**********************/ + } $query->andWhere($condition); } else { $mapping = explode(':', $mapping); $value = $filter->getValue(); + $condition = ''; if (count($mapping) > 1) { $value = $this->convertValue($value, $mapping[1]); } - $bindings[sprintf($param_prefix, $param_idx)] = $value; - $query = $query->andWhere(sprintf("%s %s :%s", $mapping[0], $filter->getOperator(), sprintf($param_prefix, $param_idx))); - ++$param_idx; + + if(is_array($value)){ + $inner_condition = '( '; + foreach ($value as $val) { + $inner_condition .= sprintf(" %s %s :%s %s ", $mapping[0], $filter->getOperator(), sprintf($param_prefix, $param_idx), $filter->getSameFieldOp()); + $bindings[sprintf($param_prefix, $param_idx)] = $val; + ++$param_idx; + } + $inner_condition = substr($inner_condition, 0, (strlen($filter->getSameFieldOp())+1) * -1); + $inner_condition .= ' )'; + $condition .= $inner_condition; + } + else { + $bindings[sprintf($param_prefix, $param_idx)] = $value; + $condition .= sprintf("%s %s :%s", $mapping[0], $filter->getOperator(), sprintf($param_prefix, $param_idx)); + ++$param_idx; + } + + $query->andWhere($condition); } } else if (is_array($filter)) { @@ -316,9 +360,23 @@ final class Filter } if(!empty($condition)) $condition .= ' OR '; - $bindings[sprintf($param_prefix, $param_idx)] = $value; - $condition .= sprintf(" %s %s :%s ", $mapping_or[0], $e->getOperator(), sprintf($param_prefix, $param_idx)); - ++$param_idx; + + if(is_array($value)){ + $inner_condition = '( '; + foreach ($value as $val) { + $inner_condition .= sprintf(" %s %s :%s %s ", $mapping_or[0], $e->getOperator(), sprintf($param_prefix, $param_idx), $e->getSameFieldOp()); + $bindings[sprintf($param_prefix, $param_idx)] = $val; + ++$param_idx; + } + $inner_condition = substr($inner_condition, 0, (strlen($e->getSameFieldOp())+1) * -1); + $inner_condition .= ' )'; + $condition .= $inner_condition; + } + else { + $bindings[sprintf($param_prefix, $param_idx)] = $value; + $condition .= sprintf("%s %s :%s", $mapping_or[0], $e->getOperator(), sprintf($param_prefix, $param_idx)); + ++$param_idx; + } } if(!empty($sub_or_query)) $sub_or_query .= ' OR '; $sub_or_query .= ' ( '.$condition.' ) '; @@ -333,9 +391,22 @@ final class Filter if(!empty($sub_or_query)) $sub_or_query .= ' OR '; - $bindings[sprintf($param_prefix, $param_idx)] = $value; - $sub_or_query .= sprintf(" %s %s :%s ", $mapping[0], $e->getOperator(), sprintf($param_prefix, $param_idx)); - ++$param_idx; + if(is_array($value)){ + $inner_condition = '( '; + foreach ($value as $val) { + $inner_condition .= sprintf(" %s %s :%s %s ", $mapping[0], $e->getOperator(), sprintf($param_prefix, $param_idx), $e->getSameFieldOp()); + $bindings[sprintf($param_prefix, $param_idx)] = $val; + ++$param_idx; + } + $inner_condition = substr($inner_condition, 0, (strlen($e->getSameFieldOp())+1) * -1); + $inner_condition .= ' )'; + $sub_or_query .= $inner_condition; + } + else { + $bindings[sprintf($param_prefix, $param_idx)] = $value; + $sub_or_query .= sprintf("%s %s :%s", $mapping[0], $e->getOperator(), sprintf($param_prefix, $param_idx)); + ++$param_idx; + } } } } @@ -356,14 +427,36 @@ final class Filter { switch ($original_format) { case 'datetime_epoch': + if(is_array($value)){ + $res = []; + foreach ($value as $val){ + $datetime = new \DateTime("@$val"); + $res[] = sprintf("%s", $datetime->format("Y-m-d H:i:s")); + } + return $res; + } $datetime = new \DateTime("@$value"); return sprintf("%s", $datetime->format("Y-m-d H:i:s")); break; case 'json_int': + if(is_array($value)){ + $res = []; + foreach ($value as $val){ + $res[] = intval($val); + } + return $res; + } return intval($value); break; case 'json_string': - return sprintf("%s",$value); + if(is_array($value)){ + $res = []; + foreach ($value as $val){ + $res[] = sprintf("%s", $val); + } + return $res; + } + return sprintf("%s", $value); break; default: return $value; @@ -401,9 +494,21 @@ final class Filter if (count($mapping) > 1) { $filter->setValue($this->convertValue($value, $mapping[1])); } - $cond = sprintf(' %s %s :%s', $mapping[0], $op, sprintf($param_prefix, $param_idx)); - $this->bindings[sprintf($param_prefix, $param_idx)] = $filter->getValue(); - ++$param_idx; + if(is_array($value)){ + $cond = '( '; + foreach ($value as $val) { + $cond .= sprintf(" %s %s :%s %s ", $mapping[0], $op, sprintf($param_prefix, $param_idx), $filter->getSameFieldOp()); + $this->bindings[sprintf($param_prefix, $param_idx)] = $val; + ++$param_idx; + } + $cond = substr($cond, 0, (strlen($filter->getSameFieldOp())+1) * -1); + $cond .= ' )'; + } + else { + $cond = sprintf(' %s %s :%s', $mapping[0], $op, sprintf($param_prefix, $param_idx)); + $this->bindings[sprintf($param_prefix, $param_idx)] = $filter->getValue(); + ++$param_idx; + } if (!empty($sql)) $sql .= " AND "; $sql .= $cond; } @@ -420,9 +525,22 @@ final class Filter if (count($mapping) > 1) { $e->setValue($this->convertValue($value, $mapping[1])); } - $cond = sprintf(" %s %s :%s", $mapping[0], $op, sprintf($param_prefix, $param_idx)); - $this->bindings[sprintf($param_prefix, $param_idx)] = $e->getValue(); - ++$param_idx; + + if(is_array($value)){ + $cond = '( '; + foreach ($value as $val) { + $cond .= sprintf(" %s %s :%s %s ", $mapping[0], $op, sprintf($param_prefix, $param_idx), $e->getSameFieldOp()); + $this->bindings[sprintf($param_prefix, $param_idx)] = $val; + ++$param_idx; + } + $cond = substr($cond, 0, (strlen($e->getSameFieldOp())+1) * -1); + $cond .= ' )'; + } + else { + $cond = sprintf(" %s %s :%s", $mapping[0], $op, sprintf($param_prefix, $param_idx)); + $this->bindings[sprintf($param_prefix, $param_idx)] = $e->getValue(); + ++$param_idx; + } if (!empty($sql_or)) $sql_or .= " OR "; $sql_or .= $cond; } diff --git a/app/Http/Utils/Filters/FilterElement.php b/app/Http/Utils/Filters/FilterElement.php index 800395ef..198ca01d 100644 --- a/app/Http/Utils/Filters/FilterElement.php +++ b/app/Http/Utils/Filters/FilterElement.php @@ -23,16 +23,23 @@ class FilterElement extends AbstractFilterElement */ private $field; + /** + * @var string + */ + private $same_field_op; + /** * @param $field * @param $value * @param $operator + * @param $same_field_op */ - protected function __construct($field, $value, $operator) + protected function __construct($field, $value, $operator, $same_field_op) { parent::__construct($operator); $this->field = $field; $this->value = $value; + $this->same_field_op = $same_field_op; } /** @@ -61,6 +68,13 @@ class FilterElement extends AbstractFilterElement switch($this->operator) { case 'like': + if(is_array($this->value)){ + $res = []; + foreach ($this->value as $val){ + $res[]= empty($val) ? '' : "%".$val."%"; + } + return $res; + } return empty($this->value) ? '' : "%".$this->value."%"; break; default: @@ -69,38 +83,42 @@ class FilterElement extends AbstractFilterElement } } - public static function makeEqual($field, $value) - { - return new self($field, $value, '='); + public function getSameFieldOp():?string { + return $this->same_field_op; } - public static function makeGreather($field, $value) + public static function makeEqual($field, $value, $same_field_op = null) { - return new self($field, $value, '>'); + return new self($field, $value, '=', $same_field_op); } - public static function makeGreatherOrEqual($field, $value) + public static function makeGreather($field, $value, $same_field_op = null) { - return new self($field, $value, '>='); + return new self($field, $value, '>', $same_field_op); } - public static function makeLower($field, $value) + public static function makeGreatherOrEqual($field, $value, $same_field_op = null) { - return new self($field, $value, '<'); + return new self($field, $value, '>=', $same_field_op); } - public static function makeLowerOrEqual($field, $value) + public static function makeLower($field, $value, $same_field_op = null) { - return new self($field, $value, '<='); + return new self($field, $value, '<', $same_field_op); } - public static function makeNotEqual($field, $value) + public static function makeLowerOrEqual($field, $value, $same_field_op = null) { - return new self($field, $value, '<>'); + return new self($field, $value, '<=', $same_field_op); } - public static function makeLike($field, $value) + public static function makeNotEqual($field, $value, $same_field_op = null) { - return new self($field, $value, 'like'); + return new self($field, $value, '<>', $same_field_op); + } + + public static function makeLike($field, $value, $same_field_op = null) + { + return new self($field, $value, 'like', $same_field_op); } } \ No newline at end of file diff --git a/app/Http/Utils/Filters/FilterParser.php b/app/Http/Utils/Filters/FilterParser.php index f4073c6b..d1f2c244 100644 --- a/app/Http/Utils/Filters/FilterParser.php +++ b/app/Http/Utils/Filters/FilterParser.php @@ -61,8 +61,24 @@ final class FilterParser if (!in_array($op, $allowed_fields[$field])){ throw new FilterParserException(sprintf("%s op is not allowed for filter by field %s",$op, $field)); } + // check if value has AND or OR values on same field + $same_field_op = null; + if(str_contains($value, '&&')){ + $values = explode('&&', $value); + if (count($values) > 1) { + $value = $values; + $same_field_op = 'AND'; + } + } + else if(str_contains($value, '||')){ + $values = explode('||', $value); + if (count($values) > 1) { + $value = $values; + $same_field_op = 'OR'; + } + } - $f_or = self::buildFilter($field, $op, $value); + $f_or = self::buildFilter($field, $op, $value, $same_field_op); if (!is_null($f_or)) $f[] = $f_or; } @@ -78,10 +94,21 @@ final class FilterParser $field = $operands[0]; $value = $operands[1]; - // parse AND on same fields - $values = explode('&&', $value); - if (count($values) > 1) { - $value = $values; + // check if value has AND or OR values on same field + $same_field_op = null; + if(str_contains($value, '&&')){ + $values = explode('&&', $value); + if (count($values) > 1) { + $value = $values; + $same_field_op = 'AND'; + } + } + else if(str_contains($value, '||')){ + $values = explode('||', $value); + if (count($values) > 1) { + $value = $values; + $same_field_op = 'OR'; + } } if (!isset($allowed_fields[$field])){ @@ -96,7 +123,7 @@ final class FilterParser $and_fields[] = $field; - $f = self::buildFilter($field, $op, $value); + $f = self::buildFilter($field, $op, $value, $same_field_op); } if (!is_null($f)) @@ -110,32 +137,33 @@ final class FilterParser * * @param string $field * @param string $op - * @param string $value + * @param mixed $value + * @param string $same_field_op * @return FilterElement|null */ - public static function buildFilter($field, $op, $value) + public static function buildFilter($field, $op, $value, $same_field_op = null ) { switch ($op) { case '==': - return FilterElement::makeEqual($field, $value); + return FilterElement::makeEqual($field, $value, $same_field_op); break; case '=@': - return FilterElement::makeLike($field, $value); + return FilterElement::makeLike($field, $value, $same_field_op); break; case '>': - return FilterElement::makeGreather($field, $value); + return FilterElement::makeGreather($field, $value, $same_field_op); break; case '>=': - return FilterElement::makeGreatherOrEqual($field, $value); + return FilterElement::makeGreatherOrEqual($field, $value, $same_field_op); break; case '<': - return FilterElement::makeLower($field, $value); + return FilterElement::makeLower($field, $value, $same_field_op); break; case '<=': - return FilterElement::makeLowerOrEqual($field, $value); + return FilterElement::makeLowerOrEqual($field, $value, $same_field_op); break; case '<>': - return FilterElement::makeNotEqual($field, $value); + return FilterElement::makeNotEqual($field, $value, $same_field_op); break; } return null; diff --git a/app/Http/Utils/IFileUploader.php b/app/Http/Utils/IFileUploader.php index b980bf9c..336c5df4 100644 --- a/app/Http/Utils/IFileUploader.php +++ b/app/Http/Utils/IFileUploader.php @@ -21,10 +21,10 @@ interface IFileUploader { /** * @param UploadedFile $file - * @param $folder_name + * @param string $path * @param bool $is_image * @return File * @throws \Exception */ - public function build(UploadedFile $file, $folder_name, $is_image = false); + public function build(UploadedFile $file, string $path, bool $is_image = false); } \ No newline at end of file diff --git a/app/Http/Utils/Logs/LaravelMailerHandler.php b/app/Http/Utils/Logs/LaravelMailerHandler.php index 64ed9300..af6376d2 100644 --- a/app/Http/Utils/Logs/LaravelMailerHandler.php +++ b/app/Http/Utils/Logs/LaravelMailerHandler.php @@ -12,16 +12,21 @@ * limitations under the License. **/ use Illuminate\Mail\Message; +use Illuminate\Support\Facades\Log; +use libs\utils\ICacheService; use Monolog\Handler\MailHandler; use Monolog\Logger; use Monolog\Formatter\LineFormatter; use Illuminate\Support\Facades\Mail; +use Illuminate\Support\Facades\App; /** * Class LaravelMailerHandler * @package App\Http\Utils\Logs */ final class LaravelMailerHandler extends MailHandler { + // in seconds + const TIME_BETWEEN_SAME_ERROR = 60 * 60; /** * The email addresses to which the message will be sent * @var array @@ -67,16 +72,24 @@ final class LaravelMailerHandler extends MailHandler protected $from = null; /** - * @param string|array $to The receiver of the mail - * @param string $subject The subject of the mail - * @param string $from The sender of the mail - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param int $maxColumnWidth The maximum column width that the message lines will have + * @var ICacheService */ - public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70) + private $cacheService; + + /** + * LaravelMailerHandler constructor. + * @param ICacheService $cacheService + * @param $to + * @param $subject + * @param $from + * @param int $level + * @param bool $bubble + * @param int $maxColumnWidth + */ + public function __construct(ICacheService $cacheService, $to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70) { parent::__construct($level, $bubble); + $this->cacheService = $cacheService; $this->from = $from; $this->to = is_array($to) ? $to : array($to); $this->subject = $subject; @@ -122,12 +135,24 @@ final class LaravelMailerHandler extends MailHandler { $content = wordwrap($content, $this->maxColumnWidth); + $subject = $this->subject; if ($records) { $subjectFormatter = new LineFormatter($this->subject); $subject = $subjectFormatter->format($this->getHighestRecord($records)); } + // to avoid bloating inboxes/quotas + if($this->cacheService){ + $footPrint = md5($subject.$content); + if($this->cacheService->exists($footPrint)){ + // short circuit + Log::debug(sprintf("LaravelMailerHandler::send skipping exception %s %s", $subject, $content)); + return; + } + $this->cacheService->setSingleValue($footPrint, $footPrint, LaravelMailerHandler::TIME_BETWEEN_SAME_ERROR); + } + foreach ($this->to as $to) { Mail::raw($content, function(Message $message) use($to, $subject, $content){ $message diff --git a/app/Http/Utils/SwiftBucket.php b/app/Http/Utils/SwiftBucket.php deleted file mode 100644 index d05fd9ea..00000000 --- a/app/Http/Utils/SwiftBucket.php +++ /dev/null @@ -1,102 +0,0 @@ -container)) { - - $configOptions = [ - 'authUrl' => Config::get("cloudstorage.auth_url"), - 'region' => Config::get("cloudstorage.region"), - ]; - - $userName = Config::get("cloudstorage.user_name"); - $userPassword = Config::get("cloudstorage.api_key"); - - if(!empty($userName) && !empty($userPassword)){ - $configOptions['user'] = [ - 'name' => $userName, - 'password' => $userPassword, - 'domain' => ['id' => Config::get("cloudstorage.user_domain", "default")] - ]; - - $configOptions['scope' ] = [ - 'project' => [ - 'name' => Config::get("cloudstorage.project_name"), - 'domain' => ['id' => Config::get("cloudstorage.project_domain", "default")] - ], - ]; - } - - $appCredentialId = Config::get("cloudstorage.app_credential_id"); - $appCredentialSecret = Config::get("cloudstorage.app_credential_secret"); - - if(!empty($appCredentialId) && !empty($appCredentialSecret)){ - $configOptions['application_credential'] = [ - 'id' => $appCredentialId, - 'secret' => $appCredentialSecret, - ]; - } - - $openstack = new OpenStack($configOptions); - - $this->container = $openstack->objectStoreV1()->getContainer( Config::get("cloudstorage.assets_container")); - } - - return $this->container; - } - - /** - * @param File $f - * @param string $local_path - * @return object|StorageObject - * @throws Exception - */ - public function put(File $f, $local_path) - { - - $fp = fopen($local_path, 'r'); - if (!$fp) { - throw new Exception("Unable to open file: " . $f->getFilename()); - } - - $options = [ - 'name' => $f->getRelativeLinkFor(), - 'stream' => new Stream($fp) - ]; - - return $this->getContainer()->createObject($options); - } - - -} \ No newline at end of file diff --git a/app/Http/Utils/UtilsProvider.php b/app/Http/Utils/UtilsProvider.php index f0362c53..79570cfb 100644 --- a/app/Http/Utils/UtilsProvider.php +++ b/app/Http/Utils/UtilsProvider.php @@ -28,7 +28,6 @@ final class UtilsProvider extends ServiceProvider public function register() { // file uploadedr service - App::singleton(IBucket::class, SwiftBucket::class); App::singleton(IFileUploader ::class, FileUploader::class); } } \ No newline at end of file diff --git a/app/Http/routes.php b/app/Http/routes.php index aace0494..471d032a 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -69,7 +69,8 @@ Route::group([ // companies Route::group(['prefix'=>'companies'], function(){ - Route::get('', 'OAuth2CompaniesApiController@getAll'); + Route::get('', 'OAuth2CompaniesApiController@getAllCompanies'); + Route::post('', 'OAuth2CompaniesApiController@add'); }); // organizations @@ -83,34 +84,85 @@ Route::group([ Route::get('', 'OAuth2GroupsApiController@getAll'); }); + // summit-media-file-types + Route::group(['prefix'=>'summit-media-file-types'], function(){ + Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaFileTypeApiController@getAll']); + Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaFileTypeApiController@add']); + Route::group(['prefix'=>'{id}'], function(){ + Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaFileTypeApiController@get']); + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaFileTypeApiController@update']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaFileTypeApiController@delete']); + }); + }); + // summits Route::group(array('prefix' => 'summits'), function () { Route::get('', [ 'middleware' => 'cache:'.Config::get('cache_api_response.get_summits_response_lifetime', 600), 'uses' => 'OAuth2SummitApiController@getSummits']); Route::group(['prefix' => 'all'], function () { - Route::get('', 'OAuth2SummitApiController@getAllSummits'); + + Route::get('', 'OAuth2SummitApiController@getAllSummits'); Route::get('{id}', 'OAuth2SummitApiController@getAllSummitByIdOrSlug'); - Route::group(['prefix' => 'selection-plans'], function () { - Route::get('current/{status}', ['uses' => 'OAuth2SummitSelectionPlansApiController@getCurrentSelectionPlanByStatus'])->where('status', 'submission|selection|voting'); - }); + Route::group(['prefix' => 'locations'], function () { // GET /api/v1/summits/all/locations/bookable-rooms/all/reservations/{id} Route::get('bookable-rooms/all/reservations/{id}', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitLocationsApiController@getReservationById']); }); + Route::group(['prefix' => 'registration-invitations'], function () { + Route::group(['prefix' => '{token}'], function () { + Route::get('', ['uses' => 'OAuth2SummitRegistrationInvitationApiController@getInvitationByToken']); + }); + }); + + Route::group(['prefix' => 'orders'], function () { + Route::get('me', 'OAuth2SummitOrdersApiController@getAllMyOrders'); + + Route::group(['prefix' => 'all'], function () { + Route::group(['prefix' => 'tickets'], function () { + Route::group(['prefix' => '{ticket_id}'], function () { + Route::put('', 'OAuth2SummitOrdersApiController@updateTicketById'); + Route::get('pdf', 'OAuth2SummitOrdersApiController@getTicketPDFById'); + }); + + Route::group(['prefix' => 'me'], function () { + Route::get('', 'OAuth2SummitTicketApiController@getAllMyTickets'); + }); + }); + }); + + Route::group(['prefix' => '{order_id}'], function () { + Route::delete('refund', 'OAuth2SummitOrdersApiController@requestRefundMyOrder'); + Route::put('resend', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrdersApiController@reSendOrderEmail']); + Route::put('', 'OAuth2SummitOrdersApiController@updateMyOrder'); + Route::group(['prefix' => 'tickets'], function () { + Route::group(['prefix' => '{ticket_id}'], function () { + Route::get('pdf', 'OAuth2SummitOrdersApiController@getTicketPDFByOrderId'); + Route::delete('refund', 'OAuth2SummitOrdersApiController@requestRefundMyTicket'); + Route::group(['prefix' => 'attendee'], function () { + Route::put('', 'OAuth2SummitOrdersApiController@assignAttendee'); + Route::put('reinvite', 'OAuth2SummitOrdersApiController@reInviteAttendee'); + Route::delete('', 'OAuth2SummitOrdersApiController@removeAttendee'); + }); + }); + }); + }); + + }); }); Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@addSummit']); Route::group(['prefix' => '{id}'], function () { + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@updateSummit']); Route::post('logo', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@addSummitLogo']); Route::delete('logo', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@deleteSummitLogo']); Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@deleteSummit']); Route::get('', [ 'middleware' => 'cache:'.Config::get('cache_api_response.get_summit_response_lifetime', 1200), 'uses' => 'OAuth2SummitApiController@getSummit'])->where('id', 'current|[0-9]+'); - // selection plans + // selection plans crud Route::group(['prefix' => 'selection-plans'], function () { Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitSelectionPlansApiController@addSelectionPlan']); Route::group(['prefix' => '{selection_plan_id}'], function () { @@ -159,39 +211,6 @@ Route::group([ Route::get('entity-events', 'OAuth2SummitApiController@getSummitEntityEvents'); - // attendees - Route::group(array('prefix' => 'attendees'), function () { - - Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@getAttendeesBySummit']); - Route::get('me', 'OAuth2SummitAttendeesApiController@getOwnAttendee'); - Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@addAttendee']); - Route::group(array('prefix' => '{attendee_id}'), function () { - - Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@getAttendee']); - Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@updateAttendee']); - Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@deleteAttendee']); - Route::group(array('prefix' => 'schedule'), function () - { - Route::get('', 'OAuth2SummitAttendeesApiController@getAttendeeSchedule')->where('attendee_id', 'me'); - - Route::group(array('prefix' => '{event_id}'), function (){ - Route::post('', 'OAuth2SummitAttendeesApiController@addEventToAttendeeSchedule')->where('attendee_id', 'me|[0-9]+'); - Route::delete('', 'OAuth2SummitAttendeesApiController@removeEventFromAttendeeSchedule')->where('attendee_id', 'me|[0-9]+'); - Route::delete('/rsvp', 'OAuth2SummitAttendeesApiController@deleteEventRSVP')->where('attendee_id', 'me|[0-9]+'); - Route::put('/check-in', 'OAuth2SummitAttendeesApiController@checkingAttendeeOnEvent')->where('attendee_id', 'me|[0-9]+'); - }); - }); - Route::group(array('prefix' => 'tickets'), function () - { - Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@addAttendeeTicket']); - Route::group(array('prefix' => '{ticket_id}'), function (){ - Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@deleteAttendeeTicket']); - Route::put('reassign/{other_member_id}', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@reassignAttendeeTicket']); - }); - }); - }); - }); - // notifications Route::group(['prefix' => 'notifications'], function () { Route::get('sent', 'OAuth2SummitNotificationsApiController@getAllApprovedByUser'); @@ -211,6 +230,7 @@ Route::group([ Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitSpeakersApiController@addSpeakerBySummit']); Route::get('', 'OAuth2SummitSpeakersApiController@getSpeakers'); + Route::get('on-schedule', 'OAuth2SummitSpeakersApiController@getSpeakersOnSchedule'); Route::get('me', 'OAuth2SummitSpeakersApiController@getMySummitSpeaker'); Route::group(['prefix' => '{speaker_id}'], function () { @@ -273,11 +293,10 @@ Route::group([ Route::group(['prefix' => 'feedback'], function () { Route::get('', ['middleware' => 'cache:'.Config::get('cache_api_response.get_event_feedback_response_lifetime', 300), 'uses' => 'OAuth2SummitEventsApiController@getEventFeedback']); }); - }); - Route::group(['prefix' => 'all'], function () { - Route::group(['prefix' => 'published'], function () { - Route::get('tags', 'OAuth2SummitEventsApiController@getScheduledEventsTags'); + Route::group(['prefix' => 'image'], function () { + Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitEventsApiController@addEventImage']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitEventsApiController@deleteEventImage']); }); }); }); @@ -328,6 +347,18 @@ Route::group([ Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2PresentationApiController@deletePresentationLink' ]); }); }); + + // media uploads + + Route::group(['prefix' => 'media-uploads'], function () { + Route::get('', 'OAuth2PresentationApiController@getPresentationMediaUploads'); + Route::post('', 'OAuth2PresentationApiController@addPresentationMediaUpload' ); + Route::group(['prefix' => '{media_upload_id}'], function () { + Route::get('', 'OAuth2PresentationApiController@getPresentationMediaUpload'); + Route::put('','OAuth2PresentationApiController@updatePresentationMediaUpload' ); + Route::delete('', 'OAuth2PresentationApiController@deletePresentationMediaUpload' ); + }); + }); }); }); @@ -409,7 +440,7 @@ Route::group([ Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitLocationsApiController@addVenueBookableRoom']); Route::group(['prefix' => '{room_id}'], function () { // GET /api/v1/summits/{id}/locations/venues/{venue_id}/bookable-rooms/{room_id} - Route::get('', 'OAuth2SummitLocationsApiController@getBookableVenueRoom'); + Route::get('', 'OAuth2SummitLocationsApiController@getBookableVenueRoomByVenue'); // PUT /api/v1/summits/{id}/locations/venues/{venue_id}/bookable-rooms/{room_id} Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitLocationsApiController@updateVenueBookableRoom']); // DELETE /api/v1/summits/{id}/locations/venues/{venue_id}/bookable-rooms/{room_id} @@ -550,6 +581,30 @@ Route::group([ Route::get('', 'OAuth2SummitsEventTypesApiController@getEventTypeBySummit'); Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitsEventTypesApiController@updateEventTypeBySummit']); Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitsEventTypesApiController@deleteEventTypeBySummit']); + + Route::group(['prefix' => 'summit-documents'], function () { + Route::group(['prefix' => '{document_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitsEventTypesApiController@addSummitDocument']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitsEventTypesApiController@removeSummitDocument']); + }); + }); + }); + }); + + // documents + Route::group(['prefix' => 'summit-documents'], function () { + Route::get('', 'OAuth2SummitDocumentsApiController@getAllBySummit'); + Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitDocumentsApiController@add']); + Route::group(['prefix' => '{document_id}'], function () { + Route::get('', 'OAuth2SummitDocumentsApiController@get'); + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitDocumentsApiController@update']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitDocumentsApiController@delete']); + Route::group(['prefix' => 'event-types'], function () { + Route::group(['prefix' => '{event_type_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitDocumentsApiController@addEventType']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitDocumentsApiController@removeEventType']); + }); + }); }); }); @@ -566,7 +621,276 @@ Route::group([ }); }); - // external orders + // begin registration endpoints + + // tax-types + Route::group(['prefix' => 'tax-types'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitTaxTypeApiController@getAllBySummit']); + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitTaxTypeApiController@add']); + Route::group(['prefix' => '{tax_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitTaxTypeApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitTaxTypeApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitTaxTypeApiController@delete']); + + Route::group(['prefix' => 'ticket-types'], function () { + Route::group(['prefix' => '{ticket_type_id}'], function () { + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitTaxTypeApiController@addTaxToTicketType']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitTaxTypeApiController@removeTaxFromTicketType']); + }); + }); + }); + }); + + // payment-gateway-profiles + Route::group(['prefix' => 'payment-gateway-profiles'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2PaymentGatewayProfileApiController@getAllBySummit']); + Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2PaymentGatewayProfileApiController@add']); + Route::group(['prefix' => '{payment_profile_id}'], function () { + Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2PaymentGatewayProfileApiController@get']); + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2PaymentGatewayProfileApiController@update']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2PaymentGatewayProfileApiController@delete']); + }); + }); + + // refund-policies + Route::group(['prefix' => 'refund-policies'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitRefundPolicyTypeApiController@getAllBySummit']); + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitRefundPolicyTypeApiController@add']); + Route::group(['prefix' => '{policy_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitRefundPolicyTypeApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitRefundPolicyTypeApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitRefundPolicyTypeApiController@delete']); + }); + }); + + // sponsors + Route::group(['prefix' => 'sponsors'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@getAllBySummit']); + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@add']); + Route::group(['prefix' => '{sponsor_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@delete']); + Route::group(['prefix' => 'users'], function () { + Route::group(['prefix' => '{member_id}'], function () { + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@addSponsorUser']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitSponsorApiController@removeSponsorUser']); + }); + }); + }); + }); + + // order-extra-questions + Route::group(['prefix' => 'order-extra-questions'], function () { + Route::get('metadata', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrderExtraQuestionTypeApiController@getMetadata']); + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrderExtraQuestionTypeApiController@getAllBySummit']); + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrderExtraQuestionTypeApiController@add']); + Route::group(['prefix' => '{question_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrderExtraQuestionTypeApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrderExtraQuestionTypeApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrderExtraQuestionTypeApiController@delete']); + Route::group(['prefix' => 'values'], function () { + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrderExtraQuestionTypeApiController@addQuestionValue']); + Route::group(['prefix' => '{value_id}'], function () { + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrderExtraQuestionTypeApiController@updateQuestionValue']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrderExtraQuestionTypeApiController@deleteQuestionValue']); + }); + }); + }); + }); + + // access-levels + Route::group(['prefix' => 'access-level-types'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAccessLevelTypeApiController@getAllBySummit']); + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAccessLevelTypeApiController@add']); + Route::group(['prefix' => '{level_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAccessLevelTypeApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAccessLevelTypeApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAccessLevelTypeApiController@delete']); + }); + }); + + // badge-feature-types + Route::group(['prefix' => 'badge-feature-types'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeFeatureTypeApiController@getAllBySummit']); + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeFeatureTypeApiController@add']); + Route::group(['prefix' => '{feature_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeFeatureTypeApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeFeatureTypeApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeFeatureTypeApiController@delete']); + }); + }); + + // badge-feature-types + Route::group(['prefix' => 'badge-scans'], function () { + + Route::get('me','OAuth2SummitBadgeScanApiController@getAllMyBadgeScans' ); + Route::get('', 'OAuth2SummitBadgeScanApiController@getAllBySummit'); + Route::get('csv','OAuth2SummitBadgeScanApiController@getAllBySummitCSV'); + Route::post('', "OAuth2SummitBadgeScanApiController@add"); + }); + + // badge-types + Route::group(['prefix' => 'badge-types'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeTypeApiController@getAllBySummit']); + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeTypeApiController@add']); + Route::group(['prefix' => '{badge_type_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeTypeApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeTypeApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeTypeApiController@delete']); + Route::group(['prefix' => 'access-levels'], function () { + Route::group(['prefix' => '{access_level_id}'], function () { + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeTypeApiController@addAccessLevelToBadgeType']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeTypeApiController@removeAccessLevelFromBadgeType']); + }); + }); + Route::group(['prefix' => 'features'], function () { + Route::group(['prefix' => '{feature_id}'], function () { + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeTypeApiController@addFeatureToBadgeType']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgeTypeApiController@removeFeatureFromBadgeType']); + }); + }); + + }); + }); + + // orders + Route::group(['prefix' => 'orders'], function () { + Route::get('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@getAllBySummit']); + Route::get('csv', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@getAllBySummitCSV']); + Route::post('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@add']); + Route::group(['prefix' => '{order_id}'], function () { + Route::get('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@get']); + Route::put('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@update']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@delete']); + Route::delete('refund', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@refundOrder']); + + Route::group(['prefix' => 'tickets'], function () { + Route::post('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@addTicket']); + Route::group(['prefix' => '{ticket_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@updateTicket']); + Route::get('pdf', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitOrdersApiController@getTicketPDFBySummit']); + }); + }); + }); + Route::post('reserve', 'OAuth2SummitOrdersApiController@reserve'); + Route::group(['prefix' => '{hash}'], function () { + Route::put('checkout', 'OAuth2SummitOrdersApiController@checkout'); + Route::group(['prefix' => 'tickets'], function () { + Route::get('mine', 'OAuth2SummitOrdersApiController@getMyTicketByOrderHash'); + }); + Route::delete('', 'OAuth2SummitOrdersApiController@cancel'); + }); + }); + + // tickets + Route::group(['prefix' => 'tickets'], function () { + Route::get('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@getAllBySummit']); + Route::group(['prefix' => 'csv'], function () { + Route::get('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@getAllBySummitCSV']); + Route::get('template', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@getImportTicketDataTemplate']); + Route::post('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@importTicketData']); + }); + + Route::post('ingest', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@ingestExternalTicketData']); + + Route::group(['prefix' => '{ticket_id}'], function () { + Route::get('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@get']); + // badge endpoints + Route::group(['prefix' => 'badge'], function () { + Route::post('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@createAttendeeBadge']); + Route::get('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@getAttendeeBadge']); + Route::group(['prefix' => 'current'], function () { + Route::delete('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@deleteAttendeeBadge']); + Route::put('print', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@printAttendeeBadge']); + Route::group(['prefix' => 'features'], function () { + Route::group(['prefix' => '{feature_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@addAttendeeBadgeFeature']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@removeAttendeeBadgeFeature']); + }); + }); + Route::group(['prefix' => 'type'], function () { + Route::group(['prefix' => '{type_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@updateAttendeeBadgeType']); + }); + }); + }); + }); + // badge endpoints + Route::delete('refund', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitTicketApiController@refundTicket']); + }); + }); + + // attendees + Route::group(array('prefix' => 'attendees'), function () { + + Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@getAttendeesBySummit']); + Route::get('csv', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@getAttendeesBySummitCSV']); + Route::get('me', 'OAuth2SummitAttendeesApiController@getOwnAttendee'); + Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@addAttendee']); + + Route::group(array('prefix' => '{attendee_id}'), function () { + Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@getAttendee']); + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@updateAttendee']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@deleteAttendee']); + // attendee schedule + Route::group(array('prefix' => 'schedule'), function () + { + Route::get('', 'OAuth2SummitAttendeesApiController@getAttendeeSchedule')->where('attendee_id', 'me'); + + Route::group(array('prefix' => '{event_id}'), function (){ + Route::post('', 'OAuth2SummitAttendeesApiController@addEventToAttendeeSchedule')->where('attendee_id', 'me|[0-9]+'); + Route::delete('', 'OAuth2SummitAttendeesApiController@removeEventFromAttendeeSchedule')->where('attendee_id', 'me|[0-9]+'); + Route::delete('/rsvp', 'OAuth2SummitAttendeesApiController@deleteEventRSVP')->where('attendee_id', 'me|[0-9]+'); + Route::put('/check-in', 'OAuth2SummitAttendeesApiController@checkingAttendeeOnEvent')->where('attendee_id', 'me|[0-9]+'); + }); + }); + + // attendee tickets + Route::group(array('prefix' => 'tickets'), function () + { + Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@addAttendeeTicket']); + Route::group(array('prefix' => '{ticket_id}'), function (){ + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@deleteAttendeeTicket']); + Route::group(array('prefix' => 'reassign'), function (){ + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@reassignAttendeeTicket']); + Route::put('{other_member_id}', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAttendeesApiController@reassignAttendeeTicketByMember']); + }); + }); + }); + }); + }); + + // invitations + Route::group(array('prefix' => 'registration-invitations'), function () { + Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitRegistrationInvitationApiController@getAllBySummit']); + Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitRegistrationInvitationApiController@add']); + Route::group(['prefix' => 'csv'], function () { + Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitRegistrationInvitationApiController@ingestInvitations']); + Route::get('', [ 'middleware' => 'auth.user', 'uses' =>'OAuth2SummitRegistrationInvitationApiController@getAllBySummitCSV']); + }); + + Route::group(['prefix' => 'all'], function () { + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitRegistrationInvitationApiController@deleteAll']); + Route::put('send', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitRegistrationInvitationApiController@send']); + }); + + Route::group(['prefix' => '{invitation_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitRegistrationInvitationApiController@update'])->where('invitation_id', '[0-9]+');; + Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitRegistrationInvitationApiController@get'])->where('invitation_id', '[0-9]+');; + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitRegistrationInvitationApiController@delete'])->where('invitation_id', '[0-9]+');; + }); + + + }); + + // badges + Route::group(['prefix' => 'badges'], function () { + Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgesApiController@getAllBySummit']); + Route::get('csv', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitBadgesApiController@getAllBySummitCSV']); + }); + + // external orders @todo to deprecate Route::group(['prefix' => 'external-orders'], function () { Route::get('{external_order_id}', 'OAuth2SummitApiController@getExternalOrder'); Route::post('{external_order_id}/external-attendees/{external_attendee_id}/confirm', 'OAuth2SummitApiController@confirmExternalOrderAttendee'); @@ -619,6 +943,10 @@ Route::group([ Route::post('', 'OAuth2SummitMembersApiController@addEventToMemberSchedule')->where('member_id', 'me'); Route::delete('', 'OAuth2SummitMembersApiController@removeEventFromMemberSchedule')->where('member_id', 'me'); + + + Route::put('enter', 'OAuth2SummitMembersApiController@enterToEvent')->where('member_id', 'me'); + Route::post('leave', 'OAuth2SummitMembersApiController@leaveFromEvent')->where('member_id', 'me'); }); }); }); @@ -697,6 +1025,19 @@ Route::group([ Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitPromoCodesApiController@updatePromoCodeBySummit']); Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitPromoCodesApiController@deletePromoCodeBySummit']); Route::post('mail', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitPromoCodesApiController@sendPromoCodeMail']); + Route::group(['prefix' => 'badge-features'], function () { + Route::group(['prefix' => '{badge_feature_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitPromoCodesApiController@addBadgeFeatureToPromoCode']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitPromoCodesApiController@removeBadgeFeatureFromPromoCode']); + }); + }); + + Route::group(['prefix' => 'ticket-types'], function () { + Route::group(['prefix' => '{ticket_type_id}'], function () { + Route::put('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitPromoCodesApiController@addTicketTypeToPromoCode']); + Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitPromoCodesApiController@removeTicketTypeFromPromoCode']); + }); + }); }); }); @@ -746,6 +1087,48 @@ Route::group([ }); }); + // email-flows-events + Route::group(['prefix' => 'email-flows-events'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitEmailEventFlowApiController@getAllBySummit']); + Route::group(['prefix' => '{event_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitEmailEventFlowApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitEmailEventFlowApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitEmailEventFlowApiController@delete']); + }); + }); + + // media-upload-types + + Route::group(['prefix' => 'media-upload-types'], function(){ + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaUploadTypeApiController@getAllBySummit']); + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaUploadTypeApiController@add']); + Route::group(['prefix' => '{media_upload_type_id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaUploadTypeApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaUploadTypeApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaUploadTypeApiController@delete']); + Route::group(['prefix' => 'presentation-types'] , function(){ + Route::group(['prefix' => '{event_type_id}'] , function(){ + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaUploadTypeApiController@addToPresentationType']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaUploadTypeApiController@deleteFromPresentationType']); + }); + }); + }); + + Route::group(['prefix' => 'all'], function () { + Route::post('clone/{to_summit_id}', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitMediaUploadTypeApiController@cloneMediaUploadTypes']); + }); + }); + }); + }); + + // sponsorship-types + Route::group(['prefix' => 'sponsorship-types'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SponsorshipTypeApiController@getAll']); + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SponsorshipTypeApiController@add']); + Route::group(['prefix' => '{id}'], function () { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SponsorshipTypeApiController@get']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SponsorshipTypeApiController@update']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SponsorshipTypeApiController@delete']); }); }); @@ -807,7 +1190,17 @@ Route::group([ Route::put('','OAuth2SummitSpeakersApiController@updateSpeaker')->where('speaker_id', 'me|[0-9]+'); Route::delete('',[ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitSpeakersApiController@deleteSpeaker'])->where('speaker_id', 'me|[0-9]+'); Route::get('', 'OAuth2SummitSpeakersApiController@getSpeaker'); - Route::post('/photo', 'OAuth2SummitSpeakersApiController@addSpeakerPhoto'); + // speaker photos + Route::group(['prefix' => 'photo'], function () { + Route::post('', [ 'uses' => 'OAuth2SummitSpeakersApiController@addSpeakerPhoto']); + Route::delete('', ['uses' => 'OAuth2SummitSpeakersApiController@deleteSpeakerPhoto']); + }); + + Route::group(['prefix' => 'big-photo'], function () { + Route::post('', [ 'uses' => 'OAuth2SummitSpeakersApiController@addSpeakerBigPhoto']); + Route::delete('', [ 'uses' => 'OAuth2SummitSpeakersApiController@deleteSpeakerBigPhoto']); + }); + }); }); @@ -848,9 +1241,34 @@ Route::group([ Route::delete('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2TrackQuestionsTemplateApiController@deleteTrackQuestionTemplateValue']); }); }); - }); }); + + // summit-administrator-groups + Route::group(['prefix'=>'summit-administrator-groups'], function(){ + Route::get('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAdministratorPermissionGroupApiController@getAll']); + Route::post('', [ 'middleware' => 'auth.user', 'uses' => 'OAuth2SummitAdministratorPermissionGroupApiController@add']); + Route::group(['prefix'=>'{group_id}'], function() { + Route::get('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAdministratorPermissionGroupApiController@get']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAdministratorPermissionGroupApiController@delete']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAdministratorPermissionGroupApiController@update']); + + Route::group(['prefix'=>'members'], function() { + Route::group(['prefix'=>'{member_id}'], function() { + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAdministratorPermissionGroupApiController@addMember']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAdministratorPermissionGroupApiController@removeMember']); + }); + }); + + Route::group(['prefix'=>'summits'], function() { + Route::group(['prefix'=>'{summit_id}'], function() { + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAdministratorPermissionGroupApiController@addSummit']); + Route::put('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitAdministratorPermissionGroupApiController@removeSummit']); + }); + }); + }); + }); + }); //OAuth2 Protected API V2 diff --git a/app/Jobs/CompensatePromoCodes.php b/app/Jobs/CompensatePromoCodes.php new file mode 100644 index 00000000..d69a8ca0 --- /dev/null +++ b/app/Jobs/CompensatePromoCodes.php @@ -0,0 +1,90 @@ +summit_id = $summit->getId(); + $this->code = $code; + $this->qty_to_return = $qty_to_return; + } + + /** + * @param ISummitRepository $summit_repository + * @param ISummitRegistrationPromoCodeRepository $repository + * @param ITransactionService $tx_service + * @throws \Exception + */ + public function handle + ( + ISummitRepository $summit_repository, + ISummitRegistrationPromoCodeRepository $repository, + ITransactionService $tx_service + ) + { + $tx_service->transaction(function() use($summit_repository, $repository){ + $summit = $summit_repository->getById($this->summit_id); + if(is_null($summit) || ! $summit instanceof Summit) return; + $promo_code = $repository->getByValueExclusiveLock($summit, $this->code); + if(is_null($promo_code) || !$promo_code instanceof SummitRegistrationPromoCode) return; + Log::debug(sprintf("CompensatePromoCodes::handle: compensating promo code %s on %s usages", $this->code, $this->qty_to_return)); + try { + $promo_code->removeUsage($this->qty_to_return); + } + catch (ValidationException $ex){ + Log::error($ex); + } + }); + } +} diff --git a/app/Jobs/CompensateTickets.php b/app/Jobs/CompensateTickets.php new file mode 100644 index 00000000..75f070bf --- /dev/null +++ b/app/Jobs/CompensateTickets.php @@ -0,0 +1,76 @@ +ticket_type_id = $ticket_type_id; + $this->qty_to_return = $qty_to_return; + } + + + /** + * @param ISummitTicketTypeRepository $repository + * @param ITransactionService $tx_service + * @throws \Exception + */ + public function handle(ISummitTicketTypeRepository $repository, ITransactionService $tx_service) + { + $tx_service->transaction(function () use ($repository) { + + $ticket_type = $repository->getByIdExclusiveLock($this->ticket_type_id); + if(is_null($ticket_type) || !$ticket_type instanceof SummitTicketType) return; + Log::debug(sprintf("CompensateTickets::handle: compensating ticket type %s on %s usages", $this->ticket_type_id, $this->qty_to_return)); + try { + $ticket_type->restore($this->qty_to_return); + } + catch(ValidationException $ex){ + Log::error($ex); + } + }); + } +} diff --git a/app/Jobs/Emails/AbstractEmailJob.php b/app/Jobs/Emails/AbstractEmailJob.php new file mode 100644 index 00000000..f413757d --- /dev/null +++ b/app/Jobs/Emails/AbstractEmailJob.php @@ -0,0 +1,100 @@ +template_identifier = $template_identifier; + if(empty($this->template_identifier)){ + throw new \InvalidArgumentException("missing template_identifier value"); + } + $this->payload = $payload; + $this->to_email = $to_email; + $this->subject = $subject; + } + + /** + * @param IMailApi $api + * @return array + * @throws \Exception + */ + public function handle + ( + IMailApi $api + ) + { + try { + Log::debug(sprintf("AbstractEmailJob::handle template_identifier %s to_email %s", $this->template_identifier, $this->to_email)); + return $api->sendEmail($this->payload, $this->template_identifier, $this->to_email, $this->subject); + } + catch (\Exception $ex){ + Log::error(sprintf("AbstractEmailJob::sendEmail template_identifier %s to_email %s", $this->template_identifier, $this->to_email)); + Log::error($ex); + throw $ex; + } + } + + abstract protected function getEmailEventSlug():string; + + /** + * @param Summit $summit + * @return string|null + */ + protected function getEmailTemplateIdentifierFromEmailEvent(Summit $summit):?string{ + return $summit->getEmailIdentifierPerEmailEventFlowSlug($this->getEmailEventSlug()); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/BookableRooms/AbstractBookableRoomReservationEmail.php b/app/Jobs/Emails/BookableRooms/AbstractBookableRoomReservationEmail.php new file mode 100644 index 00000000..d923f0bd --- /dev/null +++ b/app/Jobs/Emails/BookableRooms/AbstractBookableRoomReservationEmail.php @@ -0,0 +1,56 @@ +getOwner()->getEmail(); + } + + /** + * AbstractBookableRoomReservationEmail constructor. + * @param string $to + * @param SummitRoomReservation $reservation + */ + public function __construct(SummitRoomReservation $reservation) + { + $payload = []; + $room = $reservation->getRoom(); + $summit = $room->getSummit(); + $payload['owner_fullname'] = $reservation->getOwner()->getFullName(); + $payload['owner_email'] = $reservation->getOwner()->getEmail(); + $payload['room_complete_name'] = $room->getCompleteName(); + $payload['reservation_start_datetime'] = $reservation->getLocalStartDatetime()->format("Y-m-d H:i:s"); + $payload['reservation_end_datetime'] = $reservation->getLocalEndDatetime()->format("Y-m-d H:i:s"); + $payload['reservation_created_datetime'] = $reservation->getCreated()->format("Y-m-d H:i:s"); + $payload['reservation_amount'] = $reservation->getAmount(); + $payload['reservation_currency'] = $reservation->getCurrency(); + $payload['reservation_id'] = $reservation->getId(); + $payload['room_capacity'] = $room->getCapacity(); + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['reservation_refunded_amount'] = $reservation->getRefundedAmount(); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + parent::__construct($payload, $template_identifier, $this->getTo($reservation)); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/BookableRooms/BookableRoomReservationCanceledEmail.php b/app/Jobs/Emails/BookableRooms/BookableRoomReservationCanceledEmail.php new file mode 100644 index 00000000..038da89b --- /dev/null +++ b/app/Jobs/Emails/BookableRooms/BookableRoomReservationCanceledEmail.php @@ -0,0 +1,31 @@ +getSummit(); + $creator = $presentation->getCreator(); + $selection_plan = $presentation->getSelectionPlan(); + + if(is_null($selection_plan)) + throw new \InvalidArgumentException('Presentation selection plan is null.'); + + $speaker_management_base_url = Config::get('cfp.base_url'); + $idp_base_url = Config::get('idp.base_url'); + $support_email = $summit->getSupportEmail(); + $support_email = !empty($support_email) ? $support_email: Config::get("cfp.support_email", null); + + if(empty($speaker_management_base_url)) + throw new \InvalidArgumentException('cfp.base_url is null.'); + + if(empty($idp_base_url)) + throw new \InvalidArgumentException('idp.base_url is null.'); + + if(empty($support_email)) + throw new \InvalidArgumentException('cfp.support_email is null.'); + + $payload = []; + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['creator_full_name'] = $creator->getFullName(); + $payload['creator_email'] = $creator->getEmail(); + $payload['selection_plan_name'] = $selection_plan->getName(); + $payload['presentation_edit_link'] = $presentation->getEditLink(); + $payload['summit_date'] = $summit->getMonthYear(); + $payload['until_date'] = $selection_plan->getSubmissionEndDate()->format('d F, Y'); + $payload['selection_process_link'] = sprintf("%s/app/%s", $speaker_management_base_url, $summit->getRawSlug()); + $payload['speaker_management_link'] = sprintf("%s/app/%s", $speaker_management_base_url, $summit->getRawSlug()); + $payload['bio_edit_link'] = sprintf("%s/app/%s/profile", $speaker_management_base_url, $summit->getRawSlug()); + $payload['reset_password_link'] = sprintf("%s/auth/password/reset", $idp_base_url); + $payload['support_email'] = $support_email; + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['creator_email']); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/PresentationSpeakerNotificationEmail.php b/app/Jobs/Emails/PresentationSubmissions/PresentationSpeakerNotificationEmail.php new file mode 100644 index 00000000..ea75ab3d --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/PresentationSpeakerNotificationEmail.php @@ -0,0 +1,85 @@ +getSummit(); + $creator = $presentation->getCreator(); + $selection_plan = $presentation->getSelectionPlan(); + + if(is_null($selection_plan)) + throw new \InvalidArgumentException('Presentation selection plan is null.'); + + $speaker_management_base_url = Config::get('cfp.base_url'); + $idp_base_url = Config::get('idp.base_url'); + $support_email = $summit->getSupportEmail(); + $support_email = !empty($support_email) ? $support_email: Config::get("cfp.support_email", null); + + + if(empty($speaker_management_base_url)) + throw new \InvalidArgumentException('cfp.base_url is null.'); + + if(empty($idp_base_url)) + throw new \InvalidArgumentException('idp.base_url is null.'); + + if(empty($support_email)) + throw new \InvalidArgumentException('cfp.support_email is null.'); + + $payload = []; + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['speaker_full_name'] = $speaker->getFullName(); + $payload['speaker_email'] = $speaker->getEmail(); + $payload['creator_full_name'] = $creator->getFullName(); + $payload['creator_email'] = $creator->getEmail(); + $payload['selection_plan_name'] = $selection_plan->getName(); + $payload['presentation_edit_link'] = $presentation->getEditLink(); + $payload['summit_date'] = $summit->getMonthYear(); + $payload['until_date'] = $selection_plan->getSubmissionEndDate()->format('d F, Y'); + $payload['selection_process_link'] = sprintf("%s/app/%s", $speaker_management_base_url, $summit->getRawSlug()); + $payload['speaker_management_link'] = sprintf("%s/app/%s", $speaker_management_base_url, $summit->getRawSlug()); + $payload['bio_edit_link'] = sprintf("%s/app/%s/profile", $speaker_management_base_url, $summit->getRawSlug()); + $payload['reset_password_link'] = sprintf("%s/auth/password/reset", $idp_base_url); + $payload['support_email'] = $support_email; + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['speaker_email']); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAcceptedAlternateEmail.php b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAcceptedAlternateEmail.php new file mode 100644 index 00000000..53403c4c --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAcceptedAlternateEmail.php @@ -0,0 +1,63 @@ +getSummit(); + $this->payload['accepted_presentations'] = []; + foreach($speaker->getPublishedRegularPresentations($summit, $speaker_role) as $p){ + $this->payload['accepted_presentations'][] = ['title' => $p->getTitle()]; + } + $this->payload['alternate_presentations'] = []; + foreach($speaker->getAlternatePresentations($summit, $speaker_role) as $p){ + $this->payload['alternate_presentations'][] = ['title' => $p->getTitle()]; + } + + $payload['speaker_confirmation_link'] = sprintf("%s?t=%s", $this->payload['speaker_confirmation_link'], base64_encode($confirmation_token)); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAcceptedOnlyEmail.php b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAcceptedOnlyEmail.php new file mode 100644 index 00000000..5680bb2c --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAcceptedOnlyEmail.php @@ -0,0 +1,59 @@ +getSummit(); + $this->payload['accepted_presentations'] = []; + foreach($speaker->getPublishedRegularPresentations($summit, $speaker_role) as $p){ + $this->payload['accepted_presentations'][] = ['title' => $p->getTitle()]; + } + + $payload['speaker_confirmation_link'] = sprintf("%s?t=%s", $this->payload['speaker_confirmation_link'], base64_encode($confirmation_token)); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAcceptedRejectedEmail.php b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAcceptedRejectedEmail.php new file mode 100644 index 00000000..be91fdcb --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAcceptedRejectedEmail.php @@ -0,0 +1,64 @@ +getSummit(); + $this->payload['accepted_presentations'] = []; + foreach($speaker->getPublishedRegularPresentations($summit, $speaker_role) as $p){ + $this->payload['accepted_presentations'][] = ['title' => $p->getTitle()]; + } + $this->payload['rejected_presentations'] = []; + foreach($speaker->getRejectedPresentations($summit, $speaker_role) as $p){ + $this->payload['rejected_presentations'][] = ['title' => $p->getTitle()]; + } + + $payload['speaker_confirmation_link'] = sprintf("%s?t=%s", $this->payload['speaker_confirmation_link'], base64_encode($confirmation_token)); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAlternateOnlyEmail.php b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAlternateOnlyEmail.php new file mode 100644 index 00000000..e365992f --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAlternateOnlyEmail.php @@ -0,0 +1,60 @@ +getSummit(); + $this->payload['alternate_presentations'] = []; + foreach($speaker->getAlternatePresentations($summit, $speaker_role) as $p){ + $this->payload['alternate_presentations'][] = ['title' => $p->getTitle()]; + } + + $payload['speaker_confirmation_link'] = sprintf("%s?t=%s", $this->payload['speaker_confirmation_link'], base64_encode($confirmation_token)); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAlternateRejectedEmail.php b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAlternateRejectedEmail.php new file mode 100644 index 00000000..43516af9 --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessAlternateRejectedEmail.php @@ -0,0 +1,64 @@ +getSummit(); + $this->payload['alternate_presentations'] = []; + foreach($speaker->getAlternatePresentations($summit, $speaker_role) as $p){ + $this->payload['alternate_presentations'][] = ['title' => $p->getTitle()]; + } + $this->payload['rejected_presentations'] = []; + foreach($speaker->getRejectedPresentations($summit, $speaker_role) as $p){ + $this->payload['rejected_presentations'][] = ['title' => $p->getTitle()]; + } + + $payload['speaker_confirmation_link'] = sprintf("%s?t=%s", $this->payload['speaker_confirmation_link'], base64_encode($confirmation_token)); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessEmail.php b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessEmail.php new file mode 100644 index 00000000..971596b5 --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessEmail.php @@ -0,0 +1,68 @@ +getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_schedule_url'] = $summit->getScheduleDefaultPageUrl(); + $payload['summit_site_url'] = $summit->getDefaultPageUrl(); + $payload['speaker_full_name'] = $speaker->getFullName(); + $payload['speaker_email'] = $speaker->getEmail(); + $speaker_management_base_url = Config::get('cfp.base_url'); + if(empty($speaker_management_base_url)) + throw new \InvalidArgumentException('cfp.base_url is null.'); + + $payload['promo_code'] = ''; + $payload['promo_code_until_date'] = ''; + $payload['ticket_type'] = ''; + + if(!is_null($promo_code)){ + $payload['promo_code'] = $promo_code->getCode(); + if(!is_null($promo_code->getValidUntilDate())) + $payload['promo_code_until_date'] = $promo_code->getValidUntilDate()->format("Y-m-d H:i:s"); + $allowed_ticket_types = $promo_code->getAllowedTicketTypes(); + if(count($allowed_ticket_types) > 0) + $payload['ticket_type'] = $allowed_ticket_types[0]->getName(); + } + + $payload['bio_edit_link'] = sprintf("%s/app/profile", $speaker_management_base_url); + $payload['speaker_confirmation_link'] = $summit->getSpeakerConfirmationDefaultPageUrl(); + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['speaker_email']); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessEmailFactory.php b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessEmailFactory.php new file mode 100644 index 00000000..29392c92 --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessEmailFactory.php @@ -0,0 +1,123 @@ +getToken() + ); + break; + case SpeakerAnnouncementSummitEmail::TypeRejected: + PresentationSpeakerSelectionProcessRejectedEmail::dispatch + ( + $summit, + $speaker, + $speaker_role + ); + break; + case SpeakerAnnouncementSummitEmail::TypeAcceptedAlternate: + PresentationSpeakerSelectionProcessAcceptedAlternateEmail::dispatch + ( + $summit, + $promo_code, + $speaker, + $speaker_role, + $speaker_assistance->getToken() + ); + break; + case SpeakerAnnouncementSummitEmail::TypeAcceptedRejected: + PresentationSpeakerSelectionProcessAcceptedRejectedEmail::dispatch + ( + $summit, + $promo_code, + $speaker, + $speaker_role, + $speaker_assistance->getToken() + ); + break; + case SpeakerAnnouncementSummitEmail::TypeAlternate: + PresentationSpeakerSelectionProcessAlternateOnlyEmail::dispatch + ( + $summit, + $promo_code, + $speaker, + $speaker_role, + $speaker_assistance->getToken() + ); + break; + case SpeakerAnnouncementSummitEmail::TypeAlternateRejected: + PresentationSpeakerSelectionProcessAlternateRejectedEmail::dispatch + ( + $summit, + $promo_code, + $speaker, + $speaker_role, + $speaker_assistance->getToken() + ); + break; + } + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessRejectedEmail.php b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessRejectedEmail.php new file mode 100644 index 00000000..7748fd8d --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SelectionProcess/PresentationSpeakerSelectionProcessRejectedEmail.php @@ -0,0 +1,52 @@ +payload['rejected_presentations'] = []; + foreach($speaker->getRejectedPresentations($summit, $speaker_role) as $p){ + $this->payload['rejected_presentations'][] = ['title' => $p->getTitle()]; + } + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SpeakerCreationEmail.php b/app/Jobs/Emails/PresentationSubmissions/SpeakerCreationEmail.php new file mode 100644 index 00000000..d2d1d940 --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SpeakerCreationEmail.php @@ -0,0 +1,75 @@ +getFullName(); + $payload['speaker_email'] = $speaker->getEmail(); + $payload['speaker_management_link'] = $speaker_management_base_url; + $bio_edit_link = sprintf("%s/app/profile", $speaker_management_base_url); + $registrationRequest = $speaker->getRegistrationRequest(); + /** + * + @todo need 2 update CFP to support registration request retrieval + if(is_null($registrationRequest)){ + $token = $registrationRequest->getToken(); + if(!is_null($token)) + $bio_edit_link = $bio_edit_link.'/'.$token; + } + */ + $payload['bio_edit_link'] = $bio_edit_link; + $payload['reset_password_link'] = sprintf("%s/auth/password/reset", $idp_base_url); + $payload['support_email'] = $support_email; + $payload['tenant_name'] = Config::get("app.tenant_name"); + + parent::__construct($payload, self::DEFAULT_TEMPLATE, $payload['speaker_email']); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SpeakerEditPermissionApprovedEmail.php b/app/Jobs/Emails/PresentationSubmissions/SpeakerEditPermissionApprovedEmail.php new file mode 100644 index 00000000..0e8bad09 --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SpeakerEditPermissionApprovedEmail.php @@ -0,0 +1,49 @@ +getRequestedBy()->getFullName(); + $payload['speaker_full_name'] = $request->getSpeaker()->getFullName(); + $payload['speaker_management_link'] = + $payload['tenant_name'] = Config::get("app.tenant_name"); + $payload['requested_by_email'] = $request->getRequestedBy()->getEmail(); + parent::__construct($payload, self::DEFAULT_TEMPLATE, $payload['requested_by_email']); + } + +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SpeakerEditPermissionRejectedEmail.php b/app/Jobs/Emails/PresentationSubmissions/SpeakerEditPermissionRejectedEmail.php new file mode 100644 index 00000000..63029b4f --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SpeakerEditPermissionRejectedEmail.php @@ -0,0 +1,49 @@ +getRequestedBy()->getFullName(); + $payload['speaker_full_name'] = $request->getSpeaker()->getFullName(); + $payload['speaker_management_link'] = + $payload['tenant_name'] = Config::get("app.tenant_name"); + $payload['requested_by_email'] = $request->getRequestedBy()->getEmail(); + parent::__construct($payload, self::DEFAULT_TEMPLATE, $payload['requested_by_email']); + } + +} \ No newline at end of file diff --git a/app/Jobs/Emails/PresentationSubmissions/SpeakerEditPermissionRequestedEmail.php b/app/Jobs/Emails/PresentationSubmissions/SpeakerEditPermissionRequestedEmail.php new file mode 100644 index 00000000..582e6f74 --- /dev/null +++ b/app/Jobs/Emails/PresentationSubmissions/SpeakerEditPermissionRequestedEmail.php @@ -0,0 +1,54 @@ +getRequestedBy()->getFullName(); + $payload['speaker_full_name'] = $request->getSpeaker()->getFullName(); + $payload['token'] = $token; + $payload['link'] = $request->getConfirmationLink($request->getSpeaker()->getId(), $token); + $payload['tenant_name'] = Config::get("app.tenant_name"); + $payload['requested_by_email'] = $request->getRequestedBy()->getEmail(); + $payload['speaker_email'] = $request->getSpeaker()->getEmail(); + parent::__construct($payload, self::DEFAULT_TEMPLATE, $payload['speaker_email']); + } + + protected function getEmailEventSlug(): string + { + return self::EVENT_SLUG; + } + +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/AbstractSummitAttendeeTicketEmail.php b/app/Jobs/Emails/Registration/AbstractSummitAttendeeTicketEmail.php new file mode 100644 index 00000000..9cb628ed --- /dev/null +++ b/app/Jobs/Emails/Registration/AbstractSummitAttendeeTicketEmail.php @@ -0,0 +1,78 @@ +payload['owner_email']; + // check if exist at idp + $user = $memberService->checkExternalUser($email); + + if(is_null($user)){ + + // user does not exist at idp so we need to generate a registration request + // and create the magic links to complete the registration request + + $userRegistrationRequest = $memberService->emitRegistrationRequest + ( + $email, + $this->payload['owner_first_name'], + $this->payload['owner_last_name'] + ); + + $setPasswordLink = $userRegistrationRequest['set_password_link']; + + if(isset($this->payload['summit_virtual_site_url']) && + !empty($this->payload['summit_virtual_site_url']) && + isset($this->payload['summit_virtual_site_oauth2_client_id']) && + !empty($this->payload['summit_virtual_site_oauth2_client_id'])){ + $this->payload['summit_virtual_site_url'] = sprintf( + "%s?client_id=%s&redirect_uri=%s", + $setPasswordLink, + $this->payload['summit_virtual_site_oauth2_client_id'], + urlencode($this->payload['summit_virtual_site_url']) + ); + } + + if(isset($this->payload['summit_marketing_site_url']) && + !empty($this->payload['summit_marketing_site_url']) && + isset($this->payload['summit_marketing_site_oauth2_client_id']) && + !empty($this->payload['summit_marketing_site_oauth2_client_id'])){ + $this->payload['summit_marketing_site_url'] = sprintf( + "%s?client_id=%s&redirect_uri=%s", + $setPasswordLink, + $this->payload['summit_marketing_site_oauth2_client_id'], + urlencode($this->payload['summit_marketing_site_url']) + ); + } + } + } + return parent::handle($api); + } + +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/ExternalIngestion/SuccessfulIIngestionEmail.php b/app/Jobs/Emails/Registration/ExternalIngestion/SuccessfulIIngestionEmail.php new file mode 100644 index 00000000..63990936 --- /dev/null +++ b/app/Jobs/Emails/Registration/ExternalIngestion/SuccessfulIIngestionEmail.php @@ -0,0 +1,52 @@ +getId(); + $payload['summit_name'] = $summit->getName(); + $payload['feed_type'] = $summit->getExternalRegistrationFeedType(); + $payload['external_id'] = $summit->getExternalSummitId(); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $email_to); + } + +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/ExternalIngestion/UnsuccessfulIIngestionEmail.php b/app/Jobs/Emails/Registration/ExternalIngestion/UnsuccessfulIIngestionEmail.php new file mode 100644 index 00000000..f6f61d5b --- /dev/null +++ b/app/Jobs/Emails/Registration/ExternalIngestion/UnsuccessfulIIngestionEmail.php @@ -0,0 +1,55 @@ +getId(); + $payload['summit_name'] = $summit->getName(); + $payload['feed_type'] = $summit->getExternalRegistrationFeedType(); + $payload['external_id'] = $summit->getExternalSummitId(); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $email_to); + } + +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/Invitations/InviteSummitRegistrationEmail.php b/app/Jobs/Emails/Registration/Invitations/InviteSummitRegistrationEmail.php new file mode 100644 index 00000000..9f96c60b --- /dev/null +++ b/app/Jobs/Emails/Registration/Invitations/InviteSummitRegistrationEmail.php @@ -0,0 +1,79 @@ +getSummit(); + $owner_email = $invitation->getEmail(); + $payload = []; + $payload['owner_email'] = $owner_email; + $payload['first_name'] = $invitation->getFirstName(); + $payload['last_name'] = $invitation->getLastName(); + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + + $base_url = Config::get('registration.dashboard_base_url', null); + $invitation_form_url = Config::get('registration.dashboard_invitation_form_url', null); + + if (empty($base_url)) + throw new \InvalidArgumentException("missing dashboard_base_url value"); + if (empty($invitation_form_url)) + throw new \InvalidArgumentException("missing dashboard_invitation_form_url value"); + + $payload['invitation_form_url'] = sprintf($invitation_form_url, $base_url, $invitation->getToken()); + + if(!empty($invitation->getSetPasswordLink())){ + $payload['invitation_form_url'] = sprintf( + "%s?client_id=%s&redirect_uri=%s", + $invitation->getSetPasswordLink(), + Config::get("registration.dashboard_client_id"), + urlencode($payload['invitation_form_url']) + ); + } + + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $owner_email); + } + + protected function getEmailEventSlug(): string + { + return self::EVENT_SLUG; + } + + // metadata + const EVENT_SLUG = 'SUMMIT_REGISTRATION_INVITE_REGISTRATION'; + const EVENT_NAME = 'SUMMIT_REGISTRATION_INVITE_REGISTRATION'; + const DEFAULT_TEMPLATE = 'SUMMIT_REGISTRATION_INVITE_REGISTRATION'; +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/Invitations/ProcessRegistrationInvitationsJob.php b/app/Jobs/Emails/Registration/Invitations/ProcessRegistrationInvitationsJob.php new file mode 100644 index 00000000..cd7acc80 --- /dev/null +++ b/app/Jobs/Emails/Registration/Invitations/ProcessRegistrationInvitationsJob.php @@ -0,0 +1,66 @@ +summit_id = $summit->getId(); + $this->payload = $payload; + $this->filter = $filter; + } + + /** + * @param ISummitRegistrationInvitationService $service + * @throws \utils\FilterParserException + */ + public function handle(ISummitRegistrationInvitationService $service){ + + Log::debug(sprintf("ProcessRegistrationInvitationsJob::handle summit id %s", $this->summit_id)); + $filter = !is_null($this->filter) ? FilterParser::parse($this->filter, [ + 'is_accepted' => ['=='], + 'is_sent' => ['=='], + ]) : null; + + $service->send($this->summit_id, $this->payload, $filter); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/Invitations/ReInviteSummitRegistrationEmail.php b/app/Jobs/Emails/Registration/Invitations/ReInviteSummitRegistrationEmail.php new file mode 100644 index 00000000..ef1703db --- /dev/null +++ b/app/Jobs/Emails/Registration/Invitations/ReInviteSummitRegistrationEmail.php @@ -0,0 +1,79 @@ +getSummit(); + $owner_email = $invitation->getEmail(); + $payload = []; + $payload['owner_email'] = $owner_email; + $payload['first_name'] = $invitation->getFirstName(); + $payload['last_name'] = $invitation->getLastName(); + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + + $base_url = Config::get('registration.dashboard_base_url', null); + $invitation_form_url = Config::get('registration.dashboard_invitation_form_url', null); + + if (empty($base_url)) + throw new \InvalidArgumentException("missing dashboard_base_url value"); + if (empty($invitation_form_url)) + throw new \InvalidArgumentException("missing dashboard_invitation_form_url value"); + + $payload['invitation_form_url'] = sprintf($invitation_form_url, $base_url, $invitation->getToken()); + + if(!empty($invitation->getSetPasswordLink())){ + $payload['invitation_form_url'] = sprintf( + "%s?client_id=%s&redirect_uri=%s", + $invitation->getSetPasswordLink(), + Config::get("registration.dashboard_client_id"), + urlencode($payload['invitation_form_url']) + ); + } + + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $owner_email); + } + + protected function getEmailEventSlug(): string + { + return self::EVENT_SLUG; + } + + // metadata + const EVENT_SLUG = 'SUMMIT_REGISTRATION_REINVITE_REGISTRATION'; + const EVENT_NAME = 'SUMMIT_REGISTRATION_REINVITE_REGISTRATION'; + const DEFAULT_TEMPLATE = 'SUMMIT_REGISTRATION_REINVITE_REGISTRATION'; +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/InviteAttendeeTicketEditionMail.php b/app/Jobs/Emails/Registration/InviteAttendeeTicketEditionMail.php new file mode 100644 index 00000000..faa6f482 --- /dev/null +++ b/app/Jobs/Emails/Registration/InviteAttendeeTicketEditionMail.php @@ -0,0 +1,124 @@ +getOwner(); + $order = $ticket->getOrder(); + $summit = $order->getSummit(); + $payload = []; + + $payload['order_owner_full_name'] = $order->getOwnerFullName(); + $payload['order_owner_company'] = $order->getOwnerCompany(); + $payload['order_owner_email'] = $order->getOwnerEmail(); + + $payload['owner_full_name'] = $owner->getFullName(); + $payload['owner_company'] = $owner->getCompanyName(); + $payload['owner_email'] = $owner->getEmail(); + $payload['owner_first_name'] = $owner->getFirstName(); + $payload['owner_last_name'] = $owner->getSurname(); + + $summit_reassign_ticket_till_date = $summit->getReassignTicketTillDateLocal(); + if(!is_null($summit_reassign_ticket_till_date)) { + $payload['summit_reassign_ticket_till_date'] = $summit_reassign_ticket_till_date->format("l j F Y h:i A T"); + } + + if(empty($payload['owner_full_name'])){ + Log::warning(sprintf("InviteAttendeeTicketEditionMail owner_full_name is empty setting email")); + $payload['owner_full_name'] = $payload['owner_email']; + } + + if(empty($payload['owner_first_name'])){ + Log::warning(sprintf("InviteAttendeeTicketEditionMail owner_first_name is empty setting email")); + $payload['owner_first_name'] = $payload['owner_email']; + } + + if(empty($payload['owner_last_name'])){ + Log::warning(sprintf("InviteAttendeeTicketEditionMail owner_last_name is empty setting email")); + $payload['owner_last_name'] = $payload['owner_email']; + } + + $payload['hash'] = $ticket->getHash(); + + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + $payload['summit_virtual_site_oauth2_client_id'] = $summit->getVirtualSiteOAuth2ClientId(); + $payload['summit_marketing_site_oauth2_client_id'] = $summit->getMarketingSiteOAuth2ClientId(); + + $base_url = Config::get('registration.dashboard_base_url', null); + $edit_ticket_link = Config::get('registration.dashboard_attendee_edit_form_url', null); + + if (empty($base_url)) + throw new \InvalidArgumentException("missing dashboard_base_url value"); + if (empty($edit_ticket_link)) + throw new \InvalidArgumentException("missing dashboard_attendee_edit_form_url value"); + + $payload['edit_ticket_link'] = sprintf($edit_ticket_link, $base_url, $payload['hash']); + $payload['ticket_number'] = $ticket->getNumber(); + $payload['ticket_type_name'] = $ticket->getTicketType()->getName(); + $payload['ticket_raw_amount'] = $ticket->getRawCost(); + $payload['ticket_currency'] = $ticket->getCurrency(); + $payload['ticket_currency_symbol'] = '$'; + $payload['ticket_discount'] = $ticket->getDiscount(); + $payload['ticket_taxes'] = $ticket->getTaxesAmount(); + $payload['ticket_amount'] = $ticket->getFinalAmount(); + $payload['need_details'] = $owner->needToFillDetails(); + + $promo_code = $ticket->hasPromoCode() ? $ticket->getPromoCode() : null; + $payload['promo_code'] = ''; + if (!is_null($promo_code)) { + $payload['promo_code'] = $promo_code->getCode(); + + if ($promo_code instanceof SummitRegistrationDiscountCode) { + $payload['promo_code_discount_rate'] = $promo_code->getRate(); + $payload['promo_code_discount_amount'] = $promo_code->getAmount(); + } + } + + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['owner_email'] ); + } + + protected function getEmailEventSlug(): string + { + return self::EVENT_SLUG; + } + + // metadata + const EVENT_SLUG = 'SUMMIT_REGISTRATION_INVITE_ATTENDEE_TICKET_EDITION'; + const EVENT_NAME = 'SUMMIT_REGISTRATION_INVITE_ATTENDEE_TICKET_EDITION'; + const DEFAULT_TEMPLATE = 'REGISTRATION_INVITE_ATTENDEE_TICKET_EDITION'; +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/MemberPromoCodeEmail.php b/app/Jobs/Emails/Registration/MemberPromoCodeEmail.php new file mode 100644 index 00000000..e54df3b5 --- /dev/null +++ b/app/Jobs/Emails/Registration/MemberPromoCodeEmail.php @@ -0,0 +1,31 @@ +getSummit(); + $payload = []; + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + $payload['promo_code'] = $promo_code->getCode(); + $payload['owner_email'] = $promo_code->getOwnerEmail(); + $payload['owner_fullname'] = $promo_code->getOwnerFullname(); + $payload['registration_url'] = Config::get("registration.dashboard_base_url", null); + if(empty($payload['registration_url'])) + throw new \InvalidArgumentException("missing dashboard_base_url value"); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + parent::__construct($payload, $template_identifier, $payload['owner_email']); + } + +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/PromoCodeEmailFactory.php b/app/Jobs/Emails/Registration/PromoCodeEmailFactory.php new file mode 100644 index 00000000..58754881 --- /dev/null +++ b/app/Jobs/Emails/Registration/PromoCodeEmailFactory.php @@ -0,0 +1,34 @@ +getOwnerType() == 'MEMBER'){ + MemberPromoCodeEmail::dispatch($promo_code); + } + if($promo_code->getOwnerType() == 'SPEAKER'){ + SpeakerPromoCodeEMail::dispatch($promo_code); + } + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/Refunds/SummitOrderRefundAccepted.php b/app/Jobs/Emails/Registration/Refunds/SummitOrderRefundAccepted.php new file mode 100644 index 00000000..5121238a --- /dev/null +++ b/app/Jobs/Emails/Registration/Refunds/SummitOrderRefundAccepted.php @@ -0,0 +1,30 @@ +getSummit(); + $payload['owner_full_name'] = $order->getOwnerFullName(); + $payload['owner_email'] = $order->getOwnerEmail(); + $payload['owner_company'] = $order->getOwnerCompany(); + $payload['order_number'] = $order->getNumber(); + $payload['summit_name'] = $order->getSummit()->getName(); + $payload['summit_logo'] = $order->getSummit()->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + $to = Config::get("registration.admin_email"); + if(empty($to)){ + throw new \InvalidArgumentException("registration.admin_email is not set"); + } + + parent::__construct($payload, $template_identifier, $to); + } + + +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/Refunds/SummitOrderRefundRequestOwner.php b/app/Jobs/Emails/Registration/Refunds/SummitOrderRefundRequestOwner.php new file mode 100644 index 00000000..35836967 --- /dev/null +++ b/app/Jobs/Emails/Registration/Refunds/SummitOrderRefundRequestOwner.php @@ -0,0 +1,106 @@ +getSummit(); + $payload['owner_full_name'] = $order->getOwnerFullName(); + $payload['owner_first_name'] = $order->getOwnerFirstName(); + $payload['owner_full_name'] = $order->getOwnerFullName(); + $payload['owner_company'] = $order->getOwnerCompany(); + $payload['owner_email'] = $order->getOwnerEmail(); + $payload['order_number'] = $order->getNumber(); + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + $payload['order_amount'] = $order->getFinalAmount(); + $payload['order_currency'] = $order->getCurrency(); + $payload['order_currency_symbol'] = "$"; + $payload['tickets'] = []; + + $tickets = []; + foreach ($order->getTickets() as $ticket) { + $ticket_dto = [ + 'number' => $ticket->getNumber(), + 'ticket_type_name' => $ticket->getTicketType()->getName(), + 'has_owner' => false, + 'price' => $ticket->getFinalAmount(), + 'currency' => $ticket->getCurrency(), + 'currency_symbol' => '$', + 'need_details' => false, + ]; + if ($ticket->hasPromoCode()) { + $promo_code = $ticket->getPromoCode(); + $promo_code_dto = [ + 'code' => $promo_code->getCode(), + 'is_discount' => false, + ]; + + if ($promo_code instanceof SummitRegistrationDiscountCode) { + $promo_code_dto['is_discount'] = true; + $promo_code_dto['discount_amount'] = $promo_code->getAmount(); + $promo_code_dto['discount_rate'] = $promo_code->getRate(); + } + + $ticket_dto['promo_code'] = $promo_code_dto; + } + if ($ticket->hasOwner()) { + $ticket_dto['has_owner'] = true; + $ticket_owner = $ticket->getOwner(); + $ticket_dto['owner_email'] = $ticket_owner->getEmail(); + $ticket_dto['owner_full_name'] = $ticket_owner->getFullName(); + $ticket_dto['owner_company'] = $ticket_owner->getCompanyName(); + $ticket_dto['owner_first_name'] = $ticket_owner->getFirstName(); + $ticket_dto['owner_last_name'] = $ticket_owner->getSurname(); + $ticket_dto['need_details'] = $ticket_owner->needToFillDetails(); + } + $tickets[] = $ticket_dto; + } + + $payload['tickets'] = $tickets; + + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['owner_email']); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/Refunds/SummitTicketRefundAccepted.php b/app/Jobs/Emails/Registration/Refunds/SummitTicketRefundAccepted.php new file mode 100644 index 00000000..e6c3b554 --- /dev/null +++ b/app/Jobs/Emails/Registration/Refunds/SummitTicketRefundAccepted.php @@ -0,0 +1,30 @@ +getOrder(); + $summit = $order->getSummit(); + $payload = []; + $payload['owner_full_name'] = $order->getOwnerFullName(); + $payload['owner_email'] = $order->getOwnerEmail(); + $payload['owner_company'] = $order->getOwnerCompany(); + $payload['ticket_number'] = $ticket->getNumber(); + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + $to = Config::get("registration.admin_email"); + if(empty($to)){ + throw new \InvalidArgumentException("registration.admin_email is not set"); + } + + parent::__construct($payload, $template_identifier, $to); + } + +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/Refunds/SummitTicketRefundRequestOwner.php b/app/Jobs/Emails/Registration/Refunds/SummitTicketRefundRequestOwner.php new file mode 100644 index 00000000..c994ddb9 --- /dev/null +++ b/app/Jobs/Emails/Registration/Refunds/SummitTicketRefundRequestOwner.php @@ -0,0 +1,78 @@ +getOrder(); + $summit = $order->getSummit(); + $payload['order_number'] = $order->getNumber(); + $payload['owner_full_name'] = $order->getOwnerFullName(); + $payload['owner_email'] = $order->getOwnerEmail(); + $payload['owner_company'] = $order->getOwnerCompany(); + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + $payload['ticket_number'] = $ticket->getNumber(); + $payload['ticket_type_name'] = $ticket->getTicketType()->getName(); + $payload['ticket_currency'] = $ticket->getCurrency(); + $payload['ticket_amount'] = $ticket->getFinalAmount(); + $payload['ticket_currency_symbol'] = '$'; + + $payload['ticket_promo_code'] = ''; + if ($ticket->hasPromoCode()) { + $payload['ticket_promo_code'] = $ticket->getPromoCode()->getCode(); + } + + $payload['ticket_owner'] = ''; + if ($ticket->hasOwner()) { + $payload['ticket_owner'] = $ticket->getOwner()->getFullName(); + } + + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['owner_email']); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/RegisteredMemberOrderPaidMail.php b/app/Jobs/Emails/Registration/RegisteredMemberOrderPaidMail.php new file mode 100644 index 00000000..fd205369 --- /dev/null +++ b/app/Jobs/Emails/Registration/RegisteredMemberOrderPaidMail.php @@ -0,0 +1,126 @@ +getOwnerFullName(); + $payload['owner_company'] = $order->getOwnerCompany(); + $owner_email = $order->getOwnerEmail(); + $payload['owner_email'] = $owner_email; + $summit = $order->getSummit(); + $payload['order_raw_amount'] = $order->getRawAmount(); + $payload['order_amount'] = $order->getFinalAmount(); + $payload['order_currency'] = $order->getCurrency(); + $payload['order_currency_symbol'] = '$'; + $payload['order_taxes'] = $order->getTaxesAmount(); + $payload['order_discount'] = $order->getDiscountAmount(); + $payload['order_number'] = $order->getNumber(); + $payload['order_qr_value'] = $order->getQRCode(); + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + + $summit_reassign_ticket_till_date = $summit->getReassignTicketTillDateLocal(); + if(!is_null($summit_reassign_ticket_till_date)) { + $payload['summit_reassign_ticket_till_date'] = $summit_reassign_ticket_till_date->format("l j F Y h:i A T"); + } + + $base_url = Config::get("registration.dashboard_base_url", null); + if (empty($base_url)) + throw new \InvalidArgumentException("missing dashboard_base_url value"); + + $back_url = Config::get("registration.dashboard_back_url", null); + if (empty($back_url)) + throw new \InvalidArgumentException("missing dashboard_back_url value"); + + $payload['manage_orders_url'] = sprintf($back_url, $base_url); + + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + foreach ($order->getTickets() as $ticket) { + $ticket_dto = [ + 'number' => $ticket->getNumber(), + 'ticket_type_name' => $ticket->getTicketType()->getName(), + 'has_owner' => false, + 'price' => $ticket->getFinalAmount(), + 'currency' => $ticket->getCurrency(), + 'currency_symbol' => '$', + 'need_details' => false, + ]; + + if ($ticket->hasPromoCode()) { + $promo_code = $ticket->getPromoCode(); + $promo_code_dto = [ + 'code' => $promo_code->getCode(), + 'is_discount' => false, + ]; + + if ($promo_code instanceof SummitRegistrationDiscountCode) { + $promo_code_dto['is_discount'] = true; + $promo_code_dto['discount_amount'] = $promo_code->getAmount(); + $promo_code_dto['discount_rate'] = $promo_code->getRate(); + } + + $ticket_dto['promo_code'] = $promo_code_dto; + } + + if ($ticket->hasOwner()) { + $ticket_dto['has_owner'] = true; + $ticket_owner = $ticket->getOwner(); + $ticket_dto['owner_email'] = $ticket_owner->getEmail(); + $ticket_dto['owner_full_name'] = $ticket_owner->getFullName(); + $ticket_dto['owner_first_name'] = $ticket_owner->getFirstName(); + $ticket_dto['owner_company'] = $ticket_owner->getCompanyName(); + $ticket_dto['owner_last_name'] = $ticket_owner->getSurname(); + $ticket_dto['need_details'] = $ticket_owner->needToFillDetails(); + } + $tickets[] = $ticket_dto; + } + $payload['tickets'] = $tickets; + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $owner_email); + } + + protected function getEmailEventSlug(): string + { + return self::EVENT_SLUG; + } + + // metadata + const EVENT_SLUG = 'SUMMIT_REGISTRATION_REGISTERED_MEMBER_ORDER_PAID'; + const EVENT_NAME = 'SUMMIT_REGISTRATION_REGISTERED_MEMBER_ORDER_PAID'; + const DEFAULT_TEMPLATE = 'REGISTRATION_REGISTERED_MEMBER_ORDER_PAID'; +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/Reminders/SummitOrderReminderEmail.php b/app/Jobs/Emails/Registration/Reminders/SummitOrderReminderEmail.php new file mode 100644 index 00000000..55a9dc0d --- /dev/null +++ b/app/Jobs/Emails/Registration/Reminders/SummitOrderReminderEmail.php @@ -0,0 +1,127 @@ +getSummit(); + $payload['owner_full_name'] = $order->getOwnerFullName(); + $payload['owner_email'] = $order->getOwnerEmail(); + $payload['owner_company'] = $order->getOwnerCompany(); + $summit_reassign_ticket_till_date = $summit->getReassignTicketTillDateLocal(); + if(!is_null($summit_reassign_ticket_till_date)) { + $payload['summit_reassign_ticket_till_date'] = $summit_reassign_ticket_till_date->format("l j F Y h:i A T"); + } + $owner_email = $payload['owner_email']; + + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + + $payload['summit_name'] = $order->getSummit()->getName(); + $payload['summit_logo'] = $order->getSummit()->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + + $base_url = Config::get("registration.dashboard_base_url", null); + if (empty($base_url)) + throw new \InvalidArgumentException("missing dashboard_base_url value"); + + $back_url = Config::get("registration.dashboard_back_url", null); + if (empty($back_url)) + throw new \InvalidArgumentException("missing dashboard_back_url value"); + + $payload['manage_orders_url'] = sprintf($back_url, $base_url); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + $tickets = []; + + foreach ($order->getTickets() as $ticket) { + if (!$ticket->hasTicketType()) continue; + + $ticket_dto = [ + 'number' => $ticket->getNumber(), + 'ticket_type_name' => $ticket->getTicketType()->getName(), + 'has_owner' => false, + 'price' => $ticket->getFinalAmount(), + 'currency' => $ticket->getCurrency(), + 'currency_symbol' => '$', + 'need_details' => false, + ]; + + if ($ticket->hasPromoCode()) { + $promo_code = $ticket->getPromoCode(); + $promo_code_dto = [ + 'code' => $promo_code->getCode(), + 'is_discount' => false, + ]; + + if ($promo_code instanceof SummitRegistrationDiscountCode) { + $promo_code_dto['is_discount'] = true; + $promo_code_dto['discount_amount'] = $promo_code->getAmount(); + $promo_code_dto['discount_rate'] = $promo_code->getRate(); + } + + $ticket_dto['promo_code'] = $promo_code_dto; + } + + if ($ticket->hasOwner()) { + $ticket_dto['has_owner'] = true; + $ticket_owner = $ticket->getOwner(); + $ticket_dto['owner_full_name'] = $ticket_owner->getFullName(); + $ticket_dto['owner_company'] = $ticket_owner->getCompanyName(); + $ticket_dto['owner_email'] = $ticket_owner->getEmail(); + $ticket_dto['owner_first_name'] = $ticket_owner->getFirstName(); + $ticket_dto['owner_last_name'] = $ticket_owner->getSurname(); + $ticket_dto['need_details'] = $ticket_owner->needToFillDetails(); + } + + $tickets[] = $ticket_dto; + } + + $payload['tickets'] = $tickets; + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $owner_email); + } + + protected function getEmailEventSlug(): string + { + return self::EVENT_SLUG; + } + + // metadata + const EVENT_SLUG = 'SUMMIT_REGISTRATION_ORDER_REMINDER'; + const EVENT_NAME = 'SUMMIT_REGISTRATION_ORDER_REMINDER'; + const DEFAULT_TEMPLATE = 'REGISTRATION_ORDER_REMINDER_EMAIL'; +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/Reminders/SummitTicketReminderEmail.php b/app/Jobs/Emails/Registration/Reminders/SummitTicketReminderEmail.php new file mode 100644 index 00000000..802a0070 --- /dev/null +++ b/app/Jobs/Emails/Registration/Reminders/SummitTicketReminderEmail.php @@ -0,0 +1,80 @@ +getOwner(); + $summit = $attendee->getSummit(); + $order = $ticket->getOrder(); + $payload = []; + $summit_reassign_ticket_till_date = $summit->getReassignTicketTillDateLocal(); + if(!is_null($summit_reassign_ticket_till_date)) { + $payload['summit_reassign_ticket_till_date'] = $summit_reassign_ticket_till_date->format("l j F Y h:i A T"); + } + $payload['order_owner_full_name'] = $order->getOwnerFullName(); + $payload['order_owner_company'] = $order->getOwnerCompany(); + $payload['order_owner_email'] = $order->getOwnerEmail(); + $payload['owner_full_name'] = $attendee->getFullName(); + $payload['owner_email'] = $attendee->getEmail(); + $payload['owner_company'] = $attendee->getCompanyName(); + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + + $base_url = Config::get('registration.dashboard_base_url', null); + $edit_ticket_link = Config::get('registration.dashboard_attendee_edit_form_url', null); + + if (empty($base_url)) + throw new \InvalidArgumentException("missing dashboard_base_url value"); + if (empty($edit_ticket_link)) + throw new \InvalidArgumentException("missing dashboard_attendee_edit_form_url value"); + + $payload['edit_ticket_link'] = sprintf($edit_ticket_link, $base_url, $ticket->getHash()); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['owner_email']); + } + + protected function getEmailEventSlug(): string + { + return self::EVENT_SLUG; + } + + // metadata + const EVENT_SLUG = 'SUMMIT_REGISTRATION_TICKET_REMINDER'; + const EVENT_NAME = 'SUMMIT_REGISTRATION_TICKET_REMINDER'; + const DEFAULT_TEMPLATE = 'REGISTRATION_TICKET_REMINDER_EMAIL'; +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/RevocationTicketEmail.php b/app/Jobs/Emails/Registration/RevocationTicketEmail.php new file mode 100644 index 00000000..f848d362 --- /dev/null +++ b/app/Jobs/Emails/Registration/RevocationTicketEmail.php @@ -0,0 +1,70 @@ +getEmail(); + $summit = $attendee->getSummit(); + $order = $ticket->getOrder(); + $payload = []; + + $payload['owner_full_name'] = $attendee->getFullName(); + $payload['owner_email'] = $attendee->getEmail(); + $payload['owner_first_name'] = $attendee->getFirstName(); + $payload['owner_last_name'] = $attendee->getSurname(); + $payload['owner_company'] = $attendee->getCompanyName(); + $payload['order_owner_full_name'] = $order->getOwnerFullName(); + $payload['order_owner_email'] = $order->getOwnerEmail(); + $payload['order_owner_company'] = $order->getOwnerCompany(); + $payload['ticket_number'] = $ticket->getNumber(); + + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $owner_email); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/SpeakerPromoCodeEMail.php b/app/Jobs/Emails/Registration/SpeakerPromoCodeEMail.php new file mode 100644 index 00000000..e064968f --- /dev/null +++ b/app/Jobs/Emails/Registration/SpeakerPromoCodeEMail.php @@ -0,0 +1,32 @@ +getOwner(); + $summit = $attendee->getSummit(); + $order = $ticket->getOrder(); + $payload['order_owner_full_name'] = $order->getOwnerFullName(); + $payload['order_owner_company'] = $order->getOwnerCompany(); + $payload['order_owner_email'] = $order->getOwnerEmail(); + $payload['summit_name'] = $summit->getName(); + $payload['summit_logo'] = $summit->getLogoUrl(); + + $summit_reassign_ticket_till_date = $summit->getReassignTicketTillDateLocal(); + if(!is_null($summit_reassign_ticket_till_date)) { + $payload['summit_reassign_ticket_till_date'] = $summit_reassign_ticket_till_date->format("l j F Y h:i A T"); + } + + $payload['summit_virtual_site_url'] = $summit->getVirtualSiteUrl(); + $payload['summit_marketing_site_url'] = $summit->getMarketingSiteUrl(); + $payload['summit_virtual_site_oauth2_client_id'] = $summit->getVirtualSiteOAuth2ClientId(); + $payload['summit_marketing_site_oauth2_client_id'] = $summit->getMarketingSiteOAuth2ClientId(); + + $payload['ticket_number'] = $ticket->getNumber(); + $payload['ticket_type_name'] = $ticket->getTicketType()->getName(); + $payload['ticket_amount'] = $ticket->getFinalAmount(); + $payload['ticket_currency'] = $ticket->getCurrency(); + $payload['ticket_currency_symbol'] = '$'; + $owner_email = $attendee->getEmail(); + $payload['owner_email'] = $owner_email; + $payload['owner_first_name'] = $attendee->getFirstName(); + $payload['owner_last_name'] = $attendee->getSurname(); + $payload['owner_full_name'] = $attendee->getFullName(); + $payload['owner_company'] = $attendee->getCompanyName(); + + if(empty($payload['owner_full_name'])){ + Log::warning(sprintf("SummitAttendeeTicketEmail owner_full_name is empty setting email")); + $payload['owner_full_name'] = $payload['owner_email']; + } + + if(empty($payload['owner_first_name'])){ + Log::warning(sprintf("SummitAttendeeTicketEmail owner_first_name is empty setting email")); + $payload['owner_first_name'] = $payload['owner_email']; + } + + if(empty($payload['owner_last_name'])){ + Log::warning(sprintf("SummitAttendeeTicketEmail owner_last_name is empty setting email")); + $payload['owner_last_name'] = $payload['owner_email']; + } + + $payload['promo_code'] = ($ticket->hasPromoCode()) ? $ticket->getPromoCode()->getCode() : ''; + + $support_email = $summit->getSupportEmail(); + $payload['support_email'] = !empty($support_email) ? $support_email: Config::get("registration.support_email", null); + + if (empty($payload['support_email'])) + throw new \InvalidArgumentException("missing support_email value"); + + $sendTicketAttachments = Config::get("registration.send_ticket_attachments", false); + + // @todo attachments are only meant for in person events + // we need on a future a way to determine if current summit is virtual or in person + // to included this attachments, for now , will be managed by managed by a environmental + // variable + // attachments + if($sendTicketAttachments) { + $renderer = new SummitAttendeeTicketPDFRenderer($ticket); + $attachments = []; + $attachments[] = [ + 'name' => 'qr.png', + 'content' => base64_encode(QrCode::format('png')->size(250, 250)->generate($ticket->getQRCode())), + 'type' => 'application/octet-stream', + 'disposition' => 'inline', + 'content_id' => 'qrcid', + ]; + + $attachments[] = [ + 'name' => 'ticket_' . $ticket->getNumber() . '.pdf', + 'content' => base64_encode($renderer->render()), + 'type' => 'application/pdf', + 'disposition' => 'attachment', + ]; + + $payload['attachments'] = $attachments; + } + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + parent::__construct($payload, $template_identifier, $owner_email); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/Registration/SummitAttendeeTicketRegenerateHashEmail.php b/app/Jobs/Emails/Registration/SummitAttendeeTicketRegenerateHashEmail.php new file mode 100644 index 00000000..8e998516 --- /dev/null +++ b/app/Jobs/Emails/Registration/SummitAttendeeTicketRegenerateHashEmail.php @@ -0,0 +1,31 @@ +payload['set_password_link'] = $set_password_link; + + $this->payload['set_password_link_to_registration'] = sprintf( + "%s?client_id=%s&redirect_uri=%s", + $set_password_link, + Config::get("registration.dashboard_client_id"), + urlencode(sprintf($back_url, $base_url)) + ); + } +} \ No newline at end of file diff --git a/app/Jobs/Emails/Schedule/RSVPMail.php b/app/Jobs/Emails/Schedule/RSVPMail.php new file mode 100644 index 00000000..91fed982 --- /dev/null +++ b/app/Jobs/Emails/Schedule/RSVPMail.php @@ -0,0 +1,59 @@ +getEvent(); + $summit = $event->getSummit(); + $owner = $rsvp->getOwner(); + $payload['owner_fullname'] = $owner->getFullName(); + $payload['owner_email'] = $owner->getEmail(); + $payload['event_title'] = $event->getTitle(); + $payload['event_date'] = $event->getDateNice(); + $payload['confirmation_number'] = $rsvp->getConfirmationNumber(); + $payload['summit_name'] = $summit->getName(); + $payload['summit_schedule_default_event_detail_url'] = $summit->getScheduleDefaultEventDetailUrl(); + $event_uri = $rsvp->getEventUri(); + + $payload['event_uri'] = ''; + + if (!empty($event_uri)) { + // we got a valid origin + $payload['event_uri'] = $event_uri; + } + // if we dont have a custom event uri, try to get default one + if (empty($payload['event_uri']) && !empty($payload['summit_schedule_default_event_detail_url'])) { + $payload['event_uri'] = str_replace(":event_id", $event->getId(), $payload['summit_schedule_default_event_detail_url']); + } + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['owner_email']); + } +} \ No newline at end of file diff --git a/app/Mail/Schedule/RSVPRegularSeatMail.php b/app/Jobs/Emails/Schedule/RSVPRegularSeatMail.php similarity index 53% rename from app/Mail/Schedule/RSVPRegularSeatMail.php rename to app/Jobs/Emails/Schedule/RSVPRegularSeatMail.php index a652ca3f..dfa80be7 100644 --- a/app/Mail/Schedule/RSVPRegularSeatMail.php +++ b/app/Jobs/Emails/Schedule/RSVPRegularSeatMail.php @@ -1,6 +1,4 @@ -summit_name); - $from = Config::get("mail.from"); - if(empty($from)){ - throw new \InvalidArgumentException("mail.from is not set"); - } - - return $this->from($from) - ->to($this->owner_email) - ->subject($subject) - ->view('emails.schedule.rsvp_regular_seat'); + return self::EVENT_SLUG; } + + // metadata + const EVENT_SLUG = 'SUMMIT_SCHEDULE_RSVP_REGULAR_SEAT_CREATION'; + const EVENT_NAME = 'SUMMIT_SCHEDULE_RSVP_REGULAR_SEAT_CREATION'; + const DEFAULT_TEMPLATE = 'SUMMIT_SCHEDULE_RSVP_REGULAR_SEAT'; } \ No newline at end of file diff --git a/app/Mail/Schedule/RSVPWaitListSeatMail.php b/app/Jobs/Emails/Schedule/RSVPWaitListSeatMail.php similarity index 54% rename from app/Mail/Schedule/RSVPWaitListSeatMail.php rename to app/Jobs/Emails/Schedule/RSVPWaitListSeatMail.php index 7737c39f..d99aaf61 100644 --- a/app/Mail/Schedule/RSVPWaitListSeatMail.php +++ b/app/Jobs/Emails/Schedule/RSVPWaitListSeatMail.php @@ -1,6 +1,4 @@ -summit_name); - $from = Config::get("mail.from"); - if(empty($from)){ - throw new \InvalidArgumentException("mail.from is not set"); - } - return $this->from($from) - ->to($this->owner_email) - ->subject($subject) - ->view('emails.schedule.rsvp_wait_seat'); + return self::EVENT_SLUG; } + + // metadata + const EVENT_SLUG = 'SUMMIT_SCHEDULE_RSVP_WAITLIST_SEAT_CREATION'; + const EVENT_NAME = 'SUMMIT_SCHEDULE_RSVP_WAITLIST_SEAT_CREATION'; + const DEFAULT_TEMPLATE = 'SUMMIT_SCHEDULE_RSVP_WAITLIST_SEAT'; } \ No newline at end of file diff --git a/app/Jobs/Emails/Schedule/ShareEventEmail.php b/app/Jobs/Emails/Schedule/ShareEventEmail.php new file mode 100644 index 00000000..b756175f --- /dev/null +++ b/app/Jobs/Emails/Schedule/ShareEventEmail.php @@ -0,0 +1,56 @@ +getSummit(); + $payload = []; + $payload['from_email'] = $from_email; + $payload['to_email '] = $to_email; + $payload['summit_name'] = $summit->getName(); + $payload['event_title'] = $event->getTitle(); + $payload['event_description'] = $event->getAbstract(); + $payload['event_url'] = $event_url; + + $template_identifier = $this->getEmailTemplateIdentifierFromEmailEvent($summit); + + parent::__construct($payload, $template_identifier, $payload['to_email']); + } + + protected function getEmailEventSlug(): string + { + return self::EVENT_SLUG; + } + + // metadata + const EVENT_SLUG = 'SUMMIT_SCHEDULE_SHARE_EVENT'; + const EVENT_NAME = 'SUMMIT_SCHEDULE_SHARE_EVENT'; + const DEFAULT_TEMPLATE = 'SUMMIT_SCHEDULE_SHARE_EVENT'; + +} \ No newline at end of file diff --git a/app/Jobs/IngestSummitExternalRegistrationData.php b/app/Jobs/IngestSummitExternalRegistrationData.php new file mode 100644 index 00000000..92880674 --- /dev/null +++ b/app/Jobs/IngestSummitExternalRegistrationData.php @@ -0,0 +1,101 @@ +summit_id = $summit_id; + $this->email_to = $email_to; + } + + /** + * @param ISummitRepository $summit_repository + * @param IRegistrationIngestionService $service + * @param ITransactionService $tx_service + */ + public function handle + ( + ISummitRepository $summit_repository, + IRegistrationIngestionService $service, + ITransactionService $tx_service + ) + { + try { + Log::debug("IngestSummitExternalRegistrationData::handle"); + + $tx_service->transaction(function () use ($summit_repository, $service) { + + $summit = $summit_repository->getById($this->summit_id); + if (is_null($summit) || !$summit instanceof Summit) return; + $service->ingestSummit($summit); + if(!empty($this->email_to)) { + Log::debug(sprintf("IngestSummitExternalRegistrationData::handle - sending result email to %s", $this->email_to)); + SuccessfulIIngestionEmail::dispatch($this->email_to, $summit); + } + }); + } + catch (ValidationException $ex){ + Log::warning($ex); + if(!empty($this->email_to)) { + $summit = $summit_repository->getById($this->summit_id); + if (is_null($summit) || !$summit instanceof Summit) return; + UnsuccessfulIIngestionEmail::dispatch($ex->getMessage(), $this->email_to, $summit); + } + } + catch (\Exception $ex){ + Log::error($ex); + if(!empty($this->email_to)) { + $summit = $summit_repository->getById($this->summit_id); + if (is_null($summit) || !$summit instanceof Summit) return; + UnsuccessfulIIngestionEmail::dispatch($ex->getMessage(), $this->email_to, $summit); + } + } + } + +} \ No newline at end of file diff --git a/app/Jobs/NewMemberAssocSummitOrders.php b/app/Jobs/NewMemberAssocSummitOrders.php new file mode 100644 index 00000000..7f46196f --- /dev/null +++ b/app/Jobs/NewMemberAssocSummitOrders.php @@ -0,0 +1,93 @@ +member_id = $member_id; + } + + /** + * @param ISummitOrderRepository $order_repository + * @param IMemberRepository $member_repository + * @param ISummitAttendeeRepository $attendee_repository + * @param ITransactionService $tx_service + * @throws \Exception + */ + public function handle + ( + ISummitOrderRepository $order_repository, + IMemberRepository $member_repository, + ISummitAttendeeRepository $attendee_repository, + ITransactionService $tx_service + ) + { + $tx_service->transaction(function() use($order_repository, $member_repository, $attendee_repository){ + + Log::debug(sprintf("NewMemberAssocSummitOrders::handle trying to get member id %s", $this->member_id)); + $member = $member_repository->getById($this->member_id); + if(is_null($member) || !$member instanceof Member) return; + + // associate orders + $orders = $order_repository->getAllByOwnerEmail($member->getEmail()); + if(!is_null($orders)) { + foreach ($orders as $order) { + if (!$order instanceof SummitOrder) continue; + Log::debug(sprintf("NewMemberAssocSummitOrders::handle got order %s for member %s", $order->getNumber(), $this->member_id)); + $member->addSummitRegistrationOrder($order); + } + } + + // associate attendees/tickets + $attendees = $attendee_repository->getByEmail($member->getEmail()); + if(!is_null($attendees)) { + foreach ($attendees as $attendee) { + if (!$attendee instanceof SummitAttendee) continue; + Log::debug(sprintf("NewMemberAssocSummitOrders::handle got attendee %s for member", $attendee->getId(), $this->member_id)); + $attendee->setMember($member); + } + } + + }); + } +} diff --git a/app/Jobs/ProcessOrderRefundRequest.php b/app/Jobs/ProcessOrderRefundRequest.php new file mode 100644 index 00000000..9edaa616 --- /dev/null +++ b/app/Jobs/ProcessOrderRefundRequest.php @@ -0,0 +1,159 @@ +order_id = $order_id; + $this->requested_n_days_before_summit = $requested_n_days_before_summit; + } + + + /** + * @param IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy + * @param ISummitOrderRepository $repository + * @param ITransactionService $tx_service + * @throws \Exception + */ + public function handle( + IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy, + ISummitOrderRepository $repository, + ITransactionService $tx_service + ) + { + $tx_service->transaction(function() use($default_payment_gateway_strategy, $repository){ + + Log::debug(sprintf("ProcessOrderRefundRequest::handle: processing for order id %s", $this->order_id)); + + $order = $repository->getByIdExclusiveLock($this->order_id); + + if(is_null($order) || !$order instanceof SummitOrder || !$order->isRefundRequested()){ + Log::debug(sprintf("ProcessOrderRefundRequest::handle: order id %s not found", $this->order_id)); + } + + $summit = $order->getSummit(); + + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeRegistration, + $default_payment_gateway_strategy + ); + if(is_null($payment_gateway)){ + Log::warning(sprintf("Payment configuration is not set for summit %s", $summit->getId())); + return; + } + + $policy = $summit->getRefundPolicyForRefundRequest($this->requested_n_days_before_summit); + + if(is_null($policy)){ + + Log::debug + ( + sprintf + ( + "ProcessOrderRefundRequest::handle: policy not found for order id %s - requested_n_days_before_summit %s summit id %s", + $this->order_id, + $this->requested_n_days_before_summit, + $summit->getId()) + ); + return; + } + $rate = $policy->getRefundRate(); + if($rate <= 0){ + Log::debug + ( + sprintf + ( + "ProcessOrderRefundRequest::handle: policy id %s has not a valid refund rate %s", + $policy->getId(), + $rate + ) + ); + return; + } + + $amount_2_refund = ($rate/100.00) * $order->getFinalAmount(); + + Log::debug + ( + sprintf + ( + "ProcessOrderRefundRequest::handle: requesting refund to payment gateway with following data amount_2_refund %s - cart id %s - currency %s ", + $amount_2_refund, + $order->getPaymentGatewayCartId(), + $order->getCurrency()) + ); + + if(!$order->hasPaymentInfo()) + { + Log::warning(sprintf("order %s has not payment info ", $order->getId())); + return; + } + + try { + $payment_gateway->refundPayment( + $order->getPaymentGatewayCartId(), + $amount_2_refund, + $order->getCurrency() + ); + } + catch(\Exception $ex){ + log::error($ex); + return; + } + + $order->refund($amount_2_refund); + + }); + } +} diff --git a/app/Jobs/ProcessSummitOrderPaymentConfirmation.php b/app/Jobs/ProcessSummitOrderPaymentConfirmation.php new file mode 100644 index 00000000..8044eaab --- /dev/null +++ b/app/Jobs/ProcessSummitOrderPaymentConfirmation.php @@ -0,0 +1,66 @@ +order_id = $order_id; + } + + /** + * @param ISummitOrderService $orderService + * @throws \Exception + */ + public function handle + ( + ISummitOrderService $orderService + ) + { + try{ + Log::debug(sprintf("ProcessSummitOrderPaymentConfirmation::handle order %s", $this->order_id)); + $orderService->processOrderPaymentConfirmation($this->order_id); + } + catch (\Exception $ex){ + Log::error($ex); + throw $ex; + } + } +} diff --git a/app/Jobs/ProcessTicketDataImport.php b/app/Jobs/ProcessTicketDataImport.php new file mode 100644 index 00000000..37ba58f4 --- /dev/null +++ b/app/Jobs/ProcessTicketDataImport.php @@ -0,0 +1,75 @@ +summit_id = $summit_id; + $this->filename = $filename; + } + + /** + * @param ISummitOrderService $service + */ + public function handle + ( + ISummitOrderService $service + ) + { + try { + Log::debug(sprintf("ProcessTicketDataImport::handle summit %s filename %s", $this->summit_id, $this->filename)); + $service->processTicketData($this->summit_id, $this->filename); + } catch (ValidationException $ex) { + Log::warning($ex); + } catch (\Exception $ex) { + Log::error($ex); + } + } +} \ No newline at end of file diff --git a/app/Jobs/ProcessTicketRefundRequest.php b/app/Jobs/ProcessTicketRefundRequest.php new file mode 100644 index 00000000..3e645096 --- /dev/null +++ b/app/Jobs/ProcessTicketRefundRequest.php @@ -0,0 +1,116 @@ +ticket_id = $ticket_id; + $this->requested_n_days_before_summit = $requested_n_days_before_summit; + } + + /** + * @param IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy + * @param ISummitAttendeeTicketRepository $repository + * @param ITransactionService $tx_service + * @throws \Exception + */ + public function handle( + IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy, + ISummitAttendeeTicketRepository $repository, + ITransactionService $tx_service + ) + { + $tx_service->transaction(function () use ($default_payment_gateway_strategy, $repository) { + + $ticket = $repository->getByIdExclusiveLock($this->ticket_id); + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket || !$ticket->isRefundRequested()) return; + + + $order = $ticket->getOrder(); + $summit = $order->getSummit(); + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeRegistration, + $default_payment_gateway_strategy + ); + + if (is_null($payment_gateway)) { + Log::warning(sprintf("Payment configuration is not set for summit %s", $summit->getId())); + return; + } + + $policy = $summit->getRefundPolicyForRefundRequest($this->requested_n_days_before_summit); + if (is_null($policy)) return; + $rate = $policy->getRefundRate(); + if ($rate <= 0) return; + $amount_2_refund = ($rate / 100.00) * $ticket->getFinalAmount(); + + if (!$order->hasPaymentInfo()) { + Log::warning(sprintf("order %s has not payment info ", $order->getId())); + return; + } + + try { + $payment_gateway->refundPayment( + $order->getPaymentGatewayCartId(), + $amount_2_refund, + $ticket->getCurrency() + ); + } catch (\Exception $ex) { + Log::warning($ex); + return; + } + + $ticket->refund($amount_2_refund); + + }); + } +} diff --git a/app/Jobs/PublishUserCreated.php b/app/Jobs/PublishUserCreated.php new file mode 100644 index 00000000..8b02d124 --- /dev/null +++ b/app/Jobs/PublishUserCreated.php @@ -0,0 +1,47 @@ +user_id, $this->user_email)); + + $service->registerExternalUserById($this->user_id); + } +} diff --git a/app/Jobs/PublishUserDeleted.php b/app/Jobs/PublishUserDeleted.php new file mode 100644 index 00000000..08a092f6 --- /dev/null +++ b/app/Jobs/PublishUserDeleted.php @@ -0,0 +1,47 @@ +user_id, $this->user_email)); + + $service->registerExternalUserById($this->user_id); + } +} diff --git a/app/Mail/AbstractBookableRoomReservationEmail.php b/app/Mail/AbstractBookableRoomReservationEmail.php deleted file mode 100644 index 61734a6c..00000000 --- a/app/Mail/AbstractBookableRoomReservationEmail.php +++ /dev/null @@ -1,106 +0,0 @@ -owner_fullname = $reservation->getOwner()->getFullName(); - $this->owner_email = $reservation->getOwner()->getEmail(); - $this->room_complete_name = $reservation->getRoom()->getCompleteName(); - $this->reservation_start_datetime = $reservation->getLocalStartDatetime()->format("Y-m-d H:i:s"); - $this->reservation_end_datetime = $reservation->getLocalEndDatetime()->format("Y-m-d H:i:s"); - $this->reservation_created_datetime = $reservation->getCreated()->format("Y-m-d H:i:s"); - $this->reservation_amount = $reservation->getAmount(); - $this->reservation_currency = $reservation->getCurrency(); - $this->reservation_id = $reservation->getId(); - $this->room_capacity = $reservation->getRoom()->getCapacity(); - $this->summit_name = $reservation->getRoom()->getSummit()->getName(); - $this->reservation_refunded_amount = $reservation->getRefundedAmount(); - } - -} diff --git a/app/Mail/BookableRoomReservationCanceledEmail.php b/app/Mail/BookableRoomReservationCanceledEmail.php deleted file mode 100644 index 08feb35e..00000000 --- a/app/Mail/BookableRoomReservationCanceledEmail.php +++ /dev/null @@ -1,40 +0,0 @@ -summit_name); - $from = Config::get("mail.from"); - if(empty($from)){ - throw new \InvalidArgumentException("mail.from is not set"); - } - return $this->from($from) - ->to($this->owner_email) - ->subject($subject) - ->view('emails.bookable_rooms.reservation_canceled'); - } -} diff --git a/app/Mail/BookableRoomReservationCreatedEmail.php b/app/Mail/BookableRoomReservationCreatedEmail.php deleted file mode 100644 index aa204fed..00000000 --- a/app/Mail/BookableRoomReservationCreatedEmail.php +++ /dev/null @@ -1,39 +0,0 @@ -summit_name); - $from = Config::get("mail.from"); - if(empty($from)){ - throw new \InvalidArgumentException("mail.from is not set"); - } - return $this->from($from) - ->to($this->owner_email) - ->subject($subject) - ->view('emails.bookable_rooms.reservation_created'); - } -} diff --git a/app/Mail/BookableRoomReservationPaymentConfirmedEmail.php b/app/Mail/BookableRoomReservationPaymentConfirmedEmail.php deleted file mode 100644 index 1aeb2837..00000000 --- a/app/Mail/BookableRoomReservationPaymentConfirmedEmail.php +++ /dev/null @@ -1,39 +0,0 @@ -summit_name); - $from = Config::get("mail.from"); - if(empty($from)){ - throw new \InvalidArgumentException("mail.from is not set"); - } - return $this->from($from) - ->to($this->owner_email) - ->subject($subject) - ->view('emails.bookable_rooms.reservation_payment_confirmed'); - } -} diff --git a/app/Mail/BookableRoomReservationRefundAcceptedEmail.php b/app/Mail/BookableRoomReservationRefundAcceptedEmail.php deleted file mode 100644 index a8e02a44..00000000 --- a/app/Mail/BookableRoomReservationRefundAcceptedEmail.php +++ /dev/null @@ -1,39 +0,0 @@ -summit_name); - $from = Config::get("mail.from"); - if(empty($from)){ - throw new \InvalidArgumentException("mail.from is not set"); - } - return $this->from($from) - ->to($this->owner_email) - ->subject($subject) - ->view('emails.bookable_rooms.reservation_refund_accepted'); - } -} diff --git a/app/Mail/BookableRoomReservationRefundRequestedAdminEmail.php b/app/Mail/BookableRoomReservationRefundRequestedAdminEmail.php deleted file mode 100644 index 08b375a1..00000000 --- a/app/Mail/BookableRoomReservationRefundRequestedAdminEmail.php +++ /dev/null @@ -1,39 +0,0 @@ -summit_name); - $from = Config::get("mail.from"); - if(empty($from)){ - throw new \InvalidArgumentException("mail.from is not set"); - } - return $this->from($from) - ->to(Config::get("bookable_rooms.admin_email")) - ->subject($subject) - ->view('emails.bookable_rooms.reservation_refund_requested_admin'); - } -} diff --git a/app/Mail/BookableRoomReservationRefundRequestedOwnerEmail.php b/app/Mail/BookableRoomReservationRefundRequestedOwnerEmail.php deleted file mode 100644 index e0e4fc52..00000000 --- a/app/Mail/BookableRoomReservationRefundRequestedOwnerEmail.php +++ /dev/null @@ -1,39 +0,0 @@ -summit_name); - $from = Config::get("mail.from"); - if(empty($from)){ - throw new \InvalidArgumentException("mail.from is not set"); - } - return $this->from($from) - ->to($this->owner_email) - ->subject($subject) - ->view('emails.bookable_rooms.reservation_refund_requested_owner'); - } -} diff --git a/app/Mail/Schedule/RSVPMail.php b/app/Mail/Schedule/RSVPMail.php deleted file mode 100644 index f8ecd50d..00000000 --- a/app/Mail/Schedule/RSVPMail.php +++ /dev/null @@ -1,93 +0,0 @@ -getEvent(); - $summit = $event->getSummit(); - $owner = $rsvp->getOwner(); - $this->owner_fullname = $owner->getFullName(); - $this->owner_email = $owner->getEmail(); - $this->event_title = $event->getTitle(); - $this->event_date = $event->getDateNice(); - $this->confirmation_number = $rsvp->getConfirmationNumber(); - $this->summit_name = $summit->getName(); - $this->summit_schedule_default_event_detail_url = $summit->getScheduleDefaultEventDetailUrl(); - $event_uri = $rsvp->getEventUri(); - - if(!empty($event_uri)){ - // we got a valid origin - $this->event_uri = $event_uri; - } - // if we dont have a custom event uri, try to get default one - if(empty($this->event_uri) && !empty($this->summit_schedule_default_event_detail_url)){ - $this->event_uri = str_replace(":event_id", $event->getId(), $this->summit_schedule_default_event_detail_url); - } - } -} \ No newline at end of file diff --git a/app/Mail/Schedule/ShareEventEmail.php b/app/Mail/Schedule/ShareEventEmail.php deleted file mode 100644 index 61c291f7..00000000 --- a/app/Mail/Schedule/ShareEventEmail.php +++ /dev/null @@ -1,79 +0,0 @@ -from_email = $from_email; - $this->to_email = $to_email; - $this->summit_name = $event->getSummit()->getName(); - $this->event_title = $event->getTitle(); - $this->event_description = $event->getAbstract(); - $this->event_url = $event_url; - } - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - $subject = sprintf("[%s] Fwd %s", $this->summit_name, $this->event_title); - return $this->from($this->from_email) - ->to($this->to_email) - ->subject($subject) - ->view('emails.schedule.share_event'); - } -} \ No newline at end of file diff --git a/app/Mail/SpeakerEditPermissionApprovedEmail.php b/app/Mail/SpeakerEditPermissionApprovedEmail.php deleted file mode 100644 index dc56e3d2..00000000 --- a/app/Mail/SpeakerEditPermissionApprovedEmail.php +++ /dev/null @@ -1,53 +0,0 @@ -request = $request; - } - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this - ->from('noreply@openstack.org') - ->subject("OpenStack - Speaker Profile Edit Permission Approved") - ->view('emails.speakers.permissioneditapproved'); - } -} diff --git a/app/Mail/SpeakerEditPermissionRejectedEmail.php b/app/Mail/SpeakerEditPermissionRejectedEmail.php deleted file mode 100644 index 0d813f3c..00000000 --- a/app/Mail/SpeakerEditPermissionRejectedEmail.php +++ /dev/null @@ -1,53 +0,0 @@ -request = $request; - } - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this - ->from('noreply@openstack.org') - ->subject("OpenStack - Speaker Profile Edit Permission Rejected") - ->view('emails.speakers.permissioneditrejected'); - } -} diff --git a/app/Mail/SpeakerEditPermissionRequestedEmail.php b/app/Mail/SpeakerEditPermissionRequestedEmail.php deleted file mode 100644 index 3d1982fc..00000000 --- a/app/Mail/SpeakerEditPermissionRequestedEmail.php +++ /dev/null @@ -1,60 +0,0 @@ -request = $request; - $this->token = $token; - } - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this - ->from('noreply@openstack.org') - ->subject("OpenStack - Speaker Profile Edit Permission Requested") - ->view('emails.speakers.permissioneditrequested'); - } -} diff --git a/app/ModelSerializers/AdminMemberSerializer.php b/app/ModelSerializers/AdminMemberSerializer.php new file mode 100644 index 00000000..9bbb5ff3 --- /dev/null +++ b/app/ModelSerializers/AdminMemberSerializer.php @@ -0,0 +1,24 @@ + 'email:json_string', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/BaseSerializerTypeSelector.php b/app/ModelSerializers/BaseSerializerTypeSelector.php index 3002bfbb..b59f60c1 100644 --- a/app/ModelSerializers/BaseSerializerTypeSelector.php +++ b/app/ModelSerializers/BaseSerializerTypeSelector.php @@ -55,7 +55,7 @@ final class BaseSerializerTypeSelector implements ISerializerTypeSelector $serializer_type = SerializerRegistry::SerializerType_Public; $current_member = $this->resource_server_context->getCurrentUser(); if(!is_null($current_member)){ - if($current_member->isOnGroup(IGroup::SummitAdministrators)){ + if($current_member->isAdmin()){ $serializer_type = SerializerRegistry::SerializerType_Private; } } diff --git a/app/ModelSerializers/CompanySerializer.php b/app/ModelSerializers/CompanySerializer.php index 83a9a0a1..543f148c 100644 --- a/app/ModelSerializers/CompanySerializer.php +++ b/app/ModelSerializers/CompanySerializer.php @@ -12,15 +12,18 @@ * limitations under the License. **/ - /** * Class CompanySerializer * @package ModelSerializers */ final class CompanySerializer extends SilverStripeSerializer { - protected static $array_mappings = array - ( + protected static $array_mappings = [ 'Name' => 'name:json_string', - ); + 'LogoUrl' => 'logo:json_url', + 'BigLogoUrl' => 'big_logo:json_url', + 'Description' => 'description:json_string', + 'Industry' => 'industry:json_string', + 'Url' => 'url:json_string', + ]; } \ No newline at end of file diff --git a/app/ModelSerializers/ISummitAttendeeTicketSerializerTypes.php b/app/ModelSerializers/ISummitAttendeeTicketSerializerTypes.php new file mode 100644 index 00000000..6b0378ba --- /dev/null +++ b/app/ModelSerializers/ISummitAttendeeTicketSerializerTypes.php @@ -0,0 +1,24 @@ +getSerializer($attr_value->getType())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + $values['type'] = SerializerRegistry::getInstance()->getSerializer + ( + $attr_value->getType() + )->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); } break; diff --git a/app/ModelSerializers/Locations/SummitBookableVenueRoomAvailableSlotSerializer.php b/app/ModelSerializers/Locations/SummitBookableVenueRoomAvailableSlotSerializer.php index c26e6b6b..1d1fd31b 100644 --- a/app/ModelSerializers/Locations/SummitBookableVenueRoomAvailableSlotSerializer.php +++ b/app/ModelSerializers/Locations/SummitBookableVenueRoomAvailableSlotSerializer.php @@ -21,8 +21,6 @@ final class SummitBookableVenueRoomAvailableSlotSerializer extends AbstractSeria protected static $array_mappings = [ 'StartDate' => 'start_date:datetime_epoch', 'EndDate' => 'end_date:datetime_epoch', - 'LocalStartDate' => 'local_start_date:datetime_epoch', - 'LocalEndDate' => 'local_end_date:datetime_epoch', 'Free' => 'is_free:json_boolean', 'Status' => 'status:json_string', ]; diff --git a/app/ModelSerializers/Locations/SummitBookableVenueRoomSerializer.php b/app/ModelSerializers/Locations/SummitBookableVenueRoomSerializer.php index aa6d5729..4ff1965c 100644 --- a/app/ModelSerializers/Locations/SummitBookableVenueRoomSerializer.php +++ b/app/ModelSerializers/Locations/SummitBookableVenueRoomSerializer.php @@ -11,6 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use Libs\ModelSerializers\AbstractSerializer; use models\summit\SummitBookableVenueRoom; use ModelSerializers\Locations\SummitVenueRoomSerializer; use ModelSerializers\SerializerRegistry; @@ -35,7 +37,10 @@ class SummitBookableVenueRoomSerializer extends SummitVenueRoomSerializer $attributes = []; foreach ($room->getAttributes() as $attribute){ - $attributes[] = SerializerRegistry::getInstance()->getSerializer($attribute)->serialize($expand); + $attributes[] = SerializerRegistry::getInstance()->getSerializer($attribute)->serialize + ( + AbstractSerializer::filterExpandByPrefix($expand, 'attributes') + ); } $values['attributes'] = $attributes; return $values; diff --git a/app/ModelSerializers/OwnMemberSerializer.php b/app/ModelSerializers/OwnMemberSerializer.php index eea02802..66aef8d1 100644 --- a/app/ModelSerializers/OwnMemberSerializer.php +++ b/app/ModelSerializers/OwnMemberSerializer.php @@ -21,7 +21,6 @@ final class OwnMemberSerializer extends AbstractMemberSerializer { protected static $array_mappings = [ - 'FirstName' => 'first_name:json_string', 'LastName' => 'last_name:json_string', 'Gender' => 'gender:json_string', @@ -43,7 +42,9 @@ final class OwnMemberSerializer extends AbstractMemberSerializer 'favorite_summit_events', 'feedback', 'schedule_summit_events', + 'summit_tickets', 'rsvp', + 'sponsor_memberships', ]; private static $expand_group_events = [ @@ -101,6 +102,16 @@ final class OwnMemberSerializer extends AbstractMemberSerializer $values['team_memberships'] = $res; } + if(in_array('sponsor_memberships', $relations)){ + $res = []; + foreach ($member->getSponsorMemberships() as $sponsor_membership){ + $res[] = SerializerRegistry::getInstance() + ->getSerializer($sponsor_membership) + ->serialize('summit,company,sponsorship'); + } + $values['sponsor_memberships'] = $res; + } + if(in_array('favorite_summit_events', $relations) && !is_null($summit)){ $res = []; foreach ($member->getFavoritesEventsIds($summit) as $event_id){ @@ -119,6 +130,14 @@ final class OwnMemberSerializer extends AbstractMemberSerializer $values['schedule_summit_events'] = $schedule; } + if(in_array('summit_tickets', $relations) && !is_null($summit)){ + $res = []; + foreach ($member->getPaidSummitTicketsIds($summit) as $ticket_id){ + $res[] = intval($ticket_id); + } + $values['summit_tickets'] = $res; + } + if (!empty($expand)) { foreach (explode(',', $expand) as $relation) { $relation = trim($relation); @@ -180,6 +199,18 @@ final class OwnMemberSerializer extends AbstractMemberSerializer $values['schedule_summit_events'] = $schedule; } break; + case 'summit_tickets':{ + if(!in_array('summit_tickets', $relations)) break; + if(is_null($summit)) break; + $summit_tickets = []; + foreach ($member->getPaidSummitTickets($summit) as $ticket){ + $summit_tickets[] = SerializerRegistry::getInstance() + ->getSerializer($ticket) + ->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + $values['summit_tickets'] = $summit_tickets; + } + break; case 'rsvp':{ if(!in_array('rsvp', $relations)) break; if(is_null($summit)) break; diff --git a/app/ModelSerializers/SerializerRegistry.php b/app/ModelSerializers/SerializerRegistry.php index 4a275459..147aed66 100644 --- a/app/ModelSerializers/SerializerRegistry.php +++ b/app/ModelSerializers/SerializerRegistry.php @@ -11,8 +11,12 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric; use App\ModelSerializers\CCLA\TeamSerializer; use App\ModelSerializers\FileSerializer; +use App\ModelSerializers\ISummitAttendeeTicketSerializerTypes; +use App\ModelSerializers\ISummitOrderSerializerTypes; use App\ModelSerializers\LanguageSerializer; use App\ModelSerializers\Locations\SummitBookableVenueRoomAttributeTypeSerializer; use App\ModelSerializers\Locations\SummitBookableVenueRoomAttributeValueSerializer; @@ -48,6 +52,7 @@ use App\ModelSerializers\ResourceServer\ApiScopeSerializer; use App\ModelSerializers\ResourceServer\ApiSerializer; use App\ModelSerializers\Software\OpenStackComponentSerializer; use App\ModelSerializers\Software\OpenStackReleaseSerializer; +use App\ModelSerializers\Summit\AdminStripePaymentProfileSerializer; use App\ModelSerializers\Summit\AdminSummitSerializer; use App\ModelSerializers\Summit\PersonalCalendarShareInfoSerializer; use App\ModelSerializers\Summit\Presentation\SummitPresentationCommentSerializer; @@ -56,6 +61,12 @@ use App\ModelSerializers\Summit\Presentation\TrackQuestions\TrackDropDownQuestio use App\ModelSerializers\Summit\Presentation\TrackQuestions\TrackMultiValueQuestionTemplateSerializer; use App\ModelSerializers\Summit\Presentation\TrackQuestions\TrackQuestionValueTemplateSerializer; use App\ModelSerializers\Summit\Presentation\TrackQuestions\TrackSingleValueTemplateQuestionSerializer; +use App\ModelSerializers\Summit\Registration\SummitAttendeeCSVSerializer; +use App\ModelSerializers\Summit\Registration\SummitAttendeeTicketCSVSerializer; +use App\ModelSerializers\Summit\SponsorBadgeScanCSVSerializer; +use App\ModelSerializers\Summit\SponsorBadgeScanSerializer; +use App\ModelSerializers\Summit\StripePaymentProfileSerializer; +use App\ModelSerializers\Summit\SummitAttendeeBadgeSerializer; use App\ModelSerializers\Summit\RSVP\Templates\RSVPDropDownQuestionTemplateSerializer; use App\ModelSerializers\Summit\RSVP\Templates\RSVPLiteralContentQuestionTemplateSerializer; use App\ModelSerializers\Summit\RSVP\Templates\RSVPMultiValueQuestionTemplateSerializer; @@ -64,6 +75,7 @@ use App\ModelSerializers\Summit\RSVP\Templates\RSVPSingleValueTemplateQuestionSe use App\ModelSerializers\Summit\RSVPTemplateSerializer; use App\ModelSerializers\Summit\ScheduledSummitLocationBannerSerializer; use App\ModelSerializers\Summit\SelectionPlanSerializer; +use App\ModelSerializers\Summit\SummitEmailEventFlowSerializer; use App\ModelSerializers\Summit\SummitLocationBannerSerializer; use App\ModelSerializers\Summit\TrackTagGroups\TrackTagGroupAllowedTagSerializer; use App\ModelSerializers\Summit\TrackTagGroups\TrackTagGroupSerializer; @@ -100,6 +112,8 @@ final class SerializerRegistry const SerializerType_Public = 'PUBLIC'; const SerializerType_Private = 'PRIVATE'; + const SerializerType_Admin = 'ADMIN'; + const SerializerType_CSV = 'CSV'; private function __clone(){} @@ -125,12 +139,23 @@ final class SerializerRegistry $this->registry['ApiScope'] = ApiScopeSerializer::class; $this->registry['ApiEndpointAuthzGroup'] = ApiEndpointAuthzGroupSerializer::class; // + + $this->registry['SummitEventAttendanceMetric'] = SummitEventAttendanceMetricSerializer::class; + $this->registry['StripePaymentProfile'] = [ + self::SerializerType_Public => StripePaymentProfileSerializer::class, + self::SerializerType_Private => AdminStripePaymentProfileSerializer::class, + ]; + + $this->registry['SummitAdministratorPermissionGroup'] = SummitAdministratorPermissionGroupSerializer::class; + $this->registry['Summit'] = [ self::SerializerType_Public => SummitSerializer::class, self::SerializerType_Private => AdminSummitSerializer::class ]; + $this->registry['SummitDocument'] = SummitDocumentSerializer::class; + $this->registry['SummitEmailEventFlow'] = SummitEmailEventFlowSerializer::class; $this->registry['SelectionPlan'] = SelectionPlanSerializer::class; $this->registry['SummitWIFIConnection'] = SummitWIFIConnectionSerializer::class; $this->registry['SummitType'] = SummitTypeSerializer::class; @@ -150,10 +175,10 @@ final class SerializerRegistry $this->registry['TrackDropDownQuestionTemplate'] = TrackDropDownQuestionTemplateSerializer::class; $this->registry['TrackCheckBoxListQuestionTemplate'] = TrackMultiValueQuestionTemplateSerializer::class; $this->registry['TrackRadioButtonListQuestionTemplate'] = TrackMultiValueQuestionTemplateSerializer::class; + // events $this->registry['SummitEvent'] = SummitEventSerializer::class; $this->registry['SummitGroupEvent'] = SummitGroupEventSerializer::class; - $this->registry['SummitEventMetricsSnapshot'] = SummitEventMetricsSnapshotSerializer::class; $this->registry['TrackTagGroup'] = TrackTagGroupSerializer::class; $this->registry['Presentation'] = [ @@ -163,9 +188,15 @@ final class SerializerRegistry $this->registry['SummitPresentationComment'] = SummitPresentationCommentSerializer::class; + $this->registry['SummitMediaFileType'] = SummitMediaFileTypeSerializer::class; + $this->registry['SummitMediaUploadType'] = SummitMediaUploadTypeSerializer::class; $this->registry['PresentationVideo'] = PresentationVideoSerializer::class; $this->registry['PresentationSlide'] = PresentationSlideSerializer::class; $this->registry['PresentationLink'] = PresentationLinkSerializer::class; + $this->registry['PresentationMediaUpload'] = [ + self::SerializerType_Public => PresentationMediaUploadSerializer::class, + self::SerializerType_Private => AdminPresentationMediaUploadSerializer::class + ]; $this->registry['Company'] = CompanySerializer::class; $this->registry['PresentationSpeaker'] = @@ -202,19 +233,74 @@ final class SerializerRegistry $this->registry['SpeakerOrganizationalRole'] = SpeakerOrganizationalRoleSerializer::class; $this->registry['SummitEventFeedback'] = SummitEventFeedbackSerializer::class; - $this->registry['SummitAttendee'] = SummitAttendeeSerializer::class; - $this->registry['SummitAttendeeTicket'] = SummitAttendeeTicketSerializer::class; $this->registry['SummitMemberSchedule'] = SummitMemberScheduleSerializer::class; $this->registry['SummitMemberFavorite'] = SummitMemberFavoriteSerializer::class; $this->registry['SummitEntityEvent'] = SummitEntityEventSerializer::class; $this->registry['SummitEventWithFile'] = SummitEventWithFileSerializer::class; $this->registry['SummitScheduleEmptySpot'] = SummitScheduleEmptySpotSerializer::class; + // promo codes $this->registry['SummitRegistrationPromoCode'] = SummitRegistrationPromoCodeSerializer::class; $this->registry['MemberSummitRegistrationPromoCode'] = MemberSummitRegistrationPromoCodeSerializer::class; $this->registry['SpeakerSummitRegistrationPromoCode'] = SpeakerSummitRegistrationPromoCodeSerializer::class; $this->registry['SponsorSummitRegistrationPromoCode'] = SponsorSummitRegistrationPromoCodeSerializer::class; $this->registry['PresentationSpeakerSummitAssistanceConfirmationRequest'] = PresentationSpeakerSummitAssistanceConfirmationRequestSerializer::class; + $this->registry['SummitRegistrationDiscountCodeTicketTypeRule'] = SummitRegistrationDiscountCodeTicketTypeRuleSerializer::class; + $this->registry['SummitRegistrationDiscountCode'] = SummitRegistrationDiscountCodeSerializer::class; + $this->registry['MemberSummitRegistrationDiscountCode'] = MemberSummitRegistrationDiscountCodeSerializer::class; + $this->registry['SpeakerSummitRegistrationDiscountCode'] = SpeakerSummitRegistrationDiscountCodeSerializer::class; + $this->registry['SponsorSummitRegistrationDiscountCode'] = SponsorSummitRegistrationDiscountCodeSerializer::class; + + // registration + $this->registry['SummitRegistrationInvitation'] = + [ + self::SerializerType_Public => SummitRegistrationInvitationSerializer::class, + self::SerializerType_CSV => SummitRegistrationInvitationCSVSerializer::class, + ]; + $this->registry['SummitAccessLevelType'] = SummitAccessLevelTypeSerializer::class; + $this->registry['SummitTaxType'] = SummitTaxTypeSerializer::class; + $this->registry['SummitBadgeType'] = SummitBadgeTypeSerializer::class; + $this->registry['SummitBadgeFeatureType'] = SummitBadgeFeatureTypeSerializer::class; + $this->registry['SummitRefundPolicyType'] = SummitRefundPolicyTypeSerializer::class; + $this->registry['SummitOrderExtraQuestionValue'] = SummitOrderExtraQuestionValueSerializer::class; + $this->registry['SummitOrderExtraQuestionType'] = SummitOrderExtraQuestionTypeSerializer::class; + + // orders + + $this->registry['SummitOrder'] =[ + self::SerializerType_Public => SummitOrderBaseSerializer::class, + ISummitOrderSerializerTypes::CheckOutType => SummitOrderBaseSerializer::class, + ISummitOrderSerializerTypes::ReservationType => SummitOrderReservationSerializer::class, + ISummitOrderSerializerTypes::AdminType => SummitOrderAdminSerializer::class, + ]; + + $this->registry['SummitOrderExtraQuestionAnswer'] = SummitOrderExtraQuestionAnswerSerializer::class; + $this->registry['SummitAttendee'] = [ + self::SerializerType_Public => SummitAttendeeSerializer::class, + self::SerializerType_Private => SummitAttendeeSerializer::class, + self::SerializerType_CSV => SummitAttendeeCSVSerializer::class, + ]; + $this->registry['SummitAttendeeTicket'] = [ + self::SerializerType_Public => BaseSummitAttendeeTicketSerializer::class, + ISummitAttendeeTicketSerializerTypes::AdminType => SummitAttendeeTicketSerializer::class, + ISummitAttendeeTicketSerializerTypes::PublicEdition => PublicEditionSummitAttendeeTicketSerializer::class, + ISummitAttendeeTicketSerializerTypes::GuestEdition => GuestEditionSummitAttendeeTicketSerializer::class, + self::SerializerType_CSV => SummitAttendeeTicketCSVSerializer::class, + ]; + + $this->registry['SummitAttendeeBadge'] = SummitAttendeeBadgeSerializer::class; + $this->registry['SponsorBadgeScan'] = [ + self::SerializerType_Public => SponsorBadgeScanSerializer::class, + self::SerializerType_CSV => SponsorBadgeScanCSVSerializer::class, + ]; + + $this->registry['SummitAttendeeTicketTax'] = SummitAttendeeTicketTaxSerializer::class; + + // summit sponsors + + $this->registry['SponsorshipType'] = SponsorshipTypeSerializer::class; + $this->registry['Sponsor'] = SponsorSerializer::class; + // locations $this->registry['SummitVenue'] = SummitVenueSerializer::class; $this->registry['SummitVenueRoom'] = SummitVenueRoomSerializer::class; @@ -238,9 +324,10 @@ final class SerializerRegistry $this->registry['PersonalCalendarShareInfo'] = PersonalCalendarShareInfoSerializer::class; // member - $this->registry['Member'] = [ + $this->registry['Member'] = [ self::SerializerType_Public => PublicMemberSerializer::class, - self::SerializerType_Private => OwnMemberSerializer::class + self::SerializerType_Private => OwnMemberSerializer::class, + self::SerializerType_Admin => AdminMemberSerializer::class ]; $this->registry['Group'] = GroupSerializer::class; diff --git a/app/ModelSerializers/Summit/AdminStripePaymentProfileSerializer.php b/app/ModelSerializers/Summit/AdminStripePaymentProfileSerializer.php new file mode 100644 index 00000000..0cb17e9d --- /dev/null +++ b/app/ModelSerializers/Summit/AdminStripePaymentProfileSerializer.php @@ -0,0 +1,25 @@ + 'live_secret_key:json_string', + 'TestSecretKey' => 'test_secret_key:json_string', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/AdminSummitSerializer.php b/app/ModelSerializers/Summit/AdminSummitSerializer.php index 776d8d7c..809ce2be 100644 --- a/app/ModelSerializers/Summit/AdminSummitSerializer.php +++ b/app/ModelSerializers/Summit/AdminSummitSerializer.php @@ -11,7 +11,10 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use ModelSerializers\SerializerRegistry; use ModelSerializers\SummitSerializer; + /** * Class AdminSummitSerializer * @package App\ModelSerializers\Summit @@ -19,16 +22,38 @@ use ModelSerializers\SummitSerializer; final class AdminSummitSerializer extends SummitSerializer { protected static $array_mappings = [ - 'AvailableOnApi' => 'available_on_api:json_boolean', + 'AvailableOnApi' => 'available_on_api:json_boolean', 'MaxSubmissionAllowedPerUser' => 'max_submission_allowed_per_user:json_int', - 'RegistrationLink' => 'registration_link:json_string', - 'Link' => 'link:json_string', - 'ExternalSummitId' => 'external_summit_id:json_string', - 'CalendarSyncName' => 'calendar_sync_name:json_string', - 'CalendarSyncDesc' => 'calendar_sync_desc:json_string', + 'RegistrationLink' => 'registration_link:json_string', + 'Link' => 'link:json_string', + 'ExternalSummitId' => 'external_summit_id:json_string', + 'CalendarSyncName' => 'calendar_sync_name:json_string', + 'CalendarSyncDesc' => 'calendar_sync_desc:json_string', // External Feeds - 'ApiFeedType' => 'api_feed_type:json_string', - 'ApiFeedUrl' => 'api_feed_url:json_string', - 'ApiFeedKey' => 'api_feed_key:json_string', + 'ApiFeedType' => 'api_feed_type:json_string', + 'ApiFeedUrl' => 'api_feed_url:json_string', + 'ApiFeedKey' => 'api_feed_key:json_string', + // registration + 'OrderQRPrefix' => 'order_qr_prefix:json_string', + 'TicketQRPrefix' => 'ticket_qr_prefix:json_string', + 'BadgeQRPrefix' => 'badge_qr_prefix:json_string', + 'QRRegistryFieldDelimiter' => 'qr_registry_field_delimiter:json_string', + 'ReassignTicketTillDate' => 'reassign_ticket_till_date:datetime_epoch', + 'RegistrationDisclaimerContent' => 'registration_disclaimer_content:json_string', + 'RegistrationDisclaimerMandatory' => 'registration_disclaimer_mandatory:json_boolean', + // registration external feed + 'ExternalRegistrationFeedType' => 'external_registration_feed_type:json_string', + 'ExternalRegistrationFeedApiKey' => 'external_registration_feed_api_key:json_string', + // oauth2 clients + 'VirtualSiteOAuth2ClientId' => 'virtual_site_oauth2_client_id:json_string', + 'MarketingSiteOAuth2ClientId' => 'marketing_site_oauth2_client_id:json_string', ]; + + /** + * @return string + */ + protected function getSerializerType(): string + { + return SerializerRegistry::SerializerType_Private; + } } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/PaymentGatewayProfileSerializer.php b/app/ModelSerializers/Summit/PaymentGatewayProfileSerializer.php new file mode 100644 index 00000000..5be12f9a --- /dev/null +++ b/app/ModelSerializers/Summit/PaymentGatewayProfileSerializer.php @@ -0,0 +1,26 @@ + 'active:json_boolean', + 'Provider' => 'provider:json_string', + 'ApplicationType' => 'application_type:json_string', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Presentation/AdminPresentationMediaUploadSerializer.php b/app/ModelSerializers/Summit/Presentation/AdminPresentationMediaUploadSerializer.php new file mode 100644 index 00000000..854e1ed3 --- /dev/null +++ b/app/ModelSerializers/Summit/Presentation/AdminPresentationMediaUploadSerializer.php @@ -0,0 +1,55 @@ +object; + if(!$mediaUpload instanceof PresentationMediaUpload) return []; + + $mediaUploadType = $mediaUpload->getMediaUploadType(); + if(!is_null($mediaUploadType)) { + try{ + $strategy = FileDownloadStrategyFactory::build($mediaUploadType->getPrivateStorageType()); + if (!is_null($strategy)) { + + $values['private_url'] = $strategy->getUrl($mediaUpload->getRelativePath(IStorageTypesConstants::PrivateType)); + } + } + catch (\Exception $ex){ + Log::warning($ex); + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Presentation/PresentationCategorySerializer.php b/app/ModelSerializers/Summit/Presentation/PresentationCategorySerializer.php index 02d5e85f..a704e939 100644 --- a/app/ModelSerializers/Summit/Presentation/PresentationCategorySerializer.php +++ b/app/ModelSerializers/Summit/Presentation/PresentationCategorySerializer.php @@ -11,7 +11,9 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use models\summit\PresentationCategory; + /** * Class PresentationCategorySerializer * @package ModelSerializers @@ -19,19 +21,20 @@ use models\summit\PresentationCategory; final class PresentationCategorySerializer extends SilverStripeSerializer { protected static $array_mappings = - [ - 'Title' => 'name:json_string', - 'Description' => 'description:json_string', - 'Code' => 'code:json_string', - 'Slug' => 'slug:json_string', - 'SessionCount' => 'session_count:json_int', - 'AlternateCount' => 'alternate_count:json_int', - 'LightningCount' => 'lightning_count:json_int', - 'LightningAlternateCount' => 'lightning_alternate_count:json_int', - 'VotingVisible' => 'voting_visible:json_boolean', - 'ChairVisible' => 'chair_visible:json_boolean', - 'SummitId' => 'summit_id:json_int', - ]; + [ + 'Title' => 'name:json_string', + 'Description' => 'description:json_string', + 'Code' => 'code:json_string', + 'Slug' => 'slug:json_string', + 'SessionCount' => 'session_count:json_int', + 'AlternateCount' => 'alternate_count:json_int', + 'LightningCount' => 'lightning_count:json_int', + 'LightningAlternateCount' => 'lightning_alternate_count:json_int', + 'VotingVisible' => 'voting_visible:json_boolean', + 'ChairVisible' => 'chair_visible:json_boolean', + 'SummitId' => 'summit_id:json_int', + 'Color' => 'color:json_string', + ]; /** * @param null $expand @@ -40,25 +43,34 @@ final class PresentationCategorySerializer extends SilverStripeSerializer * @param array $params * @return array */ - public function serialize($expand = null, array $fields = [], array $relations = [], array $params = [] ) + public function serialize($expand = null, array $fields = [], array $relations = [], array $params = []) { $category = $this->object; - if(!$category instanceof PresentationCategory) return []; - $values = parent::serialize($expand, $fields, $relations, $params); - $groups = []; + if (!$category instanceof PresentationCategory) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + $groups = []; $allowed_tag = []; $extra_questions = []; $summit = $category->getSummit(); - foreach($category->getGroups() as $group){ + $color = isset($values['color']) ? $values['color']:''; + if(empty($color)) + $color = 'f0f0ee'; + + if (strpos($color,'#') === false) { + $color = '#'.$color; + } + $values['color'] = $color; + + foreach ($category->getGroups() as $group) { $groups[] = intval($group->getId()); } - foreach($category->getAllowedTags() as $tag){ + foreach ($category->getAllowedTags() as $tag) { $allowed_tag[] = $tag->getId(); } - foreach($category->getExtraQuestions() as $question){ + foreach ($category->getExtraQuestions() as $question) { $extra_questions[] = intval($question->getId()); } @@ -70,42 +82,45 @@ final class PresentationCategorySerializer extends SilverStripeSerializer $exp_expand = explode(',', $expand); foreach ($exp_expand as $relation) { switch (trim($relation)) { - case 'track_groups': { - $groups = []; - unset($values['track_groups']); - foreach ($category->getGroups() as $g) { - $groups[] = SerializerRegistry::getInstance()->getSerializer($g)->serialize(null, [], ['none']); - } - $values['track_groups'] = $groups; - } - break; - } - switch (trim($relation)) { - case 'allowed_tags': { - $allowed_tags = []; - unset($values['allowed_tags']); - foreach ($category->getAllowedTags() as $tag) { - $allowed_tag = SerializerRegistry::getInstance()->getSerializer($tag)->serialize(null, [], ['none']); - $track_tag_group = $summit->getTrackTagGroupForTag($tag); - if(!is_null($track_tag_group)){ - $allowed_tag['track_tag_group'] = SerializerRegistry::getInstance()->getSerializer($track_tag_group)->serialize(null, [], ['none']); + case 'track_groups': + { + $groups = []; + unset($values['track_groups']); + foreach ($category->getGroups() as $g) { + $groups[] = SerializerRegistry::getInstance()->getSerializer($g)->serialize(null, [], ['none']); } - $allowed_tags[] = $allowed_tag; + $values['track_groups'] = $groups; } - $values['allowed_tags'] = $allowed_tags; - } - break; + break; } switch (trim($relation)) { - case 'extra_questions': { - $extra_questions = []; - unset($values['extra_questions']); - foreach ($category->getExtraQuestions() as $question) { - $extra_questions[] = SerializerRegistry::getInstance()->getSerializer($question)->serialize(null, [], ['none']); + case 'allowed_tags': + { + $allowed_tags = []; + unset($values['allowed_tags']); + foreach ($category->getAllowedTags() as $tag) { + $allowed_tag = SerializerRegistry::getInstance()->getSerializer($tag)->serialize(null, [], ['none']); + $track_tag_group = $summit->getTrackTagGroupForTag($tag); + if (!is_null($track_tag_group)) { + $allowed_tag['track_tag_group'] = SerializerRegistry::getInstance()->getSerializer($track_tag_group)->serialize(null, [], ['none']); + } + $allowed_tags[] = $allowed_tag; + } + $values['allowed_tags'] = $allowed_tags; } - $values['extra_questions'] = $extra_questions; - } - break; + break; + } + switch (trim($relation)) { + case 'extra_questions': + { + $extra_questions = []; + unset($values['extra_questions']); + foreach ($category->getExtraQuestions() as $question) { + $extra_questions[] = SerializerRegistry::getInstance()->getSerializer($question)->serialize(null, [], ['none']); + } + $values['extra_questions'] = $extra_questions; + } + break; } } } diff --git a/app/ModelSerializers/Summit/Presentation/PresentationMaterialSerializer.php b/app/ModelSerializers/Summit/Presentation/PresentationMaterialSerializer.php index c1db1db1..a5d92c1c 100644 --- a/app/ModelSerializers/Summit/Presentation/PresentationMaterialSerializer.php +++ b/app/ModelSerializers/Summit/Presentation/PresentationMaterialSerializer.php @@ -27,6 +27,6 @@ class PresentationMaterialSerializer extends SilverStripeSerializer 'Featured' => 'featured:json_boolean', 'Order' => 'order:json_int', 'PresentationId' => 'presentation_id:json_int', - 'ClassName' => 'class_name:json_text', + 'ClassName' => 'class_name:json_text', ]; } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Presentation/PresentationMediaUploadSerializer.php b/app/ModelSerializers/Summit/Presentation/PresentationMediaUploadSerializer.php new file mode 100644 index 00000000..97df0c0e --- /dev/null +++ b/app/ModelSerializers/Summit/Presentation/PresentationMediaUploadSerializer.php @@ -0,0 +1,81 @@ + 'filename:json_text', + 'MediaUploadTypeId' => 'media_upload_type_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() ) + { + $values = parent::serialize($expand, $fields, $relations, $params); + $mediaUpload = $this->object; + if(!$mediaUpload instanceof PresentationMediaUpload) return []; + unset($values['name']); + unset($values['description']); + unset($values['display_on_site']); + unset($values['featured']); + $values['display_on_site'] = false; + + $mediaUploadType = $mediaUpload->getMediaUploadType(); + if(!is_null($mediaUploadType)){ + try { + $values['name'] = $mediaUploadType->getName(); + $values['description'] = $mediaUploadType->getDescription(); + $strategy = FileDownloadStrategyFactory::build($mediaUploadType->getPublicStorageType()); + if (!is_null($strategy)) { + $values['public_url'] = $strategy->getUrl($mediaUpload->getRelativePath()); + $values['display_on_site'] = true; + } + } + catch (\Exception $ex){ + Log::warning($ex); + } + } + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + $relation = trim($relation); + switch ($relation) { + case 'media_upload_type': { + unset($values['media_upload_type_id']); + $type = $mediaUpload->getMediaUploadType(); + if(!is_null($type)) + $values['media_upload_type'] = SerializerRegistry::getInstance()->getSerializer($type)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + break; + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Presentation/PresentationSerializer.php b/app/ModelSerializers/Summit/Presentation/PresentationSerializer.php index 40959f4c..ea188ba1 100644 --- a/app/ModelSerializers/Summit/Presentation/PresentationSerializer.php +++ b/app/ModelSerializers/Summit/Presentation/PresentationSerializer.php @@ -11,7 +11,6 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - use Libs\ModelSerializers\AbstractSerializer; use models\summit\Presentation; /** @@ -33,6 +32,7 @@ class PresentationSerializer extends SummitEventSerializer 'StatusNice' => 'status:json_string', 'ProgressNice' => 'progress:json_string', 'Slug' => 'slug:json_string', + 'SelectionStatus' => 'selection_status:string', ]; protected static $allowed_fields = [ @@ -47,10 +47,12 @@ class PresentationSerializer extends SummitEventSerializer 'attending_media', 'status', 'progress', + 'selection_status', ]; protected static $allowed_relations = [ 'slides', + 'media_uploads', 'videos', 'speakers', 'links', @@ -121,6 +123,21 @@ class PresentationSerializer extends SummitEventSerializer $values['videos'] = $videos; } + if(in_array('media_uploads', $relations)) + { + $media_uploads = []; + $serializerType = SerializerRegistry::SerializerType_Public; + $currentUser = $this->resource_server_context->getCurrentUser(); + if(!is_null($currentUser) && $currentUser->isAdmin()){ + $serializerType = SerializerRegistry::SerializerType_Private; + } + + foreach ($presentation->getMediaUploads() as $mediaUpload) { + $media_uploads[] = SerializerRegistry::getInstance()->getSerializer($mediaUpload, $serializerType)->serialize(AbstractSerializer::filterExpandByPrefix($expand, 'media_uploads'));; + } + $values['media_uploads'] = $media_uploads; + } + if(in_array('extra_questions', $relations)) { $answers = []; @@ -146,8 +163,13 @@ class PresentationSerializer extends SummitEventSerializer } case 'creator':{ if($presentation->getCreatorId() > 0) { + $member = $this->resource_server_context->getCurrentUser(); + $type = SerializerRegistry::SerializerType_Public; + if(!is_null($member) && $member->isAdmin()){ + $type = SerializerRegistry::SerializerType_Admin; + } unset($values['creator_id']); - $values['creator'] = SerializerRegistry::getInstance()->getSerializer($presentation->getCreator())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + $values['creator'] = SerializerRegistry::getInstance()->getSerializer($presentation->getCreator(), $type)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); } } break; diff --git a/app/ModelSerializers/Summit/Presentation/PresentationSlideSerializer.php b/app/ModelSerializers/Summit/Presentation/PresentationSlideSerializer.php index 22024b8a..0ca7cf3e 100644 --- a/app/ModelSerializers/Summit/Presentation/PresentationSlideSerializer.php +++ b/app/ModelSerializers/Summit/Presentation/PresentationSlideSerializer.php @@ -1,6 +1,4 @@ object; + if (!$type instanceof PresentationType) return []; + + $allowed_media_upload_types = []; + + foreach ($type->getAllowedMediaUploadTypes() as $media_type){ + $allowed_media_upload_types[] = $media_type->getId(); + } + + $values['allowed_media_upload_types'] = $allowed_media_upload_types; + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + $relation = trim($relation); + switch ($relation) { + + case 'allowed_media_upload_types': { + unset($values['allowed_media_upload_types']); + $allowed_media_upload_types = []; + + foreach ($type->getAllowedMediaUploadTypes() as $media_type){ + $allowed_media_upload_types[] = SerializerRegistry::getInstance()->getSerializer($media_type)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + + $values['allowed_media_upload_types'] = $allowed_media_upload_types; + } + break; + } + } + } return $values; } } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/BaseSummitAttendeeTicketSerializer.php b/app/ModelSerializers/Summit/Registration/BaseSummitAttendeeTicketSerializer.php new file mode 100644 index 00000000..3c9b329a --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/BaseSummitAttendeeTicketSerializer.php @@ -0,0 +1,108 @@ + 'number:json_string', + 'Status' => 'status:json_string', + 'ExternalOrderId' => 'external_order_id:json_string', + 'ExternalAttendeeId' => 'external_attendee_id:json_string', + 'BoughtDate' => 'bought_date:datetime_epoch', + 'TicketTypeId' => 'ticket_type_id:json_int', + 'OwnerId' => 'owner_id:json_int', + 'OrderId' => 'order_id:json_int', + 'BadgeId' => 'badge_id:json_int', + 'PromoCodeId' => 'promo_code_id:json_int', + 'RawCost' => 'raw_cost:json_float', + 'FinalAmount' => 'final_amount:json_float', + 'Discount' => 'discount:json_float', + 'RefundedAmount' => 'refunded_amount:json_float', + 'Currency' => 'currency:json_string', + ]; + + protected static $allowed_relations = [ + 'applied_taxes', + ]; + + /** + * @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()) + { + $ticket = $this->object; + if (!$ticket instanceof SummitAttendeeTicket) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if (!count($relations)) $relations = $this->getAllowedRelations(); + + Log::debug(sprintf("BaseSummitAttendeeTicketSerializer::serialize expand %s", $expand)); + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'ticket_type': { + if(!$ticket->hasTicketType()) continue; + unset($values['ticket_type_id']); + $values['ticket_type'] = SerializerRegistry::getInstance()->getSerializer($ticket->getTicketType())->serialize(AbstractSerializer::getExpandForPrefix('ticket_type', $expand)); + } + break; + case 'badge': { + if(!$ticket->hasBadge()) continue; + unset($values['badge_id']); + $values['badge'] = SerializerRegistry::getInstance()->getSerializer($ticket->getBadge())->serialize(AbstractSerializer::getExpandForPrefix('badge', $expand)); + } + break; + case 'promo_code': { + if(!$ticket->hasPromoCode()) continue; + unset($values['promo_code_id']); + $values['promo_code'] = SerializerRegistry::getInstance()->getSerializer($ticket->getPromoCode())->serialize(AbstractSerializer::getExpandForPrefix('promo_code', $expand)); + } + break; + case 'applied_taxes': { + if (in_array('applied_taxes', $relations)) { + unset( $values['applied_taxes']); + $applied_taxes = []; + foreach ($ticket->getAppliedTaxes() as $tax) { + $applied_taxes[] = SerializerRegistry::getInstance()->getSerializer($tax)->serialize(AbstractSerializer::getExpandForPrefix('applied_taxes', $expand)); + } + $values['applied_taxes'] = $applied_taxes; + } + } + break; + case 'owner': { + if(!$ticket->hasOwner()) continue; + unset($values['owner_id']); + $values['owner'] = SerializerRegistry::getInstance()->getSerializer($ticket->getOwner())->serialize(AbstractSerializer::getExpandForPrefix('owner', $expand)); + } + break; + } + + } + } + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/GuestEditionSummitAttendeeTicketSerializer.php b/app/ModelSerializers/Summit/Registration/GuestEditionSummitAttendeeTicketSerializer.php new file mode 100644 index 00000000..45243925 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/GuestEditionSummitAttendeeTicketSerializer.php @@ -0,0 +1,47 @@ +object; + if (!$ticket instanceof SummitAttendeeTicket) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + $base_url = Config::get('registration.dashboard_base_url', null); + $edit_ticket_link = Config::get('registration.dashboard_attendee_edit_form_url', null); + + if(empty($base_url)) + throw new \InvalidArgumentException("missing dashboard_base_url value"); + if(empty($edit_ticket_link)) + throw new \InvalidArgumentException("missing dashboard_attendee_edit_form_url value"); + + $values['edit_link'] = sprintf($edit_ticket_link, $base_url, $ticket->getHash()); + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/PromoCodes/MemberSummitRegistrationDiscountCodeSerializer.php b/app/ModelSerializers/Summit/Registration/PromoCodes/MemberSummitRegistrationDiscountCodeSerializer.php new file mode 100644 index 00000000..9ec77074 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/PromoCodes/MemberSummitRegistrationDiscountCodeSerializer.php @@ -0,0 +1,82 @@ + 'first_name:json_string', + 'LastName' => 'last_name:json_string', + 'Email' => 'email:json_string', + 'Type' => 'type: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 $relations = [], array $params = [] ) + { + if(!count($relations)) $relations = $this->getAllowedRelations(); + + $code = $this->object; + if(!$code instanceof MemberSummitRegistrationDiscountCode) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + $serializer_type = SerializerRegistry::SerializerType_Public; + + if(isset($params['serializer_type'])) + $serializer_type = $params['serializer_type']; + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + switch (trim($relation)) { + case 'owner': { + if($code->hasOwner()){ + unset($values['owner_id']); + $values['owner'] = SerializerRegistry::getInstance()->getSerializer + ( + $code->getOwner(), + $serializer_type + )->serialize($expand); + } + } + break; + case 'owner_name': { + if($code->hasOwner()){ + $values['owner_name'] = $code->getOwner()->getFullName(); + } + } + break; + case 'owner_email': { + if($code->hasOwner()){ + $values['owner_email'] = $code->getOwner()->getEmail(); + } + } + break; + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/PromoCodes/MemberSummitRegistrationPromoCodeSerializer.php b/app/ModelSerializers/Summit/Registration/PromoCodes/MemberSummitRegistrationPromoCodeSerializer.php similarity index 100% rename from app/ModelSerializers/Summit/PromoCodes/MemberSummitRegistrationPromoCodeSerializer.php rename to app/ModelSerializers/Summit/Registration/PromoCodes/MemberSummitRegistrationPromoCodeSerializer.php diff --git a/app/ModelSerializers/Summit/Registration/PromoCodes/SpeakerSummitRegistrationDiscountCodeSerializer.php b/app/ModelSerializers/Summit/Registration/PromoCodes/SpeakerSummitRegistrationDiscountCodeSerializer.php new file mode 100644 index 00000000..ef206755 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/PromoCodes/SpeakerSummitRegistrationDiscountCodeSerializer.php @@ -0,0 +1,77 @@ + 'type:json_string', + 'SpeakerId' => 'speaker_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 $relations = [], array $params = [] ) + { + if(!count($relations)) $relations = $this->getAllowedRelations(); + + $code = $this->object; + if(!$code instanceof SpeakerSummitRegistrationDiscountCode) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + $serializer_type = SerializerRegistry::SerializerType_Public; + + if(isset($params['serializer_type'])) + $serializer_type = $params['serializer_type']; + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + switch (trim($relation)) { + case 'speaker': { + if($code->hasSpeaker()){ + unset($values['speaker_id']); + $values['speaker'] = SerializerRegistry::getInstance()->getSerializer + ( + $code->getSpeaker(), + $serializer_type + )->serialize($expand); + } + } + case 'owner_name': { + if($code->hasSpeaker()){ + $values['owner_name'] = $code->getSpeaker()->getFullName(); + } + } + break; + case 'owner_email': { + if($code->hasSpeaker()){ + $values['owner_email'] = $code->getSpeaker()->getEmail(); + } + } + break; + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/PromoCodes/SpeakerSummitRegistrationPromoCodeSerializer.php b/app/ModelSerializers/Summit/Registration/PromoCodes/SpeakerSummitRegistrationPromoCodeSerializer.php similarity index 100% rename from app/ModelSerializers/Summit/PromoCodes/SpeakerSummitRegistrationPromoCodeSerializer.php rename to app/ModelSerializers/Summit/Registration/PromoCodes/SpeakerSummitRegistrationPromoCodeSerializer.php diff --git a/app/ModelSerializers/Summit/PromoCodes/SummitRegistrationPromoCodeSerializer.php b/app/ModelSerializers/Summit/Registration/PromoCodes/SponsorSummitRegistrationDiscountCodeSerializer.php similarity index 65% rename from app/ModelSerializers/Summit/PromoCodes/SummitRegistrationPromoCodeSerializer.php rename to app/ModelSerializers/Summit/Registration/PromoCodes/SponsorSummitRegistrationDiscountCodeSerializer.php index d4c9a30a..9234394d 100644 --- a/app/ModelSerializers/Summit/PromoCodes/SummitRegistrationPromoCodeSerializer.php +++ b/app/ModelSerializers/Summit/Registration/PromoCodes/SponsorSummitRegistrationDiscountCodeSerializer.php @@ -1,6 +1,6 @@ 'code:json_string', - 'Redeemed' => 'redeemed:json_boolean', - 'EmailSent' => 'email_sent:json_boolean', - 'Source' => 'source:json_string', - 'SummitId' => 'summit_id:json_int', - 'CreatorId' => 'creator_id:json_int', - 'ClassName' => 'class_name:json_string', + 'SponsorId' => 'sponsor_id:json_int', ]; /** @@ -40,7 +35,7 @@ class SummitRegistrationPromoCodeSerializer extends SilverStripeSerializer if(!count($relations)) $relations = $this->getAllowedRelations(); $code = $this->object; - if(!$code instanceof SummitRegistrationPromoCode) return []; + if(!$code instanceof SponsorSummitRegistrationDiscountCode) return []; $values = parent::serialize($expand, $fields, $relations, $params); $serializer_type = SerializerRegistry::SerializerType_Public; @@ -50,17 +45,21 @@ class SummitRegistrationPromoCodeSerializer extends SilverStripeSerializer if (!empty($expand)) { foreach (explode(',', $expand) as $relation) { switch (trim($relation)) { - case 'creator': { - if($code->hasCreator()){ - unset($values['creator_id']); - $values['creator'] = SerializerRegistry::getInstance()->getSerializer + case 'sponsor': { + if($code->hasSponsor()){ + unset($values['sponsor_id']); + $values['sponsor'] = SerializerRegistry::getInstance()->getSerializer ( - $code->getCreator(), + $code->getSponsor(), $serializer_type )->serialize($expand); } } - break; + break; + case 'sponsor_name':{ + $values['sponsor_name'] = $code->getSponsor()->getName(); + } + break; } } } diff --git a/app/ModelSerializers/Summit/PromoCodes/SponsorSummitRegistrationPromoCodeSerializer.php b/app/ModelSerializers/Summit/Registration/PromoCodes/SponsorSummitRegistrationPromoCodeSerializer.php similarity index 100% rename from app/ModelSerializers/Summit/PromoCodes/SponsorSummitRegistrationPromoCodeSerializer.php rename to app/ModelSerializers/Summit/Registration/PromoCodes/SponsorSummitRegistrationPromoCodeSerializer.php diff --git a/app/ModelSerializers/Summit/Registration/PromoCodes/SummitRegistrationDiscountCodeSerializer.php b/app/ModelSerializers/Summit/Registration/PromoCodes/SummitRegistrationDiscountCodeSerializer.php new file mode 100644 index 00000000..bada6edb --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/PromoCodes/SummitRegistrationDiscountCodeSerializer.php @@ -0,0 +1,79 @@ + 'rate:json_float', + 'Amount' => 'amount:json_float', + ]; + + protected static $allowed_relations = [ + 'ticket_types_rules', + ]; + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = [], array $relations = [], array $params = []) + { + if (!count($relations)) $relations = $this->getAllowedRelations(); + + $code = $this->object; + if (!$code instanceof SummitRegistrationDiscountCode) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + unset($values['allowed_ticket_types']); + + if (in_array('ticket_types_rules', $relations)) { + $ticket_types_rules = []; + foreach ($code->getTicketTypesRules() as $ticket_types_rule) { + $ticket_types_rules[] = $ticket_types_rule->getId(); + } + $values['ticket_types_rules'] = $ticket_types_rules; + } + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + $relation = trim($relation); + switch ($relation) { + case 'ticket_types_rules': + { + unset($values['ticket_types_rules']); + $ticket_types_rules = []; + foreach ($code->getTicketTypesRules() as $ticket_types_rule) { + $ticket_types_rules[] = SerializerRegistry::getInstance()->getSerializer($ticket_types_rule)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + $values['ticket_types_rules'] = $ticket_types_rules; + } + break; + + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/PromoCodes/SummitRegistrationDiscountCodeTicketTypeRuleSerializer.php b/app/ModelSerializers/Summit/Registration/PromoCodes/SummitRegistrationDiscountCodeTicketTypeRuleSerializer.php new file mode 100644 index 00000000..7dc6d42c --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/PromoCodes/SummitRegistrationDiscountCodeTicketTypeRuleSerializer.php @@ -0,0 +1,69 @@ + 'id:json_int', + 'Rate' => 'rate:json_float', + 'Amount' => 'amount:json_float', + 'TicketTypeId' => 'ticket_type_id:json_int', + 'DiscountCodeId' => 'discount_code_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 $relations = [], array $params = []) + { + if (!count($relations)) $relations = $this->getAllowedRelations(); + + $rule = $this->object; + if (!$rule instanceof SummitRegistrationDiscountCodeTicketTypeRule) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + $relation = trim($relation); + switch ($relation) { + case 'ticket_type': + { + unset($values['ticket_type_id']); + $values['ticket_type'] = SerializerRegistry::getInstance()->getSerializer($rule->getTicketType())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + break; + case 'discount_code': + { + unset($values['discount_code_id']); + $values['discount_code'] = SerializerRegistry::getInstance()->getSerializer($rule->getDiscountCode())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + break; + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/PromoCodes/SummitRegistrationPromoCodeSerializer.php b/app/ModelSerializers/Summit/Registration/PromoCodes/SummitRegistrationPromoCodeSerializer.php new file mode 100644 index 00000000..71f98e33 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/PromoCodes/SummitRegistrationPromoCodeSerializer.php @@ -0,0 +1,125 @@ + 'code:json_string', + 'Redeemed' => 'redeemed:json_boolean', + 'EmailSent' => 'email_sent:json_boolean', + 'Source' => 'source:json_string', + 'SummitId' => 'summit_id:json_int', + 'CreatorId' => 'creator_id:json_int', + 'BadgeTypeId' => 'badge_type_id:json_int', + 'QuantityAvailable' => 'quantity_available:json_int', + 'QuantityUsed' => 'quantity_used:json_int', + 'ValidSinceDate' => 'valid_since_date:datetime_epoch', + 'ValidUntilDate' => 'valid_until_date:datetime_epoch', + 'ClassName' => 'class_name:json_string', + ]; + + protected static $allowed_relations = [ + 'badge_features', + 'allowed_ticket_types', + ]; + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = [], array $relations = [], array $params = [] ) + { + if(!count($relations)) $relations = $this->getAllowedRelations(); + + $code = $this->object; + if(!$code instanceof SummitRegistrationPromoCode) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + $serializer_type = SerializerRegistry::SerializerType_Public; + + if(in_array('badge_features', $relations)) { + $features = []; + foreach ($code->getBadgeFeatures() as $feature) { + $features[] = $feature->getId(); + } + $values['badge_features'] = $features; + } + + if(in_array('allowed_ticket_types', $relations)) { + $ticket_types = []; + foreach ($code->getAllowedTicketTypes() as $ticket_type) { + $ticket_types[] = $ticket_type->getId(); + } + $values['allowed_ticket_types'] = $ticket_types; + } + + if(isset($params['serializer_type'])) + $serializer_type = $params['serializer_type']; + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + switch (trim($relation)) { + case 'creator': { + if($code->hasCreator()){ + unset($values['creator_id']); + $values['creator'] = SerializerRegistry::getInstance()->getSerializer + ( + $code->getCreator(), + $serializer_type + )->serialize($expand); + } + } + break; + case 'badge_features': { + unset($values['badge_features']); + $features = []; + foreach ($code->getBadgeFeatures() as $feature) { + $features[] = SerializerRegistry::getInstance()->getSerializer($feature)->serialize($expand); + } + $values['badge_features'] = $features; + } + break; + case 'allowed_ticket_types': { + unset($values['allowed_ticket_types']); + + $ticket_types = []; + foreach ($code->getAllowedTicketTypes() as $ticket_type) { + $ticket_types[] = SerializerRegistry::getInstance()->getSerializer($ticket_type)->serialize($expand); + } + $values['allowed_ticket_types'] = $ticket_types; + } + break; + case 'badge_type': { + if($code->hasBadgeType()){ + unset($values['badge_type_id']); + $values['badge_type'] = SerializerRegistry::getInstance()->getSerializer + ( + $code->getBadgeType() + )->serialize($expand); + } + } + break; + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/PublicEditionSummitAttendeeTicketSerializer.php b/app/ModelSerializers/Summit/Registration/PublicEditionSummitAttendeeTicketSerializer.php new file mode 100644 index 00000000..0f3b3c7a --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/PublicEditionSummitAttendeeTicketSerializer.php @@ -0,0 +1,43 @@ +object; + if (!$ticket instanceof SummitAttendeeTicket) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + $order_extra_questions = []; + $summit = $ticket->getOrder()->getSummit(); + foreach ($summit->getOrderExtraQuestions() as $question) { + $order_extra_questions[] = SerializerRegistry::getInstance()->getSerializer($question)->serialize(AbstractSerializer::filterExpandByPrefix($expand,"order_extra_questions")); + } + $values['order_extra_questions'] = $order_extra_questions; + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SponsorBadgeScanCSVSerializer.php b/app/ModelSerializers/Summit/Registration/SponsorBadgeScanCSVSerializer.php new file mode 100644 index 00000000..16602e6d --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SponsorBadgeScanCSVSerializer.php @@ -0,0 +1,53 @@ + 'scan_date:datetime_epoch', + 'QRCode' => 'qr_code:json_string', + 'SponsorId' => 'sponsor_id:json_int', + 'UserId' => 'user_id:json_int', + 'BadgeId' => 'badge_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() ) + { + $scan = $this->object; + if (!$scan instanceof SponsorBadgeScan) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + $attendee = $scan->getBadge()->getTicket()->getOwner(); + + $values['attendee_first_name'] = $attendee->hasMember() ? $attendee->getMember()->getFirstName() : $attendee->getFirstName(); + $values['attendee_last_name'] = $attendee->hasMember() ? $attendee->getMember()->getLastName() :$attendee->getSurname(); + $values['attendee_email'] = $attendee->getEmail(); + $values['attendee_company'] = $attendee->getCompanyName(); + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SponsorBadgeScanSerializer.php b/app/ModelSerializers/Summit/Registration/SponsorBadgeScanSerializer.php new file mode 100644 index 00000000..02fa3d75 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SponsorBadgeScanSerializer.php @@ -0,0 +1,74 @@ + 'scan_date:datetime_epoch', + 'QRCode' => 'qr_code:json_string', + 'SponsorId' => 'sponsor_id:json_int', + 'UserId' => 'user_id:json_int', + 'BadgeId' => 'badge_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() ) + { + $scan = $this->object; + if (!$scan instanceof SponsorBadgeScan) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'sponsor': { + if(!$scan->hasSponsor()) continue; + unset($values['sponsor_id']); + $values['sponsor'] = SerializerRegistry::getInstance()->getSerializer($scan->getSponsor())->serialize(AbstractSerializer::filterExpandByPrefix($expand, "sponsor")); + } + break; + case 'user': { + if(!$scan->hasUser()) continue; + unset($values['user_id']); + $values['user'] = SerializerRegistry::getInstance()->getSerializer($scan->getUser())->serialize(AbstractSerializer::filterExpandByPrefix($expand, "user")); + } + break; + case 'badge': { + if(!$scan->hasBadge()) continue; + unset($values['badge_id']); + $values['badge'] = SerializerRegistry::getInstance()->getSerializer($scan->getBadge())->serialize(AbstractSerializer::filterExpandByPrefix($expand, "badge")); + } + break; + } + + } + } + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitAccessLevelTypeSerializer.php b/app/ModelSerializers/Summit/Registration/SummitAccessLevelTypeSerializer.php new file mode 100644 index 00000000..44c3ed69 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitAccessLevelTypeSerializer.php @@ -0,0 +1,28 @@ + 'name:json_string', + 'Description' => 'description:json_string', + 'TemplateContent' => 'template_content:json_string', + 'Default' => 'is_default:json_boolean', + 'SummitId' => 'summit_id:json_int', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitAttendeeBadgeSerializer.php b/app/ModelSerializers/Summit/Registration/SummitAttendeeBadgeSerializer.php new file mode 100644 index 00000000..bd9db527 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitAttendeeBadgeSerializer.php @@ -0,0 +1,100 @@ + 'print_date:datetime_epoch', + 'QRCode' => 'qr_code:json_string', + 'Void' => 'is_void:json_boolean', + 'TicketId' => 'ticket_id:json_int', + 'TypeId' => 'type_id:json_int', + 'PrintedTimes' => 'printed_times:json_int', + ]; + + protected static $allowed_relations = [ + 'features', + ]; + + /** + * @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()) + { + if(!count($relations)) $relations = $this->getAllowedRelations(); + $badge = $this->object; + if(!$badge instanceof SummitAttendeeBadge) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if (in_array('features', $relations)) { + $features = []; + + foreach ($badge->getAllFeatures() as $feature) { + $features[] = $feature->getId(); + } + $values['features'] = $features; + } + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + + case 'ticket': { + if ($badge->hasTicket()) + { + unset($values['ticket_id']); + $values['ticket'] = SerializerRegistry::getInstance()->getSerializer($badge->getTicket())->serialize(AbstractSerializer::getExpandForPrefix('ticket', $expand)); + } + } + break; + case 'type': { + if ($badge->hasType()) + { + unset($values['type_id']); + $values['type'] = SerializerRegistry::getInstance()->getSerializer($badge->getType())->serialize(AbstractSerializer::getExpandForPrefix('type', $expand)); + } + } + break; + case 'features': { + if (in_array('features', $relations)) { + unset( $values['features']); + $features = []; + + foreach ($badge->getAllFeatures() as $feature) { + $features[] = SerializerRegistry::getInstance()->getSerializer($feature)->serialize(AbstractSerializer::getExpandForPrefix('features', $expand)); + } + $values['features'] = $features; + } + } + break; + + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitAttendeeCSVSerializer.php b/app/ModelSerializers/Summit/Registration/SummitAttendeeCSVSerializer.php new file mode 100644 index 00000000..d7d299bb --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitAttendeeCSVSerializer.php @@ -0,0 +1,32 @@ + 'member_id:json_int', + 'SummitId' => 'summit_id:json_int', + 'FirstName' => 'first_name:json_string', + 'Surname' => 'last_name:json_string', + 'Email' => 'email:json_string', + 'CompanyName' => 'company:json_string', + 'DisclaimerAcceptedDate' => 'disclaimer_accepted_date:datetime_epoch', + ]; + + +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitAttendeeSerializer.php b/app/ModelSerializers/Summit/Registration/SummitAttendeeSerializer.php similarity index 60% rename from app/ModelSerializers/Summit/SummitAttendeeSerializer.php rename to app/ModelSerializers/Summit/Registration/SummitAttendeeSerializer.php index 635c186a..27c03c4b 100644 --- a/app/ModelSerializers/Summit/SummitAttendeeSerializer.php +++ b/app/ModelSerializers/Summit/Registration/SummitAttendeeSerializer.php @@ -11,8 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -use libs\utils\JsonUtils; -use Illuminate\Support\Facades\Config; +use Libs\ModelSerializers\AbstractSerializer; use models\summit\SummitAttendee; /** * Class SummitAttendeeSerializer @@ -25,6 +24,18 @@ final class SummitAttendeeSerializer extends SilverStripeSerializer 'SummitHallCheckedInDate' => 'summit_hall_checked_in_date:datetime_epoch', 'SharedContactInfo' => 'shared_contact_info:json_boolean', 'MemberId' => 'member_id:json_int', + 'SummitId' => 'summit_id:json_int', + 'FirstName' => 'first_name:json_string', + 'Surname' => 'last_name:json_string', + 'Email' => 'email:json_string', + 'CompanyName' => 'company:json_string', + 'DisclaimerAcceptedDate' => 'disclaimer_accepted_date:datetime_epoch', + 'Status' => 'status:json_string' + ]; + + protected static $allowed_relations = [ + 'extra_questions', + 'tickets', ]; /** @@ -43,19 +54,32 @@ final class SummitAttendeeSerializer extends SilverStripeSerializer if(isset($params['serializer_type'])) $serializer_type = $params['serializer_type']; - $summit = $attendee->getSummit(); + + $attendee->updateStatus(); + $values = parent::serialize($expand, $fields, $relations, $params); $member = null; $speaker = null; - $tickets = []; - foreach($attendee->getTickets() as $t) - { - if(!$t->hasTicketType()) continue; - $tickets[] = intval($t->getTicketType()->getId()); + if (in_array('tickets', $relations)) { + $tickets = []; + foreach ($attendee->getTickets() as $t) { + if (!$t->hasTicketType()) continue; + if ($t->isCancelled()) continue; + $tickets[] = intval($t->getTicketType()->getId()); + } + $values['tickets'] = $tickets; + } + + if (in_array('extra_questions', $relations)) { + $extra_question_answers = []; + + foreach ($attendee->getExtraQuestionAnswers() as $answer) { + $extra_question_answers[] = $answer->getId(); + } + $values['extra_questions'] = $extra_question_answers; } - $values['tickets'] = $tickets; if($attendee->hasMember()) { @@ -72,20 +96,34 @@ final class SummitAttendeeSerializer extends SilverStripeSerializer foreach ($exp_expand as $relation) { switch (trim($relation)) { case 'tickets': { + if (!in_array('tickets', $relations)) break; unset($values['tickets']); $tickets = []; foreach($attendee->getTickets() as $t) { - $tickets[] = SerializerRegistry::getInstance()->getSerializer($t)->serialize($expand); + if (!$t->hasTicketType()) continue; + if ($t->isCancelled()) continue; + $tickets[] = SerializerRegistry::getInstance()->getSerializer($t)->serialize(AbstractSerializer::getExpandForPrefix('tickets', $expand)); } $values['tickets'] = $tickets; } break; + case 'extra_questions': { + if (!in_array('extra_questions', $relations)) break; + unset($values['extra_questions']); + $extra_question_answers = []; + foreach($attendee->getExtraQuestionAnswers() as $answer) + { + $extra_question_answers[] = SerializerRegistry::getInstance()->getSerializer($answer)->serialize(AbstractSerializer::getExpandForPrefix('extra_questions', $expand)); + } + $values['extra_questions'] = $extra_question_answers; + } + break; case 'speaker': { if (!is_null($speaker)) { unset($values['speaker_id']); - $values['speaker'] = SerializerRegistry::getInstance()->getSerializer($speaker)->serialize(); + $values['speaker'] = SerializerRegistry::getInstance()->getSerializer($speaker)->serialize(AbstractSerializer::getExpandForPrefix('speaker', $expand)); } } break; @@ -96,7 +134,7 @@ final class SummitAttendeeSerializer extends SilverStripeSerializer $values['member'] = SerializerRegistry::getInstance() ->getSerializer($attendee->getMember(), $serializer_type) ->serialize( - $expand, + AbstractSerializer::getExpandForPrefix('member', $expand), [], [], ['summit' => $attendee->getSummit()]); diff --git a/app/ModelSerializers/Summit/Registration/SummitAttendeeTicketCSVSerializer.php b/app/ModelSerializers/Summit/Registration/SummitAttendeeTicketCSVSerializer.php new file mode 100644 index 00000000..2ab6b791 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitAttendeeTicketCSVSerializer.php @@ -0,0 +1,86 @@ + 'number:json_string', + 'Status' => 'status:json_string', + 'OwnerId' => 'attendee_id:json_int', + 'OwnerFirstName' => 'attendee_first_name:json_string', + 'OwnerSurname' => 'attendee_last_name:json_string', + 'OwnerEmail' => 'attendee_email:json_string', + 'OwnerCompany' => 'owner_company:json_string', + 'ExternalOrderId' => 'attendee_company:json_string', + 'ExternalAttendeeId' => 'external_attendee_id:json_string', + 'BoughtDate' => 'bought_date:datetime_epoch', + 'TicketTypeId' => 'ticket_type_id:json_int', + 'TicketTypeName' => 'ticket_type_name:json_string', + 'OrderId' => 'order_id:json_int', + 'BadgeId' => 'badge_id:json_int', + 'PromoCodeId' => 'promo_code_id:json_int', + 'PromoCodeValue' => 'promo_code:json_string', + 'RawCost' => 'raw_cost:json_float', + 'FinalAmount' => 'final_amount:json_float', + 'Discount' => 'discount:json_float', + 'RefundedAmount' => 'refunded_amount:json_float', + 'Currency' => 'currency:json_string', + 'BadgeTypeId' => 'badge_type_id:json_int', + 'BadgeTypeName' => 'badge_type_name:json_string', + ]; + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = [], array $relations = [], array $params = []) + { + $ticket = $this->object; + if (!$ticket instanceof SummitAttendeeTicket) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + if (isset($params['features_types'])) { + $ticket_features = $ticket->getBadgeFeaturesNames(); + foreach ($params['features_types'] as $features_type) { + if (!$features_type instanceof SummitBadgeFeatureType) continue; + $values[$features_type->getName()] = in_array($features_type->getName(), $ticket_features) ? '1' : '0'; + } + } + + if (isset($params['ticket_questions'])) { + foreach ($params['ticket_questions'] as $question) { + if (!$question instanceof SummitOrderExtraQuestionType) continue; + $values[$question->getLabel()] = ''; + $ticket_owner = $ticket->getOwner(); + if (!is_null($ticket_owner)) { + $answers = $ticket_owner->getExtraQuestionAnswerByQuestion($question); + if(is_null($answers)) continue; + $values[$question->getLabel()] = $question->getNiceValue($answers->getValue()); + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitAttendeeTicketSerializer.php b/app/ModelSerializers/Summit/Registration/SummitAttendeeTicketSerializer.php similarity index 58% rename from app/ModelSerializers/Summit/SummitAttendeeTicketSerializer.php rename to app/ModelSerializers/Summit/Registration/SummitAttendeeTicketSerializer.php index dfbf6088..2c6719e3 100644 --- a/app/ModelSerializers/Summit/SummitAttendeeTicketSerializer.php +++ b/app/ModelSerializers/Summit/Registration/SummitAttendeeTicketSerializer.php @@ -11,22 +11,14 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use Libs\ModelSerializers\AbstractSerializer; use models\summit\SummitAttendeeTicket; /** * Class SummitAttendeeTicketSerializer * @package ModelSerializers */ -final class SummitAttendeeTicketSerializer extends SilverStripeSerializer -{ - protected static $array_mappings = [ - 'ExternalOrderId' => 'external_order_id:json_string', - 'ExternalAttendeeId' => 'external_attendee_id:json_string', - 'BoughtDate' => 'bought_date:datetime_epoch', - 'TicketTypeId' => 'ticket_type_id:json_int', - 'OwnerId' => 'owner_id:json_int', - ]; - - /** +class SummitAttendeeTicketSerializer extends BaseSummitAttendeeTicketSerializer +{ /** * @param null $expand * @param array $fields * @param array $relations @@ -38,27 +30,21 @@ final class SummitAttendeeTicketSerializer extends SilverStripeSerializer $ticket = $this->object; if (!$ticket instanceof SummitAttendeeTicket) return []; $values = parent::serialize($expand, $fields, $relations, $params); + if (!empty($expand)) { $exp_expand = explode(',', $expand); foreach ($exp_expand as $relation) { switch (trim($relation)) { - case 'ticket_type': { - if(!$ticket->hasTicketType()) continue; - unset($values['ticket_type_id']); - $values['ticket_type'] = SerializerRegistry::getInstance()->getSerializer($ticket->getTicketType())->serialize(); - } - break; - case 'owner_id': { - if(!$ticket->hasOwner()) continue; - unset($values['owner_id']); - $values['owner'] = SerializerRegistry::getInstance()->getSerializer($ticket->getOwner())->serialize(); + case 'order': { + if(!$ticket->hasOrder()) continue; + unset($values['order_id']); + $values['order'] = SerializerRegistry::getInstance()->getSerializer($ticket->getOrder())->serialize(AbstractSerializer::getExpandForPrefix('order', $expand)); } break; } } } - return $values; } } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitAttendeeTicketTaxSerializer.php b/app/ModelSerializers/Summit/Registration/SummitAttendeeTicketTaxSerializer.php new file mode 100644 index 00000000..625679d8 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitAttendeeTicketTaxSerializer.php @@ -0,0 +1,69 @@ + 'amount:json_float', + 'TaxId' => 'tax_id:json_int', + 'TicketId' => 'ticket_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()) + { + $tax_applied = $this->object; + if (!$tax_applied instanceof SummitAttendeeTicketTax) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + if (!count($relations)) $relations = $this->getAllowedRelations(); + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'tax': + { + if ($tax_applied->hasTax()) { + unset($values['tax_id']); + $values['tax'] = SerializerRegistry::getInstance()->getSerializer($tax_applied->getTax())->serialize($expand); + } + } + break; + case 'ticket': + { + if ($tax_applied->hasTicket()) { + unset($values['ticket_id']); + $values['ticket'] = SerializerRegistry::getInstance()->getSerializer($tax_applied->getTicket())->serialize($expand); + } + } + break; + } + + } + } + return $values; + } + +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitBadgeFeatureTypeSerializer.php b/app/ModelSerializers/Summit/Registration/SummitBadgeFeatureTypeSerializer.php new file mode 100644 index 00000000..f1290030 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitBadgeFeatureTypeSerializer.php @@ -0,0 +1,27 @@ + 'name:json_string', + 'Description' => 'description:json_string', + 'TemplateContent' => 'template_content:json_string', + 'SummitId' => 'summit_id:json_int', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitBadgeTypeSerializer.php b/app/ModelSerializers/Summit/Registration/SummitBadgeTypeSerializer.php new file mode 100644 index 00000000..2869f11f --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitBadgeTypeSerializer.php @@ -0,0 +1,95 @@ + 'name:json_string', + 'Description' => 'description:json_string', + 'TemplateContent' => 'template_content:json_string', + 'Default' => 'is_default:json_boolean', + 'SummitId' => 'summit_id:json_int', + ]; + + protected static $allowed_relations = [ + 'access_levels', + 'badge_features', + ]; + + /** + * @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() ) + { + $badge_type = $this->object; + if (!$badge_type instanceof SummitBadgeType) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if(!count($relations)) $relations = $this->getAllowedRelations(); + // access_levels + if(in_array('access_levels', $relations)) { + $access_levels = []; + foreach ($badge_type->getAccessLevels() as $access_level) { + $access_levels[] = $access_level->getId(); + } + $values['access_levels'] = $access_levels; + } + + // badge_features + if(in_array('badge_features', $relations)) { + $features = []; + foreach ($badge_type->getBadgeFeatures() as $feature) { + $features[] = $feature->getId(); + } + $values['badge_features'] = $features; + } + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'access_levels': { + unset($values['access_levels']); + $access_levels = []; + foreach ($badge_type->getAccessLevels() as $access_level) { + $access_levels[] = SerializerRegistry::getInstance()->getSerializer($access_level)->serialize(AbstractSerializer::getExpandForPrefix('access_levels', $expand)); + } + $values['access_levels'] = $access_levels; + } + break; + case 'badge_features': { + unset($values['badge_features']); + $badge_features = []; + foreach ($badge_type->getBadgeFeatures() as $feature) { + $badge_features[] = SerializerRegistry::getInstance()->getSerializer($feature)->serialize(AbstractSerializer::getExpandForPrefix('badge_features', $expand)); + } + $values['badge_features'] = $badge_features; + } + break; + } + + } + } + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitOrderAdminSerializer.php b/app/ModelSerializers/Summit/Registration/SummitOrderAdminSerializer.php new file mode 100644 index 00000000..4e6f4c82 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitOrderAdminSerializer.php @@ -0,0 +1,23 @@ + 'number:json_string', + 'Status' => 'status:json_string', + 'PaymentMethod' => 'payment_method:json_string', + 'OwnerFirstName' => 'owner_first_name:json_string', + 'OwnerSurname' => 'owner_last_name:json_string', + 'OwnerEmail' => 'owner_email:json_string', + 'OwnerCompany' => 'owner_company:json_string', + 'OwnerId' => 'owner_id:json_string', + 'SummitId' => 'summit_id:json_int', + ]; + + protected static $allowed_relations = [ + 'extra_questions', + 'tickets', + ]; + + /** + * @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()) + { + $order = $this->object; + if (!$order instanceof SummitOrder) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if (!count($relations)) $relations = $this->getAllowedRelations(); + + if (in_array('tickets', $relations)) { + $tickets = []; + + foreach ($order->getTickets() as $ticket) { + $tickets[] = $ticket->getId(); + } + $values['tickets'] = $tickets; + } + + if (in_array('extra_questions', $relations)) { + $extra_question_answers = []; + + foreach ($order->getExtraQuestionAnswers() as $answer) { + $extra_question_answers[] = $answer->getId(); + } + $values['extra_questions'] = $extra_question_answers; + } + + if (!empty($expand)) { + Log::debug(sprintf("SummitOrderBaseSerializer::serialize expand %s", $expand)); + + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'tickets': + { + if (!in_array('tickets', $relations)) break; + $tickets = []; + unset($values['tickets']); + foreach ($order->getTickets() as $ticket) { + $tickets[] = SerializerRegistry::getInstance()->getSerializer($ticket)->serialize(AbstractSerializer::getExpandForPrefix('tickets', $expand)); + } + $values['tickets'] = $tickets; + } + break; + case 'owner': + { + + if ($order->hasOwner()) { + unset($values['owner_id']); + $values['owner'] = SerializerRegistry::getInstance()->getSerializer($order->getOwner())->serialize(AbstractSerializer::getExpandForPrefix('owner', $expand)); + } + } + break; + + case 'owner_company': + { + + if ($order->hasCompany()) { + unset($values['owner_company_id']); + $values['owner_company'] = SerializerRegistry::getInstance()->getSerializer($order->getCompany())->serialize(AbstractSerializer::getExpandForPrefix('owner_company', $expand)); + } + } + break; + case 'extra_questions': + { + if (!in_array('extra_questions', $relations)) break; + $extra_question_answers = []; + unset($values['extra_questions']); + foreach ($order->getExtraQuestionAnswers() as $answer) { + $extra_question_answers[] = SerializerRegistry::getInstance()->getSerializer($answer)->serialize(AbstractSerializer::getExpandForPrefix('extra_questions', $expand)); + } + $values['extra_questions'] = $extra_question_answers; + } + break; + } + } + } + + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitOrderCheckoutSerializer.php b/app/ModelSerializers/Summit/Registration/SummitOrderCheckoutSerializer.php new file mode 100644 index 00000000..8200d301 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitOrderCheckoutSerializer.php @@ -0,0 +1,30 @@ + 'billing_address_1:json_string', + 'BillingAddress2' => 'billing_address_2:json_string', + 'BillingAddressZipCode' => 'billing_address_zip_code:json_string', + 'BillingAddressCity' => 'billing_address_city:json_string', + 'BillingAddressState' => 'billing_address_state:json_string', + 'BillingAddressCountryIsoCode' => 'billing_address_country_iso_code:json_string', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitOrderExtraQuestionAnswerSerializer.php b/app/ModelSerializers/Summit/Registration/SummitOrderExtraQuestionAnswerSerializer.php new file mode 100644 index 00000000..bb45c17c --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitOrderExtraQuestionAnswerSerializer.php @@ -0,0 +1,89 @@ + 'value:json_string', + 'OrderId' => 'order_id:json_int', + 'AttendeeId' => 'attendee_id:json_int', + 'QuestionId' => 'question_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()) + { + $answer = $this->object; + if (!$answer instanceof SummitOrderExtraQuestionAnswer) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + if (!count($relations)) $relations = $this->getAllowedRelations(); + + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + + case 'order': + { + + if ($answer->hasOrder()) { + unset($values['order_id']); + $values['order'] = SerializerRegistry::getInstance()->getSerializer($answer->getOrder())->serialize(AbstractSerializer::getExpandForPrefix('order', $expand)); + } + } + break; + + case 'attendee': + { + + if ($answer->hasAttendee()) { + unset($values['attendee_id']); + $values['attendee'] = SerializerRegistry::getInstance()->getSerializer($answer->getAttendee())->serialize(AbstractSerializer::getExpandForPrefix('attendee', $expand)); + } + } + break; + + case 'question': + { + + if ($answer->hasQuestion()) { + unset($values['question_id']); + $values['question'] = SerializerRegistry::getInstance()->getSerializer($answer->getQuestion())->serialize(AbstractSerializer::getExpandForPrefix('question', $expand)); + } + } + break; + + + } + } + } + + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitOrderExtraQuestionTypeSerializer.php b/app/ModelSerializers/Summit/Registration/SummitOrderExtraQuestionTypeSerializer.php new file mode 100644 index 00000000..521fbcde --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitOrderExtraQuestionTypeSerializer.php @@ -0,0 +1,82 @@ + 'name:json_string', + 'Type' => 'type:json_string', + 'Label' => 'label:json_string', + 'Usage' => 'usage:json_string', + 'Placeholder' => 'placeholder:json_string', + 'Printable' => 'printable:json_boolean', + 'Order' => 'order:json_int', + 'Mandatory' => 'mandatory:json_boolean', + 'SummitId' => 'summit_id:json_int', + ]; + + protected static $allowed_relations = [ + 'values', + ]; + + /** + * @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() ) + { + $question = $this->object; + if (!$question instanceof SummitOrderExtraQuestionType) return []; + if(!count($relations)) $relations = $this->getAllowedRelations(); + $values = parent::serialize($expand, $fields, $relations, $params); + + if(in_array('values', $relations) && $question->allowsValues()) { + $question_values = []; + foreach ($question->getValues() as $value) { + $question_values[] = $value->getId(); + } + $values['values'] = $question_values; + } + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'values': + { + if (!$question->allowsValues()) + break; + unset($values['values']); + $question_values = []; + foreach ($question->getValues() as $value) { + $question_values[] = SerializerRegistry::getInstance()->getSerializer($value)->serialize(); + } + $values['values'] = $question_values; + } + break; + + + } + } + } + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitOrderExtraQuestionValueSerializer.php b/app/ModelSerializers/Summit/Registration/SummitOrderExtraQuestionValueSerializer.php new file mode 100644 index 00000000..554d7b4f --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitOrderExtraQuestionValueSerializer.php @@ -0,0 +1,27 @@ + 'label:json_string', + 'Value' => 'value:json_string', + 'Order' => 'order:json_int', + 'QuestionId' => 'question_id:json_int', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitOrderReservationSerializer.php b/app/ModelSerializers/Summit/Registration/SummitOrderReservationSerializer.php new file mode 100644 index 00000000..77de0e1f --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitOrderReservationSerializer.php @@ -0,0 +1,32 @@ + 'raw_amount:json_float', + 'FinalAmount' => 'amount:json_float', + 'TaxesAmount' => 'taxes_amount:json_float', + 'DiscountAmount' => 'discount_amount:json_float', + 'PaymentGatewayClientToken' => 'payment_gateway_client_token:json_string', + 'PaymentGatewayCartId' => 'payment_gateway_cart_id:json_string', + 'Hash' => 'hash:json_string', + 'HashCreationDate' => 'hash_creation_date:datetime_epoch', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitRefundPolicyTypeSerializer.php b/app/ModelSerializers/Summit/Registration/SummitRefundPolicyTypeSerializer.php new file mode 100644 index 00000000..93d70ceb --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitRefundPolicyTypeSerializer.php @@ -0,0 +1,27 @@ + 'name:json_string', + 'UntilXDaysBeforeEventStarts' => 'until_x_days_before_event_starts:json_int', + 'RefundRate' => 'refund_rate:json_float', + 'SummitId' => 'summit_id:json_int', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitRegistrationInvitationCSVSerializer.php b/app/ModelSerializers/Summit/Registration/SummitRegistrationInvitationCSVSerializer.php new file mode 100644 index 00000000..574ff69a --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitRegistrationInvitationCSVSerializer.php @@ -0,0 +1,32 @@ + 'member_id:json_int', + 'OrderId' => 'order_id:json_int', + 'SummitId' => 'summit_id:json_int', + 'FirstName' => 'first_name:json_string', + 'LastName' => 'last_name:json_string', + 'Email' => 'email:json_string', + 'Accepted' => 'is_accepted:jon_boolean', + 'Sent' => 'is_sent:jon_boolean', + ]; + +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitRegistrationInvitationSerializer.php b/app/ModelSerializers/Summit/Registration/SummitRegistrationInvitationSerializer.php new file mode 100644 index 00000000..9533f753 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitRegistrationInvitationSerializer.php @@ -0,0 +1,31 @@ + 'email:json_string', + 'FirstName' => 'first_name:json_string', + 'LastName' => 'last_name:json_string', + 'SummitId' => 'summit_id:json_int', + 'Accepted' => 'is_accepted:json_boolean', + 'Sent' => 'is_sent:json_boolean', + 'AcceptedDate' => 'accepted_date:datetime_epoch', + ]; + +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitTaxTypeSerializer.php b/app/ModelSerializers/Summit/Registration/SummitTaxTypeSerializer.php new file mode 100644 index 00000000..520adef1 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitTaxTypeSerializer.php @@ -0,0 +1,73 @@ + 'name:json_string', + 'TaxId' => 'tax_id:json_string', + 'Rate' => 'rate:json_float', + 'SummitId' => 'summit_id:json_int', + ]; + + protected static $allowed_relations = [ + 'ticket_types', + ]; + + /** + * @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() ) + { + $tax = $this->object; + if (!$tax instanceof SummitTaxType) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + if(!count($relations)) $relations = $this->getAllowedRelations(); + // applied_taxes + if(in_array('ticket_types', $relations)) { + $ticket_types = []; + foreach ($tax->getTicketTypes() as $ticket_type) { + $ticket_types[] = $ticket_type->getId(); + } + $values['ticket_types'] = $ticket_types; + } + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'ticket_types': { + unset($values['ticket_types']); + $ticket_types = []; + foreach ($tax->getTicketTypes() as $ticket_type) { + $ticket_types[] = SerializerRegistry::getInstance()->getSerializer($ticket_type)->serialize($expand); + } + $values['ticket_types'] = $ticket_types; + } + break; + } + + } + } + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Registration/SummitTicketTypeSerializer.php b/app/ModelSerializers/Summit/Registration/SummitTicketTypeSerializer.php new file mode 100644 index 00000000..1ab6f0fc --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitTicketTypeSerializer.php @@ -0,0 +1,90 @@ + 'name:json_string', + 'Description' => 'description:json_string', + 'ExternalId' => 'external_id:json_string', + 'SummitId' => 'summit_id:json_int', + 'Cost' => 'cost:json_float', + 'Currency' => 'currency:json_string', + 'Quantity2Sell' => 'quantity_2_sell:json_int', + 'MaxQuantityPerOrder' => 'max_quantity_per_order:json_int', + 'SalesStartDate' => 'sales_start_date:datetime_epoch', + 'SalesEndDate' => 'sales_end_date:datetime_epoch', + 'BadgeTypeId' => 'badge_type_id:json_int', + 'QuantitySold' => 'quantity_sold:json_int', + ]; + + protected static $allowed_relations = [ + 'applied_taxes', + ]; + + /** + * @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() ) + { + $ticket_type = $this->object; + if (!$ticket_type instanceof SummitTicketType) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + // applied_taxes + if(in_array('applied_taxes', $relations)) { + $applied_taxes = []; + foreach ($ticket_type->getAppliedTaxes() as $tax) { + $applied_taxes[] = $tax->getId(); + } + $values['applied_taxes'] = $applied_taxes; + } + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'applied_taxes': { + unset($values['applied_taxes']); + $applied_taxes = []; + foreach ($ticket_type->getAppliedTaxes() as $tax) { + $applied_taxes[] = SerializerRegistry::getInstance()->getSerializer($tax)->serialize(AbstractSerializer::filterExpandByPrefix($expand, "applied_taxes")); + } + $values['applied_taxes'] = $applied_taxes; + } + break; + + case 'badge_type': { + if($ticket_type->hasBadgeType()) { + unset($values['badge_type_id']); + $values['badge_type'] = SerializerRegistry::getInstance()->getSerializer($ticket_type->getBadgeType())->serialize(AbstractSerializer::filterExpandByPrefix($expand, "badge_type")); + } + } + break; + } + + } + } + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/Speakers/PresentationSpeakerSerializer.php b/app/ModelSerializers/Summit/Speakers/PresentationSpeakerSerializer.php index e01be8aa..8bb8b555 100644 --- a/app/ModelSerializers/Summit/Speakers/PresentationSpeakerSerializer.php +++ b/app/ModelSerializers/Summit/Speakers/PresentationSpeakerSerializer.php @@ -37,7 +37,10 @@ class PresentationSpeakerSerializer extends SilverStripeSerializer 'Email' => 'email:json_obfuscated_email', 'MemberID' => 'member_id:json_int', 'RegistrationRequestId' => 'registration_request_id:json_int', - 'ProfilePhotoUrl' => 'pic:json_url' + 'ProfilePhotoUrl' => 'pic:json_url', + 'BigProfilePhotoUrl' => 'big_pic:json_url', + 'Company' => 'company:json_string', + 'PhoneNumber' => 'phone_number:json_string', ]; protected static $allowed_relations = [ diff --git a/app/ModelSerializers/Summit/SponsorSerializer.php b/app/ModelSerializers/Summit/SponsorSerializer.php new file mode 100644 index 00000000..32b6582d --- /dev/null +++ b/app/ModelSerializers/Summit/SponsorSerializer.php @@ -0,0 +1,108 @@ + 'order:json_int', + 'SummitId' => 'summit_id:json_int', + 'CompanyId' => 'company_id:json_int', + 'SponsorshipId' => 'sponsorship_id:json_int', + ]; + + protected static $allowed_relations = [ + 'members', + ]; + + /** + * @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() ) + { + $sponsor = $this->object; + if (!$sponsor instanceof Sponsor) return []; + if(!count($relations)) $relations = $this->getAllowedRelations(); + $values = parent::serialize($expand, $fields, $relations, $params); + + if(in_array('members', $relations)) { + $members = []; + foreach ($sponsor->getMembers() as $member) { + $members[] = $member->getId(); + } + $values['members'] = $members; + } + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'summit': + { + unset($values['summit_id']); + $values['summit'] = SerializerRegistry::getInstance()->getSerializer($sponsor->getSummit())->serialize(AbstractSerializer::filterExpandByPrefix($expand,'summit'),[ + 'id', + 'name', + 'start_date', + 'end_date', + 'time_zone_id', + 'order_qr_prefix', + 'ticket_qr_prefix', + 'badge_qr_prefix', + 'qr_registry_field_delimiter', + ],['none']); + } + break; + case 'members': + { + unset($values['members']); + $members = []; + foreach ($sponsor->getMembers() as $member) { + $members[] = SerializerRegistry::getInstance()->getSerializer($member)->serialize(AbstractSerializer::filterExpandByPrefix($expand,'members')); + } + $values['members'] = $members; + } + break; + case 'company': + { + if($sponsor->hasCompany()) { + unset($values['company_id']); + $values['company'] = SerializerRegistry::getInstance()->getSerializer($sponsor->getCompany())->serialize(AbstractSerializer::filterExpandByPrefix($expand,'company')); + } + } + break; + case 'sponsorship': + { + if($sponsor->hasSponsorship()) { + unset($values['sponsorship_id']); + $values['sponsorship'] = SerializerRegistry::getInstance()->getSerializer($sponsor->getSponsorship())->serialize(AbstractSerializer::filterExpandByPrefix($expand,'sponsorship')); + } + } + break; + + + } + } + } + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SponsorshipTypeSerializer.php b/app/ModelSerializers/Summit/SponsorshipTypeSerializer.php new file mode 100644 index 00000000..04591791 --- /dev/null +++ b/app/ModelSerializers/Summit/SponsorshipTypeSerializer.php @@ -0,0 +1,27 @@ + 'name:json_string', + 'Label' => 'label:json_string', + 'Order' => 'order:json_int', + 'Size' => 'size:json_string', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/StripePaymentProfileSerializer.php b/app/ModelSerializers/Summit/StripePaymentProfileSerializer.php new file mode 100644 index 00000000..f39c19f5 --- /dev/null +++ b/app/ModelSerializers/Summit/StripePaymentProfileSerializer.php @@ -0,0 +1,26 @@ + 'test_mode_enabled:json_boolean', + 'LivePublishableKey' => 'live_publishable_key:json_string', + 'TestPublishableKey' => 'test_publishable_key:json_string', + ]; +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitDocumentSerializer.php b/app/ModelSerializers/Summit/SummitDocumentSerializer.php new file mode 100644 index 00000000..bc719e5f --- /dev/null +++ b/app/ModelSerializers/Summit/SummitDocumentSerializer.php @@ -0,0 +1,75 @@ + 'name:json_string', + 'Description' => 'description:json_string', + 'Label' => 'label:json_string', + 'SummitId' => 'summit_id:json_int', + 'FileUrl' => 'file:json_url', + ]; + + /** + * @param null $expand + * @param array $fields + * @param array $relations + * @param array $params + * @return array + */ + public function serialize($expand = null, array $fields = [], array $relations = [], array $params = []) + { + $summit_document = $this->object; + if (!$summit_document instanceof SummitDocument) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + $event_types = []; + foreach ($summit_document->getEventTypes() as $event_type) { + $event_types[] = $event_type->getId(); + } + + $values['event_types'] = $event_types; + + if (!empty($expand)) { + $relations = explode(',', $expand); + foreach ($relations as $relation) { + $relation = trim($relation); + switch ($relation) { + case 'event_types':{ + $event_types = []; + foreach ($summit_document->getEventTypes() as $event_type) { + $event_types[] = SerializerRegistry::getInstance()->getSerializer($event_type)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + $values['event_types'] = $event_types; + } + break; + case 'summit':{ + unset($values['summit_id']); + $values['summit'] = SerializerRegistry::getInstance()->getSerializer($summit_document->getSummit())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + break; + } + } + } + + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitEmailEventFlowSerializer.php b/app/ModelSerializers/Summit/SummitEmailEventFlowSerializer.php new file mode 100644 index 00000000..41240dda --- /dev/null +++ b/app/ModelSerializers/Summit/SummitEmailEventFlowSerializer.php @@ -0,0 +1,29 @@ + 'summit_id:json_int', + 'EmailTemplateIdentifier' => 'email_template_identifier:json_string', + 'FlowName' => 'flow_name:json_string', + 'EventTypeName' => 'event_type_name:json_string', + ); +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitEventSerializer.php b/app/ModelSerializers/Summit/SummitEventSerializer.php index 33459366..ab6b9652 100644 --- a/app/ModelSerializers/Summit/SummitEventSerializer.php +++ b/app/ModelSerializers/Summit/SummitEventSerializer.php @@ -11,6 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric; use Libs\ModelSerializers\AbstractSerializer; use models\summit\SummitEvent; /** @@ -41,7 +43,12 @@ class SummitEventSerializer extends SilverStripeSerializer 'RSVPWaitCount' => 'rsvp_wait_count:json_int', 'ExternalRSVP' => 'rsvp_external:json_boolean', 'CategoryId' => 'track_id:json_int', - 'Occupancy' => 'occupancy:json_string' + 'StreamingUrl' => 'streaming_url:json_string', + 'EtherpadLink' => 'etherpad_link:json_string', + 'MeetingUrl' => 'meeting_url:json_string', + 'TotalAttendanceCount' => 'attendance_count:json_int', + 'CurrentAttendanceCount' => 'current_attendance_count:json_int', + 'ImageUrl' => 'image:json_url', ]; protected static $allowed_fields = [ @@ -65,15 +72,22 @@ class SummitEventSerializer extends SilverStripeSerializer 'rsvp_template_id', 'rsvp_max_user_number', 'rsvp_max_user_wait_list_number', - 'occupancy', 'rsvp_regular_count', 'rsvp_wait_count', + 'streaming_url', + 'etherpad_link', + 'meeting_url', + 'attendance_count', + 'current_attendance_count', + 'image', ]; protected static $allowed_relations = [ 'sponsors', 'tags', 'feedback', + 'attendance', + 'current_attendance', ]; /** @@ -113,6 +127,22 @@ class SummitEventSerializer extends SilverStripeSerializer $values['feedback'] = $feedback; } + if(in_array('current_attendance', $relations)){ + $attendance = []; + foreach ($event->getCurrentAttendance() as $a){ + $attendance[] = SerializerRegistry::getInstance()->getSerializer($a)->serialize(); + } + $values['current_attendance'] = $attendance; + } + + if(in_array('attendance', $relations)){ + $attendance = []; + foreach ($event->getAttendance() as $a){ + $attendance[] = SerializerRegistry::getInstance()->getSerializer($a)->serialize(); + } + $values['attendance'] = $attendance; + } + if (!empty($expand)) { foreach (explode(',', $expand) as $relation) { $relation = trim($relation); @@ -160,15 +190,6 @@ class SummitEventSerializer extends SilverStripeSerializer } } - if(in_array('metrics', $relations)){ - // show metrics snapshot - $metrics = []; - foreach($event->getMetricsSnapShots() as $snapshot){ - $metrics[] = SerializerRegistry::getInstance()->getSerializer($snapshot)->serialize(); - } - $values['metrics'] = $metrics; - } - return $values; } } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitEventTypeSerializer.php b/app/ModelSerializers/Summit/SummitEventTypeSerializer.php index 58e07798..acf5393a 100644 --- a/app/ModelSerializers/Summit/SummitEventTypeSerializer.php +++ b/app/ModelSerializers/Summit/SummitEventTypeSerializer.php @@ -1,4 +1,8 @@ 'are_sponsors_mandatory:json_boolean', 'AllowsAttachment' => 'allows_attachment:json_boolean', 'Default' => 'is_default:json_boolean', + 'SummitId' => 'summit_id:json_int', ]; /** @@ -38,6 +43,8 @@ class SummitEventTypeSerializer extends SilverStripeSerializer */ public function serialize($expand = null, array $fields = array(), array $relations = array(), array $params = array() ) { + $event_type = $this->object; + if (!$event_type instanceof SummitEventType) return []; $values = parent::serialize($expand, $fields, $relations, $params); $color = isset($values['color']) ? $values['color']:''; if(empty($color)) @@ -46,6 +53,35 @@ class SummitEventTypeSerializer extends SilverStripeSerializer $color = '#'.$color; } $values['color'] = $color; + + $summit_documents = []; + foreach ($event_type->getSummitDocuments() as $document) { + $summit_documents[] = $document->getId(); + } + + $values['summit_documents'] = $summit_documents; + + if (!empty($expand)) { + $relations = explode(',', $expand); + foreach ($relations as $relation) { + $relation = trim($relation); + switch ($relation) { + case 'summit_documents':{ + $summit_documents = []; + foreach ($event_type->getSummitDocuments() as $document) { + $summit_documents[] = SerializerRegistry::getInstance()->getSerializer($document)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + $values['summit_documents'] = $summit_documents; + } + break; + case 'summit':{ + unset($values['summit_id']); + $values['summit'] = SerializerRegistry::getInstance()->getSerializer($event_type->getSummit())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + break; + } + } + } return $values; } } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitTicketTypeSerializer.php b/app/ModelSerializers/Summit/SummitMediaFileTypeSerializer.php similarity index 59% rename from app/ModelSerializers/Summit/SummitTicketTypeSerializer.php rename to app/ModelSerializers/Summit/SummitMediaFileTypeSerializer.php index 6bf2b2a2..54c1c773 100644 --- a/app/ModelSerializers/Summit/SummitTicketTypeSerializer.php +++ b/app/ModelSerializers/Summit/SummitMediaFileTypeSerializer.php @@ -1,6 +1,6 @@ 'name:json_string', + 'Name' => 'name:json_string', 'Description' => 'description:json_string', - 'ExternalId' => 'external_id:json_string', - 'SummitId' => 'summit_id:json_int', + 'SystemDefined' => 'is_system_defined:json_boolean', ]; /** @@ -32,10 +31,13 @@ final class SummitTicketTypeSerializer extends SilverStripeSerializer * @param array $params * @return array */ - public function serialize($expand = null, array $fields = array(), array $relations = array(), array $params = array() ) + public function serialize($expand = null, array $fields = [], array $relations = [], array $params = []) { + $type = $this->object; + if (!$type instanceof SummitMediaFileType) return []; $values = parent::serialize($expand, $fields, $relations, $params); - $ticket_type = $this->object; + $allowed_extensions = $type->getAllowedExtensions(); + $values['allowed_extensions'] = !is_null($allowed_extensions) ? explode('|', $allowed_extensions): []; return $values; } } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitMediaUploadTypeSerializer.php b/app/ModelSerializers/Summit/SummitMediaUploadTypeSerializer.php new file mode 100644 index 00000000..47ec563d --- /dev/null +++ b/app/ModelSerializers/Summit/SummitMediaUploadTypeSerializer.php @@ -0,0 +1,85 @@ + 'name:json_string', + 'Description' => 'description:json_string', + 'MaxSize' => 'max_size:json_int', + 'Mandatory' => 'is_mandatory:json_boolean', + 'PrivateStorageType' => 'private_storage_type:json_string', + 'PublicStorageType' => 'public_storage_type:json_string', + 'SummitId' => 'summit_id:json_int', + 'TypeId' => 'type_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 $relations = [], array $params = []) + { + $type = $this->object; + if (!$type instanceof SummitMediaUploadType) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + + $presentation_types = []; + + foreach ($type->getPresentationTypes() as $presentation_type){ + $presentation_types[] = $presentation_type->getId(); + } + + $values['presentation_types'] = $presentation_types; + + if (!empty($expand)) { + foreach (explode(',', $expand) as $relation) { + $relation = trim($relation); + switch ($relation) { + case 'type': { + unset($values['type_id']); + $values['type'] = SerializerRegistry::getInstance()->getSerializer($type->getType())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + break; + case 'summit': { + unset($values['summit_id']); + $values['summit'] = SerializerRegistry::getInstance()->getSerializer($type->getSummit())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + break; + case 'presentation_types': { + unset($values['presentation_types']); + $presentation_types = []; + + foreach ($type->getPresentationTypes() as $presentation_type){ + $presentation_types[] = SerializerRegistry::getInstance()->getSerializer($presentation_type)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + + $values['presentation_types'] = $presentation_types; + } + break; + } + } + } + return $values; + } +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitSerializer.php b/app/ModelSerializers/Summit/SummitSerializer.php index 474871a6..23cb5b61 100644 --- a/app/ModelSerializers/Summit/SummitSerializer.php +++ b/app/ModelSerializers/Summit/SummitSerializer.php @@ -11,12 +11,15 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\Http\Exceptions\HTTP403ForbiddenException; use App\Security\SummitScopes; use Illuminate\Support\Facades\Config; use Libs\ModelSerializers\AbstractSerializer; +use models\summit\IPaymentConstants; use models\summit\Summit; use DateTime; + /** * Class SummitSerializer * @package ModelSerializers @@ -24,59 +27,79 @@ use DateTime; class SummitSerializer extends SilverStripeSerializer { protected static $array_mappings = [ - 'Name' => 'name:json_string', - 'BeginDate' => 'start_date:datetime_epoch', - 'EndDate' => 'end_date:datetime_epoch', - 'RegistrationBeginDate' => 'registration_begin_date:datetime_epoch', - 'RegistrationEndDate' => 'registration_end_date:datetime_epoch', - 'StartShowingVenuesDate' => 'start_showing_venues_date:datetime_epoch', - 'ScheduleDefaultStartDate' => 'schedule_start_date:datetime_epoch', - 'Active' => 'active:json_boolean', - 'TypeId' => 'type_id:json_int' , - 'DatesLabel' => 'dates_label:json_string' , - 'MaxSubmissionAllowedPerUser' => 'max_submission_allowed_per_user:json_int', + 'Name' => 'name:json_string', + 'BeginDate' => 'start_date:datetime_epoch', + 'EndDate' => 'end_date:datetime_epoch', + 'RegistrationBeginDate' => 'registration_begin_date:datetime_epoch', + 'RegistrationEndDate' => 'registration_end_date:datetime_epoch', + 'StartShowingVenuesDate' => 'start_showing_venues_date:datetime_epoch', + 'ScheduleDefaultStartDate' => 'schedule_start_date:datetime_epoch', + 'Active' => 'active:json_boolean', + 'TypeId' => 'type_id:json_int', + 'DatesLabel' => 'dates_label:json_string', + 'MaxSubmissionAllowedPerUser' => 'max_submission_allowed_per_user:json_int', // calculated attributes - 'PresentationVotesCount' => 'presentation_votes_count:json_int' , - 'PresentationVotersCount' => 'presentation_voters_count:json_int' , - 'AttendeesCount' => 'attendees_count:json_int', - 'SpeakersCount' => 'speakers_count:json_int', - 'PresentationsSubmittedCount' => 'presentations_submitted_count:json_int', - 'PublishedEventsCount' => 'published_events_count:json_int', - 'SpeakerAnnouncementEmailAcceptedCount' => 'speaker_announcement_email_accepted_count:json_int', - 'SpeakerAnnouncementEmailRejectedCount' => 'speaker_announcement_email_rejected_count:json_int', - 'SpeakerAnnouncementEmailAlternateCount' => 'speaker_announcement_email_alternate_count:json_int', + 'PresentationVotesCount' => 'presentation_votes_count:json_int', + 'PresentationVotersCount' => 'presentation_voters_count:json_int', + 'AttendeesCount' => 'attendees_count:json_int', + 'PaidTicketsCount' => 'paid_tickets_count:json_int', + 'SpeakersCount' => 'speakers_count:json_int', + 'PresentationsSubmittedCount' => 'presentations_submitted_count:json_int', + 'PublishedEventsCount' => 'published_events_count:json_int', + 'SpeakerAnnouncementEmailAcceptedCount' => 'speaker_announcement_email_accepted_count:json_int', + 'SpeakerAnnouncementEmailRejectedCount' => 'speaker_announcement_email_rejected_count:json_int', + 'SpeakerAnnouncementEmailAlternateCount' => 'speaker_announcement_email_alternate_count:json_int', 'SpeakerAnnouncementEmailAcceptedAlternateCount' => 'speaker_announcement_email_accepted_alternate_count:json_int', - 'SpeakerAnnouncementEmailAcceptedRejectedCount' => 'speaker_announcement_email_accepted_rejected_count:json_int', + 'SpeakerAnnouncementEmailAcceptedRejectedCount' => 'speaker_announcement_email_accepted_rejected_count:json_int', 'SpeakerAnnouncementEmailAlternateRejectedCount' => 'speaker_announcement_email_alternate_rejected_count:json_int', - 'TimeZoneId' => 'time_zone_id:json_string', - 'SecondaryRegistrationLink' => 'secondary_registration_link:json_string', - 'SecondaryRegistrationLabel' => 'secondary_registration_label:json_string', - 'RawSlug' => 'slug:json_string', + 'TimeZoneId' => 'time_zone_id:json_string', + 'SecondaryRegistrationLink' => 'secondary_registration_link:json_string', + 'SecondaryRegistrationLabel' => 'secondary_registration_label:json_string', + 'RawSlug' => 'slug:json_string', // Bookable rooms attributes - 'MeetingRoomBookingStartTime' => 'meeting_room_booking_start_time:datetime_epoch', - 'MeetingRoomBookingEndTime' => 'meeting_room_booking_end_time:datetime_epoch', - 'MeetingRoomBookingSlotLength' => 'meeting_room_booking_slot_length:json_int', - 'MeetingRoomBookingMaxAllowed' => 'meeting_room_booking_max_allowed:json_int', - 'BeginAllowBookingDate' => 'begin_allow_booking_date:datetime_epoch', - 'EndAllowBookingDate' => 'end_allow_booking_date:datetime_epoch', - 'LogoUrl' => 'logo:json_url', + 'MeetingRoomBookingStartTime' => 'meeting_room_booking_start_time:datetime_epoch', + 'MeetingRoomBookingEndTime' => 'meeting_room_booking_end_time:datetime_epoch', + 'MeetingRoomBookingSlotLength' => 'meeting_room_booking_slot_length:json_int', + 'MeetingRoomBookingMaxAllowed' => 'meeting_room_booking_max_allowed:json_int', + 'BeginAllowBookingDate' => 'begin_allow_booking_date:datetime_epoch', + 'EndAllowBookingDate' => 'end_allow_booking_date:datetime_epoch', + 'LogoUrl' => 'logo:json_url', + // External Feeds + 'ApiFeedType' => 'api_feed_type:json_string', + 'ApiFeedUrl' => 'api_feed_url:json_string', + 'ApiFeedKey' => 'api_feed_key:json_string', + // registration + 'OrderQRPrefix' => 'order_qr_prefix:json_string', + 'TicketQRPrefix' => 'ticket_qr_prefix:json_string', + 'BadgeQRPrefix' => 'badge_qr_prefix:json_string', + 'QRRegistryFieldDelimiter' => 'qr_registry_field_delimiter:json_string', + 'ReassignTicketTillDate' => 'reassign_ticket_till_date:datetime_epoch', + 'RegistrationDisclaimerContent' => 'registration_disclaimer_content:json_string', + 'RegistrationDisclaimerMandatory' => 'registration_disclaimer_mandatory:json_boolean', + 'RegistrationReminderEmailDaysInterval' => 'registration_reminder_email_days_interval:json_int', // schedule app - 'ScheduleDefaultPageUrl' => 'schedule_default_page_url:json_url', - 'ScheduleDefaultEventDetailUrl' => 'schedule_default_event_detail_url:json_url', - 'ScheduleOgSiteName' => 'schedule_og_site_name:json_string', - 'ScheduleOgImageUrl' => 'schedule_og_image_url:json_string', - 'ScheduleOgImageSecureUrl' => 'schedule_og_image_secure_url:json_string', - 'ScheduleOgImageWidth' => 'schedule_og_image_width:json_int', - 'ScheduleOgImageHeight' => 'schedule_og_image_height:json_int', - 'ScheduleFacebookAppId' => 'schedule_facebook_app_id:json_string', - 'ScheduleIosAppName' => 'schedule_ios_app_name:json_string', - 'ScheduleIosAppStoreId' => 'schedule_ios_app_store_id:json_string', - 'ScheduleIosAppCustomSchema' => 'schedule_ios_app_custom_schema:json_string', - 'ScheduleAndroidAppName' => 'schedule_android_app_name:json_string', - 'ScheduleAndroidAppPackage' => 'schedule_android_app_package:json_string', - 'ScheduleAndroidCustomSchema' => 'schedule_android_custom_schema:json_string', - 'ScheduleTwitterAppName' => 'schedule_twitter_app_name:json_string', - 'ScheduleTwitterText' => 'schedule_twitter_text:json_string', + 'ScheduleDefaultPageUrl' => 'schedule_default_page_url:json_url', + 'ScheduleDefaultEventDetailUrl' => 'schedule_default_event_detail_url:json_url', + 'ScheduleOgSiteName' => 'schedule_og_site_name:json_string', + 'ScheduleOgImageUrl' => 'schedule_og_image_url:json_string', + 'ScheduleOgImageSecureUrl' => 'schedule_og_image_secure_url:json_string', + 'ScheduleOgImageWidth' => 'schedule_og_image_width:json_int', + 'ScheduleOgImageHeight' => 'schedule_og_image_height:json_int', + 'ScheduleFacebookAppId' => 'schedule_facebook_app_id:json_string', + 'ScheduleIosAppName' => 'schedule_ios_app_name:json_string', + 'ScheduleIosAppStoreId' => 'schedule_ios_app_store_id:json_string', + 'ScheduleIosAppCustomSchema' => 'schedule_ios_app_custom_schema:json_string', + 'ScheduleAndroidAppName' => 'schedule_android_app_name:json_string', + 'ScheduleAndroidAppPackage' => 'schedule_android_app_package:json_string', + 'ScheduleAndroidCustomSchema' => 'schedule_android_custom_schema:json_string', + 'ScheduleTwitterAppName' => 'schedule_twitter_app_name:json_string', + 'ScheduleTwitterText' => 'schedule_twitter_text:json_string', + 'DefaultPageUrl' => 'default_page_url:json_string', + 'SpeakerConfirmationDefaultPageUrl' => 'speaker_confirmation_default_page_url:json_string', + 'InviteOnlyRegistration' => 'invite_only_registration:json_boolean', + 'VirtualSiteUrl' => 'virtual_site_url:json_string', + 'MarketingSiteUrl' => 'marketing_site_url:json_string', + 'SupportEmail' => 'support_email:json_string', ]; protected static $allowed_relations = [ @@ -85,6 +108,12 @@ class SummitSerializer extends SilverStripeSerializer 'wifi_connections', 'selection_plans', 'meeting_booking_room_allowed_attributes', + 'summit_sponsors', + 'order_extra_questions', + 'tax_types', + 'payment_profiles', + 'email_flows_events', + 'summit_documents', ]; /** @@ -97,33 +126,32 @@ class SummitSerializer extends SilverStripeSerializer */ public function serialize($expand = null, array $fields = [], array $relations = [], array $params = []) { - $summit = $this->object; - if(!$summit instanceof Summit) return []; - $values = parent::serialize($expand, $fields, $relations, $params); - if(!count($relations)) $relations = $this->getAllowedRelations(); + $summit = $this->object; + if (!$summit instanceof Summit) return []; + $values = parent::serialize($expand, $fields, $relations, $params); + if (!count($relations)) $relations = $this->getAllowedRelations(); - $timezone = $summit->getTimeZone(); + $timezone = $summit->getTimeZone(); $values['time_zone'] = null; if (!is_null($timezone)) { $time_zone_info = $timezone->getLocation(); - $time_zone_info['name'] = $timezone->getName(); - $now = new DateTime("now", $timezone); - $time_zone_info['offset'] = $timezone->getOffset($now); - $values['time_zone'] = $time_zone_info; + $time_zone_info['name'] = $timezone->getName(); + $time_zone_info['offset'] = $timezone->getOffset(new DateTime("now", $timezone)); + $values['time_zone'] = $time_zone_info; } // pages info - $main_page = $summit->getMainPage(); - $schedule_page = $summit->getSchedulePage(); - $values['page_url'] = - empty($main_page)? null : - sprintf("%s%s", Config::get("server.assets_base_url", 'https://www.openstack.org/'), $main_page); + $main_page = $summit->getMainPage(); + $schedule_page = $summit->getSchedulePage(); + $values['page_url'] = + empty($main_page) ? null : + sprintf("%s%s", Config::get("server.assets_base_url", 'https://www.openstack.org/'), $main_page); $values['schedule_page_url'] = empty($schedule_page) ? null : sprintf("%s%s", Config::get("server.assets_base_url", 'https://www.openstack.org/'), $schedule_page); - $values['schedule_event_detail_url'] = empty($schedule_page) ? null : sprintf("%s%s/%s", Config::get("server.assets_base_url", 'https://www.openstack.org/'), $schedule_page, 'events/:event_id/:event_title'); + $values['schedule_event_detail_url'] = empty($schedule_page) ? null : sprintf("%s%s/%s", Config::get("server.assets_base_url", 'https://www.openstack.org/'), $schedule_page, 'events/:event_id/:event_title'); // tickets - if(in_array('ticket_types', $relations)) { + if (in_array('ticket_types', $relations)) { $ticket_types = []; foreach ($summit->getTicketTypes() as $ticket) { $ticket_types[] = SerializerRegistry::getInstance()->getSerializer($ticket)->serialize(AbstractSerializer::filterExpandByPrefix($expand, 'ticket_types')); @@ -131,8 +159,88 @@ class SummitSerializer extends SilverStripeSerializer $values['ticket_types'] = $ticket_types; } + // payment_profiles + if (in_array('payment_profiles', $relations)) { + $payment_profiles = []; + foreach ($summit->getActivePaymentGateWayProfiles() as $profile) { + $payment_profiles[] = SerializerRegistry::getInstance()->getSerializer + ( + $profile, + $this->getSerializerType() + )->serialize(AbstractSerializer::filterExpandByPrefix($expand, 'payment_profiles')); + } + + $values['payment_profiles'] = $payment_profiles; + // if this serializer is public then we should show the default profiles + // if there is not set any + + $has_registration_profile = false; + $has_bookable_rooms_profile = false; + + foreach ($values['payment_profiles'] as $payment_profile) { + if ($payment_profile['application_type'] == IPaymentConstants::ApplicationTypeBookableRooms) { + $has_bookable_rooms_profile = true; + } + if ($payment_profile['application_type'] == IPaymentConstants::ApplicationTypeRegistration) { + $has_registration_profile = true; + } + } + + $build_default_payment_gateway_profile_strategy = $params['build_default_payment_gateway_profile_strategy'] ?? null; + + if (!$has_registration_profile && + !is_null($build_default_payment_gateway_profile_strategy) && + $this->getSerializerType() == SerializerRegistry::SerializerType_Public + ) { + + $values['payment_profiles'][] = + SerializerRegistry::getInstance()->getSerializer + ( + $build_default_payment_gateway_profile_strategy->build(IPaymentConstants::ApplicationTypeRegistration), + $this->getSerializerType() + )->serialize(AbstractSerializer::filterExpandByPrefix($expand, 'payment_profiles')); + + } + + if (!$has_bookable_rooms_profile && + !is_null($build_default_payment_gateway_profile_strategy) && + $this->getSerializerType() == SerializerRegistry::SerializerType_Public + ) { + $values['payment_profiles'][] = + SerializerRegistry::getInstance()->getSerializer + ( + $build_default_payment_gateway_profile_strategy->build(IPaymentConstants::ApplicationTypeBookableRooms), + $this->getSerializerType() + )->serialize(AbstractSerializer::filterExpandByPrefix($expand, 'payment_profiles')); + } + } + + if (in_array('order_extra_questions', $relations)) { + $order_extra_questions = []; + foreach ($summit->getOrderExtraQuestions() as $question) { + $order_extra_questions[] = SerializerRegistry::getInstance()->getSerializer($question)->serialize(AbstractSerializer::filterExpandByPrefix($expand, "order_extra_questions")); + } + $values['order_extra_questions'] = $order_extra_questions; + } + + if (in_array('tax_types', $relations)) { + $tax_types = []; + foreach ($summit->getTaxTypes() as $tax_type) { + $tax_types[] = SerializerRegistry::getInstance()->getSerializer($tax_type)->serialize(AbstractSerializer::filterExpandByPrefix($expand, "tax_types")); + } + $values['tax_types'] = $tax_types; + } + + if (in_array('summit_documents', $relations)) { + $summit_documents = []; + foreach ($summit->getSummitDocuments() as $document) { + $summit_documents[] = SerializerRegistry::getInstance()->getSerializer($document)->serialize(AbstractSerializer::filterExpandByPrefix($expand, "summit_documents")); + } + $values['summit_documents'] = $summit_documents; + } + // meeting_booking_room_allowed_attributes - if(in_array('meeting_booking_room_allowed_attributes', $relations)) { + if (in_array('meeting_booking_room_allowed_attributes', $relations)) { $meeting_booking_room_allowed_attributes = []; foreach ($summit->getMeetingBookingRoomAllowedAttributes() as $attr) { $meeting_booking_room_allowed_attributes[] = SerializerRegistry::getInstance()->getSerializer($attr)->serialize($expand); @@ -140,14 +248,23 @@ class SummitSerializer extends SilverStripeSerializer $values['meeting_booking_room_allowed_attributes'] = $meeting_booking_room_allowed_attributes; } + // summit sponsors + if (in_array('summit_sponsors', $relations)) { + $summit_sponsors = []; + foreach ($summit->getSummitSponsors() as $sponsor) { + $summit_sponsors[] = SerializerRegistry::getInstance()->getSerializer($sponsor)->serialize($expand); + } + $values['summit_sponsors'] = $summit_sponsors; + } + // locations - if(in_array('locations', $relations)) { + if (in_array('locations', $relations)) { $locations = []; foreach ($summit->getLocations() as $location) { $locations[] = SerializerRegistry::getInstance()->getSerializer($location)->serialize( - // is user is already expanding by schedule, its the total expand of the venues - str_contains('schedule', $expand)? - 'floors,rooms': + // is user is already expanding by schedule, its the total expand of the venues + !is_null($expand) && str_contains('schedule', $expand) ? + 'floors,rooms' : AbstractSerializer::filterExpandByPrefix($expand, 'locations') ); } @@ -155,7 +272,7 @@ class SummitSerializer extends SilverStripeSerializer } // wifi connections - if(in_array('wifi_connections', $relations)) { + if (in_array('wifi_connections', $relations)) { $wifi_connections = []; foreach ($summit->getWifiConnections() as $wifi_connection) { $wifi_connections[] = SerializerRegistry::getInstance()->getSerializer($wifi_connection)->serialize(AbstractSerializer::filterExpandByPrefix($expand, 'wifi_connections')); @@ -164,7 +281,7 @@ class SummitSerializer extends SilverStripeSerializer } // selection plans - if(in_array('selection_plans', $relations)) { + if (in_array('selection_plans', $relations)) { $selection_plans = []; foreach ($summit->getSelectionPlans() as $selection_plan) { $selection_plans[] = SerializerRegistry::getInstance()->getSerializer($selection_plan)->serialize(AbstractSerializer::filterExpandByPrefix($expand, 'selection_plans')); @@ -172,133 +289,157 @@ class SummitSerializer extends SilverStripeSerializer $values['selection_plans'] = $selection_plans; } + if (in_array('email_flows_events', $relations)) { + $email_flows_events = []; + foreach ($summit->getAllEmailFlowsEvents() as $email_flow_event) { + $email_flows_events[] = SerializerRegistry::getInstance()->getSerializer($email_flow_event)->serialize(AbstractSerializer::filterExpandByPrefix($expand, "email_flows_events")); + } + $values['email_flows_events'] = $email_flows_events; + } + if (!empty($expand)) { foreach (explode(',', $expand) as $relation) { $relation = trim($relation); switch ($relation) { - case 'event_types':{ - $event_types = []; - foreach ($summit->getEventTypes() as $event_type) { - $event_types[] = SerializerRegistry::getInstance()->getSerializer($event_type)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); - } - $values['event_types'] = $event_types; - } - break; - case 'tracks':{ - $presentation_categories = []; - foreach ($summit->getPresentationCategories() as $cat) { - $presentation_categories[] = SerializerRegistry::getInstance()->getSerializer($cat)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); - } - $values['tracks'] = $presentation_categories; - } - break; - case 'track_groups':{ - // track_groups - $track_groups = []; - foreach ($summit->getCategoryGroups() as $group) { - $track_groups[] = SerializerRegistry::getInstance()->getSerializer($group)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); - } - $values['track_groups'] = $track_groups; - } - break; - case 'sponsors':{ - $sponsors = []; - foreach ($summit->getSponsors() as $company) { - $sponsors[] = SerializerRegistry::getInstance()->getSerializer($company)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); - } - $values['sponsors'] = $sponsors; - } - break; - case 'speakers':{ - $speakers = []; - foreach ($summit->getSpeakers() as $speaker) { - $speakers[] = - SerializerRegistry::getInstance()->getSerializer($speaker)->serialize - ( - AbstractSerializer::filterExpandByPrefix($expand, $relation), [], [], - [ - 'summit_id' => $summit->getId(), - 'published' => true - ] - ); - - } - $values['speakers'] = $speakers; - } - break; - case 'schedule': { - // only could get schedule expanded if summit its available to public or - // we had proper scopes - if(!$summit->isAvailableOnApi()) { - $scopes = $this->resource_server_context->getCurrentScope(); - $current_realm = Config::get('app.url'); - $needed_scope = sprintf(SummitScopes::ReadAllSummitData, $current_realm); - if (!in_array($needed_scope, $scopes)) - throw new HTTP403ForbiddenException; - } - - $event_types = []; - foreach ($summit->getEventTypes() as $event_type) { - $event_types[] = SerializerRegistry::getInstance()->getSerializer($event_type)->serialize(); - } - $values['event_types'] = $event_types; - - $presentation_categories = []; - foreach ($summit->getPresentationCategories() as $cat) { - $presentation_categories[] = SerializerRegistry::getInstance()->getSerializer($cat)->serialize(); - } - $values['tracks'] = $presentation_categories; - - // track_groups - $track_groups = []; - foreach ($summit->getCategoryGroups() as $group) { - $track_groups[] = SerializerRegistry::getInstance()->getSerializer($group)->serialize(); - } - $values['track_groups'] = $track_groups; - - $schedule = []; - foreach ($summit->getScheduleEvents() as $event) { - $schedule[] = SerializerRegistry::getInstance()->getSerializer($event)->serialize(); - } - $values['schedule'] = $schedule; - - $sponsors = []; - foreach ($summit->getSponsors() as $company) { - $sponsors[] = SerializerRegistry::getInstance()->getSerializer($company)->serialize(); - } - $values['sponsors'] = $sponsors; - - $speakers = []; - foreach ($summit->getSpeakers() as $speaker) { - $speakers[] = - SerializerRegistry::getInstance()->getSerializer($speaker)->serialize - ( - null, [], [], - [ - 'summit_id' => $summit->getId(), - 'published' => true - ] - ); - - } - $values['speakers'] = $speakers; - } - break; - case 'type':{ - if(isset($values['type_id'])) + case 'event_types': { - unset($values['type_id']); - $values['type'] = $summit->hasType() ? - SerializerRegistry::getInstance()->getSerializer($summit->getType())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)) : null; + $event_types = []; + foreach ($summit->getEventTypes() as $event_type) { + $event_types[] = SerializerRegistry::getInstance()->getSerializer($event_type)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + $values['event_types'] = $event_types; } - } - break; + break; + case 'tracks': + { + $presentation_categories = []; + foreach ($summit->getPresentationCategories() as $cat) { + $presentation_categories[] = SerializerRegistry::getInstance()->getSerializer($cat)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + $values['tracks'] = $presentation_categories; + } + break; + case 'track_groups': + { + // track_groups + $track_groups = []; + foreach ($summit->getCategoryGroups() as $group) { + $track_groups[] = SerializerRegistry::getInstance()->getSerializer($group)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + $values['track_groups'] = $track_groups; + } + break; + case 'sponsors': + { + $sponsors = []; + foreach ($summit->getSponsors() as $company) { + $sponsors[] = SerializerRegistry::getInstance()->getSerializer($company)->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); + } + $values['sponsors'] = $sponsors; + } + break; + case 'speakers': + { + $speakers = []; + foreach ($summit->getSpeakers() as $speaker) { + $speakers[] = + SerializerRegistry::getInstance()->getSerializer($speaker)->serialize + ( + AbstractSerializer::filterExpandByPrefix($expand, $relation), [], [], + [ + 'summit_id' => $summit->getId(), + 'published' => true + ] + ); + + } + $values['speakers'] = $speakers; + } + break; + case 'schedule': + { + // only could get schedule expanded if summit its available to public or + // we had proper scopes + if (!$summit->isAvailableOnApi()) { + $scopes = $this->resource_server_context->getCurrentScope(); + $current_realm = Config::get('app.url'); + $needed_scope = sprintf(SummitScopes::ReadAllSummitData, $current_realm); + if (!in_array($needed_scope, $scopes)) + throw new HTTP403ForbiddenException; + } + + $event_types = []; + foreach ($summit->getEventTypes() as $event_type) { + $event_types[] = SerializerRegistry::getInstance()->getSerializer($event_type)->serialize(); + } + $values['event_types'] = $event_types; + + $presentation_categories = []; + foreach ($summit->getPresentationCategories() as $cat) { + $presentation_categories[] = SerializerRegistry::getInstance()->getSerializer($cat)->serialize(); + } + $values['tracks'] = $presentation_categories; + + // track_groups + $track_groups = []; + foreach ($summit->getCategoryGroups() as $group) { + $track_groups[] = SerializerRegistry::getInstance()->getSerializer($group)->serialize(); + } + $values['track_groups'] = $track_groups; + + $schedule = []; + foreach ($summit->getScheduleEvents() as $event) { + $schedule[] = SerializerRegistry::getInstance()->getSerializer($event)->serialize(); + } + $values['schedule'] = $schedule; + + $sponsors = []; + foreach ($summit->getEventSponsors() as $company) { + $sponsors[] = SerializerRegistry::getInstance()->getSerializer($company)->serialize(); + } + $values['sponsors'] = $sponsors; + + $speakers = []; + foreach ($summit->getSpeakers() as $speaker) { + $speakers[] = + SerializerRegistry::getInstance()->getSerializer($speaker)->serialize + ( + null, [], [], + [ + 'summit_id' => $summit->getId(), + 'published' => true + ] + ); + + } + $values['speakers'] = $speakers; + } + break; + case 'type': + { + if (isset($values['type_id'])) { + unset($values['type_id']); + $values['type'] = $summit->hasType() ? + SerializerRegistry::getInstance()->getSerializer($summit->getType())->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)) : null; + } + } + break; } } } + $values['supported_currencies'] = $summit->getSupportedCurrencies(); $values['timestamp'] = time(); + return $values; } + + /** + * @return string + */ + protected function getSerializerType(): string + { + return SerializerRegistry::SerializerType_Public; + } } \ No newline at end of file diff --git a/app/ModelSerializers/Summit/TrackTagGroups/TrackTagGroupAllowedTagSerializer.php b/app/ModelSerializers/Summit/TrackTagGroups/TrackTagGroupAllowedTagSerializer.php index bacfc9ff..3835ae03 100644 --- a/app/ModelSerializers/Summit/TrackTagGroups/TrackTagGroupAllowedTagSerializer.php +++ b/app/ModelSerializers/Summit/TrackTagGroups/TrackTagGroupAllowedTagSerializer.php @@ -40,7 +40,6 @@ final class TrackTagGroupAllowedTagSerializer extends AbstractSerializer if (!$allowed_tag instanceof TrackTagGroupAllowedTag) return []; $values = parent::serialize($expand, $fields, $relations, $params); - if (!empty($expand)) { $relations = explode(',', $expand); foreach ($relations as $relation) { @@ -48,16 +47,18 @@ final class TrackTagGroupAllowedTagSerializer extends AbstractSerializer case 'track_tag_group':{ unset($values['track_tag_group_id']); - $values['track_tag_group'] = SerializerRegistry::getInstance()->getSerializer($allowed_tag->getTrackTagGroup())->serialize(); + $values['track_tag_group'] = SerializerRegistry::getInstance() + ->getSerializer($allowed_tag->getTrackTagGroup()) + ->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); } - break; - + break; case 'tag':{ unset($values['tag_id']); - $values['tag'] = SerializerRegistry::getInstance()->getSerializer($allowed_tag->getTag())->serialize(); + $values['tag'] = SerializerRegistry::getInstance() + ->getSerializer($allowed_tag->getTag()) + ->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation)); } - break; - + break; } } } diff --git a/app/ModelSerializers/Summit/TrackTagGroups/TrackTagGroupSerializer.php b/app/ModelSerializers/Summit/TrackTagGroups/TrackTagGroupSerializer.php index da8c7e41..1becc91d 100644 --- a/app/ModelSerializers/Summit/TrackTagGroups/TrackTagGroupSerializer.php +++ b/app/ModelSerializers/Summit/TrackTagGroups/TrackTagGroupSerializer.php @@ -12,6 +12,7 @@ * limitations under the License. **/ use App\Models\Foundation\Summit\TrackTagGroup; +use Libs\ModelSerializers\AbstractSerializer; use ModelSerializers\SerializerRegistry; use ModelSerializers\SilverStripeSerializer; @@ -22,11 +23,11 @@ use ModelSerializers\SilverStripeSerializer; final class TrackTagGroupSerializer extends SilverStripeSerializer { protected static $array_mappings = [ - 'Name' => 'name:json_string', - 'Label' => 'label:json_string', - 'Order' => 'order:json_int', - 'Mandatory' => 'is_mandatory:json_boolean', - 'SummitId' => 'summit_id:json_int', + 'Name' => 'name:json_string', + 'Label' => 'label:json_string', + 'Order' => 'order:json_int', + 'Mandatory' => 'is_mandatory:json_boolean', + 'SummitId' => 'summit_id:json_int', ]; /** @@ -58,7 +59,9 @@ final class TrackTagGroupSerializer extends SilverStripeSerializer unset($values['allowed_tags']); $allowed_tags = []; foreach($track_tag_group->getAllowedTags() as $allowed_tag){ - $allowed_tags[] = SerializerRegistry::getInstance()->getSerializer($allowed_tag)->serialize($expand); + $allowed_tags[] = SerializerRegistry::getInstance() + ->getSerializer($allowed_tag) + ->serialize(AbstractSerializer::filterExpandByPrefix($expand, $relation));; } $values['allowed_tags'] = $allowed_tags; } diff --git a/app/ModelSerializers/SummitAdministratorPermissionGroupSerializer.php b/app/ModelSerializers/SummitAdministratorPermissionGroupSerializer.php new file mode 100644 index 00000000..7fbd57b4 --- /dev/null +++ b/app/ModelSerializers/SummitAdministratorPermissionGroupSerializer.php @@ -0,0 +1,93 @@ + 'title:json_string', + ]; + + protected static $allowed_relations = [ + 'members', + 'summits', + ]; + + /** + * @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 SummitAdministratorPermissionGroup) return []; + + if(!count($relations)) $relations = $this->getAllowedRelations(); + + $values = parent::serialize($expand, $fields, $relations, $params); + + if(in_array('members', $relations)) { + $members = []; + foreach ($group->getMembersIds() as $member_id) + $members[] = intval($member_id) ; + $values['members'] = $members; + } + + if(in_array('summits', $relations)) { + $summits = []; + foreach ($group->getSummitsIds() as $summit_id){ + $summits[] = intval($summit_id); + } + $values['summits'] = $summits; + } + + if (!empty($expand)) { + $exp_expand = explode(',', $expand); + foreach ($exp_expand as $relation) { + switch (trim($relation)) { + case 'members': { + if(!in_array('members', $relations)) break; + $members = []; + unset($values['members']); + foreach ($group->getMembers() as $m) { + $members[] = SerializerRegistry::getInstance()->getSerializer($m)->serialize(AbstractSerializer::filterExpandByPrefix($expand,'members')); + } + $values['members'] = $members; + } + break; + case 'summits': { + if(!in_array('summits', $relations)) break; + $summits = []; + unset($values['summits']); + foreach ($group->getSummits() as $s) { + $summits[] = SerializerRegistry::getInstance()->getSerializer($s)->serialize(AbstractSerializer::filterExpandByPrefix($expand,'summits')); + } + $values['summits'] = $summits; + } + break; + } + } + } + return $values; + } + +} \ No newline at end of file diff --git a/app/ModelSerializers/Summit/SummitEventMetricsSnapshotSerializer.php b/app/ModelSerializers/SummitEventAttendanceMetricSerializer.php similarity index 58% rename from app/ModelSerializers/Summit/SummitEventMetricsSnapshotSerializer.php rename to app/ModelSerializers/SummitEventAttendanceMetricSerializer.php index b5d53030..657a57a7 100644 --- a/app/ModelSerializers/Summit/SummitEventMetricsSnapshotSerializer.php +++ b/app/ModelSerializers/SummitEventAttendanceMetricSerializer.php @@ -1,6 +1,6 @@ 'avg:json_float', - 'Max' => 'max:json_float', - 'Min' => 'min:json_float', - 'Current' => 'current:json_float', - 'TypeName' => 'type:json_string', - 'EventId' => 'event_id:json_int', - ); - + protected static $array_mappings = [ + 'MemberFirstName' => 'member_first_name:json_string', + 'MemberLastName' => 'member_last_name:json_string', + 'MemberProfilePhotoUrl' => 'member_pic:json_url', + ]; } \ No newline at end of file diff --git a/app/Models/Exceptions/ValidationException.php b/app/Models/Exceptions/ValidationException.php index 879c3368..1c7c5da6 100644 --- a/app/Models/Exceptions/ValidationException.php +++ b/app/Models/Exceptions/ValidationException.php @@ -20,24 +20,41 @@ use Exception; */ class ValidationException extends Exception { + /** + * @var array + */ private $messages; + /** + * ValidationException constructor. + * @param string $message + * @param int $code + * @param Exception|null $previous + */ public function __construct($message = '', $code = 0, Exception $previous = null) { parent::__construct($message, $code, $previous); + if(!is_array($message)){ + $message = [$message]; + } + $this->messages = $message; } - public function setMessages($messages) + /** + * @param array $messages + * @return $this + */ + public function setMessages(array $messages) { $this->messages = $messages; return $this; } - public function getMessages() + public function getMessages():array { if(is_null($this->messages)) { - $this->messages = array($this->getMessage()); + $this->messages = [$this->getMessage()]; } return $this->messages; } diff --git a/app/Models/Foundation/Main/Company.php b/app/Models/Foundation/Main/Company.php index a02ead8f..d7e98221 100644 --- a/app/Models/Foundation/Main/Company.php +++ b/app/Models/Foundation/Main/Company.php @@ -11,9 +11,11 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\ORM\Mapping AS ORM; use models\utils\SilverstripeBaseModel; +use Doctrine\ORM\Mapping AS ORM; + /** * @ORM\Entity(repositoryClass="repositories\main\DoctrineCompanyRepository") * @ORM\Table(name="Company") @@ -28,11 +30,58 @@ class Company extends SilverstripeBaseModel */ private $name; + /** + * @ORM\Column(name="Description", type="string") + */ + private $description; + + /** + * @ORM\Column(name="Industry", type="string") + */ + private $industry; + + /** + * @ORM\Column(name="City", type="string") + */ + private $city; + + /** + * @ORM\Column(name="State", type="string") + */ + private $state; + + /** + * @ORM\Column(name="Country", type="string") + */ + private $country; + + /** + * @ORM\Column(name="URL", type="string") + */ + private $url; + /** * @ORM\ManyToMany(targetEntity="models\summit\SummitEvent", mappedBy="sponsors") */ private $sponsorships; + /** + * @ORM\ManyToOne(targetEntity="models\main\File") + * @ORM\JoinColumn(name="LogoID", referencedColumnName="ID") + * @var File + */ + private $logo; + + /** + * @ORM\ManyToOne(targetEntity="models\main\File") + * @ORM\JoinColumn(name="BigLogoID", referencedColumnName="ID") + * @var File + */ + private $big_logo; + + /** + * Company constructor. + */ public function __construct() { parent::__construct(); @@ -40,19 +89,212 @@ class Company extends SilverstripeBaseModel } /** - * @return mixed + * @return string|null */ - public function getName() + public function getName(): ?string { return $this->name; } /** - * @param mixed $name + * @param string $name */ - public function setName($name) + public function setName(string $name) { $this->name = $name; } + /** + * @return mixed + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param string $description + */ + public function setDescription($description): void + { + $this->description = $description; + } + + /** + * @return string|null + */ + public function getIndustry(): ?string + { + return $this->industry; + } + + /** + * @param string $industry + */ + public function setIndustry(string $industry): void + { + $this->industry = $industry; + } + + /** + * @return string|null + */ + public function getCity(): ?string + { + return $this->city; + } + + /** + * @param string $city + */ + public function setCity(string $city): void + { + $this->city = $city; + } + + /** + * @return string|null + */ + public function getState(): ?string + { + return $this->state; + } + + /** + * @param string $state + */ + public function setState(string $state): void + { + $this->state = $state; + } + + /** + * @return string|null + */ + public function getCountry(): ?string + { + return $this->country; + } + + /** + * @param string $country + */ + public function setCountry(string $country): void + { + $this->country = $country; + } + + /** + * @return string|null + */ + public function getUrl(): ?string + { + return $this->url; + } + + /** + * @param string $url + */ + public function setUrl(string $url): void + { + $this->url = $url; + } + + /** + * @return File + */ + public function getLogo(): File + { + return $this->logo; + } + + /** + * @param File $logo + */ + public function setLogo(File $logo): void + { + $this->logo = $logo; + } + + /** + * @return File + */ + public function getBigLogo(): File + { + return $this->big_logo; + } + + /** + * @param File $big_logo + */ + public function setBigLogo(File $big_logo): void + { + $this->big_logo = $big_logo; + } + + /** + * @return bool + */ + public function hasLogo() + { + return $this->getLogoId() > 0; + } + + /** + * @return int + */ + public function getLogoId() + { + try { + if (is_null($this->logo)) return 0; + return $this->logo->getId(); + } catch (\Exception $ex) { + return 0; + } + } + + /** + * @return bool + */ + public function hasBigLogo() + { + return $this->getBigLogoId() > 0; + } + + /** + * @return int + */ + public function getBigLogoId() + { + try { + if (is_null($this->big_logo)) return 0; + return $this->big_logo->getId(); + } catch (\Exception $ex) { + return 0; + } + } + + /** + * @return string|null + */ + public function getLogoUrl(): ?string + { + $logoUrl = null; + if ($this->hasLogo() && $logo = $this->getLogo()) { + $logoUrl = $logo->getUrl(); + } + return $logoUrl; + } + + /** + * @return string|null + */ + public function getBigLogoUrl(): ?string + { + $logoUrl = null; + if ($this->hasBigLogo() && $logo = $this->getBigLogo()) { + $logoUrl = $logo->getUrl(); + } + return $logoUrl; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Main/EmailCreationRequests/CalendarSyncErrorEmailRequest.php b/app/Models/Foundation/Main/EmailCreationRequests/CalendarSyncErrorEmailRequest.php deleted file mode 100644 index 6c82a3f7..00000000 --- a/app/Models/Foundation/Main/EmailCreationRequests/CalendarSyncErrorEmailRequest.php +++ /dev/null @@ -1,46 +0,0 @@ -sync_info; - } - - /** - * @param CalendarSyncInfo $sync_info - */ - public function setSyncInfo($sync_info) - { - $this->sync_info = $sync_info; - } -} \ No newline at end of file diff --git a/app/Models/Foundation/Main/EmailCreationRequests/EmailCreationRequest.php b/app/Models/Foundation/Main/EmailCreationRequests/EmailCreationRequest.php deleted file mode 100644 index bf65e32b..00000000 --- a/app/Models/Foundation/Main/EmailCreationRequests/EmailCreationRequest.php +++ /dev/null @@ -1,106 +0,0 @@ -template_name; - } - - /** - * @param string $template_name - */ - public function setTemplateName($template_name) - { - $this->template_name = $template_name; - } - - /** - * @return bool - */ - public function isProcessed() - { - return $this->processed; - } - - /** - * @param bool $processed - */ - public function setProcessed($processed) - { - $this->processed = $processed; - } - - /** - * @return DateTime - */ - public function getProcessedDate() - { - return $this->processed_date; - } - - /** - * @param DateTime $processed_date - */ - public function setProcessedDate($processed_date) - { - $this->processed_date = $processed_date; - } - - public function __construct() - { - $this->processed = false; - parent::__construct(); - } -} \ No newline at end of file diff --git a/app/Models/Foundation/Main/EmailCreationRequests/MemberPromoCodeEmailCreationRequest.php b/app/Models/Foundation/Main/EmailCreationRequests/MemberPromoCodeEmailCreationRequest.php deleted file mode 100644 index a55e1b11..00000000 --- a/app/Models/Foundation/Main/EmailCreationRequests/MemberPromoCodeEmailCreationRequest.php +++ /dev/null @@ -1,99 +0,0 @@ -template_name = "member-promo-code"; - parent::__construct(); - } - - /** - * @return SummitRegistrationPromoCode - */ - public function getPromoCode() - { - return $this->promo_code; - } - - /** - * @param SummitRegistrationPromoCode $promo_code - */ - public function setPromoCode($promo_code) - { - $this->promo_code = $promo_code; - } - - /** - * @return string - */ - public function getEmail() - { - return $this->email; - } - - /** - * @param string $email - */ - public function setEmail($email) - { - $this->email = $email; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @param string $name - */ - public function setName($name) - { - $this->name = $name; - } -} \ No newline at end of file diff --git a/app/Models/Foundation/Main/EmailCreationRequests/PresentationCreatorNotificationEmailRequest.php b/app/Models/Foundation/Main/EmailCreationRequests/PresentationCreatorNotificationEmailRequest.php deleted file mode 100644 index 29109a12..00000000 --- a/app/Models/Foundation/Main/EmailCreationRequests/PresentationCreatorNotificationEmailRequest.php +++ /dev/null @@ -1,52 +0,0 @@ -template_name = "presentation-creator-notification"; - parent::__construct(); - } - - /** - * @return Presentation - */ - public function getPresentation(): Presentation - { - return $this->presentation; - } - - /** - * @param Presentation $presentation - */ - public function setPresentation(Presentation $presentation): void - { - $this->presentation = $presentation; - } -} \ No newline at end of file diff --git a/app/Models/Foundation/Main/EmailCreationRequests/PresentationSpeakerNotificationEmailRequest.php b/app/Models/Foundation/Main/EmailCreationRequests/PresentationSpeakerNotificationEmailRequest.php deleted file mode 100644 index 8dd340ee..00000000 --- a/app/Models/Foundation/Main/EmailCreationRequests/PresentationSpeakerNotificationEmailRequest.php +++ /dev/null @@ -1,77 +0,0 @@ -template_name = "presentation-speaker-notification"; - parent::__construct(); - } - - /** - * @return PresentationSpeaker - */ - public function getSpeaker() - { - return $this->speaker; - } - - /** - * @param PresentationSpeaker $speaker - */ - public function setSpeaker($speaker) - { - $this->speaker = $speaker; - } - - /** - * @return Presentation - */ - public function getPresentation(): Presentation - { - return $this->presentation; - } - - /** - * @param Presentation $presentation - */ - public function setPresentation(Presentation $presentation): void - { - $this->presentation = $presentation; - } - -} \ No newline at end of file diff --git a/app/Models/Foundation/Main/EmailCreationRequests/SpeakerCreationEmailCreationRequest.php b/app/Models/Foundation/Main/EmailCreationRequests/SpeakerCreationEmailCreationRequest.php deleted file mode 100644 index b64d46aa..00000000 --- a/app/Models/Foundation/Main/EmailCreationRequests/SpeakerCreationEmailCreationRequest.php +++ /dev/null @@ -1,52 +0,0 @@ -template_name = "presentation-speaker-creation"; - parent::__construct(); - } - - /** - * @return PresentationSpeaker - */ - public function getSpeaker() - { - return $this->speaker; - } - - /** - * @param PresentationSpeaker $speaker - */ - public function setSpeaker($speaker) - { - $this->speaker = $speaker; - } -} \ No newline at end of file diff --git a/app/Models/Foundation/Main/EmailCreationRequests/SpeakerSelectionAnnouncementEmailCreationRequest.php b/app/Models/Foundation/Main/EmailCreationRequests/SpeakerSelectionAnnouncementEmailCreationRequest.php deleted file mode 100644 index 33894ad7..00000000 --- a/app/Models/Foundation/Main/EmailCreationRequests/SpeakerSelectionAnnouncementEmailCreationRequest.php +++ /dev/null @@ -1,139 +0,0 @@ -type; - } - - /** - * @param string $type - */ - public function setType($type) - { - $this->type = $type; - } - - /** - * @return string - */ - public function getSpeakerRole() - { - return $this->speaker_role; - } - - /** - * @param string $speaker_role - */ - public function setSpeakerRole($speaker_role) - { - $this->speaker_role = $speaker_role; - } - - /** - * @return PresentationSpeaker - */ - public function getSpeaker() - { - return $this->speaker; - } - - /** - * @param PresentationSpeaker $speaker - */ - public function setSpeaker($speaker) - { - $this->speaker = $speaker; - } - - /** - * @return SummitRegistrationPromoCode - */ - public function getPromoCode() - { - return $this->promo_code; - } - - /** - * @param SummitRegistrationPromoCode $promo_code - */ - public function setPromoCode($promo_code) - { - $this->promo_code = $promo_code; - } - - /** - * @var array - */ - public static $valid_types = [ - SpeakerAnnouncementSummitEmail::TypeAccepted, - SpeakerAnnouncementSummitEmail::TypeAcceptedAlternate, - SpeakerAnnouncementSummitEmail::TypeAcceptedRejected, - SpeakerAnnouncementSummitEmail::TypeAlternate, - SpeakerAnnouncementSummitEmail::TypeAlternateRejected, - ]; - - /** - * @param string $type - * @return bool - */ - public static function isValidType($type){ - return in_array($type, self::$valid_types); - } -} \ No newline at end of file diff --git a/app/Models/Foundation/Main/Factories/CompanyFactory.php b/app/Models/Foundation/Main/Factories/CompanyFactory.php new file mode 100644 index 00000000..27e9334b --- /dev/null +++ b/app/Models/Foundation/Main/Factories/CompanyFactory.php @@ -0,0 +1,63 @@ +setName(trim($data['name'])); + + if (isset($data['description'])) + $company->setDescription(trim($data['description'])); + + if (isset($data['url'])) + $company->setUrl(trim($data['url'])); + + if (isset($data['industry'])) + $company->setIndustry(trim($data['industry'])); + + if (isset($data['city'])) + $company->setCity(trim($data['city'])); + + if (isset($data['state'])) + $company->setState(trim($data['state'])); + + if (isset($data['country'])) + $company->setCountry(trim($data['country'])); + + return $company; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Main/File.php b/app/Models/Foundation/Main/File.php index 5ceb8b6b..c99c4e96 100644 --- a/app/Models/Foundation/Main/File.php +++ b/app/Models/Foundation/Main/File.php @@ -12,6 +12,8 @@ * limitations under the License. **/ use Doctrine\ORM\Mapping AS ORM; +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Storage; use models\utils\SilverstripeBaseModel; use Illuminate\Support\Facades\Config; /** @@ -275,27 +277,29 @@ class File extends SilverstripeBaseModel */ public function getCloudLink() { - $relativeLink = ltrim($this->getRelativeLinkFor(), '/'); - - return - sprintf("%s/%s/%s", - Config::get("cloudstorage.base_url") , - Config::get("cloudstorage.assets_container"), - $relativeLink); + try { + $relativeLink = ltrim($this->getRelativeLinkFor(), '/'); + return Storage::disk('assets')->url($relativeLink); + } + catch (\Exception $ex){ + Log::warning($ex); + return null; + } } /** * @param string $imageRelativePath - * @return string + * @return string|null */ - public static function getCloudLinkForImages(string $imageRelativePath):string { - $imageRelativePath = ltrim($imageRelativePath, '/'); - - return - sprintf("%s/%s/%s", - Config::get("cloudstorage.base_url") , - Config::get("cloudstorage.images_container"), - $imageRelativePath); + public static function getCloudLinkForImages(string $imageRelativePath):?string { + try { + $imageRelativePath = ltrim($imageRelativePath, '/'); + return Storage::disk('static_images')->url($imageRelativePath); + } + catch (\Exception $ex){ + Log::warning($ex); + return null; + } } /** diff --git a/app/Models/Foundation/Main/Group.php b/app/Models/Foundation/Main/Group.php index f16b38d8..e18d68ce 100644 --- a/app/Models/Foundation/Main/Group.php +++ b/app/Models/Foundation/Main/Group.php @@ -28,6 +28,7 @@ class Group extends SilverstripeBaseModel parent::__construct(); $this->members = new ArrayCollection(); $this->groups = new ArrayCollection(); + $this->is_external = false; } /** @@ -38,6 +39,14 @@ class Group extends SilverstripeBaseModel $this->members->add($member); } + /** + * @param Member $member + */ + public function removeMember(Member $member){ + if(!$this->members->contains($member)) return; + $this->members->removeElement($member); + } + /** * @return string */ @@ -153,7 +162,7 @@ class Group extends SilverstripeBaseModel private $code; /** - * @ORM\ManyToMany(targetEntity="models\main\Member", mappedBy="groups") + * @ORM\ManyToMany(targetEntity="models\main\Member", mappedBy="groups", fetch="EXTRA_LAZY") */ private $members; @@ -167,4 +176,18 @@ class Group extends SilverstripeBaseModel * @ORM\OneToMany(targetEntity="Group", mappedBy="parent") */ private $groups; + + /** + * @ORM\Column(name="IsExternal", type="boolean") + * @var bool + */ + private $is_external; + + public function setExternal(){ + $this->is_external = true; + } + + public function isExternal():bool { + return $this->is_external; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Main/IGroup.php b/app/Models/Foundation/Main/IGroup.php index a81b7864..185ca47c 100644 --- a/app/Models/Foundation/Main/IGroup.php +++ b/app/Models/Foundation/Main/IGroup.php @@ -22,6 +22,8 @@ interface IGroup const Administrators = 'administrators'; const SuperAdmins = 'super-admins'; const BadgePrinters = 'badge-printers'; + const TrackChairs = 'track-chairs'; + const TrackChairsAdmins = 'track-chairs-admins'; const CommunityMembers = 'community-members'; const FoundationMembers = 'foundation-members'; const SummitAdministrators = 'summit-front-end-administrators'; diff --git a/app/Models/Foundation/Main/Member.php b/app/Models/Foundation/Main/Member.php index cd2f2d12..a21da6e3 100644 --- a/app/Models/Foundation/Main/Member.php +++ b/app/Models/Foundation/Main/Member.php @@ -11,25 +11,34 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\Models\Foundation\Main\IGroup; +use App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric; +use Illuminate\Support\Facades\App; +use Illuminate\Support\Facades\Log; use Models\Foundation\Main\CCLA\Team; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NoResultException; use models\exceptions\ValidationException; +use models\oauth2\IResourceServerContext; use models\summit\CalendarSync\CalendarSyncInfo; use models\summit\CalendarSync\ScheduleCalendarSyncInfo; +use models\summit\IOrderConstants; use models\summit\PresentationSpeaker; use models\summit\RSVP; +use models\summit\Sponsor; use models\summit\Summit; +use models\summit\SummitAttendee; +use models\summit\SummitAttendeeTicket; use models\summit\SummitEvent; use models\summit\SummitEventFeedback; +use models\summit\SummitOrder; use models\summit\SummitRoomReservation; use models\utils\SilverstripeBaseModel; -use models\oauth2\IResourceServerContext; -use Illuminate\Support\Facades\App; use Doctrine\ORM\Mapping AS ORM; + /** * @ORM\Entity * @ORM\Table(name="Member") @@ -40,6 +49,12 @@ use Doctrine\ORM\Mapping AS ORM; class Member extends SilverstripeBaseModel { + const MembershipTypeFoundation = 'Foundation'; + + const MembershipTypeCommunity = 'Community'; + + const MembershipTypeNone = 'None'; + /** * @ORM\Column(name="FirstName", type="string") * @var string @@ -64,6 +79,12 @@ class Member extends SilverstripeBaseModel */ private $github_user; + /** + * @ORM\Column(name="MembershipType", type="string") + * @var string + */ + private $membership_type; + /** * @ORM\OneToMany(targetEntity="models\summit\SummitEventFeedback", mappedBy="owner", cascade={"persist"}, orphanRemoval=true) * @var SummitEventFeedback[] @@ -145,7 +166,7 @@ class Member extends SilverstripeBaseModel /** * * @ORM\Column(name="ExternalUserId", type="integer") - * @var int + * @var int|null */ private $user_external_id; @@ -162,6 +183,12 @@ class Member extends SilverstripeBaseModel */ private $state; + /** + * @ORM\Column(name="ExternalPic", type="string") + * @var string + */ + private $external_pic; + /** * @ORM\OneToMany(targetEntity="SummitMemberSchedule", mappedBy="member", cascade={"persist"}, orphanRemoval=true) * @var SummitMemberSchedule[] @@ -187,7 +214,13 @@ class Member extends SilverstripeBaseModel private $rsvp; /** - * @ORM\ManyToMany(targetEntity="models\main\Group", inversedBy="members") + * @ORM\ManyToMany(targetEntity="models\summit\Sponsor", mappedBy="members") + * @var Sponsor[] + */ + private $sponsor_memberships; + + /** + * @ORM\ManyToMany(targetEntity="models\main\Group", inversedBy="members", cascade={"persist"}) * @ORM\JoinTable(name="Group_Members", * joinColumns={@ORM\JoinColumn(name="MemberID", referencedColumnName="ID")}, * inverseJoinColumns={@ORM\JoinColumn(name="GroupID", referencedColumnName="ID")} @@ -220,13 +253,13 @@ class Member extends SilverstripeBaseModel /** * @ORM\OneToMany(targetEntity="models\summit\SummitRoomReservation", mappedBy="owner", cascade={"persist"}, orphanRemoval=true) - * @var ArrayCollection + * @var SummitRoomReservation[] */ private $reservations; /** * @var PresentationSpeaker - * @ORM\OneToOne(targetEntity="models\summit\PresentationSpeaker", mappedBy="member", cascade={"persist"}) + * @ORM\OneToOne(targetEntity="models\summit\PresentationSpeaker", mappedBy="member", cascade={"persist", "remove"}, orphanRemoval=true) */ private $speaker; @@ -236,26 +269,50 @@ class Member extends SilverstripeBaseModel */ private $schedule_shareable_links; + /** + * @ORM\OneToMany(targetEntity="models\summit\SummitOrder", mappedBy="owner", cascade={"persist","remove"}, orphanRemoval=true) + * @var SummitOrder[] + */ + private $summit_registration_orders; + + /** + * @ORM\ManyToMany(targetEntity="models\main\SummitAdministratorPermissionGroup", mappedBy="members") + * @var SummitAdministratorPermissionGroup[] + */ + private $summit_permission_groups; + + /** + * @ORM\OneToMany(targetEntity="App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric", mappedBy="member", cascade={"persist","remove"}, orphanRemoval=true) + * @var SummitEventAttendanceMetric[] + */ + protected $summit_attendance_metrics; + /** * Member constructor. */ public function __construct() { parent::__construct(); - $this->active = false; - $this->email_verified = false; - $this->feedback = new ArrayCollection(); - $this->groups = new ArrayCollection(); - $this->ccla_teams = new ArrayCollection(); - $this->affiliations = new ArrayCollection(); - $this->team_memberships = new ArrayCollection(); - $this->favorites = new ArrayCollection(); - $this->schedule = new ArrayCollection(); - $this->rsvp = new ArrayCollection(); - $this->calendars_sync = new ArrayCollection(); - $this->schedule_sync_info = new ArrayCollection(); - $this->reservations = new ArrayCollection(); + $this->active = false; + $this->email_verified = false; + $this->feedback = new ArrayCollection(); + $this->groups = new ArrayCollection(); + $this->ccla_teams = new ArrayCollection(); + $this->affiliations = new ArrayCollection(); + $this->team_memberships = new ArrayCollection(); + $this->favorites = new ArrayCollection(); + $this->schedule = new ArrayCollection(); + $this->rsvp = new ArrayCollection(); + $this->calendars_sync = new ArrayCollection(); + $this->schedule_sync_info = new ArrayCollection(); + $this->reservations = new ArrayCollection(); + $this->sponsor_memberships = new ArrayCollection(); + $this->summit_registration_orders = new ArrayCollection(); + $this->user_external_id = 0; + $this->membership_type = self::MembershipTypeNone; $this->schedule_shareable_links = new ArrayCollection(); + $this->summit_permission_groups = new ArrayCollection(); + $this->summit_attendance_metrics = new ArrayCollection(); } /** @@ -287,7 +344,7 @@ class Member extends SilverstripeBaseModel */ public function getAffiliationByOrgName(string $orgName): ?Affiliation { - $res = $this->affiliations->filter(function ($e) use($orgName) { + $res = $this->affiliations->filter(function ($e) use ($orgName) { return $e->getOrganization()->getName() == trim($orgName) && $e->isCurrent(); })->first(); return $res ? $res : null; @@ -301,7 +358,7 @@ class Member extends SilverstripeBaseModel $criteria = Criteria::create() ->orderBy([ "start_date" => Criteria::ASC, - "end_date" => Criteria::ASC, + "end_date" => Criteria::ASC, ]); return $this->affiliations->matching($criteria); } @@ -339,7 +396,7 @@ class Member extends SilverstripeBaseModel } /** - * @return SummitEvent[] + * @return ArrayCollection|SummitMemberFavorite[] */ public function getFavoritesSummitEvents() { @@ -469,7 +526,8 @@ class Member extends SilverstripeBaseModel /** * @return string */ - public function getGitHubUser(){ + public function getGitHubUser() + { return $this->github_user; } @@ -607,7 +665,7 @@ class Member extends SilverstripeBaseModel * @param SummitEvent $event * @return SummitEventFeedback|null */ - public function getFeedbackByEvent(SummitEvent $event):?SummitEventFeedback + public function getFeedbackByEvent(SummitEvent $event): ?SummitEventFeedback { $criteria = Criteria::create(); $criteria->where(Criteria::expr()->eq('event', $event)); @@ -618,8 +676,9 @@ class Member extends SilverstripeBaseModel /** * @param SummitEventFeedback $feedback */ - public function addFeedback(SummitEventFeedback $feedback){ - if($this->feedback->contains($feedback)) return; + public function addFeedback(SummitEventFeedback $feedback) + { + if ($this->feedback->contains($feedback)) return; $this->feedback->add($feedback); $feedback->setOwner($this); } @@ -627,31 +686,50 @@ class Member extends SilverstripeBaseModel /** * @param SummitEventFeedback $feedback */ - public function removeFeedback(SummitEventFeedback $feedback){ - if(!$this->feedback->contains($feedback)) return; + public function removeFeedback(SummitEventFeedback $feedback) + { + if (!$this->feedback->contains($feedback)) return; $this->feedback->removeElement($feedback); $feedback->clearOwner(); } /** + * @param bool $skip_external * @return bool */ - public function isAdmin():bool + public function isAdmin($skip_external = false): bool { // admin or super admin - $superAdminGroup = $this->getGroupByCode(IGroup::SuperAdmins); - if(!is_null($superAdminGroup)) + $superAdminGroup = $this->getGroupByCode(IGroup::SuperAdmins); + if (!is_null($superAdminGroup)) { + Log::debug(sprintf("Member::isAdmin has Super Admin Group On DB")); return true; + } $adminGroup = $this->getGroupByCode(IGroup::Administrators); - if(!is_null($adminGroup)) + if (!is_null($adminGroup)) { + Log::debug(sprintf("Member::isAdmin has Admin Group On DB")); return true; + } - if($this->isOnExternalGroup(IGroup::SuperAdmins)) + if (!$skip_external) { + Log::debug(sprintf("Member::isAdmin check on external ")); + if ($this->isOnExternalGroup(IGroup::SuperAdmins)) + return true; + + if ($this->isOnExternalGroup(IGroup::Administrators)) + return true; + } + + return false; + } + + public function isSummitAdmin(): bool + { + $summitAdminGroup = $this->getGroupByCode(IGroup::SummitAdministrators); + if (!is_null($summitAdminGroup)) return true; - - if($this->isOnExternalGroup(IGroup::Administrators)) + if ($this->isOnExternalGroup(IGroup::SummitAdministrators)) return true; - return false; } @@ -659,11 +737,11 @@ class Member extends SilverstripeBaseModel * @param string $code * @return bool */ - public function isOnExternalGroup(string $code):bool{ + public function isOnExternalGroup(string $code): bool + { $resource_server_ctx = App::make(IResourceServerContext::class); - if($resource_server_ctx instanceof IResourceServerContext){ - foreach($resource_server_ctx->getCurrentUserGroups() as $group) - { + if ($resource_server_ctx instanceof IResourceServerContext) { + foreach ($resource_server_ctx->getCurrentUserGroups() as $group) { if ( isset($group['slug']) && @@ -680,28 +758,67 @@ class Member extends SilverstripeBaseModel * @param bool $skip_external * @return bool */ - public function isOnGroup(string $code, $skip_external = false){ - if($this->isAdmin()) return true; + public function isOnGroup(string $code, $skip_external = false) + { + Log::debug(sprintf("Member::isOnGroup member %s group code %s", $this->id, $code)); + if ($this->isAdmin($skip_external)) { + Log::debug(sprintf("Member::isOnGroup member %s group code %s isAdmin true", $this->id, $code)); + return true; + } $group = $this->getGroupByCode($code); - if(!is_null($group)) return true; - if(!$skip_external){ - return $this->isOnExternalGroup($code); + if (!is_null($group)) { + Log::debug(sprintf("Member::isOnGroup member %s group code %s belongs to group", $this->id, $code)); + return true; + } + if (!$skip_external) { + Log::debug(sprintf("Member::isOnGroup member %s group code %s check external ones", $this->id, $code)); + return $this->isOnExternalGroup($code); } return false; } - /** * @param string $code * @return Group|null */ - public function getGroupByCode(string $code):?Group { + public function getGroupByCode(string $code): ?Group + { $criteria = Criteria::create(); $criteria->where(Criteria::expr()->eq('code', trim($code))); $res = $this->groups->matching($criteria)->first(); return $res === false ? null : $res; } + /** + * @param string $code + * @return bool + */ + public function belongsToGroup(string $code): bool + { + try { + $sql = <<prepareRawSQL($sql); + $stmt->execute( + [ + 'member_id' => $this->getId(), + 'code' => trim($code), + ] + ); + $res = $stmt->fetchAll(\PDO::FETCH_COLUMN); + return intval($res[0]) > 0; + } catch (\Exception $ex) { + + } + return false; + + } + /** * @return int[] */ @@ -714,7 +831,8 @@ class Member extends SilverstripeBaseModel return $ids; } - public function getCCLATeamsIds(){ + public function getCCLATeamsIds() + { $ids = []; foreach ($this->getCCLATeams() as $t) { $ids[] = intval($t->getId()); @@ -725,7 +843,8 @@ class Member extends SilverstripeBaseModel /** * @return Team[] */ - public function getCCLATeams(){ + public function getCCLATeams() + { return $this->ccla_teams->toArray(); } @@ -738,6 +857,14 @@ class Member extends SilverstripeBaseModel foreach ($this->getGroups() as $g) { $codes[] = $g->getCode(); } + // from IDP + $resource_server_ctx = App::make(IResourceServerContext::class); + if ($resource_server_ctx instanceof IResourceServerContext) { + foreach ($resource_server_ctx->getCurrentUserGroups() as $group) { + if (isset($group['slug'])) + $codes[] = trim($group['slug']); + } + } return $codes; } @@ -784,7 +911,7 @@ class Member extends SilverstripeBaseModel { $favorite = $this->getFavoriteByEvent($event); - if(is_null($favorite)) + if (is_null($favorite)) throw new ValidationException ( sprintf('Event %s does not belongs to member %s favorite.', $event->getId(), $this->getId()) @@ -794,7 +921,7 @@ class Member extends SilverstripeBaseModel } /** - * @param Summit $summit + * @param Summit $summit * @return int[] */ public function getFavoritesEventsIds(Summit $summit) @@ -822,13 +949,13 @@ SQL; */ public function add2Schedule(SummitEvent $event) { - if($this->isOnSchedule($event)) + if ($this->isOnSchedule($event)) throw new ValidationException ( sprintf('Event %s already belongs to member %s schedule.', $event->getId(), $this->getId()) ); - if(!$event->isPublished()) + if (!$event->isPublished()) throw new ValidationException ( sprintf('Event %s is not published', $event->getId()) @@ -844,7 +971,8 @@ SQL; /** * @param ScheduleCalendarSyncInfo $sync_info */ - public function add2ScheduleSyncInfo(ScheduleCalendarSyncInfo $sync_info){ + public function add2ScheduleSyncInfo(ScheduleCalendarSyncInfo $sync_info) + { $sync_info->setMember($this); $this->schedule_sync_info->add($sync_info); } @@ -853,7 +981,7 @@ SQL; { $schedule = $this->getScheduleByEvent($event); - if(is_null($schedule)) + if (is_null($schedule)) throw new ValidationException ( sprintf('Event %s does not belongs to member %s schedule.', $event->getId(), $this->getId()) @@ -862,7 +990,8 @@ SQL; $schedule->clearOwner(); } - public function removeFromScheduleSyncInfo(ScheduleCalendarSyncInfo $sync_info){ + public function removeFromScheduleSyncInfo(ScheduleCalendarSyncInfo $sync_info) + { $this->schedule_sync_info->removeElement($sync_info); $sync_info->clearOwner(); } @@ -872,7 +1001,8 @@ SQL; * @param int $event_id * @return bool */ - public function isEventSynchronized(CalendarSyncInfo $calendar_sync_info, $event_id){ + public function isEventSynchronized(CalendarSyncInfo $calendar_sync_info, $event_id) + { $criteria = Criteria::create(); $criteria->where(Criteria::expr()->eq('summit_event_id', $event_id)); @@ -895,7 +1025,8 @@ SQL; * @param SummitEvent $event * @return null| SummitMemberSchedule */ - public function getScheduleByEvent(SummitEvent $event){ + public function getScheduleByEvent(SummitEvent $event) + { try { $query = $this->createQuery("SELECT s from models\main\SummitMemberSchedule s @@ -907,11 +1038,9 @@ SQL; ->setParameter('member_id', $this->getIdentifier()) ->setParameter('event_id', $event->getIdentifier()) ->getSingleResult(); - } - catch(NoResultException $ex1){ + } catch (NoResultException $ex1) { return null; - } - catch(NonUniqueResultException $ex2){ + } catch (NonUniqueResultException $ex2) { // should never happen return null; } @@ -922,18 +1051,17 @@ SQL; * @param CalendarSyncInfo $calendar_sync_info * @return ScheduleCalendarSyncInfo|null */ - public function getScheduleSyncInfoByEvent($summit_event_id, CalendarSyncInfo $calendar_sync_info){ + public function getScheduleSyncInfoByEvent($summit_event_id, CalendarSyncInfo $calendar_sync_info) + { try { $criteria = Criteria::create(); $criteria->where(Criteria::expr()->eq('summit_event_id', $summit_event_id)); $criteria->andWhere(Criteria::expr()->eq('calendar_sync_info', $calendar_sync_info)); $res = $this->schedule_sync_info->matching($criteria)->first(); return $res === false ? null : $res; - } - catch(NoResultException $ex1){ + } catch (NoResultException $ex1) { return null; - } - catch(NonUniqueResultException $ex2){ + } catch (NonUniqueResultException $ex2) { // should never happen return null; } @@ -943,7 +1071,8 @@ SQL; * @param SummitEvent $event * @return SummitMemberFavorite|null */ - public function getFavoriteByEvent(SummitEvent $event){ + public function getFavoriteByEvent(SummitEvent $event) + { try { $query = $this->createQuery("SELECT f from models\main\SummitMemberFavorite f JOIN f.member a @@ -954,21 +1083,20 @@ SQL; ->setParameter('member_id', $this->getIdentifier()) ->setParameter('event_id', $event->getIdentifier()) ->getSingleResult(); - } - catch(NoResultException $ex1){ + } catch (NoResultException $ex1) { return null; - } - catch(NonUniqueResultException $ex2){ + } catch (NonUniqueResultException $ex2) { // should never happen return null; } } /** - * @param Summit $summit + * @param Summit $summit * @return int[] */ - public function getScheduledEventsIds(Summit $summit){ + public function getScheduledEventsIds(Summit $summit) + { $sql = <<createQueryBuilder(); $rsvp = $builder ->select('r') - ->from('models\summit\RSVP','r') - ->join('r.owner','o') - ->join('r.event','e') + ->from('models\summit\RSVP', 'r') + ->join('r.owner', 'o') + ->join('r.event', 'e') ->where('o.id = :owner_id and e.id = :event_id') ->setParameter('owner_id', $this->getId()) - ->setParameter('event_id', intval($event_id)) + ->setParameter('event_id', intval($event_id)) ->getQuery()->getResult(); return count($rsvp) > 0 ? $rsvp[0] : null; @@ -1009,17 +1138,18 @@ SQL; * @param Summit $summit * @return null|RSVP[] */ - public function getRsvpBySummit(Summit $summit){ + public function getRsvpBySummit(Summit $summit) + { $builder = $this->createQueryBuilder(); - $res = $builder + $res = $builder ->select('r') - ->from('models\summit\RSVP','r') - ->join('r.owner','o') - ->join('r.event','e') - ->join('e.summit','s') + ->from('models\summit\RSVP', 'r') + ->join('r.owner', 'o') + ->join('r.event', 'e') + ->join('e.summit', 's') ->where('o.id = :owner_id and s.id = :summit_id') ->setParameter('owner_id', $this->getId()) - ->setParameter('summit_id', $summit->getId()) + ->setParameter('summit_id', $summit->getId()) ->getQuery()->getResult(); return $res; @@ -1029,7 +1159,8 @@ SQL; * @param Summit $summit * @return SummitMemberSchedule[] */ - public function getScheduleBySummit(Summit $summit){ + public function getScheduleBySummit(Summit $summit) + { $query = $this->createQuery("SELECT s from models\main\SummitMemberSchedule s JOIN s.member m @@ -1063,18 +1194,17 @@ SQL; * @param Summit $summit * @return CalendarSyncInfo[] */ - public function getSyncInfoBy(Summit $summit){ + public function getSyncInfoBy(Summit $summit) + { try { $criteria = Criteria::create(); $criteria->where(Criteria::expr()->eq('summit', $summit)); $criteria->andWhere(Criteria::expr()->eq('revoked', 0)); $res = $this->calendars_sync->matching($criteria)->first(); return $res == false ? null : $res; - } - catch(NoResultException $ex1){ + } catch (NoResultException $ex1) { return null; - } - catch(NonUniqueResultException $ex2){ + } catch (NonUniqueResultException $ex2) { // should never happen return null; } @@ -1084,14 +1214,16 @@ SQL; * @param Summit $summit * @return bool */ - public function hasSyncInfoFor(Summit $summit){ + public function hasSyncInfoFor(Summit $summit) + { return !is_null($this->getSyncInfoBy($summit)); } /** * @param CalendarSyncInfo $calendar_sync_info */ - public function removeFromCalendarSyncInfo(CalendarSyncInfo $calendar_sync_info){ + public function removeFromCalendarSyncInfo(CalendarSyncInfo $calendar_sync_info) + { $this->calendars_sync->removeElement($calendar_sync_info); $calendar_sync_info->clearOwner(); } @@ -1100,7 +1232,8 @@ SQL; * @param int $affiliation_id * @return Affiliation|null */ - public function getAffiliationById($affiliation_id){ + public function getAffiliationById($affiliation_id) + { $criteria = Criteria::create(); $criteria->where(Criteria::expr()->eq('id', intval($affiliation_id))); @@ -1113,8 +1246,9 @@ SQL; * @param Affiliation $affiliation * @return $this */ - public function removeAffiliation(Affiliation $affiliation){ - if($this->affiliations->contains($affiliation)) { + public function removeAffiliation(Affiliation $affiliation) + { + if ($this->affiliations->contains($affiliation)) { $this->affiliations->removeElement($affiliation); $affiliation->clearOwner(); } @@ -1125,8 +1259,9 @@ SQL; * @param Affiliation $affiliation * @return $this */ - public function addAffiliation(Affiliation $affiliation){ - if(!$this->affiliations->contains($affiliation)) { + public function addAffiliation(Affiliation $affiliation) + { + if (!$this->affiliations->contains($affiliation)) { $this->affiliations->add($affiliation); $affiliation->setOwner($this); } @@ -1137,7 +1272,8 @@ SQL; * @param int $rsvp_id * @return RSVP|null */ - public function getRsvpById($rsvp_id){ + public function getRsvpById($rsvp_id) + { $criteria = Criteria::create(); $criteria->where(Criteria::expr()->eq('id', $rsvp_id)); @@ -1150,7 +1286,8 @@ SQL; * @param RSVP $rsvp * @return $this */ - public function removeRsvp(RSVP $rsvp){ + public function removeRsvp(RSVP $rsvp) + { $this->rsvp->removeElement($rsvp); return $this; } @@ -1158,10 +1295,11 @@ SQL; /** * @return string */ - public function getFullName(){ + public function getFullName() + { $fullname = $this->first_name; - if(!empty($this->last_name)){ - if(!empty($fullname)) $fullname .= ', '; + if (!empty($this->last_name)) { + if (!empty($fullname)) $fullname .= ' '; $fullname .= $this->last_name; } return $fullname; @@ -1170,7 +1308,8 @@ SQL; /** * @return bool */ - public function hasPhoto(){ + public function hasPhoto() + { return $this->getPhotoId() > 0; } @@ -1179,40 +1318,59 @@ SQL; */ public function getPhotoId() { - try{ - if(is_null($this->photo)) return 0; + try { + if (is_null($this->photo)) return 0; return $this->photo->getId(); - } - catch(\Exception $ex){ + } catch (\Exception $ex) { return 0; } } - /** - * @return string + * @return string|null */ - public function getProfilePhotoUrl():string{ + public function getProfilePhotoUrl(): ?string + { $photoUrl = null; - if($this->hasPhoto() && $photo = $this->getPhoto()){ - $photoUrl = $photo->getUrl(); + + if(!empty($this->external_pic)){ + return $this->external_pic; } - if(empty($photo_url) && !empty($this->getTwitterHandle()) ){ + + if ($this->hasPhoto() && $photo = $this->getPhoto()) { + $photoUrl = $photo->getUrl(); + } + + if (empty($photo_url) && !empty($this->getTwitterHandle())) { $twitterName = $this->getTwitterHandle(); $photoUrl = sprintf("https://avatars.io/twitter/%s", trim(trim($twitterName, '@'))); } - if(empty($photoUrl)){ - $photoUrl = File::getCloudLinkForImages("generic-profile-photo.png"); + + if (empty($photoUrl)) { + // get gravatar by default + $photoUrl = $this->getGravatarUrl(); } + return $photoUrl; } + /** + * Get either a Gravatar URL or complete image tag for a specified email address. + */ + private function getGravatarUrl(): string + { + $url = 'https://www.gravatar.com/avatar/'; + $url .= md5(strtolower(trim($this->email))); + return $url; + } + /** * @param SummitRoomReservation $reservation * @return $this */ - public function addReservation(SummitRoomReservation $reservation){ - if($this->reservations->contains($reservation)) return $this; + public function addReservation(SummitRoomReservation $reservation) + { + if ($this->reservations->contains($reservation)) return $this; $this->reservations->add($reservation); $reservation->setOwner($this); return $this; @@ -1221,8 +1379,9 @@ SQL; /** * @return ArrayCollection */ - public function getReservations(){ - return $this->reservations; + public function getReservations() + { + return $this->reservations; } /** @@ -1231,7 +1390,8 @@ SQL; * @throws NoResultException * @throws NonUniqueResultException */ - public function getReservationsCountBySummit(Summit $summit):int{ + public function getReservationsCountBySummit(Summit $summit): int + { $query = $this->createQuery("SELECT count(rv.id) from models\summit\SummitRoomReservation rv JOIN rv.owner o JOIN rv.room r @@ -1255,7 +1415,8 @@ SQL; * @throws NoResultException * @throws NonUniqueResultException */ - public function getReservationsBySummit(Summit $summit){ + public function getReservationsBySummit(Summit $summit) + { $query = $this->createQuery("SELECT rv from models\summit\SummitRoomReservation rv JOIN rv.owner o JOIN rv.room r @@ -1272,7 +1433,8 @@ SQL; * @param int $reservation_id * @return SummitRoomReservation */ - public function getReservationById(int $reservation_id): ?SummitRoomReservation { + public function getReservationById(int $reservation_id): ?SummitRoomReservation + { $criteria = Criteria::create() ->where(Criteria::expr()->eq("id", $reservation_id)); @@ -1288,9 +1450,9 @@ SQL; } /** - * @param string $bio + * @param string|null $bio */ - public function setBio(string $bio): void + public function setBio(?string $bio): void { $this->bio = $bio; } @@ -1306,14 +1468,16 @@ SQL; /** * @return bool */ - public function hasSpeaker(){ + public function hasSpeaker() + { return $this->getSpeakerId() > 0; } /** * @return PresentationSpeaker|null */ - public function getSpeaker():?PresentationSpeaker{ + public function getSpeaker(): ?PresentationSpeaker + { return $this->speaker; } @@ -1322,27 +1486,28 @@ SQL; */ public function getSpeakerId() { - try{ - if(is_null($this->speaker)) return 0; + try { + if (is_null($this->speaker)) return 0; return $this->speaker->getId(); - } - catch(\Exception $ex){ + } catch (\Exception $ex) { return 0; } } - public function setSpeaker(PresentationSpeaker $speaker){ + public function setSpeaker(PresentationSpeaker $speaker) + { $this->speaker = $speaker; } - public function clearSpeaker(){ + public function clearSpeaker() + { $this->speaker = null; } /** - * @return int + * @return int|null */ - public function getUserExternalId(): int + public function getUserExternalId(): ?int { return $this->user_external_id; } @@ -1355,20 +1520,89 @@ SQL; $this->user_external_id = $user_external_id; } + /** + * @return Sponsor[] + */ + public function getSponsorMemberships() + { + return $this->sponsor_memberships; + } + + /** + * @return ArrayCollection|SummitOrder[] + */ + public function getSummitRegistrationOrders() + { + return $this->summit_registration_orders; + } + + /** + * @param int $order_id + * @return SummitOrder|null + */ + public function getSummitRegistrationOrderById(int $order_id): ?SummitOrder + { + $criteria = Criteria::create() + ->where(Criteria::expr()->eq("id", $order_id)); + $order = $this->summit_registration_orders->matching($criteria)->first(); + + return $order === false ? null : $order; + } + + /** + * @param SummitOrder $summit_order + */ + public function addSummitRegistrationOrder(SummitOrder $summit_order) + { + if ($this->summit_registration_orders->contains($summit_order)) return; + $this->summit_registration_orders->add($summit_order); + $summit_order->setOwner($this); + } + + /** + * @param Summit $summit + * @return Sponsor|null + */ + public function getSponsorBySummit(Summit $summit): ?Sponsor + { + $sponsor = $this->sponsor_memberships->filter(function ($entity) use ($summit) { + return $entity->getSummitId() == $summit->getId(); + })->first(); + + return $sponsor === false ? null : $sponsor; + } + + /** + * @return string|null + */ + public function getMembershipType(): ?string + { + return $this->membership_type; + } + /** * @param Group $group */ - public function add2Group(Group $group){ - if($this->groups->contains($group)) return; + public function add2Group(Group $group) + { + if ($this->groups->contains($group)) return; $this->groups->add($group); - $group->addMember($this); + //$group->addMember($this); + } + + public function removeFromGroup(Group $group) + { + if (!$this->groups->contains($group)) return; + $this->groups->removeElement($group); + //$group->removeMember($this); } /** * @param PersonalCalendarShareInfo $link */ - public function addScheduleShareableLink(PersonalCalendarShareInfo $link){ - if($this->schedule_shareable_links->contains($link)) return; + public function addScheduleShareableLink(PersonalCalendarShareInfo $link) + { + if ($this->schedule_shareable_links->contains($link)) return; $this->schedule_shareable_links->add($link); $link->setOwner($this); } @@ -1376,8 +1610,9 @@ SQL; /** * @param PersonalCalendarShareInfo $link */ - public function removeScheduleShareableLink(PersonalCalendarShareInfo $link){ - if(!$this->schedule_shareable_links->contains($link)) return; + public function removeScheduleShareableLink(PersonalCalendarShareInfo $link) + { + if (!$this->schedule_shareable_links->contains($link)) return; $this->schedule_shareable_links->removeElement($link); $link->clearOwner(); } @@ -1386,7 +1621,8 @@ SQL; * @param Summit $summit * @return PersonalCalendarShareInfo|null */ - public function getScheduleShareableLinkBy(Summit $summit):?PersonalCalendarShareInfo{ + public function getScheduleShareableLinkBy(Summit $summit): ?PersonalCalendarShareInfo + { $criteria = Criteria::create(); $criteria->where(Criteria::expr()->eq('summit', $summit)); $criteria->andWhere(Criteria::expr()->eq('revoked', false)); @@ -1399,10 +1635,11 @@ SQL; * @return PersonalCalendarShareInfo|null * @throws \Exception */ - public function createScheduleShareableLink(Summit $summit):?PersonalCalendarShareInfo{ + public function createScheduleShareableLink(Summit $summit): ?PersonalCalendarShareInfo + { $former_link = $this->getScheduleShareableLinkBy($summit); - if(!is_null($former_link)){ + if (!is_null($former_link)) { return $former_link; } @@ -1413,4 +1650,151 @@ SQL; return $link; } + /** + * @param SummitAdministratorPermissionGroup $group + */ + public function add2SummitAdministratorPermissionGroup(SummitAdministratorPermissionGroup $group) + { + if ($this->summit_permission_groups->contains($group)) return; + $this->summit_permission_groups->add($group); + } + + public function removeFromSummitAdministratorPermissionGroup(SummitAdministratorPermissionGroup $group) + { + if (!$this->summit_permission_groups->contains($group)) return; + $this->summit_permission_groups->removeElement($group); + } + + public function getSummitAdministratorPermissionGroup() + { + return $this->summit_permission_groups; + } + + /** + * @return array + */ + public function getAllAllowedSummitsIds(): array + { + $sql = <<prepareRawSQL($sql); + $stmt->execute( + [ + 'member_id' => $this->getId(), + ] + ); + return $stmt->fetchAll(\PDO::FETCH_COLUMN); + } + + public function hasAllowedSummits(): bool + { + return count($this->getAllAllowedSummitsIds()) > 0; + } + + /** + * @param Summit $summit + * @param string $groupSlug + * @return bool + */ + public function hasPermissionForOnGroup(Summit $summit, string $groupSlug): bool + { + if(!SummitAdministratorPermissionGroup::isValidGroup($groupSlug)) return false; + + $sql = <<prepareRawSQL($sql); + $stmt->execute( + [ + 'member_id' => $this->getId(), + 'summit_id' => $summit->getId() + ] + ); + $allowed_summits = $stmt->fetchAll(\PDO::FETCH_COLUMN); + return count($allowed_summits) > 0 && $this->isOnGroup($groupSlug); + } + + /** + * @param Summit $summit + * @return int[] + */ + public function getPaidSummitTicketsIds(Summit $summit) + { + $sql = <<prepareRawSQL($sql); + $stmt->execute( + [ + 'member_id' => $this->getId(), + 'member_email' => $this->email, + 'ticket_status' => IOrderConstants::PaidStatus, + 'summit_id' => $summit->getId(), + ] + ); + return $stmt->fetchAll(\PDO::FETCH_COLUMN); + } + + + /** + * @param Summit $summit + * @return SummitAttendeeTicket[] + */ + public function getPaidSummitTickets(Summit $summit) + { + + $query = $this->createQuery("SELECT t from models\summit\SummitAttendeeTicket t + JOIN t.owner o + LEFT JOIN o.member m + JOIN o.summit su + WHERE su.id = :summit_id + and ( m.id = :member_id or o.email = :member_email) + and t.status = :ticket_status"); + + return $query + ->setParameter('member_id', $this->getId()) + ->setParameter('member_email', $this->email) + ->setParameter('ticket_status', IOrderConstants::PaidStatus) + ->setParameter('summit_id', $summit->getId()) + ->getResult(); + } + + /** + * @return string + */ + public function getExternalPic(): ?string + { + return $this->external_pic; + } + + /** + * @param string $external_pic + */ + public function setExternalPic(string $external_pic): void + { + $this->external_pic = $external_pic; + } + + } \ No newline at end of file diff --git a/app/Models/Foundation/Main/Repositories/ICompanyRepository.php b/app/Models/Foundation/Main/Repositories/ICompanyRepository.php index d2ed1408..c87d290f 100644 --- a/app/Models/Foundation/Main/Repositories/ICompanyRepository.php +++ b/app/Models/Foundation/Main/Repositories/ICompanyRepository.php @@ -12,12 +12,11 @@ * limitations under the License. **/ use models\utils\IBaseRepository; - /** * Interface ICompanyRepository * @package models\main */ interface ICompanyRepository extends IBaseRepository { - + public function getByName(string $name):?Company; } \ No newline at end of file diff --git a/app/Models/Foundation/Main/Repositories/IGroupRepository.php b/app/Models/Foundation/Main/Repositories/IGroupRepository.php index 989b5b25..ce35b59b 100644 --- a/app/Models/Foundation/Main/Repositories/IGroupRepository.php +++ b/app/Models/Foundation/Main/Repositories/IGroupRepository.php @@ -12,11 +12,16 @@ * limitations under the License. **/ use models\utils\IBaseRepository; + /** * Interface IGroupRepository * @package models\main */ interface IGroupRepository extends IBaseRepository { - public function getBySlug(string $slug): ?Group; + /** + * @param string $slug + * @return Group|null + */ + public function getBySlug(string $slug):?Group; } \ No newline at end of file diff --git a/app/Models/Foundation/Main/Repositories/IMemberRepository.php b/app/Models/Foundation/Main/Repositories/IMemberRepository.php index 5c85024e..9c1ee00d 100644 --- a/app/Models/Foundation/Main/Repositories/IMemberRepository.php +++ b/app/Models/Foundation/Main/Repositories/IMemberRepository.php @@ -25,9 +25,15 @@ interface IMemberRepository extends IBaseRepository { /** * @param string $email - * @return Member + * @return Member|null */ - public function getByEmail($email); + public function getByEmail($email):?Member; + + /** + * @param string $email + * @return Member|null + */ + public function getByEmailExclusiveLock($email):?Member; /** * @param string $fullname @@ -48,4 +54,10 @@ interface IMemberRepository extends IBaseRepository * @return Member|null */ public function getByExternalId(int $external_id):?Member; + + /** + * @param int $external_id + * @return Member|null + */ + public function getByExternalIdExclusiveLock(int $external_id): ?Member; } \ No newline at end of file diff --git a/app/Models/Foundation/Main/Repositories/ISummitAdministratorPermissionGroupRepository.php b/app/Models/Foundation/Main/Repositories/ISummitAdministratorPermissionGroupRepository.php new file mode 100644 index 00000000..3f9a5bf2 --- /dev/null +++ b/app/Models/Foundation/Main/Repositories/ISummitAdministratorPermissionGroupRepository.php @@ -0,0 +1,27 @@ +members = new ArrayCollection(); + $this->summits = new ArrayCollection(); + } + + /** + * @ORM\ManyToMany(targetEntity="models\main\Member", inversedBy="summit_permission_groups") + * @ORM\JoinTable(name="SummitAdministratorPermissionGroup_Members", + * joinColumns={@ORM\JoinColumn(name="SummitAdministratorPermissionGroupID", referencedColumnName="ID")}, + * inverseJoinColumns={@ORM\JoinColumn(name="MemberID", referencedColumnName="ID")} + * ) + * @var Member[] + */ + private $members; + + /** + * @ORM\ManyToMany(targetEntity="models\summit\Summit", inversedBy="permission_groups") + * @ORM\JoinTable(name="SummitAdministratorPermissionGroup_Summits", + * joinColumns={@ORM\JoinColumn(name="SummitAdministratorPermissionGroupID", referencedColumnName="ID")}, + * inverseJoinColumns={@ORM\JoinColumn(name="SummitID", referencedColumnName="ID")} + * ) + * @var Summit[] + */ + private $summits; + + /** + * @param Member $member + * @throws ValidationException + */ + public function addMember(Member $member) + { + if(!$this->canAddMember($member)){ + throw new ValidationException(sprintf("Member %s should belong to following groups (%s)", $member->getId(), + implode(",", self::ValidGroups))); + } + if ($this->members->contains($member)) return; + $this->members->add($member); + $member->add2SummitAdministratorPermissionGroup($this); + } + + public function canAddMember(Member $member):bool{ + return + $member->isOnGroup(IGroup::SummitAdministrators) || + $member->isOnGroup(IGroup::TrackChairs) || + $member->isOnGroup(IGroup::TrackChairsAdmins); + } + + /** + * @param Member $member + */ + public function removeMember(Member $member) + { + if (!$this->members->contains($member)) return; + $this->members->removeElement($member); + $member->removeFromSummitAdministratorPermissionGroup($this); + } + + public function getMembers() + { + return $this->members; + } + + public function getMembersIds(): array + { + + $sql = <<prepareRawSQL($sql); + $stmt->execute( + [ + 'group_id' => $this->getId(), + ] + ); + return $stmt->fetchAll(\PDO::FETCH_COLUMN); + + } + + /** + * @param Summit $summit + */ + public function addSummit(Summit $summit) + { + if ($this->summits->contains($summit)) return; + $this->summits->add($summit); + $summit->add2SummitAdministratorPermissionGroup($this); + } + + public function removeSummit(Summit $summit) + { + if (!$this->summits->contains($summit)) return; + $this->summits->removeElement($summit); + $summit->removeFromSummitAdministratorPermissionGroup($this); + } + + public function getSummits() + { + return $this->summits; + } + + public function getSummitsIds(): array + { + + $sql = <<prepareRawSQL($sql); + $stmt->execute( + [ + 'group_id' => $this->getId(), + ] + ); + return $stmt->fetchAll(\PDO::FETCH_COLUMN); + + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle(string $title): void + { + $this->title = $title; + } + + public function clearMembers(){ + $this->members->clear(); + } + + public function clearSummits(){ + $this->summits->clear(); + } + + /** + * @param string $groupSlug + * @return bool + */ + public static function isValidGroup(string $groupSlug):bool { + return in_array($groupSlug,self::ValidGroups); + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/AllowedCurrencies.php b/app/Models/Foundation/Summit/AllowedCurrencies.php new file mode 100644 index 00000000..6d4949cf --- /dev/null +++ b/app/Models/Foundation/Summit/AllowedCurrencies.php @@ -0,0 +1,25 @@ +summit_hall_checked_in_date; - } - - /** - * @return bool - */ - public function getSummitHallCheckedIn(){ - return (bool)$this->summit_hall_checked_in; - } - - /** - * @param bool $summit_hall_checked_in - */ - public function setSummitHallCheckedIn($summit_hall_checked_in){ - $this->summit_hall_checked_in = $summit_hall_checked_in; - } - - /** - * @param \DateTime $summit_hall_checked_in_date - */ - public function setSummitHallCheckedInDate(\DateTime $summit_hall_checked_in_date){ - $this->summit_hall_checked_in_date = $summit_hall_checked_in_date; - } - - /** - * @return boolean - */ - public function getSharedContactInfo() - { - return $this->share_contact_info; - } - - /** - * @param boolean $share_contact_info - */ - public function setShareContactInfo($share_contact_info) - { - $this->share_contact_info = $share_contact_info; - } - - /** - * @return int - */ - public function getMemberId(){ - try{ - return $this->member->getId(); - } - catch(\Exception $ex){ - return 0; - } - } - - /** - * @return bool - */ - public function hasMember(){ - return $this->getMemberId() > 0; - } - - /** - * @ORM\OneToMany(targetEntity="SummitAttendeeTicket", mappedBy="owner", cascade={"persist", "remove"}) - * @var SummitAttendeeTicket[] - */ - private $tickets; - - /** - * @return SummitAttendeeTicket[] - */ - public function getTickets(){ - return $this->tickets; - } - - /** - * @param SummitAttendeeTicket $ticket - */ - public function addTicket(SummitAttendeeTicket $ticket){ - $this->tickets->add($ticket); - $ticket->setOwner($this); - } - - /** - * @return Member - */ - public function getMember(){ - return $this->member; - } - - /** - * @param Member $member - */ - public function setMember(Member $member){ - $this->member = $member; - } - - use SummitOwned; - - public function __construct() - { - parent::__construct(); - $this->share_contact_info = false; - $this->summit_hall_checked_in = false; - $this->tickets = new ArrayCollection(); - } - - /** - * @return SummitEventFeedback[] - */ - public function getEmittedFeedback(){ - - return $this->member->getFeedback()->matching - ( - Criteria::create()->orderBy(["id" => Criteria::ASC]) - ); - } - - /** - * @param SummitEvent $event - * @throws ValidationException - * @deprecated use Member::add2Schedule instead - */ - public function add2Schedule(SummitEvent $event) - { - $this->member->add2Schedule($event); - } - - /** - * @param SummitEvent $event - * @throws ValidationException - * @deprecated use Member::removeFromSchedule instead - */ - public function removeFromSchedule(SummitEvent $event) - { - $this->member->removeFromSchedule($event); - } - - /** - * @param SummitEvent $event - * @return bool - * @deprecated use Member::isOnSchedule instead - */ - public function isOnSchedule(SummitEvent $event) - { - return $this->member->isOnSchedule($event); - } - - /** - * @param SummitEvent $event - * @return null| SummitMemberSchedule - * @deprecated use Member::getScheduleByEvent instead - */ - public function getScheduleByEvent(SummitEvent $event){ - return $this->member->getScheduleByEvent($event); - } - - /** - * @return SummitMemberSchedule[] - * @deprecated use Member::getScheduleBySummit instead - */ - public function getSchedule(){ - return $this->member->getScheduleBySummit($this->summit); - } - - /** - * @return int[] - * @deprecated use Member::getScheduledEventsIds instead - */ - public function getScheduledEventsIds(){ - return $this->member->getScheduledEventsIds($this->summit); - } - - /** - * @param int $event_id - * @return null|RSVP - * @deprecated use Member::getRsvpByEvent instead - */ - public function getRsvpByEvent($event_id){ - return $this->member->getRsvpByEvent($event_id); - } - - /** - * @param int $ticket_id - * @return SummitAttendeeTicket - */ - public function getTicketById($ticket_id){ - $ticket = $this->tickets->matching( - $criteria = Criteria::create() - ->where(Criteria::expr()->eq("id", $ticket_id)) - )->first(); - return $ticket ? $ticket : null; - } - - /** - * @param SummitAttendeeTicket $ticket - * @return $this - */ - public function removeTicket(SummitAttendeeTicket $ticket){ - $this->tickets->removeElement($ticket); - return $this; - } - - /** - * @return bool - */ - public function hasTickets(){ - return $this->tickets->count() > 0; - } - -} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Attendees/SummitAttendeeTicket.php b/app/Models/Foundation/Summit/Attendees/SummitAttendeeTicket.php deleted file mode 100644 index 544821c8..00000000 --- a/app/Models/Foundation/Summit/Attendees/SummitAttendeeTicket.php +++ /dev/null @@ -1,197 +0,0 @@ -changed_date; - } - - /** - * @param mixed $changed_date - */ - public function setChangedDate($changed_date) - { - $this->changed_date = $changed_date; - } - /** - * @return string - */ - public function getExternalOrderId() - { - return $this->external_order_id; - } - - /** - * @param string $external_order_id - */ - public function setExternalOrderId($external_order_id) - { - $this->external_order_id = $external_order_id; - } - - /** - * @return string - */ - public function getExternalAttendeeId() - { - return $this->external_attendee_id; - } - - /** - * @param string $external_attendee_id - */ - public function setExternalAttendeeId($external_attendee_id) - { - $this->external_attendee_id = $external_attendee_id; - } - - /** - * @return \DateTime - */ - public function getBoughtDate() - { - return $this->bought_date; - } - - /** - * @param \DateTime $bought_date - */ - public function setBoughtDate($bought_date) - { - $this->bought_date = $bought_date; - } - - /** - * @return SummitTicketType - */ - public function getTicketType() - { - return $this->ticket_type; - } - - /** - * @return int - */ - public function getTicketTypeId(){ - try{ - return is_null($this->ticket_type) ? 0 : $this->ticket_type->getId(); - } - catch(\Exception $ex){ - return 0; - } - } - - /** - * @return bool - */ - public function hasTicketType(){ - return $this->getTicketTypeId() > 0; - } - - /** - * @param SummitTicketType $ticket_type - */ - public function setTicketType($ticket_type) - { - $this->ticket_type = $ticket_type; - } - - /** - * @return SummitAttendee - */ - public function getOwner() - { - return $this->owner; - } - - /** - * @param SummitAttendee $owner - */ - public function setOwner($owner) - { - $this->owner = $owner; - } - - /** - * @return int - */ - public function getOwnerId(){ - try{ - return is_null($this->owner) ? 0 : $this->owner->getId(); - } - catch(\Exception $ex){ - return 0; - } - } - - /** - * @return bool - */ - public function hasOwner(){ - return $this->getOwnerId() > 0; - } - - -} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/EmailFlows/SummitEmailEventFlow.php b/app/Models/Foundation/Summit/EmailFlows/SummitEmailEventFlow.php new file mode 100644 index 00000000..b5caa5fb --- /dev/null +++ b/app/Models/Foundation/Summit/EmailFlows/SummitEmailEventFlow.php @@ -0,0 +1,86 @@ +email_template_identifier; + } + + public function getFlowName():string{ + return $this->event_type->getFlow()->getName(); + } + + public function getEventTypeName():string{ + return $this->event_type->getName(); + } + + /** + * @param string $email_template_identifier + */ + public function setEmailTemplateIdentifier(string $email_template_identifier): void + { + $this->email_template_identifier = $email_template_identifier; + } + + /** + * @return SummitEmailEventFlowType + */ + public function getEventType(): SummitEmailEventFlowType + { + return $this->event_type; + } + + /** + * @param SummitEmailEventFlowType $event_type + */ + public function setEventType(SummitEmailEventFlowType $event_type): void + { + $this->event_type = $event_type; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/EmailFlows/SummitEmailEventFlowType.php b/app/Models/Foundation/Summit/EmailFlows/SummitEmailEventFlowType.php new file mode 100644 index 00000000..f5191a99 --- /dev/null +++ b/app/Models/Foundation/Summit/EmailFlows/SummitEmailEventFlowType.php @@ -0,0 +1,114 @@ +flow; + } + + /** + * @param SummitEmailFlowType $flow + */ + public function setFlow(SummitEmailFlowType $flow): void + { + $this->flow = $flow; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return string + */ + public function getSlug(): string + { + return $this->slug; + } + + /** + * @param string $slug + */ + public function setSlug(string $slug): void + { + $this->slug = $slug; + } + + /** + * @return string + */ + public function getDefaultEmailTemplate(): string + { + return $this->default_email_template; + } + + /** + * @param string $default_email_template + */ + public function setDefaultEmailTemplate(string $default_email_template): void + { + $this->default_email_template = $default_email_template; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/EmailFlows/SummitEmailFlowType.php b/app/Models/Foundation/Summit/EmailFlows/SummitEmailFlowType.php new file mode 100644 index 00000000..5e01566f --- /dev/null +++ b/app/Models/Foundation/Summit/EmailFlows/SummitEmailFlowType.php @@ -0,0 +1,83 @@ +flow_event_types = new ArrayCollection(); + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @param SummitEmailEventFlowType $event_type + */ + public function addFlowEventType(SummitEmailEventFlowType $event_type){ + if($this->flow_event_types->contains($event_type)) return; + $this->flow_event_types->add($event_type); + $event_type->setFlow($this); + } + + public function removeFlowEventType(SummitEmailEventFlowType $event_type){ + if(!$this->flow_event_types->contains($event_type)) return; + $this->flow_event_types->removeElement($event_type); + } + + public function clearFlowEventType(){ + $this->flow_event_types->clear(); + } + + public function getEventTypes(){ + return $this->flow_event_types; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMaterial.php b/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMaterial.php index ffae830f..1fc49569 100644 --- a/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMaterial.php +++ b/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMaterial.php @@ -21,7 +21,9 @@ use Doctrine\ORM\Mapping AS ORM; * @ORM\Table(name="PresentationMaterial") * @ORM\InheritanceType("JOINED") * @ORM\DiscriminatorColumn(name="ClassName", type="string") - * @ORM\DiscriminatorMap({"PresentationSlide" = "PresentationSlide", "PresentationVideo" = "PresentationVideo", "PresentationLink" = "PresentationLink"}) + * @ORM\DiscriminatorMap( + * {"PresentationSlide" = "PresentationSlide", "PresentationVideo" = "PresentationVideo", + * "PresentationLink" = "PresentationLink", "PresentationMediaUpload" = "PresentationMediaUpload" }) * @ORM\HasLifecycleCallbacks * Class PresentationMaterial * @package models\summit diff --git a/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMediaUpload.php b/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMediaUpload.php new file mode 100644 index 00000000..8cbc6a07 --- /dev/null +++ b/app/Models/Foundation/Summit/Events/Presentations/Materials/PresentationMediaUpload.php @@ -0,0 +1,120 @@ +filename; + } + + /** + * @param string $filename + */ + public function setFilename(string $filename): void + { + $this->filename = $filename; + } + + /** + * @return SummitMediaUploadType|null + */ + public function getMediaUploadType(): ?SummitMediaUploadType + { + return $this->media_upload_type; + } + + /** + * @param SummitMediaUploadType $media_upload_type + */ + public function setMediaUploadType(SummitMediaUploadType $media_upload_type): void + { + $this->media_upload_type = $media_upload_type; + } + + /** + * @return int + */ + public function getMediaUploadTypeId(){ + try { + return is_null($this->media_upload_type) ? 0 : $this->media_upload_type->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return bool + */ + public function hasMediaUploadType():bool{ + return $this->getMediaUploadTypeId() > 0; + } + + public function clearMediaUploadType(){ + $this->media_upload_type = null; + } + + /** + * @param string $storageType + * @return string + */ + public function getRelativePath(string $storageType = IStorageTypesConstants::PublicType):string { + return sprintf('%s/%s', $this->getPath($storageType), $this->getFilename()); + } + + /** + * @param string $storageType + * @return string + */ + public function getPath(string $storageType = IStorageTypesConstants::PublicType): string { + $mountingFolder = Config::get('mediaupload.mounting_folder'); + $format = $storageType == IStorageTypesConstants::PublicType ? '%s/%s/%s': '%s/'.IStorageTypesConstants::PrivateType.'/%s/%s'; + return sprintf($format, $mountingFolder, $this->getPresentation()->getSummit()->getId(), $this->getPresentation()->getId()); + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/Presentations/Presentation.php b/app/Models/Foundation/Summit/Events/Presentations/Presentation.php index 4e2e2972..d6f502ee 100644 --- a/app/Models/Foundation/Summit/Events/Presentations/Presentation.php +++ b/app/Models/Foundation/Summit/Events/Presentations/Presentation.php @@ -20,6 +20,7 @@ use App\Models\Foundation\Summit\SelectionPlan; use Doctrine\Common\Collections\Criteria; use Doctrine\Common\Collections\ArrayCollection; use App\Models\Foundation\Summit\Events\Presentations\TrackQuestions\TrackQuestionTemplate; +use Illuminate\Support\Facades\Config; use models\exceptions\ValidationException; use models\main\Member; /** @@ -85,37 +86,37 @@ class Presentation extends SummitEvent * @ORM\Column(name="Level", type="string") * @var string */ - private $level; + protected $level; /** * @ORM\Column(name="Slug", type="string") * @var string */ - private $slug; + protected $slug; /** * @ORM\Column(name="Status", type="string") * @var string */ - private $status; + protected $status; /** * @ORM\Column(name="Progress", type="integer") * @var int */ - private $progress; + protected $progress; /** * @ORM\Column(name="ProblemAddressed", type="string") * @var string */ - private $problem_addressed; + protected $problem_addressed; /** * @ORM\Column(name="AttendeesExpectedLearnt", type="string") * @var string */ - private $attendees_expected_learnt; + protected $attendees_expected_learnt; /** * @ORM\Column(name="ToRecord", type="boolean") @@ -134,7 +135,7 @@ class Presentation extends SummitEvent * @ORM\JoinColumn(name="ModeratorID", referencedColumnName="ID", onDelete="SET NULL") * @var PresentationSpeaker */ - private $moderator; + protected $moderator; /** @@ -142,26 +143,26 @@ class Presentation extends SummitEvent * @ORM\JoinColumn(name="CreatorID", referencedColumnName="ID", onDelete="SET NULL") * @var Member */ - private $creator; + protected $creator; /** * @ORM\ManyToOne(targetEntity="App\Models\Foundation\Summit\SelectionPlan", inversedBy="presentations") * @ORM\JoinColumn(name="SelectionPlanID", referencedColumnName="ID") * @var SelectionPlan */ - private $selection_plan; + protected $selection_plan; /** * @ORM\OneToMany(targetEntity="models\summit\PresentationMaterial", mappedBy="presentation", cascade={"persist", "remove"}, orphanRemoval=true) * @var PresentationMaterial[] */ - private $materials; + protected $materials; /** * @ORM\OneToMany(targetEntity="models\summit\SummitPresentationComment", mappedBy="presentation", cascade={"persist", "remove"}, orphanRemoval=true) * @var SummitPresentationComment[] */ - private $comments; + protected $comments; /** * @ORM\ManyToMany(targetEntity="models\summit\PresentationSpeaker", inversedBy="presentations") @@ -175,19 +176,19 @@ class Presentation extends SummitEvent * } * ) */ - private $speakers; + protected $speakers; /** * @ORM\OneToMany(targetEntity="models\summit\SummitSelectedPresentation", mappedBy="presentation", cascade={"persist", "remove"}, orphanRemoval=true) * @var SummitSelectedPresentation[] */ - private $selected_presentations; + protected $selected_presentations; /** * @ORM\OneToMany(targetEntity="App\Models\Foundation\Summit\Events\Presentations\TrackQuestions\TrackAnswer", mappedBy="presentation", cascade={"persist"}, orphanRemoval=true, fetch="EXTRA_LAZY") * @var TrackAnswer[] */ - private $answers; + protected $answers; /** * @return bool @@ -219,13 +220,13 @@ class Presentation extends SummitEvent public function __construct() { parent::__construct(); - $this->progress = self::PHASE_NEW; - $this->materials = new ArrayCollection(); - $this->speakers = new ArrayCollection(); - $this->answers = new ArrayCollection(); - $this->comments = new ArrayCollection(); - $this->to_record = false; - $this->attending_media = false; + $this->progress = self::PHASE_NEW; + $this->materials = new ArrayCollection(); + $this->speakers = new ArrayCollection(); + $this->answers = new ArrayCollection(); + $this->comments = new ArrayCollection(); + $this->to_record = false; + $this->attending_media = false; } /** @@ -389,6 +390,18 @@ class Presentation extends SummitEvent return $res === false ? null : $res; } + /** + * @param int $mediaUploadId + * @return PresentationMediaUpload + */ + public function getMediaUploadBy($mediaUploadId){ + $res = $this->materials + ->filter(function( $element) use($mediaUploadId) { return $element instanceof PresentationMediaUpload && $element->getId() == $mediaUploadId; }) + ->first(); + return $res === false ? null : $res; + } + + /** * @param PresentationVideo $video */ @@ -413,6 +426,14 @@ class Presentation extends SummitEvent $link->unsetPresentation(); } + /** + * @param PresentationMediaUpload $mediaUpload + */ + public function removeMediaUpload(PresentationMediaUpload $mediaUpload){ + $this->materials->removeElement($mediaUpload); + $mediaUpload->unsetPresentation(); + } + /** * @param PresentationSpeaker $speaker */ @@ -448,10 +469,29 @@ class Presentation extends SummitEvent return $this; } + /** + * @return PresentationMediaUpload[] + */ + public function getMediaUploads() + { + return $this->materials->filter(function( $element) { return $element instanceof PresentationMediaUpload; }); + } + + /** + * @param PresentationMediaUpload $mediaUpload + * @return $this + */ + public function addMediaUpload(PresentationMediaUpload $mediaUpload){ + $this->materials->add($mediaUpload); + $mediaUpload->setPresentation($this); + $mediaUpload->setOrder($this->getMaterialsMaxOrder() + 1); + return $this; + } + /** * @return int */ - private function getMaterialsMaxOrder(){ + protected function getMaterialsMaxOrder(){ $criteria = Criteria::create(); $criteria->orderBy(['order' => 'DESC']); $material = $this->materials->matching($criteria)->first(); @@ -906,7 +946,7 @@ class Presentation extends SummitEvent return $this->slug; } - private static $default_replacements = [ + protected static $default_replacements = [ '/\s/' => '-', // remove whitespace '/_/' => '-', // underscores to dashes '/[^A-Za-z0-9+.\-]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot @@ -934,4 +974,20 @@ class Presentation extends SummitEvent return $this; } + /** + * Gets a link to edit this presentation + * + * @return string + */ + public function getEditLink():string + { + return sprintf + ( + "%s/app/%s/presentations/%s/summary", + Config::get('cfp.base_url'), + $this->summit->getRawSlug(), + $this->id + ); + } + } diff --git a/app/Models/Foundation/Summit/Events/Presentations/PresentationCategory.php b/app/Models/Foundation/Summit/Events/Presentations/PresentationCategory.php index 2e3a14a9..df62f8db 100644 --- a/app/Models/Foundation/Summit/Events/Presentations/PresentationCategory.php +++ b/app/Models/Foundation/Summit/Events/Presentations/PresentationCategory.php @@ -96,6 +96,12 @@ class PresentationCategory extends SilverstripeBaseModel */ private $chair_visible; + /** + * @ORM\Column(name="Color", type="string") + * @var string + */ + protected $color; + /** * @return string */ @@ -482,4 +488,20 @@ SQL; return $res; } + + /** + * @return string|null + */ + public function getColor():?string + { + return $this->color; + } + + /** + * @param string|null $color + */ + public function setColor(?string $color) + { + $this->color = $color; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/Presentations/PresentationType.php b/app/Models/Foundation/Summit/Events/Presentations/PresentationType.php index b2e97f35..93370a97 100644 --- a/app/Models/Foundation/Summit/Events/Presentations/PresentationType.php +++ b/app/Models/Foundation/Summit/Events/Presentations/PresentationType.php @@ -12,6 +12,7 @@ * limitations under the License. **/ +use Doctrine\Common\Collections\ArrayCollection; use models\summit\SummitEventType; use Doctrine\ORM\Mapping AS ORM; /** @@ -83,6 +84,11 @@ class PresentationType extends SummitEventType */ protected $moderator_label; + /** + * @ORM\ManyToMany(targetEntity="SummitMediaUploadType", mappedBy="presentation_types") + */ + protected $allowed_media_upload_types; + /** * @param Summit $summit * @param string $type @@ -290,5 +296,28 @@ SQL; $this->use_moderator = false; $this->is_moderator_mandatory = false; $this->should_be_available_on_cfp = false; + $this->allowed_media_upload_types = new ArrayCollection(); + $this->max_moderators = 0; + $this->max_speakers = 0; + $this->min_moderators = 0; + $this->min_speakers = 0; + } + + public function addAllowedMediaUploadType(SummitMediaUploadType $type){ + if($this->allowed_media_upload_types->contains($type)) return; + $this->allowed_media_upload_types->add($type); + } + + public function removeAllowedMediaUploadType(SummitMediaUploadType $type){ + if(!$this->allowed_media_upload_types->contains($type)) return; + $this->allowed_media_upload_types->removeElement($type); + } + + public function clearAllowedMediaUploadType(){ + $this->allowed_media_upload_types->clear(); + } + + public function getAllowedMediaUploadTypes(){ + return $this->allowed_media_upload_types; } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/Presentations/SummitPresentationComment.php b/app/Models/Foundation/Summit/Events/Presentations/SummitPresentationComment.php index dac59595..9db44609 100644 --- a/app/Models/Foundation/Summit/Events/Presentations/SummitPresentationComment.php +++ b/app/Models/Foundation/Summit/Events/Presentations/SummitPresentationComment.php @@ -48,7 +48,7 @@ class SummitPresentationComment extends SilverstripeBaseModel private $presentation; /** - * @ORM\ManyToOne(targetEntity="models\main\Member", inversedBy="presentation_comments") + * @ORM\ManyToOne(targetEntity="models\main\Member") * @ORM\JoinColumn(name="CommenterID", referencedColumnName="ID", onDelete="SET NULL") * @var Member */ diff --git a/app/Models/Foundation/Summit/Events/SummitEvent.php b/app/Models/Foundation/Summit/Events/SummitEvent.php index 7d47d65e..9fdf3e9d 100644 --- a/app/Models/Foundation/Summit/Events/SummitEvent.php +++ b/app/Models/Foundation/Summit/Events/SummitEvent.php @@ -11,14 +11,18 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\Models\Foundation\Summit\Events\RSVP\RSVPTemplate; use App\Events\SummitEventCreated; use App\Events\SummitEventDeleted; use App\Events\SummitEventUpdated; +use App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric; use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\Event\PreUpdateEventArgs; use models\exceptions\ValidationException; use models\main\Company; +use models\main\File; +use models\main\Member; use models\main\Tag; use models\utils\PreRemoveEventArgs; use models\utils\SilverstripeBaseModel; @@ -28,6 +32,7 @@ use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Config; use Cocur\Slugify\Slugify; use Doctrine\ORM\Mapping AS ORM; + /** * @ORM\Entity(repositoryClass="App\Repositories\Summit\DoctrineSummitEventRepository") * @ORM\AssociationOverrides({ @@ -39,7 +44,12 @@ use Doctrine\ORM\Mapping AS ORM; * @ORM\Table(name="SummitEvent") * @ORM\InheritanceType("JOINED") * @ORM\DiscriminatorColumn(name="ClassName", type="string") - * @ORM\DiscriminatorMap({"SummitEvent" = "SummitEvent", "Presentation" = "Presentation", "SummitGroupEvent" = "SummitGroupEvent", "SummitEventWithFile" = "SummitEventWithFile"}) + * @ORM\DiscriminatorMap({ + * "SummitEvent" = "SummitEvent", + * "Presentation" = "Presentation", + * "SummitGroupEvent" = "SummitGroupEvent", + * "SummitEventWithFile" = "SummitEventWithFile" + * }) * @ORM\HasLifecycleCallbacks * Class SummitEvent * @package models\summit @@ -187,7 +197,7 @@ class SummitEvent extends SilverstripeBaseModel protected $feedback; /** - * @ORM\ManyToMany(targetEntity="models\main\Tag", cascade={"persist"}) + * @ORM\ManyToMany(targetEntity="models\main\Tag", cascade={"persist"}, inversedBy="events") * @ORM\JoinTable(name="SummitEvent_Tags", * joinColumns={@ORM\JoinColumn(name="SummitEventID", referencedColumnName="ID")}, * inverseJoinColumns={@ORM\JoinColumn(name="TagID", referencedColumnName="ID")} @@ -196,30 +206,44 @@ class SummitEvent extends SilverstripeBaseModel protected $tags; /** - * @return string + * @ORM\OneToMany(targetEntity="App\Models\Foundation\Summit\Events\SummitEventAttendanceMetric", mappedBy="event", cascade={"persist","remove"}, orphanRemoval=true) + * @var SummitEventAttendanceMetric[] */ - public function getTitle() - { - return $this->title; - } + protected $attendance_metrics; /** - * @return boolean + * @ORM\Column(name="StreamingUrl", type="string") + * @var string */ - public function isAllowFeedback() - { - return $this->getAllowFeedback(); - } + protected $streaming_url; /** - * @return boolean + * @ORM\Column(name="EtherpadLink", type="string") + * @var string */ - public function getAllowFeedback() - { - return $this->allow_feedback; - } + protected $etherpad_link; - use SummitOwned; + /** + * @ORM\Column(name="MeetingUrl", type="string") + * @var string + */ + protected $meeting_url; + /** + * @var PreRemoveEventArgs + */ + private $pre_remove_events; + /** + * @var PreUpdateEventArgs + */ + private $pre_update_args; + + + /** + * @ORM\ManyToOne(targetEntity="models\main\File", cascade={"persist"}) + * @ORM\JoinColumn(name="ImageID", referencedColumnName="ID") + * @var File + */ + private $image; /** * SummitEvent constructor. @@ -229,45 +253,27 @@ class SummitEvent extends SilverstripeBaseModel parent::__construct(); $this->allow_feedback = false; - $this->published = false; - $this->avg_feedback = 0; - $this->head_count = 0; + $this->published = false; + $this->avg_feedback = 0; + $this->head_count = 0; $this->rsvp_max_user_number = 0; $this->rsvp_max_user_wait_list_number = 0; - $this->tags = new ArrayCollection(); - $this->feedback = new ArrayCollection(); - $this->sponsors = new ArrayCollection(); - $this->rsvp = new ArrayCollection(); + $this->tags = new ArrayCollection(); + $this->feedback = new ArrayCollection(); + $this->sponsors = new ArrayCollection(); + $this->rsvp = new ArrayCollection(); + $this->attendance_metrics = new ArrayCollection(); } + use SummitOwned; + /** - * @param PresentationCategory $category - * @return $this + * @return string */ - public function setCategory(PresentationCategory $category) + public function getTitle() { - $this->category = $category; - return $this; - } - - /** - * @return PresentationCategory - */ - public function getCategory(){ - return $this->category; - } - - /** - * @return int - */ - public function getCategoryId(){ - try { - return !is_null($this->category)? $this->category->getId():0; - } - catch(\Exception $ex){ - return 0; - } + return $this->title; } /** @@ -281,10 +287,59 @@ class SummitEvent extends SilverstripeBaseModel } /** - * @return string + * @return boolean */ - public function getClassName(){ - return "SummitEvent"; + public function getAllowFeedback() + { + return $this->allow_feedback; + } + + /** + * @return boolean + */ + public function isAllowFeedback() + { + return $this->getAllowFeedback(); + } + + /** + * @param bool $allow_feeback + * @return $this + */ + public function setAllowFeedBack($allow_feeback) + { + $this->allow_feedback = $allow_feeback; + return $this; + } + + /** + * @return PresentationCategory + */ + public function getCategory() + { + return $this->category; + } + + /** + * @param PresentationCategory $category + * @return $this + */ + public function setCategory(PresentationCategory $category) + { + $this->category = $category; + return $this; + } + + /** + * @return int + */ + public function getCategoryId() + { + try { + return !is_null($this->category) ? $this->category->getId() : 0; + } catch (\Exception $ex) { + return 0; + } } /** @@ -356,11 +411,11 @@ class SummitEvent extends SilverstripeBaseModel */ public function getRSVPLink() { - if($this->hasRSVPTemplate()){ + if ($this->hasRSVPTemplate()) { - $summit = $this->getSummit(); - $schedule_page = $summit->getSchedulePage(); - if(empty($schedule_page)) return ''; + $summit = $this->getSummit(); + $schedule_page = $summit->getSchedulePage(); + if (empty($schedule_page)) return ''; $url = sprintf("%s%s/events/%s/%s/rsvp", Config::get("server.assets_base_url", 'https://www.openstack.org/'), $schedule_page, @@ -372,70 +427,57 @@ class SummitEvent extends SilverstripeBaseModel return $this->rsvp_link; } + /** + * @param string $rsvp_link + */ + public function setRSVPLink($rsvp_link) + { + $this->rsvp_link = $rsvp_link; + $this->rsvp_template = null; + $this->rsvp_max_user_wait_list_number = 0; + $this->rsvp_max_user_number = 0; + } + /** * @return bool */ - public function hasRSVPTemplate(){ + public function hasRSVPTemplate() + { return $this->getRSVPTemplateId() > 0; } /** * @return int */ - public function getRSVPTemplateId(){ - try{ + public function getRSVPTemplateId() + { + try { return !is_null($this->rsvp_template) ? $this->rsvp_template->getId() : 0; - } - catch (\Exception $ex){ + } catch (\Exception $ex) { return 0; } } - /** - * @return RSVPTemplate - */ - public function getRSVPTemplate() + public function getSlug() { - return $this->rsvp_template; - } - - /** - * @param RSVPTemplate $rsvp_template - */ - public function setRSVPTemplate(RSVPTemplate $rsvp_template) - { - $this->rsvp_template = $rsvp_template; - $this->rsvp_link = ''; + $slugify = new Slugify(); + return $slugify->slugify($this->title); } /** * @return bool */ - public function hasRSVP(){ + public function hasRSVP() + { return !empty($this->rsvp_link) || $this->hasRSVPTemplate(); } /** * @return bool */ - public function isExternalRSVP(){ - return !empty($this->rsvp_link) && !$this->hasRSVPTemplate(); - } - - public function getSlug(){ - $slugify = new Slugify(); - return $slugify->slugify($this->title); - } - - /** - * @param string $rsvp_link - */ - public function setRSVPLink($rsvp_link) + public function isExternalRSVP() { - $this->rsvp_link = $rsvp_link; - $this->rsvp_template = null; - $this->rsvp_max_user_wait_list_number = 0; - $this->rsvp_max_user_number = 0; + return !empty($this->rsvp_link) && !$this->hasRSVPTemplate(); } /** @@ -454,116 +496,6 @@ class SummitEvent extends SilverstripeBaseModel $this->head_count = $head_count; } - /** - * @return bool - */ - public function hasLocation(){ - return $this->getLocationId() > 0; - } - - /** - * @return int - */ - public function getLocationId() - { - try { - return !is_null($this->location)? $this->location->getId():0; - } - catch(\Exception $ex){ - return 0; - } - } - - /** - * @param DateTime $value - * @return $this - */ - public function setStartDate(DateTime $value) - { - $summit = $this->getSummit(); - if(!is_null($summit)) - { - $value = $summit->convertDateFromTimeZone2UTC($value); - } - $this->start_date = $value; - return $this; - } - - /** - * @return DateTime|null - */ - public function getLocalStartDate() - { - if(!empty($this->start_date)) { - $value = clone $this->start_date; - $summit = $this->getSummit(); - if(!is_null($summit)) - { - $res = $summit->convertDateFromUTC2TimeZone($value); - } - return $res; - } - return null; - } - - /** - * @return \DateTime|null - */ - public function getStartDate() - { - return $this->start_date; - } - - /** - * @param DateTime $value - * @return $this - */ - public function setEndDate(DateTime $value) - { - $summit = $this->getSummit(); - if(!is_null($summit)) - { - $value = $summit->convertDateFromTimeZone2UTC($value); - } - $this->end_date = $value; - return $this; - } - - /** - * @return DateTime|null - */ - public function getLocalEndDate() - { - if(!empty($this->end_date)) { - $value = clone $this->end_date; - $summit = $this->getSummit(); - if(!is_null($summit)) - { - $res = $summit->convertDateFromUTC2TimeZone($value); - } - return $res; - } - return null; - } - - /** - * @return \DateTime|null - */ - public function getEndDate() - { - return $this->end_date; - } - - /** - * @param bool $allow_feeback - * @return $this - */ - public function setAllowFeedBack($allow_feeback) - { - $this->allow_feedback = $allow_feeback; - return $this; - } - /** * @return int */ @@ -571,12 +503,19 @@ class SummitEvent extends SilverstripeBaseModel { try { return !is_null($this->type) ? $this->type->getId() : 0; - } - catch(\Exception $ex){ + } catch (\Exception $ex) { return 0; } } + /** + * @return SummitEventType + */ + public function getType() + { + return $this->type; + } + /** * @param SummitEventType $type * @return $this @@ -587,24 +526,8 @@ class SummitEvent extends SilverstripeBaseModel return $this; } - /** - * @return SummitEventType - */ - public function getType(){ - return $this->type; - } - - /** - * @param SummitAbstractLocation $location - * @return $this - */ - public function setLocation(SummitAbstractLocation $location) + public function clearLocation() { - $this->location = $location; - return $this; - } - - public function clearLocation(){ $this->location = null; return $this; } @@ -617,12 +540,22 @@ class SummitEvent extends SilverstripeBaseModel return $this->location; } + /** + * @param SummitAbstractLocation $location + * @return $this + */ + public function setLocation(SummitAbstractLocation $location) + { + $this->location = $location; + return $this; + } + /** * @return array */ public function getSponsorsIds() { - return $this->sponsors->map(function($entity) { + return $this->sponsors->map(function ($entity) { return $entity->getId(); })->toArray(); } @@ -638,26 +571,27 @@ class SummitEvent extends SilverstripeBaseModel /** * @param Company $sponsor */ - public function addSponsor(Company $sponsor){ + public function addSponsor(Company $sponsor) + { $this->sponsors->add($sponsor); } - - public function clearSponsors(){ + public function clearSponsors() + { $this->sponsors->clear(); } - public function addFeedBack(SummitEventFeedback $feedback) { - $this->feedback->add($feedback); - $feedback->setEvent($this); + $this->feedback->add($feedback); + $feedback->setEvent($this); } /** * @return SummitEventFeedback[] */ - public function getFeedback(){ + public function getFeedback() + { $criteria = Criteria::create(); $criteria = $criteria->orderBy(['created' => Criteria::DESC]); return $this->feedback->matching($criteria); @@ -666,7 +600,8 @@ class SummitEvent extends SilverstripeBaseModel /** * @return ArrayCollection */ - public function getTags(){ + public function getTags() + { return $this->tags; } @@ -675,7 +610,7 @@ class SummitEvent extends SilverstripeBaseModel */ public function addTag(Tag $tag) { - if($this->tags->contains($tag)) return; + if ($this->tags->contains($tag)) return; $this->tags->add($tag); } @@ -685,35 +620,35 @@ class SummitEvent extends SilverstripeBaseModel } /** - * @throws ValidationException * @return void + * @throws ValidationException */ public function publish() { - if($this->isPublished()) + if ($this->isPublished()) throw new ValidationException('Already published Summit Event'); $start_date = $this->getStartDate(); - $end_date = $this->getEndDate(); + $end_date = $this->getEndDate(); - if((is_null($start_date) || is_null($end_date))) + if ((is_null($start_date) || is_null($end_date))) throw new ValidationException('To publish this event you must define a start/end datetime!'); $summit = $this->getSummit(); - if(is_null($summit)) + if (is_null($summit)) throw new ValidationException('To publish you must assign a summit'); $timezone = $summit->getTimeZoneId(); - if(empty($timezone)){ + if (empty($timezone)) { throw new ValidationException('Invalid Summit TimeZone!'); } - if($end_date < $start_date) + if ($end_date < $start_date) throw new ValidationException('start datetime must be greather or equal than end datetime!'); - if(!$summit->isEventInsideSummitDuration($this)) + if (!$summit->isEventInsideSummitDuration($this)) throw new ValidationException ( sprintf @@ -724,7 +659,7 @@ class SummitEvent extends SilverstripeBaseModel ) ); - $this->published = true; + $this->published = true; $this->published_date = new DateTime(); } @@ -741,58 +676,110 @@ class SummitEvent extends SilverstripeBaseModel */ public function getPublished() { - return (bool)$this->published; + return (bool)$this->published; } + /** + * @return \DateTime|null + */ + public function getStartDate() + { + return $this->start_date; + } + + /** + * @param DateTime $value + * @return $this + */ + public function setStartDate(DateTime $value) + { + $summit = $this->getSummit(); + if (!is_null($summit)) { + $value = $summit->convertDateFromTimeZone2UTC($value); + } + $this->start_date = $value; + return $this; + } + + public function setRawStartDate(DateTime $value){ + $this->start_date = $value; + } + + /** + * @return \DateTime|null + */ + public function getEndDate() + { + return $this->end_date; + } + + /** + * @param DateTime $value + * @return $this + */ + public function setEndDate(DateTime $value) + { + $summit = $this->getSummit(); + if (!is_null($summit)) { + $value = $summit->convertDateFromTimeZone2UTC($value); + } + $this->end_date = $value; + return $this; + } + + public function setRawEndDate(DateTime $value){ + $this->end_date = $value; + } /** * @return void */ public function unPublish() { - $this->published = false; + $this->published = false; $this->published_date = null; } - // events - - /** - * @var PreRemoveEventArgs - */ - private $pre_remove_events; /** * @ORM\PreRemove: */ - public function deleting($args){ + public function deleting($args) + { $this->pre_remove_events = new PreRemoveEventArgs ( [ - 'id' => $this->id, + 'id' => $this->id, 'class_name' => $this->getClassName(), - 'summit' => $this->summit, - 'published' => $this->isPublished(), + 'summit' => $this->summit, + 'published' => $this->isPublished(), ] ); } + /** + * @return string + */ + public function getClassName() + { + return "SummitEvent"; + } + /** * @ORM\PostRemove: */ - public function deleted($args){ + public function deleted($args) + { - if($this->summit->isDeleting()) return; - Event::fire(new SummitEventDeleted($this, $this->pre_remove_events )); + if (is_null($this->summit)) return; + if ($this->summit->isDeleting()) return; + Event::fire(new SummitEventDeleted($this, $this->pre_remove_events)); $this->pre_remove_events = null; } - /** - * @var PreUpdateEventArgs - */ - private $pre_update_args; - /** * @ORM\PreUpdate: */ - public function updating(PreUpdateEventArgs $args){ + public function updating(PreUpdateEventArgs $args) + { $this->pre_update_args = $args; } @@ -805,71 +792,16 @@ class SummitEvent extends SilverstripeBaseModel $this->pre_update_args = null; } + // events + /** * @ORM\PostPersist */ - public function inserted($args){ + public function inserted($args) + { Event::fire(new SummitEventCreated($this, $args)); } - public function hasMetricsAvailable(){ - if(is_null($this->location)) return false; - if(!$this->location instanceof SummitVenueRoom) return false; - return $this->location->getMetrics()->count() > 0; - } - - /** - * @return SummitEventMetricsSnapshot[] - */ - public function getMetricsSnapShots(){ - $snapshots = []; - if(is_null($this->location)) return $snapshots; - if(!$this->location instanceof SummitVenueRoom) return $snapshots; - foreach($this->location->getMetrics() as $metric){ - $snapshot = $this->getMetricsValuesByType($metric); - if(is_null($snapshot)) continue; - $snapshots[] = $snapshot; - } - return $snapshots; - } - - /** - * @param int $type_id - * @return SummitEventMetricsSnapshot - */ - public function getMetricValuesByTypeId($type_id){ - - $metrics = []; - if(is_null($this->location)) return $metrics; - if(!$this->location instanceof SummitVenueRoom) return $metrics; - - $metric_type = $this->location->getMetricsByType($type_id); - if(is_null($metric_type)) return $metrics; - if(!$metric_type instanceof RoomMetricType) return $metrics; - - return $this->getMetricsValuesByType($metric_type); - } - - /** - * @param RoomMetricType $type - * @return SummitEventMetricsSnapshot - */ - private function getMetricsValuesByType(RoomMetricType $type){ - - $epoch_start_date = $this->getStartDate()->getTimestamp(); - $epoch_end_date = $this->getEndDate()->getTimestamp(); - - return new SummitEventMetricsSnapshot - ( - $this, - $type, - $type->getMeanValueByTimeWindow($epoch_start_date, $epoch_end_date), - $type->getMaxValueByTimeWindow($epoch_start_date, $epoch_end_date), - $type->getMinValueByTimeWindow($epoch_start_date, $epoch_end_date), - $type->getCurrentValueByTimeWindow($epoch_start_date, $epoch_end_date) - ); - } - /** * @return ArrayCollection */ @@ -889,10 +821,31 @@ class SummitEvent extends SilverstripeBaseModel /** * @return string */ - public function getLocationName(){ + public function getLocationName() + { return $this->hasLocation() ? $this->location->getName() : 'TBD'; } + /** + * @return bool + */ + public function hasLocation() + { + return $this->getLocationId() > 0; + } + + /** + * @return int + */ + public function getLocationId() + { + try { + return !is_null($this->location) ? $this->location->getId() : 0; + } catch (\Exception $ex) { + return 0; + } + } + /** * @return int */ @@ -961,27 +914,46 @@ class SummitEvent extends SilverstripeBaseModel * @return string * @throws ValidationException */ - public function getCurrentRSVPSubmissionSeatType():string{ + public function getCurrentRSVPSubmissionSeatType(): string + { - if(!$this->hasRSVPTemplate()) + if (!$this->hasRSVPTemplate()) throw new ValidationException(sprintf("Event %s has not RSVP configured.", $this->id)); - if(!$this->getRSVPTemplate()->isEnabled()){ + if (!$this->getRSVPTemplate()->isEnabled()) { throw new ValidationException(sprintf("Event %s has not RSVP configured.", $this->id)); } $count_regular = $this->getRSVPSeatTypeCount(RSVP::SeatTypeRegular); - if($count_regular < intval($this->rsvp_max_user_number)) return RSVP::SeatTypeRegular; + if ($count_regular < intval($this->rsvp_max_user_number)) return RSVP::SeatTypeRegular; $count_wait = $this->getRSVPSeatTypeCount(RSVP::SeatTypeWaitList); - if($count_wait < intval($this->rsvp_max_user_wait_list_number)) return RSVP::SeatTypeWaitList; + if ($count_wait < intval($this->rsvp_max_user_wait_list_number)) return RSVP::SeatTypeWaitList; throw new ValidationException(sprintf("Event %s is Full.", $this->id)); } + /** + * @return RSVPTemplate + */ + public function getRSVPTemplate() + { + return $this->rsvp_template; + } + + /** + * @param RSVPTemplate $rsvp_template + */ + public function setRSVPTemplate(RSVPTemplate $rsvp_template) + { + $this->rsvp_template = $rsvp_template; + $this->rsvp_link = ''; + } + /** * @param string $seat_type * @return int */ - public function getRSVPSeatTypeCount(string $seat_type):int{ + public function getRSVPSeatTypeCount(string $seat_type): int + { $criteria = Criteria::create(); $criteria = $criteria->where(Criteria::expr()->eq('seat_type', $seat_type)); return $this->rsvp->matching($criteria)->count(); @@ -991,13 +963,16 @@ class SummitEvent extends SilverstripeBaseModel * @param string $seat_type * @return bool */ - public function couldAddSeatType(string $seat_type):bool{ - switch($seat_type){ - case RSVP::SeatTypeRegular: { + public function couldAddSeatType(string $seat_type): bool + { + switch ($seat_type) { + case RSVP::SeatTypeRegular: + { $count_regular = $this->getRSVPSeatTypeCount(RSVP::SeatTypeRegular); return $count_regular < intval($this->rsvp_max_user_number); } - case RSVP::SeatTypeWaitList: { + case RSVP::SeatTypeWaitList: + { $count_wait = $this->getRSVPSeatTypeCount(RSVP::SeatTypeWaitList); return $count_wait < intval($this->rsvp_max_user_wait_list_number); } @@ -1005,28 +980,31 @@ class SummitEvent extends SilverstripeBaseModel return false; } - public function getRSVPRegularCount():?int{ - return $this->getRSVPSeatTypeCount(RSVP::SeatTypeRegular); + public function getRSVPRegularCount(): ?int + { + return $this->getRSVPSeatTypeCount(RSVP::SeatTypeRegular); } - public function getRSVPWaitCount():?int{ - return $this->getRSVPSeatTypeCount(RSVP::SeatTypeWaitList); + public function getRSVPWaitCount(): ?int + { + return $this->getRSVPSeatTypeCount(RSVP::SeatTypeWaitList); } /** * @param RSVP $rsvp * @throws ValidationException */ - public function addRSVPSubmission(RSVP $rsvp){ - if(!$this->hasRSVPTemplate()){ + public function addRSVPSubmission(RSVP $rsvp) + { + if (!$this->hasRSVPTemplate()) { throw new ValidationException(sprintf("Event %s has not RSVP configured.", $this->id)); } - if(!$this->getRSVPTemplate()->isEnabled()){ + if (!$this->getRSVPTemplate()->isEnabled()) { throw new ValidationException(sprintf("Event %s has not RSVP configured.", $this->id)); } - if($this->rsvp->contains($rsvp)) return; + if ($this->rsvp->contains($rsvp)) return; $this->rsvp->add($rsvp); $rsvp->setEvent($this); } @@ -1034,8 +1012,9 @@ class SummitEvent extends SilverstripeBaseModel /** * @param RSVP $rsvp */ - public function removeRSVPSubmission(RSVP $rsvp){ - if(!$this->rsvp->contains($rsvp)) return; + public function removeRSVPSubmission(RSVP $rsvp) + { + if (!$this->rsvp->contains($rsvp)) return; $this->rsvp->removeElement($rsvp); $rsvp->clearEvent(); } @@ -1043,34 +1022,241 @@ class SummitEvent extends SilverstripeBaseModel /** * @return string */ - public function getStartDateNice():string + public function getDateNice(): string { - $start_date = $this->getLocalStartDate(); - if(empty($start_date)) return 'TBD'; + $start_date = $this->getStartDateNice(); + $end_date = $this->getEndDateNice(); + $date_nice = ''; + + if ($start_date == 'TBD' || $end_date == 'TBD') return $start_date; + + $date_nice = date('l, F j, g:ia', strtotime($start_date)) . '-' . date('g:ia', strtotime($end_date)); + return $date_nice; + } + + /** + * @return string + */ + public function getStartDateNice(): string + { + $start_date = $this->getLocalStartDate(); + if (empty($start_date)) return 'TBD'; return $start_date->format("Y-m-d H:i:s"); } /** - * @return string + * @return DateTime|null */ - public function getEndDateNice():string + public function getLocalStartDate() { - $end_date = $this->getLocalEndDate(); - if(empty($end_date)) return 'TBD'; - return $end_date->format("Y-m-d H:i:s"); + if (!empty($this->start_date)) { + $value = clone $this->start_date; + $summit = $this->getSummit(); + if (!is_null($summit)) { + $res = $summit->convertDateFromUTC2TimeZone($value); + } + return $res; + } + return null; } /** * @return string */ - public function getDateNice():string { - $start_date = $this->getStartDateNice(); - $end_date = $this->getEndDateNice(); - $date_nice = ''; + public function getEndDateNice(): string + { + $end_date = $this->getLocalEndDate(); + if (empty($end_date)) return 'TBD'; + return $end_date->format("Y-m-d H:i:s"); + } - if ($start_date == 'TBD' || $end_date == 'TBD') return $start_date; + /** + * @return DateTime|null + */ + public function getLocalEndDate() + { + if (!empty($this->end_date)) { + $value = clone $this->end_date; + $summit = $this->getSummit(); + if (!is_null($summit)) { + $res = $summit->convertDateFromUTC2TimeZone($value); + } + return $res; + } + return null; + } - $date_nice = date('l, F j, g:ia', strtotime($start_date)).'-'.date('g:ia', strtotime($end_date)); - return $date_nice; + /** + * @return bool + */ + public function isLive(): bool + { + return !empty($this->streaming_url); + } + + /** + * @return string + */ + public function getStreamingUrl(): ?string + { + return $this->streaming_url; + } + + /** + * @param string $streaming_url + */ + public function setStreamingUrl(?string $streaming_url): void + { + $this->streaming_url = $streaming_url; + } + + /** + * @return string + */ + public function getEtherpadLink(): ?string + { + return $this->etherpad_link; + } + + /** + * @param string $etherpad_link + */ + public function setEtherpadLink(?string $etherpad_link): void + { + $this->etherpad_link = $etherpad_link; + } + + /** + * @return string + */ + public function getMeetingUrl(): ?string + { + return $this->meeting_url; + } + + /** + * @param string $meeting_url + */ + public function setMeetingUrl(string $meeting_url): void + { + $this->meeting_url = $meeting_url; + } + + /** + * @param Member $member + * @return SummitEventAttendanceMetric + * @throws \Exception + */ + public function enter(Member $member){ + // check if we have one + $criteria = Criteria::create(); + $criteria = $criteria + ->where(Criteria::expr()->eq('member', $member)) + ->andWhere(Criteria::expr()->isNull("outgress_date")); + + $formerMetric = $this->attendance_metrics->matching($criteria)->first(); + + if($formerMetric and $formerMetric instanceof SummitEventAttendanceMetric){ + // mark as leave + $formerMetric->abandon(); + } + + $metric = SummitEventAttendanceMetric::build($member, $this); + $this->attendance_metrics->add($metric); + return $metric; + } + + /** + * @param Member $member + * @return mixed + * @throws ValidationException + */ + public function leave(Member $member){ + $criteria = Criteria::create(); + $criteria = $criteria + ->where(Criteria::expr()->eq('member', $member)) + ->andWhere(Criteria::expr()->isNull("outgress_date")) + ->orderBy(['ingress_date' => Criteria::DESC]); + + $metric = $this->attendance_metrics->matching($criteria)->first(); + if(!$metric) + throw new ValidationException(sprintf("User %s did not enter to event yet.", $member->getId())); + $metric->abandon(); + + return $metric; + } + + /** + * @return int + */ + public function getTotalAttendanceCount():int{ + return $this->attendance_metrics->count(); + } + + public function getAttendance(){ + return $this->attendance_metrics; + } + + /** + * @return int + */ + public function getCurrentAttendanceCount():int{ + $criteria = Criteria::create(); + $criteria = $criteria->where(Criteria::expr()->isNull('outgress_date')); + return $this->attendance_metrics->matching($criteria)->count(); + } + + public function getCurrentAttendance(){ + $criteria = Criteria::create(); + $criteria = $criteria->where(Criteria::expr()->isNull('outgress_date')); + return $this->attendance_metrics->matching($criteria)->toArray(); + } + + /** + * @return bool + */ + public function hasImage(){ + return $this->getImageId() > 0; + } + + /** + * @return int + */ + public function getImageId() + { + try{ + if(is_null($this->image)) return 0; + return $this->image->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + public function getImage():?File{ + return $this->image; + } + + /** + * @return string|null + */ + public function getImageUrl():?string{ + $photoUrl = null; + if($this->hasImage() && $photo = $this->getImage()){ + $photoUrl = $photo->getUrl(); + } + return $photoUrl; + } + + /** + * @param File $image + */ + public function setImage(File $image): void + { + $this->image = $image; + } + + public function clearImage():void{ + $this->image = null; } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/SummitEventAttendanceMetric.php b/app/Models/Foundation/Summit/Events/SummitEventAttendanceMetric.php new file mode 100644 index 00000000..923013af --- /dev/null +++ b/app/Models/Foundation/Summit/Events/SummitEventAttendanceMetric.php @@ -0,0 +1,158 @@ +ingress_date; + } + + /** + * @param \DateTime $ingress_date + */ + public function setIngressDate(\DateTime $ingress_date): void + { + $this->ingress_date = $ingress_date; + } + + /** + * @return \DateTime + */ + public function getOutgressDate(): ?\DateTime + { + return $this->outgress_date; + } + + /** + * @param \DateTime $outgress_date + */ + public function setOutgressDate(\DateTime $outgress_date): void + { + $this->outgress_date = $outgress_date; + } + + /** + * @return Member + */ + public function getMember(): Member + { + return $this->member; + } + + /** + * @param Member $member + */ + public function setMember(Member $member): void + { + $this->member = $member; + } + + /** + * @return SummitEvent + */ + public function getEvent(): SummitEvent + { + return $this->event; + } + + /** + * @param SummitEvent $event + */ + public function setEvent(SummitEvent $event): void + { + $this->event = $event; + } + + + public function __construct() + { + parent::__construct(); + } + + /** + * @param Member $member + * @param SummitEvent $event + * @return SummitEventAttendanceMetric + * @throws \Exception + */ + public static function build(Member $member, SummitEvent $event){ + $metric = new self(); + $metric->member = $member; + $metric->event = $event; + $metric->ingress_date = new \DateTime('now', new \DateTimeZone('UTC')); + return $metric; + } + + /** + * @throws ValidationException + */ + public function abandon(){ + if(is_null($this->ingress_date)) + throw new ValidationException('You must enter first.'); + $this->outgress_date = new \DateTime('now', new \DateTimeZone('UTC')); + } + + public function getMemberFirstName():?string{ + return $this->member->getFirstName(); + } + + public function getMemberLastName():?string{ + return $this->member->getLastName(); + } + + public function getMemberProfilePhotoUrl():?string{ + return $this->member->getProfilePhotoUrl(); + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Events/SummitEventType.php b/app/Models/Foundation/Summit/Events/SummitEventType.php index 96239884..6b32e440 100644 --- a/app/Models/Foundation/Summit/Events/SummitEventType.php +++ b/app/Models/Foundation/Summit/Events/SummitEventType.php @@ -11,6 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use Doctrine\Common\Collections\ArrayCollection; use models\utils\SilverstripeBaseModel; use Doctrine\ORM\Mapping AS ORM; /** @@ -72,6 +74,11 @@ class SummitEventType extends SilverstripeBaseModel */ protected $is_default; + /** + * @ORM\ManyToMany(targetEntity="SummitDocument", mappedBy="event_types") + */ + private $summit_documents; + /** * @return string */ @@ -223,6 +230,7 @@ class SummitEventType extends SilverstripeBaseModel $this->are_sponsors_mandatory = false; $this->allows_attachment = false; $this->is_private = false; + $this->summit_documents = new ArrayCollection(); } /** @@ -287,4 +295,21 @@ SQL; return $res; } + public function getSummitDocuments(){ + return $this->summit_documents; + } + + public function addSummitDocument(SummitDocument $doc){ + if($this->summit_documents->contains($doc)) return; + $this->summit_documents->add($doc); + } + + public function removeSummitDocument(SummitDocument $doc){ + if(!$this->summit_documents->contains($doc)) return; + $this->summit_documents->removeElement($doc); + } + + public function clearSummitDocuments(){ + $this->summit_documents->clear(); + } } diff --git a/app/Models/Foundation/Summit/Factories/PaymentGatewayProfileFactory.php b/app/Models/Foundation/Summit/Factories/PaymentGatewayProfileFactory.php new file mode 100644 index 00000000..e913fcdb --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/PaymentGatewayProfileFactory.php @@ -0,0 +1,83 @@ +setTestKeys([ + 'publishable_key' => $test_publishable_key, + 'secret_key' => $test_secret_key + ]); + + $live_publishable_key = $params['live_publishable_key'] ?? null; + $live_secret_key = $params['live_secret_key'] ?? null; + $profile->setLiveKeys( + [ + 'publishable_key' => $live_publishable_key, + 'secret_key' => $live_secret_key, + ] + ); + + $profile->setTestWebhookSecretKey($params['test_web_hook_secret'] ?? ''); + $profile->setLiveWebhookSecretKey($params['live_web_hook_secret'] ?? ''); + + if (isset($params['test_mode_enabled'])) + boolval($params['test_mode_enabled']) == true ? $profile->setTestMode() : $profile->setLiveMode(); + } + + // common properties + if (isset($params['application_type'])) + $profile->setApplicationType($params['application_type']); + + if (isset($params['active'])) + boolval(['active']) == true ? $profile->activate() : $profile->disable(); + + return $profile; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/PresentationCategoryFactory.php b/app/Models/Foundation/Summit/Factories/PresentationCategoryFactory.php index 38679598..6ca3fc4d 100644 --- a/app/Models/Foundation/Summit/Factories/PresentationCategoryFactory.php +++ b/app/Models/Foundation/Summit/Factories/PresentationCategoryFactory.php @@ -42,6 +42,9 @@ final class PresentationCategoryFactory if(isset($data['code']) && !empty($data['code'])) $track->setCode(trim($data['code'])); + if(isset($data['color'])) + $track->setColor(trim($data['color'])); + if(isset($data['description'])) $track->setDescription(trim($data['description'])); diff --git a/app/Models/Foundation/Summit/Factories/SponsorFactory.php b/app/Models/Foundation/Summit/Factories/SponsorFactory.php new file mode 100644 index 00000000..bd6dc1db --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SponsorFactory.php @@ -0,0 +1,44 @@ +setCompany($data['company']); + + if(isset($data['sponsorship'])) + $sponsor->setSponsorship($data['sponsorship']); + + return $sponsor; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SponsorshipTypeFactory.php b/app/Models/Foundation/Summit/Factories/SponsorshipTypeFactory.php new file mode 100644 index 00000000..3b316bb6 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SponsorshipTypeFactory.php @@ -0,0 +1,49 @@ +setLabel(trim($data['label'])); + + if(isset($data['name'])) + $sponsorship_type->setName(trim($data['name'])); + + if(isset($data['size'])) + $sponsorship_type->setSize(trim($data['size'])); + + return $sponsorship_type; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitAccessLevelTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitAccessLevelTypeFactory.php new file mode 100644 index 00000000..7f9a5a02 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitAccessLevelTypeFactory.php @@ -0,0 +1,50 @@ +setName(trim($data['name'])); + + if(isset($data['description'])) + $access_level->setDescription(trim($data['description'])); + + if(isset($data['template_content'])) + $access_level->setTemplateContent(trim($data['template_content'])); + + if(isset($data['is_default'])) + $access_level->setIsDefault(boolval($data['is_default'])); + + return $access_level; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitAttendeeFactory.php b/app/Models/Foundation/Summit/Factories/SummitAttendeeFactory.php index b1aee260..8de1facf 100644 --- a/app/Models/Foundation/Summit/Factories/SummitAttendeeFactory.php +++ b/app/Models/Foundation/Summit/Factories/SummitAttendeeFactory.php @@ -11,9 +11,14 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use Illuminate\Support\Facades\Log; +use models\exceptions\ValidationException; use models\main\Member; use models\summit\Summit; use models\summit\SummitAttendee; +use models\summit\SummitOrderExtraQuestionAnswer; +use models\summit\SummitOrderExtraQuestionType; +use models\summit\SummitOrderExtraQuestionTypeConstants; /** * Class SummitAttendeeFactory * @package models\summit\factories @@ -22,37 +27,115 @@ final class SummitAttendeeFactory { /** * @param Summit $summit - * @param Member $member - * @param array $data + * @param array $payload + * @param Member|null $member * @return SummitAttendee + * @throws ValidationException */ - public static function build(Summit $summit, Member $member, array $data){ - return self::updateMainData($summit, new SummitAttendee, $member, $data); + public static function build(Summit $summit, array $payload, ?Member $member = null) + { + return self::populate($summit, new SummitAttendee, $payload, $member); } /** * @param Summit $summit * @param SummitAttendee $attendee - * @param Member $member - * @param array $data + * @param array $payload + * @param Member|null $member * @return SummitAttendee + * @throws ValidationException */ - public static function updateMainData(Summit $summit, SummitAttendee $attendee, Member $member, array $data){ - $attendee->setMember($member); - $attendee->setSummit($summit); + public static function populate + ( + Summit $summit, + SummitAttendee $attendee, + array $payload, + ?Member $member = null + ) + { - if(isset($data['shared_contact_info'])) - $attendee->setShareContactInfo($data['shared_contact_info']); + if (!is_null($member)) + $attendee->setMember($member); - if(isset($data['summit_hall_checked_in'])) - $attendee->setSummitHallCheckedIn($data['summit_hall_checked_in']); + $summit->addAttendee($attendee); - if(isset($data['summit_hall_checked_in_date'])) + if(isset($payload['external_id'])) + $attendee->setExternalId(trim($payload['external_id'])); + + if(isset($payload['first_name'])) + $attendee->setFirstName(trim($payload['first_name'])); + + if (isset($payload['last_name'])) + $attendee->setSurname(trim($payload['last_name'])); + + if (isset($payload['email']) && !empty($payload['email'])) + $attendee->setEmail(trim($payload['email'])); + + if (isset($payload['company']) && !empty($payload['company'])) + $attendee->setCompanyName(trim($payload['company'])); + + if (isset($payload['shared_contact_info'])) + $attendee->setShareContactInfo(boolval($payload['shared_contact_info'])); + + if (isset($payload['summit_hall_checked_in'])) + $attendee->setSummitHallCheckedIn(boolval($payload['summit_hall_checked_in'])); + + if (isset($payload['summit_hall_checked_in_date']) && !empty($payload['summit_hall_checked_in_date'])) $attendee->setSummitHallCheckedInDate ( - new \DateTime(intval($data['summit_hall_checked_in_date'])) + new \DateTime(intval($payload['summit_hall_checked_in_date'])) ); + if (isset($payload['disclaimer_accepted']) && !empty($payload['disclaimer_accepted'])) { + $disclaimer_accepted = boolval($payload['disclaimer_accepted']); + if ($disclaimer_accepted && !$attendee->hasDisclaimerAccepted()) { + $attendee->setDisclaimerAcceptedDate + ( + new \DateTime('now', new \DateTimeZone('UTC')) + ); + } + } + + // extra questions + + $extra_questions = $payload['extra_questions'] ?? []; + + if (count($extra_questions)) { + + $mandatory_questions = $summit->getMandatoryOrderExtraQuestionsByUsage(SummitOrderExtraQuestionTypeConstants::TicketQuestionUsage); + if (count($extra_questions) < $mandatory_questions->count()) { + throw new ValidationException("You neglected to fill in all mandatory questions for the attendee."); + } + + $questions = $summit->getOrderExtraQuestionsByUsage(SummitOrderExtraQuestionTypeConstants::TicketQuestionUsage); + if ($questions->count() > 0) { + $attendee->clearExtraQuestionAnswers(); + foreach ($questions as $question) { + if (!$question instanceof SummitOrderExtraQuestionType) continue; + foreach ($extra_questions as $question_answer) { + if (intval($question_answer['question_id']) == $question->getId()) { + $value = trim($question_answer['answer']); + + if (empty($value) && $question->isMandatory()) + throw new ValidationException(sprintf('Question "%s" is mandatory', $question->getLabel())); + + if ($question->allowsValues() && !$question->allowValue($value)) { + Log::warning(sprintf("value %s is not allowed for question %s", $value, $question->getName())); + throw new ValidationException("The answer you provided is invalid"); + } + + $answer = new SummitOrderExtraQuestionAnswer(); + $answer->setQuestion($question); + $answer->setValue($value); + $attendee->addExtraQuestionAnswer($answer); + + break; + } + } + } + } + } + return $attendee; } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitAttendeeTicketFactory.php b/app/Models/Foundation/Summit/Factories/SummitAttendeeTicketFactory.php index 8f8958de..6bc258ae 100644 --- a/app/Models/Foundation/Summit/Factories/SummitAttendeeTicketFactory.php +++ b/app/Models/Foundation/Summit/Factories/SummitAttendeeTicketFactory.php @@ -29,6 +29,7 @@ final class SummitAttendeeTicketFactory */ public static function build(SummitAttendee $attendee, SummitTicketType $type, array $data){ $ticket = new SummitAttendeeTicket(); + $attendee->addTicket($ticket); if(isset($data['external_order_id'])) diff --git a/app/Models/Foundation/Summit/Factories/SummitBadgeFeatureTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitBadgeFeatureTypeFactory.php new file mode 100644 index 00000000..9a45c632 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitBadgeFeatureTypeFactory.php @@ -0,0 +1,49 @@ +setName(trim($data['name'])); + + if(isset($data['description'])) + $feature->setDescription(trim($data['description'])); + + if(isset($data['template_content'])) + $feature->setTemplateContent(trim($data['template_content'])); + + return $feature; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitBadgeTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitBadgeTypeFactory.php new file mode 100644 index 00000000..102ad4cb --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitBadgeTypeFactory.php @@ -0,0 +1,50 @@ +setName(trim($data['name'])); + + if(isset($data['description'])) + $badge_type->setDescription(trim($data['description'])); + + if(isset($data['template_content'])) + $badge_type->setTemplateContent(trim($data['template_content'])); + + if(isset($data['is_default'])) + $badge_type->setIsDefault(boolval($data['is_default'])); + + return $badge_type; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitDocumentFactory.php b/app/Models/Foundation/Summit/Factories/SummitDocumentFactory.php new file mode 100644 index 00000000..09100abc --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitDocumentFactory.php @@ -0,0 +1,46 @@ +setName(trim($payload['name'])); + if(isset($payload['label'])) + $document->setLabel(trim($payload['label'])); + if(isset($payload['description'])) + $document->setDescription(trim($payload['description'])); + return $document; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitFactory.php b/app/Models/Foundation/Summit/Factories/SummitFactory.php index 42c7fea5..d204409e 100644 --- a/app/Models/Foundation/Summit/Factories/SummitFactory.php +++ b/app/Models/Foundation/Summit/Factories/SummitFactory.php @@ -11,6 +11,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use models\exceptions\ValidationException; use models\summit\Summit; /** * Class SummitFactory @@ -57,10 +59,6 @@ final class SummitFactory $summit->setDatesLabel(trim($data['dates_label'])); } - if(isset($data['external_summit_id']) ){ - $summit->setExternalSummitId(trim($data['external_summit_id'])); - } - if(isset($data['calendar_sync_name']) ){ $summit->setCalendarSyncName(trim($data['calendar_sync_name'])); } @@ -69,53 +67,101 @@ final class SummitFactory $summit->setCalendarSyncDesc(trim($data['calendar_sync_desc'])); } + // BOOKING PERIOD if(array_key_exists('begin_allow_booking_date', $data) && array_key_exists('end_allow_booking_date', $data)) { if (isset($data['begin_allow_booking_date']) && isset($data['end_allow_booking_date'])) { - $start_datetime = intval($data['begin_allow_booking_date']); - $start_datetime = new \DateTime("@$start_datetime"); - $start_datetime->setTimezone($summit->getTimeZone()); - $end_datetime = intval($data['end_allow_booking_date']); - $end_datetime = new \DateTime("@$end_datetime"); - $end_datetime->setTimezone($summit->getTimeZone()); - // set local time from UTC - $summit->setBeginAllowBookingDate($start_datetime); - $summit->setEndAllowBookingDate($end_datetime); + $val1 = intval($data['begin_allow_booking_date']); + if($val1 > 0) { + $start_datetime = new \DateTime("@$val1"); + $start_datetime->setTimezone($summit->getTimeZone()); + // set local time from UTC + $summit->setBeginAllowBookingDate($start_datetime); + } + else{ + $summit->clearAllowBookingDates(); + } + + $val2 = intval($data['end_allow_booking_date']); + if($val2 > 0) { + $end_datetime = new \DateTime("@$val2"); + $end_datetime->setTimezone($summit->getTimeZone()); + // set local time from UTC + $summit->setEndAllowBookingDate($end_datetime); + } + else{ + $summit->clearAllowBookingDates(); + } } else{ $summit->clearAllowBookingDates(); } } - + // SUMMIT PERIOD if(array_key_exists('start_date', $data) && array_key_exists('end_date', $data)) { if (isset($data['start_date']) && isset($data['end_date'])) { - $start_datetime = intval($data['start_date']); - $start_datetime = new \DateTime("@$start_datetime"); - $start_datetime->setTimezone($summit->getTimeZone()); - $end_datetime = intval($data['end_date']); - $end_datetime = new \DateTime("@$end_datetime"); - $end_datetime->setTimezone($summit->getTimeZone()); - // set local time from UTC - $summit->setBeginDate($start_datetime); - $summit->setEndDate($end_datetime); + $val1 = intval($data['start_date']); + if($val1 > 0) { + $start_datetime = new \DateTime("@$val1"); + $start_datetime->setTimezone($summit->getTimeZone()); + // set local time from UTC + $summit->setBeginDate($start_datetime); + } + else{ + $summit->clearBeginEndDates(); + } + + $val2 = intval($data['end_date']); + if($val2 > 0) { + $end_datetime = new \DateTime("@$val2"); + $end_datetime->setTimezone($summit->getTimeZone()); + // set local time from UTC + $summit->setEndDate($end_datetime); + } + else{ + $summit->clearBeginEndDates(); + } } else{ $summit->clearBeginEndDates(); } } + // REGISTRATION PERIOD if(array_key_exists('registration_begin_date', $data) && array_key_exists('registration_end_date', $data)) { if (isset($data['registration_begin_date']) && isset($data['registration_end_date'])) { - $start_datetime = intval($data['registration_begin_date']); - $start_datetime = new \DateTime("@$start_datetime"); - $start_datetime->setTimezone($summit->getTimeZone()); - $end_datetime = intval($data['registration_end_date']); - $end_datetime = new \DateTime("@$end_datetime"); - $end_datetime->setTimezone($summit->getTimeZone()); - // set local time from UTC - $summit->setRegistrationBeginDate($start_datetime); - $summit->setRegistrationEndDate($end_datetime); + $val1 = intval($data['registration_begin_date']); + + if($val1 > 0) { + $start_datetime = new \DateTime("@$val1"); + $start_datetime->setTimezone($summit->getTimeZone()); + // set local time from UTC + $summit->setRegistrationBeginDate($start_datetime); + } + else{ + $summit->clearRegistrationDates(); + } + + $val2 = intval($data['registration_end_date']); + if($val2 > 0) { + $end_datetime = new \DateTime("@$val2"); + $end_datetime->setTimezone($summit->getTimeZone()); + // set local time from UTC + $summit->setRegistrationEndDate($end_datetime); + + $summit_end_date = $summit->getLocalEndDate(); + + if(!is_null($summit_end_date)){ + // registration end date could be after summit end date due people could get registered after summit is end + // to obtain access to summit content ( mainly for virtual events) + if($start_datetime > $summit_end_date) + throw new ValidationException("The Registration Begin Date cannot be after the Summit End Date."); + } + } + else{ + $summit->clearRegistrationDates(); + } } else{ $summit->clearRegistrationDates(); @@ -124,26 +170,57 @@ final class SummitFactory if(array_key_exists('start_showing_venues_date', $data)){ if (isset($data['start_showing_venues_date'])) { - $start_datetime = intval($data['start_showing_venues_date']); - $start_datetime = new \DateTime("@$start_datetime"); - $start_datetime->setTimezone($summit->getTimeZone()); - - // set local time from UTC - $summit->setStartShowingVenuesDate($start_datetime); + $val = intval($data['start_showing_venues_date']); + if($val > 0) { + $start_datetime = new \DateTime("@$val"); + $start_datetime->setTimezone($summit->getTimeZone()); + // set local time from UTC + $summit->setStartShowingVenuesDate($start_datetime); + } + else{ + $summit->clearStartShowingVenuesDate(); + } } else{ $summit->clearStartShowingVenuesDate(); } } + if(array_key_exists('reassign_ticket_till_date', $data)){ + if (isset($data['reassign_ticket_till_date'])) { + + $val = intval($data['reassign_ticket_till_date']); + if($val > 0) { + $date = new \DateTime("@$val"); + $date->setTimezone($summit->getTimeZone()); + + + // set local time from UTC + $summit->setReassignTicketTillDate($date); + } + else + { + $summit->clearReassignTicketTillDate(); + } + } + else{ + $summit->clearReassignTicketTillDate(); + } + } + if(array_key_exists('schedule_start_date', $data)) { if (isset($data['schedule_start_date'])) { - $start_datetime = intval($data['schedule_start_date']); - $start_datetime = new \DateTime("@$start_datetime"); - $start_datetime->setTimezone($summit->getTimeZone()); + $val = intval($data['schedule_start_date']); + if($val > 0) { + $start_datetime = new \DateTime("@$val"); + $start_datetime->setTimezone($summit->getTimeZone()); - // set local time from UTC - $summit->setScheduleDefaultStartDate($start_datetime); + // set local time from UTC + $summit->setScheduleDefaultStartDate($start_datetime); + } + else{ + $summit->clearScheduleDefaultStartDate(); + } } else{ $summit->clearScheduleDefaultStartDate(); @@ -154,6 +231,26 @@ final class SummitFactory $summit->setLink(trim($data['link'])); } + if(isset($data['registration_disclaimer_mandatory']) ){ + $registration_disclaimer_mandatory = boolval($data['registration_disclaimer_mandatory']); + $summit->setRegistrationDisclaimerMandatory($registration_disclaimer_mandatory); + if($registration_disclaimer_mandatory){ + + $registration_disclaimer_content = $data['registration_disclaimer_content'] ?? ''; + if(empty($registration_disclaimer_content)){ + throw new ValidationException("registration_disclaimer_content is mandatory"); + } + } + } + + if(isset($data['registration_disclaimer_content'])){ + $summit->setRegistrationDisclaimerContent(trim($data['registration_disclaimer_content'])); + } + + if(isset($data['link']) ){ + $summit->setLink(trim($data['link'])); + } + if(isset($data['slug']) ){ $summit->setRawSlug(trim($data['slug'])); } @@ -185,12 +282,17 @@ final class SummitFactory $summit->setMeetingRoomBookingSlotLength(intval($data['meeting_room_booking_slot_length'])); } + if(isset($data['registration_reminder_email_days_interval']) ){ + // days + $summit->setRegistrationReminderEmailDaysInterval(intval($data['registration_reminder_email_days_interval'])); + } + if(isset($data['meeting_room_booking_max_allowed']) ){ // maximun books per user $summit->setMeetingRoomBookingMaxAllowed(intval($data['meeting_room_booking_max_allowed'])); } - // external feed + // external schedule feed if(isset($data['api_feed_type'])){ $summit->setApiFeedType($data['api_feed_type']); @@ -270,6 +372,52 @@ final class SummitFactory $summit->setScheduleTwitterText(trim($data['schedule_twitter_text'])); } + // external registration feed + + if(isset($data['external_summit_id']) ){ + $summit->setExternalSummitId(trim($data['external_summit_id'])); + } + + if(isset($data['external_registration_feed_type']) ){ + $summit->setExternalRegistrationFeedType(trim($data['external_registration_feed_type'])); + } + + if(isset($data['external_registration_feed_api_key']) ){ + $summit->setExternalRegistrationFeedApiKey(trim($data['external_registration_feed_api_key'])); + } + + $summit->generateRegistrationSlugPrefix(); + + // urls + + if(isset($data['default_page_url']) ){ + $summit->setDefaultPageUrl(trim($data['default_page_url'])); + } + + if(isset($data['speaker_confirmation_default_page_url']) ){ + $summit->setSpeakerConfirmationDefaultPageUrl(trim($data['speaker_confirmation_default_page_url'])); + } + + if(isset($data['virtual_site_url']) ){ + $summit->setVirtualSiteUrl(trim($data['virtual_site_url'])); + } + + if(isset($data['marketing_site_url']) ){ + $summit->setMarketingSiteUrl(trim($data['marketing_site_url'])); + } + + if(isset($data['virtual_site_oauth2_client_id']) ){ + $summit->setVirtualSiteOAuth2ClientId(trim($data['virtual_site_oauth2_client_id'])); + } + + if(isset($data['marketing_site_oauth2_client_id']) ){ + $summit->setMarketingSiteOAuth2ClientId(trim($data['marketing_site_oauth2_client_id'])); + } + + if(isset($data['support_email']) ){ + $summit->setSupportEmail(trim($data['support_email'])); + } + return $summit; } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitMediaFileTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitMediaFileTypeFactory.php new file mode 100644 index 00000000..b900beff --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitMediaFileTypeFactory.php @@ -0,0 +1,40 @@ +setName(trim($data['name'])); + } + if(isset($data['description'])){ + $type->setDescription(trim($data['description'])); + } + if(isset($data['allowed_extensions'])){ + $allowed_extensions = implode('|', $data['allowed_extensions']); + $type->setAllowedExtensions($allowed_extensions); + } + $type->markAsUserDefined(); + return $type; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitMediaUploadTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitMediaUploadTypeFactory.php new file mode 100644 index 00000000..1ba68d77 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitMediaUploadTypeFactory.php @@ -0,0 +1,59 @@ +setName(trim($data['name'])); + + if(isset($data['description'])) + $type->setDescription(trim($data['description'])); + + if(isset($data['max_size'])) + $type->setMaxSize(intval($data['max_size'])); + + if(isset($data['private_storage_type'])) + $type->setPrivateStorageType(trim($data['private_storage_type'])); + + if(isset($data['public_storage_type'])) + $type->setPublicStorageType(trim($data['public_storage_type'])); + + if(isset($data['is_mandatory'])) + if(boolval($data['is_mandatory'])) + $type->markAsMandatory(); + else + $type->markAsOptional(); + + return $type; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitOrderExtraQuestionTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitOrderExtraQuestionTypeFactory.php new file mode 100644 index 00000000..a3fb7eb9 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitOrderExtraQuestionTypeFactory.php @@ -0,0 +1,60 @@ +setName(trim($data['name'])); + + if(isset($data['label'])) + $question->setLabel(trim($data['label'])); + + if(isset($data['type'])) + $question->setType(trim($data['type'])); + + if(isset($data['usage'])) + $question->setUsage(trim($data['usage'])); + + if(isset($data['printable'])) + $question->setPrintable(boolval($data['printable'])); + + if(isset($data['placeholder'])) + $question->setPlaceholder(trim($data['placeholder'])); + + if(isset($data['mandatory'])) + $question->setMandatory(boolval($data['mandatory'])); + + + return $question; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitOrderExtraQuestionValueFactory.php b/app/Models/Foundation/Summit/Factories/SummitOrderExtraQuestionValueFactory.php new file mode 100644 index 00000000..71e5c6b3 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitOrderExtraQuestionValueFactory.php @@ -0,0 +1,44 @@ +setLabel(trim($data['label'])); + + if(isset($data['value'])) + $value->setValue(trim($data['value'])); + + return $value; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitOrderFactory.php b/app/Models/Foundation/Summit/Factories/SummitOrderFactory.php new file mode 100644 index 00000000..98d71771 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitOrderFactory.php @@ -0,0 +1,126 @@ +setSummit($summit); + + if(isset($payload['external_id'])) + $order->setExternalId(trim($payload['external_id'])); + + if(isset($payload['owner_first_name']) && !is_null($payload['owner_first_name'])) + $order->setOwnerFirstName(trim($payload['owner_first_name'])); + + if (isset($payload['owner_last_name']) && !is_null($payload['owner_last_name'])) + $order->setOwnerSurname(trim($payload['owner_last_name'])); + + if (isset($payload['owner_email']) && !is_null($payload['owner_email'])) + $order->setOwnerEmail(trim($payload['owner_email'])); + + if (isset($payload['owner_company']) && !is_null($payload['owner_company'])) + $order->setOwnerCompany(trim($payload['owner_company'])); + + if (isset($payload['billing_address_1']) && !is_null($payload['billing_address_1'])) + $order->setBillingAddress1(trim($payload['billing_address_1'])); + + if (isset($payload['billing_address_2']) && !is_null($payload['billing_address_2'])) + $order->setBillingAddress2(trim($payload['billing_address_2'])); + + if (isset($payload['billing_address_city']) && !is_null($payload['billing_address_city'])) + $order->setBillingAddressCity(trim($payload['billing_address_city'])); + + if (isset($payload['billing_address_zip_code']) && !is_null($payload['billing_address_zip_code'])) + $order->setBillingAddressZipCode(trim($payload['billing_address_zip_code'])); + + if (isset($payload['billing_address_state']) && !is_null($payload['billing_address_state'])) + $order->setBillingAddressState(trim($payload['billing_address_state'])); + + if (isset($payload['billing_address_country']) && !is_null($payload['billing_address_country'])) + $order->setBillingAddressCountryIsoCode(trim($payload['billing_address_country'])); + + // extra questions + + $extra_questions = $payload['extra_questions'] ?? []; + + if (count($extra_questions) > 0) { + $mandatory_questions = $summit->getMandatoryOrderExtraQuestionsByUsage(SummitOrderExtraQuestionTypeConstants::OrderQuestionUsage); + + if (count($extra_questions) < $mandatory_questions->count()) { + throw new ValidationException("You neglected to fill in all mandatory questions for the order."); + } + + $questions = $summit->getOrderExtraQuestionsByUsage(SummitOrderExtraQuestionTypeConstants::OrderQuestionUsage); + + if ($questions->count() > 0) { + $order->clearExtraQuestionAnswers(); + foreach ($questions as $question) { + if (!$question instanceof SummitOrderExtraQuestionType) continue; + foreach ($extra_questions as $question_answer) { + if (intval($question_answer['question_id']) == $question->getId()) { + + $value = trim($question_answer['answer']); + if (empty($value) && $question->isMandatory()) + throw new ValidationException(sprintf('Question "%s" is mandatory', $question->getLabel())); + + if ($question->allowsValues() && !$question->allowValue($value)) { + Log::warning(sprintf("value %s is not allowed for question %s", $value, $question->getName())); + throw new ValidationException("The answer you provided is invalid"); + } + + $answer = new SummitOrderExtraQuestionAnswer(); + $answer->setQuestion($question); + $answer->setValue($value); + $order->addExtraQuestionAnswer($answer); + + break; + } + } + } + } + } + + return $order; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitPromoCodeFactory.php b/app/Models/Foundation/Summit/Factories/SummitPromoCodeFactory.php index 035cbe7e..6fa1df18 100644 --- a/app/Models/Foundation/Summit/Factories/SummitPromoCodeFactory.php +++ b/app/Models/Foundation/Summit/Factories/SummitPromoCodeFactory.php @@ -11,10 +11,14 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use models\summit\MemberSummitRegistrationDiscountCode; use models\summit\MemberSummitRegistrationPromoCode; +use models\summit\SpeakerSummitRegistrationDiscountCode; use models\summit\SpeakerSummitRegistrationPromoCode; +use models\summit\SponsorSummitRegistrationDiscountCode; use models\summit\SponsorSummitRegistrationPromoCode; use models\summit\Summit; +use models\summit\SummitRegistrationDiscountCode; use models\summit\SummitRegistrationPromoCode; /** * Class SummitPromoCodeFactory @@ -31,6 +35,14 @@ final class SummitPromoCodeFactory public static function build(Summit $summit, array $data, array $params = []){ $promo_code = null; switch ($data['class_name']){ + case SummitRegistrationPromoCode::ClassName:{ + $promo_code = new SummitRegistrationPromoCode(); + } + break; + case SummitRegistrationDiscountCode::ClassName:{ + $promo_code = new SummitRegistrationDiscountCode(); + } + break; case MemberSummitRegistrationPromoCode::ClassName:{ $promo_code = new MemberSummitRegistrationPromoCode(); } @@ -43,6 +55,18 @@ final class SummitPromoCodeFactory $promo_code = new SponsorSummitRegistrationPromoCode(); } break; + case MemberSummitRegistrationDiscountCode::ClassName:{ + $promo_code = new MemberSummitRegistrationDiscountCode(); + } + break; + case SpeakerSummitRegistrationDiscountCode::ClassName:{ + $promo_code = new SpeakerSummitRegistrationDiscountCode(); + } + break; + case SponsorSummitRegistrationDiscountCode::ClassName:{ + $promo_code = new SponsorSummitRegistrationDiscountCode(); + } + break; } if(is_null($promo_code)) return null; @@ -57,7 +81,66 @@ final class SummitPromoCodeFactory * @return SummitRegistrationPromoCode */ public static function populate(SummitRegistrationPromoCode $promo_code, Summit $summit, array $data, array $params = []){ + + // common members + + if(isset($params['badge_type'])) + $promo_code->setBadgeType($params['badge_type']); + + if(isset($params['allowed_ticket_types'])){ + foreach ($params['allowed_ticket_types'] as $ticket_type){ + $promo_code->addAllowedTicketType($ticket_type); + } + } + + if(isset($params['badge_features'])){ + foreach ($params['badge_features'] as $feature){ + $promo_code->addBadgeFeatureType($feature); + } + } + + if(isset($data['external_id'])){ + $promo_code->setExternalId(trim($params['external_id'])); + } + + if(isset($data['code'])) + $promo_code->setCode(trim($data['code'])); + + if(isset($data['quantity_available'])) + $promo_code->setQuantityAvailable(intval($data['quantity_available'])); + + if(isset($data['valid_since_date'])) { + $val = intval($data['valid_since_date']); + if($val > 0) { + $val = new \DateTime("@$val"); + $val->setTimezone($summit->getTimeZone()); + $promo_code->setValidSinceDate($summit->convertDateFromTimeZone2UTC($val)); + } + else{ + $promo_code->setValidSinceDate(null); + } + } + + if(isset($data['valid_until_date'])) { + $val = intval($data['valid_until_date']); + if($val > 0) { + $val = new \DateTime("@$val"); + $val->setTimezone($summit->getTimeZone()); + $promo_code->setValidUntilDate($summit->convertDateFromTimeZone2UTC($val)); + } + else{ + $promo_code->setValidUntilDate(null); + } + } + switch ($data['class_name']){ + case SummitRegistrationDiscountCode::ClassName:{ + if(isset($data['amount'])) + $promo_code->setAmount(floatval($data['amount'])); + if(isset($data['rate'])) + $promo_code->setRate(floatval($data['rate'])); + } + break; case MemberSummitRegistrationPromoCode::ClassName:{ if(isset($params['owner'])) $promo_code->setOwner($params['owner']); @@ -70,20 +153,83 @@ final class SummitPromoCodeFactory if(isset($data['email'])) $promo_code->setEmail(trim($data['email'])); } - break; + break; case SpeakerSummitRegistrationPromoCode::ClassName:{ if(isset($data['type'])) $promo_code->setType($data['type']); - $promo_code->setSpeaker($params['speaker']); + if(isset($params['speaker'])) + $promo_code->setSpeaker($params['speaker']); + } + break; + case SponsorSummitRegistrationPromoCode::ClassName:{ + + if(isset($params['owner'])) + $promo_code->setOwner($params['owner']); + if(isset($data['type'])) + $promo_code->setType($data['type']); + if(isset($data['first_name'])) + $promo_code->setFirstName(trim($data['first_name'])); + if(isset($data['last_name'])) + $promo_code->setLastName(trim($data['last_name'])); + if(isset($data['email'])) + $promo_code->setEmail(trim($data['email'])); + + $promo_code->setSponsor($params['sponsor']); + } + break; + case MemberSummitRegistrationDiscountCode::ClassName:{ + if(isset($params['owner'])) + $promo_code->setOwner($params['owner']); + if(isset($data['type'])) + $promo_code->setType($data['type']); + if(isset($data['first_name'])) + $promo_code->setFirstName(trim($data['first_name'])); + if(isset($data['last_name'])) + $promo_code->setLastName(trim($data['last_name'])); + if(isset($data['email'])) + $promo_code->setEmail(trim($data['email'])); + if(isset($data['amount'])) + $promo_code->setAmount(floatval($data['amount'])); + if(isset($data['rate'])) + $promo_code->setRate(floatval($data['rate'])); } break; - case SponsorSummitRegistrationPromoCode::ClassName:{ - $promo_code->setSponsor($params['sponsor']); + case SpeakerSummitRegistrationDiscountCode::ClassName:{ + if(isset($data['type'])) + $promo_code->setType($data['type']); + if(isset($params['speaker'])) + $promo_code->setSpeaker($params['speaker']); + if(isset($data['amount'])) + $promo_code->setAmount(floatval($data['amount'])); + if(isset($data['rate'])) + $promo_code->setRate(floatval($data['rate'])); + } + break; + case SponsorSummitRegistrationDiscountCode::ClassName:{ + if(isset($params['owner'])) + $promo_code->setOwner($params['owner']); + if(isset($data['type'])) + $promo_code->setType($data['type']); + if(isset($data['first_name'])) + $promo_code->setFirstName(trim($data['first_name'])); + if(isset($data['last_name'])) + $promo_code->setLastName(trim($data['last_name'])); + if(isset($data['email'])) + $promo_code->setEmail(trim($data['email'])); + if(isset($data['amount'])) + $promo_code->setAmount(floatval($data['amount'])); + if(isset($data['rate'])) + $promo_code->setRate(floatval($data['rate'])); + if(isset($params['sponsor'])) + $promo_code->setSponsor($params['sponsor']); + if(isset($data['amount'])) + $promo_code->setAmount(floatval($data['amount'])); + if(isset($data['rate'])) + $promo_code->setRate(floatval($data['rate'])); } break; } - $promo_code->setCode(trim($data['code'])); $summit->addPromoCode($promo_code); return $promo_code; } diff --git a/app/Models/Foundation/Summit/Factories/SummitRefundPolicyTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitRefundPolicyTypeFactory.php new file mode 100644 index 00000000..1fa3a414 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitRefundPolicyTypeFactory.php @@ -0,0 +1,47 @@ +setName(trim($data['name'])); + + if(isset($data['refund_rate'])) + $policy->setRefundRate(floatval($data['refund_rate'])); + + if(isset($data['until_x_days_before_event_starts'])) + $policy->setUntilXDaysBeforeEventStarts(intval($data['until_x_days_before_event_starts'])); + + return $policy; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitRegistrationDiscountCodeTicketTypeRuleFactory.php b/app/Models/Foundation/Summit/Factories/SummitRegistrationDiscountCodeTicketTypeRuleFactory.php new file mode 100644 index 00000000..b96ee8ca --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitRegistrationDiscountCodeTicketTypeRuleFactory.php @@ -0,0 +1,44 @@ +setAmount(floatval($data['amount'])); + if(isset($data['rate'])) + $rule->setRate(floatval($data['rate'])); + if(isset($data['ticket_type'])) + $rule->setTicketType($data['ticket_type']); + return $rule; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitRegistrationInvitationFactory.php b/app/Models/Foundation/Summit/Factories/SummitRegistrationInvitationFactory.php new file mode 100644 index 00000000..8683f624 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitRegistrationInvitationFactory.php @@ -0,0 +1,44 @@ +setEmail(trim($data['email'])); + if(isset($data['first_name'])){ + $invitation->setFirstName(trim($data['first_name'])); + } + if(isset($data['last_name'])){ + $invitation->setLastName(trim($data['last_name'])); + } + return $invitation; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitTaxTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitTaxTypeFactory.php new file mode 100644 index 00000000..ad981f59 --- /dev/null +++ b/app/Models/Foundation/Summit/Factories/SummitTaxTypeFactory.php @@ -0,0 +1,47 @@ +setName(trim($data['name'])); + + if(isset($data['tax_id'])) + $tax_type->setTaxId(trim($data['tax_id'])); + + if(isset($data['rate'])) + $tax_type->setRate(floatval($data['rate'])); + + return $tax_type; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Factories/SummitTicketTypeFactory.php b/app/Models/Foundation/Summit/Factories/SummitTicketTypeFactory.php index 067a86c9..ac8d534f 100644 --- a/app/Models/Foundation/Summit/Factories/SummitTicketTypeFactory.php +++ b/app/Models/Foundation/Summit/Factories/SummitTicketTypeFactory.php @@ -11,6 +11,9 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use models\exceptions\ValidationException; +use models\summit\Summit; use models\summit\SummitTicketType; /** * Class SummitTicketTypeFactory @@ -20,10 +23,12 @@ final class SummitTicketTypeFactory { /** * @param array $data - * @return SummitTicketTypeFactory + * @return SummitTicketType */ - public static function build(array $data){ - return self::populate(new SummitTicketType, $data); + public static function build(Summit $summit,array $data){ + $ticket_type = new SummitTicketType; + $ticket_type->setSummit($summit); + return self::populate($ticket_type, $data); } /** @@ -42,6 +47,71 @@ final class SummitTicketTypeFactory if(isset($data['external_id'])) $ticket_type->setExternalId(trim($data['external_id'])); + if(isset($data['cost'])) + $ticket_type->setCost(floatval($data['cost'])); + + if(isset($data['currency'])) + $ticket_type->setCurrency(trim($data['currency'])); + + if(isset($data['quantity_2_sell'])) + $ticket_type->setQuantity2Sell(intval($data['quantity_2_sell'])); + + if(isset($data['max_quantity_per_order'])) + $ticket_type->setMaxQuantityPerOrder(intval($data['max_quantity_per_order'])); + + // Sales Period + if(isset($data['sales_start_date'])){ + $val = intval($data['sales_start_date']); + if($val > 0) { + // we need a registration period defined to set this + $summit = $ticket_type->getSummit(); + if(is_null($summit)){ + throw new ValidationException("Summit is not defined."); + } + if(!$summit->isRegistrationPeriodDefined()) + throw new ValidationException("Summit Registration Period is not defined."); + + $val = new \DateTime("@$val"); + $val->setTimezone($summit->getTimeZone()); + $ticket_type->setSalesStartDate($summit->convertDateFromTimeZone2UTC($val)); + + if(!$summit->isDateOnRegistrationPeriod($ticket_type->getSalesStartDate())){ + throw new ValidationException(sprintf("Ticket Type Sales Start Date is not under Summit Registration Period")); + } + } + else{ + $ticket_type->clearSalesStartDate(); + } + } + + if(isset($data['sales_end_date'])){ + $val = intval($data['sales_end_date']); + if($val > 0) { + // we need a registration period defined to set this + $summit = $ticket_type->getSummit(); + if(is_null($summit)){ + throw new ValidationException("Summit is not defined."); + } + + if(!$summit->isRegistrationPeriodDefined()) + throw new ValidationException("Summit Registration Period is not defined."); + + $val = new \DateTime("@$val"); + $val->setTimezone($summit->getTimeZone()); + $ticket_type->setSalesEndDate($summit->convertDateFromTimeZone2UTC($val)); + + if(!$summit->isDateOnRegistrationPeriod($ticket_type->getSalesEndDate())){ + throw new ValidationException(sprintf("Ticket Type Sales End Date is not under Summit Registration Period")); + } + } + else{ + $ticket_type->clearSalesEndDate(); + } + } + + if(isset($data['badge_type'])) + $ticket_type->setBadgeType($data['badge_type']); + return $ticket_type; } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/ISponsorshipTypeConstants.php b/app/Models/Foundation/Summit/ISponsorshipTypeConstants.php new file mode 100644 index 00000000..48a3f442 --- /dev/null +++ b/app/Models/Foundation/Summit/ISponsorshipTypeConstants.php @@ -0,0 +1,33 @@ +timestamp; - } - - /** - * @param int $timestamp - */ - public function setTimestamp($timestamp) - { - $this->timestamp = $timestamp; - } - - /** - * @return float - */ - public function getValue() - { - return $this->value; - } - - /** - * @param float $value - */ - public function setValue($value) - { - $this->value = $value; - } - - /** - * @return RoomMetricType - */ - public function getType() - { - return $this->type; - } - - /** - * @param RoomMetricType $type - */ - public function setType($type) - { - $this->type = $type; - } -} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Locations/Metrics/RoomMetricType.php b/app/Models/Foundation/Summit/Locations/Metrics/RoomMetricType.php deleted file mode 100644 index f8321002..00000000 --- a/app/Models/Foundation/Summit/Locations/Metrics/RoomMetricType.php +++ /dev/null @@ -1,200 +0,0 @@ -samples = new ArrayCollection(); - } - - /** - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * @param string $type - */ - public function setType($type) - { - $this->type = $type; - } - - /** - * @return string - */ - public function getEndpoint() - { - return $this->endpoint; - } - - /** - * @param string $endpoint - */ - public function setEndpoint($endpoint) - { - $this->endpoint = $endpoint; - } - - /** - * @return SummitVenueRoom - */ - public function getRoom() - { - return $this->room; - } - - /** - * @param SummitVenueRoom $room - */ - public function setRoom($room) - { - $this->room = $room; - } - - /** - * @return ArrayCollection - */ - public function getSamples() - { - return $this->samples; - } - - /** - * @param ArrayCollection $samples - */ - public function setSamples($samples) - { - $this->samples = $samples; - } - - /** - * @param int $epoch_start_date - * @param int $epoch_end_date - * @return float - */ - public function getMaxValueByTimeWindow($epoch_start_date, $epoch_end_date){ - $samples = $this->getValuesByTimeWindow($epoch_start_date, $epoch_end_date, 'value', Criteria::DESC); - $max = count($samples) > 0 ? $samples[0] : null; - return !is_null($max) ? $max->getValue() : 0.0; - } - - /** - * @param int $epoch_start_date - * @param int $epoch_end_date - * @return float - */ - public function getMinValueByTimeWindow($epoch_start_date, $epoch_end_date){ - $samples = $this->getValuesByTimeWindow($epoch_start_date, $epoch_end_date, 'value', Criteria::ASC); - $min = count($samples) > 0 ? $samples[0] : null; - return !is_null($min) ? $min->getValue() : 0.0; - } - - /** - * @param int $epoch_start_date - * @param int $epoch_end_date - * @return float - */ - public function getCurrentValueByTimeWindow($epoch_start_date, $epoch_end_date){ - $utc_epoch = time(); - $rounded_epoch = $utc_epoch- $utc_epoch % 60; - $res = 0.0; - if($epoch_start_date <= $rounded_epoch && $rounded_epoch <= $epoch_end_date){ - $samples = $this->getValuesByTimeWindow($epoch_start_date, $epoch_end_date, 'timestamp', Criteria::ASC); - foreach($samples as $sample){ - if($sample->getTimestamp() == $rounded_epoch) - $res = $sample->getValue(); - } - } - return $res; - } - - /** - * @param int $epoch_start_date - * @param int $epoch_end_date - * @return float - */ - public function getMeanValueByTimeWindow($epoch_start_date, $epoch_end_date){ - $samples = $this->getValuesByTimeWindow($epoch_start_date, $epoch_end_date, 'value', Criteria::ASC); - $sum = 0.0; - foreach($samples as $sample){ - $sum += $sample->getValue(); - } - return count($samples) > 0 ? $sum / count($samples) : 0.0; - } - - /** - * @param int $epoch_start_date - * @param int $epoch_end_date - * @param string|null $order_by - * @param string|null $order_by_direction - * @return array - */ - public function getValuesByTimeWindow($epoch_start_date, $epoch_end_date, $order_by = null, $order_by_direction = null){ - $criteria = Criteria::create() - ->where(Criteria::expr()->gte("timestamp", $epoch_start_date)) - ->andWhere(Criteria::expr()->lte("timestamp", $epoch_end_date)); - - if(!is_null($order_by) && !is_null($order_by_direction)){ - $criteria = $criteria->orderBy(array($order_by => $order_by_direction)); - } - - $samples = $this->samples->matching($criteria); - return $samples->toArray(); - } -} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Locations/Metrics/SummitEventMetricsSnapshot.php b/app/Models/Foundation/Summit/Locations/Metrics/SummitEventMetricsSnapshot.php deleted file mode 100644 index 54896372..00000000 --- a/app/Models/Foundation/Summit/Locations/Metrics/SummitEventMetricsSnapshot.php +++ /dev/null @@ -1,123 +0,0 @@ -average = $average; - $this->max = $max; - $this->min = $min; - $this->current = $current; - $this->event = $event; - $this->type = $type; - } - - /** - * @return RoomMetricType - */ - public function getType() - { - return $this->type; - } - - /** - * @return string - */ - public function getTypeName() - { - return $this->type->getType(); - } - - /** - * @return int - */ - public function getEventId(){ - return $this->event->getId(); - } - - /** - * @return float - */ - public function getAverage() - { - return $this->average; - } - - /** - * @return float - */ - public function getMax() - { - return $this->max; - } - - /** - * @return float - */ - public function getMin() - { - return $this->min; - } - - /** - * @return float - */ - public function getCurrent() - { - return $this->current; - } - - -} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Locations/SummitBookableVenueRoom.php b/app/Models/Foundation/Summit/Locations/SummitBookableVenueRoom.php index 0952266f..cfb8ce76 100644 --- a/app/Models/Foundation/Summit/Locations/SummitBookableVenueRoom.php +++ b/app/Models/Foundation/Summit/Locations/SummitBookableVenueRoom.php @@ -70,9 +70,15 @@ class SummitBookableVenueRoom extends SummitVenueRoom if(!$this->summit->isBookingPeriodOpen()) throw new ValidationException(sprintf("booking period is not open for summit %s", $this->summit->getId())); - $criteria = Criteria::create(); - $start_date = $reservation->getStartDatetime(); - $end_date = $reservation->getEndDatetime(); + $criteria = Criteria::create(); + $start_date = $reservation->getStartDatetime(); + $end_date = $reservation->getEndDatetime(); + $summit = $this->summit; + $local_start_date = $summit->convertDateFromUTC2TimeZone(clone $start_date); + $local_end_date = $summit->convertDateFromUTC2TimeZone(clone $end_date); + + if(!$summit->isTimeFrameOnBookingPeriod($local_start_date, $local_end_date)) + throw new ValidationException("requested reservation slot does not belong to summit booking period"); $criteria ->where(Criteria::expr()->eq('start_datetime', $start_date)) @@ -98,16 +104,9 @@ class SummitBookableVenueRoom extends SummitVenueRoom if($this->reservations->matching($criteria)->count() > 0) throw new ValidationException(sprintf("reservation overlaps an existent reservation (2)")); - $summit = $this->summit; - - $local_start_date = $summit->convertDateFromUTC2TimeZone($start_date); - $local_end_date = $summit->convertDateFromUTC2TimeZone($end_date); $start_time = $summit->getMeetingRoomBookingStartTime(); $end_time = $summit->getMeetingRoomBookingEndTime(); - if(!$summit->isTimeFrameInsideSummitDuration($local_start_date, $local_end_date)) - throw new ValidationException("requested reservation period does not belong to summit period"); - $local_start_time = new \DateTime("now", $this->summit->getTimeZone()); $local_start_time->setTime( intval($start_time->format("H")), @@ -226,10 +225,13 @@ class SummitBookableVenueRoom extends SummitVenueRoom * @return array * @throws ValidationException */ - public function getAvailableSlots(\DateTime $day):array{ + public function getAvailableSlots(\DateTime $day): array { $availableSlots = []; $summit = $this->summit; - $day = $day->setTimezone($summit->getTimeZone())->setTime(0, 0,0); + $test_date = clone $day; + // reset time only interest the date portion + $test_date = $test_date->setTimezone($summit->getTimeZone())->setTime(0, 0,0); + $booking_start_time = $summit->getMeetingRoomBookingStartTime(); if(is_null($booking_start_time)) throw new ValidationException("MeetingRoomBookingStartTime is null!"); @@ -238,44 +240,51 @@ class SummitBookableVenueRoom extends SummitVenueRoom if(is_null($booking_end_time)) throw new ValidationException("MeetingRoomBookingEndTime is null!"); - $booking_slot_len = $summit->getMeetingRoomBookingSlotLength(); - $start_datetime = clone $day; - $end_datetime = clone $day; + $booking_slot_len = $summit->getMeetingRoomBookingSlotLength(); + $local_start_datetime = clone $test_date; + $local_end_datetime = clone $test_date; - $start_datetime->setTime( + // set the time frames + + $local_start_datetime->setTimezone($summit->getTimeZone())->setTime( intval($booking_start_time->format("H")), intval($booking_start_time->format("i")), 0); - $start_datetime->setTimezone($summit->getTimeZone()); - $end_datetime->setTime( + $local_end_datetime->setTimezone($summit->getTimeZone())->setTime( intval($booking_end_time->format("H")), intval($booking_end_time->format("i")), 00); - $end_datetime->setTimezone($summit->getTimeZone()); + + // check if day belongs to booking period + + if(!$summit->isTimeFrameOnBookingPeriod($local_start_datetime, $local_end_datetime)) + throw new ValidationException("requested day does not belong to summit booking period"); + + // now we have the allowed time frame for that particular day + $criteria = Criteria::create(); - if(!$summit->isTimeFrameInsideSummitDuration($start_datetime, $end_datetime)) - throw new ValidationException("requested day does not belong to summit period"); $criteria - ->where(Criteria::expr()->gte('start_datetime', $summit->convertDateFromTimeZone2UTC($start_datetime))) - ->andWhere(Criteria::expr()->lte('end_datetime', $summit->convertDateFromTimeZone2UTC($end_datetime))) + ->where(Criteria::expr()->gte('start_datetime', $summit->convertDateFromTimeZone2UTC($local_start_datetime))) + ->andWhere(Criteria::expr()->lte('end_datetime', $summit->convertDateFromTimeZone2UTC($local_end_datetime))) ->andWhere(Criteria::expr()->notIn("status", [ SummitRoomReservation::RequestedRefundStatus, SummitRoomReservation::RefundedStatus, SummitRoomReservation::Canceled, ])); - $reservations = $this->reservations->matching($criteria); - - while($start_datetime <= $end_datetime) { - $current_time_slot_end = clone $start_datetime; + $reservations = $this->reservations->matching($criteria); + // calculate all possible slots + while($local_start_datetime <= $local_end_datetime) { + $current_time_slot_end = clone $local_start_datetime; $current_time_slot_end->add(new \DateInterval("PT" . $booking_slot_len . 'M')); - if($current_time_slot_end<=$end_datetime) - $availableSlots[$start_datetime->format('Y-m-d H:i:s').'|'.$current_time_slot_end->format('Y-m-d H:i:s')] = true; - $start_datetime = $current_time_slot_end; + if($current_time_slot_end <= $local_end_datetime) + $availableSlots[$local_start_datetime->format('Y-m-d H:i:s').'|'.$current_time_slot_end->format('Y-m-d H:i:s')] = true; + $local_start_datetime = $current_time_slot_end; } + // and mark all not available slots on that time frame foreach ($reservations as $reservation){ if(!$reservation instanceof SummitRoomReservation) continue; $availableSlots[ @@ -294,8 +303,10 @@ class SummitBookableVenueRoom extends SummitVenueRoom * @throws ValidationException */ public function getFreeSlots(\DateTime $day):array{ - $slots = $this->getAvailableSlots($day); + + $slots = $this->getAvailableSlots(clone $day); $free_slots = []; + foreach ($slots as $label => $status){ if(!$status) continue; $free_slots[] = $label; diff --git a/app/Models/Foundation/Summit/Locations/SummitBookableVenueRoomAttributeType.php b/app/Models/Foundation/Summit/Locations/SummitBookableVenueRoomAttributeType.php index 03ea3749..a1e2f949 100644 --- a/app/Models/Foundation/Summit/Locations/SummitBookableVenueRoomAttributeType.php +++ b/app/Models/Foundation/Summit/Locations/SummitBookableVenueRoomAttributeType.php @@ -23,7 +23,7 @@ use models\utils\SilverstripeBaseModel; * @ORM\AssociationOverrides({ * @ORM\AssociationOverride( * name="summit", - * inversedBy="booking_room_allowed_attributes" + * inversedBy="meeting_booking_room_allowed_attributes" * ) * }) * Class SummitBookableVenueRoomAttributeType @@ -40,7 +40,7 @@ class SummitBookableVenueRoomAttributeType extends SilverstripeBaseModel use SummitOwned; /** - * @ORM\OneToMany(targetEntity="models\summit\SummitBookableVenueRoomAttributeValue", mappedBy="type", cascade={"persist"}, orphanRemoval=true) + * @ORM\OneToMany(targetEntity="SummitBookableVenueRoomAttributeValue", mappedBy="type", cascade={"persist"}, orphanRemoval=true) * @var ArrayCollection */ private $values; diff --git a/app/Models/Foundation/Summit/Locations/SummitRoomReservation.php b/app/Models/Foundation/Summit/Locations/SummitRoomReservation.php index 6ed82855..ae141932 100644 --- a/app/Models/Foundation/Summit/Locations/SummitRoomReservation.php +++ b/app/Models/Foundation/Summit/Locations/SummitRoomReservation.php @@ -313,11 +313,20 @@ class SummitRoomReservation extends SilverstripeBaseModel } /** - * @throws ValidationException + * @return bool */ + public function isPaid():bool { + return $this->status == self::PaidStatus; + } + public function setPaid():void{ + if($this->isPaid()){ + Log::warning(sprintf("SummitRoomReservation %s is already Paid", $this->getId())); + return; + } + if($this->status != self::ReservedStatus){ - Log::warning("setting payed status to SummitRoomReservation %s with status %s", $this->getId(), $this->status); + Log::warning(sprintf("setting payed status to SummitRoomReservation %s with status %s", $this->getId(), $this->status)); } $this->status = self::PaidStatus; @@ -345,6 +354,13 @@ class SummitRoomReservation extends SilverstripeBaseModel $this->last_error = $error; } + /** + * @return null|string + */ + public function getLastError():?string{ + return $this->last_error; + } + /** * @return int */ diff --git a/app/Models/Foundation/Summit/Locations/SummitVenueRoom.php b/app/Models/Foundation/Summit/Locations/SummitVenueRoom.php index c40d370f..71c676c2 100644 --- a/app/Models/Foundation/Summit/Locations/SummitVenueRoom.php +++ b/app/Models/Foundation/Summit/Locations/SummitVenueRoom.php @@ -1,5 +1,4 @@ override_blackouts = $override_blackouts; } - /** - * @return ArrayCollection - */ - public function getMetrics() - { - return $this->metrics; - } - - /** - * @param ArrayCollection $metrics - */ - public function setMetrics($metrics) - { - $this->metrics = $metrics; - } /** * SummitVenueRoom constructor. @@ -230,21 +209,11 @@ class SummitVenueRoom extends SummitAbstractLocation implements IOrderable public function __construct() { parent::__construct(); - $this->metrics = new ArrayCollection(); $this->override_blackouts = false; $this->capacity = 0; $this->type = self::TypeInternal; } - /** - * @param int $type_id - * @return RoomMetricType - */ - public function getMetricByType($type_id){ - - $criteria = Criteria::create()->where(Criteria::expr()->eq("id", $type_id)); - return $this->metrics->matching($criteria)->first(); - } /** * @param SummitVenue|null $venue diff --git a/app/Models/Foundation/Summit/MediaUploads/SummitMediaFileType.php b/app/Models/Foundation/Summit/MediaUploads/SummitMediaFileType.php new file mode 100644 index 00000000..01db0e9a --- /dev/null +++ b/app/Models/Foundation/Summit/MediaUploads/SummitMediaFileType.php @@ -0,0 +1,118 @@ +is_system_defined = false; + $this->description = ''; + } + + /** + * @ORM\Column(name="Name", type="string") + * @var string + */ + private $name; + + /** + * @ORM\Column(name="Description", type="string") + * @var string + */ + private $description; + + /** + * @ORM\Column(name="AllowedExtensions", type="string") + * @var string + */ + private $allowed_extensions; + + /** + * @ORM\Column(name="IsSystemDefine", type="boolean") + * @var bool + */ + private $is_system_defined; + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return string + */ + public function getDescription(): ?string + { + return $this->description; + } + + /** + * @param string $description + */ + public function setDescription(string $description): void + { + $this->description = $description; + } + + /** + * @return string + */ + public function getAllowedExtensions(): ?string + { + return $this->allowed_extensions; + } + + /** + * @param string $allowed_extensions + */ + public function setAllowedExtensions(string $allowed_extensions): void + { + $this->allowed_extensions = strtoupper($allowed_extensions); + } + + /** + * @return bool + */ + public function IsSystemDefined(): bool + { + return $this->is_system_defined; + } + + public function markAsSystemDefined(): void { + $this->is_system_defined = true; + } + + public function markAsUserDefined(): void { + $this->is_system_defined = false; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/MediaUploads/SummitMediaUploadType.php b/app/Models/Foundation/Summit/MediaUploads/SummitMediaUploadType.php new file mode 100644 index 00000000..a28d9b7b --- /dev/null +++ b/app/Models/Foundation/Summit/MediaUploads/SummitMediaUploadType.php @@ -0,0 +1,275 @@ +is_mandatory = false; + $this->max_size = 0; + $this->presentation_types = new ArrayCollection(); + $this->public_storage_type = IStorageTypesConstants::None; + $this->private_storage_type = IStorageTypesConstants::None; + } + + public function setType(SummitMediaFileType $type){ + $this->type = $type; + } + + /** + * @return SummitMediaFileType + */ + public function getType(): ?SummitMediaFileType{ + return $this->type; + } + + /** + * @return int + */ + public function getTypeId(){ + try { + return is_null($this->type) ? 0 : $this->type->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return bool + */ + public function hasType():bool{ + return $this->getTypeId() > 0; + } + + public function clearType(){ + $this->type = null; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return string + */ + public function getDescription(): string + { + return $this->description; + } + + /** + * @param string $description + */ + public function setDescription(string $description): void + { + $this->description = $description; + } + + /** + * @return int + */ + public function getMaxSize(): int + { + return $this->max_size; + } + + /** + * @param int $max_size + */ + public function setMaxSize(int $max_size): void + { + $this->max_size = $max_size; + } + + /** + * @return bool + */ + public function isMandatory(): bool + { + return $this->is_mandatory; + } + + public function markAsMandatory(): void + { + $this->is_mandatory = true; + } + + public function markAsOptional():void{ + $this->is_mandatory = false; + } + + /** + * @return string + */ + public function getPrivateStorageType(): string + { + return $this->private_storage_type; + } + + /** + * @param string $private_storage_type + */ + public function setPrivateStorageType(string $private_storage_type): void + { + $this->private_storage_type = $private_storage_type; + } + + /** + * @return string + */ + public function getPublicStorageType(): string + { + return $this->public_storage_type; + } + + /** + * @param string $public_storage_type + */ + public function setPublicStorageType(string $public_storage_type): void + { + $this->public_storage_type = $public_storage_type; + } + + /** + * @param PresentationType $presentationType + */ + public function addPresentationType(PresentationType $presentationType){ + if($this->presentation_types->contains($presentationType)) return; + $this->presentation_types->add($presentationType); + $presentationType->addAllowedMediaUploadType($this); + } + + /** + * @param PresentationType $presentationType + */ + public function removePresentationType(PresentationType $presentationType){ + if(!$this->presentation_types->contains($presentationType)) return; + $this->presentation_types->removeElement($presentationType); + $presentationType->removeAllowedMediaUploadType($this); + } + + public function getPresentationTypes(){ + return $this->presentation_types; + } + + public function isPresentationTypeAllowed(SummitEventType $type):bool { + return $this->presentation_types->contains($type); + } + + public function clearPresentationTypes():void{ + $this->presentation_types->clear(); + } + + /** + * @param string $ext + * @return bool + */ + public function isValidExtension(string $ext):bool { + return in_array(strtoupper($ext), explode('|', $this->type->getAllowedExtensions())); + } + + public function hasStorageSet():bool { + return ($this->private_storage_type != IStorageTypesConstants::None || $this->public_storage_type != IStorageTypesConstants::None); + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/PromoCodes/SummitRegistrationPromoCode.php b/app/Models/Foundation/Summit/PromoCodes/SummitRegistrationPromoCode.php deleted file mode 100644 index afe17f49..00000000 --- a/app/Models/Foundation/Summit/PromoCodes/SummitRegistrationPromoCode.php +++ /dev/null @@ -1,230 +0,0 @@ -summit = $summit; - } - - /** - * @return Summit - */ - public function getSummit(){ - return $this->summit; - } - - public function clearSummit(){ - $this->summit = null; - } - - /** - * @return int - */ - public function getSummitId(){ - try { - return $this->summit->getId(); - } - catch(\Exception $ex){ - return 0; - } - } - - /** - * @ORM\ManyToOne(targetEntity="models\main\Member") - * @ORM\JoinColumn(name="CreatorID", referencedColumnName="ID") - * @var Member - */ - protected $creator; - - /** - * @return string - */ - public function getCode() - { - return $this->code; - } - - /** - * @param string $code - */ - public function setCode($code) - { - $this->code = $code; - } - - /** - * @return bool - */ - public function isEmailSent() - { - return $this->email_sent; - } - - /** - * @param bool $email_sent - */ - public function setEmailSent($email_sent) - { - $this->email_sent = $email_sent; - } - - /** - * @return bool - */ - public function isRedeemed() - { - return $this->redeemed; - } - - /** - * @param bool $redeemed - */ - public function setRedeemed($redeemed) - { - $this->redeemed = $redeemed; - } - - /** - * @return string - */ - public function getSource() - { - return $this->source; - } - - /** - * @param string $source - */ - public function setSource($source) - { - $this->source = $source; - } - - /** - * @return Member - */ - public function getCreator() - { - return $this->creator; - } - - /** - * @param Member $creator - */ - public function setCreator($creator) - { - $this->creator = $creator; - } - - public function __construct() - { - $this->email_sent = false; - $this->redeemed = false; - parent::__construct(); - } - - public function setSourceAdmin(){ - $this->source = 'ADMIN'; - } - - /** - * @return int - */ - public function getCreatorId(){ - try { - return is_null($this->creator) ? 0: $this->creator->getId(); - } - catch(\Exception $ex){ - return 0; - } - } - - /** - * @return bool - */ - public function hasCreator(){ - return $this->getCreatorId() > 0; - } - - const ClassName = 'SUMMIT_PROMO_CODE'; - - /** - * @return string - */ - public function getClassName(){ - return self::ClassName; - } - - public static $metadata = [ - 'code' => 'string', - 'email_sent' => 'boolean', - 'redeemed' => 'boolean', - 'source' => ['CSV','ADMIN'], - 'summit_id' => 'integer', - 'creator_id' => 'integer', - ]; - - /** - * @return array - */ - public static function getMetadata(){ - return self::$metadata; - } -} diff --git a/app/Models/Foundation/Summit/Attendees/ConfirmationExternalOrderRequest.php b/app/Models/Foundation/Summit/Registration/Attendees/ConfirmationExternalOrderRequest.php similarity index 100% rename from app/Models/Foundation/Summit/Attendees/ConfirmationExternalOrderRequest.php rename to app/Models/Foundation/Summit/Registration/Attendees/ConfirmationExternalOrderRequest.php diff --git a/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendee.php b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendee.php new file mode 100644 index 00000000..d73ed332 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendee.php @@ -0,0 +1,682 @@ +summit_hall_checked_in_date; + } + + /** + * @return bool + */ + public function getSummitHallCheckedIn(){ + return (bool)$this->summit_hall_checked_in; + } + + /** + * @param bool $summit_hall_checked_in + */ + public function setSummitHallCheckedIn($summit_hall_checked_in){ + $this->summit_hall_checked_in = $summit_hall_checked_in; + } + + /** + * @param \DateTime $summit_hall_checked_in_date + */ + public function setSummitHallCheckedInDate(\DateTime $summit_hall_checked_in_date){ + $this->summit_hall_checked_in_date = $summit_hall_checked_in_date; + } + + /** + * @return boolean + */ + public function getSharedContactInfo() + { + return $this->share_contact_info; + } + + /** + * @param boolean $share_contact_info + */ + public function setShareContactInfo($share_contact_info) + { + $this->share_contact_info = $share_contact_info; + } + + /** + * @return int + */ + public function getMemberId(){ + try { + return is_null($this->member) ? 0 : $this->member->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return bool + */ + public function hasMember(){ + return $this->getMemberId() > 0; + } + + /** + * @ORM\OneToMany(targetEntity="SummitAttendeeTicket", mappedBy="owner", cascade={"persist", "remove"}) + * @var SummitAttendeeTicket[] + */ + private $tickets; + + /** + * @return SummitAttendeeTicket[] + */ + public function getTickets(){ + return $this->tickets; + } + + /** + * @param SummitAttendeeTicket $ticket + */ + public function addTicket(SummitAttendeeTicket $ticket){ + if($this->tickets->contains($ticket)) return; + $this->tickets->add($ticket); + $ticket->setOwner($this); + } + + /** + * @return Member + */ + public function getMember():?Member{ + return $this->member; + } + + /** + * @param Member $member + */ + public function setMember(Member $member){ + $this->member = $member; + } + + use SummitOwned; + + public function __construct() + { + parent::__construct(); + $this->share_contact_info = false; + $this->summit_hall_checked_in = false; + $this->tickets = new ArrayCollection(); + $this->extra_question_answers = new ArrayCollection(); + $this->disclaimer_accepted_date = null; + $this->status = self::StatusIncomplete; + } + + /** + * @return SummitEventFeedback[] + */ + public function getEmittedFeedback(){ + + return $this->member->getFeedback()->matching + ( + Criteria::create()->orderBy(["id" => Criteria::ASC]) + ); + } + + /** + * @param SummitEvent $event + * @throws ValidationException + * @deprecated use Member::add2Schedule instead + */ + public function add2Schedule(SummitEvent $event) + { + $this->member->add2Schedule($event); + } + + /** + * @param SummitEvent $event + * @throws ValidationException + * @deprecated use Member::removeFromSchedule instead + */ + public function removeFromSchedule(SummitEvent $event) + { + $this->member->removeFromSchedule($event); + } + + /** + * @param SummitEvent $event + * @return bool + * @deprecated use Member::isOnSchedule instead + */ + public function isOnSchedule(SummitEvent $event) + { + return $this->member->isOnSchedule($event); + } + + /** + * @param SummitEvent $event + * @return null| SummitMemberSchedule + * @deprecated use Member::getScheduleByEvent instead + */ + public function getScheduleByEvent(SummitEvent $event){ + return $this->member->getScheduleByEvent($event); + } + + /** + * @return SummitMemberSchedule[] + * @deprecated use Member::getScheduleBySummit instead + */ + public function getSchedule(){ + return $this->member->getScheduleBySummit($this->summit); + } + + /** + * @return int[] + * @deprecated use Member::getScheduledEventsIds instead + */ + public function getScheduledEventsIds(){ + return $this->member->getScheduledEventsIds($this->summit); + } + + /** + * @param int $event_id + * @return null|RSVP + * @deprecated use Member::getRsvpByEvent instead + */ + public function getRsvpByEvent($event_id){ + return $this->member->getRsvpByEvent($event_id); + } + + /** + * @param int $ticket_id + * @return SummitAttendeeTicket + */ + public function getTicketById($ticket_id){ + $ticket = $this->tickets->matching( + $criteria = Criteria::create() + ->where(Criteria::expr()->eq("id", $ticket_id)) + )->first(); + return $ticket ? $ticket : null; + } + + /** + * @param SummitAttendeeTicket $ticket + * @return $this + */ + public function removeTicket(SummitAttendeeTicket $ticket){ + $this->tickets->removeElement($ticket); + $ticket->clearOwner(); + return $this; + } + + /** + * @param SummitAttendeeTicket $ticket + */ + public function sendRevocationTicketEmail(SummitAttendeeTicket $ticket){ + if(!$ticket->hasOwner()) return; + + if($ticket->getOwner()->getId() != $this->getId()) return; + + RevocationTicketEmail::dispatch($this, $ticket); + } + + /** + * @param SummitAttendeeTicket $ticket + */ + public function sendInvitationEmail(SummitAttendeeTicket $ticket){ + Log::debug(sprintf("SummitAttendee::sendInvitationEmail attendee %s", $this->getEmail())); + if($ticket->getOwnerEmail() != $this->getEmail()) return; + $this->updateStatus(); + if($this->isComplete()) { + Log::debug(sprintf("SummitAttendee::sendInvitationEmail attendee %s is complete", $this->getEmail())); + SummitAttendeeTicketEmail::dispatch($ticket)->delay(now()->addMinutes(5)); + return; + } + Log::debug(sprintf("SummitAttendee::sendInvitationEmail attendee %s is not complete", $this->getEmail())); + $order = $ticket->getOrder(); + // if order owner is ticket owner then dont sent this email + // buyer is presented the option to fill in the details during the checkout process. Second, buyer will + // receive daily reminder emails. So, I think that makes this email not really needed as the buyer already knows + // they bought a ticket for themselves. + if($order->getOwnerEmail() !== $ticket->getOwnerEmail()) { + // no delay + InviteAttendeeTicketEditionMail::dispatch($ticket); + } + } + + /** + * @return bool + */ + public function hasTickets(){ + return $this->tickets->count() > 0; + } + + /** + * @return string + */ + public function getFirstName(): ?string + { + if($this->hasMember()){ + return $this->member->getFirstName(); + } + return $this->first_name; + } + + /** + * @param string $first_name + */ + public function setFirstName(string $first_name): void + { + $this->first_name = $first_name; + } + + /** + * @return string + */ + public function getSurname(): ?string + { + if($this->hasMember()){ + return $this->member->getLastName(); + } + return $this->surname; + } + + /** + * @param string $surname + */ + public function setSurname(string $surname): void + { + $this->surname = $surname; + } + + /** + * @return string + */ + public function getEmail(): string + { + if($this->hasMember()){ + return $this->member->getEmail(); + } + return $this->email; + } + + public function getFullName():?string{ + Log::debug(sprintf("SummitAttendee::getFullName id %s", $this->id)); + if($this->hasMember()){ + Log::debug(sprintf("SummitAttendee::getFullName id %s hasMember", $this->id)); + $fullname = $this->member->getFullName(); + Log::debug(sprintf("SummitAttendee::getFullName id %s Member Full Name %s", $this->id, $fullname)); + if(!empty($fullname)) + return $fullname; + } + + $fullname = $this->first_name; + if(!empty($this->surname)){ + if(!empty($fullname)) $fullname .= ' '; + $fullname .= $this->surname; + } + + Log::debug(sprintf("SummitAttendee::getFullName id %s Attendee Full Name %s", $this->id, $fullname)); + return $fullname; + } + + /** + * @param string $email + */ + public function setEmail(string $email): void + { + $this->email = strtolower(trim($email)); + } + + /** + * @return \DateTime + */ + public function getDisclaimerAcceptedDate(): ?\DateTime + { + return $this->disclaimer_accepted_date; + } + + /** + * @return bool + */ + public function hasDisclaimerAccepted():bool{ + return !is_null($this->disclaimer_accepted_date); + } + + /** + * @param \DateTime $disclaimer_accepted_date + */ + public function setDisclaimerAcceptedDate(\DateTime $disclaimer_accepted_date): void + { + $this->disclaimer_accepted_date = $disclaimer_accepted_date; + } + + /** + * @return SummitOrderExtraQuestionAnswer[] + */ + public function getExtraQuestionAnswers() + { + return $this->extra_question_answers; + } + + /** + * @param SummitOrderExtraQuestionType $question + * @return SummitOrderExtraQuestionAnswer|null + */ + public function getExtraQuestionAnswerByQuestion(SummitOrderExtraQuestionType $question):?SummitOrderExtraQuestionAnswer{ + $answer = $this->extra_question_answers->matching( + $criteria = Criteria::create() + ->where(Criteria::expr()->eq("question", $question)) + )->first(); + return $answer ? $answer : null; + } + + public function clearExtraQuestionAnswers() + { + return $this->extra_question_answers->clear(); + } + + /** + * @param SummitOrderExtraQuestionAnswer $answer + */ + public function addExtraQuestionAnswer(SummitOrderExtraQuestionAnswer $answer){ + if($this->extra_question_answers->contains($answer)) return; + $this->extra_question_answers->add($answer); + $answer->setAttendee($this); + } + + /** + * @param SummitOrderExtraQuestionAnswer $answer + */ + public function removeExtraQuestionAnswer(SummitOrderExtraQuestionAnswer $answer){ + if(!$this->extra_question_answers->contains($answer)) return; + $this->extra_question_answers->removeElement($answer); + $answer->clearAttendee(); + } + + /** + * @return string + */ + public function getCompanyName(): ?string + { + return $this->company_name; + } + + /** + * @param string $company_name + */ + public function setCompanyName(string $company_name): void + { + $this->company_name = $company_name; + } + + /** + * @return Company + */ + public function getCompany(): ?Company + { + return $this->company; + } + + /** + * @param Company $company + */ + public function setCompany(Company $company): void + { + $this->company = $company; + } + + /** + * @return bool + */ + public function needToFillDetails():bool { + return $this->getStatus() == self::StatusIncomplete; + } + + /** + * @return bool + */ + public function isComplete():bool{ + return $this->getStatus() == self::StatusComplete; + } + + /** + * @return string + */ + public function getStatus():?string{ + return $this->status; + } + + public function updateStatus():string { + + Log::debug(sprintf("SummitAttendee::updateStatus original status %s", $this->status)); + $is_disclaimer_mandatory = $this->summit->isRegistrationDisclaimerMandatory(); + + // mandatory fields + if($is_disclaimer_mandatory && !$this->hasDisclaimerAccepted()){ + $this->status = self::StatusIncomplete; + Log::debug(sprintf("SummitAttendee::updateStatus StatusIncomplete for attendee %s (disclaimer mandatory)", $this->id)); + return $this->status; + } + + if(empty($this->getFirstName())){ + $this->status = self::StatusIncomplete; + Log::debug(sprintf("SummitAttendee::updateStatus StatusIncomplete for attendee %s (first name empty)", $this->id)); + return $this->status; + } + + if(empty($this->getSurname())){ + $this->status = self::StatusIncomplete; + Log::debug(sprintf("SummitAttendee::updateStatus StatusIncomplete for attendee %s (last name empty)", $this->id)); + return $this->status; + } + + if(empty($this->getEmail())){ + $this->status = self::StatusIncomplete; + Log::debug(sprintf("SummitAttendee::updateStatus StatusIncomplete for attendee %s (email empty)", $this->id)); + return $this->status; + } + + // check mandatory questions + + // get mandatory question ids + $extra_questions_mandatory_questions = $this->summit->getMandatoryOrderExtraQuestionsByUsage(SummitOrderExtraQuestionTypeConstants::TicketQuestionUsage); + $extra_questions_mandatory_questions_ids = []; + + foreach($extra_questions_mandatory_questions as $extra_mandatory_question){ + $extra_questions_mandatory_questions_ids[] = $extra_mandatory_question->getId(); + } + + // now check the answers + foreach($this->extra_question_answers as $extra_question_answer){ + if(!$extra_question_answer->hasQuestion()) continue; + $question_type = $extra_question_answer->getQuestion(); + if(in_array($question_type->getId(), $extra_questions_mandatory_questions_ids)) { + // is mandatory now check if we have value set + if(!$extra_question_answer->hasValue()) { + $this->status = self::StatusIncomplete; + Log::debug(sprintf("SummitAttendee::updateStatus StatusIncomplete for attendee %s ( mandatory extra question missing value )", $this->id)); + return $this->status; + } + // delete from ids due its already answeres + if (($key = array_search($question_type->getId(), $extra_questions_mandatory_questions_ids)) !== false) { + unset($extra_questions_mandatory_questions_ids[$key]); + } + } + } + + // if we have mandatory questions without answer ... + if(count($extra_questions_mandatory_questions_ids) > 0 ){ + $this->status = self::StatusIncomplete; + Log::debug(sprintf("SummitAttendee::updateStatus StatusIncomplete for attendee %s ( mandatory extra questions )", $this->id)); + return $this->status; + } + + $this->status = self::StatusComplete; + + return $this->status; + } + + /** + * @return \DateTime + */ + public function getLastReminderEmailSentDate(): ?\DateTime + { + $last_action_date = $this->last_reminder_email_sent_date; + + if (is_null($last_action_date)) { + $last_action_date = $this->getCreatedUTC(); + } + + return $last_action_date; + } + + /** + * @param \DateTime $last_reminder_email_sent_date + */ + public function setLastReminderEmailSentDate(\DateTime $last_reminder_email_sent_date): void + { + $this->last_reminder_email_sent_date = $last_reminder_email_sent_date; + } + + public function getExternalId(): ?string + { + return $this->external_id; + } + + /** + * @param string $external_id + */ + public function setExternalId(string $external_id): void + { + $this->external_id = $external_id; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeBadge.php b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeBadge.php new file mode 100644 index 00000000..d29317db --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeBadge.php @@ -0,0 +1,314 @@ + 'ticket', + 'getTypeId' => 'type', + ]; + + protected $hasPropertyMappings = [ + 'hasTicket' => 'ticket', + 'hasType' => 'type', + ]; + + + /** + * @ORM\Column(name="IsVoid", type="boolean") + * @var boolean + */ + private $is_void; + + /** + * @ORM\Column(name="QRCode", type="string", nullable=true) + * @var string + */ + private $qr_code; + + /** + * @ORM\OneToOne(targetEntity="SummitAttendeeTicket", inversedBy="badge") + * @ORM\JoinColumn(name="TicketID", referencedColumnName="ID") + * @var SummitAttendeeTicket + */ + private $ticket; + + /** + * @ORM\ManyToOne(targetEntity="SummitBadgeType") + * @ORM\JoinColumn(name="BadgeTypeID", referencedColumnName="ID") + * @var SummitBadgeType + */ + private $type; + + /** + * @ORM\ManyToMany(targetEntity="SummitBadgeFeatureType") + * @ORM\JoinTable(name="SummitAttendeeBadge_Features", + * joinColumns={@ORM\JoinColumn(name="SummitAttendeeBadgeID", referencedColumnName="ID")}, + * inverseJoinColumns={@ORM\JoinColumn(name="SummitBadgeFeatureTypeID", referencedColumnName="ID")} + * ) + * @var SummitBadgeFeatureType[] + */ + private $features; + + /** + * @ORM\OneToMany(targetEntity="models\summit\SummitAttendeeBadgePrint", mappedBy="badge", cascade={"persist","remove"}, orphanRemoval=true) + */ + private $prints; + + /** + * SummitAttendeeBadge constructor. + */ + public function __construct() + { + parent::__construct(); + $this->features = new ArrayCollection(); + $this->prints = new ArrayCollection(); + $this->is_void = false; + } + + public function getQRCode(): ?string + { + return $this->qr_code; + } + + use QRGeneratorTrait; + + /** + * @return string + * @throws ValidationException + */ + public function generateQRCode(): string + { + $ticket = $this->getTicket(); + if(is_null($ticket)) + throw new ValidationException("ticket is not set"); + + $order = $ticket->getOrder(); + if(is_null($order)) + throw new ValidationException("order is not set"); + + $summit = $order->getSummit(); + if(is_null($summit)) + throw new ValidationException("summit is not set"); + + $this->qr_code = $this->generateQRFromFields([ + $summit->getBadgeQRPrefix(), + $ticket->getNumber(), + $ticket->getOwnerEmail(), + $ticket->getOwnerFullName(), + ]); + + return $this->qr_code; + } + + /** + * @param string $qr_code + * @return array + * @throws ValidationException + */ + static public function parseQRCode(string $qr_code):array{ + $fields = explode(IQREntity::QRRegistryFieldDelimiterChar, $qr_code); + if(count($fields) != 4) throw new ValidationException("invalid qr code"); + + return [ + 'prefix' => $fields[0], + 'ticket_number' => $fields[1], + 'owner_fullname' => $fields[3], + 'owner_email' => $fields[2], + ]; + } + /** + * @return bool + */ + public function isVoid(): bool + { + return $this->is_void; + } + + public function markVoid() + { + $this->is_void = true; + } + + /** + * @return SummitAttendeeTicket + */ + public function getTicket(): SummitAttendeeTicket + { + return $this->ticket; + } + + /** + * @param SummitAttendeeTicket $ticket + */ + public function setTicket(SummitAttendeeTicket $ticket): void + { + $this->ticket = $ticket; + } + + /** + * @return SummitBadgeType + */ + public function getType(): SummitBadgeType + { + return $this->type; + } + + /** + * @param SummitBadgeType $type + */ + public function setType(SummitBadgeType $type): void + { + $this->type = $type; + } + + /** + * @return SummitBadgeFeatureType[] + */ + public function getFeatures() + { + return $this->features; + } + + /** + * @return array + */ + public function getAllFeatures(){ + $features = $this->features->toArray(); + $inherited_features = $this->type->getBadgeFeatures(); + foreach ($inherited_features as $inherited_feature){ + if($this->features->contains($inherited_feature)) continue; + $features[] = $inherited_feature; + } + return $features; + } + + public function clearFeatures():void{ + $this->features->clear(); + } + + + public function addFeature(SummitBadgeFeatureType $feature){ + if($this->features->contains($feature)) return; + $this->features->add($feature); + } + + public function removeFeature(SummitBadgeFeatureType $feature){ + if(!$this->features->contains($feature)) return; + $this->features->removeElement($feature); + } + + /** + * @param SummitRegistrationPromoCode $promo_code + * @return $this + */ + public function applyPromoCode(SummitRegistrationPromoCode $promo_code){ + $this->setType($promo_code->getBadgeType()); + foreach ($promo_code->getBadgeFeatures() as $feature) + $this->addFeature($feature); + return $this; + } + + /** + * @param SummitTicketType $ticket_type + * @return $this + */ + public function applyTicketType(SummitTicketType $ticket_type){ + $this->setType($ticket_type->getBadgeType()); + return $this; + } + + /** + * @return bool + */ + public function isPrinted():bool { + return $this->prints->count() > 0; + } + + /** + * @param Member $requestor + * @return SummitAttendeeBadgePrint + * @throws ValidationException + */ + public function printIt(Member $requestor):SummitAttendeeBadgePrint{ + if(!$this->ticket->hasOwner()) + throw new ValidationException("badge has not owner set"); + + if($this->is_void){ + throw new ValidationException("badge is void"); + } + $this->generateQRCode(); + $print = SummitAttendeeBadgePrint::build($this, $requestor); + $this->prints->add($print); + return $print; + } + + /** + * @param Group $group + * @return int + */ + public function getPrintCountPerGroup(Group $group):int{ + if($this->prints->count() == 0) return 0; + + try { + $sql = <<prepareRawSQL($sql); + $stmt->execute([ + 'badge_id' => $this->id, + 'group_id' => $group->getId(), + ]); + $res = $stmt->fetchAll(\PDO::FETCH_COLUMN); + return count($res) > 0 ? $res[0] : 0; + } catch (\Exception $ex) { + + } + return 0; + } + + public function getPrintDate():?\DateTime{ + if(!$this->isPrinted()) return null; + // get last print date + return $this->prints->last()->getPrintDate(); + } + + /** + * @return int + */ + public function getPrintedTimes(): ?int + { + return $this->prints->count(); + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeBadgePrint.php b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeBadgePrint.php new file mode 100644 index 00000000..9281ff0a --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeBadgePrint.php @@ -0,0 +1,95 @@ + 'requestor', + 'getBadgeId' => 'badge', + ]; + + protected $hasPropertyMappings = [ + 'hasRequestor' => 'requestor', + 'hasBadge' => 'badge', + ]; + + /** + * @ORM\ManyToOne(targetEntity="models\summit\SummitAttendeeBadge", inversedBy="prints") + * @ORM\JoinColumn(name="BadgeID", referencedColumnName="ID") + * @var SummitAttendeeBadge + */ + private $badge; + + /** + * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\JoinColumn(name="RequestorID", referencedColumnName="ID") + * @var Member + */ + private $requestor; + + /** + * @ORM\Column(name="PrintDate", type="datetime", nullable=true) + * @var \DateTime + */ + private $print_date; + + /** + * @return SummitAttendeeBadge + */ + public function getBadge(): SummitAttendeeBadge + { + return $this->badge; + } + + /** + * @return Member + */ + public function getRequestor(): Member + { + return $this->requestor; + } + + /** + * @return \DateTime + */ + public function getPrintDate(): \DateTime + { + return $this->print_date; + } + + /** + * @param SummitAttendeeBadge $badge + * @param Member $requestor + * @return SummitAttendeeBadgePrint + */ + public static function build(SummitAttendeeBadge $badge, Member $requestor){ + $print = new SummitAttendeeBadgePrint(); + $print->badge = $badge; + $print->requestor = $requestor; + $print->print_date = new \DateTime('now', new \DateTimeZone('UTC')); + return $print; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeBadgePrintRule.php b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeBadgePrintRule.php new file mode 100644 index 00000000..80786a8d --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeBadgePrintRule.php @@ -0,0 +1,96 @@ + 'group', + ]; + + protected $hasPropertyMappings = [ + 'hasGroup' => 'group', + ]; + + /** + * @ORM\Column(name="MaxPrintTimes", type="integer") + * @var int + */ + private $max_print_times; + + /** + * @ORM\OneToOne(targetEntity="models\main\Group") + * @ORM\JoinColumn(name="GroupID", referencedColumnName="ID") + * @var Group + */ + private $group; + + public function __construct() + { + parent::__construct(); + $this->max_print_times = 0; + } + + /** + * @return int + */ + public function getMaxPrintTimes(): int + { + return $this->max_print_times; + } + + /** + * @param int $max_print_times + */ + public function setMaxPrintTimes(int $max_print_times): void + { + $this->max_print_times = $max_print_times; + } + + /** + * @return Group + */ + public function getGroup(): Group + { + return $this->group; + } + + /** + * @param Group $group + */ + public function setGroup(Group $group): void + { + $this->group = $group; + } + + /** + * @param SummitAttendeeBadge $badge + * @return bool + */ + public function canPrintBadge(SummitAttendeeBadge $badge):bool{ + if($this->max_print_times == 0) return true; + $count = $badge->getPrintCountPerGroup($this->group); + return $count < $this->max_print_times; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeTicket.php b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeTicket.php new file mode 100644 index 00000000..007b8462 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeTicket.php @@ -0,0 +1,908 @@ +status = IOrderConstants::ReservedStatus; + $this->currency = AllowedCurrencies::USD; + $this->applied_taxes = new ArrayCollection(); + $this->former_hashes = new ArrayCollection(); + $this->raw_cost = 0.0; + $this->discount = 0.0; + $this->refunded_amount = 0.0; + } + + /** + * @return string + */ + public function getHash(): string + { + return $this->hash; + } + + /** + * @return \DateTime + */ + public function getHashCreationDate(): \DateTime + { + return $this->hash_creation_date; + } + + /** + * @return string + */ + public function getNumber(): ?string + { + return $this->number; + } + + /** + * @param string $number + */ + public function setNumber(string $number): void + { + $this->number = $number; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @param string $status + */ + public function setStatus(string $status): void + { + $this->status = $status; + } + + /** + * @return float + */ + public function getRawCost(): ?float + { + return $this->raw_cost; + } + + /** + * @param float $raw_cost + */ + public function setRawCost(float $raw_cost): void + { + $this->raw_cost = $raw_cost; + } + + /** + * @return float + */ + public function getRefundedAmount(): ?float + { + return $this->refunded_amount; + } + + /** + * @param float $refunded_amount + */ + public function setRefundedAmount(float $refunded_amount): void + { + $this->refunded_amount = $refunded_amount; + } + + /** + * @return string + */ + public function getCurrency(): ?string + { + return $this->currency; + } + + /** + * @param string $currency + */ + public function setCurrency(string $currency): void + { + $this->currency = $currency; + } + + /** + * @return string + */ + public function getQRCode(): ?string + { + return $this->qr_code; + } + + public function generateHash():void + { + $token = $this->number; + if (!is_null($this->order)) { + $token .= $this->order->getHash(); + } + $salt = random_bytes(16); + if(!empty($this->hash)){ + $former_hash = new SummitAttendeeTicketFormerHash($this->hash, $this); + $this->former_hashes->add($former_hash); + } + $this->hash = hash('sha256', $token.$salt.time()); + $this->hash_creation_date = new \DateTime('now', new \DateTimeZone('UTC')); + } + + /** + * @return bool + */ + public function hasOrder() + { + return $this->getOrderId() > 0; + } + + /** + * @return int + */ + public function getOrderId() + { + try { + return is_null($this->order) ? 0 : $this->order->getId(); + } catch (\Exception $ex) { + return 0; + } + } + + /** + * @return SummitOrder + */ + public function getOrder(): SummitOrder + { + return $this->order; + } + + /** + * @param SummitOrder $order + */ + public function setOrder(SummitOrder $order): void + { + $this->order = $order; + } + + /** + * @return bool + * @throws \Exception + */ + public function canPubliclyEdit(): bool + { + if (empty($this->hash) || is_null($this->hash_creation_date)) return false; + $ttl_minutes = Config::get("registration.ticket_public_edit_ttl", 30); + $eol = new \DateTime('now', new \DateTimeZone('UTC')); + $eol->sub(new \DateInterval('PT' . $ttl_minutes . 'M')); + if ($this->hash_creation_date <= $eol) + return false; + return true; + } + + /** + * @return string + */ + public function generateNumber(): string + { + $summit = $this->getOrder()->getSummit(); + $this->number = strtoupper(str_replace(".", "", uniqid($summit->getTicketQRPrefix().'_', true))); + return $this->number; + } + + /** + * @return mixed + */ + public function getChangedDate() + { + return $this->changed_date; + } + + /** + * @param mixed $changed_date + */ + public function setChangedDate($changed_date) + { + $this->changed_date = $changed_date; + } + + /** + * @return string + */ + public function getExternalOrderId():?string + { + return $this->external_order_id; + } + + /** + * @param string $external_order_id + */ + public function setExternalOrderId($external_order_id) + { + $this->external_order_id = $external_order_id; + } + + /** + * @return string + */ + public function getExternalAttendeeId():?string + { + return $this->external_attendee_id; + } + + /** + * @param string $external_attendee_id + */ + public function setExternalAttendeeId($external_attendee_id) + { + $this->external_attendee_id = $external_attendee_id; + } + + /** + * @return \DateTime + */ + public function getBoughtDate() + { + return $this->bought_date; + } + + /** + * @param \DateTime $bought_date + */ + public function setBoughtDate($bought_date) + { + $this->bought_date = $bought_date; + } + + /** + * @return SummitTicketType + */ + public function getTicketType() + { + return $this->ticket_type; + } + + /** + * @param $ticket_type + * @return $this + */ + public function setTicketType($ticket_type) + { + $this->ticket_type = $ticket_type; + $this->raw_cost = $this->ticket_type->getCost(); + $this->currency = $this->ticket_type->getCurrency(); + return $this->ticket_type->applyTo($this); + } + + /** + * @return bool + */ + public function hasTicketType() + { + return $this->getTicketTypeId() > 0; + } + + /** + * @return int + */ + public function getTicketTypeId() + { + try { + return is_null($this->ticket_type) ? 0 : $this->ticket_type->getId(); + } catch (\Exception $ex) { + return 0; + } + } + + /** + * @return SummitAttendee|null + */ + public function getOwner():?SummitAttendee + { + return $this->owner; + } + + /** + * @param SummitAttendee $owner + */ + public function setOwner($owner) + { + $this->owner = $owner; + } + + /** + * @return bool + */ + public function hasOwner() + { + return $this->getOwnerId() > 0; + } + + /** + * @return int + */ + public function getOwnerId() + { + try { + return is_null($this->owner) ? 0 : $this->owner->getId(); + } catch (\Exception $ex) { + return 0; + } + } + + /** + * @return bool + */ + public function isPaid():bool { + return $this->status == IOrderConstants::PaidStatus; + } + + /** + * @return bool + */ + public function isCancelled():bool { + return $this->status == IOrderConstants::CancelledStatus; + } + + use QRGeneratorTrait; + + /** + * @return string + */ + public function generateQRCode(): string + { + if(is_null($this->order)){ + throw new ValidationException("ticket has not order set"); + } + + $this->qr_code = $this->generateQRFromFields([ + $this->order->getSummit()->getTicketQRPrefix(), + $this->number + ]); + + return $this->qr_code; + } + + /** + * @return SummitAttendeeBadge + */ + public function getBadge(): SummitAttendeeBadge + { + return $this->badge; + } + + /** + * @param SummitAttendeeBadge $badge + */ + public function setBadge(SummitAttendeeBadge $badge): void + { + $this->badge = $badge; + $badge->setTicket($this); + } + + /** + * @return bool + */ + public function hasBadge() + { + return $this->getBadgeId() > 0 || !is_null($this->badge); + } + + /** + * @return int + */ + public function getBadgeId() + { + try { + return is_null($this->badge) ? 0 : $this->badge->getId(); + } catch (\Exception $ex) { + return 0; + } + } + + public function setPaid() + { + $this->status = IOrderConstants::PaidStatus; + $this->bought_date = new \DateTime('now', new \DateTimeZone('UTC')); + } + + public function setCancelled() + { + if ($this->status == IOrderConstants::PaidStatus) return; + $this->status = IOrderConstants::CancelledStatus; + } + + public function setRefunded() + { + $this->status = IOrderConstants::RefundedStatus; + } + + /** + * @return bool + */ + public function canRefund():bool{ + $validStatuses = [IOrderConstants::RefundRequestedStatus, IOrderConstants::PaidStatus]; + if(!in_array($this->status, $validStatuses)){ + return false; + } + if($this->isFree()){ + return false; + } + return true; + } + /** + * @param float $amount + * @throws ValidationException + */ + public function refund(float $amount) + { + if (!$this->canRefund()) + throw new ValidationException + ( + sprintf + ( + "can not request a refund on a %s ticket", + $this->status + ) + ); + + $this->status = IOrderConstants::RefundedStatus; + $this->refunded_amount = $amount; + + $tickets_to_return = []; + $promo_codes_to_return = []; + + if(!isset($tickets_to_return[$this->getTicketTypeId()])) + $tickets_to_return[$this->getTicketTypeId()] = 0; + $tickets_to_return[$this->getTicketTypeId()] += 1; + if($this->hasPromoCode()){ + if(!isset($promo_codes_to_return[$this->getPromoCode()->getCode()])) + $promo_codes_to_return[$this->getPromoCode()->getCode()] = 0; + $promo_codes_to_return[$this->getPromoCode()->getCode()] +=1; + } + + Event::fire(new SummitAttendeeTicketRefundAccepted($this->getId(), $tickets_to_return, $promo_codes_to_return)); + } + + /** + * @return bool + */ + public function hasPromoCode(): bool + { + return $this->getPromoCodeId() > 0; + } + + /** + * @return int + */ + public function getPromoCodeId(): int + { + try { + return is_null($this->promo_code) ? 0 : $this->promo_code->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return SummitRegistrationPromoCode + */ + public function getPromoCode(): ?SummitRegistrationPromoCode + { + return $this->promo_code; + } + + /** + * @param SummitRegistrationPromoCode $promo_code + */ + public function setPromoCode(SummitRegistrationPromoCode $promo_code): void + { + $this->promo_code = $promo_code; + } + + /** + * @return bool + */ + public function isRefundRequested():bool{ + return $this->status == IOrderConstants::RefundRequestedStatus; + } + + /** + * @return bool + */ + public function isRefunded():bool{ + return $this->status == IOrderConstants::RefundedStatus; + } + + /** + * @return bool + */ + public function isBadgePrinted():bool{ + if($this->hasBadge()){ + $badge = $this->getBadge(); + return $badge->isPrinted(); + } + return false; + } + /** + * @param bool $refund_entire_order + * @throws ValidationException + */ + public function requestRefund($refund_entire_order = false): void + { + if ($this->status != IOrderConstants::PaidStatus) + throw new ValidationException(sprintf( "you can not request a refund for this ticket %s ( invalid status %s)", $this->number, $this->status)); + + $summit = $this->getOrder()->getSummit(); + $begin_date = $summit->getBeginDate(); + if(is_null($begin_date)) return; + + if($this->isBadgePrinted()) + throw new ValidationException(sprintf( "you can not request a refund for this ticket %s ( badge already printed)", $this->number)); + + $now = new \DateTime('now', new \DateTimeZone('UTC')); + + if($now > $begin_date){ + Log::debug("SummitAttendeeTicket::requestRefund: now is greater than Summit.BeginDate"); + throw new ValidationException("you can not request a refund after summit started"); + } + + $interval = $begin_date->diff($now); + + $days_before_event_starts = intval($interval->format('%a')); + + Log::debug(sprintf("SummitAttendeeTicket::requestRefund: days_before_event_starts %s", $days_before_event_starts)); + + $this->status = IOrderConstants::RefundRequestedStatus; + + if (!$refund_entire_order) + Event::fire(new RequestedSummitAttendeeTicketRefund($this->getId(), $days_before_event_starts)); + } + + /** + * @param array $taxes + */ + public function applyTaxes(array $taxes) + { + $amount = $this->raw_cost; + $amount -= $this->discount; + foreach ($taxes as $tax) { + if (!$tax instanceof SummitTaxType) continue; + if (!$tax->mustApplyTo($this->ticket_type)) continue; + $ticketTax = new SummitAttendeeTicketTax(); + $ticketTax->setTicket($this); + $ticketTax->setTax($tax); + $ticketTax->setAmount(($amount * $tax->getRate()) / 100.00); + $this->applied_taxes->add($ticketTax); + } + } + + /** + * @return float + */ + public function getFinalAmount(): float + { + $amount = $this->raw_cost; + $amount -= $this->discount; + foreach ($this->applied_taxes as $tax) { + $amount += $tax->getAmount(); + } + return $amount; + } + + /** + * @return bool + */ + public function isFree():bool { + return $this->getFinalAmount() == 0; + } + + /** + * @return float + */ + public function getTaxesAmount(): float + { + $amount = 0.0; + foreach ($this->getAppliedTaxes() as $appliedTax) { + $amount += $appliedTax->getAmount(); + } + return $amount; + } + + /** + * @return SummitAttendeeTicketTax[] + */ + public function getAppliedTaxes() + { + return $this->applied_taxes; + } + + /** + * @return float + */ + public function getDiscount(): float + { + return $this->discount; + } + + /** + * @param float $amount + * @return $this + */ + public function setDiscount(float $amount) + { + $this->discount = $amount > $this->raw_cost ? $this->raw_cost: $amount; + return $this; + } + + public function clearOwner() + { + $this->owner = null; + } + + /** + * @return string + */ + public function getOwnerFullName():?string{ + if(is_null($this->owner)) null; + return $this->owner->getFullName(); + } + + /** + * @return string + */ + public function getOwnerFirstName():?string{ + if(is_null($this->owner)) return null; + return $this->owner->getFirstName(); + } + + /** + * @return string + */ + public function getOwnerSurname():?string{ + if(is_null($this->owner)) return null; + return $this->owner->getSurname(); + } + /** + * @return string + */ + public function getOwnerCompany():?string{ + if(is_null($this->owner)) return null; + return $this->owner->getCompanyName(); + } + + /** + * @return string + */ + public function getOwnerEmail():?string{ + try { + return is_null($this->owner)? null : $this->owner->getEmail(); + } + catch (\Exception $ex){ + return null; + } + } + + /** + * @return int|null + */ + public function getBadgeTypeId():?int{ + if(is_null($this->badge)) return 0; + return $this->badge->getType()->getId(); + } + + /** + * @return null|string + */ + public function getBadgeTypeName():?string{ + if(is_null($this->badge)) return null; + return $this->badge->getType()->getName(); + } + + /** + * @return null|string + */ + public function getTicketTypeName():?string{ + if(is_null($this->ticket_type)) return null; + return $this->ticket_type->getName(); + } + + /** + * @return array + */ + public function getBadgeFeaturesNames():array { + $res = []; + if(is_null($this->badge)) return []; + foreach ($this->badge->getFeatures() as $feature){ + $res[] = $feature->getName(); + } + foreach ($this->badge->getType()->getBadgeFeatures() as $feature){ + if(in_array($feature->getName(),$res)) continue; + $res[] = $feature->getName(); + } + + return $res; + } + + /** + * @return null|string + */ + public function getPromoCodeValue():?string{ + return $this->hasPromoCode() ? $this->promo_code->getCode() : null; + } + + /** + * @param Member $member + * @return bool + */ + public function canEditTicket(Member $member):bool{ + if($member->isAdmin()) return true; + // i am ticket owner + if($this->hasOwner() && $this->owner->getEmail() == $member->getEmail()) return true; + // i am order owner + if($this->order->getOwnerEmail() == $member->getEmail()) return true; + } +} diff --git a/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeTicketFormerHash.php b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeTicketFormerHash.php new file mode 100644 index 00000000..2b861858 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeTicketFormerHash.php @@ -0,0 +1,73 @@ +hash = $hash; + $this->ticket = $ticket; + } + + /** + * @return string + */ + public function getHash(): string + { + return $this->hash; + } + + /** + * @return SummitAttendeeTicket + */ + public function getTicket(): SummitAttendeeTicket + { + return $this->ticket; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeTicketTax.php b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeTicketTax.php new file mode 100644 index 00000000..7cad934b --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/Attendees/SummitAttendeeTicketTax.php @@ -0,0 +1,112 @@ + 'ticket', + 'getTaxId' => 'tax', + ]; + + protected $hasPropertyMappings = [ + 'hasTicket' => 'ticket', + 'hasTax' => 'tax', + ]; + + /** + * @return SummitAttendeeTicket + */ + public function getTicket(): SummitAttendeeTicket + { + return $this->ticket; + } + + /** + * @param SummitAttendeeTicket $ticket + */ + public function setTicket(SummitAttendeeTicket $ticket): void + { + $this->ticket = $ticket; + } + + /** + * @return SummitTaxType + */ + public function getTax(): SummitTaxType + { + return $this->tax; + } + + /** + * @param SummitTaxType $tax + */ + public function setTax(SummitTaxType $tax): void + { + $this->tax = $tax; + } + + /** + * @return float + */ + public function getAmount(): float + { + return $this->amount; + } + + /** + * @param float $amount + */ + public function setAmount(float $amount): void + { + $this->amount = $amount; + } + + /** + * @ORM\ManyToOne(targetEntity="SummitAttendeeTicket", inversedBy="applied_taxes") + * @ORM\JoinColumn(name="SummitAttendeeTicketID", referencedColumnName="ID") + * @var SummitAttendeeTicket + */ + private $ticket; + + /** + * @ORM\ManyToOne(targetEntity="SummitTaxType") + * @ORM\JoinColumn(name="SummitTaxTypeID", referencedColumnName="ID") + * @var SummitTaxType + */ + private $tax; + + /** + * @ORM\Column(name="Amount", type="float") + * @var float + */ + private $amount; + + public function __construct() + { + + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/BuildDefaultPaymentGatewayProfileStrategy.php b/app/Models/Foundation/Summit/Registration/BuildDefaultPaymentGatewayProfileStrategy.php new file mode 100644 index 00000000..00dc60a9 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/BuildDefaultPaymentGatewayProfileStrategy.php @@ -0,0 +1,101 @@ + true, + 'application_type' => $application_type, + ]) + ); + } + + if ($application_type == IPaymentConstants::ApplicationTypeBookableRooms) { + $provider = Config::get('bookable_rooms.default_payment_provider'); + if(empty($provider)){ + throw new ValidationException + ( + sprintf("Missing Provider settings for application %s", $application_type) + ); + } + $config = Config::get('bookable_rooms.default_payment_provider_config'); + $provider_config = $config[$provider] ?? []; + if(!count($provider_config)){ + throw new ValidationException + ( + sprintf + ( + "Missing configuration for provider %s and application %s", + $provider, + $application_type + ) + ); + } + return PaymentGatewayProfileFactory::build + ( + $provider, + array_merge($provider_config, [ + 'active' => true, + 'application_type' => $application_type, + ]) + ); + } + } + catch (\Exception $ex){ + Log::warning($ex); + } + + return null; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/IBuildDefaultPaymentGatewayProfileStrategy.php b/app/Models/Foundation/Summit/Registration/IBuildDefaultPaymentGatewayProfileStrategy.php new file mode 100644 index 00000000..7781bd29 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/IBuildDefaultPaymentGatewayProfileStrategy.php @@ -0,0 +1,22 @@ +active = false; + $this->application_type = IPaymentConstants::ApplicationTypeRegistration; + } + + /** + * @return bool + */ + public function isActive(): bool + { + return $this->active; + } + + public function activate():void{ + $this->active = true; + } + + public function disable():void{ + $this->active = false; + } + + /** + * @return string + */ + public function getApplicationType(): ?string + { + return $this->application_type; + } + + /** + * @param string $application_type + * @throws ValidationException + */ + public function setApplicationType(string $application_type): void + { + if(!in_array($application_type, IPaymentConstants::ValidApplicationTypes)) + throw new ValidationException(sprintf("Application Type %s is not valid.", $application_type)); + + $this->application_type = $application_type; + } + + /** + * @return string + */ + public function getProvider(): ?string + { + return $this->provider; + } + + /** + * @return IPaymentGatewayAPI + */ + abstract public function buildPaymentGatewayApi():IPaymentGatewayAPI; + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/Payment/StripePaymentProfile.php b/app/Models/Foundation/Summit/Registration/Payment/StripePaymentProfile.php new file mode 100644 index 00000000..d15035f7 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/Payment/StripePaymentProfile.php @@ -0,0 +1,500 @@ +test_mode_enabled = true; + $this->provider = IPaymentConstants::ProviderStripe; + $this->live_webhook_id = ''; + $this->live_webhook_secret_key = ''; + $this->live_publishable_key = ''; + $this->live_secret_key = ''; + $this->test_webhook_id = ''; + $this->test_webhook_secret_key = ''; + $this->test_publishable_key = ''; + $this->test_secret_key = ''; + } + + /** + * @return bool + */ + public function isTestModeEnabled(): bool + { + return $this->test_mode_enabled; + } + + /** + * @return string + */ + public function getLiveSecretKey(): ?string + { + return $this->live_secret_key; + } + + /** + * @return string + */ + public function getLivePublishableKey(): ?string + { + return $this->live_publishable_key; + } + + /** + * @return string + */ + public function getLiveWebhookId(): ?string + { + return $this->live_webhook_id; + } + + /** + * @return string + */ + public function getLiveWebhookSecretKey(): ?string + { + return $this->live_webhook_secret_key; + } + + /** + * @return string + */ + public function getTestSecretKey(): ?string + { + return $this->test_secret_key; + } + + /** + * @return string + */ + public function getTestPublishableKey(): ?string + { + return $this->test_publishable_key; + } + + /** + * @return string + */ + public function getTestWebhookId(): ?string + { + return $this->test_webhook_id; + } + + /** + * @return string + */ + public function getTestWebhookSecretKey(): ?string + { + return $this->test_webhook_secret_key; + } + + /** + * @param array $keys + */ + public function setLiveKeys(array $keys): void + { + $this->live_publishable_key = $keys['publishable_key']; + $this->live_secret_key = $keys['secret_key']; + } + + /** + * @param string $live_secret_key + */ + public function setLiveSecretKey(string $live_secret_key): void + { + $this->live_secret_key = $live_secret_key; + } + + /** + * @param string $live_publishable_key + */ + public function setLivePublishableKey(string $live_publishable_key): void + { + $this->live_publishable_key = $live_publishable_key; + } + + /** + * @param string $test_secret_key + */ + public function setTestSecretKey(string $test_secret_key): void + { + $this->test_secret_key = $test_secret_key; + } + + /** + * @param string $test_publishable_key + */ + public function setTestPublishableKey(string $test_publishable_key): void + { + $this->test_publishable_key = $test_publishable_key; + } + + /** + * @param array $keys + */ + public function setTestKeys(array $keys): void + { + $this->test_publishable_key = $keys['publishable_key']; + $this->test_secret_key = $keys['secret_key']; + } + + public function setLiveMode(): void + { + $this->test_mode_enabled = false; + $this->buildWebHook(); + } + + public function setTestMode(): void + { + $this->test_mode_enabled = true; + $this->buildWebHook(); + } + + /** + * @param array $webhook_data + */ + public function setLiveWebHookData(array $webhook_data): void + { + $this->live_webhook_id = $webhook_data['id']; + $this->live_webhook_secret_key = $webhook_data['secret_key']; + } + + /** + * @param array $webhook_data + */ + public function setTestWebHookData(array $webhook_data): void + { + $this->test_webhook_id = $webhook_data['id']; + $this->test_webhook_secret_key = $webhook_data['secret_key']; + } + + /** + * @return array + */ + private function createConfiguration(): array + { + if ($this->test_mode_enabled) { + return $this->createTestConfiguration(); + } + return $this->createLiveConfiguration(); + } + + /** + * @return array + */ + private function createTestConfiguration(): array + { + $params = [ + 'secret_key' => $this->test_secret_key + ]; + if (!empty($this->test_webhook_secret_key)) { + $params['webhook_secret_key'] = $this->test_webhook_secret_key; + } + return $params; + } + + /** + * @return array + */ + private function createLiveConfiguration(): array + { + $params = [ + 'secret_key' => $this->live_secret_key + ]; + if (!empty($this->live_webhook_secret_key)) { + $params['webhook_secret_key'] = $this->live_webhook_secret_key; + } + return $params; + } + + /** + * @throws ValidationException + */ + public function activate(): void + { + if (!$this->hasSecretKey()) { + throw new ValidationException("You can not activate a profile without a secret key set."); + } + + if (!$this->hasPublicKey()) { + throw new ValidationException("You can not activate a profile without a published key set."); + } + + parent::activate(); + + $this->buildWebHook(); + } + + public function disable(): void + { + parent::disable(); + $this->clearWebHooks(); + } + + /** + * @return bool + */ + public function hasSecretKey(): bool + { + if ($this->test_mode_enabled) { + return !empty($this->test_secret_key); + } + return !empty($this->live_secret_key); + } + + /** + * @return bool + */ + public function hasPublicKey(): bool + { + if ($this->test_mode_enabled) { + return !empty($this->test_publishable_key); + } + return !empty($this->live_publishable_key); + } + + /** + * @return bool + */ + public function existsWebHook(): bool + { + if ($this->test_mode_enabled) { + return !empty($this->test_webhook_id) || !empty($this->test_webhook_secret_key); + } + return !empty($this->live_webhook_id) || !empty($this->live_webhook_secret_key); + } + + /** + * @return bool + */ + public function existsWebHookTest(): bool + { + return !empty($this->test_webhook_id); + } + + /** + * @return bool + */ + public function existsWebHookLive(): bool + { + return !empty($this->live_webhook_id); + } + + /** + * @param array $info + */ + private function setWebHookInfo(array $info): void + { + if ($this->test_mode_enabled) { + $this->test_webhook_secret_key = $info['secret']; + $this->test_webhook_id = $info['id']; + return; + } + $this->live_webhook_secret_key = $info['secret']; + $this->live_webhook_id = $info['id']; + } + + /** + * @return null|string + */ + public function getWebHookSecretKey(): ?string + { + if ($this->test_mode_enabled) { + return $this->test_webhook_secret_key; + } + return $this->live_webhook_secret_key; + } + + /** + * @return null|string + */ + public function getWebHookId(): ?string + { + if ($this->test_mode_enabled) { + return $this->test_webhook_id; + } + return $this->live_webhook_id; + } + + public function buildWebHook(): void + { + try { + if (!$this->existsWebHook() && $this->hasSecretKey() && $this->hasSummit()) { + $api = new StripeApi($this->createConfiguration()); + // create it + $info = $api->createWebHook(action('PaymentGatewayWebHookController@confirm', [ + 'id' => $this->summit->getId(), + 'application_type' => $this->getApplicationType() + ])); + // and set web hook info + $this->setWebHookInfo($info); + } + } catch (\Exception $ex) { + Log::error($ex); + throw new ValidationException("Can not create the Stripe Webhook, please review your provided credentials."); + } + } + + /** + * @return IPaymentGatewayAPI + */ + public function buildPaymentGatewayApi(): IPaymentGatewayAPI + { + $api = new StripeApi($this->createConfiguration()); + if ($this->existsWebHook()) { + $api->setWebHookSecretKey($this->getWebHookSecretKey()); + } + return $api; + } + + private function clearTestWebHook(): void + { + try { + Log::debug("StripePaymentProfile::clearTestWebHook"); + if ($this->existsWebHookTest()) { + $api = new StripeApi($this->createTestConfiguration()); + // delete it + Log::debug(sprintf("StripePaymentProfile::clearTestWebHook deleting webhook %s", $this->getTestWebhookId())); + $api->deleteWebHookById($this->getTestWebhookId()); + Log::debug(sprintf("StripePaymentProfile::clearTestWebHook webhook %s deleted", $this->getTestWebhookId())); + $this->test_webhook_secret_key = $this->test_webhook_id = ''; + } + } catch (\Exception $ex) { + Log::error($ex); + } + } + + private function clearLiveWebHook(): void + { + try { + Log::debug("StripePaymentProfile::clearLiveWebHook"); + if ($this->existsWebHookLive()) { + $api = new StripeApi($this->createLiveConfiguration()); + // delete it + Log::debug(sprintf("StripePaymentProfile::clearLiveWebHook deleting webhook %s", $this->getTestWebhookId())); + $api->deleteWebHookById($this->getLiveWebhookId()); + Log::debug(sprintf("StripePaymentProfile::clearLiveWebHook webhook %s deleted", $this->getTestWebhookId())); + $this->live_webhook_secret_key = $this->live_webhook_id = ''; + + } + } catch (\Exception $ex) { + Log::error($ex); + } + } + + private function clearWebHooks(): void + { + Log::debug(sprintf("StripePaymentProfile::clearWebHooks")); + $this->clearLiveWebHook(); + $this->clearTestWebHook(); + } + + /** + * @ORM\PreRemove + */ + public function deleting($args) + { + // remove web hooks + $this->clearWebHooks(); + } + + /** + * @param string $live_webhook_secret_key + */ + public function setLiveWebhookSecretKey(string $live_webhook_secret_key): void + { + Log::debug(sprintf("StripePaymentProfile::setLiveWebhookSecretKey %s", $live_webhook_secret_key)); + $this->live_webhook_secret_key = $live_webhook_secret_key; + } + + /** + * @param string $test_webhook_secret_key + */ + public function setTestWebhookSecretKey(string $test_webhook_secret_key): void + { + Log::debug(sprintf("StripePaymentProfile::setTestWebhookSecretKey %s", $test_webhook_secret_key)); + $this->test_webhook_secret_key = $test_webhook_secret_key; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/PromoCodes/IOwnablePromoCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/IOwnablePromoCode.php new file mode 100644 index 00000000..6dc4f781 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/IOwnablePromoCode.php @@ -0,0 +1,28 @@ + self::ClassName, + 'first_name' => 'string', + 'last_name' => 'string', + 'email' => 'string', + 'type' => PromoCodesConstants::MemberSummitRegistrationPromoCodeTypes, + 'owner_id' => 'integer' + ]; + + /** + * @return array + */ + public static function getMetadata(){ + return array_merge(SummitRegistrationDiscountCode::getMetadata(), self::$metadata); + } + + /** + * @return string + */ + public function getClassName(){ + return self::ClassName; + } + + public function getOwnerFullname(): string + { + return $this->owner->getFullName(); + } + + public function getOwnerEmail(): string + { + return $this->owner->getEmail(); + } + + public function getOwnerType(): string + { + return "MEMBER"; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/PromoCodes/MemberSummitRegistrationPromoCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/MemberSummitRegistrationPromoCode.php new file mode 100644 index 00000000..dd830635 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/MemberSummitRegistrationPromoCode.php @@ -0,0 +1,68 @@ + self::ClassName, + 'first_name' => 'string', + 'last_name' => 'string', + 'email' => 'string', + 'type' => PromoCodesConstants::MemberSummitRegistrationPromoCodeTypes, + 'owner_id' => 'integer' + ]; + + /** + * @return array + */ + public static function getMetadata(){ + return array_merge(SummitRegistrationPromoCode::getMetadata(), self::$metadata); + } + + /** + * @return string + */ + public function getClassName(){ + return self::ClassName; + } + + public function getOwnerFullname(): string + { + return $this->owner->getFullName(); + } + + public function getOwnerEmail(): string + { + return $this->owner->getEmail(); + } + + public function getOwnerType(): string + { + return "MEMBER"; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/PromoCodes/PromoCodesConstants.php b/app/Models/Foundation/Summit/Registration/PromoCodes/PromoCodesConstants.php similarity index 52% rename from app/Models/Foundation/Summit/PromoCodes/PromoCodesConstants.php rename to app/Models/Foundation/Summit/Registration/PromoCodes/PromoCodesConstants.php index 1ced3b3d..d8611add 100644 --- a/app/Models/Foundation/Summit/PromoCodes/PromoCodesConstants.php +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/PromoCodesConstants.php @@ -11,9 +11,14 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use models\summit\MemberSummitRegistrationDiscountCode; use models\summit\MemberSummitRegistrationPromoCode; +use models\summit\SpeakerSummitRegistrationDiscountCode; use models\summit\SpeakerSummitRegistrationPromoCode; +use models\summit\SponsorSummitRegistrationDiscountCode; use models\summit\SponsorSummitRegistrationPromoCode; +use models\summit\SummitRegistrationDiscountCode; +use models\summit\SummitRegistrationPromoCode; /** * Class PromoCodesValidClasses * @package App\Models\Foundation\Summit\PromoCodes @@ -21,15 +26,28 @@ use models\summit\SponsorSummitRegistrationPromoCode; final class PromoCodesConstants { public static $valid_class_names = [ + SummitRegistrationPromoCode::ClassName, + SummitRegistrationDiscountCode::ClassName, SpeakerSummitRegistrationPromoCode::ClassName, SponsorSummitRegistrationPromoCode::ClassName, MemberSummitRegistrationPromoCode::ClassName, + MemberSummitRegistrationDiscountCode::ClassName, + SpeakerSummitRegistrationDiscountCode::ClassName, + SponsorSummitRegistrationDiscountCode::ClassName, ]; + const SpeakerSummitRegistrationPromoCodeTypeAccepted = 'ACCEPTED'; + const SpeakerSummitRegistrationPromoCodeTypeAlternate = 'ALTERNATE'; + + const MemberSummitRegistrationPromoCodeTypes = ["VIP","ATC","MEDIA ANALYST"]; + + const SponsorSummitRegistrationPromoCodeTypes = ["SPONSOR"]; + + const SpeakerSummitRegistrationPromoCodeTypes = [self::SpeakerSummitRegistrationPromoCodeTypeAccepted, self::SpeakerSummitRegistrationPromoCodeTypeAlternate]; /** * @return array */ public static function getValidTypes(){ - return array_merge(MemberSummitRegistrationPromoCode::$valid_type_values, SpeakerSummitRegistrationPromoCode::$valid_type_values); + return array_merge(self::MemberSummitRegistrationPromoCodeTypes, self::SpeakerSummitRegistrationPromoCodeTypes); } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/PromoCodes/SpeakerSummitRegistrationDiscountCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/SpeakerSummitRegistrationDiscountCode.php new file mode 100644 index 00000000..bb44dbe0 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/SpeakerSummitRegistrationDiscountCode.php @@ -0,0 +1,71 @@ + self::ClassName, + 'type' => PromoCodesConstants::SpeakerSummitRegistrationPromoCodeTypes, + 'speaker_id' => 'integer' + ]; + + /** + * @return array + */ + public static function getMetadata(){ + return array_merge(SummitRegistrationDiscountCode::getMetadata(), self::$metadata); + } + + public function hasOwner(): bool + { + return $this->hasSpeaker(); + } + + public function getOwnerFullname(): string + { + return $this->getSpeaker()->getFullName(); + } + + public function getOwnerEmail(): string + { + return $this->getSpeaker()->getEmail(); + } + + public function getOwnerType(): string + { + return "SPEAKER"; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/PromoCodes/SpeakerSummitRegistrationPromoCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/SpeakerSummitRegistrationPromoCode.php new file mode 100644 index 00000000..eeab74fe --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/SpeakerSummitRegistrationPromoCode.php @@ -0,0 +1,69 @@ + self::ClassName, + 'type' => PromoCodesConstants::SpeakerSummitRegistrationPromoCodeTypes, + 'speaker_id' => 'integer' + ]; + + /** + * @return array + */ + public static function getMetadata(){ + return array_merge(SummitRegistrationPromoCode::getMetadata(), self::$metadata); + } + + public function hasOwner(): bool + { + return $this->hasSpeaker(); + } + + public function getOwnerFullname(): string + { + return $this->getSpeaker()->getFullName(); + } + + public function getOwnerEmail(): string + { + return $this->getSpeaker()->getEmail(); + } + + public function getOwnerType(): string + { + return "SPEAKER"; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/PromoCodes/SponsorSummitRegistrationDiscountCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/SponsorSummitRegistrationDiscountCode.php new file mode 100644 index 00000000..a4ac0655 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/SponsorSummitRegistrationDiscountCode.php @@ -0,0 +1,51 @@ + self::ClassName, + 'sponsor_id' => 'integer', + 'type' => PromoCodesConstants::SponsorSummitRegistrationPromoCodeTypes, + ]; + + /** + * @return array + */ + public static function getMetadata(){ + return array_merge(MemberSummitRegistrationDiscountCode::getMetadata(), self::$metadata); + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/PromoCodes/SponsorSummitRegistrationPromoCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/SponsorSummitRegistrationPromoCode.php new file mode 100644 index 00000000..423a1c78 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/SponsorSummitRegistrationPromoCode.php @@ -0,0 +1,50 @@ + self::ClassName, + 'sponsor_id' => 'integer', + 'type' => PromoCodesConstants::SponsorSummitRegistrationPromoCodeTypes, + ]; + + /** + * @return array + */ + public static function getMetadata(){ + return array_merge(MemberSummitRegistrationPromoCode::getMetadata(), self::$metadata); + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationDiscountCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationDiscountCode.php new file mode 100644 index 00000000..6c0ce688 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationDiscountCode.php @@ -0,0 +1,225 @@ +rate; + } + + /** + * @param float $rate + * @throws ValidationException + */ + public function setRate(float $rate): void + { + if($this->amount > 0.0 && $rate > 0.0) + throw new ValidationException("discount amount already set"); + $this->rate = $rate; + } + + /** + * @param float $amount + * @throws ValidationException + */ + public function setAmount(float $amount): void + { + if($this->rate > 0.0 && $amount > 0.0) + throw new ValidationException("discount rate already set"); + $this->amount = $amount; + } + + /** + * @return float + */ + public function getAmount(): float + { + return $this->amount; + } + + public function __construct() + { + parent::__construct(); + $this->ticket_types_rules = new ArrayCollection(); + $this->amount = 0.0; + $this->rate = 0.0; + } + + public function getTicketTypesRules(){ + return $this->ticket_types_rules; + } + + /** + * @param SummitTicketType $ticket_type + * @return bool + */ + public function isOnRules(SummitTicketType $ticket_type) + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('ticket_type', $ticket_type)); + return $this->ticket_types_rules->matching($criteria)->count() > 0; + } + + /** + * @param SummitRegistrationDiscountCodeTicketTypeRule $rule + * @throws ValidationException + */ + public function addTicketTypeRule(SummitRegistrationDiscountCodeTicketTypeRule $rule){ + $rule->setDiscountCode($this); + if($this->ticket_types_rules->contains($rule)) return; + if ($this->isOnRules($rule->getTicketType())) + throw new ValidationException + ( + sprintf('ticket type %s already belongs to discount code %s rules.', $rule->getTicketType()->getId(), $this->getId()) + ); + $this->ticket_types_rules->add($rule); + } + + /** + * @param SummitTicketType $ticket_type + * @return SummitRegistrationDiscountCodeTicketTypeRule|null + */ + public function getRuleByTicketType(SummitTicketType $ticket_type){ + try { + $query = $this->createQuery("SELECT r from models\summit\SummitRegistrationDiscountCodeTicketTypeRule r + JOIN r.discount_code d + JOIN r.ticket_type t + WHERE d.id = :discount_code_id and t.id = :ticket_type_id + "); + return $query + ->setParameter('discount_code_id', $this->getIdentifier()) + ->setParameter('ticket_type_id', $ticket_type->getIdentifier()) + ->getSingleResult(); + } + catch(NoResultException $ex1){ + return null; + } + catch(NonUniqueResultException $ex2){ + // should never happen + return null; + } + } + + + /** + * @param SummitTicketType $ticketType + * @throws ValidationException + */ + public function removeTicketTypeRuleForTicketType(SummitTicketType $ticketType){ + $rule = $this->getRuleByTicketType($ticketType); + if(is_null($rule)) + throw new ValidationException + ( + sprintf('ticket type %s does not belongs to discount code %s rules.', $ticketType->getId(), $this->getId()) + ); + $this->ticket_types_rules->removeElement($rule); + $rule->clearDiscountCode(); + } + + /** + * @param SummitRegistrationDiscountCodeTicketTypeRule $rule + */ + public function removeTicketTypeRule(SummitRegistrationDiscountCodeTicketTypeRule $rule){ + if(!$this->ticket_types_rules->contains($rule)) return; + $this->ticket_types_rules->removeElement($rule); + } + + const ClassName = 'SUMMIT_DISCOUNT_CODE'; + + /** + * @return string + */ + public function getClassName(){ + return self::ClassName; + } + + public static $metadata = [ + 'rate' => 'float', + 'amount' => 'float', + 'ticket_types_rules' => 'array' + ]; + + /** + * @return array + */ + public static function getMetadata(){ + $parent_metadata = SummitRegistrationPromoCode::getMetadata(); + $parent_metadata['class_name']= SummitRegistrationDiscountCode::ClassName; + unset($parent_metadata['allowed_ticket_types']); + return array_merge($parent_metadata, SummitRegistrationDiscountCode::$metadata); + } + + /** + * @param SummitAttendeeTicket $ticket + * @return SummitAttendeeTicket + */ + public function applyTo(SummitAttendeeTicket $ticket){ + $ticket = parent::applyTo($ticket); + + if(!$ticket->isFree()) { + $amount2Discount = 0.0; + + if ($this->amount > 0.0) { + $amount2Discount = $this->amount; + } else if ($this->rate > 0.0) { + $amount2Discount = ($ticket->getRawCost() * $this->rate) / 100.00; + } else { + $rule = $this->getRuleByTicketType($ticket->getTicketType()); + if (!is_null($rule) && $rule->getAmount() > 0.0) { + $amount2Discount = $rule->getAmount(); + } else if (!is_null($rule) && $rule->getRate() > 0.0) { + $amount2Discount = ($ticket->getRawCost() * $rule->getRate()) / 100.00; + } + } + + $ticket->setDiscount($amount2Discount); + } + return $ticket; + } + + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationDiscountCodeTicketTypeRule.php b/app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationDiscountCodeTicketTypeRule.php new file mode 100644 index 00000000..a323a017 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationDiscountCodeTicketTypeRule.php @@ -0,0 +1,148 @@ +rate; + } + + /** + * @param float $rate + * @throws ValidationException + */ + public function setRate(float $rate): void + { + if($this->amount > 0.0 && $rate > 0.0) + throw new ValidationException("discount amount already set"); + $this->rate = $rate; + } + + /** + * @param float $amount + * @throws ValidationException + */ + public function setAmount(float $amount): void + { + if($this->rate > 0.0 && $amount > 0.0) + throw new ValidationException("discount rate already set"); + $this->amount = $amount; + } + + /** + * @return float + */ + public function getAmount(): ?float + { + return $this->amount; + } + + /** + * @return SummitTicketType + */ + public function getTicketType(): SummitTicketType + { + return $this->ticket_type; + } + + /** + * @param SummitTicketType $ticket_type + */ + public function setTicketType(SummitTicketType $ticket_type): void + { + $this->ticket_type = $ticket_type; + } + + /** + * @return SummitRegistrationDiscountCode + */ + public function getDiscountCode(): SummitRegistrationDiscountCode + { + return $this->discount_code; + } + + /** + * @param SummitRegistrationDiscountCode $discount_code + */ + public function setDiscountCode(SummitRegistrationDiscountCode $discount_code): void + { + $this->discount_code = $discount_code; + } + + public function __construct() + { + $this->amount = 0.0; + $this->rate = 0.0; + } + + public function clearDiscountCode(){ + $this->discount_code = null; + } + + public function getTicketTypeId(){ + try { + return is_null($this->ticket_type) ? 0 : $this->ticket_type->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + public function getDiscountCodeId(){ + try { + return is_null($this->discount_code) ? 0 : $this->discount_code->getId(); + } + catch(\Exception $ex){ + return 0; + } + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationPromoCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationPromoCode.php new file mode 100644 index 00000000..179350cf --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/SummitRegistrationPromoCode.php @@ -0,0 +1,575 @@ +summit = $summit; + } + + /** + * @return Summit + */ + public function getSummit(){ + return $this->summit; + } + + public function clearSummit(){ + $this->summit = null; + } + + /** + * @return int + */ + public function getSummitId(){ + try { + return $this->summit->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * @param $code + * @throws ValidationException + */ + public function setCode(string $code):void + { + $new_code = strtoupper(trim($code)); + if(empty($new_code)) + throw new ValidationException("code can not be empty!"); + $this->code = $new_code; + } + + /** + * @return bool + */ + public function isEmailSent() + { + return $this->email_sent; + } + + /** + * @param bool $email_sent + */ + public function setEmailSent($email_sent) + { + $this->email_sent = $email_sent; + } + + /** + * @return bool + */ + public function isRedeemed() + { + return $this->redeemed; + } + + /** + * @param bool $redeemed + */ + public function setRedeemed($redeemed) + { + $this->redeemed = $redeemed; + } + + /** + * @return string + */ + public function getSource() + { + return $this->source; + } + + /** + * @param string $source + */ + public function setSource($source) + { + $this->source = $source; + } + + /** + * @return Member + */ + public function getCreator() + { + return $this->creator; + } + + /** + * @param Member $creator + */ + public function setCreator($creator) + { + $this->creator = $creator; + } + + public function __construct() + { + parent::__construct(); + $this->email_sent = false; + $this->redeemed = false; + $this->quantity_available = 0; + $this->quantity_used = 0; + $this->valid_since_date = null; + $this->valid_until_date = null; + $this->badge_features = new ArrayCollection(); + $this->allowed_ticket_types = new ArrayCollection(); + } + + /** + * @return bool + */ + public function canUse():bool { + if($this->quantity_available > 0 && $this->quantity_available == $this->quantity_used) return false; + return $this->isLive(); + } + + /** + * @param string $email + * @param null|string $company + * @return bool + * @throw ValidationException + */ + public function checkSubject(string $email, ?string $company):bool{ + return true; + } + + /** + * @return bool + */ + public function isLive():bool { + // if valid period is not set , that is valid_since_date == valid_until_date == null , then promo code lives forever + $now_utc = new \DateTime('now', new \DateTimeZone('UTC')); + if(!is_null($this->valid_since_date) && !is_null($this->valid_until_date) && ($now_utc < $this->valid_since_date || $now_utc > $this->valid_until_date)){ + return false; + } + return true; + } + + /** + * @param int $usage + * @throws ValidationException + */ + public function addUsage(int $usage){ + Log::debug + ( + sprintf + ( + "SummitRegistrationPromoCode::addUsage code %s usage %s quantity_used %s quantity_available %s", + $this->code, + $usage, + $this->quantity_used, + $this->quantity_available + ) + ); + $new_value = $this->quantity_used + $usage; + if($this->quantity_available > 0 && $new_value > $this->quantity_available){ + throw new ValidationException(sprintf("promo code %s has reached max usage", $this->code)); + } + $this->quantity_used = $new_value; + } + + /** + * @param int $to_restore + * @throws ValidationException + */ + public function removeUsage(int $to_restore){ + Log::debug + ( + sprintf + ( + "SummitRegistrationPromoCode::removeUsage code %s to_restore %s quantity_used %s quantity_available %s", + $this->code, + $to_restore, + $this->quantity_used, + $this->quantity_available + ) + ); + + if(($this->quantity_used - $to_restore) < 0) + throw new ValidationException + ( + sprintf + ( + "Can not restore %s usages to promo code %s - current usages %s", $to_restore, $this->code, $this->quantity_used + ) + ); + + $this->quantity_used -= $to_restore; + + Log::info(sprintf("SummitRegistrationPromoCode::removeUsage quantity_used %s", $this->quantity_used)); + } + + public function canBeAppliedTo(SummitTicketType $ticketType):bool{ + if($this->allowed_ticket_types->count() > 0){ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($ticketType->getId()))); + return $this->allowed_ticket_types->matching($criteria)->count() > 0; + } + return true; + } + + /** + * @return int + */ + public function getBadgeTypeId(){ + try { + return is_null($this->badge_type) ? 0: $this->badge_type->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return bool + */ + public function hasBadgeType(){ + return $this->getBadgeTypeId() > 0; + } + + public function clearBadgeType(){ + $this->badge_type = null; + } + + public function setSourceAdmin(){ + $this->source = 'ADMIN'; + } + + /** + * @return int + */ + public function getCreatorId(){ + try { + return is_null($this->creator) ? 0: $this->creator->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return bool + */ + public function hasCreator(){ + return $this->getCreatorId() > 0; + } + + const ClassName = 'SUMMIT_PROMO_CODE'; + + /** + * @return string + */ + public function getClassName(){ + return self::ClassName; + } + + public static $metadata = [ + 'class_name' => self::ClassName, + 'code' => 'string', + 'email_sent' => 'boolean', + 'redeemed' => 'boolean', + 'quantity_available' => 'integer', + 'valid_since_date' => 'datetime', + 'valid_until_date' => 'datetime', + 'source' => ['CSV','ADMIN'], + 'summit_id' => 'integer', + 'badge_type_id' => 'integer', + 'creator_id' => 'integer', + 'allowed_ticket_types' => 'array', + ]; + + /** + * @return array + */ + public static function getMetadata(){ + return self::$metadata; + } + + /** + * @return SummitBadgeFeatureType[] + */ + public function getBadgeFeatures() + { + return $this->badge_features; + } + + /** + * @return SummitTicketType[] + */ + public function getAllowedTicketTypes() + { + return $this->allowed_ticket_types; + } + + public function getQuantityUsed():int{ + return $this->quantity_used; + } + + /** + * @return int + */ + public function getQuantityAvailable(): int + { + return $this->quantity_available; + } + + /** + * @param int $quantity_available + */ + public function setQuantityAvailable(int $quantity_available): void + { + $this->quantity_available = $quantity_available; + } + + /** + * @return \DateTime|null + */ + public function getValidSinceDate(): ?\DateTime + { + return $this->valid_since_date; + } + + /** + * @param \DateTime $valid_since_date + */ + public function setValidSinceDate(?\DateTime $valid_since_date): void + { + $this->valid_since_date = $valid_since_date; + } + + /** + * @return \DateTime|null + */ + public function getValidUntilDate(): ?\DateTime + { + return $this->valid_until_date; + } + + /** + * @param \DateTime $valid_until_date + */ + public function setValidUntilDate(?\DateTime $valid_until_date): void + { + $this->valid_until_date = $valid_until_date; + } + + /** + * @return SummitBadgeType + */ + public function getBadgeType(): ?SummitBadgeType + { + return $this->badge_type; + } + + /** + * @param SummitBadgeType $badge_type + */ + public function setBadgeType(SummitBadgeType $badge_type): void + { + $this->badge_type = $badge_type; + } + + /** + * @param SummitTicketType $ticket_type + */ + public function addAllowedTicketType(SummitTicketType $ticket_type){ + if($this->allowed_ticket_types->contains($ticket_type)) return; + $this->allowed_ticket_types->add($ticket_type); + } + + /** + * @param SummitTicketType $ticket_type + */ + public function removeAllowedTicketType(SummitTicketType $ticket_type){ + if(!$this->allowed_ticket_types->contains($ticket_type)) return; + $this->allowed_ticket_types->removeElement($ticket_type); + } + + /** + * @param SummitBadgeFeatureType $feature_type + */ + public function addBadgeFeatureType(SummitBadgeFeatureType $feature_type){ + if($this->badge_features->contains($feature_type)) return; + $this->badge_features->add($feature_type); + } + + /** + * @param SummitBadgeFeatureType $feature_type + */ + public function removeBadgeFeatureType(SummitBadgeFeatureType $feature_type){ + if(!$this->badge_features->contains($feature_type)) return; + $this->badge_features->removeElement($feature_type); + } + + /** + * @param SummitAttendeeTicket $ticket + * @return SummitAttendeeTicket + */ + public function applyTo(SummitAttendeeTicket $ticket){ + if($this->hasBadgeType()){ + $badge = $ticket->hasBadge() ? $ticket->getBadge() : new SummitAttendeeBadge(); + $ticket->setBadge($badge->applyPromoCode($this)); + } + $ticket->setPromoCode($this); + return $ticket; + } + + /** + * @return string + */ + public function getExternalId(): ?string + { + return $this->external_id; + } + + /** + * @param string $external_id + */ + public function setExternalId(string $external_id): void + { + $this->external_id = $external_id; + } + +} diff --git a/app/Models/Foundation/Summit/PromoCodes/MemberSummitRegistrationPromoCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/Traits/MemberPromoCodeTrait.php similarity index 78% rename from app/Models/Foundation/Summit/PromoCodes/MemberSummitRegistrationPromoCode.php rename to app/Models/Foundation/Summit/Registration/PromoCodes/Traits/MemberPromoCodeTrait.php index 5ed0b267..02ebc9ee 100644 --- a/app/Models/Foundation/Summit/PromoCodes/MemberSummitRegistrationPromoCode.php +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/Traits/MemberPromoCodeTrait.php @@ -1,6 +1,6 @@ owner = $owner; } - const ClassName = 'MEMBER_PROMO_CODE'; - - public static $metadata = [ - 'class_name' => self::ClassName, - 'first_name' => 'string', - 'last_name' => 'string', - 'email' => 'string', - 'type' => ['VIP','ATC','MEDIA ANALYST'], - 'owner_id' => 'integer' - ]; - - /** - * @return array - */ - public static function getMetadata(){ - return array_merge(SummitRegistrationPromoCode::getMetadata(), self::$metadata); - } - - /** - * @return string - */ - public function getClassName(){ - return self::ClassName; - } - /** * @return int */ @@ -192,4 +165,16 @@ class MemberSummitRegistrationPromoCode extends SummitRegistrationPromoCode return $this->getOwnerId() > 0; } + /** + * @param string $email + * @param null|string $company + * @return bool + * @throw ValidationException + */ + public function checkSubject(string $email, ?string $company):bool{ + if($this->hasOwner() && $this->getOwnerEmail() != $email){ + throw new ValidationException(sprintf('The Promo Code “%s” is not valid for the %s. Promo Code restrictions are associated with the purchaser email not the attendee.', $this->getCode(), $email)); + } + return true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/PromoCodes/SpeakerSummitRegistrationPromoCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/Traits/SpeakerPromoCodeTrait.php similarity index 63% rename from app/Models/Foundation/Summit/PromoCodes/SpeakerSummitRegistrationPromoCode.php rename to app/Models/Foundation/Summit/Registration/PromoCodes/Traits/SpeakerPromoCodeTrait.php index 75b7cba2..358dbfae 100644 --- a/app/Models/Foundation/Summit/PromoCodes/SpeakerSummitRegistrationPromoCode.php +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/Traits/SpeakerPromoCodeTrait.php @@ -1,6 +1,6 @@ speaker = $speaker; } - public function __construct() - { - parent::__construct(); - $this->redeemed = false; - } - /** * @return int */ @@ -93,27 +86,16 @@ class SpeakerSummitRegistrationPromoCode extends SummitRegistrationPromoCode return $this->getSpeakerId() > 0; } - const ClassName = 'SPEAKER_PROMO_CODE'; - /** - * @return string + * @param string $email + * @param null|string $company + * @return bool + * @throw ValidationException */ - public function getClassName(){ - return self::ClassName; + public function checkSubject(string $email, ?string $company):bool{ + if($this->hasOwner() && $this->getOwnerEmail() != $email){ + throw new ValidationException(sprintf('The Promo Code “%s” is not valid for the %s. Promo Code restrictions are associated with the purchaser email not the attendee.', $this->getCode(), $email)); + } + return true; } - - public static $metadata = [ - 'class_name' => self::ClassName, - 'type' => ["ACCEPTED", "ALTERNATE"], - 'speaker_id' => 'integer' - ]; - - /** - * @return array - */ - public static function getMetadata(){ - return array_merge(SummitRegistrationPromoCode::getMetadata(), self::$metadata); - } - - public static $valid_type_values = ["ACCEPTED", "ALTERNATE"]; } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/PromoCodes/SponsorSummitRegistrationPromoCode.php b/app/Models/Foundation/Summit/Registration/PromoCodes/Traits/SponsorPromoCodeTrait.php similarity index 62% rename from app/Models/Foundation/Summit/PromoCodes/SponsorSummitRegistrationPromoCode.php rename to app/Models/Foundation/Summit/Registration/PromoCodes/Traits/SponsorPromoCodeTrait.php index d07effd7..ece39f12 100644 --- a/app/Models/Foundation/Summit/PromoCodes/SponsorSummitRegistrationPromoCode.php +++ b/app/Models/Foundation/Summit/Registration/PromoCodes/Traits/SponsorPromoCodeTrait.php @@ -1,6 +1,6 @@ sponsor; - } - - /** - * @param Company $sponsor - */ - public function setSponsor($sponsor) - { - $this->sponsor = $sponsor; - } - - const ClassName = 'SPONSOR_PROMO_CODE'; - - /** - * @return string - */ - public function getClassName(){ - return self::ClassName; - } - /** * @return int */ @@ -80,16 +57,37 @@ class SponsorSummitRegistrationPromoCode extends MemberSummitRegistrationPromoCo return $this->getSponsorId() > 0; } - public static $metadata = [ - 'class_name' => self::ClassName, - 'sponsor_id' => 'integer', - 'type' => ['SPONSOR'], - ]; + /** + * @return Company + */ + public function getSponsor() + { + return $this->sponsor; + } /** - * @return array + * @param Company $sponsor */ - public static function getMetadata(){ - return array_merge(MemberSummitRegistrationPromoCode::getMetadata(), self::$metadata); + public function setSponsor($sponsor) + { + $this->sponsor = $sponsor; + } + + /** + * @param string $email + * @param null|string $company + * @return bool + * @throw ValidationException + */ + public function checkSubject(string $email, ?string $company):bool{ + + if($this->hasOwner() && $this->getOwnerEmail() != $email){ + throw new ValidationException(sprintf('The Promo Code “%s” is not valid for the %s. Promo Code restrictions are associated with the purchaser email not the attendee.', $this->getCode(), $email)); + } + + if(!empty($company) &&$this->hasSponsor() && $this->getSponsor()->getName() != $company){ + throw new ValidationException(sprintf("The Promo Code %s is not available for Company %s", $this->getCode(), $company)); + } + return true; } } \ No newline at end of file diff --git a/app/Repositories/Main/DoctrineEmailCreationRequestRepository.php b/app/Models/Foundation/Summit/Registration/QRGeneratorTrait.php similarity index 54% rename from app/Repositories/Main/DoctrineEmailCreationRequestRepository.php rename to app/Models/Foundation/Summit/Registration/QRGeneratorTrait.php index aebd3c59..7705e687 100644 --- a/app/Repositories/Main/DoctrineEmailCreationRequestRepository.php +++ b/app/Models/Foundation/Summit/Registration/QRGeneratorTrait.php @@ -1,6 +1,6 @@ -name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return string + */ + public function getPlaceholder(): string + { + return $this->placeholder; + } + + /** + * @param string $placeholder + */ + public function setPlaceholder(string $placeholder): void + { + $this->placeholder = $placeholder; + } + + /** + * @param string $type + * @throws ValidationException + */ + public function setType(string $type): void + { + if(!in_array($type, SummitOrderExtraQuestionTypeConstants::ValidQuestionTypes)) + throw new ValidationException(sprintf("%s type is not valid", $type)); + + $this->type = $type; + } + + /** + * @return string + */ + public function getLabel(): string + { + return $this->label; + } + + /** + * @param string $label + */ + public function setLabel(string $label): void + { + $this->label = $label; + } + + /** + * @return int + */ + public function getOrder(): int + { + return $this->order; + } + + /** + * @param int $order + */ + public function setOrder($order): void + { + $this->order = $order; + } + + /** + * @return bool + */ + public function isMandatory(): bool + { + return $this->mandatory; + } + + /** + * @param bool $mandatory + */ + public function setMandatory(bool $mandatory): void + { + $this->mandatory = $mandatory; + } + + /** + * @return string + */ + public function getUsage(): string + { + return $this->usage; + } + + /** + * @param string $usage + * @throws ValidationException + */ + public function setUsage(string $usage): void + { + if(!in_array($usage, SummitOrderExtraQuestionTypeConstants::ValidQuestionUsages)) + throw new ValidationException(sprintf("%s usage is not valid", $usage)); + $this->usage = $usage; + } + + /** + * @return bool + */ + public function isPrintable(): bool + { + return $this->printable; + } + + /** + * @param bool $printable + */ + public function setPrintable(bool $printable): void + { + $this->printable = $printable; + } + + public function __construct() + { + parent::__construct(); + $this->values = new ArrayCollection(); + $this->mandatory = false; + $this->printable = false; + } + + /** + * @return SummitOrderExtraQuestionValue[] + */ + public function getValues() + { + return $this->values; + } + + /** + * @param SummitOrderExtraQuestionValue $value + * @throws ValidationException + */ + public function addValue(SummitOrderExtraQuestionValue $value){ + if(!$this->allowsValues()) + throw new ValidationException(sprintf("%s type does not allow multivalues", $this->type)); + if($this->values->contains($value)) return; + $this->values->add($value); + $value->setQuestion($this); + $value->setOrder($this->getValueMaxOrder() + 1); + } + + /** + * @return int + */ + private function getValueMaxOrder():int{ + $criteria = Criteria::create(); + $criteria->orderBy(['order' => 'DESC']); + $value = $this->values->matching($criteria)->first(); + return $value === false ? 0 : $value->getOrder(); + } + + public function allowsValues():bool { + return in_array($this->type, SummitOrderExtraQuestionTypeConstants::AllowedMultivalueQuestionType); + } + /** + * @param SummitOrderExtraQuestionValue $value + * @throws ValidationException + */ + public function removeValue(SummitOrderExtraQuestionValue $value){ + if(!$this->allowsValues()) + throw new ValidationException(sprintf("%s type does not allow multivalues", $this->type)); + + if(!$this->values->contains($value)) return; + $this->values->removeElement($value); + } + + /** + * @param string $label + * @return SummitOrderExtraQuestionValue|null + */ + public function getValueByLabel(string $label):?SummitOrderExtraQuestionValue{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('label', trim($label))); + $value = $this->values->matching($criteria)->first(); + return $value === false ? null : $value; + } + + /** + * @param string $name + * @return SummitOrderExtraQuestionValue|null + */ + public function getValueByName(string $name):?SummitOrderExtraQuestionValue{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('value', trim($name))); + $value = $this->values->matching($criteria)->first(); + return $value === false ? null : $value; + } + + /** + * @param string $value + * @return bool + */ + public function allowValue(string $value):bool{ + + if(empty($value) && !$this->isMandatory()) return true; + + if($this->type == SummitOrderExtraQuestionTypeConstants::ComboBoxQuestionType) + return !is_null($this->getValueById(intval($value))); + + foreach (explode(',',$value) as $v) + { + if(is_null($this->getValueById(intval($v)))) + return false; + } + return true; + } + + /** + * @param int $id + * @return SummitOrderExtraQuestionValue|null + */ + public function getValueById(int $id):?SummitOrderExtraQuestionValue{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', $id)); + $value = $this->values->matching($criteria)->first(); + return $value === false ? null : $value; + } + + use OrderableChilds; + + /** + * @param SummitOrderExtraQuestionValue $value + * @param int $new_order + * @throws ValidationException + */ + public function recalculateValueOrder(SummitOrderExtraQuestionValue $value, $new_order){ + self::recalculateOrderForSelectable($this->values, $value, $new_order); + } + + /** + * @param string $value + * @return string|null + */ + public function getNiceValue(string $value):?string { + if($this->values->count() == 0) return $value; + + $value = explode(',' , $value); + $dict = []; + $niceValues = []; + + foreach ($this->values as $questionValue){ + $dict[$questionValue->getId()] = $questionValue->getLabel(); + } + + foreach($value as $v){ + $nv = $dict[$v] ?? null; + if(!empty($nv)){ + $niceValues[] = $nv; + } + } + + return implode(',', $niceValues); + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/Questions/SummitOrderExtraQuestionTypeConstants.php b/app/Models/Foundation/Summit/Registration/Questions/SummitOrderExtraQuestionTypeConstants.php new file mode 100644 index 00000000..b0b8587d --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/Questions/SummitOrderExtraQuestionTypeConstants.php @@ -0,0 +1,54 @@ +label; + } + + /** + * @param string $label + */ + public function setLabel(string $label): void + { + $this->label = $label; + } + + /** + * @return string + */ + public function getValue(): ?string + { + return $this->value; + } + + /** + * @param string $value + */ + public function setValue(string $value): void + { + $this->value = $value; + } + + /** + * @return int + */ + public function getOrder(): int + { + return $this->order; + } + + /** + * @param int $order + */ + public function setOrder($order): void + { + $this->order = $order; + } + + /** + * @return SummitOrderExtraQuestionType + */ + public function getQuestion(): SummitOrderExtraQuestionType + { + return $this->question; + } + + /** + * @param SummitOrderExtraQuestionType $question + */ + public function setQuestion(SummitOrderExtraQuestionType $question): void + { + $this->question = $question; + } + + public function __construct() + { + parent::__construct(); + $this->order = 0; + } + + /** + * @return int + */ + public function getQuestionId():int{ + try { + return is_null($this->question) ? 0 : $this->question->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SponsorBadgeScan.php b/app/Models/Foundation/Summit/Registration/SponsorBadgeScan.php new file mode 100644 index 00000000..a7515d96 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SponsorBadgeScan.php @@ -0,0 +1,155 @@ + 'sponsor', + 'getUserId' => 'user', + 'getBadgeId' => 'badge', + ]; + + protected $hasPropertyMappings = [ + 'hasSponsor' => 'sponsor', + 'hasUser' => 'user', + 'hasBadge' => 'badge', + ]; + + /** + * @ORM\Column(name="QRCode", type="string") + * @var string + */ + private $qr_code; + + /** + * @ORM\ManyToOne(targetEntity="models\summit\Sponsor", inversedBy="badge_scans") + * @ORM\JoinColumn(name="SponsorID", referencedColumnName="ID") + * @var Sponsor + */ + private $sponsor; + + /** + * @var \DateTime + * @ORM\Column(name="ScanDate", type="datetime") + */ + protected $scan_date; + + /** + * @ORM\ManyToOne(targetEntity="models\main\Member") + * @ORM\JoinColumn(name="UserID", referencedColumnName="ID") + * @var Member + */ + private $user; + + /** + * @ORM\ManyToOne(targetEntity="models\summit\SummitAttendeeBadge") + * @ORM\JoinColumn(name="BadgeID", referencedColumnName="ID") + * @var SummitAttendeeBadge + */ + private $badge; + + /** + * @return string + */ + public function getQRCode(): string + { + return $this->qr_code; + } + + /** + * @param string $qr_code + */ + public function setQRCode(string $qr_code): void + { + $this->qr_code = $qr_code; + } + + /** + * @return Sponsor + */ + public function getSponsor(): Sponsor + { + return $this->sponsor; + } + + /** + * @param Sponsor $sponsor + */ + public function setSponsor(Sponsor $sponsor): void + { + $this->sponsor = $sponsor; + } + + /** + * @return Member + */ + public function getUser(): Member + { + return $this->user; + } + + /** + * @param Member $user + */ + public function setUser(Member $user): void + { + $this->user = $user; + } + + /** + * @return SummitAttendeeBadge + */ + public function getBadge(): SummitAttendeeBadge + { + return $this->badge; + } + + /** + * @param SummitAttendeeBadge $badge + */ + public function setBadge(SummitAttendeeBadge $badge): void + { + $this->badge = $badge; + } + + /** + * @return \DateTime + */ + public function getScanDate(): \DateTime + { + return $this->scan_date; + } + + /** + * @param \DateTime $scan_date + */ + public function setScanDate(\DateTime $scan_date): void + { + $this->scan_date = $scan_date; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SummitAccessLevelType.php b/app/Models/Foundation/Summit/Registration/SummitAccessLevelType.php new file mode 100644 index 00000000..3174f704 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SummitAccessLevelType.php @@ -0,0 +1,129 @@ +name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return string + */ + public function getDescription(): ?string + { + return $this->description; + } + + /** + * @param string $description + */ + public function setDescription(string $description): void + { + $this->description = $description; + } + + /** + * @return string + */ + public function getTemplateContent(): ?string + { + return $this->template_content; + } + + /** + * @param string $template_content + */ + public function setTemplateContent(string $template_content): void + { + $this->template_content = $template_content; + } + + /** + * @return bool + */ + public function isDefault(): bool + { + return $this->is_default; + } + + /** + * @param bool $is_default + */ + public function setIsDefault(bool $is_default): void + { + $this->is_default = $is_default; + } + + + public function __construct() + { + parent::__construct(); + $this->template_content = ''; + $this->is_default = false; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/SummitTicketType.php b/app/Models/Foundation/Summit/Registration/SummitBadgeFeatureType.php similarity index 66% rename from app/Models/Foundation/Summit/SummitTicketType.php rename to app/Models/Foundation/Summit/Registration/SummitBadgeFeatureType.php index 7a9fed16..e5c85933 100644 --- a/app/Models/Foundation/Summit/SummitTicketType.php +++ b/app/Models/Foundation/Summit/Registration/SummitBadgeFeatureType.php @@ -1,6 +1,6 @@ name; } @@ -59,7 +59,7 @@ class SummitTicketType extends SilverstripeBaseModel /** * @param string $name */ - public function setName($name) + public function setName(string $name): void { $this->name = $name; } @@ -67,7 +67,7 @@ class SummitTicketType extends SilverstripeBaseModel /** * @return string */ - public function getDescription() + public function getDescription(): ?string { return $this->description; } @@ -75,7 +75,7 @@ class SummitTicketType extends SilverstripeBaseModel /** * @param string $description */ - public function setDescription($description) + public function setDescription(string $description): void { $this->description = $description; } @@ -83,19 +83,22 @@ class SummitTicketType extends SilverstripeBaseModel /** * @return string */ - public function getExternalId(){return $this->external_id; } + public function getTemplateContent(): ?string + { + return $this->template_content; + } /** - * @param string $external_id + * @param string $template_content */ - public function setExternalId($external_id) + public function setTemplateContent(string $template_content): void { - $this->external_id = $external_id; + $this->template_content = $template_content; } public function __construct() { parent::__construct(); + $this->template_content = ''; } - } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SummitBadgeType.php b/app/Models/Foundation/Summit/Registration/SummitBadgeType.php new file mode 100644 index 00000000..69ff4159 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SummitBadgeType.php @@ -0,0 +1,257 @@ +name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return string + */ + public function getDescription(): string + { + return $this->description; + } + + /** + * @param string $description + */ + public function setDescription(string $description): void + { + $this->description = $description; + } + + /** + * @return string + */ + public function getTemplateContent(): ?string + { + return $this->template_content; + } + + /** + * @param string $template_content + */ + public function setTemplateContent(string $template_content): void + { + $this->template_content = $template_content; + } + + /** + * @return bool + */ + public function isDefault(): bool + { + return $this->default; + } + + /** + * @param bool $is_default + */ + public function setIsDefault(bool $is_default): void + { + $this->default = $is_default; + } + + public function __construct() + { + parent::__construct(); + $this->template_content = ''; + $this->default = false; + $this->badge_features = new ArrayCollection(); + $this->access_levels = new ArrayCollection(); + } + + /** + * @return SummitAccessLevelType[] + */ + public function getAccessLevels() + { + return $this->access_levels; + } + + /** + * @return SummitBadgeFeatureType[] + */ + public function getBadgeFeatures() + { + return $this->badge_features; + } + + /** + * @param SummitBadgeFeatureType $feature_type + */ + public function addBadgeFeatureType(SummitBadgeFeatureType $feature_type){ + if($this->badge_features->contains($feature_type)) return; + $this->badge_features->add($feature_type); + } + + /** + * @param SummitBadgeFeatureType $feature_type + */ + public function removeBadgeFeatureType(SummitBadgeFeatureType $feature_type){ + if(!$this->badge_features->contains($feature_type)) return; + $this->badge_features->removeElement($feature_type); + } + + /** + * @param SummitAccessLevelType $access_level + */ + public function addAccessLevel(SummitAccessLevelType $access_level){ + if($this->access_levels->contains($access_level)) return; + $this->access_levels->add($access_level); + } + + /** + * @param SummitAccessLevelType $access_level + */ + public function removeAccessLevel(SummitAccessLevelType $access_level){ + if(!$this->access_levels->contains($access_level)) return; + $this->access_levels->removeElement($access_level); + } + + /** + * @param int $access_level_id + * @return SummitAccessLevelType|null + */ + public function getAccessLevelById(int $access_level_id):?SummitAccessLevelType + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($access_level_id))); + $access_level = $this->access_levels->matching($criteria)->first(); + return $access_level === false ? null : $access_level; + } + + /** + * @param string $access_level_name + * @return SummitAccessLevelType|null + */ + public function getAccessLevelByName(string $access_level_name):?SummitAccessLevelType + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', $access_level_name)); + $access_level = $this->access_levels->matching($criteria)->first(); + return $access_level === false ? null : $access_level; + } + + /** + * @param int $badge_feature_id + * @return SummitBadgeFeatureType|null + */ + public function getBadgeFeatureById(int $badge_feature_id):?SummitBadgeFeatureType + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($badge_feature_id))); + $badge_feature = $this->badge_features->matching($criteria)->first(); + return $badge_feature === false ? null : $badge_feature; + } + + /** + * @param string $badge_feature_name + * @return SummitBadgeFeatureType|null + */ + public function getBadgeFeatureByName(string $badge_feature_name):?SummitBadgeFeatureType + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', $badge_feature_name)); + $badge_feature = $this->badge_features->matching($criteria)->first(); + return $badge_feature === false ? null : $badge_feature; + } + + /** + * @param SummitBadgeType $type + * @return SummitAttendeeBadge + */ + public static function buildBadgeFromType(SummitBadgeType $type):SummitAttendeeBadge{ + $badge = new SummitAttendeeBadge(); + $badge->setType($type); + return $badge; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SummitOrder.php b/app/Models/Foundation/Summit/Registration/SummitOrder.php new file mode 100644 index 00000000..c6342247 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SummitOrder.php @@ -0,0 +1,1061 @@ +tickets = new ArrayCollection(); + $this->extra_question_answers = new ArrayCollection(); + $this->status = IOrderConstants::ReservedStatus; + $this->payment_method = IOrderConstants::OnlinePaymentMethod; + $this->refunded_amount = 0.0; + } + + + public function setPaymentMethodOffline(){ + $this->payment_method = IOrderConstants::OfflinePaymentMethod; + } + + public function generateHash(){ + $email = $this->getOwnerEmail(); + if(empty($email)) + throw new ValidationException("owner email is null"); + + $fname = $this->getOwnerFirstName(); + if(empty($fname)) + throw new ValidationException("owner first name is null"); + + $lname = $this->getOwnerSurname(); + if(empty($lname)) + throw new ValidationException("owner first last name is null"); + + $token = $this->number.'.'.$email.'.'.$fname.".".$lname; + $token = $token . random_bytes(16).time(); + $this->hash = hash('sha256', $token); + $this->hash_creation_date = new \DateTime('now', new \DateTimeZone('UTC')); + } + + /** + * @return bool + * @throws \Exception + */ + public function canPubliclyEdit():bool { + if(empty($this->hash) || is_null($this->hash_creation_date)) return false; + $ttl_minutes = Config::get("registration.order_public_edit_ttl", 10); + $eol = new \DateTime('now', new \DateTimeZone('UTC')); + $eol->sub(new \DateInterval('PT'.$ttl_minutes.'M')); + if($this->hash_creation_date <= $eol) + return false; + return true; + } + + /** + * @return string + */ + public function generateNumber():string{ + $this->number = strtoupper(str_replace(".","", uniqid($this->summit->getOrderQRPrefix().'_', true))); + $this->generateQRCode(); + return $this->number; + } + + /** + * @return string + */ + public function getNumber(): string + { + return $this->number; + } + + /** + * @param string $number + */ + public function setNumber(string $number): void + { + $this->number = $number; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + + public function setPaidStatus(){ + $this->status = IOrderConstants::PaidStatus; + $this->approved_payment_date = new \DateTime('now', new \DateTimeZone('UTC')); + + } + + public function setPaid(){ + if($this->isPaid()){ + Log::warning(sprintf("SummitOrder %s is already Paid.", $this->getId())); + return; + } + + $this->setPaidStatus(); + + foreach($this->tickets as $ticket){ + $ticket->setPaid(); + } + + Event::fire(new PaymentSummitRegistrationOrderConfirmed($this->getId())); + } + + /** + * @param null|string $error + */ + public function setPaymentError(?string $error):void{ + if(empty($error)) return; + $this->status = IOrderConstants::ErrorStatus; + $this->last_error = $error; + } + + public function setConfirmed(){ + if($this->status == IOrderConstants::ReservedStatus) + $this->status = IOrderConstants::ConfirmedStatus; + } + + /** + * @param bool $sendMail + */ + public function setCancelled(bool $sendMail = true):void { + $ignore_statuses = [ IOrderConstants::PaidStatus, IOrderConstants::CancelledStatus]; + + if(in_array($this->status, $ignore_statuses)) return; + $this->status = IOrderConstants::CancelledStatus; + list($tickets_to_return, $promo_codes_to_return) = $this->calculateTicketsAndPromoCodesToReturn(); + + foreach ($this->getTickets() as $ticket){ + $ticket->setCancelled(); + } + + Event::fire(new SummitOrderCanceled($this->id, $sendMail, $tickets_to_return, $promo_codes_to_return)); + } + + /** + * @return array + */ + public function calculateTicketsAndPromoCodesToReturn():array { + $tickets_to_return = []; + $promo_codes_to_return = []; + + foreach($this->tickets as $ticket){ + if($ticket->isCancelled()) continue; + if($ticket->isRefunded()) continue; + if(!isset($tickets_to_return[$ticket->getTicketTypeId()])) + $tickets_to_return[$ticket->getTicketTypeId()] = 0; + $tickets_to_return[$ticket->getTicketTypeId()] += 1; + if($ticket->hasPromoCode()){ + if(!isset($promo_codes_to_return[$ticket->getPromoCode()->getCode()])) + $promo_codes_to_return[$ticket->getPromoCode()->getCode()] = 0; + $promo_codes_to_return[$ticket->getPromoCode()->getCode()] +=1; + } + } + return [$tickets_to_return, $promo_codes_to_return]; + } + + /** + * @throws ValidationException + */ + public function requestRefund():void{ + $summit = $this->getSummit(); + + $begin_date = $summit->getBeginDate(); + if(is_null($begin_date)) return; + + // check tickets badge printings + + if($this->getRawAmount() == 0 ) + + foreach ($this->tickets as $ticket){ + if($ticket->isBadgePrinted()){ + throw new ValidationException(sprintf( "you can not request a refund for this ticket %s ( badge already printed)", $ticket->getNumber())); + } + } + + $now = new \DateTime('now', new \DateTimeZone('UTC')); + + if($now > $begin_date){ + Log::debug("SummitOrder::requestRefund: now is greater than Summit.BeginDate"); + throw new ValidationException("you can not request a refund after summit started"); + } + + $interval = $begin_date->diff($now); + + $days_before_event_starts = intval($interval->format('%a')); + + Log::debug(sprintf("SummitOrder::requestRefund: days_before_event_starts %s", $days_before_event_starts)); + + if($this->status != IOrderConstants::PaidStatus){ + throw new ValidationException("you can not request a refund on this order"); + } + + $this->status = IOrderConstants::RefundRequestedStatus; + + Event::fire(new RequestedSummitOrderRefund($this->getId(), $days_before_event_starts)); + } + /** + * @return string + */ + public function getPaymentMethod(): string + { + return $this->payment_method; + } + + /** + * @param string $payment_method + */ + public function setPaymentMethod(string $payment_method): void + { + $this->payment_method = $payment_method; + } + + /** + * @return string + */ + public function getQRCode(): ?string + { + return $this->qr_code; + } + + /** + * @return string + */ + public function getOwnerFirstName(): ?string + { + if($this->hasOwner()){ + return $this->owner->getFirstName(); + } + return $this->owner_first_name; + } + + /** + * @param string $owner_first_name + */ + public function setOwnerFirstName(string $owner_first_name): void + { + $this->owner_first_name = $owner_first_name; + } + + /** + * @return string + */ + public function getOwnerSurname(): ?string + { + if($this->hasOwner()){ + return $this->owner->getLastName(); + } + return $this->owner_surname; + } + + /** + * @param string $owner_surname + */ + public function setOwnerSurname(string $owner_surname): void + { + $this->owner_surname = $owner_surname; + } + + /** + * @return string + */ + public function getOwnerEmail(): ?string + { + if(!is_null($this->owner)){ + return $this->owner->getEmail(); + } + return $this->owner_email; + } + + /** + * @param string $owner_email + */ + public function setOwnerEmail(string $owner_email): void + { + $this->owner_email = strtolower($owner_email); + } + + /** + * @return string + */ + public function getOwnerCompany(): ?string + { + if($this->hasCompany()) + return $this->company->getName(); + return $this->owner_company; + } + + /** + * @param string $owner_company + */ + public function setOwnerCompany(string $owner_company): void + { + $this->owner_company = $owner_company; + } + + /** + * @return Company + */ + public function getCompany(): Company + { + return $this->company; + } + + /** + * @param Company $company + */ + public function setCompany(Company $company): void + { + $this->company = $company; + } + + /** + * @return Member + */ + public function getOwner(): ?Member + { + return $this->owner; + } + + /** + * @param Member $owner + */ + public function setOwner(Member $owner): void + { + $this->owner = $owner; + } + + /** + * @return string + */ + public function getBillingAddress1(): ?string + { + return $this->billing_address_1; + } + + /** + * @param string $billing_address_1 + */ + public function setBillingAddress1(string $billing_address_1): void + { + $this->billing_address_1 = $billing_address_1; + } + + /** + * @return string + */ + public function getBillingAddress2(): ?string + { + return $this->billing_address_2; + } + + /** + * @param string $billing_address_2 + */ + public function setBillingAddress2(string $billing_address_2): void + { + $this->billing_address_2 = $billing_address_2; + } + + /** + * @return string + */ + public function getBillingAddressZipCode(): ?string + { + return $this->billing_address_zip_code; + } + + /** + * @param string $billing_address_zip_code + */ + public function setBillingAddressZipCode(string $billing_address_zip_code): void + { + $this->billing_address_zip_code = $billing_address_zip_code; + } + + /** + * @return string + */ + public function getBillingAddressCity(): ?string + { + return $this->billing_address_city; + } + + /** + * @param string $billing_address_city + */ + public function setBillingAddressCity(string $billing_address_city): void + { + $this->billing_address_city = $billing_address_city; + } + + /** + * @return string + */ + public function getBillingAddressState(): ?string + { + return $this->billing_address_state; + } + + /** + * @param string $billing_address_state + */ + public function setBillingAddressState(string $billing_address_state): void + { + $this->billing_address_state = $billing_address_state; + } + + /** + * @return string + */ + public function getBillingAddressCountryIsoCode(): ?string + { + return $this->billing_address_country_iso_code; + } + + /** + * @param string $billing_address_country_iso_code + */ + public function setBillingAddressCountryIsoCode(string $billing_address_country_iso_code): void + { + $this->billing_address_country_iso_code = $billing_address_country_iso_code; + } + + /** + * @return \DateTime + */ + public function getApprovedPaymentDate(): \DateTime + { + return $this->approved_payment_date; + } + + /** + * @param \DateTime $approved_payment_date + */ + public function setApprovedPaymentDate(\DateTime $approved_payment_date): void + { + $this->approved_payment_date = $approved_payment_date; + } + + /** + * @return string + */ + public function getLastError(): ?string + { + return $this->last_error; + } + + /** + * @param string $last_error + */ + public function setLastError(string $last_error): void + { + $this->last_error = $last_error; + } + + /** + * @return string + */ + public function getPaymentGatewayClientToken(): ?string + { + return $this->payment_gateway_client_token; + } + + /** + * @param string $payment_gateway_client_token + */ + public function setPaymentGatewayClientToken(string $payment_gateway_client_token): void + { + $this->payment_gateway_client_token = $payment_gateway_client_token; + } + + /** + * @return string + */ + public function getPaymentGatewayCartId(): ?string + { + return $this->payment_gateway_cart_id; + } + + /** + * @param string $payment_gateway_cart_id + */ + public function setPaymentGatewayCartId(string $payment_gateway_cart_id): void + { + $this->payment_gateway_cart_id = $payment_gateway_cart_id; + } + + /** + * @return string + */ + public function getHash(): ?string + { + return $this->hash; + } + + /** + * @return \DateTime + */ + public function getHashCreationDate(): ?\DateTime + { + return $this->hash_creation_date; + } + + /** + * @return ArrayCollection|SummitAttendeeTicket[] + */ + public function getTickets() + { + return $this->tickets; + } + + /** + * @param SummitAttendeeTicket $ticket + */ + public function addTicket(SummitAttendeeTicket $ticket){ + if($this->tickets->contains($ticket)) return; + $this->tickets->add($ticket); + $ticket->setOrder($this); + } + + /** + * @param int $ticket_id + * @return SummitAttendeeTicket|null + */ + public function getTicketById(int $ticket_id):?SummitAttendeeTicket{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($ticket_id))); + $ticket = $this->tickets->matching($criteria)->first(); + return $ticket === false ? null : $ticket; + } + + /** + * @return SummitOrderExtraQuestionAnswer[] + */ + public function getExtraQuestionAnswers() + { + return $this->extra_question_answers; + } + + public function clearExtraQuestionAnswers(){ + $this->extra_question_answers->clear(); + } + + public function addExtraQuestionAnswer(SummitOrderExtraQuestionAnswer $answer){ + if($this->extra_question_answers->contains($answer)) return; + $this->extra_question_answers->add($answer); + $answer->setOrder($this); + } + + public function removeExtraQuestionAnswer(SummitOrderExtraQuestionAnswer $answer){ + if(!$this->extra_question_answers->contains($answer)) return; + $this->extra_question_answers->removeElement($answer); + $answer->clearOrder(); + } + + use QRGeneratorTrait; + + public function generateQRCode(): string + { + $this->qr_code = $this->generateQRFromFields([ + $this->summit->getOrderQRPrefix(), + $this->number + ]); + + return $this->qr_code; + } + + /** + * @return int + */ + public function getOwnerId(){ + try { + return is_null($this->owner) ? 0 : $this->owner->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return bool + */ + public function hasCompany():bool{ + return $this->getCompanyId() > 0; + } + + /** + * @return int + */ + public function getCompanyId(){ + try { + return is_null($this->company) ? 0 : $this->company->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return bool + */ + public function hasOwner():bool{ + return $this->getOwnerId() > 0; + } + + /** + * @return float + */ + public function getRawAmount():float{ + $amount = 0.0; + foreach ($this->tickets as $ticket){ + $amount += $ticket->getRawCost(); + } + return $amount; + } + + /** + * @return float + */ + public function getFinalAmount():float { + $amount = 0.0; + foreach ($this->tickets as $ticket){ + $amount += $ticket->getFinalAmount(); + } + return $amount; + } + + /** + * @return bool + */ + public function isFree():bool { + return $this->getFinalAmount() == 0; + } + + /** + * @return bool + */ + public function hasPaymentInfo():bool{ + return empty($this->payment_gateway_cart_id) || empty($this->payment_gateway_client_token); + } + + /** + * @return float + */ + public function getTaxesAmount(): float{ + $amount = 0.0; + foreach ($this->tickets as $ticket){ + foreach($ticket->getAppliedTaxes() as $appliedTax){ + $amount += $appliedTax->getAmount(); + } + } + return $amount; + } + + /** + * @return float + */ + public function getDiscountAmount(): float{ + $amount = 0.0; + foreach ($this->tickets as $ticket){ + $amount += $ticket->getDiscount(); + } + return $amount; + } + + /** + * @return string + */ + public function getCurrency():string{ + $ticket = $this->tickets->first(); + return $ticket->getCurrency(); + } + + /** + * @return string + */ + public function getOwnerFullName():string { + if($this->hasOwner()){ + return $this->owner->getFullName(); + } + return sprintf("%s %s", $this->owner_first_name, $this->owner_surname); + } + + /** + * @return bool + */ + public function isPaid():bool { + return $this->status == IOrderConstants::PaidStatus; + } + + /** + * @return bool + */ + public function canRefund():bool{ + $validStatuses = [IOrderConstants::RefundRequestedStatus, IOrderConstants::PaidStatus]; + if(!in_array($this->status, $validStatuses)){ + return false; + } + if($this->isFree()){ + return false; + } + return true; + } + + /** + * @param float $amount + * @throws ValidationException + */ + public function refund(float $amount) + { + if (!$this->canRefund()) + throw new ValidationException + ( + sprintf + ( + "can not request a refund on a %s order", + $this->status + ) + ); + + $this->status = IOrderConstants::RefundedStatus; + $this->refunded_amount = $amount; + list($tickets_to_return, $promo_codes_to_return) = $this->calculateTicketsAndPromoCodesToReturn(); + + foreach ($this->tickets as $ticket){ + $ticket->setRefunded(); + } + + Event::fire(new SummitOrderRefundAccepted($this->getId(), $tickets_to_return, $promo_codes_to_return)); + } + + /** + * @return string + * - if tixs in an order are all in a combination of status refund requested or refunded, show order as refund requested. + * - if all tix in an order are in status refund requested, show order as refund requested. + * - if all tix in an order are in status refunded, show order as refunded. + */ + public function recalculateOrderStatus():string { + Log::debug(sprintf("SummitOrder::recalculateOrderStatus current status %s", $this->status)); + $request_refund_count = 0; + $refund_count = 0; + + foreach ($this->tickets as $ticket){ + $ticket_status = $ticket->getStatus(); + Log::debug(sprintf("SummitOrder::recalculateOrderStatus ticket_id %s ticket_status %s", $ticket->getId(), $ticket_status)); + if($ticket_status == IOrderConstants::RefundRequestedStatus) + ++$request_refund_count; + if($ticket_status == IOrderConstants::RefundedStatus) + ++$refund_count; + } + + $tickets_count = $this->tickets->count(); + + Log::debug(sprintf("SummitOrder::recalculateOrderStatus tickets_count %s request_refund_count %s refund_count %s", $tickets_count, $request_refund_count, $refund_count)); + + if(($request_refund_count == $tickets_count || ( $refund_count > 0 && $request_refund_count > 0 && ($refund_count + $request_refund_count) == $tickets_count))) + $this->status = IOrderConstants::RefundRequestedStatus; + + if($refund_count == $tickets_count) + $this->status = IOrderConstants::RefundedStatus; + + Log::debug(sprintf("SummitOrder::recalculateOrderStatus recalculated status %s", $this->status)); + + return $this->status; + } + + /** + * @return bool + */ + public function isRefundRequested():bool { + return $this->status == IOrderConstants::RefundRequestedStatus; + } + + /** + * @return float + */ + public function getRefundedAmount(): float + { + return $this->refunded_amount; + } + + /** + * @return \DateTime + */ + public function getLastReminderEmailSentDate(): ?\DateTime + { + $last_action_date = $this->last_reminder_email_sent_date; + + if (is_null($last_action_date)) { + $last_action_date = $this->getCreatedUTC(); + } + + return $last_action_date; + } + + /** + * @param \DateTime $last_reminder_email_sent_date + */ + public function setLastReminderEmailSentDate(\DateTime $last_reminder_email_sent_date): void + { + $this->last_reminder_email_sent_date = $last_reminder_email_sent_date; + } + + /** + * @return bool + */ + public function isSingleOrder():bool{ + if($this->tickets->count() > 1){ + return false; + } + + $ticket = $this->tickets->first(); + + if(!$ticket instanceof SummitAttendeeTicket) return false; + + if($ticket->getOwnerEmail() != $this->getOwnerEmail()) return false; + + return true; + } + + /** + * @return SummitAttendeeTicket|null + */ + public function getFirstTicket():?SummitAttendeeTicket{ + if(is_null($this->tickets)) return null; + if($this->tickets->count() == 0) return null; + return $this->tickets->first(); + } + + /* + * @return string + */ + public function getExternalId(): ?string + { + return $this->external_id; + } + + /** + * @param string $external_id + */ + public function setExternalId(string $external_id): void + { + $this->external_id = $external_id; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SummitOrderExtraQuestionAnswer.php b/app/Models/Foundation/Summit/Registration/SummitOrderExtraQuestionAnswer.php new file mode 100644 index 00000000..95ead35b --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SummitOrderExtraQuestionAnswer.php @@ -0,0 +1,144 @@ + 'order', + 'getAttendeeId' => 'attendee', + 'getQuestionId' => 'question', + ]; + + protected $hasPropertyMappings = [ + 'hasOrder' => 'order', + 'hasAttendee' => 'attendee', + 'hasQuestion' => 'question', + ]; + /** + * @ORM\ManyToOne(targetEntity="models\summit\SummitOrder", inversedBy="extra_question_answers") + * @ORM\JoinColumn(name="OrderID", referencedColumnName="ID") + * @var SummitOrder + */ + private $order; + + /** + * @ORM\ManyToOne(targetEntity="models\summit\SummitAttendee", inversedBy="extra_question_answers") + * @ORM\JoinColumn(name="SummitAttendeeID", referencedColumnName="ID") + * @var SummitAttendee + */ + private $attendee; + + /** + * @ORM\ManyToOne(targetEntity="models\summit\SummitOrderExtraQuestionType") + * @ORM\JoinColumn(name="QuestionID", referencedColumnName="ID") + * @var SummitOrderExtraQuestionType + */ + private $question; + + /** + * @ORM\Column(name="Value", type="string") + * @var string + */ + private $value; + + /** + * @return SummitOrder + */ + public function getOrder(): ?SummitOrder + { + return $this->order; + } + + /** + * @param SummitOrder $order + */ + public function setOrder(SummitOrder $order): void + { + $this->order = $order; + } + + /** + * @return SummitAttendee + */ + public function getAttendee(): ?SummitAttendee + { + return $this->attendee; + } + + /** + * @param SummitAttendee $attendee + */ + public function setAttendee(SummitAttendee $attendee): void + { + $this->attendee = $attendee; + } + + /** + * @return SummitOrderExtraQuestionType + */ + public function getQuestion(): ?SummitOrderExtraQuestionType + { + return $this->question; + } + + /** + * @param SummitOrderExtraQuestionType $question + */ + public function setQuestion(SummitOrderExtraQuestionType $question): void + { + $this->question = $question; + } + + /** + * @return string + */ + public function getValue(): string + { + return $this->value; + } + + /** + * @return bool + */ + public function hasValue():bool { + return !empty($this->value); + } + + /** + * @param string $value + */ + public function setValue(string $value): void + { + $this->value = $value; + } + + public function clearOrder(){ + $this->order = null; + } + + public function clearAttendee(){ + $this->attendee = null; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SummitRefundPolicyType.php b/app/Models/Foundation/Summit/Registration/SummitRefundPolicyType.php new file mode 100644 index 00000000..d1b79267 --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SummitRefundPolicyType.php @@ -0,0 +1,105 @@ +name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return int + */ + public function getUntilXDaysBeforeEventStarts(): int + { + return $this->until_x_days_before_event_starts; + } + + /** + * @param int $until_x_days_before_event_starts + */ + public function setUntilXDaysBeforeEventStarts(int $until_x_days_before_event_starts): void + { + $this->until_x_days_before_event_starts = $until_x_days_before_event_starts; + } + + /** + * @return float + */ + public function getRefundRate(): float + { + return $this->refund_rate; + } + + /** + * @param float $refund_rate + */ + public function setRefundRate(float $refund_rate): void + { + $this->refund_rate = $refund_rate; + } + + public function __construct() + { + parent::__construct(); + $this->refund_rate = 0.0; + } + + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SummitRegistrationInvitation.php b/app/Models/Foundation/Summit/Registration/SummitRegistrationInvitation.php new file mode 100644 index 00000000..18f49f2c --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SummitRegistrationInvitation.php @@ -0,0 +1,292 @@ +first_name; + } + + /** + * @param string $first_name + */ + public function setFirstName(string $first_name): void + { + $this->first_name = $first_name; + } + + /** + * @return string + */ + public function getLastName(): ?string + { + return $this->last_name; + } + + /** + * @param string $last_name + */ + public function setLastName(string $last_name): void + { + $this->last_name = $last_name; + } + + /** + * @return string + */ + public function getEmail(): string + { + return $this->email; + } + + /** + * @param string $email + */ + public function setEmail(string $email): void + { + $this->email = $email; + } + + /** + * @return string + */ + public function getHash(): ?string + { + return $this->hash; + } + + /** + * @param string $hash + */ + public function setHash(string $hash): void + { + $this->hash = $hash; + } + + /** + * @return \DateTime + */ + public function getAcceptedDate(): ?\DateTime + { + return $this->accepted_date; + } + + public function isAccepted(): bool + { + return !is_null($this->accepted_date); + } + + public function isSent(): bool + { + return !empty($this->hash); + } + + /** + * @return Member + */ + public function getMember(): ?Member + { + return $this->member; + } + + /** + * @param Member $member + */ + public function setMember(Member $member): void + { + $this->member = $member; + } + + /** + * @return int + */ + public function getMemberId() + { + try { + return is_null($this->member) ? 0 : $this->member->getId(); + } catch (\Exception $ex) { + return 0; + } + } + + /** + * @return bool + */ + public function hasMember(): bool + { + return $this->getMemberId() > 0; + } + + public function clearMember() + { + $this->member = null; + } + + /** + * transient variable + * @var string + */ + private $token; + + public function getToken(): ?string + { + return $this->token; + } + + /** + * @return string + */ + public function generateConfirmationToken(): string + { + $generator = new RandomGenerator(); + $this->accepted_date = null; + $this->token = $generator->randomToken(); + $this->hash = self::HashConfirmationToken($this->token); + return $this->token; + } + + public static function HashConfirmationToken(string $token): string + { + return md5($token); + } + + /** + * @return string + */ + public function getSetPasswordLink(): ?string + { + return $this->set_password_link; + } + + /** + * @param string $set_password_link + */ + public function setSetPasswordLink(string $set_password_link): void + { + $this->set_password_link = $set_password_link; + } + + /** + * @return SummitOrder + */ + public function getOrder(): ?SummitOrder + { + return $this->order; + } + + /** + * @param SummitOrder $order + */ + public function setOrder(SummitOrder $order): void + { + $this->order = $order; + } + + public function markAsAccepted(): void + { + $this->accepted_date = new \DateTime('now', new \DateTimeZone('UTC')); + } + + /** + * @return int + */ + public function getOrderId() + { + try { + return is_null($this->order) ? 0 : $this->order->getId(); + } catch (\Exception $ex) { + return 0; + } + } + + public function clearOrder() + { + $this->order = null; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SummitTaxType.php b/app/Models/Foundation/Summit/Registration/SummitTaxType.php new file mode 100644 index 00000000..b89c245a --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SummitTaxType.php @@ -0,0 +1,150 @@ +name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return string|null + */ + public function getTaxId(): ?string + { + return $this->tax_id; + } + + /** + * @param string $tax_id + */ + public function setTaxId(string $tax_id): void + { + $this->tax_id = $tax_id; + } + + /** + * @return float + */ + public function getRate(): float + { + return $this->rate; + } + + /** + * @param float $rate + */ + public function setRate(float $rate): void + { + $this->rate = $rate; + } + + public function __construct() + { + parent::__construct(); + $this->ticket_types = new ArrayCollection(); + $this->tax_id = ""; + $this->rate = 0.0; + } + + /** + * @param SummitTicketType $ticketType + */ + public function addTicketType(SummitTicketType $ticketType){ + if($this->ticket_types->contains($ticketType)) return; + $this->ticket_types->add($ticketType); + } + + /** + * @param SummitTicketType $ticketType + */ + public function removeTicketType(SummitTicketType $ticketType){ + if(!$this->ticket_types->contains($ticketType)) return; + $this->ticket_types->removeElement($ticketType); + } + + /** + * @return SummitTicketType[] + */ + public function getTicketTypes() + { + return $this->ticket_types; + } + + /** + * @param SummitTicketType $ticket_type + * @return bool + */ + public function mustApplyTo(SummitTicketType $ticket_type):bool{ + if($this->ticket_types->count() == 0) return true; + return $this->ticket_types->contains($ticket_type); + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Registration/SummitTicketType.php b/app/Models/Foundation/Summit/Registration/SummitTicketType.php new file mode 100644 index 00000000..6e6c0b5e --- /dev/null +++ b/app/Models/Foundation/Summit/Registration/SummitTicketType.php @@ -0,0 +1,495 @@ +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 string + */ + public function getExternalId():?string + { + return $this->external_id; + } + + /** + * @param string $external_id + */ + public function setExternalId($external_id) + { + $this->external_id = $external_id; + } + + public function __construct() + { + parent::__construct(); + $this->cost = 0.0; + $this->max_quantity_per_order = 0; + $this->quantity_2_sell = 0; + $this->quantity_sold = 0; + $this->currency = AllowedCurrencies::USD; + $this->applied_taxes = new ArrayCollection(); + $this->sales_start_date = null; + $this->sales_end_date = null; + } + + /** + * @ORM\PreRemove: + * @param LifecycleEventArgs $args + * @throws ValidationException + */ + public function preRemoveHandler(LifecycleEventArgs $args){ + if(Config::get('registration.validate_ticket_type_removal', true) && $this->quantity_sold > 0) + throw new ValidationException + ( + sprintf + ( + "Can not delete ticket type %s because has sold tickets.", $this->getId() + ) + ); + } + + /** + * @return ArrayCollection|SummitTaxType[] + */ + public function getAppliedTaxes() + { + return $this->applied_taxes; + } + + /** + * @param SummitTicketType $tax + */ + public function addAppliedTax(SummitTicketType $tax){ + if($this->applied_taxes->contains($tax)) return; + $this->applied_taxes->add($tax); + } + + /** + * @param SummitTicketType $tax + */ + public function removeAppliedTax(SummitTicketType $tax){ + if(!$this->applied_taxes->contains($tax)) return; + $this->applied_taxes->removeElement($tax); + } + + /** + * @return float + */ + public function getCost(): float + { + return $this->cost; + } + + /** + * @param float $cost + */ + public function setCost(float $cost): void + { + $this->cost = $cost; + } + + /** + * @return string|null + */ + public function getCurrency(): ?string + { + return $this->currency; + } + + /** + * @param string $currency + */ + public function setCurrency(string $currency): void + { + $this->currency = $currency; + } + + /** + * @return int + */ + public function getQuantity2Sell(): int + { + return $this->quantity_2_sell; + } + + /** + * @param int $quantity_2_sell + */ + public function setQuantity2Sell(int $quantity_2_sell): void + { + $this->quantity_2_sell = $quantity_2_sell; + } + + /** + * @return int + */ + public function getMaxQuantityPerOrder(): int + { + return $this->max_quantity_per_order; + } + + /** + * @param int $max_quantity_per_order + */ + public function setMaxQuantityPerOrder(int $max_quantity_per_order): void + { + $this->max_quantity_per_order = $max_quantity_per_order; + } + + /** + * @return \DateTime|null + */ + public function getSalesStartDate(): ?\DateTime + { + return $this->sales_start_date; + } + + /** + * @param \DateTime|null $sales_start_date + */ + public function setSalesStartDate(?\DateTime $sales_start_date): void + { + $this->sales_start_date = $sales_start_date; + } + + public function clearSalesStartDate():void{ + $this->sales_start_date = null; + } + + /** + * @return \DateTime|null + */ + public function getSalesEndDate(): ?\DateTime + { + return $this->sales_end_date; + } + + /** + * @param \DateTime|null $sales_end_date + */ + public function setSalesEndDate(?\DateTime $sales_end_date): void + { + $this->sales_end_date = $sales_end_date; + } + + public function clearSalesEndDate():void{ + $this->sales_end_date = null; + } + + /** + * @return \DateTime + */ + public function getLocalSalesStartDate(): \DateTime + { + return $this->getSummit()->convertDateFromUTC2TimeZone($this->sales_start_date); + } + + /** + * @return \DateTime + */ + public function getLocalSalesEndDate(): \DateTime + { + return $this->getSummit()->convertDateFromUTC2TimeZone($this->sales_end_date); + } + + /** + * @return int + */ + public function getQuantitySold(): int + { + return $this->quantity_sold; + } + + /** + * @return bool + */ + public function canSell():bool { + if($this->isSoldOut()) { + Log::warning(sprintf("SummitTicketType::canSell ticket %s is sold out", $this->id)); + return false; + } + return $this->isLive(); + } + + /** + * @return bool + */ + public function isSoldOut():bool{ + return $this->quantity_2_sell == $this->quantity_sold; + } + + /** + * @return bool + */ + public function isLive(){ + // if valid period is not set , that is valid_since_date == valid_until_date == null , then ticket code lives forever + $now_utc = new \DateTime('now', new \DateTimeZone('UTC')); + if(!is_null($this->sales_start_date) && $now_utc < $this->sales_start_date){ + Log::warning(sprintf("SummitTicketType::isLive ticket %s is not live (now_utc < sales_start_date)", $this->id)); + return false; + } + if(!is_null($this->sales_end_date) && $now_utc > $this->sales_end_date){ + Log::warning(sprintf("SummitTicketType::isLive ticket %s is not live (now_utc < sales_end_date)", $this->id)); + return false; + } + return true; + } + + /** + * @param int $qty + * @return int + * @throws ValidationException + */ + public function sell(int $qty = 1):int { + + Log::debug + ( + sprintf + ( + "SummitTicketType::sell id %s qty %s quantity_sold %s quantity_2_sell %s", + $this->id, + $qty, + $this->quantity_sold, + $this->quantity_2_sell + ) + ); + + if($qty > $this->quantity_2_sell){ + throw new ValidationException(sprintf("Can not sell more tickets than max available.")); + } + + if(($this->quantity_sold + $qty) > $this->quantity_2_sell){ + throw new ValidationException(sprintf("Can not sell more ticket than available ones.")); + } + + $this->quantity_sold = $this->quantity_sold + $qty; + + return $this->quantity_sold; + } + + /** + * @param int $qty + * @return int + * @throws ValidationException + */ + public function restore(int $qty):int{ + + Log::debug + ( + sprintf + ( + "SummitTicketType::restore qty %s ticket type %s quantity_sold %s", + $qty, + $this->id, + $this->quantity_sold + ) + ); + + if(($this->quantity_sold - $qty) < 0) + throw new ValidationException + ( + sprintf + ( + "Can not restore a greater qty than sold one quantity_sold %s qty %s id %s", + $this->quantity_sold, + $qty, + $this->id + ) + ); + + $this->quantity_sold = $this->quantity_sold - $qty; + + Log::info(sprintf("SummitTicketType::restore qty_2_restore %s final qty %s", $qty, $this->quantity_sold)); + + return $this->quantity_sold; + } + + /** + * @return int + */ + public function getBadgeTypeId(){ + try { + return is_null($this->badge_type) ? 0: $this->badge_type->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return SummitBadgeType + */ + public function getBadgeType(): ?SummitBadgeType + { + return $this->badge_type; + } + + /** + * @return bool + */ + public function hasBadgeType(){ + return $this->getBadgeTypeId() > 0; + } + + public function clearBadgeType(){ + $this->badge_type = null; + } + + /** + * @param SummitBadgeType $badge_type + */ + public function setBadgeType(SummitBadgeType $badge_type): void + { + $this->badge_type = $badge_type; + } + + /** + * @param SummitAttendeeTicket $ticket + * @return SummitAttendeeTicket + */ + public function applyTo(SummitAttendeeTicket $ticket){ + if($this->hasBadgeType()){ + $badge = $ticket->hasBadge() ? $ticket->getBadge() : new SummitAttendeeBadge(); + $ticket->setBadge($badge->applyTicketType($this)); + } + return $ticket; + } +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Repositories/IPaymentGatewayProfileRepository.php b/app/Models/Foundation/Summit/Repositories/IPaymentGatewayProfileRepository.php new file mode 100644 index 00000000..044a2afe --- /dev/null +++ b/app/Models/Foundation/Summit/Repositories/IPaymentGatewayProfileRepository.php @@ -0,0 +1,22 @@ +photo; } @@ -1098,6 +1116,7 @@ class PresentationSpeaker extends SilverstripeBaseModel * @return $this */ public function addSummitAssistance(PresentationSpeakerSummitAssistanceConfirmationRequest $assistance){ + if($this->summit_assistances->contains($assistance)) return $this; $this->summit_assistances->add($assistance); $assistance->setSpeaker($this); return $this; @@ -1220,16 +1239,25 @@ SQL; return $summits; } - - /** - * @return null|string - */ + /* + * @return null|string + */ public function getEmail(){ - if($this->hasMember()){ - return $this->member->getEmail(); + try { + if (!is_null($this->member)) { + return $this->member->getEmail(); + } } - if($this->hasRegistrationRequest()){ - return $this->registration_request->getEmail(); + catch(\Exception $ex){ + Log::warning($ex); + } + try { + if (!is_null($this->registration_request)) { + return $this->registration_request->getEmail(); + } + } + catch(\Exception $ex){ + Log::warning($ex); } return null; } @@ -1256,10 +1284,10 @@ SQL; } /** - * @return PresentationSpeakerSummitAssistanceConfirmationRequest + * @return PresentationSpeakerSummitAssistanceConfirmationRequest|null */ public function getLatestAssistance(){ - return $this->summit_assistances->last(); + return !is_null($this->summit_assistances) ? $this->summit_assistances->last() : null; } // life cycle events @@ -1312,10 +1340,12 @@ SQL; $this->pre_update_args = null; } + public static $bypass_events = false; /** * @ORM\PostPersist */ public function inserted($args){ + if(self::$bypass_events) return; Event::fire(new PresentationSpeakerCreated($this, $args)); } @@ -1621,9 +1651,9 @@ SQL; } /** - * @return string + * @return string|null */ - public function getProfilePhotoUrl():string{ + public function getProfilePhotoUrl():?string{ $photoUrl = null; if($this->hasPhoto() && $photo = $this->getPhoto()){ $photoUrl = $photo->getUrl(); @@ -1646,6 +1676,7 @@ SQL; * @return bool */ public function canBeEditedBy(Member $member):bool{ + Log::debug(sprintf("PresentationSpeaker::canBeEditedBy member %s speaker member id %s", $member->getId(), $this->getMemberId())); if($member->isAdmin()) return true; if($this->getMemberId() == $member->getId()) return true; $criteria = Criteria::create(); @@ -1654,4 +1685,95 @@ SQL; ->andWhere(Criteria::expr()->eq('approved', true)); return $this->granted_edit_permissions->matching($criteria)->count() > 0 ; } + + /** + * @return bool + */ + public function hasBigPhoto(){ + return $this->getBigPhotoId() > 0; + } + + /** + * @return int + */ + public function getBigPhotoId() + { + try{ + if(is_null($this->big_photo)) return 0; + return $this->big_photo->getId(); + } + catch(\Exception $ex){ + Log::warning($ex); + return 0; + } + } + + public function getBigPhoto():?File{ + return $this->big_photo; + } + + /** + * @return string|null + */ + public function getBigProfilePhotoUrl():?string{ + $photoUrl = null; + if($this->hasBigPhoto() && $photo = $this->getBigPhoto()){ + $photoUrl = $photo->getUrl(); + } + if(empty($photoUrl)){ + $photoUrl = File::getCloudLinkForImages("generic-speaker-icon.png"); + } + return $photoUrl; + } + + /** + * @param File $big_photo + */ + public function setBigPhoto(File $big_photo): void + { + $this->big_photo = $big_photo; + } + + public function clearBigPhoto():void{ + $this->big_photo = null; + } + + public function clearPhoto():void{ + $this->photo = null; + } + + /** + * @return mixed + */ + public function getCompany() + { + return $this->company; + } + + /** + * @param mixed $company + */ + public function setCompany($company): void + { + $this->company = $company; + } + + /** + * @return mixed + */ + public function getPhoneNumber() + { + return $this->phone_number; + } + + /** + * @param mixed $phoner_number + */ + public function setPhoneNumber($phone_number): void + { + $this->phone_number = $phone_number; + } + + + } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Speakers/PresentationSpeakerSummitAssistanceConfirmationRequest.php b/app/Models/Foundation/Summit/Speakers/PresentationSpeakerSummitAssistanceConfirmationRequest.php index f75eb318..2b14edd4 100644 --- a/app/Models/Foundation/Summit/Speakers/PresentationSpeakerSummitAssistanceConfirmationRequest.php +++ b/app/Models/Foundation/Summit/Speakers/PresentationSpeakerSummitAssistanceConfirmationRequest.php @@ -206,6 +206,14 @@ class PresentationSpeakerSummitAssistanceConfirmationRequest extends Silverstrip return md5($token); } + public function getConfirmationHash():?string{ + return $this->confirmation_hash; + } + + public function getToken():?string{ + return $this->token; + } + public function __construct() { $this->registered = false; diff --git a/app/Models/Foundation/Summit/Speakers/SpeakerRegistrationRequest.php b/app/Models/Foundation/Summit/Speakers/SpeakerRegistrationRequest.php index 955fd488..c09ad9c3 100644 --- a/app/Models/Foundation/Summit/Speakers/SpeakerRegistrationRequest.php +++ b/app/Models/Foundation/Summit/Speakers/SpeakerRegistrationRequest.php @@ -179,4 +179,9 @@ class SpeakerRegistrationRequest extends SilverstripeBaseModel { return $this->token; } + + public function confirm():void{ + $this->confirmation_date = new \DateTime('now', new \DateTimeZone('UTC')); + $this->is_confirmed = true; + } } \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Sponsor.php b/app/Models/Foundation/Summit/Sponsor.php new file mode 100644 index 00000000..45aff487 --- /dev/null +++ b/app/Models/Foundation/Summit/Sponsor.php @@ -0,0 +1,199 @@ +members = new ArrayCollection(); + $this->badge_scans = new ArrayCollection(); + } + + /** + * @return int + */ + public function getOrder(): ?int + { + return $this->order; + } + + /** + * @param int $order + */ + public function setOrder($order): void + { + $this->order = $order; + } + + /** + * @return Company + */ + public function getCompany(): ?Company + { + return $this->company; + } + + /** + * @param Company $company + */ + public function setCompany(Company $company): void + { + $this->company = $company; + } + + /** + * @return SponsorshipType + */ + public function getSponsorship():?SponsorshipType + { + return $this->sponsorship; + } + + /** + * @param SponsorshipType $sponsorship + */ + public function setSponsorship(SponsorshipType $sponsorship): void + { + $this->sponsorship = $sponsorship; + } + + /** + * @return Member[] + */ + public function getMembers() + { + return $this->members; + } + + public function hasSponsorship():bool{ + return $this->getSponsorshipId() > 0; + } + + /** + * @return int + */ + public function getSponsorshipId(){ + try { + return is_null($this->sponsorship) ? 0 : $this->sponsorship->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return int + */ + public function getCompanyId(){ + try { + return is_null($this->company) ? 0 : $this->company->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @param SponsorBadgeScan $scan + */ + public function addBadgeScan(SponsorBadgeScan $scan){ + if($this->badge_scans->contains($scan)) return; + $this->badge_scans->add($scan); + $scan->setSponsor($this); + } + + public function getScans(){ + return $this->badge_scans; + } + + public function hasCompany():bool{ + return $this->getCompanyId() > 0; + } + + /** + * @param Member $user + */ + public function addUser(Member $user){ + if($this->members->contains($user)) return; + $this->members->add($user); + } + + /** + * @param Member $user + */ + public function removeUser(Member $user){ + if(!$this->members->contains($user)) return; + $this->members->removeElement($user); + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/SponsorshipType.php b/app/Models/Foundation/Summit/SponsorshipType.php new file mode 100644 index 00000000..a6ce1624 --- /dev/null +++ b/app/Models/Foundation/Summit/SponsorshipType.php @@ -0,0 +1,123 @@ +name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return string + */ + public function getLabel(): string + { + return $this->label; + } + + /** + * @param string $label + */ + public function setLabel(string $label): void + { + $this->label = $label; + } + + /** + * @return int + */ + public function getOrder(): int + { + return $this->order; + } + + /** + * @param int $order + */ + public function setOrder($order): void + { + $this->order = $order; + } + + /** + * @return string + */ + public function getSize(): string + { + return $this->size; + } + + /** + * @param string $size + * @throws ValidationException + */ + public function setSize(string $size): void + { + if(!in_array($size, ISponsorshipTypeConstants::AllowedSizes)) + throw new ValidationException("invalid size"); + $this->size = $size; + } + + public function __construct() + { + parent::__construct(); + $this->order = 1; + } + +} \ No newline at end of file diff --git a/app/Models/Foundation/Summit/Summit.php b/app/Models/Foundation/Summit/Summit.php index 3595e2ce..ba955f85 100644 --- a/app/Models/Foundation/Summit/Summit.php +++ b/app/Models/Foundation/Summit/Summit.php @@ -1,5 +1,4 @@ external_summit_id; } @@ -535,14 +713,22 @@ class Summit extends SilverstripeBaseModel $this->schedule_default_start_date = $this->convertDateFromTimeZone2UTC($schedule_default_start_date); } + /** + * @param \DateTime $schedule_default_start_date + */ + public function setRawScheduleDefaultStartDate($schedule_default_start_date) + { + $this->schedule_default_start_date = $schedule_default_start_date; + } + public function clearScheduleDefaultStartDate(){ $this->schedule_default_start_date = null; } /** - * @return mixed + * @return DateTime|null */ - public function getBeginDate() + public function getBeginDate():?DateTime { return $this->begin_date; } @@ -555,6 +741,10 @@ class Summit extends SilverstripeBaseModel $this->begin_date = $this->convertDateFromTimeZone2UTC($begin_date); } + public function setRawBeginDate($begin_date){ + $this->begin_date = $begin_date; + } + /** * @return $this */ @@ -564,9 +754,9 @@ class Summit extends SilverstripeBaseModel } /** - * @return \DateTime + * @return \DateTime|null */ - public function getEndDate() + public function getEndDate():?\DateTime { return $this->end_date; } @@ -579,6 +769,10 @@ class Summit extends SilverstripeBaseModel $this->end_date = $this->convertDateFromTimeZone2UTC($end_date); } + public function setRawEndDate($end_date){ + $this->end_date = $end_date; + } + /** * @return bool */ @@ -611,10 +805,22 @@ class Summit extends SilverstripeBaseModel $this->start_showing_venues_date = $this->convertDateFromTimeZone2UTC($start_showing_venues_date); } + /** + * @param \DateTime $start_showing_venues_date + */ + public function setRawStartShowingVenuesDate($start_showing_venues_date) + { + $this->start_showing_venues_date = $start_showing_venues_date; + } + public function clearStartShowingVenuesDate(){ $this->start_showing_venues_date = null; } + public function clearReassignTicketTillDate(){ + $this->reassign_ticket_till_date = null; + } + /** * @return boolean */ @@ -701,7 +907,6 @@ class Summit extends SilverstripeBaseModel $this->max_submission_allowed_per_user = self::DefaultMaxSubmissionAllowedPerUser; $this->meeting_room_booking_slot_length = 60; $this->meeting_room_booking_max_allowed = 2; - $this->locations = new ArrayCollection; $this->events = new ArrayCollection; $this->event_types = new ArrayCollection; @@ -722,23 +927,30 @@ class Summit extends SilverstripeBaseModel $this->notifications = new ArrayCollection; $this->selection_plans = new ArrayCollection; $this->meeting_booking_room_allowed_attributes = new ArrayCollection(); - $this->mark_as_deleted = false; + $this->badge_access_level_types = new ArrayCollection(); + $this->tax_types = new ArrayCollection(); + $this->badge_features_types = new ArrayCollection(); + $this->badge_types = new ArrayCollection(); + $this->summit_sponsors = new ArrayCollection(); + $this->refund_policies = new ArrayCollection(); + $this->order_extra_questions = new ArrayCollection(); + $this->payment_profiles = new ArrayCollection(); + $this->orders = new ArrayCollection(); + $this->registration_disclaimer_mandatory = false; + $this->reassign_ticket_till_date = null; + $this->begin_date = null; + $this->end_date = null; + $this->registration_begin_date = null; + $this->registration_end_date = null; $this->schedule_shareable_links = new ArrayCollection(); + $this->mark_as_deleted = false; $this->schedule_og_image_width = 0; $this->schedule_og_image_height = 0; - } - - /** - * @var bool - */ - private $mark_as_deleted; - - public function markAsDeleted(){ - $this->mark_as_deleted = true; - } - - public function isDeleting():bool{ - return is_null($this->mark_as_deleted)? false : $this->mark_as_deleted; + $this->email_flows_events = new ArrayCollection(); + $this->summit_documents = new ArrayCollection(); + $this->registration_invitations = new ArrayCollection(); + $this->permission_groups = new ArrayCollection(); + $this->media_upload_types = new ArrayCollection(); } /** @@ -754,13 +966,33 @@ class Summit extends SilverstripeBaseModel } /** - * @return DateTime + * @return DateTime|null */ - public function getLocalBeginDate() + public function getLocalBeginDate():?DateTime { return $this->convertDateFromUTC2TimeZone($this->begin_date); } + + /** + * @return DateTime|null + */ + public function getLocalBeginAllowBookingDate():?DateTime + { + if(is_null($this->begin_allow_booking_date)) return null; + return $this->convertDateFromUTC2TimeZone($this->begin_allow_booking_date); + } + + /** + * @return DateTime|null + */ + public function getLocalEndAllowBookingDate():?DateTime + { + if(is_null($this->end_allow_booking_date)) return null; + return $this->convertDateFromUTC2TimeZone($this->end_allow_booking_date); + } + + /** * @return DateTime */ @@ -775,9 +1007,10 @@ class Summit extends SilverstripeBaseModel */ public function addLocation(SummitAbstractLocation $location) { + if($this->locations->contains($location)) return; + $location->setOrder($this->getLocationMaxOrder() + 1); $this->locations->add($location); $location->setSummit($this); - $location->setOrder($this->getLocationMaxOrder() + 1); return $this; } @@ -971,7 +1204,7 @@ class Summit extends SilverstripeBaseModel } /** - * @return SummitEventType[] + * @return ArrayCollection */ public function getEventTypes() { @@ -1026,7 +1259,7 @@ class Summit extends SilverstripeBaseModel } /** - * @return SummitTicketType[] + * @return ArrayCollection */ public function getTicketTypes() { @@ -1091,6 +1324,13 @@ class Summit extends SilverstripeBaseModel return $query->setParameter('summit_id', $this->getIdentifier())->getResult(); } + public function getPublishedEvents() + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('published', 1)); + return $this->events->matching($criteria); + } + /** * @param PresentationSpeaker $speaker * @param SelectionPlan|null $selectionPlan @@ -1267,9 +1507,9 @@ class Summit extends SilverstripeBaseModel /** * @param int $member_id - * @return SummitAttendee + * @return SummitAttendee|null */ - public function getAttendeeByMemberId($member_id) + public function getAttendeeByMemberId($member_id):?SummitAttendee { $builder = $this->createQueryBuilder(); $members = $builder @@ -1288,16 +1528,25 @@ class Summit extends SilverstripeBaseModel * @param Member $member * @return SummitAttendee|null */ - public function getAttendeeByMember(Member $member) + public function getAttendeeByMember(Member $member):?SummitAttendee { return $this->getAttendeeByMemberId($member->getId()); } /** - * @param int $attendee_id - * @return SummitAttendee + * @param SummitAttendee $attendee */ - public function getAttendeeById($attendee_id) + public function addAttendee(SummitAttendee $attendee){ + if($this->attendees->contains($attendee)) return; + $this->attendees->add($attendee); + $attendee->setSummit($this); + } + + /** + * @param int $attendee_id + * @return SummitAttendee|null + */ + public function getAttendeeById($attendee_id):?SummitAttendee { $criteria = Criteria::create(); $criteria->where(Criteria::expr()->eq('id', intval($attendee_id))); @@ -1305,6 +1554,19 @@ class Summit extends SilverstripeBaseModel return $attendee === false ? null : $attendee; } + /** + * @param string $email + * @return SummitAttendee|null + */ + public function getAttendeeByEmail(string $email):?SummitAttendee + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('email', strtolower(trim($email)))); + $attendee = $this->attendees->matching($criteria)->first(); + return $attendee === false ? null : $attendee; + } + + /** * @ORM\OneToMany(targetEntity="models\summit\SummitEntityEvent", mappedBy="summit", cascade={"persist"}, orphanRemoval=true) * @var SummitEntityEvent[] @@ -1340,6 +1602,20 @@ class Summit extends SilverstripeBaseModel $end_date <= $summit_end_date && $end_date >= $start_date; } + /** + * @param DateTime $start_date + * @param DateTime $end_date + * @return bool + */ + public function isTimeFrameOnBookingPeriod(DateTime $start_date, DateTime $end_date):bool + { + if(is_null($this->begin_allow_booking_date)) return false; + if(is_null($this->end_allow_booking_date)) return false; + + return $start_date >= $this->convertDateFromUTC2TimeZone($this->begin_allow_booking_date) && $start_date <= $this->convertDateFromUTC2TimeZone($this->end_allow_booking_date) && + $end_date <= $this->convertDateFromUTC2TimeZone($this->end_allow_booking_date) && $end_date >= $start_date; + } + /** * @param bool $filter_published_events * @return \Doctrine\ORM\QueryBuilder @@ -1498,7 +1774,7 @@ class Summit extends SilverstripeBaseModel /** * @return Company[] */ - public function getSponsors() + public function getEventSponsors() { $builder = $this->createQueryBuilder(); return $builder @@ -1627,14 +1903,53 @@ SQL; } /** + * @param string $suffix * @return string */ - public function getSlug() + public function getSlug($suffix='-summit') { - $res = "openstack-" . $this->name . '-'; - $res .= $this->begin_date->format('Y') . '-summit'; - $res = strtolower(preg_replace('/[^a-zA-Z0-9\-]/', '', $res)); - return $res; + $res = $this->name; + + if(!is_null($this->begin_date)) { + $res .= $this->begin_date->format('Y') . $suffix; + } + + return strtolower(preg_replace('/[^a-zA-Z0-9\-]/', '', $res)); + } + + + public function generateRegistrationSlugPrefix():void{ + if(is_null($this->registration_slug_prefix)){ + $this->registration_slug_prefix = $this->getSlug(""); + } + } + /** + * @return string + */ + public function getRegistrationSlugPrefix():string{ + $this->generateRegistrationSlugPrefix(); + return $this->registration_slug_prefix; + } + + /** + * @return string + */ + public function getOrderQRPrefix():string{ + return strtoupper('ORDER_'.$this->getRegistrationSlugPrefix()); + } + + /** + * @return string + */ + public function getTicketQRPrefix():string{ + return strtoupper('TICKET_'.$this->getRegistrationSlugPrefix()); + } + + /** + * @return string + */ + public function getBadgeQRPrefix():string{ + return strtoupper('BADGE_'.$this->getRegistrationSlugPrefix()); } /** @@ -1691,6 +2006,38 @@ SQL; return $this->attendees->count(); } + + /** + * @return int + */ + public function getPaidTicketsCount():int{ + return $this->geTicketsCountByStatus(IOrderConstants::PaidStatus); + } + /** + * @param string $status + * @return int + */ + public function geTicketsCountByStatus(string $status):int + { + try { + $sql = <<prepareRawSQL($sql); + $stmt->execute([ + 'summit_id' => $this->id, + 'status' => $status + ]); + $res = $stmt->fetchAll(\PDO::FETCH_COLUMN); + return count($res) > 0 ? $res[0] : 0; + } catch (\Exception $ex) { + + } + return 0; + } + /** * @return int */ @@ -1924,7 +2271,36 @@ SQL; return $this; } + /** + * @return int + */ + public function getTicketTypesCount():int{ + return $this->ticket_types->count(); + } + /** + * @return bool + */ + public function hasTicketTypes():bool { + return $this->getTicketTypesCount() > 0; + } + + + /** + * @return null|string + * @throws ValidationException + */ + public function getDefaultTicketTypeCurrency():?string{ + $default_currency = null; + foreach ($this->ticket_types as $ticket_type){ + $ticket_type_currency = $ticket_type->getCurrency(); + if(empty($ticket_type_currency)) continue; + if(empty($default_currency)) { $default_currency = $ticket_type_currency; continue;} + if($ticket_type_currency != $default_currency) + throw new ValidationException(sprintf("all ticket types for summit %s should have same currency", $this->getId())); + } + return $default_currency; + } /** * @param SummitTicketType $ticket_type * @return $this @@ -2239,11 +2615,34 @@ SQL; /** * @return DateTime */ - public function getRegistrationBeginDate() + public function getRegistrationBeginDate():?DateTime { return $this->registration_begin_date; } + /** + * @return bool + * @throws \Exception + */ + public function isRegistrationPeriodOpen():bool { + return $this->isDateOnRegistrationPeriod(new \DateTime('now', new \DateTimeZone('UTC'))); + } + + /** + * @param DateTime $date + * @return bool + */ + public function isDateOnRegistrationPeriod(DateTime $date):bool{ + if (!is_null($this->registration_begin_date) && !is_null($this->registration_end_date)) { + return $date >= $this->registration_begin_date && $date <= $this->registration_end_date; + } + return false; + } + + public function isRegistrationPeriodDefined():bool{ + return !is_null($this->registration_begin_date) && !is_null($this->registration_end_date); + } + /** * @param DateTime $registration_begin_date */ @@ -2251,6 +2650,14 @@ SQL; $this->registration_begin_date = $this->convertDateFromTimeZone2UTC($registration_begin_date); } + public function setRawRegistrationBeginDate(DateTime $registration_begin_date){ + $this->registration_begin_date = $registration_begin_date; + } + + public function setRawRegistrationEndDate(DateTime $registration_end_date){ + $this->registration_end_date = $registration_end_date; + } + /** * @return $this */ @@ -2262,7 +2669,7 @@ SQL; /** * @return DateTime */ - public function getRegistrationEndDate() + public function getRegistrationEndDate():?DateTime { return $this->registration_end_date; } @@ -2288,8 +2695,9 @@ SQL; * @return bool */ public function checkSelectionPlanConflicts(SelectionPlan $selection_plan){ + if(!$selection_plan->IsEnabled()) return true; foreach ($this->selection_plans as $sp){ - + if(!$sp->IsEnabled()) continue; if($sp->getId() == $selection_plan->getId()) continue; $start1 = $selection_plan->getSelectionBeginDate(); @@ -2437,9 +2845,7 @@ SQL; * @return SelectionPlan[] */ public function getActiveSelectionPlans() { - $criteria = Criteria::create(); - $criteria->where(Criteria::expr()->eq('is_enabled', 1)); - return $this->selection_plans->matching($criteria)->toArray(); + return $this->selection_plans->filter(function ($e){ return $e->IsEnabled();} )->toArray(); } /** @@ -2479,7 +2885,6 @@ SQL; const STAGE_OPEN = 0; const STAGE_FINISHED = 1; - /** * @param Tag $tag * @return TrackTagGroup|null @@ -2613,9 +3018,9 @@ SQL; public function addTrackTagGroup(TrackTagGroup $track_tag_group) { if($this->track_tag_groups->contains($track_tag_group)) return $this; + $track_tag_group->setOrder($this->getTrackTagGroupMaxOrder() + 1); $this->track_tag_groups->add($track_tag_group); $track_tag_group->setSummit($this); - $track_tag_group->setOrder($this->getTrackTagGroupMaxOrder() + 1); return $this; } @@ -2837,11 +3242,7 @@ SQL; return null; } - static $valid_feed_types = [ - IExternalScheduleFeedFactory::NoneType, - IExternalScheduleFeedFactory::SchedType, - IExternalScheduleFeedFactory::VanderpoelType - ]; + /** * @return string|null */ @@ -2856,7 +3257,7 @@ SQL; */ public function setApiFeedType(string $api_feed_type): void { - if(!empty($api_feed_type) && !in_array($api_feed_type, self::$valid_feed_types)) + if(!empty($api_feed_type) && !in_array($api_feed_type, ISummitExternalScheduleFeedType::ValidFeedTypes)) throw new ValidationException(sprintf("feed type %s is not valid!", $api_feed_type)); $this->api_feed_type = $api_feed_type; } @@ -2906,7 +3307,229 @@ SQL; */ public function setBeginAllowBookingDate(DateTime $begin_allow_booking_date): void { - $this->begin_allow_booking_date = $begin_allow_booking_date; + $this->begin_allow_booking_date = $this->convertDateFromTimeZone2UTC($begin_allow_booking_date); + } + + /** + * @param DateTime $begin_allow_booking_date + */ + public function setRawBeginAllowBookingDate(DateTime $begin_allow_booking_date): void + { + $this->begin_allow_booking_date = $begin_allow_booking_date; + } + + /* + * @return SummitAccessLevelType[] + */ + public function getBadgeAccessLevelTypes(): array + { + return $this->badge_access_level_types; + } + + /** + * @param SummitAccessLevelType $access_level + */ + public function addBadgeAccessLevelType(SummitAccessLevelType $access_level):void{ + if($this->badge_access_level_types->contains($access_level)) return; + $this->badge_access_level_types->add($access_level); + $access_level->setSummit($this); + } + + /** + * @param SummitAccessLevelType $access_level + */ + public function removeBadgeAccessLevelType(SummitAccessLevelType $access_level):void{ + if(!$this->badge_access_level_types->contains($access_level)) return; + $this->badge_access_level_types->removeElement($access_level); + $access_level->clearSummit(); + } + + /** + * @param int $levelId + * @return SummitAccessLevelType|null + */ + public function getBadgeAccessLevelTypeById(int $levelId):?SummitAccessLevelType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($levelId))); + $attr = $this->badge_access_level_types->matching($criteria)->first(); + return $attr === false ? null : $attr; + } + + /** + * @param string $level_name + * @return SummitAccessLevelType|null + */ + public function getBadgeAccessLevelTypeByName(string $level_name):?SummitAccessLevelType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', trim($level_name))); + $attr = $this->badge_access_level_types->matching($criteria)->first(); + return $attr === false ? null : $attr; + } + + /** + * @return SummitTaxType[] + */ + public function getTaxTypes() + { + return $this->tax_types; + } + + /** + * @param SummitTaxType $tax_type + */ + public function addTaxType(SummitTaxType $tax_type):void{ + if($this->tax_types->contains($tax_type)) return; + $this->tax_types->add($tax_type); + $tax_type->setSummit($this); + } + + /** + * @param SummitTaxType $tax_type + */ + public function removeTaxType(SummitTaxType $tax_type):void{ + if(!$this->tax_types->contains($tax_type)) return; + $this->tax_types->removeElement($tax_type); + $tax_type->clearSummit(); + } + + /** + * @param int $tax_id + * @return SummitTaxType|null + */ + public function getTaxTypeById(int $tax_id):?SummitTaxType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($tax_id))); + $attr = $this->tax_types->matching($criteria)->first(); + return $attr === false ? null : $attr; + } + + /** + * @param string $tax_name + * @return SummitTaxType|null + */ + public function getTaxTypeByName(string $tax_name):?SummitTaxType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', trim($tax_name))); + $attr = $this->tax_types->matching($criteria)->first(); + return $attr === false ? null : $attr; + } + + /** + * @return SummitBadgeFeatureType[]|ArrayCollection + */ + public function getBadgeFeaturesTypes() + { + return $this->badge_features_types; + } + + /** + * @param SummitBadgeFeatureType $feature_type + */ + public function addFeatureType(SummitBadgeFeatureType $feature_type):void{ + if($this->badge_features_types->contains($feature_type)) return; + $this->badge_features_types->add($feature_type); + $feature_type->setSummit($this); + } + + /** + * @param SummitBadgeFeatureType $feature_type + */ + public function removeFeatureType(SummitBadgeFeatureType $feature_type):void{ + if(!$this->badge_features_types->contains($feature_type)) return; + $this->badge_features_types->removeElement($feature_type); + $feature_type->clearSummit(); + } + + + /** + * @param int $feature_id + * @return SummitBadgeFeatureType|null + */ + public function getFeatureTypeById(int $feature_id):?SummitBadgeFeatureType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($feature_id))); + $feature = $this->badge_features_types->matching($criteria)->first(); + return $feature === false ? null : $feature; + } + + /** + * @param string $feature_name + * @return SummitBadgeFeatureType|null + */ + public function getFeatureTypeByName(string $feature_name):?SummitBadgeFeatureType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', trim($feature_name))); + $feature = $this->badge_features_types->matching($criteria)->first(); + return $feature === false ? null : $feature; + } + + /** + * @return SummitBadgeType[] + */ + public function getBadgeTypes(): array + { + return $this->badge_types; + } + + /** + * @param SummitBadgeType $badge_type + */ + public function addBadgeType(SummitBadgeType $badge_type){ + if($this->badge_types->contains($badge_type)) return; + $this->badge_types->add($badge_type); + $badge_type->setSummit($this); + } + + /** + * @param SummitBadgeType $badge_type + */ + public function removeBadgeType(SummitBadgeType $badge_type):void{ + if(!$this->badge_types->contains($badge_type)) return; + $this->badge_types->removeElement($badge_type); + $badge_type->clearSummit(); + } + + /** + * @param int $badge_type_id + * @return SummitBadgeType|null + */ + public function getBadgeTypeById(int $badge_type_id): ?SummitBadgeType + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($badge_type_id))); + $badge_type = $this->badge_types->matching($criteria)->first(); + return $badge_type === false ? null : $badge_type; + } + + /** + * @param string $badge_type_name + * @return SummitBadgeType|null + */ + public function getBadgeTypeByName(string $badge_type_name): ?SummitBadgeType + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', trim($badge_type_name))); + $badge_type = $this->badge_types->matching($criteria)->first(); + return $badge_type === false ? null : $badge_type; + } + + /** + * @return bool + */ + public function hasDefaultBadgeType():bool { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('default', true)); + return $this->badge_types->matching($criteria)->count() > 0; + } + + /** + * @return bool + */ + public function getDefaultBadgeType():?SummitBadgeType { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('default', true)); + $badge_type = $this->badge_types->matching($criteria)->first(); + return $badge_type === false ? null : $badge_type; } /** @@ -2921,6 +3544,14 @@ SQL; * @param DateTime $end_allow_booking_date */ public function setEndAllowBookingDate(DateTime $end_allow_booking_date): void + { + $this->end_allow_booking_date = $this->convertDateFromTimeZone2UTC($end_allow_booking_date); + } + + /** + * @param DateTime $end_allow_booking_date + */ + public function setRawEndAllowBookingDate(DateTime $end_allow_booking_date): void { $this->end_allow_booking_date = $end_allow_booking_date; } @@ -2932,26 +3563,525 @@ SQL; /** * @return bool */ - public function isBookingPeriodOpen():bool{ + public function isBookingPeriodOpen():bool + { $now_utc = new \DateTime('now', new \DateTimeZone('UTC')); - if(!is_null($this->begin_allow_booking_date) && !is_null($this->end_allow_booking_date)){ - return $now_utc >= $this->begin_allow_booking_date && $now_utc <= $this->end_allow_booking_date; + if (!is_null($this->begin_allow_booking_date) && !is_null($this->end_allow_booking_date)) { + return $now_utc >= $this->begin_allow_booking_date && $now_utc <= $this->end_allow_booking_date; } return false; } + public function getMonthYear():?string{ + if(is_null($this->end_date)) return ""; + return $this->convertDateFromUTC2TimeZone($this->end_date)->format("M Y"); + } /** * @return string */ - public function getLogoUrl():?string { + public function getLogoUrl():?string + { $logoUrl = null; - if($this->hasLogo() && $logo = $this->getLogo()){ - $logoUrl = $logo->getUrl(); + if ($this->hasLogo() && $logo = $this->getLogo()) { + $logoUrl = $logo->getUrl(); } return $logoUrl; } + public function getReassignTicketTillDate(): ?DateTime + { + return $this->reassign_ticket_till_date; + } + + public function getReassignTicketTillDateLocal(): ?DateTime + { + return $this->convertDateFromUTC2TimeZone($this->reassign_ticket_till_date); + } + + + /** + * @return bool + */ + public function hasReassignTicketLimit():bool { + return !is_null($this->reassign_ticket_till_date); + } + + /** + * @param DateTime $reassign_ticket_till_date + */ + public function setReassignTicketTillDate(DateTime $reassign_ticket_till_date): void + { + $this->reassign_ticket_till_date = $this->convertDateFromTimeZone2UTC($reassign_ticket_till_date); + } + + /** + * @param DateTime $reassign_ticket_till_date + */ + public function setRawReassignTicketTillDate(DateTime $reassign_ticket_till_date): void + { + $this->reassign_ticket_till_date = $reassign_ticket_till_date; + } + + /** + * @return string + */ + public function getRegistrationDisclaimerContent(): ?string + { + return $this->registration_disclaimer_content; + } + + /** + * @param string $registration_disclaimer_content + */ + public function setRegistrationDisclaimerContent(string $registration_disclaimer_content): void + { + $this->registration_disclaimer_content = $registration_disclaimer_content; + } + + /** + * @return bool + */ + public function isRegistrationDisclaimerMandatory(): bool + { + return $this->registration_disclaimer_mandatory; + } + + /** + * @param bool $registration_disclaimer_mandatory + */ + public function setRegistrationDisclaimerMandatory(bool $registration_disclaimer_mandatory): void + { + $this->registration_disclaimer_mandatory = $registration_disclaimer_mandatory; + } + + /** + * @return array + */ + public function getSupportedCurrencies():array{ + return [AllowedCurrencies::USD, AllowedCurrencies::GBP, AllowedCurrencies::EUR]; + } + + /** + * @return Sponsor[] + */ + public function getSummitSponsors(){ + return $this->summit_sponsors; + } + + /** + * @param Company $company + * @return Sponsor|null + */ + public function getSummitSponsorByCompany(Company $company):?Sponsor{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('company', $company)); + $sponsor = $this->summit_sponsors->matching($criteria)->first(); + return $sponsor === false ? null : $sponsor; + } + + /** + * @param string $badge_type_name + * @return Sponsor|null + */ + public function getSummitSponsorById(int $id): ?Sponsor + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($id))); + $sponsor = $this->summit_sponsors->matching($criteria)->first(); + return $sponsor === false ? null : $sponsor; + } + + /** + * @param Sponsor $sponsor + */ + public function addSummitSponsor(Sponsor $sponsor){ + if($this->summit_sponsors->contains($sponsor)) return; + $sponsor->setOrder($this->getSummitSponsorMaxOrder()+1); + $this->summit_sponsors->add($sponsor); + $sponsor->setSummit($this); + + } + + /** + * @return int + */ + private function getSummitSponsorMaxOrder(){ + $criteria = Criteria::create(); + $criteria->orderBy(['order' => 'DESC']); + $sponsor = $this->summit_sponsors->matching($criteria)->first(); + $res = $sponsor === false ? 0 : $sponsor->getOrder(); + return is_null($res) ? 0 : $res; + } + + + /** + * @param Sponsor $sponsor + */ + public function removeSummitSponsor(Sponsor $sponsor){ + if(!$this->summit_sponsors->contains($sponsor)) return; + $this->summit_sponsors->removeElement($sponsor); + $sponsor->clearSummit(); + } + + /** + * @return SummitRefundPolicyType[] + */ + public function getRefundPolicies(): array + { + return $this->refund_policies; + } + + /** + * @param SummitRefundPolicyType $policy + */ + public function addRefundPolicy(SummitRefundPolicyType $policy){ + if($this->refund_policies->contains($policy)) return; + $this->refund_policies->add($policy); + $policy->setSummit($this); + } + + /** + * @param SummitRefundPolicyType $policy + */ + public function removeRefundPolicy(SummitRefundPolicyType $policy){ + if(!$this->refund_policies->contains($policy)) return; + $this->refund_policies->removeElement($policy); + $policy->clearSummit(); + } + + /** + * @param string $policy_name + * @return SummitBadgeType|null + */ + public function getRefundPolicyByName(string $policy_name): ?SummitRefundPolicyType + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', trim($policy_name))); + $policy = $this->refund_policies->matching($criteria)->first(); + return $policy === false ? null : $policy; + } + + /** + * @param int $until_x_days_before_event_starts + * @return SummitBadgeType|null + */ + public function getRefundPolicyByDays(int $until_x_days_before_event_starts): ?SummitRefundPolicyType + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('until_x_days_before_event_starts', intval($until_x_days_before_event_starts))); + $policy = $this->refund_policies->matching($criteria)->first(); + return $policy === false ? null : $policy; + } + + /** + * @param int $performed_n_days_before_event_starts + * @return SummitRefundPolicyType|null + */ + public function getRefundPolicyForRefundRequest(int $performed_n_days_before_event_starts):?SummitRefundPolicyType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->lte('until_x_days_before_event_starts', intval($performed_n_days_before_event_starts))); + $criteria->orderBy(['until_x_days_before_event_starts' => 'DESC']); + $policy = $this->refund_policies->matching($criteria)->first(); + return $policy === false ? null : $policy; + } + + /** + * @param int $id + * @return SummitBadgeType|null + */ + public function getRefundPolicyById(int $id): ?SummitRefundPolicyType + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($id))); + $policy = $this->refund_policies->matching($criteria)->first(); + return $policy === false ? null : $policy; + } + + /** + * @return SummitOrderExtraQuestionType[] + */ + public function getOrderExtraQuestions() + { + return $this->order_extra_questions; + } + + /** + * @param string $usage + * @return ArrayCollection|\Doctrine\Common\Collections\Collection + */ + public function getMandatoryOrderExtraQuestionsByUsage(string $usage){ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('mandatory', true)); + $criteria->andWhere(Criteria::expr()->in('usage', [$usage, SummitOrderExtraQuestionTypeConstants::BothQuestionUsage])); + return $this->order_extra_questions->matching($criteria); + } + + /** + * @param string $usage + * @return ArrayCollection|\Doctrine\Common\Collections\Collection + */ + public function getOrderExtraQuestionsByUsage(string $usage){ + $criteria = Criteria::create(); + $criteria->andWhere(Criteria::expr()->in('usage', [$usage, SummitOrderExtraQuestionTypeConstants::BothQuestionUsage])); + return $this->order_extra_questions->matching($criteria); + } + + /** + * @param int $question_id + * @return SummitOrderExtraQuestionType|null + */ + public function getOrderExtraQuestionById(int $question_id):?SummitOrderExtraQuestionType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', $question_id)); + $question = $this->order_extra_questions->matching($criteria)->first(); + return $question === false ? null : $question; + } + + /** + * @param string $name + * @return SummitOrderExtraQuestionType|null + */ + public function getOrderExtraQuestionByName(string $name):?SummitOrderExtraQuestionType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', trim($name))); + $question = $this->order_extra_questions->matching($criteria)->first(); + return $question === false ? null : $question; + } + + /** + * @param string $label + * @return SummitOrderExtraQuestionType|null + */ + public function getOrderExtraQuestionByLabel(string $label):?SummitOrderExtraQuestionType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('label', trim($label))); + $question = $this->order_extra_questions->matching($criteria)->first(); + return $question === false ? null : $question; + } + + /** + * @return int + */ + private function getOrderExtraQuestionMaxOrder():int{ + $criteria = Criteria::create(); + $criteria->orderBy(['order' => 'DESC']); + $question = $this->order_extra_questions->matching($criteria)->first(); + return $question === false ? 0 : $question->getOrder(); + } + + /** + * @param SummitOrderExtraQuestionType $extra_question + */ + public function addOrderExtraQuestion(SummitOrderExtraQuestionType $extra_question){ + + if($this->order_extra_questions->contains($extra_question)) return; + $extra_question->setOrder($this->getOrderExtraQuestionMaxOrder() +1); + $this->order_extra_questions->add($extra_question); + $extra_question->setSummit($this); + } + + /** + * @param SummitOrderExtraQuestionType $extra_question + */ + public function removeOrderExtraQuestion(SummitOrderExtraQuestionType $extra_question){ + + if(!$this->order_extra_questions->contains($extra_question)) return; + $this->order_extra_questions->removeElement($extra_question); + $extra_question->clearSummit(); + } + + /** + * @param SummitOrderExtraQuestionType $question + * @param int $new_order + * @throws ValidationException + */ + public function recalculateQuestionOrder(SummitOrderExtraQuestionType $question, $new_order){ + self::recalculateOrderForSelectable($this->order_extra_questions, $question, $new_order); + } + + /** + * @param Sponsor $sponsor + * @param int $new_order + * @throws ValidationException + */ + public function recalculateSummitSponsorOrder(Sponsor $sponsor, $new_order){ + self::recalculateOrderForSelectable($this->summit_sponsors, $sponsor, $new_order); + } + + /** + * @return SummitOrder[] + */ + public function getOrders() + { + return $this->orders; + } + + /** + * @param int $id + * @return SummitOrder|null + */ + public function getOrderById(int $id):?SummitOrder{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($id))); + $order = $this->orders->matching($criteria)->first(); + return $order === false ? null : $order; + } + + /** + * @param SummitOrder $order + */ + public function addOrder(SummitOrder $order){ + if($this->orders->contains($order)) return; + $this->orders->add($order); + $order->setSummit($this); + } + + /** + * @param SummitOrder $order + */ + public function removeOrder(SummitOrder $order){ + if(!$this->orders->contains($order)) return; + $this->orders->removeElement($order); + $order->clearSummit(); + } + + /** + * @param string $number + * @return bool + */ + public function existOrderNumber(string $number):bool + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('number', trim($number))); + return $this->orders->matching($criteria)->count() > 0; + } + + /** + * @var bool + */ + private $mark_as_deleted; + + public function markAsDeleted(){ + $this->mark_as_deleted = true; + } + + /** + * @return bool + */ + public function isDeleting():bool{ + return is_null($this->mark_as_deleted) ? false : $this->mark_as_deleted; + } + + /** + * @return string + */ + public function getQRRegistryFieldDelimiter():string { + return IQREntity::QRRegistryFieldDelimiterChar; + } + + /** + * @return int + */ + public function getRegistrationReminderEmailDaysInterval(): ?int + { + $days_interval = $this->registration_reminder_email_days_interval; + + if (is_null($days_interval)) { + $days_interval = intval(Config::get('registration.reminder_email_days_interval', 0)); + } + + return $days_interval; + } + + /** + * @param int $registration_reminder_email_days_interval + */ + public function setRegistrationReminderEmailDaysInterval(int $registration_reminder_email_days_interval): void + { + $this->registration_reminder_email_days_interval = $registration_reminder_email_days_interval; + } + + /** + * @return bool + */ + public function isEnded():bool{ + $utc_now = new \DateTime('now', new \DateTimeZone('UTC')); + $end_date = $this->getEndDate(); + if(is_null($end_date)) return false; + return $end_date < $utc_now; + } + + + /** + * @param DateTime $day + * @param bool $omit_time_check + * @return bool + */ + public function dayIsOnSummitPeriod(\DateTime $day, $omit_time_check = true):bool{ + if(is_null($this->begin_date)) return false; + if(is_null($this->end_date)) return false; + + $dt = clone $day; + $dt = $dt->setTimezone(new \DateTimeZone('UTC')); + + if($omit_time_check) + $dt= $dt->setTime(0, 0,0); + + $dt = $dt->getTimestamp(); + + $bd = clone $this->begin_date; + + if($omit_time_check) + $bd = $bd->setTime(0,0,0,0); + + $bd = $bd->getTimestamp(); + + $ed = clone $this->end_date; + + if($omit_time_check) + $ed = $ed->setTime(0,0,0,0); + + $ed = $ed->getTimestamp(); + + return $bd <= $dt && $dt <= $ed; + } + + /* + * @return string + */ + public function getExternalRegistrationFeedType(): ?string + { + return $this->external_registration_feed_type; + } + + /** + * @return string + */ + public function getExternalRegistrationFeedApiKey(): ?string + { + return $this->external_registration_feed_api_key; + } + + /** + * @param string $external_registration_feed_type + * @throws ValidationException + */ + public function setExternalRegistrationFeedType(string $external_registration_feed_type): void + { + if(!empty($external_registration_feed_type) && !in_array($external_registration_feed_type, ISummitExternalRegistrationFeedType::ValidFeedTypes)) + throw new ValidationException(sprintf("feed type %s is not valid!", $external_registration_feed_type)); + $this->external_registration_feed_type = $external_registration_feed_type; + } + + /** + * @param string $external_registration_feed_api_key + */ + public function setExternalRegistrationFeedApiKey(string $external_registration_feed_api_key): void + { + $this->external_registration_feed_api_key = $external_registration_feed_api_key; + } + // schedule /** @@ -3239,9 +4369,535 @@ SQL; /** * @param PersonalCalendarShareInfo $link */ - public function removeScheduleShareableLink(PersonalCalendarShareInfo $link){ - if(!$this->schedule_shareable_links->contains($link)) return; + public function removeScheduleShareableLink(PersonalCalendarShareInfo $link) + { + if (!$this->schedule_shareable_links->contains($link)) return; $this->schedule_shareable_links->removeElement($link); $link->clearSummit(); } + + /** + * @param PaymentGatewayProfile $payment_profile + */ + public function addPaymentProfile(PaymentGatewayProfile $payment_profile){ + if($this->payment_profiles->contains($payment_profile)) + return; + $this->payment_profiles->add($payment_profile); + $payment_profile->setSummit($this); + } + + /** + * @param PaymentGatewayProfile $payment_profile + */ + public function removePaymentProfile(PaymentGatewayProfile $payment_profile){ + if(!$this->payment_profiles->contains($payment_profile)) + return; + $this->payment_profiles->removeElement($payment_profile); + $payment_profile->clearSummit(); + } + + /** + * @param string $application_type + * @param IBuildDefaultPaymentGatewayProfileStrategy|null $build_default_payment_gateway_profile_strategy + * @return IPaymentGatewayAPI|null + * @throws ValidationException + */ + public function getPaymentGateWayPerApp + ( + string $application_type, + ?IBuildDefaultPaymentGatewayProfileStrategy $build_default_payment_gateway_profile_strategy = null + ):?IPaymentGatewayAPI { + + Log::debug(sprintf("Summit::getPaymentGateWayPerApp id %s application_type %s", $this->id, $application_type)); + + if(!in_array($application_type, IPaymentConstants::ValidApplicationTypes)) + throw new ValidationException(sprintf("Application Type %s is not valid.", $application_type)); + + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('active', true)); + $criteria->andWhere(Criteria::expr()->eq('application_type', trim($application_type))); + $payment_profile = $this->payment_profiles->matching($criteria)->first(); + + if(!$payment_profile && !is_null($build_default_payment_gateway_profile_strategy)){ + // try to build default one + Log::debug(sprintf("Summit::getPaymentGateWayPerApp id %s application_type %s trying to get default settings", $this->id, $application_type)); + $payment_profile = $build_default_payment_gateway_profile_strategy->build($application_type); + } + + if(!$payment_profile) return null; + + return $payment_profile->buildPaymentGatewayApi(); + } + + /** + * @return ArrayCollection|\Doctrine\Common\Collections\Collection + */ + public function getActivePaymentGateWayProfiles(){ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('active', true)); + return $this->payment_profiles->matching($criteria); + } + + /** + * @param string $application_type + * @return PaymentGatewayProfile|null + * @throws ValidationException + */ + public function getPaymentGateWayProfilePerApp(string $application_type):?PaymentGatewayProfile { + + if(!in_array($application_type, IPaymentConstants::ValidApplicationTypes)) + throw new ValidationException(sprintf("Application Type %s is not valid.", $application_type)); + + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('active', true)); + $criteria->andWhere(Criteria::expr()->eq('application_type', trim($application_type))); + $payment_profile = $this->payment_profiles->matching($criteria)->first(); + return (!$payment_profile) ? null : $payment_profile; + } + + /** + * @param int $profileId + * @return PaymentGatewayProfile|null + */ + public function getPaymentProfileById(int $profileId):?PaymentGatewayProfile{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($profileId))); + $profile = $this->payment_profiles->matching($criteria)->first(); + return $profile === false ? null : $profile; + } + + public function addEmailEventFlow(SummitEmailEventFlow $email_event_flow){ + if($this->email_flows_events->contains($email_event_flow)) return; + $this->email_flows_events->add($email_event_flow); + $email_event_flow->setSummit($this); + } + + public function removeEmailEventFlow(SummitEmailEventFlow $email_event_flow){ + if(!$this->email_flows_events->contains($email_event_flow)) return; + $this->email_flows_events->removeElement($email_event_flow); + } + + public function clearEmailEventFlow(){ + $this->email_flows_events->clear(); + } + + /** + * @param string $eventSlug + * @return string|null + */ + public function getEmailIdentifierPerEmailEventFlowSlug(string $eventSlug):?string{ + Log::debug(sprintf("Summit::getEmailIdentifierPerEmailEventFlowSlug id %s slug %s", $this->id, $eventSlug)); + // first check if we have an override + $email_event = $this->createQueryBuilder() + ->select('distinct ef') + ->from('App\Models\Foundation\Summit\EmailFlows\SummitEmailEventFlow', 'ef') + ->join('ef.summit', 's') + ->join('ef.event_type', 'et') + ->where("s.id = :summit_id and et.slug = :slug") + ->setParameter('summit_id', $this->getId()) + ->setParameter('slug', trim($eventSlug)) + ->setMaxResults(1) + ->setCacheable(false) + ->getQuery() + ->setCacheable(false) + ->useQueryCache(false) + ->getOneOrNullResult(); + + if(!is_null($email_event) && $email_event instanceof SummitEmailEventFlow) { + Log::debug + ( + sprintf + ( + "Summit::getEmailIdentifierPerEmailEventFlowSlug id %s slug %s got override email event id %s template %s", + $this->id, + $eventSlug, + $email_event->id, + $email_event->getEmailTemplateIdentifier() + ) + ); + return $email_event->getEmailTemplateIdentifier(); + } + + Log::debug(sprintf("Summit::getEmailIdentifierPerEmailEventFlowSlug id %s slug %s trying to get default one", $this->id, $eventSlug)); + // then check default + $email_event_type = $this->createQueryBuilder() + ->select('distinct eft') + ->from('App\Models\Foundation\Summit\EmailFlows\SummitEmailEventFlowType', 'eft') + ->where("eft.slug = :slug") + ->setParameter('slug', trim($eventSlug)) + ->setMaxResults(1) + ->setCacheable(false) + ->getQuery() + ->setCacheable(false) + ->useQueryCache(false) + ->getOneOrNullResult(); + + if(!is_null($email_event_type) && $email_event_type instanceof SummitEmailEventFlowType) + return $email_event_type->getDefaultEmailTemplate(); + + return null; + } + + /** + * @param SummitEmailEventFlowType $type + * @return SummitEmailEventFlow|null + */ + public function getEmailEventByType(SummitEmailEventFlowType $type):?SummitEmailEventFlow{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('event_type', $type)); + $event = $this->email_flows_events->matching($criteria)->first(); + return $event === false ? null : $event; + } + + public function getEmailEventById(int $id):?SummitEmailEventFlow { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', $id)); + $event = $this->email_flows_events->matching($criteria)->first(); + return $event === false ? null : $event; + } + + /** + * @return array|SummitEmailEventFlow[] + */ + public function getAllEmailFlowsEvents(){ + return $this->seedDefaultEmailFlowEvents(); + } + + public function seedDefaultEmailFlowEvents(){ + $builder = $this->createQueryBuilder() + ->select('distinct ft') + ->from('App\Models\Foundation\Summit\EmailFlows\SummitEmailFlowType', 'ft') + ->orderBy("ft.id"); + $res = $builder->getQuery()->getResult(); + $list = []; + foreach($res as $flow_type){ + foreach ($flow_type->getEventTypes() as $event_type){ + // check if we have an override + $email_event_flow = $this->getEmailEventByType($event_type); + if(is_null($email_event_flow)){ + $email_event_flow = new SummitEmailEventFlow(); + $email_event_flow->setEventType($event_type); + $email_event_flow->setEmailTemplateIdentifier($event_type->getDefaultEmailTemplate()); + $this->addEmailEventFlow($email_event_flow); + } + $list[] = $email_event_flow; + } + } + return $list; + } + + /** + * @return string + */ + public function getDefaultPageUrl(): ?string + { + return $this->default_page_url; + } + + /** + * @param string $default_page_url + */ + public function setDefaultPageUrl(string $default_page_url): void + { + $this->default_page_url = $default_page_url; + } + + /** + * @return string + */ + public function getSpeakerConfirmationDefaultPageUrl(): ?string + { + return $this->speaker_confirmation_default_page_url; + } + + /** + * @param string $speaker_confirmation_default_page_url + */ + public function setSpeakerConfirmationDefaultPageUrl(string $speaker_confirmation_default_page_url): void + { + $this->speaker_confirmation_default_page_url = $speaker_confirmation_default_page_url; + } + + public function getSummitDocuments(){ + return $this->summit_documents; + } + + /** + * @param SummitDocument $doc + */ + public function addSummitDocument(SummitDocument $doc){ + if($this->summit_documents->contains($doc)) return; + $this->summit_documents->add($doc); + $doc->setSummit($this); + } + + /** + * @param SummitDocument $doc + */ + public function removeSummitDocument(SummitDocument $doc){ + if(!$this->summit_documents->contains($doc)) return; + $this->summit_documents->removeElement($doc); + $doc->clearSummit(); + } + + public function clearSummitDocuments(){ + $this->summit_documents->clear(); + } + + /** + * @param int $document_id + * @return SummitDocument|null + */ + public function getSummitDocumentById(int $document_id):?SummitDocument{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($document_id))); + $document = $this->summit_documents->matching($criteria)->first(); + return $document === false ? null : $document; + } + + /** + * @param string $name + * @return SummitDocument|null + */ + public function getSummitDocumentByName(string $name):?SummitDocument{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', trim($name))); + $document = $this->summit_documents->matching($criteria)->first(); + return $document === false ? null : $document; + } + + /** + * @param string $label + * @return SummitDocument|null + */ + public function getSummitDocumentByLabel(string $label):?SummitDocument{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('label', trim($label))); + $document = $this->summit_documents->matching($criteria)->first(); + return $document === false ? null : $document; + } + + /** + * @param string $email + * @return SummitRegistrationInvitation|null + */ + public function getSummitRegistrationInvitationByEmail(string $email):?SummitRegistrationInvitation{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('email', trim($email))); + $invitation = $this->registration_invitations->matching($criteria)->first(); + return $invitation === false ? null : $invitation; + } + + /** + * @param int $invitation_id + * @return SummitRegistrationInvitation|null + */ + public function getSummitRegistrationInvitationById(int $invitation_id):?SummitRegistrationInvitation{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($invitation_id))); + $invitation = $this->registration_invitations->matching($criteria)->first(); + return $invitation === false ? null : $invitation; + } + + /** + * @param string $hash + * @return SummitRegistrationInvitation|null + */ + public function getSummitRegistrationInvitationByHash(string $hash):?SummitRegistrationInvitation{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('hash', trim($hash))); + $invitation = $this->registration_invitations->matching($criteria)->first(); + return $invitation === false ? null : $invitation; + } + + /** + * @return bool + */ + public function isInviteOnlyRegistration():bool{ + return $this->registration_invitations->count() > 0; + } + + /** + * @param string $email + * @return bool + */ + public function canBuyRegistrationTickets(string $email):bool { + if(!$this->isInviteOnlyRegistration()) return true; + return $this->getSummitRegistrationInvitationByEmail($email) !== null; + } + + /** + * @param SummitRegistrationInvitation $invitation + */ + public function addRegistrationInvitation(SummitRegistrationInvitation $invitation){ + if($this->registration_invitations->contains($invitation)) return; + $this->registration_invitations->add($invitation); + $invitation->setSummit($this); + } + + /** + * @param SummitRegistrationInvitation $invitation + */ + public function removeRegistrationInvitation(SummitRegistrationInvitation $invitation){ + if(!$this->registration_invitations->contains($invitation)) return; + $this->registration_invitations->removeElement($invitation); + $invitation->clearSummit(); + } + + /** + * @return ArrayCollection|SummitRegistrationInvitation[] + */ + public function getRegistrationInvitations(){ + return $this->registration_invitations; + } + + public function clearRegistrationInvitations():void{ + $this->registration_invitations->clear(); + } + + /** + * @param SummitAdministratorPermissionGroup $group + */ + public function add2SummitAdministratorPermissionGroup(SummitAdministratorPermissionGroup $group){ + if($this->permission_groups->contains($group)) return; + $this->permission_groups->add($group); + } + + public function removeFromSummitAdministratorPermissionGroup(SummitAdministratorPermissionGroup $group){ + if(!$this->permission_groups->contains($group)) return; + $this->permission_groups->removeElement($group); + } + + public function getSummitAdministratorPermissionGroup(){ + return $this->permission_groups; + } + + /** + * @param SummitMediaUploadType $type + */ + public function addMediaUploadType(SummitMediaUploadType $type){ + if($this->media_upload_types->contains($type)) return; + $this->media_upload_types->add($type); + $type->setSummit($this); + } + + /** + * @param SummitMediaUploadType $type + */ + public function removeMediaUploadType(SummitMediaUploadType $type){ + if(!$this->media_upload_types->contains($type)) return; + $this->media_upload_types->removeElement($type); + $type->clearSummit(); + } + + public function clearMediaUploadType(){ + $this->media_upload_types->clear(); + } + + public function getMediaUploadTypes(){ + return $this->media_upload_types; + } + + /** + * @param int $id + * @return SummitMediaUploadType|null + */ + public function getMediaUploadTypeById(int $id):?SummitMediaUploadType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('id', intval($id))); + $type = $this->media_upload_types->matching($criteria)->first(); + return $type === false ? null : $type; + } + + /** + * @param string $name + * @return SummitMediaUploadType|null + */ + public function getMediaUploadTypeByName(string $name):?SummitMediaUploadType{ + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('name', trim($name))); + $type = $this->media_upload_types->matching($criteria)->first(); + return $type === false ? null : $type; + } + + /** + * @return string|null + */ + public function getVirtualSiteUrl(): ?string + { + return $this->virtual_site_url; + } + + /** + * @param string $virtual_site_url + */ + public function setVirtualSiteUrl(?string $virtual_site_url): void + { + $this->virtual_site_url = $virtual_site_url; + } + + /** + * @return string|null + */ + public function getMarketingSiteUrl(): ?string + { + return $this->marketing_site_url; + } + + /** + * @param string $marketing_site_url + */ + public function setMarketingSiteUrl(?string $marketing_site_url): void + { + $this->marketing_site_url = $marketing_site_url; + } + + /** + * @return string + */ + public function getVirtualSiteOAuth2ClientId(): ?string + { + return $this->virtual_site_oauth2_client_id; + } + + /** + * @param string $virtual_site_oauth2_client_id + */ + public function setVirtualSiteOAuth2ClientId(?string $virtual_site_oauth2_client_id): void + { + $this->virtual_site_oauth2_client_id = $virtual_site_oauth2_client_id; + } + + /** + * @return string + */ + public function getMarketingSiteOAuth2ClientId(): ?string + { + return $this->marketing_site_oauth2_client_id; + } + + /** + * @param string $marketing_site_oauth2_client_id + */ + public function setMarketingSiteOAuth2ClientId(?string $marketing_site_oauth2_client_id): void + { + $this->marketing_site_oauth2_client_id = $marketing_site_oauth2_client_id; + } + + /** + * @return string|null + */ + public function getSupportEmail(): ?string + { + return $this->support_email; + } + + /** + * @param string $support_email + */ + public function setSupportEmail(?string $support_email): void + { + $this->support_email = $support_email; + } + } diff --git a/app/Models/Foundation/Summit/SummitDocument.php b/app/Models/Foundation/Summit/SummitDocument.php new file mode 100644 index 00000000..14d3aa59 --- /dev/null +++ b/app/Models/Foundation/Summit/SummitDocument.php @@ -0,0 +1,198 @@ +event_types = new ArrayCollection(); + $this->file = null; + $this->label = ''; + $this->description = ''; + $this->name = ''; + } + + /** + * @return bool + */ + public function hasFile(){ + return $this->getFileId() > 0; + } + + /** + * @return int + */ + public function getFileId(){ + try{ + return !is_null($this->file) ? $this->file->getId():0; + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @return File + */ + public function getFile():?File + { + return $this->file; + } + + public function clearFile(){ + $this->file = null; + } + + /** + * @param File $file + */ + public function setFile(File $file) + { + $this->file = $file; + } + + /** + * @return string + */ + public function getName(): ?string + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName(string $name): void + { + $this->name = $name; + } + + /** + * @return string + */ + public function getDescription(): ?string + { + return $this->description; + } + + /** + * @param string $description + */ + public function setDescription(string $description): void + { + $this->description = $description; + } + + /** + * @return string + */ + public function getLabel(): ?string + { + return $this->label; + } + + /** + * @param string $label + */ + public function setLabel(string $label): void + { + $this->label = $label; + } + + public function getEventTypes(){ + return $this->event_types; + } + + public function addEventType(SummitEventType $eventType){ + if($this->event_types->contains($eventType)) return; + $this->event_types->add($eventType); + } + + public function removeEventType(SummitEventType $eventType){ + if(!$this->event_types->contains($eventType)) return; + $this->event_types->removeElement($eventType); + } + + public function clearEventTypes(){ + $this->event_types->clear(); + } + + /** + * @return string|null + */ + public function getFileUrl():?string{ + $fileUrl = null; + if($this->hasFile() && $file = $this->getFile()){ + $fileUrl = $file->getUrl(); + } + return $fileUrl; + } + +} \ No newline at end of file diff --git a/app/Models/OAuth2/AccessToken.php b/app/Models/OAuth2/AccessToken.php index 930d6ee8..7014d363 100644 --- a/app/Models/OAuth2/AccessToken.php +++ b/app/Models/OAuth2/AccessToken.php @@ -132,7 +132,7 @@ final class AccessToken extends Token return $this->application_type; } - public function getAllowedOrigins() + public function getAllowedOrigins():?string { return $this->allowed_origins; } diff --git a/app/Models/OAuth2/IResourceServerContext.php b/app/Models/OAuth2/IResourceServerContext.php index 8d4c87f7..1d7918a7 100644 --- a/app/Models/OAuth2/IResourceServerContext.php +++ b/app/Models/OAuth2/IResourceServerContext.php @@ -66,11 +66,6 @@ interface IResourceServerContext */ public function setAuthorizationContext(array $auth_context); - /** - * @return Member|null - */ - public function getCurrentUser(): ?Member; - /** * @return null|string */ @@ -80,4 +75,15 @@ interface IResourceServerContext * @return null|string */ public function getAllowedReturnUris(); + + /** + * @return Member|null + */ + public function getCurrentUser():?Member; + + /** + * @return array + */ + public function getCurrentUserGroups():array; + } \ No newline at end of file diff --git a/app/Models/OAuth2/ResourceServerContext.php b/app/Models/OAuth2/ResourceServerContext.php index ae4e3332..e36c0eec 100644 --- a/app/Models/OAuth2/ResourceServerContext.php +++ b/app/Models/OAuth2/ResourceServerContext.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\Models\Foundation\Main\IGroup; use App\Services\Model\IMemberService; use Illuminate\Support\Facades\Log; @@ -167,9 +168,8 @@ final class ResourceServerContext implements IResourceServerContext $member = null; // legacy test, for new IDP version this value came on null $id = $this->getCurrentUserExternalId(); - Log::debug(sprintf("ResourceServerContext::getCurrentUser trying to get user by ExternalId %s", $id)); if(!is_null($id) && !empty($id)){ - $member = $this->member_repository->getById(intval($id)); + $member = $this->member_repository->getByExternalIdExclusiveLock(intval($id)); if(!is_null($member)) return $this->checkGroups($member); } @@ -178,11 +178,10 @@ final class ResourceServerContext implements IResourceServerContext // try to get by external id $id = $this->getCurrentUserId(); - Log::debug(sprintf("ResourceServerContext::getCurrentUser trying to get user by id %s", $id)); if(is_null($id)) { return null; } - $member = $this->member_repository->getByExternalId(intval($id)); + $member = $this->member_repository->getByExternalIdExclusiveLock(intval($id)); if(!is_null($member)){ $user_first_name = $this->getAuthContextVar('user_first_name'); @@ -208,7 +207,7 @@ final class ResourceServerContext implements IResourceServerContext $user_email = $this->getAuthContextVar('user_email'); // at last resort try to get by email Log::debug(sprintf("ResourceServerContext::getCurrentUser getting user by email %s", $user_email)); - $member = $this->member_repository->getByEmail($user_email); + $member = $this->member_repository->getByEmailExclusiveLock($user_email); if (is_null($member)) {// user exist on IDP but not in our local DB, proceed to create it Log::debug @@ -252,41 +251,20 @@ final class ResourceServerContext implements IResourceServerContext * @return Member */ private function checkGroups(Member $member):Member{ + Log::debug(sprintf("ResourceServerContext::checkGroups member %s %s", $member->getId(), $member->getEmail())); // check groups - $idpGroups = $this->getCurrentUserGroups(); - foreach ($idpGroups as $idpGroup){ - if(!isset($idp_group['slug'])) continue; - $code = trim($idpGroup['slug']); - if(!$member->isOnGroup($code, true)){ - // add 2 group - $group = $this->group_repository->getBySlug($code); - if(is_null($group)){ - $group = new Group(); - $group->setCode($code); - $group->setDescription($code); - $group->setTitle($code); - $this->group_repository->add($group, true); - } - $member->add2Group($group); - } - // map from super admin to admin - if($code === IGroup::SuperAdmins){ - // try to add to admin too - if(!$member->isOnGroup(IGroup::Administrators, true)){ - // add it - $group = $this->group_repository->getBySlug(IGroup::Administrators); - if(is_null($group)){ - $group = new Group(); - $group->setCode(IGroup::Administrators); - $group->setDescription(IGroup::Administrators); - $group->setTitle(IGroup::Administrators); - $this->group_repository->add($group, true); - } - $member->add2Group($group); - } + $groups = []; + foreach ($this->getCurrentUserGroups() as $idpGroup){ + Log::debug(sprintf("ResourceServerContext::checkGroups member %s %s group %s", $member->getId(), $member->getEmail(), json_encode($idpGroup))); + $slug = $idpGroup['slug'] ?? ''; + Log::debug(sprintf("ResourceServerContext::checkGroups member %s %s group slug %s", $member->getId(), $member->getEmail(), $slug)); + if(empty($slug)){ + continue; } + $groups[] = trim($slug); + Log::debug(sprintf("ResourceServerContext::checkGroups member %s %s slug %s", $member->getId(), $member->getEmail(), trim($idpGroup['slug']))); } - return $member; + return $this->member_service->synchronizeGroups($member, $groups); } /** * @return array @@ -294,6 +272,10 @@ final class ResourceServerContext implements IResourceServerContext public function getCurrentUserGroups(): array { $res = $this->getAuthContextVar('user_groups'); - return is_null($res)? [] : $res; + if(is_null($res)){ + Log::debug("ResourceServerContext::getCurrentUserGroups is null"); + return []; + } + return $res; } } \ No newline at end of file diff --git a/app/Models/ResourceServer/AccessTokenService.php b/app/Models/ResourceServer/AccessTokenService.php index 1933bfe8..f42683a9 100644 --- a/app/Models/ResourceServer/AccessTokenService.php +++ b/app/Models/ResourceServer/AccessTokenService.php @@ -158,7 +158,7 @@ final class AccessTokenService implements IAccessTokenService } if(array_key_exists("user_groups" , $token_info)){ - $token_info['user_groups'] = json_encode($token_info['user_groups']); + $token_info['user_groups'] = json_encode($token_info['user_groups']); } $this->cache_service->storeHash(md5($token_value), $token_info, $cache_lifetime); @@ -200,7 +200,7 @@ final class AccessTokenService implements IAccessTokenService } // http://docs.guzzlephp.org/en/stable/request-options.html $response = $client->request('POST', - "{$auth_server_url}/oauth2/token/introspection", + "{$auth_server_url}/oauth2/token/introspection", [ 'form_params' => ['token' => $token_value], 'auth' => [$client_id, $client_secret], diff --git a/app/Models/Utils/BaseEntity.php b/app/Models/Utils/BaseEntity.php index 39736cb4..1b1a5c01 100644 --- a/app/Models/Utils/BaseEntity.php +++ b/app/Models/Utils/BaseEntity.php @@ -27,6 +27,13 @@ class BaseEntity implements IEntity */ protected $id; + /** + * @return bool + */ + public function isNew():bool{ + return is_null($this->id); + } + /** * @return int */ diff --git a/app/Models/Utils/IBaseRepository.php b/app/Models/Utils/IBaseRepository.php index 0bd7994e..444582ad 100644 --- a/app/Models/Utils/IBaseRepository.php +++ b/app/Models/Utils/IBaseRepository.php @@ -58,4 +58,12 @@ interface IBaseRepository */ public function getAllByPage(PagingInfo $paging_info, Filter $filter = null, Order $order = null); + /** + * @param PagingInfo $paging_info + * @param Filter|null $filter + * @param Order|null $order + * @return array + */ + public function getAllIdsByPage(PagingInfo $paging_info, Filter $filter = null, Order $order = null):array; + } \ No newline at end of file diff --git a/app/Models/Utils/IStorageTypesConstants.php b/app/Models/Utils/IStorageTypesConstants.php new file mode 100644 index 00000000..04c9c0e7 --- /dev/null +++ b/app/Models/Utils/IStorageTypesConstants.php @@ -0,0 +1,29 @@ +getIdMappings[$name] ?? null; + if(!is_null($property)) { + return $this->getPropertyId($property); + } + $property = $this->hasPropertyMappings[$name] ?? null; + if(!is_null($property)) { + return $this->hasPropertySet($property); + } + return null; + } + + /** + * @param string $property_name + * @return int + */ + public function getPropertyId(string $property_name){ + try { + return is_null($this->{$property_name}) ? 0 : $this->{$property_name}->getId(); + } + catch(\Exception $ex){ + return 0; + } + } + + /** + * @param string $property_name + * @return bool + */ + public function hasPropertySet(string $property_name):bool{ + return $this->getPropertyId($property_name) > 0; + } +} \ No newline at end of file diff --git a/app/Permissions/permissions.yml b/app/Permissions/permissions.yml index 01865856..2b386af0 100644 --- a/app/Permissions/permissions.yml +++ b/app/Permissions/permissions.yml @@ -1,5 +1,7 @@ # here you define per Entity ClassName allowed fields to edit per user role - SummitEvent: + - super-admins: + - __all__ - administrators: - __all__ - summit-front-end-administrators: @@ -7,6 +9,8 @@ - summit-room-administrators: - occupancy - Presentation: + - super-admins: + - __all__ - administrators: - __all__ - summit-front-end-administrators: diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 6354684c..7ca263bd 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -1,14 +1,26 @@ 'sometimes|int', + 'type_id' => 'sometimes|int', + 'promo_code' => 'nullable|string|max:255', + 'attendee_first_name' => 'nullable|string|max:255', + 'attendee_last_name' => 'nullable|string|max:255', + 'attendee_company' => 'nullable|string|max:255', + 'attendee_email' => 'nullable|string|max:255|email', + 'disclaimer_accepted' => 'nullable|boolean', + 'share_contact_info' => 'nullable|boolean', + 'extra_questions' => 'sometimes|order_extra_question_dto_array' + ]; + + static $order_extra_question_dto_fields = [ + 'question_id', + 'answer', + ]; + + static $order_extra_question_dto_validation_rules = [ + 'question_id' => 'required|int', + 'answer' => 'nullable|string|max:255', + ]; + const DefaultSchema = 'https://'; static $event_dto_fields = [ @@ -110,7 +158,8 @@ class AppServiceProvider extends ServiceProvider if (!empty($to) && !empty($from)) { $subject = Config::get('log.email_subject', 'openstackid-resource-server error'); - $handler = new LaravelMailerHandler($to, $subject, $from); + $cacheService = App::make(ICacheService::class); + $handler = new LaravelMailerHandler($cacheService, $to, $subject, $from); $handler->setLevel(Config::get('log.email_level', 'error')); $logger->pushHandler($handler); } @@ -123,7 +172,7 @@ class AppServiceProvider extends ServiceProvider if(!is_array($value)) return false; foreach($value as $element) { - if(!is_int($element)) return false; + if(!is_numeric($element)) return false; } return true; }); @@ -151,6 +200,55 @@ class AppServiceProvider extends ServiceProvider return true; }); + Validator::extend('order_extra_question_dto_array', function($attribute, $value, $parameters, $validator) + { + $validator->addReplacer('order_extra_question_dto_array', function($message, $attribute, $rule, $parameters) use ($validator) { + return sprintf + ( + "%s should be an array of order extra question data {question_id : int, answer: string}", + $attribute); + }); + + if(!is_array($value)) return false; + + foreach($value as $element) + { + foreach($element as $key => $element_val){ + if(!in_array($key, self::$order_extra_question_dto_fields)) return false; + } + + // Creates a Validator instance and validates the data. + $validation = Validator::make($element, self::$order_extra_question_dto_validation_rules); + + if($validation->fails()) return false; + } + return true; + }); + + Validator::extend('ticket_dto_array', function($attribute, $value, $parameters, $validator) + { + $validator->addReplacer('ticket_dto_array', function($message, $attribute, $rule, $parameters) use ($validator) { + return sprintf + ( + "%s should be an array of ticket data {id: int|optional, type_id: int|optional, promo_code:string|optional, attendee_first_name:string|optional, attendee_last_name:string|optional, attendee_email:string|optional, extra_questions:array|optional }", + $attribute + ); + }); + if(!is_array($value)) return false; + foreach($value as $element) + { + foreach($element as $key => $element_val){ + if(!in_array($key, self::$ticket_dto_fields)) return false; + } + + // Creates a Validator instance and validates the data. + $validation = Validator::make($element, self::$ticket_dto_validation_rules); + + if($validation->fails()) return false; + } + return true; + }); + Validator::extend('event_dto_publish_array', function($attribute, $value, $parameters, $validator) { $validator->addReplacer('event_dto_publish_array', function($message, $attribute, $rule, $parameters) use ($validator) { @@ -174,7 +272,6 @@ class AppServiceProvider extends ServiceProvider return true; }); - Validator::extend('text', function($attribute, $value, $parameters, $validator) { $validator->addReplacer('text', function($message, $attribute, $rule, $parameters) use ($validator) { @@ -219,19 +316,6 @@ class AppServiceProvider extends ServiceProvider return true; }); - Validator::extend('int_array', function($attribute, $value, $parameters, $validator) - { - $validator->addReplacer('int_array', function($message, $attribute, $rule, $parameters) use ($validator) { - return sprintf("%s should be an array of int", $attribute); - }); - if(!is_array($value)) return false; - foreach($value as $element) - { - if(!is_int($element)) return false; - } - return true; - }); - Validator::extend('url_array', function($attribute, $value, $parameters, $validator) { $validator->addReplacer('url_array', function($message, $attribute, $rule, $parameters) use ($validator) { @@ -300,7 +384,6 @@ class AppServiceProvider extends ServiceProvider return in_array($value, [ PushNotificationMessagePriority::Normal, PushNotificationMessagePriority::High]); }); - Validator::extend('after_or_null_epoch', function($attribute, $value, $parameters, $validator) { $validator->addReplacer('after_or_null_epoch', function($message, $attribute, $rule, $parameters) use ($validator) { @@ -331,7 +414,6 @@ class AppServiceProvider extends ServiceProvider return true; }); - Validator::extend('valid_epoch', function($attribute, $value, $parameters, $validator) { $validator->addReplacer('valid_epoch', function($message, $attribute, $rule, $parameters) use ($validator) { @@ -350,7 +432,6 @@ class AppServiceProvider extends ServiceProvider return true; }); - Validator::extend('geo_latitude', function($attribute, $value, $parameters, $validator) { $validator->addReplacer('geo_latitude', function($message, $attribute, $rule, $parameters) use ($validator) { @@ -372,286 +453,47 @@ class AppServiceProvider extends ServiceProvider return !($value < -180.00 || $value > 180.00); }); - Validator::extend('country_iso_alpha2_code', function($attribute, $value, $parameters, $validator) - { - $countries = - [ - 'AF' => 'Afghanistan', - 'AX' => 'Aland Islands', - 'AL' => 'Albania', - 'DZ' => 'Algeria', - 'AS' => 'American Samoa', - 'AD' => 'Andorra', - 'AO' => 'Angola', - 'AI' => 'Anguilla', - 'AQ' => 'Antarctica', - 'AG' => 'Antigua And Barbuda', - 'AR' => 'Argentina', - 'AM' => 'Armenia', - 'AW' => 'Aruba', - 'AU' => 'Australia', - 'AT' => 'Austria', - 'AZ' => 'Azerbaijan', - 'BS' => 'Bahamas', - 'BH' => 'Bahrain', - 'BD' => 'Bangladesh', - 'BB' => 'Barbados', - 'BY' => 'Belarus', - 'BE' => 'Belgium', - 'BZ' => 'Belize', - 'BJ' => 'Benin', - 'BM' => 'Bermuda', - 'BT' => 'Bhutan', - 'BO' => 'Bolivia', - 'BA' => 'Bosnia And Herzegovina', - 'BW' => 'Botswana', - 'BV' => 'Bouvet Island', - 'BR' => 'Brazil', - 'IO' => 'British Indian Ocean Territory', - 'BN' => 'Brunei Darussalam', - 'BG' => 'Bulgaria', - 'BF' => 'Burkina Faso', - 'BI' => 'Burundi', - 'KH' => 'Cambodia', - 'CM' => 'Cameroon', - 'CA' => 'Canada', - 'CV' => 'Cape Verde', - 'KY' => 'Cayman Islands', - 'CF' => 'Central African Republic', - 'TD' => 'Chad', - 'CL' => 'Chile', - 'CN' => 'China', - 'CX' => 'Christmas Island', - 'CC' => 'Cocos (Keeling) Islands', - 'CO' => 'Colombia', - 'KM' => 'Comoros', - 'CG' => 'Congo', - 'CD' => 'Congo, Democratic Republic', - 'CK' => 'Cook Islands', - 'CR' => 'Costa Rica', - 'CI' => 'Cote D\'Ivoire', - 'HR' => 'Croatia', - 'CU' => 'Cuba', - 'CY' => 'Cyprus', - 'CZ' => 'Czech Republic', - 'DK' => 'Denmark', - 'DJ' => 'Djibouti', - 'DM' => 'Dominica', - 'DO' => 'Dominican Republic', - 'EC' => 'Ecuador', - 'EG' => 'Egypt', - 'SV' => 'El Salvador', - 'GQ' => 'Equatorial Guinea', - 'ER' => 'Eritrea', - 'EE' => 'Estonia', - 'ET' => 'Ethiopia', - 'FK' => 'Falkland Islands (Malvinas)', - 'FO' => 'Faroe Islands', - 'FJ' => 'Fiji', - 'FI' => 'Finland', - 'FR' => 'France', - 'GF' => 'French Guiana', - 'PF' => 'French Polynesia', - 'TF' => 'French Southern Territories', - 'GA' => 'Gabon', - 'GM' => 'Gambia', - 'GE' => 'Georgia', - 'DE' => 'Germany', - 'GH' => 'Ghana', - 'GI' => 'Gibraltar', - 'GR' => 'Greece', - 'GL' => 'Greenland', - 'GD' => 'Grenada', - 'GP' => 'Guadeloupe', - 'GU' => 'Guam', - 'GT' => 'Guatemala', - 'GG' => 'Guernsey', - 'GN' => 'Guinea', - 'GW' => 'Guinea-Bissau', - 'GY' => 'Guyana', - 'HT' => 'Haiti', - 'HM' => 'Heard Island & Mcdonald Islands', - 'VA' => 'Holy See (Vatican City State)', - 'HN' => 'Honduras', - 'HK' => 'Hong Kong', - 'HU' => 'Hungary', - 'IS' => 'Iceland', - 'IN' => 'India', - 'ID' => 'Indonesia', - 'IR' => 'Iran, Islamic Republic Of', - 'IQ' => 'Iraq', - 'IE' => 'Ireland', - 'IM' => 'Isle Of Man', - 'IL' => 'Israel', - 'IT' => 'Italy', - 'JM' => 'Jamaica', - 'JP' => 'Japan', - 'JE' => 'Jersey', - 'JO' => 'Jordan', - 'KZ' => 'Kazakhstan', - 'KE' => 'Kenya', - 'KI' => 'Kiribati', - 'KR' => 'Korea', - 'KW' => 'Kuwait', - 'KG' => 'Kyrgyzstan', - 'LA' => 'Lao People\'s Democratic Republic', - 'LV' => 'Latvia', - 'LB' => 'Lebanon', - 'LS' => 'Lesotho', - 'LR' => 'Liberia', - 'LY' => 'Libyan Arab Jamahiriya', - 'LI' => 'Liechtenstein', - 'LT' => 'Lithuania', - 'LU' => 'Luxembourg', - 'MO' => 'Macao', - 'MK' => 'Macedonia', - 'MG' => 'Madagascar', - 'MW' => 'Malawi', - 'MY' => 'Malaysia', - 'MV' => 'Maldives', - 'ML' => 'Mali', - 'MT' => 'Malta', - 'MH' => 'Marshall Islands', - 'MQ' => 'Martinique', - 'MR' => 'Mauritania', - 'MU' => 'Mauritius', - 'YT' => 'Mayotte', - 'MX' => 'Mexico', - 'FM' => 'Micronesia, Federated States Of', - 'MD' => 'Moldova', - 'MC' => 'Monaco', - 'MN' => 'Mongolia', - 'ME' => 'Montenegro', - 'MS' => 'Montserrat', - 'MA' => 'Morocco', - 'MZ' => 'Mozambique', - 'MM' => 'Myanmar', - 'NA' => 'Namibia', - 'NR' => 'Nauru', - 'NP' => 'Nepal', - 'NL' => 'Netherlands', - 'AN' => 'Netherlands Antilles', - 'NC' => 'New Caledonia', - 'NZ' => 'New Zealand', - 'NI' => 'Nicaragua', - 'NE' => 'Niger', - 'NG' => 'Nigeria', - 'NU' => 'Niue', - 'NF' => 'Norfolk Island', - 'MP' => 'Northern Mariana Islands', - 'NO' => 'Norway', - 'OM' => 'Oman', - 'PK' => 'Pakistan', - 'PW' => 'Palau', - 'PS' => 'Palestinian Territory, Occupied', - 'PA' => 'Panama', - 'PG' => 'Papua New Guinea', - 'PY' => 'Paraguay', - 'PE' => 'Peru', - 'PH' => 'Philippines', - 'PN' => 'Pitcairn', - 'PL' => 'Poland', - 'PT' => 'Portugal', - 'PR' => 'Puerto Rico', - 'QA' => 'Qatar', - 'RE' => 'Reunion', - 'RO' => 'Romania', - 'RU' => 'Russian Federation', - 'RW' => 'Rwanda', - 'BL' => 'Saint Barthelemy', - 'SH' => 'Saint Helena', - 'KN' => 'Saint Kitts And Nevis', - 'LC' => 'Saint Lucia', - 'MF' => 'Saint Martin', - 'PM' => 'Saint Pierre And Miquelon', - 'VC' => 'Saint Vincent And Grenadines', - 'WS' => 'Samoa', - 'SM' => 'San Marino', - 'ST' => 'Sao Tome And Principe', - 'SA' => 'Saudi Arabia', - 'SN' => 'Senegal', - 'RS' => 'Serbia', - 'SC' => 'Seychelles', - 'SL' => 'Sierra Leone', - 'SG' => 'Singapore', - 'SK' => 'Slovakia', - 'SI' => 'Slovenia', - 'SB' => 'Solomon Islands', - 'SO' => 'Somalia', - 'ZA' => 'South Africa', - 'GS' => 'South Georgia And Sandwich Isl.', - 'ES' => 'Spain', - 'LK' => 'Sri Lanka', - 'SD' => 'Sudan', - 'SR' => 'Suriname', - 'SJ' => 'Svalbard And Jan Mayen', - 'SZ' => 'Swaziland', - 'SE' => 'Sweden', - 'CH' => 'Switzerland', - 'SY' => 'Syrian Arab Republic', - 'TW' => 'Taiwan', - 'TJ' => 'Tajikistan', - 'TZ' => 'Tanzania', - 'TH' => 'Thailand', - 'TL' => 'Timor-Leste', - 'TG' => 'Togo', - 'TK' => 'Tokelau', - 'TO' => 'Tonga', - 'TT' => 'Trinidad And Tobago', - 'TN' => 'Tunisia', - 'TR' => 'Turkey', - 'TM' => 'Turkmenistan', - 'TC' => 'Turks And Caicos Islands', - 'TV' => 'Tuvalu', - 'UG' => 'Uganda', - 'UA' => 'Ukraine', - 'AE' => 'United Arab Emirates', - 'GB' => 'United Kingdom', - 'US' => 'United States', - 'UM' => 'United States Outlying Islands', - 'UY' => 'Uruguay', - 'UZ' => 'Uzbekistan', - 'VU' => 'Vanuatu', - 'VE' => 'Venezuela', - 'VN' => 'Viet Nam', - 'VG' => 'Virgin Islands, British', - 'VI' => 'Virgin Islands, U.S.', - 'WF' => 'Wallis And Futuna', - 'EH' => 'Western Sahara', - 'YE' => 'Yemen', - 'ZM' => 'Zambia', - 'ZW' => 'Zimbabwe', - ]; - + Validator::extend('country_iso_alpha2_code', function($attribute, $value, $parameters, $validator){ $validator->addReplacer('country_iso_alpha2_code', function($message, $attribute, $rule, $parameters) use ($validator) { return sprintf("%s should be a valid country iso code", $attribute); }); if(!is_string($value)) return false; $value = trim($value); - return isset($countries[$value]); + + $isoCodes = new IsoCodesFactory(); + $countries = $isoCodes->getCountries(); + $country = $countries->getByAlpha2($value); + + return !is_null($country); }); Validator::extend('currency_iso', function($attribute, $value, $parameters, $validator) { - $currencies = - [ - 'USD' => 'USD', - 'EUR' => 'EUR', - 'GBP' => 'GBP' - ]; $validator->addReplacer('currency_iso', function($message, $attribute, $rule, $parameters) use ($validator) { return sprintf("%s should be a valid currency iso 4217 code", $attribute); }); if(!is_string($value)) return false; $value = trim($value); - return isset($currencies[$value]); + + $isoCodes = new IsoCodesFactory(); + + $currencies = $isoCodes->getCurrencies(); + + $currency = $currencies->getByLetterCode($value); + + return !is_null($currency); + }); Validator::extend('greater_than', function ($attribute, $value, $otherValue) { return intval($value) > intval($otherValue[0]); }); + Validator::extend('greater_than_or_equal', function ($attribute, $value, $otherValue) { + return intval($value) >= intval($otherValue[0]); + }); + Validator::extend('rsvp_answer_dto_array', function($attribute, $value, $parameters, $validator) { $validator->addReplacer('rsvp_answer_dto_array', function($message, $attribute, $rule, $parameters) use ($validator) { @@ -676,6 +518,18 @@ class AppServiceProvider extends ServiceProvider } return true; }); + + Validator::extend('megabyte_aligned', function($attribute, $value, $parameters, $validator){ + $validator->addReplacer('megabyte_aligned', function($message, $attribute, $rule, $parameters) use ($validator) { + return sprintf("%s should be aligned to 1024 KB", $attribute); + }); + + $value = intval($value); + + if($value <= 0) return false; + + return ($value % 1024 == 0); + }); } /** diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 186d074d..4d3d794c 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -11,11 +11,20 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\EntityPersisters\AdminSummitEventActionSyncWorkRequestPersister; use App\EntityPersisters\AdminSummitLocationActionSyncWorkRequestPersister; use App\EntityPersisters\EntityEventPersister; +use App\Events\NewMember; +use App\Events\OrderDeleted; +use App\Events\PaymentSummitRegistrationOrderConfirmed; +use App\Events\RequestedSummitAttendeeTicketRefund; +use App\Events\RequestedSummitOrderRefund; use App\Events\RSVPCreated; use App\Events\RSVPUpdated; +use App\Events\SummitAttendeeTicketRefundAccepted; +use App\Events\SummitOrderCanceled; +use App\Events\SummitOrderRefundAccepted; use App\Factories\CalendarAdminActionSyncWorkRequest\AdminSummitLocationActionSyncWorkRequestFactory; use App\Factories\CalendarAdminActionSyncWorkRequest\SummitEventDeletedCalendarSyncWorkRequestFactory; use App\Factories\CalendarAdminActionSyncWorkRequest\SummitEventUpdatedCalendarSyncWorkRequestFactory; @@ -40,22 +49,38 @@ use App\Factories\EntityEvents\SummitEventUpdatedEntityEventFactory; use App\Factories\EntityEvents\SummitTicketTypeActionEntityEventFactory; use App\Factories\EntityEvents\TrackActionEntityEventFactory; use App\Factories\EntityEvents\TrackGroupActionActionEntityEventFactory; -use App\Mail\BookableRoomReservationCanceledEmail; -use App\Mail\BookableRoomReservationCreatedEmail; -use App\Mail\BookableRoomReservationPaymentConfirmedEmail; -use App\Mail\BookableRoomReservationRefundAcceptedEmail; -use App\Mail\BookableRoomReservationRefundRequestedAdminEmail; -use App\Mail\BookableRoomReservationRefundRequestedOwnerEmail; -use App\Mail\Schedule\RSVPRegularSeatMail; -use App\Mail\Schedule\RSVPWaitListSeatMail; +use App\Jobs\CompensatePromoCodes; +use App\Jobs\CompensateTickets; +use App\Jobs\Emails\Registration\Refunds\SummitOrderRefundRequestAdmin; +use App\Jobs\Emails\Registration\Refunds\SummitOrderRefundRequestOwner; +use App\Jobs\Emails\Registration\Refunds\SummitTicketRefundAccepted; +use App\Jobs\Emails\Registration\Refunds\SummitTicketRefundRequestAdmin; +use App\Jobs\Emails\Registration\Refunds\SummitTicketRefundRequestOwner; +use App\Jobs\Emails\RevocationTicketEmail; +use App\Jobs\NewMemberAssocSummitOrders; +use App\Jobs\ProcessOrderRefundRequest; +use App\Jobs\ProcessSummitOrderPaymentConfirmation; +use App\Jobs\ProcessTicketRefundRequest; +use App\Jobs\Emails\BookableRooms\BookableRoomReservationCreatedEmail; +use App\Jobs\Emails\BookableRooms\BookableRoomReservationPaymentConfirmedEmail; +use App\Jobs\Emails\BookableRooms\BookableRoomReservationRefundAcceptedEmail; +use App\Jobs\Emails\BookableRooms\BookableRoomReservationRefundRequestedAdminEmail; +use App\Jobs\Emails\BookableRooms\BookableRoomReservationRefundRequestedOwnerEmail; +use App\Jobs\Emails\BookableRooms\BookableRoomReservationCanceledEmail; +use App\Jobs\Emails\Schedule\RSVPRegularSeatMail; +use App\Jobs\Emails\Schedule\RSVPWaitListSeatMail; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; -use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\App; +use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Mail; use LaravelDoctrine\ORM\Facades\EntityManager; -use models\main\Member; use models\summit\RSVP; +use models\summit\Summit; +use models\summit\SummitAttendeeTicket; +use models\summit\SummitOrder; use models\summit\SummitRoomReservation; + /** * Class EventServiceProvider * @package App\Providers @@ -88,7 +113,7 @@ final class EventServiceProvider extends ServiceProvider Event::listen(\Illuminate\Mail\Events\MessageSending::class, function($event){ $devEmail = env('DEV_EMAIL_TO'); - if((App::environment() === 'dev' || App::environment() === 'testing') && !empty($devEmail)){ + if(in_array(App::environment(), ['local','dev','testing']) && !empty($devEmail)){ $event->message->setTo(explode(",", $devEmail)); } return true; @@ -262,7 +287,6 @@ final class EventServiceProvider extends ServiceProvider Event::listen(\App\Events\FloorUpdated::class, function($event) { EntityEventPersister::persist(FloorActionEntityEventFactory::build($event, 'UPDATE')); - }); Event::listen(\App\Events\FloorDeleted::class, function($event) @@ -341,7 +365,7 @@ final class EventServiceProvider extends ServiceProvider $reservation = $repository->find($event->getReservationId()); if(is_null($reservation) || ! $reservation instanceof SummitRoomReservation) return; - Mail::send(new BookableRoomReservationRefundAcceptedEmail($reservation)); + Mail::queue(new BookableRoomReservationRefundAcceptedEmail($reservation)); }); @@ -351,7 +375,7 @@ final class EventServiceProvider extends ServiceProvider $reservation = $repository->find($event->getReservationId()); if(is_null($reservation) || ! $reservation instanceof SummitRoomReservation) return; - Mail::send(new BookableRoomReservationCreatedEmail($reservation)); + BookableRoomReservationCreatedEmail::dispatch($reservation); }); @@ -361,7 +385,7 @@ final class EventServiceProvider extends ServiceProvider $reservation = $repository->find($event->getReservationId()); if(is_null($reservation) || ! $reservation instanceof SummitRoomReservation) return; - Mail::send(new BookableRoomReservationPaymentConfirmedEmail($reservation)); + BookableRoomReservationPaymentConfirmedEmail::dispatch($reservation); }); Event::listen(\App\Events\RequestedBookableRoomReservationRefund::class, function($event) @@ -370,8 +394,8 @@ final class EventServiceProvider extends ServiceProvider $reservation = $repository->find($event->getReservationId()); if(is_null($reservation) || ! $reservation instanceof SummitRoomReservation) return; - Mail::send(new BookableRoomReservationRefundRequestedAdminEmail($reservation)); - Mail::send(new BookableRoomReservationRefundRequestedOwnerEmail($reservation)); + BookableRoomReservationRefundRequestedAdminEmail::dispatch($reservation); + BookableRoomReservationRefundRequestedOwnerEmail::dispatch($reservation); }); Event::listen(\App\Events\BookableRoomReservationCanceled::class, function($event) @@ -379,10 +403,94 @@ final class EventServiceProvider extends ServiceProvider $repository = EntityManager::getRepository(SummitRoomReservation::class); $reservation = $repository->find($event->getReservationId()); if(is_null($reservation) || ! $reservation instanceof SummitRoomReservation) return; - Mail::send(new BookableRoomReservationCanceledEmail($reservation)); + BookableRoomReservationCanceledEmail::dispatch($reservation); }); - Event::listen(RSVPCreated::class, function($event){ + // registration + + Event::listen(SummitOrderCanceled::class, function($event){ + if(!$event instanceof SummitOrderCanceled) return; + + $repository = EntityManager::getRepository(SummitOrder::class); + $order = $repository->find($event->getOrderId()); + if(is_null($order) || ! $order instanceof SummitOrder) return; + + Log::debug(sprintf("EventServiceProvider::SummitOrderCanceled order id %s", $order->getId())); + /* + * removed for now + * if($event->shouldSendEmail()) + Mail::queue(new SummitOrderCanceledEmail($order)); + */ + // compensate tickets types qty + + foreach ($event->getTicketsToReturn() as $ticket_type_id => $qty){ + Log::debug(sprintf("EventServiceProvider::SummitOrderCanceled: firing CompensateTickets ticket_type_id %s qty %s", $ticket_type_id, $qty)); + CompensateTickets::dispatch($ticket_type_id, $qty); + } + // compensate promo codes usages + + foreach ($event->getPromoCodesToReturn() as $code => $qty){ + Log::debug(sprintf("EventServiceProvider::SummitOrderCanceled: firing CompensatePromoCodes code %s qty %s", $code, $qty)); + CompensatePromoCodes::dispatch($order->getSummit(), $code, $qty); + } + }); + + Event::listen(OrderDeleted::class, function($event){ + if(!$event instanceof OrderDeleted) return; + + // compensate tickets types qty + + Log::debug(sprintf("EventServiceProvider::OrderDeleted id %s", $event->getOrderId())); + + $repository = EntityManager::getRepository(Summit::class); + $summit = $repository->find($event->getSummitId()); + if(is_null($summit) || ! $summit instanceof Summit) return; + + foreach ($event->getTicketsToReturn() as $ticket_type_id => $qty){ + Log::debug(sprintf("EventServiceProvider::OrderDeleted: firing CompensateTickets ticket_type_id %s qty %s", $ticket_type_id, $qty)); + CompensateTickets::dispatch($ticket_type_id, $qty); + } + // compensate promo codes usages + + foreach ($event->getPromoCodesToReturn() as $code => $qty){ + Log::debug(sprintf("EventServiceProvider::OrderDeleted: firing CompensatePromoCodes code %s qty %s", $code, $qty)); + CompensatePromoCodes::dispatch($summit, $code, $qty); + } + }); + + Event::listen(PaymentSummitRegistrationOrderConfirmed::class, function($event){ + if(!$event instanceof PaymentSummitRegistrationOrderConfirmed) return; + $order_id = $event->getOrderId(); + Log::debug(sprintf("EventServiceProvider::PaymentSummitRegistrationOrderConfirmed: firing ProcessSummitOrderPaymentConfirmation for order id %s", $order_id)); + ProcessSummitOrderPaymentConfirmation::dispatch($order_id)->delay(now()->addMinutes(1)); + }); + + Event::listen(NewMember::class, function($event){ + if(!$event instanceof NewMember) return; + Log::debug(sprintf("EventServiceProvider::NewMember - firing NewMemberAssocSummitOrders member id %s", $event->getMemberId())); + NewMemberAssocSummitOrders::dispatchNow($event->getMemberId()); + }); + + Event::Listen(RequestedSummitOrderRefund::class, function($event){ + + if(!$event instanceof RequestedSummitOrderRefund) return; + + $repository = EntityManager::getRepository(SummitOrder::class); + $order = $repository->find($event->getOrderId()); + if(is_null($order) || ! $order instanceof SummitOrder) return; + + Log::debug(sprintf("EventServiceProvider::RequestedSummitOrderRefund: dispatching job ProcessOrderRefundRequest for order id %s", $event->getOrderId())); + + SummitOrderRefundRequestAdmin::dispatch($order); + SummitOrderRefundRequestOwner::dispatch($order); + + ProcessOrderRefundRequest::dispatch( + $event->getOrderId(), + $event->getDaysBeforeEventStarts() + ); + }); + + Event::listen(RSVPCreated::class, function($event){ if(!$event instanceof RSVPCreated) return; $rsvp_id = $event->getRsvpId(); @@ -393,10 +501,10 @@ final class EventServiceProvider extends ServiceProvider if(is_null($rsvp) || ! $rsvp instanceof RSVP) return; if($rsvp->getSeatType() == RSVP::SeatTypeRegular) - Mail::send(new RSVPRegularSeatMail($rsvp)); + RSVPRegularSeatMail::dispatch($rsvp); if($rsvp->getSeatType() == RSVP::SeatTypeWaitList) - Mail::send(new RSVPWaitListSeatMail($rsvp)); + RSVPWaitListSeatMail::dispatch($rsvp); }); Event::listen(RSVPUpdated::class, function($event){ @@ -410,10 +518,91 @@ final class EventServiceProvider extends ServiceProvider if(is_null($rsvp) || ! $rsvp instanceof RSVP) return; if($rsvp->getSeatType() == RSVP::SeatTypeRegular) - Mail::send(new RSVPRegularSeatMail($rsvp)); + RSVPRegularSeatMail::dispatch($rsvp); if($rsvp->getSeatType() == RSVP::SeatTypeWaitList) - Mail::send(new RSVPWaitListSeatMail($rsvp)); + RSVPWaitListSeatMail::dispatch($rsvp); + }); + + Event::Listen(RequestedSummitAttendeeTicketRefund::class, function($event){ + if(!$event instanceof RequestedSummitAttendeeTicketRefund) return; + + $repository = EntityManager::getRepository(SummitAttendeeTicket::class); + $ticket = $repository->find($event->getTicketId()); + if(is_null($ticket) || ! $ticket instanceof SummitAttendeeTicket) return; + + Log::debug(sprintf("EventServiceProvider::RequestedSummitAttendeeTicketRefund: dispatching job ProcessOrderRefundRequest for ticket id %s", $event->getTicketId())); + + SummitTicketRefundRequestAdmin::dispatch($ticket); + SummitTicketRefundRequestOwner::dispatch($ticket); + + ProcessTicketRefundRequest::dispatch($event->getTicketId(), $event->getDaysBeforeEventStarts()); + }); + + Event::listen(SummitAttendeeTicketRefundAccepted::class, function($event){ + // send email to owner and compensate tickets types qty/ promo codes + if(!$event instanceof SummitAttendeeTicketRefundAccepted) return; + + $repository = EntityManager::getRepository(SummitAttendeeTicket::class); + $ticket = $repository->find($event->getTicketId()); + if(is_null($ticket) || ! $ticket instanceof SummitAttendeeTicket) return; + $order = $ticket->getOrder(); + $summit = $order->getSummit(); + Log::debug(sprintf("EventServiceProvider::SummitAttendeeTicketRefundAccepted order id %s ticket number %s", $order->getId(), $ticket->getNumber())); + + SummitTicketRefundAccepted::dispatch($ticket); + + if($ticket->hasOwner()) { + RevocationTicketEmail::dispatch($ticket->getOwner(), $ticket); + } + + // compensate tickets types qty + + foreach ($event->getTicketsToReturn() as $ticket_type_id => $qty){ + Log::debug(sprintf("EventServiceProvider::SummitAttendeeTicketRefundAccepted: firing CompensateTickets ticket_type_id %s qty %s", $ticket_type_id, $qty)); + CompensateTickets::dispatch($ticket_type_id, $qty); + } + // compensate promo codes usages + + foreach ($event->getPromoCodesToReturn() as $code => $qty){ + Log::debug(sprintf("EventServiceProvider::SummitAttendeeTicketRefundAccepted: firing CompensatePromoCodes code %s qty %s", $code, $qty)); + CompensatePromoCodes::dispatch($summit, $code, $qty); + } + }); + + Event::listen(SummitOrderRefundAccepted::class, function($event){ + // send email to owner and compensate tickets types qty/ promo codes + if(!$event instanceof SummitOrderRefundAccepted) return; + + $repository = EntityManager::getRepository(SummitOrder::class); + $order = $repository->find($event->getOrderId()); + + if(is_null($order) || ! $order instanceof SummitOrder) return; + + Log::debug(sprintf("EventServiceProvider::SummitOrderRefundAccepted order id %s", $order->getId())); + + \App\Jobs\Emails\Registration\Refunds\SummitOrderRefundAccepted::dispatch($order); + + foreach ($order->getTickets() as $ticket) { + if ($ticket->hasOwner()) { + RevocationTicketEmail::dispatch($ticket->getOwner(), $ticket); + } + } + + // compensate tickets types qty + + foreach ($event->getTicketsToReturn() as $ticket_type_id => $qty){ + Log::debug(sprintf("EventServiceProvider::SummitOrderRefundAccepted: firing CompensateTickets ticket_type_id %ss qty %s", $ticket_type_id, $qty)); + CompensateTickets::dispatch($ticket_type_id, $qty); + } + + // compensate promo codes usages + + foreach ($event->getPromoCodesToReturn() as $code => $qty){ + Log::debug(sprintf("EventServiceProvider::SummitOrderRefundAccepted: firing CompensatePromoCodes code %s qty %s", $code, $qty)); + CompensatePromoCodes::dispatch($order->getSummit(), $code, $qty); + } + }); } } diff --git a/app/Queue/RabbitMQ/RabbitMQConnector.php b/app/Queue/RabbitMQ/RabbitMQConnector.php new file mode 100644 index 00000000..012c094a --- /dev/null +++ b/app/Queue/RabbitMQ/RabbitMQConnector.php @@ -0,0 +1,133 @@ +dispatcher = $dispatcher; + } + + /** + * Establish a queue connection. + * + * @param array $config + * + * @return RabbitMQQueue + * @throws Exception + */ + public function connect(array $config): Queue + { + $connection = $this->createConnection(Arr::except($config, 'options.queue')); + + $queue = $this->createQueue( + Arr::get($config, 'worker', 'default'), + $connection, + $config['queue'], + Arr::get($config, 'options.queue', []) + ); + + if (! $queue instanceof RabbitMQQueue) { + throw new InvalidArgumentException('Invalid worker.'); + } + + $this->dispatcher->listen(WorkerStopping::class, static function () use ($queue): void { + $queue->close(); + }); + + return $queue; + } + + /** + * @param array $config + * @return AbstractConnection + * @throws Exception + */ + protected function createConnection(array $config): AbstractConnection + { + /** @var AbstractConnection $connection */ + $connection = Arr::get($config, 'connection', AMQPLazyConnection::class); + + // manually disable heartbeat so long-running tasks will not fail + Arr::add($config, 'options.heartbeat', 0); + + return $connection::create_connection( + Arr::shuffle(Arr::get($config, 'hosts', [])), + $this->filter(Arr::get($config, 'options', [])) + ); + } + + /** + * Create a queue for the worker. + * + * @param string $worker + * @param AbstractConnection $connection + * @param string $queue + * @param array $options + * @return RabbitMQQueue|Queue + */ + protected function createQueue(string $worker, AbstractConnection $connection, string $queue, array $options = []) + { + switch ($worker) { + case 'default': + return new RabbitMQQueue($connection, $queue, $options); + default: + return new $worker($connection, $queue, $options); + } + } + + /** + * Recursively filter only null values. + * + * @param array $array + * @return array + */ + private function filter(array $array): array + { + foreach ($array as $index => &$value) { + if (is_array($value)) { + $value = $this->filter($value); + continue; + } + + // If the value is null then remove it. + if ($value === null) { + unset($array[$index]); + continue; + } + } + + return $array; + } +} diff --git a/app/Queue/RabbitMQ/RabbitMQJob.php b/app/Queue/RabbitMQ/RabbitMQJob.php new file mode 100644 index 00000000..9bc96d9f --- /dev/null +++ b/app/Queue/RabbitMQ/RabbitMQJob.php @@ -0,0 +1,176 @@ +container = $container; + $this->rabbitmq = $rabbitmq; + $this->message = $message; + $this->connectionName = $connectionName; + $this->queue = $queue; + $this->decoded = $this->payload(); + } + + /** + * {@inheritdoc} + */ + public function getJobId() + { + return $this->decoded['id'] ?? null; + } + + /** + * {@inheritdoc} + */ + public function getRawBody(): string + { + return $this->message->getBody(); + } + + /** + * {@inheritdoc} + */ + public function attempts(): int + { + if (! $data = $this->getRabbitMQMessageHeaders()) { + return 1; + } + + $laravelAttempts = (int) Arr::get($data, 'laravel.attempts', 0); + + return $laravelAttempts + 1; + } + + /** + * {@inheritdoc} + */ + public function markAsFailed(): void + { + parent::markAsFailed(); + + // We must tel rabbitMQ this Job is failed + // The message must be rejected when the Job marked as failed, in case rabbitMQ wants to do some extra magic. + // like: Death lettering the message to an other exchange/routing-key. + $this->rabbitmq->reject($this); + } + + /** + * {@inheritdoc} + * + * @throws BindingResolutionException + */ + public function delete(): void + { + parent::delete(); + + // When delete is called and the Job was not failed, the message must be acknowledged. + // This is because this is a controlled call by a developer. So the message was handled correct. + if (! $this->failed) { + $this->rabbitmq->ack($this); + } + } + + /** + * Release the job back into the queue. + * + * @param int $delay + * @throws AMQPProtocolChannelException + */ + public function release($delay = 0): void + { + parent::release(); + + // Always create a new message when this Job is released + $this->rabbitmq->laterRaw($delay, $this->message->getBody(), $this->queue, $this->attempts()); + + // Releasing a Job means the message was failed to process. + // Because this Job message is always recreated and pushed as new message, this Job message is correctly handled. + // We must tell rabbitMQ this job message can be removed by acknowledging the message. + $this->rabbitmq->ack($this); + } + + /** + * Get the underlying RabbitMQ connection. + * + * @return RabbitMQQueue + */ + public function getRabbitMQ(): RabbitMQQueue + { + return $this->rabbitmq; + } + + /** + * Get the underlying RabbitMQ message. + * + * @return AMQPMessage + */ + public function getRabbitMQMessage(): AMQPMessage + { + return $this->message; + } + + /** + * Get the headers from the rabbitMQ message. + * + * @return array|null + */ + protected function getRabbitMQMessageHeaders(): ?array + { + /** @var AMQPTable|null $headers */ + if (! $headers = Arr::get($this->message->get_properties(), 'application_headers')) { + return null; + } + + return $headers->getNativeData(); + } +} diff --git a/app/Queue/RabbitMQ/RabbitMQQueue.php b/app/Queue/RabbitMQ/RabbitMQQueue.php new file mode 100644 index 00000000..05f431f2 --- /dev/null +++ b/app/Queue/RabbitMQ/RabbitMQQueue.php @@ -0,0 +1,803 @@ +connection = $connection; + $this->channel = $connection->channel(); + $this->default = $default; + $this->options = $options; + } + + /** + * {@inheritdoc} + * + * @throws AMQPProtocolChannelException + */ + public function size($queue = null): int + { + $queue = $this->getQueue($queue); + + if (! $this->isQueueExists($queue)) { + return 0; + } + + // create a temporary channel, so the main channel will not be closed on exception + $channel = $this->connection->channel(); + [, $size] = $channel->queue_declare($queue, true); + $channel->close(); + + return $size; + } + + /** + * {@inheritdoc} + * + * @throws AMQPProtocolChannelException + */ + public function push($job, $data = '', $queue = null) + { + return $this->pushRaw($this->createPayload($job, $data), $queue, []); + } + + /** + * {@inheritdoc} + * + * @throws AMQPProtocolChannelException + */ + public function pushRaw($payload, $queue = null, array $options = []) + { + [$destination, $exchange, $exchangeType, $attempts] = $this->publishProperties($queue, $options); + + $this->declareDestination($destination, $exchange, $exchangeType); + + [$message, $correlationId] = $this->createMessage($payload, $attempts); + + $this->channel->basic_publish($message, $exchange, $destination, true, false); + + return $correlationId; + } + + /** + * {@inheritdoc} + * + * @throws AMQPProtocolChannelException + */ + public function later($delay, $job, $data = '', $queue = null) + { + return $this->laterRaw( + $delay, + $this->createPayload($job, $data), + $queue + ); + } + + /** + * @param $delay + * @param $payload + * @param null $queue + * @param int $attempts + * @return mixed + * @throws AMQPProtocolChannelException + */ + public function laterRaw($delay, $payload, $queue = null, $attempts = 0) + { + $ttl = $this->secondsUntil($delay) * 1000; + + // When no ttl just publish a new message to the exchange or queue + if ($ttl <= 0) { + return $this->pushRaw($payload, $queue, ['delay' => $delay, 'attempts' => $attempts]); + } + + $destination = $this->getQueue($queue).'.delay.'.$ttl; + + $this->declareQueue($destination, true, false, $this->getDelayQueueArguments($this->getQueue($queue), $ttl)); + + [$message, $correlationId] = $this->createMessage($payload, $attempts); + + // Publish directly on the delayQueue, no need to publish trough an exchange. + $this->channel->basic_publish($message, null, $destination, true, false); + + return $correlationId; + } + + /** + * {@inheritdoc} + * + * @throws AMQPProtocolChannelException + */ + public function bulk($jobs, $data = '', $queue = null): void + { + foreach ((array) $jobs as $job) { + $this->bulkRaw($this->createPayload($job, $data), $queue, ['job' => $job]); + } + + $this->channel->publish_batch(); + } + + /** + * @param string $payload + * @param null $queue + * @param array $options + * @return mixed + * @throws AMQPProtocolChannelException + */ + public function bulkRaw(string $payload, $queue = null, array $options = []) + { + [$destination, $exchange, $exchangeType, $attempts] = $this->publishProperties($queue, $options); + + $this->declareDestination($destination, $exchange, $exchangeType); + + [$message, $correlationId] = $this->createMessage($payload, $attempts); + + $this->channel->batch_basic_publish($message, $exchange, $destination); + + return $correlationId; + } + + /** + * {@inheritdoc} + * + * @throws Exception + */ + public function pop($queue = null) + { + try { + $queue = $this->getQueue($queue); + + /** @var AMQPMessage|null $message */ + if ($message = $this->channel->basic_get($queue)) { + return $this->currentJob = new RabbitMQJob( + $this->container, + $this, + $message, + $this->connectionName, + $queue + ); + } + } + catch(AMQPConnectionClosedException $ex){ + // recovery from closed connection + Log::warning($ex); + try { + usleep(RabbitMQQueue::RECONNECT_WAIT); + $this->connection->reconnect(); + $this->channel = $this->connection->channel(); + } + catch (Exception $ex){ + Log::warning($ex); + } + return null; + } + catch (AMQPProtocolChannelException $exception) { + // If there is not exchange or queue AMQP will throw exception with code 404 + // We need to catch it and return null + + Log::warning($exception); + + if ($exception->amqp_reply_code === 404) { + + Log::warning(sprintf("RabbitMQQueue::pop amqp_reply_code 404 trying reconnect ...")); + // Because of the channel exception the channel was closed and removed. + // We have to open a new channel. Because else the worker(s) are stuck in a loop, without processing. + $this->channel = $this->connection->channel(); + + return null; + } + + throw $exception; + } + + return null; + } + + /** + * @return AbstractConnection + */ + public function getConnection(): AbstractConnection + { + return $this->connection; + } + + /** + * @return AMQPChannel + */ + public function getChannel(): AMQPChannel + { + return $this->channel; + } + + /** + * Gets a queue/destination, by default the queue option set on the connection. + * + * @param null $queue + * @return string + */ + public function getQueue($queue = null) + { + return $queue ?: $this->default; + } + + /** + * Checks if the given exchange already present/defined in RabbitMQ. + * Returns false when when the exchange is missing. + * + * @param string $exchange + * @return bool + * @throws AMQPProtocolChannelException + */ + public function isExchangeExists(string $exchange): bool + { + try { + // create a temporary channel, so the main channel will not be closed on exception + $channel = $this->connection->channel(); + $channel->exchange_declare($exchange, '', true); + $channel->close(); + + return true; + } catch (AMQPProtocolChannelException $exception) { + if ($exception->amqp_reply_code === 404) { + return false; + } + + throw $exception; + } + } + + /** + * Declare a exchange in rabbitMQ, when not already declared. + * + * @param string $name + * @param string $type + * @param bool $durable + * @param bool $autoDelete + * @param array $arguments + * @return void + */ + public function declareExchange(string $name, string $type = AMQPExchangeType::DIRECT, bool $durable = true, bool $autoDelete = false, array $arguments = []): void + { + if ($this->isExchangeDeclared($name)) { + return; + } + + $this->channel->exchange_declare( + $name, + $type, + false, + $durable, + $autoDelete, + false, + true, + new AMQPTable($arguments) + ); + } + + /** + * Delete a exchange from rabbitMQ, only when present in RabbitMQ. + * + * @param string $name + * @param bool $unused + * @return void + * @throws AMQPProtocolChannelException + */ + public function deleteExchange(string $name, bool $unused = false): void + { + if (! $this->isExchangeExists($name)) { + return; + } + + $this->channel->exchange_delete( + $name, + $unused + ); + } + + /** + * Checks if the given queue already present/defined in RabbitMQ. + * Returns false when when the queue is missing. + * + * @param string $name + * @return bool + * @throws AMQPProtocolChannelException + */ + public function isQueueExists(string $name = null): bool + { + try { + Log::debug(sprintf("RabbitMQQueue::isQueueExists %s", $name)); + // create a temporary channel, so the main channel will not be closed on exception + $channel = $this->connection->channel(); + $channel->queue_declare($this->getQueue($name), true); + $channel->close(); + Log::debug(sprintf("RabbitMQQueue::isQueueExists %s exists", $name)); + return true; + } catch (AMQPProtocolChannelException $exception) { + if ($exception->amqp_reply_code === 404) { + Log::debug(sprintf("RabbitMQQueue::isQueueExists %s not found", $name)); + return false; + } + + throw $exception; + } + } + + /** + * Declare a queue in rabbitMQ, when not already declared. + * + * @param string $name + * @param bool $durable + * @param bool $autoDelete + * @param array $arguments + * @return void + */ + public function declareQueue(string $name, bool $durable = true, bool $autoDelete = false, array $arguments = []): void + { + Log::debug(sprintf("RabbitMQQueue::declareQueue %s ", $name)); + if ($this->isQueueDeclared($name)) { + return; + } + + $this->channel->queue_declare( + $name, + false, + $durable, + false, + $autoDelete, + false, + new AMQPTable($arguments) + ); + } + + /** + * Delete a queue from rabbitMQ, only when present in RabbitMQ. + * + * @param string $name + * @param bool $if_unused + * @param bool $if_empty + * @return void + * @throws AMQPProtocolChannelException + */ + public function deleteQueue(string $name, bool $if_unused = false, bool $if_empty = false): void + { + if (! $this->isQueueExists($name)) { + return; + } + + $this->channel->queue_delete($name, $if_unused, $if_empty); + } + + /** + * Bind a queue to an exchange. + * + * @param string $queue + * @param string $exchange + * @param string $routingKey + * @return void + */ + public function bindQueue(string $queue, string $exchange, string $routingKey = ''): void + { + if (in_array( + implode('', compact('queue', 'exchange', 'routingKey')), + $this->boundQueues, + true + )) { + return; + } + + $this->channel->queue_bind($queue, $exchange, $routingKey); + } + + /** + * Purge the queue of messages. + * + * @param string $queue + * @return void + */ + public function purge(string $queue = null): void + { + // create a temporary channel, so the main channel will not be closed on exception + $channel = $this->connection->channel(); + $channel->queue_purge($this->getQueue($queue)); + $channel->close(); + } + + /** + * Acknowledge the message. + * + * @param RabbitMQJob $job + * @return void + */ + public function ack(RabbitMQJob $job): void + { + $this->channel->basic_ack($job->getRabbitMQMessage()->getDeliveryTag()); + } + + /** + * Reject the message. + * + * @param RabbitMQJob $job + * @param bool $requeue + * + * @return void + */ + public function reject(RabbitMQJob $job, bool $requeue = false): void + { + $this->channel->basic_reject($job->getRabbitMQMessage()->getDeliveryTag(), $requeue); + } + + /** + * Create a AMQP message. + * + * @param $payload + * @param int $attempts + * @return array + */ + protected function createMessage($payload, int $attempts = 0): array + { + $properties = [ + 'content_type' => 'application/json', + 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT, + ]; + + if ($correlationId = json_decode($payload, true)['id'] ?? null) { + $properties['correlation_id'] = $correlationId; + } + + if ($this->isPrioritizeDelayed()) { + $properties['priority'] = $attempts; + } + + $message = new AMQPMessage($payload, $properties); + + $message->set('application_headers', new AMQPTable([ + 'laravel' => [ + 'attempts' => $attempts, + ], + ])); + + return [ + $message, + $correlationId, + ]; + } + + /** + * Create a payload array from the given job and data. + * + * @param object|string $job + * @param string $data + * @return array + */ + protected function createPayloadArray($job, $data = '') + { + return array_merge(parent::createPayloadArray($job, $data), [ + 'id' => $this->getRandomId(), + ]); + } + + /** + * Get a random ID string. + * + * @return string + */ + protected function getRandomId(): string + { + return Str::random(32); + } + + /** + * Close the connection to RabbitMQ. + * + * @return void + * @throws Exception + */ + public function close(): void + { + if ($this->currentJob && ! $this->currentJob->isDeletedOrReleased()) { + $this->reject($this->currentJob, true); + } + + try { + $this->connection->close(); + } catch (ErrorException $exception) { + // Ignore the exception + } + } + + /** + * Get the Queue arguments. + * + * @param string $destination + * @return array + */ + protected function getQueueArguments(string $destination): array + { + $arguments = []; + + // Messages without a priority property are treated as if their priority were 0. + // Messages with a priority which is higher than the queue's maximum, are treated as if they were + // published with the maximum priority. + if ($this->isPrioritizeDelayed()) { + $arguments['x-max-priority'] = $this->getQueueMaxPriority(); + } + + if ($this->isRerouteFailed()) { + $arguments['x-dead-letter-exchange'] = $this->getFailedExchange() ?? ''; + $arguments['x-dead-letter-routing-key'] = $this->getFailedRoutingKey($destination); + } + + return $arguments; + } + + /** + * Get the Delay queue arguments. + * + * @param string $destination + * @param int $ttl + * @return array + */ + protected function getDelayQueueArguments(string $destination, int $ttl): array + { + return [ + 'x-dead-letter-exchange' => $this->getExchange() ?? '', + 'x-dead-letter-routing-key' => $this->getRoutingKey($destination), + 'x-message-ttl' => $ttl, + 'x-expires' => $ttl * 2, + ]; + } + + /** + * Returns &true;, if delayed messages should be prioritized. + * + * @return bool + */ + protected function isPrioritizeDelayed(): bool + { + return boolval(Arr::get($this->options, 'prioritize_delayed') ?: false); + } + + /** + * Returns a integer with a default of '2' for when using prioritization on delayed messages. + * If priority queues are desired, we recommend using between 1 and 10. + * Using more priority layers, will consume more CPU resources and would affect runtimes. + * + * @see https://www.rabbitmq.com/priority.html + * @return int + */ + protected function getQueueMaxPriority(): int + { + return intval(Arr::get($this->options, 'queue_max_priority') ?: 2); + } + + /** + * Get the exchange name, or &null; as default value. + * + * @param string $exchange + * @return string|null + */ + protected function getExchange(string $exchange = null): ?string + { + return $exchange ?: Arr::get($this->options, 'exchange') ?: null; + } + + /** + * Get the routing-key for when you use exchanges + * The default routing-key is the given destination. + * + * @param string $destination + * @return string + */ + protected function getRoutingKey(string $destination): string + { + return ltrim(sprintf(Arr::get($this->options, 'exchange_routing_key') ?: '%s', $destination), '.'); + } + + /** + * Get the exchangeType, or AMQPExchangeType::DIRECT as default. + * + * @param string|null $type + * @return string + */ + protected function getExchangeType(?string $type = null): string + { + return @constant(AMQPExchangeType::class.'::'.Str::upper($type ?: Arr::get($this->options, 'exchange_type') ?: 'direct')) ?: AMQPExchangeType::DIRECT; + } + + /** + * Returns &true;, if failed messages should be rerouted. + * + * @return bool + */ + protected function isRerouteFailed(): bool + { + return boolval(Arr::get($this->options, 'reroute_failed') ?: false); + } + + /** + * Get the exchange for failed messages. + * + * @param string|null $exchange + * @return string|null + */ + protected function getFailedExchange(string $exchange = null): ?string + { + return $exchange ?: Arr::get($this->options, 'failed_exchange') ?: null; + } + + /** + * Get the routing-key for failed messages + * The default routing-key is the given destination substituted by '.failed'. + * + * @param string $destination + * @return string + */ + protected function getFailedRoutingKey(string $destination): string + { + return ltrim(sprintf(Arr::get($this->options, 'failed_routing_key') ?: '%s.failed', $destination), '.'); + } + + /** + * Checks if the exchange was already declared. + * + * @param string $name + * @return bool + */ + protected function isExchangeDeclared(string $name): bool + { + return in_array($name, $this->exchanges, true); + } + + /** + * Checks if the queue was already declared. + * + * @param string $name + * @return bool + */ + protected function isQueueDeclared(string $name): bool + { + return in_array($name, $this->queues, true); + } + + /** + * Declare the destination when necessary. + * + * @param string $destination + * @param string|null $exchange + * @param string|null $exchangeType + * @return void + * @throws AMQPProtocolChannelException + */ + protected function declareDestination(string $destination, ?string $exchange = null, string $exchangeType = AMQPExchangeType::DIRECT): void + { + // When a exchange is provided and no exchange is present in RabbitMQ, create an exchange. + if ($exchange && ! $this->isExchangeExists($exchange)) { + $this->declareExchange($exchange, $exchangeType); + } + + // When a exchange is provided, just return. + if ($exchange) { + return; + } + + // When the queue already exists, just return. + if ($this->isQueueExists($destination)) { + return; + } + + // Create a queue for amq.direct publishing. + $this->declareQueue($destination, true, false, $this->getQueueArguments($destination)); + } + + /** + * Determine all publish properties. + * + * @param $queue + * @param array $options + * @return array + */ + protected function publishProperties($queue, array $options = []): array + { + $queue = $this->getQueue($queue); + $attempts = Arr::get($options, 'attempts') ?: 0; + + $destination = $this->getRoutingKey($queue); + $exchange = $this->getExchange(); + $exchangeType = $this->getExchangeType(); + + return [$destination, $exchange, $exchangeType, $attempts]; + } +} diff --git a/app/Queue/RabbitMQServiceProvider.php b/app/Queue/RabbitMQServiceProvider.php new file mode 100644 index 00000000..3903f8a6 --- /dev/null +++ b/app/Queue/RabbitMQServiceProvider.php @@ -0,0 +1,48 @@ +app['queue']; + + $queue->addConnector('rabbitmq', function () { + return new RabbitMQConnector($this->app['events']); + }); + } +} \ No newline at end of file diff --git a/app/Repositories/ConfigDoctrineRepository.php b/app/Repositories/ConfigDoctrineRepository.php index 0a79470a..0e144794 100644 --- a/app/Repositories/ConfigDoctrineRepository.php +++ b/app/Repositories/ConfigDoctrineRepository.php @@ -14,6 +14,7 @@ use App\Models\ResourceServer\ResourceServerEntity; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\QueryBuilder; use LaravelDoctrine\ORM\Facades\Registry; /** * Class ConfigDoctrineRepository @@ -32,4 +33,22 @@ abstract class ConfigDoctrineRepository extends DoctrineRepository $this->manager_name = ResourceServerEntity::EntityManager; parent::__construct(Registry::getManager($this->manager_name), $class); } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraFilters(QueryBuilder $query) + { + return $query; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query) + { + return $query; + } } \ No newline at end of file diff --git a/app/Repositories/DoctrineRepository.php b/app/Repositories/DoctrineRepository.php index e9a16fdf..e3f2d1b3 100644 --- a/app/Repositories/DoctrineRepository.php +++ b/app/Repositories/DoctrineRepository.php @@ -38,6 +38,7 @@ abstract class DoctrineRepository extends EntityRepository implements IBaseRepos * @var string */ protected $manager_name; + /** * @return EntityManager */ @@ -111,6 +112,12 @@ abstract class DoctrineRepository extends EntityRepository implements IBaseRepos */ protected abstract function applyExtraFilters(QueryBuilder $query); + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected abstract function applyExtraJoins(QueryBuilder $query); + /** * @param PagingInfo $paging_info * @param Filter|null $filter @@ -124,6 +131,8 @@ abstract class DoctrineRepository extends EntityRepository implements IBaseRepos ->select("e") ->from($this->getBaseEntity(), "e"); + $query = $this->applyExtraJoins($query); + $query = $this->applyExtraFilters($query); if(!is_null($filter)){ @@ -155,6 +164,39 @@ abstract class DoctrineRepository extends EntityRepository implements IBaseRepos ); } + /** + * @param PagingInfo $paging_info + * @param Filter|null $filter + * @param Order|null $order + * @return array + */ + public function getAllIdsByPage(PagingInfo $paging_info, Filter $filter = null, Order $order = null):array { + + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e.id") + ->from($this->getBaseEntity(), "e"); + + $query = $this->applyExtraJoins($query); + + $query = $this->applyExtraFilters($query); + + if(!is_null($filter)){ + $filter->apply2Query($query, $this->getFilterMappings()); + } + + if(!is_null($order)){ + $order->apply2Query($query, $this->getOrderMappings()); + } + + $query = $query + ->setFirstResult($paging_info->getOffset()) + ->setMaxResults($paging_info->getPerPage()); + + $res = $query->getQuery()->getArrayResult(); + return array_column($res, 'id'); + } + /** * Creates a new QueryBuilder instance that is prepopulated for this entity name. * @@ -301,6 +343,4 @@ abstract class DoctrineRepository extends EntityRepository implements IBaseRepos return new LazyCriteriaCollection($persister, $criteria); } - - -} +} \ No newline at end of file diff --git a/app/Repositories/Main/DoctrineCompanyRepository.php b/app/Repositories/Main/DoctrineCompanyRepository.php index 4535ba7d..3ccd5a22 100644 --- a/app/Repositories/Main/DoctrineCompanyRepository.php +++ b/app/Repositories/Main/DoctrineCompanyRepository.php @@ -52,4 +52,13 @@ final class DoctrineCompanyRepository { return Company::class; } + + /** + * @param string $name + * @return Company|null + */ + public function getByName(string $name): ?Company + { + return $this->findOneBy(['name' => trim($name)]); + } } \ No newline at end of file diff --git a/app/Repositories/Main/DoctrineGroupRepository.php b/app/Repositories/Main/DoctrineGroupRepository.php index 36e427b3..b2e1fe3d 100644 --- a/app/Repositories/Main/DoctrineGroupRepository.php +++ b/app/Repositories/Main/DoctrineGroupRepository.php @@ -54,7 +54,6 @@ final class DoctrineGroupRepository return Group::class; } - /** * @param string $slug * @return Group|null diff --git a/app/Repositories/Main/DoctrineSummitAdministratorPermissionGroupRepository.php b/app/Repositories/Main/DoctrineSummitAdministratorPermissionGroupRepository.php new file mode 100644 index 00000000..a88bca31 --- /dev/null +++ b/app/Repositories/Main/DoctrineSummitAdministratorPermissionGroupRepository.php @@ -0,0 +1,81 @@ + 'e.title', + 'member_id' => "m.id :operator :value", + 'summit_id' => "s.id :operator :value", + 'member_first_name' => "m.first_name :operator :value", + 'member_last_name' => "m.last_name :operator :value", + 'member_full_name' => "concat(m.first_name, ' ', m.last_name) :operator :value", + 'member_email' => "m.email :operator :value", + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'created' => 'e.created', + 'title' => "e.title", + ]; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query) + { + $query = $query->join('e.summits', 's') + ->join('e.members', 'm'); + return $query; + } + + /** + * @inheritDoc + */ + protected function getBaseEntity() + { + return SummitAdministratorPermissionGroup::class; + } + + /** + * @inheritDoc + */ + public function getByTitle(string $title): ?SummitAdministratorPermissionGroup + { + return $this->findOneBy(['title' => trim($title)]); + } +} \ No newline at end of file diff --git a/app/Repositories/RepositoriesProvider.php b/app/Repositories/RepositoriesProvider.php index ea5cae51..bedd087c 100644 --- a/app/Repositories/RepositoriesProvider.php +++ b/app/Repositories/RepositoriesProvider.php @@ -11,15 +11,19 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\Models\Foundation\Main\Language; use App\Models\Foundation\Main\Repositories\ILanguageRepository; +use App\Models\Foundation\Main\Repositories\ISummitAdministratorPermissionGroupRepository; use App\Models\Foundation\Summit\Defaults\DefaultSummitEventType; use App\Models\Foundation\Summit\DefaultTrackTagGroup; +use App\Models\Foundation\Summit\EmailFlows\SummitEmailEventFlow; use App\Models\Foundation\Summit\Events\Presentations\TrackQuestions\TrackQuestionTemplate; use App\Models\Foundation\Summit\Events\RSVP\RSVPTemplate; use App\Models\Foundation\Summit\Locations\Banners\SummitLocationBanner; use App\Models\Foundation\Summit\Repositories\IDefaultSummitEventTypeRepository; use App\Models\Foundation\Summit\Repositories\IDefaultTrackTagGroupRepository; +use App\Models\Foundation\Summit\Repositories\IPaymentGatewayProfileRepository; use App\Models\Foundation\Summit\Repositories\IPresentationCategoryGroupRepository; use App\Models\Foundation\Summit\Repositories\IPresentationSpeakerSummitAssistanceConfirmationRequestRepository; use App\Models\Foundation\Summit\Repositories\IRSVPTemplateRepository; @@ -27,12 +31,28 @@ use App\Models\Foundation\Summit\Repositories\ISelectionPlanRepository; use App\Models\Foundation\Summit\Repositories\ISpeakerActiveInvolvementRepository; use App\Models\Foundation\Summit\Repositories\ISpeakerEditPermissionRequestRepository; use App\Models\Foundation\Summit\Repositories\ISpeakerOrganizationalRoleRepository; +use App\Models\Foundation\Summit\Repositories\ISponsorRepository; +use App\Models\Foundation\Summit\Repositories\ISponsorshipTypeRepository; +use App\Models\Foundation\Summit\Repositories\ISummitAccessLevelTypeRepository; +use App\Models\Foundation\Summit\Repositories\ISummitAttendeeBadgePrintRuleRepository; +use App\Models\Foundation\Summit\Repositories\ISummitAttendeeBadgeRepository; +use App\Models\Foundation\Summit\Repositories\ISummitBadgeFeatureTypeRepository; +use App\Models\Foundation\Summit\Repositories\ISummitBadgeTypeRepository; use App\Models\Foundation\Summit\Repositories\ISummitBookableVenueRoomAttributeTypeRepository; use App\Models\Foundation\Summit\Repositories\ISummitBookableVenueRoomAttributeValueRepository; +use App\Models\Foundation\Summit\Repositories\ISummitDocumentRepository; +use App\Models\Foundation\Summit\Repositories\ISummitEmailEventFlowRepository; use App\Models\Foundation\Summit\Repositories\ISummitEventTypeRepository; use App\Models\Foundation\Summit\Repositories\ISummitLocationBannerRepository; use App\Models\Foundation\Summit\Repositories\ISummitLocationRepository; +use App\Models\Foundation\Summit\Repositories\ISummitMediaFileTypeRepository; +use App\Models\Foundation\Summit\Repositories\ISummitMediaUploadTypeRepository; +use App\Models\Foundation\Summit\Repositories\ISummitOrderExtraQuestionTypeRepository; +use App\Models\Foundation\Summit\Repositories\ISummitOrderRepository; +use App\Models\Foundation\Summit\Repositories\ISummitRefundPolicyTypeRepository; +use App\Models\Foundation\Summit\Repositories\ISummitRegistrationInvitationRepository; use App\Models\Foundation\Summit\Repositories\ISummitRoomReservationRepository; +use App\Models\Foundation\Summit\Repositories\ISummitTaxTypeRepository; use App\Models\Foundation\Summit\Repositories\ISummitTrackRepository; use App\Models\Foundation\Summit\Repositories\ITrackQuestionTemplateRepository; use App\Models\Foundation\Summit\Repositories\ITrackTagGroupAllowedTagsRepository; @@ -45,13 +65,15 @@ use Illuminate\Support\ServiceProvider; use LaravelDoctrine\ORM\Facades\EntityManager; use models\main\AssetsSyncRequest; use models\main\Company; -use models\main\EmailCreationRequest; use models\main\File; use models\main\Group; use models\main\IOrganizationRepository; use models\main\Organization; +use models\main\SummitAdministratorPermissionGroup; +use models\summit\ISponsorBadgeScanRepository; use models\summit\ISummitRegistrationPromoCodeRepository; use models\summit\ISummitTicketTypeRepository; +use models\summit\PaymentGatewayProfile; use models\summit\PresentationCategory; use models\summit\PresentationCategoryGroup; use models\summit\PresentationSpeakerSummitAssistanceConfirmationRequest; @@ -59,13 +81,30 @@ use models\summit\SpeakerActiveInvolvement; use models\summit\SpeakerOrganizationalRole; use models\summit\SpeakerRegistrationRequest; use models\summit\SpeakerSummitRegistrationPromoCode; +use models\summit\Sponsor; +use models\summit\SponsorBadgeScan; +use models\summit\SponsorshipType; use models\summit\SummitAbstractLocation; +use models\summit\SummitAccessLevelType; +use models\summit\SummitAttendeeBadge; +use models\summit\SummitAttendeeBadgePrintRule; +use models\summit\SummitBadgeFeatureType; +use models\summit\SummitBadgeType; use models\summit\SummitBookableVenueRoomAttributeType; use models\summit\SummitBookableVenueRoomAttributeValue; +use models\summit\SummitDocument; use models\summit\SummitEventType; +use models\summit\SummitMediaFileType; +use models\summit\SummitMediaUploadType; +use models\summit\SummitOrder; +use models\summit\SummitOrderExtraQuestionType; +use models\summit\SummitRefundPolicyType; +use models\summit\SummitRegistrationInvitation; use models\summit\SummitRegistrationPromoCode; use models\summit\SummitRoomReservation; +use models\summit\SummitTaxType; use models\summit\SummitTicketType; + /** * Class RepositoriesProvider * @package repositories @@ -99,8 +138,6 @@ final class RepositoriesProvider extends ServiceProvider return EntityManager::getRepository(\App\Models\ResourceServer\EndPointRateLimitByIP::class); }); - - App::singleton( 'models\summit\ISummitRepository', function(){ @@ -278,12 +315,6 @@ final class RepositoriesProvider extends ServiceProvider return EntityManager::getRepository(SpeakerSummitRegistrationPromoCode::class); }); - App::singleton( - 'models\main\IEmailCreationRequestRepository', - function(){ - return EntityManager::getRepository(EmailCreationRequest::class); - }); - App::singleton( ISummitTicketTypeRepository::class, function(){ @@ -437,5 +468,138 @@ final class RepositoriesProvider extends ServiceProvider } ); + App::singleton( + ISummitAccessLevelTypeRepository::class, + function(){ + return EntityManager::getRepository(SummitAccessLevelType::class); + } + ); + + App::singleton( + ISummitTaxTypeRepository::class, + function(){ + return EntityManager::getRepository(SummitTaxType::class); + } + ); + + App::singleton( + ISummitBadgeFeatureTypeRepository::class, + function(){ + return EntityManager::getRepository(SummitBadgeFeatureType::class); + } + ); + + App::singleton( + ISummitBadgeTypeRepository::class, + function(){ + return EntityManager::getRepository(SummitBadgeType::class); + } + ); + + App::singleton( + ISponsorRepository::class, + function(){ + return EntityManager::getRepository(Sponsor::class); + } + ); + + App::singleton( + ISponsorshipTypeRepository::class, + function(){ + return EntityManager::getRepository(SponsorshipType::class); + } + ); + + App::singleton( + ISummitRefundPolicyTypeRepository::class, + function(){ + return EntityManager::getRepository(SummitRefundPolicyType::class); + } + ); + + App::singleton( + ISummitOrderExtraQuestionTypeRepository::class, + function(){ + return EntityManager::getRepository(SummitOrderExtraQuestionType::class); + } + ); + + App::singleton( + ISummitOrderRepository::class, + function(){ + return EntityManager::getRepository(SummitOrder::class); + } + ); + + App::singleton( + ISummitAttendeeBadgeRepository::class, + function(){ + return EntityManager::getRepository(SummitAttendeeBadge::class); + } + ); + + App::singleton( + ISponsorBadgeScanRepository::class, + function(){ + return EntityManager::getRepository(SponsorBadgeScan::class); + } + ); + + App::singleton( + ISummitAttendeeBadgePrintRuleRepository::class, + function(){ + return EntityManager::getRepository(SummitAttendeeBadgePrintRule::class); + } + ); + + App::singleton( + IPaymentGatewayProfileRepository::class, + function(){ + return EntityManager::getRepository(PaymentGatewayProfile::class); + } + ); + + App::singleton( + ISummitEmailEventFlowRepository::class, + function(){ + return EntityManager::getRepository(SummitEmailEventFlow::class); + } + ); + + App::singleton( + ISummitDocumentRepository::class, + function(){ + return EntityManager::getRepository(SummitDocument::class); + } + ); + + App::singleton( + ISummitRegistrationInvitationRepository::class, + function(){ + return EntityManager::getRepository(SummitRegistrationInvitation::class); + } + ); + + App::singleton( + ISummitAdministratorPermissionGroupRepository::class, + function(){ + return EntityManager::getRepository(SummitAdministratorPermissionGroup::class); + } + ); + + App::singleton( + ISummitMediaFileTypeRepository::class, + function(){ + return EntityManager::getRepository(SummitMediaFileType::class); + } + ); + + App::singleton( + ISummitMediaUploadTypeRepository::class, + function(){ + return EntityManager::getRepository(SummitMediaUploadType::class); + } + ); + } } \ No newline at end of file diff --git a/app/Repositories/ResourceServer/DoctrineApiEndpointRepository.php b/app/Repositories/ResourceServer/DoctrineApiEndpointRepository.php index 857da2db..b44c9d66 100644 --- a/app/Repositories/ResourceServer/DoctrineApiEndpointRepository.php +++ b/app/Repositories/ResourceServer/DoctrineApiEndpointRepository.php @@ -30,16 +30,6 @@ final class DoctrineApiEndpointRepository implements IApiEndpointRepository { - /** - * Initializes a new EntityRepository. - * - * @param EntityManager $em The EntityManager to use. - * @param ClassMetadata $class The class descriptor. - */ - public function __construct($em, ClassMetadata $class) - { - parent::__construct($em, $class); - } /** * @param string $url * @param string $http_method @@ -90,12 +80,4 @@ final class DoctrineApiEndpointRepository return []; } - /** - * @param QueryBuilder $query - * @return QueryBuilder - */ - protected function applyExtraFilters(QueryBuilder $query) - { - return $query; - } } \ No newline at end of file diff --git a/app/Repositories/ResourceServer/EloquentApiEndpointRepository.php b/app/Repositories/ResourceServer/EloquentApiEndpointRepository.php deleted file mode 100644 index 73e474a2..00000000 --- a/app/Repositories/ResourceServer/EloquentApiEndpointRepository.php +++ /dev/null @@ -1,103 +0,0 @@ -entity = $endpoint; - } - - /** - * @param string $url - * @param string $http_method - * @return IApiEndpoint - */ - public function getApiEndpointByUrlAndMethod($url, $http_method) - { - return $this->entity->Filter(array( - array( - 'name' => 'route', - 'op' => '=', - 'value' => $url - ), - array( - 'name' => 'http_method', - 'op' => '=', - 'value' => $http_method - ) - ))->firstOrFail(); - } - - /** - * @param int $id - * @return IEntity - */ - public function getById($id) - { - // TODO: Implement getById() method. - } - - /** - * @param IEntity $entity - * @return void - */ - public function add($entity) - { - // TODO: Implement add() method. - } - - /** - * @param IEntity $entity - * @return void - */ - public function delete($entity) - { - // TODO: Implement delete() method. - } - - /** - * @return IEntity[] - */ - public function getAll() - { - // TODO: Implement getAll() method. - } - - /** - * @param PagingInfo $paging_info - * @param Filter|null $filter - * @param Order|null $order - * @return PagingResponse - */ - public function getAllByPage(PagingInfo $paging_info, Filter $filter = null, Order $order = null) - { - // TODO: Implement getAllByPage() method. - } -} \ No newline at end of file diff --git a/app/Repositories/SilverStripeDoctrineRepository.php b/app/Repositories/SilverStripeDoctrineRepository.php index b21eab6b..5d2f9ee8 100644 --- a/app/Repositories/SilverStripeDoctrineRepository.php +++ b/app/Repositories/SilverStripeDoctrineRepository.php @@ -60,6 +60,14 @@ abstract class SilverStripeDoctrineRepository extends DoctrineRepository return $query; } + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query){ + return $query; + } + /** * @param string $group_code * @return bool @@ -70,4 +78,10 @@ abstract class SilverStripeDoctrineRepository extends DoctrineRepository if(is_null($member)) return false; return $member->isOnGroup($group_code); } + + public function deleteAll():void{ + foreach ($this->getAll() as $entity){ + $this->delete($entity); + } + } } \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineMemberRepository.php b/app/Repositories/Summit/DoctrineMemberRepository.php index 9dc58cc6..bdc00e91 100644 --- a/app/Repositories/Summit/DoctrineMemberRepository.php +++ b/app/Repositories/Summit/DoctrineMemberRepository.php @@ -32,16 +32,16 @@ final class DoctrineMemberRepository /** * @param string $email - * @return Member + * @return Member|null */ - public function getByEmail($email) + public function getByEmail($email): ?Member { return $this->getEntityManager() ->createQueryBuilder() ->select("e") ->from($this->getBaseEntity(), "e") ->where("e.email = :email") - ->setParameter("email",trim($email)) + ->setParameter("email", strtolower(trim($email))) ->setMaxResults(1) ->getQuery() ->getOneOrNullResult(); @@ -172,4 +172,36 @@ final class DoctrineMemberRepository 'user_external_id' => $external_id ]); } + + public function getByExternalIdExclusiveLock(int $external_id): ?Member{ + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.user_external_id = :user_external_id"); + + $query->setParameter("user_external_id", $external_id); + + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->getOneOrNullResult(); + } + + /** + * @inheritDoc + */ + public function getByEmailExclusiveLock($email): ?Member + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.email = :email"); + + $query->setParameter("email", $email); + + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->getOneOrNullResult(); + } } \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrinePaymentGatewayProfileRepository.php b/app/Repositories/Summit/DoctrinePaymentGatewayProfileRepository.php new file mode 100644 index 00000000..a08d7a12 --- /dev/null +++ b/app/Repositories/Summit/DoctrinePaymentGatewayProfileRepository.php @@ -0,0 +1,57 @@ + 'e.application_type:json_string', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'application_type' => 'e.application_type', + ]; + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrinePresentationSpeakerSummitAssistanceConfirmationRequestRepository.php b/app/Repositories/Summit/DoctrinePresentationSpeakerSummitAssistanceConfirmationRequestRepository.php index a0e8d15c..e39e3cc0 100644 --- a/app/Repositories/Summit/DoctrinePresentationSpeakerSummitAssistanceConfirmationRequestRepository.php +++ b/app/Repositories/Summit/DoctrinePresentationSpeakerSummitAssistanceConfirmationRequestRepository.php @@ -13,6 +13,7 @@ **/ use App\Models\Foundation\Summit\Repositories\IPresentationSpeakerSummitAssistanceConfirmationRequestRepository; use App\Repositories\SilverStripeDoctrineRepository; +use models\summit\PresentationSpeaker; use models\summit\PresentationSpeakerSummitAssistanceConfirmationRequest; use models\summit\Summit; use utils\DoctrineFilterMapping; @@ -129,4 +130,45 @@ final class DoctrinePresentationSpeakerSummitAssistanceConfirmationRequestReposi $data ); } + + /** + * @inheritDoc + */ + public function getBySpeaker(PresentationSpeaker $speaker, Summit $summit): ?PresentationSpeakerSummitAssistanceConfirmationRequest + { + return $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.summit = :summit") + ->andWhere("e.speaker = :speaker") + ->setParameter("speaker", $speaker) + ->setParameter("summit", $summit) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } + + /** + * @param PresentationSpeakerSummitAssistanceConfirmationRequest $request + * @return bool + * @throws \Doctrine\ORM\NonUniqueResultException + */ + public function existByHash(PresentationSpeakerSummitAssistanceConfirmationRequest $request): bool + { + $res = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.summit = :summit") + ->andWhere("e.speaker <> :speaker") + ->andWhere("e.confirmation_hash = :confirmation_hash") + ->setParameter("speaker", $request->getSpeaker()) + ->setParameter("summit", $request->getSummit()) + ->setParameter("confirmation_hash", $request->getConfirmationHash()) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + return !is_null($res); + } } \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSpeakerRepository.php b/app/Repositories/Summit/DoctrineSpeakerRepository.php index 0e881e41..b4f59c2f 100644 --- a/app/Repositories/Summit/DoctrineSpeakerRepository.php +++ b/app/Repositories/Summit/DoctrineSpeakerRepository.php @@ -179,6 +179,7 @@ FROM ( CONCAT(IFNULL(S.FirstName, M.FirstName), ' ', IFNULL(S.LastName, M.Surname)) AS FullName, IFNULL(M.Email,R.Email) AS Email, S.PhotoID, + S.BigPhotoID, R.ID AS RegistrationRequestID FROM PresentationSpeaker S LEFT JOIN Member M ON M.ID = S.MemberID @@ -214,6 +215,7 @@ FROM ( CONCAT(IFNULL(S.FirstName, M.FirstName), ' ', IFNULL(S.LastName, M.Surname)) AS FullName, IFNULL(M.Email,R.Email) AS Email, S.PhotoID, + S.BigPhotoID, R.ID AS RegistrationRequestID FROM PresentationSpeaker S LEFT JOIN Member M ON M.ID = S.MemberID @@ -248,6 +250,7 @@ FROM ( CONCAT(IFNULL(S.FirstName, M.FirstName), ' ', IFNULL(S.LastName, M.Surname)) AS FullName, IFNULL(M.Email,R.Email) AS Email, S.PhotoID, + S.BigPhotoID, R.ID AS RegistrationRequestID FROM PresentationSpeaker S LEFT JOIN Member M ON M.ID = S.MemberID @@ -282,6 +285,7 @@ FROM ( IFNULL(M.Email,R.Email) AS Email, CONCAT(IFNULL(S.FirstName, M.FirstName), ' ', IFNULL(S.LastName, M.Surname)) AS FullName, S.PhotoID, + S.BigPhotoID, R.ID AS RegistrationRequestID FROM PresentationSpeaker S LEFT JOIN Member M ON M.ID = S.MemberID @@ -329,6 +333,273 @@ SQL; return new PagingResponse($total, $paging_info->getPerPage(), $paging_info->getCurrentPage(), $last_page, $speakers); } + /** + * @param Summit $summit + * @param PagingInfo $paging_info + * @param Filter|null $filter + * @param Order|null $order + * @return PagingResponse + */ + public function getSpeakersBySummitAndOnSchedule(Summit $summit, PagingInfo $paging_info, Filter $filter = null, Order $order = null) + { + + $extra_filters = ''; + $extra_events_filters = ''; + $extra_orders = ''; + $bindings = []; + + if(!is_null($filter)) + { + $where_conditions = $filter->toRawSQL([ + 'full_name' => 'FullName', + 'first_name' => 'FirstName', + 'last_name' => 'LastName', + 'email' => 'Email', + 'id' => 'ID', + ]); + + if(!empty($where_conditions)) { + $extra_filters = " WHERE {$where_conditions}"; + $bindings = array_merge($bindings, $filter->getSQLBindings()); + } + + $where_event_conditions = $filter->toRawSQL([ + 'event_start_date' => 'E.StartDate:datetime_epoch', + 'event_end_date' => 'E.EndDate:datetime_epoch', + ]); + + if(!empty($where_event_conditions)) { + $extra_events_filters = " AND {$where_event_conditions}"; + $bindings = array_merge($bindings, $filter->getSQLBindings()); + } + } + + if(!is_null($order)) + { + $extra_orders = $order->toRawSQL(array + ( + 'id' => 'ID', + 'email' => 'Email', + 'first_name' => 'FirstName', + 'last_name' => 'LastName', + 'full_name' => 'FullName', + )); + } + + $query_count = <<getId()} AND PS.PresentationSpeakerID = S.ID AND E.Published = 1 {$extra_events_filters} + ) + UNION + SELECT S.ID, + IFNULL(S.FirstName, M.FirstName) AS FirstName, + IFNULL(S.LastName, M.Surname) AS LastName, + CONCAT(IFNULL(S.FirstName, M.FirstName), ' ', IFNULL(S.LastName, M.Surname)) AS FullName, + IFNULL(M.Email, R.Email) AS Email + FROM PresentationSpeaker S + LEFT JOIN Member M ON M.ID = S.MemberID + LEFT JOIN SpeakerRegistrationRequest R ON R.SpeakerID = S.ID + WHERE + EXISTS + ( + SELECT E.ID FROM SummitEvent E + INNER JOIN Presentation P ON E.ID = P.ID + INNER JOIN Presentation_Speakers PS ON PS.PresentationID = P.ID + WHERE E.SummitID = {$summit->getId()} AND P.ModeratorID = S.ID AND E.Published = 1 {$extra_events_filters} + ) + UNION + SELECT S.ID, + IFNULL(S.FirstName, M.FirstName) AS FirstName, + IFNULL(S.LastName, M.Surname) AS LastName, + CONCAT(IFNULL(S.FirstName, M.FirstName), ' ', IFNULL(S.LastName, M.Surname)) AS FullName, + IFNULL(M.Email, R.Email) AS Email + FROM PresentationSpeaker S + LEFT JOIN Member M ON M.ID = S.MemberID + LEFT JOIN SpeakerRegistrationRequest R ON R.SpeakerID = S.ID + WHERE + EXISTS + ( + SELECT E.ID FROM SummitEvent E + INNER JOIN Presentation P ON E.ID = P.ID + INNER JOIN Presentation_Speakers PS ON PS.PresentationID = P.ID + WHERE E.SummitID = {$summit->getId()} AND P.ModeratorID = S.ID AND E.Published = 1 {$extra_events_filters} + ) +) +SUMMIT_SPEAKERS +{$extra_filters} +SQL; + + + $stm = $this->getEntityManager()->getConnection()->executeQuery($query_count, $bindings); + + $total = intval($stm->fetchColumn(0)); + + $bindings = array_merge( $bindings, array + ( + 'per_page' => $paging_info->getPerPage(), + 'offset' => $paging_info->getOffset(), + )); + + $query = <<getId()} AND PS.PresentationSpeakerID = S.ID AND E.Published = 1 {$extra_events_filters} + ) + UNION + SELECT + S.ID, + S.ClassName, + S.Created, + S.LastEdited, + S.Title AS SpeakerTitle, + S.Bio, + S.IRCHandle, + S.AvailableForBureau, + S.FundedTravel, + S.Country, + S.MemberID, + S.WillingToTravel, + S.WillingToPresentVideo, + S.Notes, + S.TwitterName, + IFNULL(S.FirstName, M.FirstName) AS FirstName, + IFNULL(S.LastName, M.Surname) AS LastName, + CONCAT(IFNULL(S.FirstName, M.FirstName), ' ', IFNULL(S.LastName, M.Surname)) AS FullName, + IFNULL(M.Email,R.Email) AS Email, + S.PhotoID, + S.BigPhotoID, + R.ID AS RegistrationRequestID + FROM PresentationSpeaker S + LEFT JOIN Member M ON M.ID = S.MemberID + LEFT JOIN SpeakerRegistrationRequest R ON R.SpeakerID = S.ID + WHERE + EXISTS + ( + SELECT E.ID FROM SummitEvent E + INNER JOIN Presentation P ON E.ID = P.ID + INNER JOIN Presentation_Speakers PS ON PS.PresentationID = P.ID + WHERE E.SummitID = {$summit->getId()} AND P.ModeratorID = S.ID AND E.Published = 1 {$extra_events_filters} + ) + UNION + SELECT + S.ID, + S.ClassName, + S.Created, + S.LastEdited, + S.Title AS SpeakerTitle, + S.Bio, + S.IRCHandle, + S.AvailableForBureau, + S.FundedTravel, + S.Country, + S.MemberID, + S.WillingToTravel, + S.WillingToPresentVideo, + S.Notes, + S.TwitterName, + IFNULL(S.FirstName, M.FirstName) AS FirstName, + IFNULL(S.LastName, M.Surname) AS LastName, + CONCAT(IFNULL(S.FirstName, M.FirstName), ' ', IFNULL(S.LastName, M.Surname)) AS FullName, + IFNULL(M.Email,R.Email) AS Email, + S.PhotoID, + S.BigPhotoID, + R.ID AS RegistrationRequestID + FROM PresentationSpeaker S + LEFT JOIN Member M ON M.ID = S.MemberID + LEFT JOIN SpeakerRegistrationRequest R ON R.SpeakerID = S.ID + WHERE + EXISTS + ( + SELECT E.ID FROM SummitEvent E + INNER JOIN Presentation P ON E.ID = P.ID + INNER JOIN Presentation_Speakers PS ON PS.PresentationID = P.ID + WHERE E.SummitID = {$summit->getId()} AND P.ModeratorID = S.ID AND E.Published = 1 {$extra_events_filters} + ) +) +SUMMIT_SPEAKERS +{$extra_filters} {$extra_orders} limit :per_page offset :offset; +SQL; + + /*$rsm = new ResultSetMapping(); + $rsm->addEntityResult(\models\summit\PresentationSpeaker::class, 's'); + $rsm->addJoinedEntityResult(\models\main\File::class,'p', 's', 'photo'); + $rsm->addJoinedEntityResult(\models\main\Member::class,'m', 's', 'member'); + + $rsm->addFieldResult('s', 'ID', 'id'); + $rsm->addFieldResult('s', 'FirstName', 'first_name'); + $rsm->addFieldResult('s', 'LastName', 'last_name'); + $rsm->addFieldResult('s', 'Bio', 'last_name'); + $rsm->addFieldResult('s', 'SpeakerTitle', 'title' ); + $rsm->addFieldResult('p', 'PhotoID', 'id'); + $rsm->addFieldResult('p', 'PhotoTitle', 'title'); + $rsm->addFieldResult('p', 'PhotoFileName', 'filename'); + $rsm->addFieldResult('p', 'PhotoName', 'name'); + $rsm->addFieldResult('m', 'MemberID', 'id');*/ + + $rsm = new ResultSetMappingBuilder($this->getEntityManager()); + $rsm->addRootEntityFromClassMetadata(\models\summit\PresentationSpeaker::class, 's', ['Title' => 'SpeakerTitle']); + + // build rsm here + $native_query = $this->getEntityManager()->createNativeQuery($query, $rsm); + + foreach($bindings as $k => $v) + $native_query->setParameter($k, $v); + + $speakers = $native_query->getResult(); + + $last_page = (int) ceil($total / $paging_info->getPerPage()); + + return new PagingResponse($total, $paging_info->getPerPage(), $paging_info->getCurrentPage(), $last_page, $speakers); + } + /** * @param PagingInfo $paging_info * @param Filter|null $filter @@ -419,6 +690,7 @@ FROM ( IFNULL(M.Email,R.Email) AS Email, CONCAT(IFNULL(S.FirstName, M.FirstName), ' ', IFNULL(S.LastName, M.Surname)) AS FullName, S.PhotoID, + S.BigPhotoID, M.ID AS MemberID, R.ID AS RegistrationRequestID FROM PresentationSpeaker S diff --git a/app/Repositories/Summit/DoctrineSponsorBadgeScanRepository.php b/app/Repositories/Summit/DoctrineSponsorBadgeScanRepository.php new file mode 100644 index 00000000..ed5d7ff3 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSponsorBadgeScanRepository.php @@ -0,0 +1,105 @@ + new DoctrineFilterMapping("t.number :operator :value"), + 'summit_id' => new DoctrineFilterMapping("s.id :operator :value"), + 'user_id' => new DoctrineFilterMapping("u.id :operator :value"), + 'sponsor_id' => new DoctrineFilterMapping("sp.id :operator :value"), + 'company_id' => new DoctrineFilterMapping("c.id :operator :value"), + 'order_number' => new DoctrineFilterMapping("ord.number :operator :value"), + 'attendee_first_name' => [ + "m.first_name :operator :value", + "o.first_name :operator :value" + ], + 'attendee_last_name' => [ + "m.last_name :operator :value", + "o.surname :operator :value" + ], + 'attendee_full_name' => [ + "concat(m.first_name, ' ', m.last_name) :operator :value", + "concat(o.first_name, ' ', o.surname) :operator :value" + ], + 'attendee_email' => [ + "m.email :operator :value", + "o.email :operator :value" + ], + 'attendee_company' => new DoctrineFilterMapping("o.company_name :operator :value"), + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'scan_date' => 'e.scan_date', + 'created' => 'e.created', + 'ticket_number' => "t.number", + 'order_number' => "ord.order_number", + 'sponsor_id' => "sp.id", + 'attendee_company' => 'o.company_name', + "attendee_full_name" => "LOWER(CONCAT(o.first_name, ' ', o.surname))", + 'attendee_first_name' => 'o.first_name', + 'attendee_last_name' => 'o.surname', + 'attendee_email' => 'o.email', + ]; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query){ + $query = $query->join('e.sponsor', 'sp') + ->join('sp.summit', 's') + ->join('sp.company', 'c') + ->join('e.user', 'u') + ->join('e.badge', 'b') + ->join('b.ticket', 't') + ->join('t.order', 'ord') + ->leftJoin('t.owner', 'o') + ->leftJoin('o.member', 'm'); + return $query; + } + + /** + * @return string + */ + protected function getBaseEntity() + { + return SponsorBadgeScan::class; + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSponsorRepository.php b/app/Repositories/Summit/DoctrineSponsorRepository.php new file mode 100644 index 00000000..be1264fe --- /dev/null +++ b/app/Repositories/Summit/DoctrineSponsorRepository.php @@ -0,0 +1,72 @@ + new DoctrineJoinFilterMapping("e.company", "c" ,"c.name :operator :value"), + 'sponsorship_name' => new DoctrineJoinFilterMapping("e.sponsorship", "sp" ,"sp.name :operator :value"), + 'sponsorship_label' => new DoctrineJoinFilterMapping("e.sponsorship", "sp" ,"sp.label :operator :value"), + 'sponsorship_size' => new DoctrineJoinFilterMapping("e.sponsorship", "sp" ,"sp.size :operator :value"), + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value"), + 'badge_scans_count' => new DoctrineHavingFilterMapping("", "bs.sponsor", "count(bs.id) :operator :value"), + ]; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query){ + $query = $query->leftJoin("e.badge_scans", "bs"); + return $query; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + 'order' => 'e.order', + ]; + } + + /** + * @return string + */ + protected function getBaseEntity() + { + return Sponsor::class; + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSponsorshipTypeRepository.php b/app/Repositories/Summit/DoctrineSponsorshipTypeRepository.php new file mode 100644 index 00000000..e7c035a6 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSponsorshipTypeRepository.php @@ -0,0 +1,91 @@ +findOneBy(['name' => trim($name)]); + } + + /** + * @param string $label + * @return SponsorshipType|null + */ + public function getByLabel(string $label): ?SponsorshipType + { + return $this->findOneBy(['label' => trim($label)]); + } + + /** + * @return array + */ + protected function getFilterMappings() + { + return [ + 'name' => 'e.name:json_string', + 'label' => 'e.label:json_string', + 'size' => 'e.size:json_string', + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + 'label' => 'e.label', + 'size' => 'e.size', + 'order' => 'e.orde', + ]; + } + + /** + * @return int + * @throws \Doctrine\DBAL\DBALException + */ + public function getMaxOrder(): int + { + $sql = <<getEntityManager()->getConnection()->executeQuery($sql); + + return intval($stm->fetchColumn(0)); + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitAccessLevelTypeRepository.php b/app/Repositories/Summit/DoctrineSummitAccessLevelTypeRepository.php new file mode 100644 index 00000000..88ac4941 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitAccessLevelTypeRepository.php @@ -0,0 +1,67 @@ + 'e.name:json_string', + 'is_default' => 'e.is_default|json_boolean', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + ]; + } + + /** + * @return string + */ + protected function getBaseEntity() + { + return SummitAccessLevelType::class; + } + + /** + * @param string $name + * @return SummitAccessLevelType|null + */ + public function getByName(string $name): ?SummitAccessLevelType + { + return $this->findOneBy(['name'=>trim($name)]); + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitAttendeeBadgePrintRuleRepository.php b/app/Repositories/Summit/DoctrineSummitAttendeeBadgePrintRuleRepository.php new file mode 100644 index 00000000..fa86c1de --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitAttendeeBadgePrintRuleRepository.php @@ -0,0 +1,67 @@ +getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->join('e.group','g') + ->where("g.id in :group_ids") + ->setParameter("group_ids", $group_ids) + ->getQuery() + ->getResult(); + } + + /** + * @param array $group_slugs + * @return mixed + */ + public function getByGroupsSlugs(array $group_slugs) + { + return $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->join('e.group','g') + ->where("g.code in (:group_slugs)") + ->setParameter("group_slugs", $group_slugs) + ->getQuery() + ->getResult(); + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitAttendeeBadgeRepository.php b/app/Repositories/Summit/DoctrineSummitAttendeeBadgeRepository.php new file mode 100644 index 00000000..ca2635a3 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitAttendeeBadgeRepository.php @@ -0,0 +1,108 @@ + new DoctrineFilterMapping("t.number :operator :value"), + 'summit_id' => new DoctrineFilterMapping("s.id :operator :value"), + 'order_number' => new DoctrineFilterMapping("ord.number :operator :value"), + 'owner_first_name' => [ + "m.first_name :operator :value", + "o.first_name :operator :value" + ], + 'owner_last_name' => [ + "m.last_name :operator :value", + "o.surname :operator :value" + ], + 'owner_full_name' => [ + "concat(m.first_name, ' ', m.last_name) :operator :value", + "concat(o.first_name, ' ', o.surname) :operator :value" + ], + 'owner_email' => [ + "m.email :operator :value", + "o.email :operator :value" + ], + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'created' => 'e.created', + 'ticket_number' => "t.number", + 'order_number' => "ord.order_number", + ]; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query){ + $query = $query->join('e.ticket', 't') + ->leftJoin('t.owner', 'o') + ->leftJoin('o.member', 'm') + ->join('t.order', 'ord') + ->join('ord.summit', 's') + ->join('e.type', 'tp') + ->join('e.features','f'); + return $query; + } + + /** + * @return string + */ + protected function getBaseEntity() + { + return SummitAttendeeBadge::class; + } + + /** + * @param string $ticket_number + * @return SummitAttendeeBadge|null + */ + public function getBadgeByTicketNumber(string $ticket_number): ?SummitAttendeeBadge + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->leftJoin('e.ticket', 't') + ->where("t.number = :ticket_number") + ->setParameter("ticket_number", trim($ticket_number)); + + return $query->getQuery()->getOneOrNullResult(); + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitAttendeeRepository.php b/app/Repositories/Summit/DoctrineSummitAttendeeRepository.php index 579afbab..d1ad5484 100644 --- a/app/Repositories/Summit/DoctrineSummitAttendeeRepository.php +++ b/app/Repositories/Summit/DoctrineSummitAttendeeRepository.php @@ -1,5 +1,4 @@ join('e.summit', 's') + ->leftJoin('e.member', 'm') + ->leftJoin('e.tickets', 't'); + return $query; + } + + /** + * @return array + */ + protected function getFilterMappings() + { + return [ + 'summit_id' => new DoctrineFilterMapping("s.id :operator :value"), + 'first_name' => [ + "m.first_name :operator :value", + "e.first_name :operator :value" + ], + 'last_name' => [ + "m.last_name :operator :value", + "e.surname :operator :value" + ], + 'full_name' => [ + "concat(m.first_name, ' ', m.last_name) :operator :value", + "concat(e.first_name, ' ', e.surname) :operator :value" + ], + 'company' => new DoctrineFilterMapping("e.company_name :operator :value"), + 'email' => [ + "m.email :operator :value", + "e.email :operator :value" + ], + 'external_order_id' => new DoctrineFilterMapping("t.external_order_id :operator :value"), + 'external_attendee_id' => new DoctrineFilterMapping("t.external_attendee_id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'first_name' => 'm.first_name', + 'last_name' => 'm.last_name', + 'external_order_id' => 't.external_order_id', + 'company' => 'e.company_name' + ]; + } + /** * @return string */ @@ -51,59 +103,22 @@ final class DoctrineSummitAttendeeRepository { $query = $this->getEntityManager() ->createQueryBuilder() - ->select("a") - ->from(SummitAttendee::class, "a") - ->leftJoin('a.summit', 's') - ->leftJoin('a.member', 'm') - ->leftJoin('a.tickets', 't') + ->select("e") + ->from($this->getBaseEntity(), "e") + ->leftJoin('e.summit', 's') + ->leftJoin('e.member', 'm') + ->leftJoin('e.tickets', 't') ->where("s.id = :summit_id"); $query->setParameter("summit_id", $summit->getId()); if(!is_null($filter)){ - $filter->apply2Query($query, [ - 'first_name' => new DoctrineLeftJoinFilterMapping - ( - 'a.member', - 'm', - "m.first_name :operator :value" - ), - 'last_name' => new DoctrineLeftJoinFilterMapping - ( - 'a.member', - 'm', - "m.last_name :operator :value" - ), - 'email' => new DoctrineLeftJoinFilterMapping - ( - 'a.member', - 'm', - "m.email :operator :value" - ), - 'external_order_id' => new DoctrineLeftJoinFilterMapping - ( - 'a.tickets', - 't', - "t.external_order_id :operator :value" - ), - 'external_attendee_id' => new DoctrineLeftJoinFilterMapping - ( - 'a.tickets', - 't', - "t.external_attendee_id :operator :value" - ), - ]); + $filter->apply2Query($query, $this->getFilterMappings()); } if (!is_null($order)) { - - $order->apply2Query($query, [ - 'id' => 'a.id', - 'first_name' => 'm.first_name', - 'last_name' => 'm.last_name', - 'external_order_id' => 't.external_order_id', - ]); + $order->apply2Query($query, $this->getOrderMappings()); } else { //default order $query = $query->addOrderBy("m.first_name",'ASC'); @@ -136,14 +151,14 @@ final class DoctrineSummitAttendeeRepository * @param Member $member * @return SummitAttendee */ - public function getBySummitAndMember(Summit $summit, Member $member) + public function getBySummitAndMember(Summit $summit, Member $member):?SummitAttendee { $query = $this->getEntityManager() ->createQueryBuilder() - ->select("a") - ->from(SummitAttendee::class, "a") - ->leftJoin('a.summit', 's') - ->leftJoin('a.member', 'm') + ->select("e") + ->from($this->getBaseEntity(), "e") + ->leftJoin('e.summit', 's') + ->leftJoin('e.member', 'm') ->where("s.id = :summit_id")->andWhere("m.id = :member_id") ->setParameter("summit_id", $summit->getId()) ->setParameter("member_id", $member->getId()); @@ -152,4 +167,78 @@ final class DoctrineSummitAttendeeRepository return $res; } + + /** + * @param Summit $summit + * @param string $email + * @return SummitAttendee|null + */ + public function getBySummitAndEmail(Summit $summit, string $email): ?SummitAttendee + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->leftJoin('e.summit', 's') + ->leftJoin('e.member', 'm') + ->where("s.id = :summit_id") + ->andWhere("m.email = :email or e.email = :email") + ->setParameter("summit_id", $summit->getId()) + ->setParameter("email", strtolower(trim($email))); + + return $query->getQuery()->getOneOrNullResult(); + } + + /** + * @param string $email + * @return mixed + */ + public function getByEmail(string $email) + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.email = :email") + ->setParameter("email", strtolower(trim($email))); + return $query->getQuery()->getResult(); + } + + /** + * @param Summit $summit + * @param string $email + * @param null|string $first_name + * @param null|string $last_name + * @param null|string $external_id + * @return SummitAttendee|null + */ + public function getBySummitAndEmailAndFirstNameAndLastNameAndExternalId(Summit $summit, string $email, ?string $first_name = null, ?string $last_name = null, ?string $external_id = null):?SummitAttendee + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->leftJoin('e.summit', 's') + ->leftJoin('e.member', 'm') + ->where("s.id = :summit_id") + ->andWhere("m.email = :email or e.email = :email"); + + if(!empty($first_name)){ + $query = $query->andWhere("e.first_name = :first_name")->setParameter("first_name", $first_name); + } + + if(!empty($last_name)){ + $query = $query->andWhere("e.surname = :surname")->setParameter("surname", $last_name); + } + if(!empty($external_id)){ + $query = $query->andWhere("e.external_id = :external_id")->setParameter("external_id", $external_id); + } + + $query = + $query + ->setParameter("summit_id", $summit->getId()) + ->setParameter("email", trim($email)); + + return $query->getQuery()->getOneOrNullResult(); + } } \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitAttendeeTicketRepository.php b/app/Repositories/Summit/DoctrineSummitAttendeeTicketRepository.php index f8f417b9..900c32af 100644 --- a/app/Repositories/Summit/DoctrineSummitAttendeeTicketRepository.php +++ b/app/Repositories/Summit/DoctrineSummitAttendeeTicketRepository.php @@ -11,11 +11,17 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use Doctrine\DBAL\LockMode; +use Doctrine\ORM\QueryBuilder; +use models\summit\IOrderConstants; use models\summit\ISummitAttendeeTicketRepository; +use models\summit\Summit; use models\summit\SummitAttendeeTicket; use App\Repositories\SilverStripeDoctrineRepository; use models\utils\IEntity; - +use utils\DoctrineFilterMapping; +use utils\DoctrineJoinFilterMapping; +use utils\DoctrineLeftJoinFilterMapping; /** * Class DoctrineSummitAttendeeTicketRepository * @package App\Repositories\Summit @@ -25,6 +31,58 @@ final class DoctrineSummitAttendeeTicketRepository implements ISummitAttendeeTicketRepository { + + /** + * @return array + */ + protected function getFilterMappings() + { + return [ + 'number' => 'e.number:json_string', + 'order_number' => 'o.number:json_string', + 'owner_name' => [ + "concat(m.first_name, ' ', m.last_name) :operator :value", + "concat(a.first_name, ' ', a.surname) :operator :value" + ], + 'owner_company' => 'a.company_name:json_string', + 'owner_first_name' => [ + 'm.first_name:json_string', + 'a.first_name:json_string' + ], + 'owner_last_name' => ['m.last_name:json_string', 'a.surname:json_string'], + 'owner_email' => ['m.email:json_string', 'm.second_email:json_string', 'm.third_email:json_string','a.email:json_string'], + 'summit_id' => 's.id:json_int', + 'owner_id' => 'a.id:json_int', + 'member_id' => 'm.id:json_int', + 'order_id' => 'o.id:json_int', + 'status' => 'e.status:json_string', + ]; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query){ + $query->join("e.order","o"); + $query->join("o.summit","s"); + $query->leftJoin("e.owner","a"); + $query->leftJoin("a.member","m"); + return $query; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'number' => 'e.number', + 'status' => 'e.status', + ]; + } + /** * @param string $external_order_id * @param string $external_attendee_id @@ -33,18 +91,46 @@ final class DoctrineSummitAttendeeTicketRepository public function getByExternalOrderIdAndExternalAttendeeId($external_order_id, $external_attendee_id) { $query = $this->getEntityManager()->createQueryBuilder() - ->select("t") - ->from(\models\summit\SummitAttendeeTicket::class, "t"); + ->select("e") + ->from($this->getBaseEntity(), "e"); $tickets = $query - ->where('t.external_order_id = :external_order_id') - ->andWhere('t.external_attendee_id = :external_attendee_id') + ->where('e.external_order_id = :external_order_id') + ->andWhere('e.external_attendee_id = :external_attendee_id') ->setParameter('external_order_id', $external_order_id) ->setParameter('external_attendee_id', $external_attendee_id)->getQuery()->getResult(); return count($tickets) > 0 ? $tickets[0] : null; } + /** + * @param string $external_order_id + * @param string $external_attendee_id + * @return SummitAttendeeTicket + */ + public function getByExternalOrderIdAndExternalAttendeeIdExclusiveLock + ( + $external_order_id, + $external_attendee_id + ): ?SummitAttendeeTicket + { + $query = $this->getEntityManager()->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e"); + + return $query + ->join("e.order","o") + ->join("e.owner","ow") + ->where('o.external_id = :external_order_id') + ->andWhere('ow.external_id = :external_attendee_id') + ->setParameter('external_order_id', $external_order_id) + ->setParameter('external_attendee_id', $external_attendee_id) + ->getQuery() + ->setLockMode(LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + /** * @return string */ @@ -63,4 +149,145 @@ final class DoctrineSummitAttendeeTicketRepository SummitAttendeeTicket ", ["ID" => $entity->getIdentifier()]); } + + /** + * @param string $number + * @return bool + */ + public function existNumber(string $number): bool + { + return $this->count(['number' => $number]) > 0; + } + + /** + * @param string $hash + * @return SummitAttendeeTicket|null + */ + public function getByHashExclusiveLock(string $hash): ?SummitAttendeeTicket + { + return $this->getEntityManager()->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where('e.hash = :hash') + ->setParameter('hash', trim($hash))->getQuery() + ->setLockMode(LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + + /** + * @param string $hash + * @return SummitAttendeeTicket|null + */ + public function getByNumberExclusiveLock(string $number):?SummitAttendeeTicket{ + return $this->getEntityManager()->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where('e.number = :number') + ->setParameter('number', trim($number))->getQuery() + ->setLockMode(LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + + /** + * @param string $number + * @return SummitAttendeeTicket|null + */ + public function getByNumber(string $number): ?SummitAttendeeTicket + { + return $this->getEntityManager()->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where('e.number = :number') + ->setParameter('number', trim($number))->getQuery() + ->getOneOrNullResult(); + } + + /** + * @param string $hash + * @return SummitAttendeeTicket|null + */ + public function getByFormerHashExclusiveLock(string $hash): ?SummitAttendeeTicket + { + return $this->getEntityManager()->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->join("e.former_hashes", "fh") + ->where('fh.hash = :hash') + ->setParameter('hash', trim($hash))->getQuery() + ->setLockMode(LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + + /** + * @param Summit $summit + * @param string $external_order_id + * @param string $external_attendee_id + * @return SummitAttendeeTicket|null + * @throws \Doctrine\ORM\NonUniqueResultException + * @throws \Doctrine\ORM\TransactionRequiredException + */ + public function getBySummitAndExternalOrderIdAndExternalAttendeeIdExclusiveLock + ( + Summit $summit, + $external_order_id, + $external_attendee_id + ): ?SummitAttendeeTicket + { + $query = $this->getEntityManager()->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e"); + + return $query + ->join("e.order","o") + ->join("o.summit","s") + ->join("e.owner","ow") + ->where('o.external_id = :external_order_id') + ->andWhere('ow.external_id = :external_attendee_id') + ->andWhere('s.id = :summit_id') + ->setParameter('external_order_id', $external_order_id) + ->setParameter('external_attendee_id', $external_attendee_id) + ->setParameter('summit_id', $summit->getId()) + ->getQuery() + ->setLockMode(LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + + /** + * @param Summit $summit + * @param string $external_attendee_id + * @return SummitAttendeeTicket|null + */ + public function getByExternalAttendeeIdExclusiveLock(Summit $summit, string $external_attendee_id):?SummitAttendeeTicket + { + $query = $this->getEntityManager()->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e"); + + return $query + ->join("e.order","o") + ->join("o.summit","s") + ->join("e.owner","ow") + ->where('ow.external_id = :external_attendee_id') + ->andWhere('s.id = :summit_id') + ->setParameter('external_attendee_id', $external_attendee_id) + ->setParameter('summit_id', $summit->getId()) + ->getQuery() + ->setLockMode(LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraFilters(QueryBuilder $query){ + $query = $query->andWhere("e.status <> :cancelled")->setParameter("cancelled", IOrderConstants::CancelledStatus); + return $query; + } + } \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitBadgeFeatureTypeRepository.php b/app/Repositories/Summit/DoctrineSummitBadgeFeatureTypeRepository.php new file mode 100644 index 00000000..0cc1820d --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitBadgeFeatureTypeRepository.php @@ -0,0 +1,57 @@ + 'e.name:json_string', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + ]; + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitBadgeTypeRepository.php b/app/Repositories/Summit/DoctrineSummitBadgeTypeRepository.php new file mode 100644 index 00000000..36d0bdbe --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitBadgeTypeRepository.php @@ -0,0 +1,58 @@ + 'e.name:json_string', + 'is_default' => 'e.is_default|json_boolean', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + ]; + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitDocumentRepository.php b/app/Repositories/Summit/DoctrineSummitDocumentRepository.php new file mode 100644 index 00000000..d5643e4c --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitDocumentRepository.php @@ -0,0 +1,69 @@ +join('e.summit', 's') + ->leftJoin('e.event_types', 'et'); + return $query; + } + + /** + * @return array + */ + protected function getFilterMappings() + { + return [ + 'name' => 'e.name:json_string', + 'description' => 'e.description:json_string', + 'label' => 'e.label:json_string', + 'event_type' => 'et.type:json_string', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + 'label' => 'e.label', + ]; + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitEmailEventFlowRepository.php b/app/Repositories/Summit/DoctrineSummitEmailEventFlowRepository.php new file mode 100644 index 00000000..8863f998 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitEmailEventFlowRepository.php @@ -0,0 +1,71 @@ +join('e.event_type', 'et') + ->join('et.flow', 'f'); + return $query; + } + + /** + * @return array + */ + protected function getFilterMappings() + { + return [ + 'email_template_identifier' => 'e.email_template_identifier:json_string', + 'event_type_name' => 'et.name:json_string', + 'flow_name' => 'f.name:json_string', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'email_template_identifier' => 'e.email_template_identifier', + ]; + } + +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitEntityEventRepository.php b/app/Repositories/Summit/DoctrineSummitEntityEventRepository.php index 8a6bdaac..6994af42 100644 --- a/app/Repositories/Summit/DoctrineSummitEntityEventRepository.php +++ b/app/Repositories/Summit/DoctrineSummitEntityEventRepository.php @@ -17,7 +17,6 @@ use models\summit\ISummitEntityEventRepository; use models\summit\Summit; use models\summit\SummitEntityEvent; use App\Repositories\SilverStripeDoctrineRepository; - /** * Class DoctrineSummitEntityEventRepository * @package App\Repositories\Summit @@ -118,7 +117,7 @@ SQL; $entity_events = $native_query->getResult(); - if($detach) $this->getEntityManager()->clear(\models\summit\SummitEntityEvent::class); + if($detach) $this->getEntityManager() ->clear(\models\summit\SummitEntityEvent::class); return $entity_events; } diff --git a/app/Repositories/Summit/DoctrineSummitEventRepository.php b/app/Repositories/Summit/DoctrineSummitEventRepository.php index fcec20ad..727f1f52 100644 --- a/app/Repositories/Summit/DoctrineSummitEventRepository.php +++ b/app/Repositories/Summit/DoctrineSummitEventRepository.php @@ -114,6 +114,10 @@ final class DoctrineSummitEventRepository 'c', "c.id :operator :value" ), + 'selection_plan_id' => new DoctrineFilterMapping + ( + "(selp.id :operator :value)" + ), 'location_id' => new DoctrineLeftJoinFilterMapping ( 'e.location', @@ -200,6 +204,7 @@ final class DoctrineSummitEventRepository ->leftJoin("e.category", 'cc', Join::LEFT_JOIN) ->leftJoin("p.speakers", "sp", Join::LEFT_JOIN) ->leftJoin('p.selected_presentations', "ssp", Join::LEFT_JOIN) + ->leftJoin('p.selection_plan', "selp", Join::LEFT_JOIN) ->leftJoin('ssp.list', "sspl", Join::LEFT_JOIN) ->leftJoin('p.moderator', "spm", Join::LEFT_JOIN) ->leftJoin('spm.member', "spmm2", Join::LEFT_JOIN) @@ -293,7 +298,7 @@ final class DoctrineSummitEventRepository ->leftJoin("e.location", 'l', Join::LEFT_JOIN) ->leftJoin("e.category", 'cc', Join::LEFT_JOIN) ->leftJoin("p.speakers", "sp", Join::LEFT_JOIN) - ->leftJoin('p.selected_presentations', "ssp", Join::LEFT_JOIN) + ->leftJoin('p.selection_plan', "selp", Join::LEFT_JOIN) ->leftJoin('ssp.list', "sspl", Join::LEFT_JOIN) ->leftJoin('p.moderator', "spm", Join::LEFT_JOIN) ->leftJoin('sp.member', "spmm", Join::LEFT_JOIN) @@ -354,7 +359,7 @@ final class DoctrineSummitEventRepository { $query = $this->getEntityManager()->createQueryBuilder() ->select("e") - ->from(\models\summit\SummitEvent::class, "e") + ->from($this->getBaseEntity(), "e") ->join('e.summit', 's', Join::WITH, " s.id = :summit_id") ->where('e.published = 1') ->andWhere('e.external_id not in (:external_ids)') diff --git a/app/Repositories/Summit/DoctrineSummitLocationRepository.php b/app/Repositories/Summit/DoctrineSummitLocationRepository.php index d71f6a92..6bac8713 100644 --- a/app/Repositories/Summit/DoctrineSummitLocationRepository.php +++ b/app/Repositories/Summit/DoctrineSummitLocationRepository.php @@ -157,10 +157,11 @@ final class DoctrineSummitLocationRepository if($filter->hasFilter("availability_day")){ // special case, we need to figure if each room has available slots - $res = $query->getQuery()->execute(); - $rooms = []; + $res = $query->getQuery()->execute(); + $rooms = []; $availability_day = $filter->getUniqueFilter("availability_day")->getValue(); - $day = new \DateTime("@$availability_day"); + $day = new \DateTime("@$availability_day"); + foreach ($res as $room){ if(!$room instanceof SummitBookableVenueRoom) continue; if(count($room->getFreeSlots($day)) > 0) diff --git a/app/Repositories/Summit/DoctrineSummitMediaFileTypeRepository.php b/app/Repositories/Summit/DoctrineSummitMediaFileTypeRepository.php new file mode 100644 index 00000000..d153092d --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitMediaFileTypeRepository.php @@ -0,0 +1,50 @@ + 'e.name:json_string', + ]; + } + + /** + * @inheritDoc + */ + protected function getBaseEntity() + { + return SummitMediaFileType::class; + } + + public function getByName(string $name): ?SummitMediaFileType + { + return $this->findOneBy(['name'=> trim($name)]); + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitMediaUploadTypeRepository.php b/app/Repositories/Summit/DoctrineSummitMediaUploadTypeRepository.php new file mode 100644 index 00000000..a19e0121 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitMediaUploadTypeRepository.php @@ -0,0 +1,56 @@ + 'e.name:json_string', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + ]; + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitOrderExtraQuestionTypeRepository.php b/app/Repositories/Summit/DoctrineSummitOrderExtraQuestionTypeRepository.php new file mode 100644 index 00000000..ed0f9f12 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitOrderExtraQuestionTypeRepository.php @@ -0,0 +1,137 @@ + 'e.name:json_string', + 'type' => 'e.type:json_string', + 'usage;' => 'e.$usage;:json_string', + 'label' => 'e.label:json_string', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + 'label' => 'e.label', + 'order' => 'e.order', + ]; + } + + /** + * + * @return string + */ + protected function getBaseEntity() + { + return SummitOrderExtraQuestionType::class; + } + + /** + * @param Summit $summit + * @return array + */ + public function getQuestionsMetadata(Summit $summit) + { + return [ + [ + 'type' => 'TextArea', + ], + [ + 'type' => 'Text', + ], + [ + 'type' => 'CheckBox', + ], + [ + 'type' => 'ComboBox', + 'values' => 'array', + ], + [ + 'type' => 'CheckBoxList', + 'values' => 'array', + ], + [ + 'type' => 'RadioButtonList', + 'values' => 'array', + ], + + ]; + } + + /** + * @param SummitOrderExtraQuestionType $questionType + * @return bool + */ + public function hasAnswers(SummitOrderExtraQuestionType $questionType): bool + { + try { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("count(e.id)") + ->from(SummitOrderExtraQuestionAnswer::class, "e")->join("e.question", "q") + ->where("q = :question")->setParameter("question", $questionType); + + return $query->getQuery()->getSingleScalarResult() > 0; + } + catch (\Exception $ex){ + Log::error($ex); + return false; + } + } + + /** + * @param SummitOrderExtraQuestionType $questionType + */ + public function deleteAnswersFrom(SummitOrderExtraQuestionType $questionType):void{ + try { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->delete(SummitOrderExtraQuestionAnswer::class, "e") + ->where("e.question = :question") + ->setParameter("question", $questionType); + + $query->getQuery()->execute(); + } + catch (\Exception $ex){ + Log::error($ex); + } + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitOrderRepository.php b/app/Repositories/Summit/DoctrineSummitOrderRepository.php new file mode 100644 index 00000000..99e8bdbc --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitOrderRepository.php @@ -0,0 +1,300 @@ + 'e.number:json_string', + 'summit_id' => new DoctrineFilterMapping("s.id :operator :value"), + 'owner_id' => new DoctrineFilterMapping("o.id :operator :value"), + 'owner_name' => [ + "LOWER(CONCAT(o.first_name, ' ', o.last_name)) :operator :value" , + "LOWER(CONCAT(e.owner_first_name, ' ', e.owner_surname)) :operator :value" + ], + 'owner_email' => [ + "o.email :operator :value", + "e.owner_email :operator :value" + ], + 'owner_company' => 'e.owner_company:json_string', + 'status' => 'e.status:json_string', + 'ticket_owner_name' => [ + "LOWER(CONCAT(to.first_name, ' ', to.surname)) :operator :value", + "LOWER(CONCAT(tom.first_name, ' ', tom.last_name)) :operator :value" + ], + 'ticket_owner_email' => [ + "to.email :operator :value", + "tom.email :operator :value" + ], + 'ticket_number' => new DoctrineFilterMapping("t.number :operator :value"), + ]; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query){ + $query + ->join('e.tickets','t') + ->join('e.summit','s') + ->leftJoin('e.owner','o') + ->leftJoin('t.owner','to') + ->leftJoin('to.member', 'tom'); + return $query; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'number' => 'e.number', + 'id' => 'e.id', + 'status' => 'e.status', + ]; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraFilters(QueryBuilder $query){ + $query = $query->andWhere("e.status <> :cancelled")->setParameter("cancelled", IOrderConstants::CancelledStatus); + return $query; + } + + /** + * @return string + */ + protected function getBaseEntity() + { + return SummitOrder::class; + } + + /** + * @param string $hash + * @return SummitOrder|null + */ + public function getByHashLockExclusive(string $hash): ?SummitOrder + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.hash = :hash"); + + $query->setParameter("hash", $hash); + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + + /** + * @param string $payment_gateway_cart_id + * @return SummitOrder|null + */ + public function getByPaymentGatewayCartIdExclusiveLock(string $payment_gateway_cart_id): ?SummitOrder + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.payment_gateway_cart_id = :payment_gateway_cart_id"); + + $query->setParameter("payment_gateway_cart_id", $payment_gateway_cart_id); + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + + /** + * @param string $email + * @return mixed + */ + public function getAllByOwnerEmail(string $email) + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.owner_email = :owner_email"); + + $query->setParameter("owner_email", trim($email)); + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getResult(); + } + + /** + * @param int $minutes + * @param int $max + * @return mixed + */ + public function getAllReservedOlderThanXMinutes(int $minutes, int $max = 100) + { + $eol = new \DateTime('now', new \DateTimeZone(SilverstripeBaseModel::DefaultTimeZone)); + $eol->sub(new \DateInterval('PT' . $minutes . 'M')); + + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.created <= :eol") + ->andWhere("e.status = :status"); + + $query->setParameter("eol", $eol); + $query->setParameter("status", IOrderConstants::ReservedStatus); + + return $query->getQuery()->setMaxResults($max)->getResult(); + + } + + /** + * @param int $minutes + * @param int $max + * @return mixed + */ + public function getAllConfirmedOlderThanXMinutes(int $minutes, int $max = 100) + { + $eol = new \DateTime('now', new \DateTimeZone(SilverstripeBaseModel::DefaultTimeZone)); + $eol->sub(new \DateInterval('PT' . $minutes . 'M')); + + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.created <= :eol") + ->andWhere("e.status = :status"); + + $query->setParameter("eol", $eol); + $query->setParameter("status", IOrderConstants::ConfirmedStatus); + + return $query->getQuery()->setMaxResults($max)->getResult(); + + } + + /** + * @param string $externalId + * @return SummitOrder|null + */ + public function getByExternalIdLockExclusive(string $externalId): ?SummitOrder + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.external_id = :external_id"); + + $query->setParameter("external_id", $externalId); + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + + /** + * @param Summit $summit + * @param string $externalId + * @return SummitOrder|null + */ + public function getByExternalIdAndSummitLockExclusive(Summit $summit, string $externalId): ?SummitOrder + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->join('e.summit', 's') + ->where("e.external_id = :external_id") + ->andWhere('s.id = :summit_id') + ; + + $query->setParameter("external_id", $externalId); + $query->setParameter("summit_id", $summit->getId()) + ; + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } + + /** + * @param Summit $summit + * @param PagingInfo $paging_info + * @return PagingResponse + */ + public function getAllOrderThatNeedsEmailActionReminder(Summit $summit, PagingInfo $paging_info):PagingResponse + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->join("e.tickets","t") + ->join("e.summit","s") + ->leftJoin("t.owner","o") + ->where('e.status = :order_status') + ->andWhere('s.id = :summit_id') + ->andWhere("o is null OR o.status = :attendee_status"); + + $query->setParameter("order_status", IOrderConstants::PaidStatus); + $query->setParameter("summit_id", $summit->getId()); + $query->setParameter("attendee_status", SummitAttendee::StatusIncomplete); + + $query= $query + ->setFirstResult($paging_info->getOffset()) + ->setMaxResults($paging_info->getPerPage()); + + $paginator = new Paginator($query, $fetchJoinCollection = true); + $total = $paginator->count(); + $data = []; + + foreach($paginator as $entity) + $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/Summit/DoctrineSummitRefundPolicyTypeRepository.php b/app/Repositories/Summit/DoctrineSummitRefundPolicyTypeRepository.php new file mode 100644 index 00000000..0e164817 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitRefundPolicyTypeRepository.php @@ -0,0 +1,60 @@ + 'e.name:json_string', + 'until_x_days_before_event_starts' => 'e.until_x_days_before_event_starts:json_int', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + 'until_x_days_before_event_starts' => 'e.until_x_days_before_event_starts' + ]; + } + + /** + * @return string + */ + protected function getBaseEntity() + { + return SummitRefundPolicyType::class; + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitRegistrationInvitationRepository.php b/app/Repositories/Summit/DoctrineSummitRegistrationInvitationRepository.php new file mode 100644 index 00000000..8e8f7c52 --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitRegistrationInvitationRepository.php @@ -0,0 +1,117 @@ +join('e.summit', 's'); + return $query; + } + + /** + * @return array + */ + protected function getFilterMappings() + { + return [ + 'email' => 'e.email:json_string', + 'first_name' => 'e.first_name:json_string', + 'last_name' => 'e.last_name:json_string', + 'is_accepted' => new DoctrineSwitchFilterMapping([ + 'true' => new DoctrineCaseFilterMapping( + 'true', + "e.accepted_date is not null" + ), + 'false' => new DoctrineCaseFilterMapping( + 'false', + "e.accepted_date is null" + ), + ] + ), + 'is_sent' => new DoctrineSwitchFilterMapping([ + 'true' => new DoctrineCaseFilterMapping( + 'true', + "e.hash is not null" + ), + 'false' => new DoctrineCaseFilterMapping( + 'false', + "e.hash is null" + ), + ] + ), + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'email' => 'e.email', + ]; + } + + /** + * @param string $hash + * @return SummitRegistrationInvitation|null + */ + public function getByHashExclusiveLock(string $hash): ?SummitRegistrationInvitation + { + return $this->findOneBy(['hash'=> trim($hash)]); + } + + /** + * @inheritDoc + */ + public function getAllIdsNonAcceptedPerSummit(Summit $summit): array + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e.id") + ->from($this->getBaseEntity(), "e") + ->join("e.summit","s") + ->where('e.accepted_date is null') + ->andWhere('s.id = :summit_id')->setParameter("summit_id", $summit->getId()); + return $query->getQuery()->getResult(); + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitRegistrationPromoCodeRepository.php b/app/Repositories/Summit/DoctrineSummitRegistrationPromoCodeRepository.php index 213ff576..4ad0a6f9 100644 --- a/app/Repositories/Summit/DoctrineSummitRegistrationPromoCodeRepository.php +++ b/app/Repositories/Summit/DoctrineSummitRegistrationPromoCodeRepository.php @@ -14,10 +14,14 @@ use App\Repositories\SilverStripeDoctrineRepository; use Doctrine\ORM\Query\Expr\Join; use models\summit\ISummitRegistrationPromoCodeRepository; +use models\summit\MemberSummitRegistrationDiscountCode; use models\summit\MemberSummitRegistrationPromoCode; +use models\summit\SpeakerSummitRegistrationDiscountCode; use models\summit\SpeakerSummitRegistrationPromoCode; +use models\summit\SponsorSummitRegistrationDiscountCode; use models\summit\SponsorSummitRegistrationPromoCode; use models\summit\Summit; +use models\summit\SummitRegistrationDiscountCode; use models\summit\SummitRegistrationPromoCode; use utils\DoctrineFilterMapping; use utils\DoctrineInstanceOfFilterMapping; @@ -47,16 +51,12 @@ class DoctrineSummitRegistrationPromoCodeRepository * @param string $code * @return SummitRegistrationPromoCode|null */ - public function getByCode($code){ + public function getByCode(string $code):?SummitRegistrationPromoCode{ $query = $this->getEntityManager() ->createQueryBuilder() - ->select("pc") - ->from(SummitRegistrationPromoCode::class, "pc") - ->leftJoin(MemberSummitRegistrationPromoCode::class, 'mpc', 'WITH', 'pc.id = mpc.id') - ->leftJoin(SponsorSummitRegistrationPromoCode::class, 'spc', 'WITH', 'mpc.id = spc.id') - ->leftJoin(SpeakerSummitRegistrationPromoCode::class, 'spkpc', 'WITH', 'spkpc.id = pc.id') - - ->where("pc.code = :code"); + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.code = :code"); $query->setParameter("code", $code); @@ -67,16 +67,15 @@ class DoctrineSummitRegistrationPromoCodeRepository { return [ 'code' => 'pc.code:json_string', - 'sponsor' => new DoctrineFilterMapping ( - "(spnr.name :operator :value)" + "(spnr.name :operator :value) OR (spnr2.name :operator :value)" ), 'creator' => new DoctrineFilterMapping ( "( concat(ct.first_name, ' ', ct.last_name) :operator :value ". "OR ct.first_name :operator :value ". - "OR ct.last_name :operator :value )" + "OR ct.last_name :operator :value ) " ), 'creator_email' => new DoctrineFilterMapping ( @@ -86,11 +85,15 @@ class DoctrineSummitRegistrationPromoCodeRepository ( "( concat(owr.first_name, ' ', owr.last_name) :operator :value ". "OR owr.first_name :operator :value ". - "OR owr.last_name :operator :value )" + "OR owr.last_name :operator :value ) ". + "OR ( concat(owr2.first_name, ' ', owr2.last_name) :operator :value ". + "OR owr2.first_name :operator :value ". + "OR owr2.last_name :operator :value ) " ), 'owner_email' => new DoctrineFilterMapping ( - "(owr.email :operator :value)" + "(owr.email :operator :value) ". + "OR (owr2.email :operator :value) " ), 'speaker' => new DoctrineFilterMapping ( @@ -99,22 +102,35 @@ class DoctrineSummitRegistrationPromoCodeRepository "OR spkr.first_name :operator :value ". "OR spkr.last_name :operator :value ". "OR spmm.first_name :operator :value ". - "OR spmm.last_name :operator :value )" + "OR spmm.last_name :operator :value ) ". + "OR ( concat(spkr2.first_name, ' ', spkr2.last_name) :operator :value ". + "OR concat(spmm2.first_name, ' ', spmm2.last_name) :operator :value ". + "OR spkr2.first_name :operator :value ". + "OR spkr2.last_name :operator :value ". + "OR spmm2.first_name :operator :value ". + "OR spmm2.last_name :operator :value ) " ), 'speaker_email' => new DoctrineFilterMapping ( - "(sprr.email :operator :value OR spmm.email :operator :value)" + "(sprr.email :operator :value OR spmm.email :operator :value) ". + "OR (sprr2.email :operator :value OR spmm2.email :operator :value) " ), 'type' => new DoctrineFilterMapping ( - "(mpc.type :operator :value OR spkpc.type :operator :value)" + "(mpc.type :operator :value OR spkpc.type :operator :value) ". + " OR (mdc.type :operator :value OR spkdc.type :operator :value) " ), 'class_name' => new DoctrineInstanceOfFilterMapping( "pc", [ - MemberSummitRegistrationPromoCode::ClassName => MemberSummitRegistrationPromoCode::class, - SpeakerSummitRegistrationPromoCode::ClassName => SpeakerSummitRegistrationPromoCode::class, - SponsorSummitRegistrationPromoCode::ClassName => SponsorSummitRegistrationPromoCode::class + SummitRegistrationPromoCode::ClassName => SummitRegistrationPromoCode::class, + SummitRegistrationDiscountCode::ClassName => SummitRegistrationDiscountCode::class, + MemberSummitRegistrationPromoCode::ClassName => MemberSummitRegistrationPromoCode::class, + SpeakerSummitRegistrationPromoCode::ClassName => SpeakerSummitRegistrationPromoCode::class, + SponsorSummitRegistrationPromoCode::ClassName => SponsorSummitRegistrationPromoCode::class, + MemberSummitRegistrationDiscountCode::ClassName => MemberSummitRegistrationDiscountCode::class, + SpeakerSummitRegistrationDiscountCode::ClassName => SpeakerSummitRegistrationDiscountCode::class, + SponsorSummitRegistrationDiscountCode::ClassName => SponsorSummitRegistrationDiscountCode::class, ] ) ]; @@ -146,20 +162,29 @@ class DoctrineSummitRegistrationPromoCodeRepository Order $order = null ) { - $query = $this->getEntityManager() + $query = $this->getEntityManager() ->createQueryBuilder() ->select("pc") - ->from(SummitRegistrationPromoCode::class, "pc") + ->from($this->getBaseEntity(), "pc") + ->leftJoin(SummitRegistrationDiscountCode::class, 'dc', 'WITH', 'pc.id = dc.id') + ->leftJoin(MemberSummitRegistrationDiscountCode::class, 'mdc', 'WITH', 'pc.id = mdc.id') + ->leftJoin(SpeakerSummitRegistrationDiscountCode::class, 'spkdc', 'WITH', 'pc.id = spkdc.id') + ->leftJoin(SponsorSummitRegistrationDiscountCode::class, 'spdc', 'WITH', 'pc.id = spdc.id') ->leftJoin(MemberSummitRegistrationPromoCode::class, 'mpc', 'WITH', 'pc.id = mpc.id') ->leftJoin(SponsorSummitRegistrationPromoCode::class, 'spc', 'WITH', 'mpc.id = spc.id') ->leftJoin(SpeakerSummitRegistrationPromoCode::class, 'spkpc', 'WITH', 'spkpc.id = pc.id') ->leftJoin('pc.summit', 's') ->leftJoin('pc.creator', 'ct') ->leftJoin("spkpc.speaker", "spkr") + ->leftJoin("spkdc.speaker", "spkr2") ->leftJoin('spkr.member', "spmm", Join::LEFT_JOIN) + ->leftJoin('spkr2.member', "spmm2", Join::LEFT_JOIN) ->leftJoin('spkr.registration_request', "sprr", Join::LEFT_JOIN) + ->leftJoin('spkr2.registration_request', "sprr2", Join::LEFT_JOIN) ->leftJoin("mpc.owner", "owr") + ->leftJoin("mdc.owner", "owr2") ->leftJoin("spc.sponsor", "spnr") + ->leftJoin("spdc.sponsor", "spnr2") ->where("s.id = :summit_id"); $query->setParameter("summit_id", $summit->getId()); @@ -203,9 +228,63 @@ class DoctrineSummitRegistrationPromoCodeRepository public function getMetadata(Summit $summit) { return [ + SummitRegistrationPromoCode::getMetadata(), + SummitRegistrationDiscountCode::getMetadata(), MemberSummitRegistrationPromoCode::getMetadata(), SpeakerSummitRegistrationPromoCode::getMetadata(), - SponsorSummitRegistrationPromoCode::getMetadata() + SponsorSummitRegistrationPromoCode::getMetadata(), + SponsorSummitRegistrationDiscountCode::getMetadata(), + SpeakerSummitRegistrationDiscountCode::getMetadata(), + MemberSummitRegistrationDiscountCode::getMetadata(), ]; } + + /** + * @param Summit $sumit + * @param array $codes + * @return SummitRegistrationPromoCode|null + */ + public function getByValuesExclusiveLock(Summit $summit, array $codes) + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->leftJoin('e.summit', 's') + ->where("s.id = :summit_id") + ->andWhere("e.code in (:codes)"); + + $query->setParameter("summit_id", $summit->getId()); + $query->setParameter("codes", $codes); + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getResult(); + } + + /** + * @param Summit $summit + * @param string $code + * @return SummitRegistrationPromoCode|null + * @throws \Doctrine\ORM\NonUniqueResultException + * @throws \Doctrine\ORM\TransactionRequiredException + */ + public function getByValueExclusiveLock(Summit $summit, string $code): ?SummitRegistrationPromoCode + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->leftJoin('e.summit', 's') + ->where("s.id = :summit_id") + ->andWhere("e.code = :code"); + + $query->setParameter("code", strtoupper(trim($code))); + $query->setParameter("summit_id", $summit->getId()); + + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); + } } \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitRepository.php b/app/Repositories/Summit/DoctrineSummitRepository.php index 38ee4d31..4026c878 100644 --- a/app/Repositories/Summit/DoctrineSummitRepository.php +++ b/app/Repositories/Summit/DoctrineSummitRepository.php @@ -11,11 +11,12 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - +use Doctrine\ORM\QueryBuilder; use Illuminate\Support\Facades\Log; use models\summit\ISummitRepository; use models\summit\Summit; use App\Repositories\SilverStripeDoctrineRepository; +use utils\DoctrineHavingFilterMapping; /** * Class DoctrineSummitRepository * @package App\Repositories\Summit @@ -25,6 +26,57 @@ final class DoctrineSummitRepository implements ISummitRepository { + /** + * @return array + */ + protected function getFilterMappings() + { + return [ + 'name' => 'e.name', + 'start_date' => 'e.begin_date:datetime_epoch', + 'end_date' => 'e.end_date:datetime_epoch', + 'submission_begin_date' => 'sp.submission_begin_date:datetime_epoch', + 'submission_end_date' => 'sp.submission_end_date:datetime_epoch', + 'selection_plan_enabled' => 'sp.is_enabled:json_boolean', + 'registration_begin_date' => 'e.registration_begin_date:datetime_epoch', + 'registration_end_date' => 'e.registration_end_date:datetime_epoch', + 'available_on_api' => 'e.available_on_api:json_int', + 'summit_id' => 'e.id:json_int', + 'ticket_types_count' => new DoctrineHavingFilterMapping("","tt.summit", "count(tt.id) :operator :value"), + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + 'begin_date' => 'e.begin_date', + 'registration_begin_date' => 'e.registration_begin_date', + ]; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraFilters(QueryBuilder $query){ + return $query; + } + + /** + * @param QueryBuilder $query + * @return QueryBuilder + */ + protected function applyExtraJoins(QueryBuilder $query){ + $query = $query->leftJoin("e.ticket_types", "tt"); + $query = $query->leftJoin("e.selection_plans", "sp"); + return $query; + } + /** * @return Summit */ @@ -32,7 +84,7 @@ final class DoctrineSummitRepository { $res = $this->getEntityManager()->createQueryBuilder() ->select("s") - ->from(\models\summit\Summit::class, "s") + ->from($this->getBaseEntity(), "s") ->where('s.active = 1') ->orderBy('s.begin_date', 'DESC') ->getQuery() @@ -48,8 +100,10 @@ final class DoctrineSummitRepository $now_utc = new \DateTime('now', new \DateTimeZone('UTC')); return $this->getEntityManager()->createQueryBuilder() ->select("s") - ->from(\models\summit\Summit::class, "s") + ->from($this->getBaseEntity(), "s") + // current ->where('s.begin_date <= :now and s.end_date >= :now') + // or future ->orWhere('s.begin_date >= :now') ->orderBy('s.begin_date', 'DESC') ->setParameter('now', $now_utc) @@ -64,7 +118,7 @@ final class DoctrineSummitRepository { return $this->getEntityManager()->createQueryBuilder() ->select("s") - ->from(\models\summit\Summit::class, "s") + ->from($this->getBaseEntity(), "s") ->where('s.available_on_api = 1') ->orderBy('s.begin_date', 'ASC') ->getQuery() @@ -78,7 +132,7 @@ final class DoctrineSummitRepository { return $this->getEntityManager()->createQueryBuilder() ->select("s") - ->from(\models\summit\Summit::class, "s") + ->from($this->getBaseEntity(), "s") ->orderBy('s.begin_date', 'ASC') ->getQuery() ->getResult(); @@ -100,7 +154,7 @@ final class DoctrineSummitRepository { return $this->getEntityManager()->createQueryBuilder() ->select("s") - ->from(\models\summit\Summit::class, "s") + ->from($this->getBaseEntity(), "s") ->where('s.name = :name') ->setParameter('name', $name) ->getQuery() @@ -118,7 +172,7 @@ final class DoctrineSummitRepository ->select("s") ->from($this->getBaseEntity(), "s") ->where('s.slug = :slug') - ->setParameter('slug', $slug) + ->setParameter('slug', strtolower($slug)) ->getQuery() ->getOneOrNullResult(); } @@ -135,7 +189,7 @@ final class DoctrineSummitRepository { $res = $this->getEntityManager()->createQueryBuilder() ->select("s") - ->from(\models\summit\Summit::class, "s") + ->from($this->getBaseEntity(), "s") ->where('s.active = 1') ->orderBy('s.begin_date', 'DESC') ->getQuery() @@ -150,8 +204,8 @@ final class DoctrineSummitRepository public function getCurrentAndAvailable() { $res = $this->getEntityManager()->createQueryBuilder() - ->select("s") - ->from(\models\summit\Summit::class, "s") + ->select( "s") + ->from($this->getBaseEntity(), 's') ->where('s.active = 1') ->andWhere('s.available_on_api = 1') ->orderBy('s.begin_date', 'DESC') @@ -182,9 +236,46 @@ final class DoctrineSummitRepository ->getResult(); } + /** + * @return Summit[] + */ + public function getAllWithExternalRegistrationFeed():array { + return $this->getEntityManager()->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.api_feed_type is not null") + ->andWhere("e.external_registration_feed_type <> ''") + ->andWhere("e.external_registration_feed_type is not null") + ->andWhere("e.external_registration_feed_api_key <> ''") + ->andWhere("e.external_registration_feed_api_key is not null") + ->andWhere("e.external_summit_id <> ''") + ->andWhere("e.external_summit_id is not null") + ->andWhere("e.end_date >= :now") + ->orderBy('e.id', 'DESC') + ->setParameter("now", new \DateTime('now', new \DateTimeZone('UTC'))) + ->getQuery() + ->getResult(); + } + /** * @return array */ + public function getNotEnded(): array + { + return $this->getEntityManager()->createQueryBuilder() + ->select("e") + ->from($this->getBaseEntity(), "e") + ->where("e.end_date >= :now") + ->orderBy('e.id', 'DESC') + ->setParameter("now", new \DateTime('now', new \DateTimeZone('UTC'))) + ->getQuery() + ->getResult(); + } + + /** + * @return array + * @throws \Exception + */ public function getOnGoing(): array { return $this->getEntityManager()->createQueryBuilder() diff --git a/app/Repositories/Summit/DoctrineSummitRoomReservationRepository.php b/app/Repositories/Summit/DoctrineSummitRoomReservationRepository.php index c705e263..8df0fba4 100644 --- a/app/Repositories/Summit/DoctrineSummitRoomReservationRepository.php +++ b/app/Repositories/Summit/DoctrineSummitRoomReservationRepository.php @@ -167,11 +167,14 @@ final class DoctrineSummitRoomReservationRepository ->createQueryBuilder() ->select("e") ->from($this->getBaseEntity(), "e") - ->where("e.payment_gateway_cart_id = payment_gateway_cart_id"); + ->where("e.payment_gateway_cart_id = :payment_gateway_cart_id"); $query->setParameter("payment_gateway_cart_id", trim($payment_gateway_cart_id)); - return $query->getQuery()->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE)->getOneOrNullResult(); + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getOneOrNullResult(); } /** diff --git a/app/Repositories/Summit/DoctrineSummitTaxTypeRepository.php b/app/Repositories/Summit/DoctrineSummitTaxTypeRepository.php new file mode 100644 index 00000000..2e57212c --- /dev/null +++ b/app/Repositories/Summit/DoctrineSummitTaxTypeRepository.php @@ -0,0 +1,79 @@ +findOneBy([ + 'name' => trim($name) + ]); + } + + /** + * @param string $tax_id + * @return SummitTaxType|null + */ + public function getByTaxID(string $tax_id): ?SummitTaxType + { + return $this->findOneBy([ + 'tax_id' => trim($tax_id) + ]); + } + + /** + * @return array + */ + protected function getFilterMappings() + { + return [ + 'name' => 'e.name:json_string', + 'summit_id' => new DoctrineLeftJoinFilterMapping("e.summit", "s" ,"s.id :operator :value") + ]; + } + + /** + * @return array + */ + protected function getOrderMappings() + { + return [ + 'id' => 'e.id', + 'name' => 'e.name', + ]; + } +} \ No newline at end of file diff --git a/app/Repositories/Summit/DoctrineSummitTicketTypeRepository.php b/app/Repositories/Summit/DoctrineSummitTicketTypeRepository.php index 55b7ff94..748654f6 100644 --- a/app/Repositories/Summit/DoctrineSummitTicketTypeRepository.php +++ b/app/Repositories/Summit/DoctrineSummitTicketTypeRepository.php @@ -112,4 +112,48 @@ final class DoctrineSummitTicketTypeRepository $data ); } + + /** + * @param Summit $summit + * @param array $ids + * @return SummitTicketType[] + */ + public function getByIdsExclusiveLock(Summit $summit, array $ids) + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from(SummitTicketType::class, "e") + ->leftJoin('e.summit', 's') + ->where("s.id = :summit_id") + ->andWhere("e.id in (:ticket_ids)"); + + $query->setParameter("summit_id", $summit->getId()); + $query->setParameter("ticket_ids", $ids); + return $query->getQuery() + ->setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE) + ->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true) + ->getResult(); + } + + /** + * @param Summit $summit + * @param string $type + * @return SummitTicketType|null + */ + public function getByType(Summit $summit, string $type): ?SummitTicketType + { + $query = $this->getEntityManager() + ->createQueryBuilder() + ->select("e") + ->from(SummitTicketType::class, "e") + ->leftJoin('e.summit', 's') + ->where("s.id = :summit_id") + ->andWhere("e.name = :type"); + + $query->setParameter("summit_id", $summit->getId()); + $query->setParameter("type", $type); + + return $query->getQuery()->getOneOrNullResult(); + } } \ No newline at end of file diff --git a/app/Security/SummitScopes.php b/app/Security/SummitScopes.php index d863cba4..b68ac607 100644 --- a/app/Security/SummitScopes.php +++ b/app/Security/SummitScopes.php @@ -34,6 +34,9 @@ final class SummitScopes const AddMyScheduleShareable = '%s/me/summits/events/schedule/shareable/add'; const DeleteMyScheduleShareable = '%s/me/summits/events/schedule/shareable/delete'; const SendMyScheduleMail = '%s/me/summits/events/schedule/mail'; + const EnterEvent = '%s/me/summits/events/enter'; + const LeaveEvent = '%s/me/summits/events/leave'; + // registration const CreateRegistrationOrders = '%s/summits/registration-orders/create'; @@ -50,7 +53,11 @@ final class SummitScopes const ReadBadgeScan = '%s/summits/badge-scans/read'; const ReadMyBadgeScan = '%s/summits/badge-scans/read/me'; const WriteRegistrationData = '%s/summits/registration/write'; - + const ReadPaymentProfiles = '%s/summits/payment-gateway-profiles/read'; + const WritePaymentProfiles = '%s/summits/payment-gateway-profiles/write'; + const WriteRegistrationInvitations = '%s/summits/registration-invitations/write'; + const ReadRegistrationInvitations = '%s/summits/registration-invitations/read'; + const ReadMyRegistrationInvitations = '%s/summits/registration-invitations/read/me'; // bookable rooms const ReadBookableRoomsData = '%s/bookable-rooms/read'; const WriteMyBookableRoomsReservationData = '%s/bookable-rooms/my-reservations/write'; @@ -91,4 +98,10 @@ final class SummitScopes const WriteTagsData = '%s/tags/write'; const ReadTagsData = '%s/tags/read'; + + const ReadSummitAdminGroups = '%s/summit-administrator-groups/read'; + const WriteSummitAdminGroups = '%s/summit-administrator-groups/write'; + + const ReadSummitMediaFileTypes = '%s/summit-media-file-types/read'; + const WriteSummitMediaFileTypes = '%s/summit-media-file-types/write'; } \ No newline at end of file diff --git a/app/Services/Apis/AbstractExternalFeed.php b/app/Services/Apis/AbstractExternalFeed.php new file mode 100644 index 00000000..a9d2eb1d --- /dev/null +++ b/app/Services/Apis/AbstractExternalFeed.php @@ -0,0 +1,82 @@ +client = $client; + $this->summit = $summit; + } + + /** + * @param string $url + * @return array + * @throws Exception + */ + protected function get(string $url):array { + try { + $response = $this->client->get($url); + + if ($response->getStatusCode() !== 200) + throw new Exception('invalid status code!'); + + $json = $response->getBody()->getContents(); + Log::debug(sprintf("AbstractExternalFeed get from %s - %s", $url, $json)); + $res = json_decode($json, true); + return $res ?? []; + } + catch(RequestException $ex){ + Log::warning($ex->getMessage()); + throw $ex; + } + } + + /** + * @param null|string $content + * @return string + */ + public static function convert2UTF8(?string $content):string{ + if(empty($content)) return ''; + if(!mb_check_encoding($content, 'UTF-8') + OR !($content === mb_convert_encoding(mb_convert_encoding($content, 'UTF-32', 'UTF-8' ), 'UTF-8', 'UTF-32'))) { + $content = mb_convert_encoding($content, 'UTF-8'); + } + return $content; + } + +} \ No newline at end of file diff --git a/app/Services/Apis/AbstractOAuth2Api.php b/app/Services/Apis/AbstractOAuth2Api.php new file mode 100644 index 00000000..7af912ae --- /dev/null +++ b/app/Services/Apis/AbstractOAuth2Api.php @@ -0,0 +1,114 @@ +cacheService = $cacheService; + } + + const SkewTime = 60; + const AccessTokenCacheKey = '%s_OAUTH2_ACCESS_TOKEN'; + + public abstract function getAppName():string; + + public function getIdpConfig():array { + return [ + 'authorization_endpoint' => Config::get("idp.authorization_endpoint"), + 'token_endpoint' => Config::get("idp.token_endpoint"), + ]; + } + + /** + * @return array + */ + public abstract function getAppConfig():array; + + /** + * @return GenericProvider + */ + private function getIDPClient():GenericProvider { + return OAuth2ClientFactory::build + ( + $this->getIdpConfig(), + $this->getAppConfig() + ); + } + + /** + * @return string + */ + private function getAccessTokenCacheKey():string{ + return sprintf(self::AccessTokenCacheKey, $this->getAppName()); + } + + /** + * @return string|null + * @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException + */ + protected function getAccessToken():?string{ + Log::debug("AbstractOAuth2Api::getAccessToken"); + $token = $this->cacheService->getSingleValue($this->getAccessTokenCacheKey()); + if (empty($token)) { + try { + Log::debug("AbstractOAuth2Api::getAccessToken - access token is empty, getting new one"); + $client = $this->getIDPClient(); + $appConfig = $this->getAppConfig(); + $scopes = $appConfig['scopes'] ?? []; + Log::debug(sprintf( "AbstractOAuth2Api::getAccessToken - got scopes %s", $scopes)); + // Try to get an access token using the client credentials grant. + $accessToken = $client->getAccessToken('client_credentials', ['scope' => $scopes]); + $token = $accessToken->getToken(); + $expires_in = $accessToken->getExpires() - time(); + Log::debug(sprintf("AbstractOAuth2Api::getAccessToken - setting new access token %s expires in %s", $token, $expires_in)); + $ttl = $expires_in - self::SkewTime; + if($ttl < 0) + $ttl = $expires_in; + if($ttl > 0) { + Log::debug(sprintf("AbstractOAuth2Api::getAccessToken ttl %s", $ttl)); + $this->cacheService->setSingleValue($this->getAccessTokenCacheKey(), $token, $ttl); + } + } + catch (ClientException $ex){ + Log::warning($ex); + if($ex->getCode() == 401) { + // invalid token + $this->cacheService->delete($this->getAccessTokenCacheKey()); + } + throw $ex; + } + } + return $token; + } +} \ No newline at end of file diff --git a/app/Services/Apis/EventbriteAPI.php b/app/Services/Apis/EventbriteAPI.php index 8fe2cc86..85c1a2ff 100644 --- a/app/Services/Apis/EventbriteAPI.php +++ b/app/Services/Apis/EventbriteAPI.php @@ -50,7 +50,6 @@ final class EventbriteAPI implements IEventbriteAPI $client = new Client(); $query = [ - 'token' => $this->auth_info['token'] ]; diff --git a/app/Services/Apis/ExternalRegistrationFeeds/ExternalRegistrationFeedFactory.php b/app/Services/Apis/ExternalRegistrationFeeds/ExternalRegistrationFeedFactory.php new file mode 100644 index 00000000..429ef50d --- /dev/null +++ b/app/Services/Apis/ExternalRegistrationFeeds/ExternalRegistrationFeedFactory.php @@ -0,0 +1,40 @@ +getExternalRegistrationFeedType()){ + case ISummitExternalRegistrationFeedType::Eventbrite: + return new EventbriteRegistrationFeed($summit, $client); + break; + } + return null; + } +} \ No newline at end of file diff --git a/app/Services/Apis/ExternalRegistrationFeeds/IExternalRegistrationFeed.php b/app/Services/Apis/ExternalRegistrationFeeds/IExternalRegistrationFeed.php new file mode 100644 index 00000000..6cf1b661 --- /dev/null +++ b/app/Services/Apis/ExternalRegistrationFeeds/IExternalRegistrationFeed.php @@ -0,0 +1,26 @@ +summit->getExternalRegistrationFeedApiKey(); + $eventId = $this->summit->getExternalSummitId(); + + if (empty($apiFeedKey)) { + Log::warning(sprintf("external_registration_feed_api_key is empty for summit %s", $this->summit->getId())); + return null; + } + if (empty($eventId)) { + Log::warning(sprintf("external_summit_id is empty for summit %s", $this->summit->getId())); + return null; + } + + $api = new EventbriteAPI(); + $api->setCredentials([ + 'token' => $apiFeedKey + ]); + + return new EventbriteRegistrationFeedResponse($api->getAttendees($this->summit, $page_nbr, 'promotional_code,order,ticket_class')); + + } + catch(RequestException $ex){ + Log::warning($ex->getMessage()); + throw $ex; + } + } +} \ No newline at end of file diff --git a/app/Services/Apis/ExternalRegistrationFeeds/implementations/EventbriteRegistrationFeedResponse.php b/app/Services/Apis/ExternalRegistrationFeeds/implementations/EventbriteRegistrationFeedResponse.php new file mode 100644 index 00000000..f1897fdc --- /dev/null +++ b/app/Services/Apis/ExternalRegistrationFeeds/implementations/EventbriteRegistrationFeedResponse.php @@ -0,0 +1,70 @@ +position = 0; + $this->data = $data; + + if(isset($data['attendees'])) + $this->attendees = $data['attendees']; + } + + public function rewind() { + $this->position = 0; + } + + public function current() { + return $this->attendees[$this->position]; + } + + public function key() { + return $this->position; + } + + public function next() { + ++$this->position; + } + + public function valid() { + return isset($this->attendees[$this->position]); + } + + public function hasData(): bool + { + if (!isset($this->data ['pagination'])) return false; + if (!isset($this->data ['attendees'])) return false; + return true; + } + + public function hasMoreItems(): bool + { + if (!isset($this->data['pagination'])) return false; + $pagination = $this->data['pagination']; + return boolval($pagination['has_more_items']); + } +} \ No newline at end of file diff --git a/app/Services/Apis/ExternalScheduleFeeds/AbstractExternalScheduleFeed.php b/app/Services/Apis/ExternalScheduleFeeds/AbstractExternalScheduleFeed.php index 2a4edd42..17037b09 100644 --- a/app/Services/Apis/ExternalScheduleFeeds/AbstractExternalScheduleFeed.php +++ b/app/Services/Apis/ExternalScheduleFeeds/AbstractExternalScheduleFeed.php @@ -11,74 +11,15 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -use Exception; -use GuzzleHttp\ClientInterface; -use GuzzleHttp\Exception\RequestException; -use Illuminate\Support\Facades\Log; -use models\summit\Summit; +use App\Services\Apis\AbstractExternalFeed; /** * Class AbstractExternalScheduleFeed * @package App\Services\Apis\ExternalScheduleFeeds */ -abstract class AbstractExternalScheduleFeed implements IExternalScheduleFeed +abstract class AbstractExternalScheduleFeed extends AbstractExternalFeed implements IExternalScheduleFeed { const CHARS_TO_REMOVE = array("-", "_"); - /** - * @var ClientInterface - */ - protected $client; - - /** - * @var Summit - */ - protected $summit; - - /** - * AbstractExternalScheduleFeed constructor. - * @param ClientInterface $client - * @param Summit $summit - */ - public function __construct(Summit $summit, ClientInterface $client) - { - $this->client = $client; - $this->summit = $summit; - } - - /** - * @param string $url - * @return array - * @throws Exception - */ - protected function get(string $url):array { - try { - $response = $this->client->get($url); - - if ($response->getStatusCode() !== 200) - throw new Exception('invalid status code!'); - - $json = $response->getBody()->getContents(); - return json_decode($json, true); - } - catch(RequestException $ex){ - Log::warning($ex->getMessage()); - throw $ex; - } - } - - /** - * @param null|string $content - * @return string - */ - public static function convert2UTF8(?string $content):string{ - if(empty($content)) return ''; - if(!mb_check_encoding($content, 'UTF-8') - OR !($content === mb_convert_encoding(mb_convert_encoding($content, 'UTF-32', 'UTF-8' ), 'UTF-8', 'UTF-32'))) { - $content = mb_convert_encoding($content, 'UTF-8'); - } - return $content; - } abstract public function getDefaultSpeakerEmail(string $speakerFullName):string; - } \ No newline at end of file diff --git a/app/Services/Apis/ExternalScheduleFeeds/ExternalScheduleFeedFactory.php b/app/Services/Apis/ExternalScheduleFeeds/ExternalScheduleFeedFactory.php index c820e1cb..8ae5ee8e 100644 --- a/app/Services/Apis/ExternalScheduleFeeds/ExternalScheduleFeedFactory.php +++ b/app/Services/Apis/ExternalScheduleFeeds/ExternalScheduleFeedFactory.php @@ -14,6 +14,7 @@ use models\summit\Summit; use GuzzleHttp\ClientInterface; use Illuminate\Support\Facades\App; +use App\Models\Foundation\Summit\ISummitExternalScheduleFeedType; /** * Class ExternalScheduleFeedFactory * @package App\Services\Apis\ExternalScheduleFeeds @@ -29,9 +30,9 @@ final class ExternalScheduleFeedFactory implements IExternalScheduleFeedFactory { $client = App::make(ClientInterface::class); switch ($summit->getApiFeedType()){ - case IExternalScheduleFeedFactory::SchedType: + case ISummitExternalScheduleFeedType::SchedType: return new SchedScheduleFeed($summit, $client); - case IExternalScheduleFeedFactory::VanderpoelType: + case ISummitExternalScheduleFeedType::VanderpoelType: return new VanderpoelScheduleFeed($summit, $client); } return null; diff --git a/app/Services/Apis/ExternalScheduleFeeds/IExternalScheduleFeedFactory.php b/app/Services/Apis/ExternalScheduleFeeds/IExternalScheduleFeedFactory.php index 23c95a01..b9a24e9a 100644 --- a/app/Services/Apis/ExternalScheduleFeeds/IExternalScheduleFeedFactory.php +++ b/app/Services/Apis/ExternalScheduleFeeds/IExternalScheduleFeedFactory.php @@ -18,10 +18,6 @@ use models\summit\Summit; */ interface IExternalScheduleFeedFactory { - const NoneType = ''; - const VanderpoelType = 'Vanderpoel'; - const SchedType = 'Sched'; - /** * @param Summit $summit * @return IExternalScheduleFeed|null diff --git a/app/Services/Apis/ExternalUserApi.php b/app/Services/Apis/ExternalUserApi.php new file mode 100644 index 00000000..5403a36e --- /dev/null +++ b/app/Services/Apis/ExternalUserApi.php @@ -0,0 +1,183 @@ +client = new Client([ + 'base_uri' => Config::get('idp.base_url') ?? '', + 'timeout' => Config::get('curl.timeout', 60), + 'allow_redirects' => Config::get('curl.allow_redirects', false), + 'verify' => Config::get('curl.verify_ssl_cert', true), + ]); + } + + /** + * @param string $email + * @return null|mixed + * @throws Exception + */ + public function getUserByEmail(string $email) + { + try { + Log::debug(sprintf("ExternalUserApi::getUserByEmail email %s", $email)); + + $query = [ + 'access_token' => $this->getAccessToken() + ]; + + $params = [ + 'filter' => 'email==' . $email + ]; + + foreach ($params as $param => $value) { + $query[$param] = $value; + } + + $response = $this->client->get('/api/v1/users', [ + 'query' => $query, + ] + ); + + $data = json_decode($response->getBody()->getContents(), true); + + return intval($data['total']) > 0 ? $data['data'][0] : null; + } + catch (Exception $ex) { + Log::error($ex); + throw $ex; + } + } + + /** + * @param string $email + * @param string $first_name + * @param string $last_name + * @return mixed + * @throws Exception + */ + public function registerUser(string $email, ?string $first_name, ?string $last_name) + { + Log::debug(sprintf("ExternalUserApi::registerUser email %s first_name %s last_name %s", $email, $first_name, $last_name)); + + try { + $query = [ + 'access_token' => $this->getAccessToken() + ]; + + if(empty($email)) + throw new ValidationException("Email field es required."); + + if(empty($first_name)) + throw new ValidationException("First Name field es required."); + + if(empty($last_name)) + throw new ValidationException("Last Name field es required."); + + $response = $this->client->post('/api/v1/user-registration-requests', [ + 'query' => $query, + RequestOptions::JSON => [ + 'email' => $email, + 'first_name' => $first_name, + 'last_name' => $last_name, + ] + ] + ); + + return json_decode($response->getBody()->getContents(), true); + } catch (Exception $ex) { + Log::error($ex); + throw $ex; + } + } + + const AppName = 'REGISTRATION_SERVICE'; + + /** + * @return string + */ + public function getAppName(): string + { + return self::AppName; + } + + /** + * @return array + */ + public function getAppConfig(): array + { + return [ + 'client_id' => Config::get("registration.service_client_id"), + 'client_secret' => Config::get("registration.service_client_secret"), + 'scopes' => Config::get("registration.service_client_scopes") + ]; + } + + /** + * @param int $id + * @return mixed|null + * @throws Exception + */ + public function getUserById(int $id) + { + try { + Log::debug(sprintf("ExternalUserApi::getUserById id %s", $id)); + + $query = [ + 'access_token' => $this->getAccessToken() + ]; + + $response = $this->client->get(sprintf('/api/v1/users/%s', $id), [ + 'query' => $query, + ] + ); + + return json_decode($response->getBody()->getContents(), true); + } + catch (Exception $ex) { + Log::error($ex); + throw $ex; + } + } +} + diff --git a/app/Services/Apis/IExternalUserApi.php b/app/Services/Apis/IExternalUserApi.php new file mode 100644 index 00000000..36bd47cf --- /dev/null +++ b/app/Services/Apis/IExternalUserApi.php @@ -0,0 +1,43 @@ +client = new Client([ + 'base_uri' => Config::get('mail.service_base_url') ?? '', + 'timeout' => Config::get('curl.timeout', 60), + 'allow_redirects' => Config::get('curl.allow_redirects', false), + 'verify' => Config::get('curl.verify_ssl_cert', true), + ]); + } + + /** + * @return array + */ + public function getAppConfig(): array + { + return [ + 'client_id' => Config::get("mail.service_client_id"), + 'client_secret' => Config::get("mail.service_client_secret"), + 'scopes' => Config::get("mail.service_client_scopes") + ]; + } + + /** + * @param array $payload + * @param string $template_identifier + * @param string $to_email + * @param string|null $subject + * @return array + * @throws \Exception + */ + public function sendEmail(array $payload, string $template_identifier, string $to_email, string $subject = null): array + { + + Log::debug + ( + sprintf + ( + "MailApi::sendEmail template_identifier %s to_email %s payload %s", + $template_identifier, + $to_email, + json_encode($payload) + ) + ); + + try { + if(empty($to_email)) + throw new ValidationException("to_email field es required."); + + if(empty($template_identifier)) + throw new ValidationException("template_identifier field es required."); + + $query = [ + 'access_token' => $this->getAccessToken() + ]; + + $response = $this->client->post('/api/v1/mails', [ + 'query' => $query, + RequestOptions::JSON => [ + 'payload' => $payload, + 'template' => $template_identifier, + 'to_email' => $to_email + ] + ] + ); + + $body = $response->getBody()->getContents(); + Log::debug + ( + sprintf + ( + "MailApi::sendEmail template_identifier %s to_email %s body %s", + $template_identifier, + $to_email, + $body + ) + ); + return json_decode($body, true); + + } catch (\Exception $ex) { + Log::error($ex); + throw $ex; + } + } +} \ No newline at end of file diff --git a/app/Services/Apis/PaymentGateways/StripeApi.php b/app/Services/Apis/PaymentGateways/StripeApi.php index e798e437..4838fcbf 100644 --- a/app/Services/Apis/PaymentGateways/StripeApi.php +++ b/app/Services/Apis/PaymentGateways/StripeApi.php @@ -11,88 +11,110 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\Services\Apis\CartAlreadyPaidException; use App\Services\Apis\IPaymentGatewayAPI; use Illuminate\Http\Request as LaravelRequest; use models\exceptions\ValidationException; use Stripe\Charge; +use Stripe\Error\InvalidRequest; use Stripe\Error\SignatureVerification; use Stripe\Event; use Stripe\Stripe; use Stripe\PaymentIntent; use Stripe\WebhookSignature; +use Stripe\WebhookEndpoint; use Illuminate\Support\Facades\Log; + /** * Class StripesApi * @package App\Services\Apis\PaymentGateways */ final class StripeApi implements IPaymentGatewayAPI { - /** - * @var string - */ - private $api_key; + const Version = '2019-12-03'; /** * @var string */ - private $webhook_secret; + private $secret_key; + + /** + * @var string + */ + private $webhook_secret_key; /** * StripeApi constructor. - * @param string $api_key - * @param string $webhook_secret + * @param array $config */ - public function __construct(?string $api_key, ?string $webhook_secret) + public function __construct(array $config) { - $this->api_key = $api_key; - $this->webhook_secret = $webhook_secret; + $this->secret_key = $config['secret_key'] ?? null; + $this->webhook_secret_key = $config['webhook_secret_key'] ?? null; + + Log::debug + ( + sprintf + ( + "StripeApi::__construct secret_key %s webhook_secret_key %s", + $this->secret_key, + $this->webhook_secret_key + ) + ); + } + + /** + * @param string $webhook_secret_key + */ + public function setWebHookSecretKey(string $webhook_secret_key):void{ + $this->webhook_secret_key = $webhook_secret_key; } /** * @param array $payload * @return array */ - public function generatePayment(array $payload):array + public function generatePayment(array $payload): array { - if(empty($this->api_key)) + if (empty($this->secret_key)) throw new \InvalidArgumentException(); - Stripe::setApiKey($this->api_key); + Stripe::setApiKey($this->secret_key); + Stripe::setApiVersion(self::Version); - $amount = $payload['amount']; + $amount = $payload['amount']; $currency = $payload['currency']; - if(!self::isZeroDecimalCurrency($currency)){ + if (!self::isZeroDecimalCurrency($currency)) { /** * All API requests expect amounts to be provided in a currency’s smallest unit. For example, * to charge $10 USD, provide an amount value of 1000 (i.e, 1000 cents). * For zero-decimal currencies, still provide amounts as an integer but without multiplying by 100. * For example, to charge ¥500, simply provide an amount value of 500. */ - $amount = $amount * 100 ; + $amount = $amount * 100; } $request = [ - 'amount' => intval($amount), - 'currency' => $currency, + 'amount' => intval($amount), + 'currency' => $currency, + 'payment_method_types' => ['card'], ]; - if(isset($payload['receipt_email'])) - { - $request['receipt_email']= trim($payload['receipt_email']); + if (isset($payload['receipt_email'])) { + $request['receipt_email'] = trim($payload['receipt_email']); } - if(isset($payload['metadata'])) - { - $request['metadata']= $payload['metadata']; + if (isset($payload['metadata'])) { + $request['metadata'] = $payload['metadata']; } $intent = PaymentIntent::create($request); return [ - 'client_token' => $intent->client_secret, - 'cart_id' => $intent->id, + 'client_token' => $intent->client_secret, + 'cart_id' => $intent->id, ]; } @@ -101,7 +123,8 @@ final class StripeApi implements IPaymentGatewayAPI * @return bool * @see https://stripe.com/docs/currencies#zero-decimal */ - private static function isZeroDecimalCurrency(string $currency):bool{ + private static function isZeroDecimalCurrency(string $currency): bool + { $zeroDecimalCurrencies = [ 'JPY', 'BIF', @@ -134,14 +157,27 @@ final class StripeApi implements IPaymentGatewayAPI { try { - WebhookSignature::verifyHeader( - $request->getContent(), - $request->header('Stripe-Signature'), - $this->webhook_secret + $signature = $request->header('Stripe-Signature'); + $requestContent = $request->getContent(); + Log::debug + ( + sprintf + ( + "StripeApi::processCallback Stripe-Signature %s requestContent %s webHook Secret %s", + $signature, + $requestContent, + $this->webhook_secret_key + ) ); - $event = Event::constructFrom(json_decode($request->getContent(), true)); - if(!in_array($event->type, ["payment_intent.succeeded", "payment_intent.payment_failed"])) + WebhookSignature::verifyHeader( + $requestContent, + $signature, + $this->webhook_secret_key + ); + + $event = Event::constructFrom(json_decode($requestContent, true)); + if (!in_array($event->type, ["payment_intent.succeeded", "payment_intent.payment_failed"])) throw new \InvalidArgumentException(); $intent = $event->data->object; @@ -149,7 +185,7 @@ final class StripeApi implements IPaymentGatewayAPI Log::debug("StripeApi::processCallback: payment_intent.succeeded"); return [ "event_type" => $event->type, - "cart_id" => $intent->id, + "cart_id" => $intent->id, ]; } @@ -158,25 +194,22 @@ final class StripeApi implements IPaymentGatewayAPI $intent = $event->data->object; return [ "event_type" => $event->type, - "cart_id" => $intent->id, + "cart_id" => $intent->id, "error" => [ "last_payment_error" => $intent->last_payment_error, - "message" => $intent->last_payment_error->message + "message" => $intent->last_payment_error->message ] ]; } throw new ValidationException(sprintf("event type %s not handled!", $event->type)); - } - catch(\UnexpectedValueException $e) { + } catch (\UnexpectedValueException $e) { // Invalid payload - throw $e; - } - catch(SignatureVerification $e) { + throw $e; + } catch (SignatureVerification $e) { // Invalid signature throw $e; - } - catch (\Exception $e){ + } catch (\Exception $e) { throw $e; } } @@ -187,7 +220,7 @@ final class StripeApi implements IPaymentGatewayAPI */ public function isSuccessFullPayment(array $payload): bool { - if(isset($payload['event_type']) && $payload['event_type'] == "payment_intent.succeeded") return true; + if (isset($payload['event_type']) && $payload['event_type'] == "payment_intent.succeeded") return true; Log::debug("StripeApi::isSuccessFullPayment false"); return false; } @@ -198,10 +231,10 @@ final class StripeApi implements IPaymentGatewayAPI */ public function getPaymentError(array $payload): ?string { - if(isset($payload['event_type']) && $payload['event_type'] == "payment_intent.payment_failed"){ - if(isset($payload['error'])) { + if (isset($payload['event_type']) && $payload['event_type'] == "payment_intent.payment_failed") { + if (isset($payload['error'])) { $error = $payload['error']; - if(isset($error["message"])) { + if (isset($error["message"])) { return $error["message"]; } } @@ -217,22 +250,24 @@ final class StripeApi implements IPaymentGatewayAPI */ public function refundPayment(string $cart_id, float $amount, string $currency): void { - if(empty($this->api_key)) + if (empty($this->secret_key)) throw new \InvalidArgumentException(); - Stripe::setApiKey($this->api_key); + Stripe::setApiKey($this->secret_key); + Stripe::setApiVersion(self::Version); + $intent = PaymentIntent::retrieve($cart_id); - if(is_null($intent)) + if (is_null($intent)) throw new \InvalidArgumentException(); - if(count($intent->charges->data) == 0) + if (count($intent->charges->data) == 0) throw new \InvalidArgumentException("this intent payment has no charges"); $charge = $intent->charges->data[0]; - if(!$charge instanceof Charge) + if (!$charge instanceof Charge) throw new \InvalidArgumentException(); $params = []; - if($amount > 0 ){ - if(!self::isZeroDecimalCurrency($currency)){ + if ($amount > 0) { + if (!self::isZeroDecimalCurrency($currency)) { /** * All API requests expect amounts to be provided in a currency’s smallest unit. For example, * to charge $10 USD, provide an amount value of 1000 (i.e, 1000 cents). @@ -254,19 +289,24 @@ final class StripeApi implements IPaymentGatewayAPI */ public function abandonCart(string $cart_id) { - if(empty($this->api_key)) + if (empty($this->secret_key)) throw new \InvalidArgumentException(); - Stripe::setApiKey($this->api_key); + Stripe::setApiKey($this->secret_key); + Stripe::setApiVersion(self::Version); + $intent = PaymentIntent::retrieve($cart_id); - if(is_null($intent)) + if (is_null($intent)) throw new \InvalidArgumentException(); - if(!in_array($intent->status,[ PaymentIntent::STATUS_REQUIRES_PAYMENT_METHOD, + if (!in_array($intent->status, [ + PaymentIntent::STATUS_REQUIRES_PAYMENT_METHOD, PaymentIntent::STATUS_REQUIRES_CAPTURE, PaymentIntent::STATUS_REQUIRES_CONFIRMATION, - PaymentIntent::STATUS_REQUIRES_ACTION + PaymentIntent::STATUS_REQUIRES_ACTION, + "requires_source", + "requires_source_action", ])) throw new CartAlreadyPaidException(sprintf("cart id %s has status %s", $cart_id, $intent->status)); @@ -279,11 +319,13 @@ final class StripeApi implements IPaymentGatewayAPI */ public function canAbandon(string $status): bool { - return in_array($status,[ + return in_array($status, [ PaymentIntent::STATUS_REQUIRES_PAYMENT_METHOD, PaymentIntent::STATUS_REQUIRES_CAPTURE, PaymentIntent::STATUS_REQUIRES_CONFIRMATION, - PaymentIntent::STATUS_REQUIRES_ACTION + PaymentIntent::STATUS_REQUIRES_ACTION, + "requires_source", + "requires_source_action", ]); } @@ -291,25 +333,88 @@ final class StripeApi implements IPaymentGatewayAPI * @param string $status * @return bool */ - public function isSucceeded(string $status):bool { + public function isSucceeded(string $status): bool + { return $status == PaymentIntent::STATUS_SUCCEEDED; } /** * @param string $cart_id - * @return string + * @return string|null */ - public function getCartStatus(string $cart_id): string + public function getCartStatus(string $cart_id): ?string { - if(empty($this->api_key)) + + if (empty($this->secret_key)) throw new \InvalidArgumentException(); - Stripe::setApiKey($this->api_key); - $intent = PaymentIntent::retrieve($cart_id); + Stripe::setApiKey($this->secret_key); + Stripe::setApiVersion(self::Version); - if(is_null($intent)) + try { + $intent = PaymentIntent::retrieve($cart_id); + + if (is_null($intent)) + throw new \InvalidArgumentException(); + + return $intent->status; + } + catch(InvalidRequest $ex){ + Log::warning(sprintf("StripeApi::getCartStatus cart_id %s code %s message %s", $cart_id, $ex->getCode(), $ex->getMessage())); + return null; + } + } + + /** + * @param string $webhook_endpoint_url + * @return array + */ + public function createWebHook(string $webhook_endpoint_url): array + { + if (empty($this->secret_key)) throw new \InvalidArgumentException(); - return $intent->status; + Stripe::setApiKey($this->secret_key); + Stripe::setApiVersion(self::Version); + + $res = WebhookEndpoint::create([ + 'url' => $webhook_endpoint_url, + 'enabled_events' => [ + 'payment_intent.succeeded', + 'payment_intent.payment_failed', + ], + ]); + + return [ + 'id' => $res->id, + 'secret' => $res->secret, + 'livemode' => $res->livemode + ]; + } + + /** + * @param string $id + * @return WebhookEndpoint + */ + public function getWebHookById(string $id){ + + if (empty($this->secret_key)) + throw new \InvalidArgumentException(); + + Stripe::setApiKey($this->secret_key); + Stripe::setApiVersion(self::Version); + + return WebhookEndpoint::retrieve($id); + } + + /** + * @param string $id + * @return void + */ + public function deleteWebHookById(string $id):void{ + + $webhook = $this->getWebHookById($id); + if(!$webhook) return; + $webhook->delete(); } } \ No newline at end of file diff --git a/app/Services/Auth/OAuth2ClientFactory.php b/app/Services/Auth/OAuth2ClientFactory.php new file mode 100644 index 00000000..6e3aaced --- /dev/null +++ b/app/Services/Auth/OAuth2ClientFactory.php @@ -0,0 +1,59 @@ + $client_id, + 'clientSecret' => $client_secret, + 'redirectUri' => $redirectUri, + 'urlAuthorize' => $idpConfig['authorization_endpoint'] ?? '', + 'urlAccessToken' => $idpConfig['token_endpoint'] ?? '', + 'urlResourceOwnerDetails' => "", + 'scopes' => $scopes, + ]); + + $provider->setHttpClient( + new Client([ + 'timeout' => Config::get('curl.timeout', 60), + 'allow_redirects' => Config::get('curl.allow_redirects', false), + 'verify' => Config::get('curl.verify_ssl_cert', true), + ]) + ); + return $provider; + } +} \ No newline at end of file diff --git a/app/Services/BaseServicesProvider.php b/app/Services/BaseServicesProvider.php new file mode 100644 index 00000000..b8794044 --- /dev/null +++ b/app/Services/BaseServicesProvider.php @@ -0,0 +1,141 @@ +setCredentials(array('token' => Config::get("server.eventbrite_oauth2_personal_token", null))); + return $api; + }); + + App::singleton(IPushNotificationApi::class, function(){ + $api = new FireBaseGCMApi(Config::get("server.firebase_gcm_server_key", null)); + return $api; + }); + + App::singleton(IGeoCodingAPI::class, function(){ + return new GoogleGeoCodingAPI + ( + Config::get("server.google_geocoding_api_key", null) + ); + }); + + App::singleton( + IExternalUserApi::class, + ExternalUserApi::class + ); + + App::singleton + ( + IFolderService::class, + FolderService::class + ); + + App::singleton( + IMailApi::class, + MailApi::class + ); + + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return [ + ClientInterface::class, + ICacheService::class, + IPermissionsManager::class, + ITransactionService::class, + ISerializerTypeSelector::class, + IEncryptionService::class, + IEventbriteAPI::class, + IPushNotificationApi::class, + IGeoCodingAPI::class, + IExternalUserApi::class, + IFolderService::class + ]; + } +} \ No newline at end of file diff --git a/app/Services/FileSystem/Dropbox/DropboxServiceProvider.php b/app/Services/FileSystem/Dropbox/DropboxServiceProvider.php new file mode 100644 index 00000000..fe2f3f27 --- /dev/null +++ b/app/Services/FileSystem/Dropbox/DropboxServiceProvider.php @@ -0,0 +1,49 @@ +download( + $path, + $name, + $options + ); + } + + /** + * @inheritDoc + */ + public function getUrl(string $relativeFileName): ?string + { + return Storage::disk('dropbox')->url($relativeFileName); + } + + /** + * @inheritDoc + */ + public function delete(string $relativeFileName) + { + return Storage::disk('dropbox')->delete($relativeFileName); + } +} diff --git a/app/Services/FileSystem/Dropbox/DropboxStorageFileUploadStrategy.php b/app/Services/FileSystem/Dropbox/DropboxStorageFileUploadStrategy.php new file mode 100644 index 00000000..385a5f78 --- /dev/null +++ b/app/Services/FileSystem/Dropbox/DropboxStorageFileUploadStrategy.php @@ -0,0 +1,31 @@ +putFileAs($path, $file, $filename); + } +} diff --git a/app/Services/FileSystem/FileDownloadStrategyFactory.php b/app/Services/FileSystem/FileDownloadStrategyFactory.php new file mode 100644 index 00000000..f08c18ef --- /dev/null +++ b/app/Services/FileSystem/FileDownloadStrategyFactory.php @@ -0,0 +1,42 @@ + '-', // remove whitespace + '/_/' => '-', // underscores to dashes + '/[^A-Za-z0-9+.\-]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot + '/[\-]{2,}/' => '-', // remove duplicate dashes + '/^[\.\-_]+/' => '', // Remove all leading dots, dashes or underscores + ]; + + /** + * @param string $filename + * @return string + */ + public static function sanitize(string $filename):string { + $filename = trim(Transliterator::utf8ToAscii($filename)); + foreach(self::$default_replacements as $regex => $replace) { + $filename = preg_replace($regex, $replace, $filename); + } + return $filename; + } +} \ No newline at end of file diff --git a/app/Services/FileSystem/FileUploadStrategyFactory.php b/app/Services/FileSystem/FileUploadStrategyFactory.php new file mode 100644 index 00000000..a9a4ad06 --- /dev/null +++ b/app/Services/FileSystem/FileUploadStrategyFactory.php @@ -0,0 +1,42 @@ +download($path, $name, $options); + } + + /** + * @inheritDoc + */ + public function getUrl(string $relativeFileName): ?string + { + return Storage::disk('local')->url($relativeFileName); + } + + /** + * @inheritDoc + */ + public function delete(string $relativeFileName) + { + return Storage::disk('local')->delete($relativeFileName); + } +} diff --git a/app/Services/FileSystem/Local/LocalStorageFileUploadStrategy.php b/app/Services/FileSystem/Local/LocalStorageFileUploadStrategy.php new file mode 100644 index 00000000..8fe812e6 --- /dev/null +++ b/app/Services/FileSystem/Local/LocalStorageFileUploadStrategy.php @@ -0,0 +1,34 @@ +putFileAs($path, $file, $filename); + } +} diff --git a/app/Services/FileSystem/Swift/SwiftAdapter.php b/app/Services/FileSystem/Swift/SwiftAdapter.php new file mode 100644 index 00000000..2e2ba58a --- /dev/null +++ b/app/Services/FileSystem/Swift/SwiftAdapter.php @@ -0,0 +1,360 @@ +setPathPrefix($prefix); + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function write($path, $contents, Config $config, $size = 0) + { + $path = $this->applyPathPrefix($path); + + $data = $this->getWriteData($path, $config); + $type = 'content'; + + if (is_a($contents, 'GuzzleHttp\Psr7\Stream')) { + $type = 'stream'; + } + + $data[$type] = $contents; + + // Create large object if the stream is larger than 300 MiB (default). + if ($type === 'stream' && $size > $config->get('swiftLargeObjectThreshold', 314572800)) { + // Set the segment size to 100 MiB by default as suggested in OVH docs. + $data['segmentSize'] = $config->get('swiftSegmentSize', 104857600); + // Set segment container to the same container by default. + $data['segmentContainer'] = $config->get('swiftSegmentContainer', $this->container->name); + + $response = $this->container->createLargeObject($data); + } else { + $response = $this->container->createObject($data); + } + + return $this->normalizeObject($response); + } + + /** + * {@inheritdoc} + */ + public function writeStream($path, $resource, Config $config) + { + return $this->write($path, new Stream($resource), $config, fstat($resource)['size']); + } + + /** + * {@inheritdoc} + */ + public function update($path, $contents, Config $config) + { + return $this->write($path, $contents, $config); + } + + /** + * {@inheritdoc} + */ + public function updateStream($path, $resource, Config $config) + { + return $this->write($path, new Stream($resource), $config, fstat($resource)['size']); + } + + /** + * {@inheritdoc} + */ + public function rename($path, $newpath) + { + $object = $this->getObject($path); + $newLocation = $this->applyPathPrefix($newpath); + $destination = '/'.$this->container->name.'/'.ltrim($newLocation, '/'); + + try { + $response = $object->copy(compact('destination')); + } catch (BadResponseError $e) { + return false; + } + + $object->delete(); + + return true; + } + + /** + * {@inheritdoc} + */ + public function delete($path) + { + $object = $this->getObjectInstance($path); + + try { + $object->delete(); + } catch (BadResponseError $e) { + return false; + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function deleteDir($dirname) + { + $objects = $this->container->listObjects([ + 'prefix' => $this->applyPathPrefix($dirname) + ]); + + try { + foreach ($objects as $object) { + $object->containerName = $this->container->name; + $object->delete(); + } + } catch (BadResponseError $e) { + return false; + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function createDir($dirname, Config $config) + { + return ['path' => $dirname]; + } + + /** + * {@inheritdoc} + */ + public function has($path) + { + try { + $object = $this->getObject($path); + } catch (BadResponseError $e) { + $code = $e->getResponse()->getStatusCode(); + + if ($code == 404) return false; + + throw $e; + } + + return $this->normalizeObject($object); + } + + /** + * {@inheritdoc} + */ + public function read($path) + { + $object = $this->getObject($path); + $data = $this->normalizeObject($object); + + $stream = $object->download(); + $stream->rewind(); + $data['contents'] = $stream->getContents(); + + return $data; + } + + /** + * {@inheritdoc} + */ + public function readStream($path) + { + $object = $this->getObject($path); + $data = $this->normalizeObject($object); + + $stream = $object->download(); + $stream->rewind(); + $data['stream'] = StreamWrapper::getResource($stream); + + return $data; + } + + /** + * {@inheritdoc} + */ + public function listContents($directory = '', $recursive = false) + { + $location = $this->applyPathPrefix($directory); + + $objectList = $this->container->listObjects([ + 'prefix' => $directory + ]); + + $response = iterator_to_array($objectList); + + return Util::emulateDirectories(array_map([$this, 'normalizeObject'], $response)); + } + + /** + * {@inheritdoc} + */ + public function getMetadata($path) + { + $object = $this->getObject($path); + + return $this->normalizeObject($object); + } + + /** + * {@inheritdoc} + */ + public function getSize($path) + { + return $this->getMetadata($path); + } + + /** + * {@inheritdoc} + */ + public function getMimetype($path) + { + return $this->getMetadata($path); + } + + /** + * {@inheritdoc} + */ + public function getTimestamp($path) + { + return $this->getMetadata($path); + } + + /** + * Get the data properties to write or update an object. + * + * @param string $path + * @param Config $config + * + * @return array + */ + protected function getWriteData($path, $config) + { + return ['name' => $path]; + } + + /** + * Get an object instance. + * + * @param string $path + * + * @return StorageObject + */ + protected function getObjectInstance($path) + { + $location = $this->applyPathPrefix($path); + + $object = $this->container->getObject($location); + + return $object; + } + + /** + * Get an object instance and retrieve its metadata from storage. + * + * @param string $path + * + * @return StorageObject + */ + protected function getObject($path) + { + $object = $this->getObjectInstance($path); + $object->retrieve(); + + return $object; + } + + /** + * Normalize Openstack "StorageObject" object into an array + * + * @param StorageObject $object + * @return array + */ + protected function normalizeObject(StorageObject $object) + { + $name = $this->removePathPrefix($object->name); + $mimetype = explode('; ', $object->contentType); + + if ($object->lastModified instanceof \DateTimeInterface) { + $timestamp = $object->lastModified->getTimestamp(); + } else { + $timestamp = strtotime($object->lastModified); + } + + return [ + 'type' => 'file', + 'dirname' => Util::dirname($name), + 'path' => $name, + 'timestamp' => $timestamp, + 'mimetype' => reset($mimetype), + 'size' => $object->contentLength, + ]; + } + + + public function getTemporaryLink(string $path): ?string + { + return $this->getUrl($path); + } + + public function getTemporaryUrl(string $path): ?string + { + return $this->getUrl($path); + } + + public function getUrl(string $path): ?string + { + $obj = $this->container->getObject($path); + if(is_null($obj)) + return null; + $url = $obj->getPublicUri(); + Log::debug(sprintf("SwiftAdapter get Url for path %s got %s", $path, $url)); + return $url; + } +} diff --git a/app/Services/FileSystem/Swift/SwiftServiceProvider.php b/app/Services/FileSystem/Swift/SwiftServiceProvider.php new file mode 100644 index 00000000..3b7440a5 --- /dev/null +++ b/app/Services/FileSystem/Swift/SwiftServiceProvider.php @@ -0,0 +1,84 @@ + $config["auth_url"], + 'region' => $config["region"], + ]; + + $userName = $config["user_name"] ?? null; + $userPassword = $config["api_key"] ?? null; + + if(!empty($userName) && !empty($userPassword)){ + + $configOptions['user'] = [ + 'name' => $userName, + 'password' => $userPassword, + 'domain' => ['id' => $config["user_domain"] ?? 'default'] + ]; + + $configOptions['scope' ] = [ + 'project' => [ + 'name' => $config["project_name"], + 'domain' => ['id' => $config["project_domain"] ?? 'default'] + ], + ]; + } + + $appCredentialId = $config["app_credential_id"] ?? null; + $appCredentialSecret = $config["app_credential_secret"] ?? null; + + if(!empty($appCredentialId) && !empty($appCredentialSecret)){ + $configOptions['application_credential'] = [ + 'id' => $appCredentialId, + 'secret' => $appCredentialSecret, + ]; + } + + $openstackClient = new OpenStack($configOptions); + + $container = $openstackClient->objectStoreV1()->getContainer($config["container"]); + + return new Filesystem(new SwiftAdapter($container)); + }); + } +} diff --git a/app/Services/FileSystem/Swift/SwiftStorageFileDownloadStrategy.php b/app/Services/FileSystem/Swift/SwiftStorageFileDownloadStrategy.php new file mode 100644 index 00000000..ea7b9131 --- /dev/null +++ b/app/Services/FileSystem/Swift/SwiftStorageFileDownloadStrategy.php @@ -0,0 +1,49 @@ +download( + $path, + $name, + $options + ); + } + + /** + * @inheritDoc + */ + public function getUrl(string $relativeFileName): ?string + { + return Storage::disk('swift')->url($relativeFileName); + } + + /** + * @inheritDoc + */ + public function delete(string $relativeFileName) + { + return Storage::disk('swift')->delete($relativeFileName); + } +} \ No newline at end of file diff --git a/app/Services/FileSystem/Swift/SwiftStorageFileUploadStrategy.php b/app/Services/FileSystem/Swift/SwiftStorageFileUploadStrategy.php new file mode 100644 index 00000000..95a55cae --- /dev/null +++ b/app/Services/FileSystem/Swift/SwiftStorageFileUploadStrategy.php @@ -0,0 +1,34 @@ +putFileAs($path, $file, $filename); + } +} \ No newline at end of file diff --git a/app/Services/Model/AttendeeService.php b/app/Services/Model/AttendeeService.php index 7bcd4c36..09ddc048 100644 --- a/app/Services/Model/AttendeeService.php +++ b/app/Services/Model/AttendeeService.php @@ -12,6 +12,7 @@ * limitations under the License. **/ use GuzzleHttp\Exception\ClientException; +use Illuminate\Support\Facades\Log; use libs\utils\ITransactionService; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; @@ -25,7 +26,9 @@ use models\summit\ISummitRegistrationPromoCodeRepository; use models\summit\ISummitTicketTypeRepository; use models\summit\Summit; use models\summit\SummitAttendee; +use models\summit\SummitAttendeeBadge; use models\summit\SummitAttendeeTicket; +use models\summit\SummitTicketType; use services\apis\IEventbriteAPI; /** * Class AttendeeService @@ -88,28 +91,43 @@ final class AttendeeService extends AbstractService implements IAttendeeService /** * @param Summit $summit * @param array $data - * @return SummitAttendee + * @return mixed|SummitAttendee + * @throws \Exception */ public function addAttendee(Summit $summit, array $data) { return $this->tx_service->transaction(function() use($summit, $data){ - if(!isset($data['member_id'])) - throw new ValidationException("member_id is required"); + $member = null; + $member_id = $data['member_id'] ?? 0; + $member_id = intval($member_id); + $email = $data['email'] ?? null; - $member_id = intval($data['member_id']); - $member = $this->member_repository->getById($member_id); + if($member_id > 0 && !empty($email)){ + // both are defined + throw new ValidationException("you should define a member_id or an email, not both"); + } - if(is_null($member)) - throw new EntityNotFoundException("member not found"); + if($member_id > 0 ) { - // check if attendee already exist for this summit + $member = $this->member_repository->getById($member_id); + if (is_null($member) || !$member instanceof Member) + throw new EntityNotFoundException("member not found"); - $old_attendee = $this->attendee_repository->getBySummitAndMember($summit, $member); - if(!is_null($old_attendee)) - throw new ValidationException(sprintf("attendee already exist for summit id %s and member id %s", $summit->getId(), $member->getIdentifier())); + $old_attendee = $this->attendee_repository->getBySummitAndMember($summit, $member); - $attendee = SummitAttendeeFactory::build($summit, $member, $data); + if (!is_null($old_attendee)) + throw new ValidationException(sprintf("attendee already exist for summit id %s and member id %s", $summit->getId(), $member->getIdentifier())); + + } + + if(!empty($email)) { + $old_attendee = $this->attendee_repository->getBySummitAndEmail($summit, trim($email)); + if (!is_null($old_attendee)) + throw new ValidationException(sprintf("attendee already exist for summit id %s and email %s", $summit->getId(), trim($data['email']))); + } + + $attendee = SummitAttendeeFactory::build($summit, $data, $member); $this->attendee_repository->add($attendee); @@ -152,97 +170,30 @@ final class AttendeeService extends AbstractService implements IAttendeeService if(is_null($attendee)) throw new EntityNotFoundException(sprintf("attendee does not belongs to summit id %s", $summit->getId())); - if(!isset($data['member_id'])) - throw new ValidationException("member_id is required"); + $member = null; + if(isset($data['member_id'])) { + $member_id = intval($data['member_id']); + $member = $this->member_repository->getById($member_id); - $member_id = intval($data['member_id']); - $member = $this->member_repository->getById($member_id); + if (is_null($member)) + throw new EntityNotFoundException("member not found"); - if(is_null($member)) - throw new EntityNotFoundException("member not found"); + $old_attendee = $this->attendee_repository->getBySummitAndMember($summit, $member); + if(!is_null($old_attendee) && $old_attendee->getId() != $attendee->getId()) + throw new ValidationException(sprintf("another attendee (%s) already exist for summit id %s and member id %s", $old_attendee->getId(), $summit->getId(), $member->getIdentifier())); + } + + if(isset($data['email'])) { + $old_attendee = $this->attendee_repository->getBySummitAndEmail($summit, trim($data['email'])); + if(!is_null($old_attendee) && $old_attendee->getId() != $attendee->getId()) + throw new ValidationException(sprintf("attendee already exist for summit id %s and email %s", $summit->getId(), trim($data['email']))); + } // check if attendee already exist for this summit - $old_attendee = $this->attendee_repository->getBySummitAndMember($summit, $member); - if(!is_null($old_attendee) && $old_attendee->getId() != $attendee->getId()) - throw new ValidationException(sprintf("another attendee (%s) already exist for summit id %s and member id %s", $old_attendee->getId(), $summit->getId(), $member->getIdentifier())); + SummitAttendeeFactory::populate($summit, $attendee , $data, $member); - return SummitAttendeeFactory::updateMainData($summit, $attendee, $member , $data); - - }); - } - - /** - * @param SummitAttendee $attendee - * @param array $data - * @throws ValidationException - * @throws EntityNotFoundException - * @return SummitAttendeeTicket - */ - public function addAttendeeTicket(SummitAttendee $attendee, array $data){ - return $this->tx_service->transaction(function() use($attendee, $data){ - - if(!isset($data['ticket_type_id'])) - throw new ValidationException("ticket_type_id is mandatory!"); - - $type = $this->ticket_type_repository->getById(intval($data['ticket_type_id'])); - - if(is_null($type)) - throw new EntityNotFoundException(sprintf("ticket type %s not found!", $data['ticket_type_id'])); - - $old_ticket = $this->ticket_repository->getByExternalOrderIdAndExternalAttendeeId - ( - $data['external_order_id'], - $data['external_attendee_id'] - ); - - if(!is_null($old_ticket)) { - if ($old_ticket->hasOwner()) - throw new ValidationException - ( - sprintf - ( - "external_order_id %s - external_attendee_id %s already assigned to attendee id %s", - $data['external_order_id'], - $data['external_attendee_id'], - $old_ticket->getOwner()->getId() - ) - ); - $this->ticket_repository->delete($old_ticket); - } - - // validate with external api ... - - try { - $external_order = $this->eventbrite_api->getOrder($data['external_order_id']); - $external_attendee_found = false; - $summit_external_id = $external_order['event_id']; - - if (intval($attendee->getSummit()->getSummitExternalId()) !== intval($summit_external_id)) - throw new ValidationException('order %s does not belongs to current summit!', $summit_external_id); - - foreach ($external_order['attendees'] as $external_attendee){ - if($data['external_attendee_id'] == $external_attendee['id']){ - $external_attendee_found = true; - break; - } - } - if(!$external_attendee_found){ - throw new ValidationException - ( - sprintf("external_attendee_id %s does not belongs to external_order_id %s", $data['external_attendee_id'], $data['external_order_id']) - ); - } - } - catch (ClientException $ex1) { - if ($ex1->getCode() === 400) - throw new EntityNotFoundException('external order does not exists!'); - if ($ex1->getCode() === 403) - throw new EntityNotFoundException('external order does not exists!'); - throw $ex1; - } - - return SummitAttendeeTicketFactory::build($attendee, $type, $data); + return $attendee; }); } @@ -301,31 +252,110 @@ final class AttendeeService extends AbstractService implements IAttendeeService * @param Member $other_member * @param int $ticket_id * @return SummitAttendeeTicket - * @throws ValidationException - * @throws EntityNotFoundException + * @throws \Exception */ - public function reassignAttendeeTicket(Summit $summit, SummitAttendee $attendee, Member $other_member, $ticket_id) + public function reassignAttendeeTicketByMember(Summit $summit, SummitAttendee $attendee, Member $other_member, int $ticket_id):SummitAttendeeTicket { return $this->tx_service->transaction(function() use($summit, $attendee, $other_member, $ticket_id){ - $ticket = $this->ticket_repository->getById($ticket_id); - if(is_null($ticket)){ + $ticket = $this->ticket_repository->getByIdExclusiveLock($ticket_id); + + if(is_null($ticket) || !$ticket instanceof SummitAttendeeTicket){ throw new EntityNotFoundException("ticket not found"); } $new_owner = $this->attendee_repository->getBySummitAndMember($summit, $other_member); if(is_null($new_owner)){ - $new_owner = SummitAttendeeFactory::build($summit, $other_member, []); + $new_owner = SummitAttendeeFactory::build($summit,[ + 'first_name' => $other_member->getFirstName(), + 'last_name' => $other_member->getLastName(), + 'email' => $other_member->getEmail(), + ], $other_member); $this->attendee_repository->add($new_owner); } + $attendee->sendRevocationTicketEmail($ticket); + $attendee->removeTicket($ticket); $new_owner->addTicket($ticket); - if(!$attendee->hasTickets()){ - $this->attendee_repository->delete($attendee); - } + $ticket->generateQRCode(); + $ticket->generateHash(); + + $new_owner->sendInvitationEmail($ticket); + return $ticket; }); } + + + /** + * @param Summit $summit + * @param SummitAttendee $attendee + * @param int $ticket_id + * @param array $payload + * @return SummitAttendeeTicket + * @throws \Exception + */ + public function reassignAttendeeTicket(Summit $summit, SummitAttendee $attendee, int $ticket_id, array $payload):SummitAttendeeTicket + { + return $this->tx_service->transaction(function() use($summit, $attendee, $ticket_id, $payload){ + $ticket = $this->ticket_repository->getByIdExclusiveLock($ticket_id); + + if(is_null($ticket) || !$ticket instanceof SummitAttendeeTicket){ + throw new EntityNotFoundException("ticket not found"); + } + + $attendee_email = $payload['attendee_email'] ?? null; + + $new_owner = $this->attendee_repository->getBySummitAndEmail($summit , $attendee_email); + + if(is_null($new_owner)){ + Log::debug(sprintf("attendee %s does no exists .. creating it ", $attendee_email)); + $attendee_payload = [ + 'email' => $attendee_email + ]; + + $new_owner = SummitAttendeeFactory::build + ( + $summit, + $attendee_payload, + $this->member_repository->getByEmail($attendee_email) + ); + + $this->attendee_repository->add($new_owner); + } + + $attendee_payload = []; + + if(isset($payload['attendee_first_name'])) + $attendee_payload['first_name'] = $payload['attendee_first_name']; + + if(isset($payload['attendee_last_name'])) + $attendee_payload['last_name'] = $payload['attendee_last_name']; + + if(isset($payload['attendee_company'])) + $attendee_payload['company'] = $payload['attendee_company']; + + if(isset($payload['extra_questions'])) + $attendee_payload['extra_questions'] = $payload['extra_questions']; + + SummitAttendeeFactory::populate($summit, $new_owner , $attendee_payload); + + $attendee->sendRevocationTicketEmail($ticket); + + $attendee->removeTicket($ticket); + + $new_owner->addTicket($ticket); + + $ticket->generateQRCode(); + $ticket->generateHash(); + + $new_owner->sendInvitationEmail($ticket); + + return $ticket; + }); + + } + } \ No newline at end of file diff --git a/app/Services/Model/IAttendeeService.php b/app/Services/Model/IAttendeeService.php index b580fb5f..c3900e55 100644 --- a/app/Services/Model/IAttendeeService.php +++ b/app/Services/Model/IAttendeeService.php @@ -51,15 +51,6 @@ interface IAttendeeService */ public function updateAttendee(Summit $summit, $attendee_id, array $data); - /** - * @param SummitAttendee $attendee - * @param array $data - * @throws ValidationException - * @throws EntityNotFoundException - * @return SummitAttendeeTicket - */ - public function addAttendeeTicket(SummitAttendee $attendee, array $data); - /** * @param SummitAttendee $attendee * @param int $ticket_id @@ -82,8 +73,17 @@ interface IAttendeeService * @param Member $other_member * @param int $ticket_id * @return SummitAttendeeTicket - * @throws ValidationException - * @throws EntityNotFoundException + * @throws \Exception */ - public function reassignAttendeeTicket(Summit $summit,SummitAttendee $attendee, Member $other_member, $ticket_id); + public function reassignAttendeeTicketByMember(Summit $summit, SummitAttendee $attendee, Member $other_member, int $ticket_id):SummitAttendeeTicket; + + /** + * @param Summit $summit + * @param SummitAttendee $attendee + * @param int $ticket_id + * @param array $payload + * @return SummitAttendeeTicket + * @throws \Exception + */ + public function reassignAttendeeTicket(Summit $summit, SummitAttendee $attendee, int $ticket_id, array $payload):SummitAttendeeTicket; } \ No newline at end of file diff --git a/app/Services/Model/ICompanyService.php b/app/Services/Model/ICompanyService.php new file mode 100644 index 00000000..dd86cf92 --- /dev/null +++ b/app/Services/Model/ICompanyService.php @@ -0,0 +1,45 @@ +tx_service = $tx_service; + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/CompanyService.php b/app/Services/Model/Imp/CompanyService.php new file mode 100644 index 00000000..8dd98cbf --- /dev/null +++ b/app/Services/Model/Imp/CompanyService.php @@ -0,0 +1,92 @@ +repository = $repository; + } + + /** + * @param array $payload + * @throws ValidationException + * @return Company + */ + public function addCompany(array $payload): Company + { + return $this->tx_service->transaction(function() use($payload){ + $company_name = trim($payload['name']); + $former_company = $this->repository->getByName($company_name); + if(!is_null($former_company)){ + throw new ValidationException(sprintf("company %s already exists", $company_name)); + } + $company = CompanyFactory::build($payload); + $this->repository->add($company); + return $company; + }); + } + + /** + * @param int $company_id + * @param array $payload + * @throws ValidationException + * @throws EntityNotFoundException + * @return Company + */ + public function updateCompany(int $company_id, array $payload): Company + { + // TODO: Implement updateCompany() method. + } + + /** + * @param int $company_id + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function deleteCompany(int $company_id): void + { + // TODO: Implement deleteCompany() method. + } +} \ No newline at end of file diff --git a/app/Services/Model/MemberActionsCalendarSyncPreProcessor.php b/app/Services/Model/Imp/MemberActionsCalendarSyncPreProcessor.php similarity index 100% rename from app/Services/Model/MemberActionsCalendarSyncPreProcessor.php rename to app/Services/Model/Imp/MemberActionsCalendarSyncPreProcessor.php diff --git a/app/Services/Model/MemberActionsCalendarSyncProcessingService.php b/app/Services/Model/Imp/MemberActionsCalendarSyncProcessingService.php similarity index 94% rename from app/Services/Model/MemberActionsCalendarSyncProcessingService.php rename to app/Services/Model/Imp/MemberActionsCalendarSyncProcessingService.php index 0f21773a..9fb2ad82 100644 --- a/app/Services/Model/MemberActionsCalendarSyncProcessingService.php +++ b/app/Services/Model/Imp/MemberActionsCalendarSyncProcessingService.php @@ -17,9 +17,6 @@ use App\Services\Apis\CalendarSync\ICalendarSyncRemoteFacadeFactory; use CalDAVClient\Facade\Exceptions\ForbiddenException; use CalDAVClient\Facade\Exceptions\NotFoundResourceException; use CalDAVClient\Facade\Exceptions\ServerErrorException; -use models\exceptions\EntityNotFoundException; -use models\main\CalendarSyncErrorEmailRequest; -use models\main\IEmailCreationRequestRepository; use models\summit\CalendarSync\CalendarSyncInfo; use models\summit\CalendarSync\WorkQueue\AbstractCalendarSyncWorkRequest; use models\summit\CalendarSync\WorkQueue\MemberCalendarScheduleSummitActionSyncWorkRequest; @@ -59,11 +56,6 @@ implements IMemberActionsCalendarSyncProcessingService */ private $preprocessor_requests; - /** - * @var IEmailCreationRequestRepository - */ - private $email_creation_request_repository; - /** * @var ICalendarSyncRemoteFacadeFactory */ @@ -73,7 +65,6 @@ implements IMemberActionsCalendarSyncProcessingService * MemberActionsCalendarSyncProcessingService constructor. * @param IAbstractCalendarSyncWorkRequestRepository $work_request_repository * @param ICalendarSyncInfoRepository $calendar_sync_repository - * @param IEmailCreationRequestRepository $email_creation_request_repository * @param ICalendarSyncWorkRequestPreProcessor $preprocessor_requests * @param ICalendarSyncRemoteFacadeFactory $facade_factory * @param ITransactionService $tx_manager @@ -82,7 +73,6 @@ implements IMemberActionsCalendarSyncProcessingService ( IAbstractCalendarSyncWorkRequestRepository $work_request_repository, ICalendarSyncInfoRepository $calendar_sync_repository, - IEmailCreationRequestRepository $email_creation_request_repository, ICalendarSyncWorkRequestPreProcessor $preprocessor_requests, ICalendarSyncRemoteFacadeFactory $facade_factory, ITransactionService $tx_manager @@ -90,7 +80,6 @@ implements IMemberActionsCalendarSyncProcessingService { $this->work_request_repository = $work_request_repository; $this->calendar_sync_repository = $calendar_sync_repository; - $this->email_creation_request_repository = $email_creation_request_repository; $this->preprocessor_requests = $preprocessor_requests; $this->facade_factory = $facade_factory; $this->tx_manager = $tx_manager; @@ -103,10 +92,6 @@ implements IMemberActionsCalendarSyncProcessingService if(!is_null($calendar_sync_info) && !$calendar_sync_info->isRevoked()){ // revoke it ... $calendar_sync_info->setRevoked(true); - // create email request - $email_request = new CalendarSyncErrorEmailRequest(); - $email_request->setSyncInfo($calendar_sync_info); - $this->email_creation_request_repository->add($email_request); } } /** diff --git a/app/Services/Model/MemberScheduleWorkQueueManager.php b/app/Services/Model/Imp/MemberScheduleWorkQueueManager.php similarity index 100% rename from app/Services/Model/MemberScheduleWorkQueueManager.php rename to app/Services/Model/Imp/MemberScheduleWorkQueueManager.php diff --git a/app/Services/Model/Imp/MemberService.php b/app/Services/Model/Imp/MemberService.php new file mode 100644 index 00000000..509c9d1c --- /dev/null +++ b/app/Services/Model/Imp/MemberService.php @@ -0,0 +1,470 @@ +organization_repository = $organization_repository; + $this->member_repository = $member_repository; + $this->user_ext_api = $user_ext_api; + $this->group_repository = $group_repository; + $this->cache_service = $cache_service; + $this->external_user_api = $external_user_api; + } + + /** + * @param Member $member + * @param int $affiliation_id + * @param array $data + * @return Affiliation + */ + public function updateAffiliation(Member $member, $affiliation_id, array $data) + { + return $this->tx_service->transaction(function () use ($member, $affiliation_id, $data) { + $affiliation = $member->getAffiliationById($affiliation_id); + if (is_null($affiliation)) + throw new EntityNotFoundException(sprintf("affiliation id %s does not belongs to member id %s", $affiliation_id, $member->getId())); + + if (isset($data['is_current'])) { + $affiliation->setIsCurrent(boolval($data['is_current'])); + } + + if (isset($data['start_date'])) { + $start_date = intval($data['start_date']); + $affiliation->setStartDate(new DateTime("@$start_date")); + } + + if (!$affiliation->isCurrent() && isset($data['end_date'])) { + $end_date = intval($data['end_date']); + $affiliation->setEndDate($end_date > 0 ? new DateTime("@$end_date") : null); + } + + if (isset($data['organization_id'])) { + $org = $this->organization_repository->getById(intval($data['organization_id'])); + if (is_null($org)) + throw new EntityNotFoundException(sprintf("organization id %s not found", $data['organization_id'])); + $affiliation->setOrganization($org); + } + + if (isset($data['organization_name'])) { + $org = $this->organization_repository->getByName(trim($data['organization_name'])); + if (is_null($org)) { + $org = new Organization(); + $org->setName(trim($data['organization_name'])); + $this->organization_repository->add($org); + } + + $affiliation->setOrganization($org); + } + + if (isset($data['job_title'])) { + $affiliation->setJobTitle(trim($data['job_title'])); + } + + if ($affiliation->isCurrent()) { + $affiliation->clearEndDate(); + } + + return $affiliation; + }); + } + + /** + * @param Member $member + * @param $affiliation_id + * @return void + */ + public function deleteAffiliation(Member $member, $affiliation_id) + { + return $this->tx_service->transaction(function () use ($member, $affiliation_id) { + $affiliation = $member->getAffiliationById($affiliation_id); + if (is_null($affiliation)) + throw new EntityNotFoundException(sprintf("affiliation id %s does not belongs to member id %s", $affiliation_id, $member->getId())); + + $member->removeAffiliation($affiliation); + }); + } + + /** + * @param Member $member + * @param int $rsvp_id + * @return void + */ + public function deleteRSVP(Member $member, $rsvp_id) + { + return $this->tx_service->transaction(function () use ($member, $rsvp_id) { + $rsvp = $member->getRsvpById($rsvp_id); + if (is_null($rsvp)) + throw new EntityNotFoundException(sprintf("rsvp id %s does not belongs to member id %s", $rsvp_id, $member->getId())); + + $member->removeRsvp($rsvp); + }); + } + + /** + * @param Member $member + * @param array $data + * @return Affiliation + */ + public function addAffiliation(Member $member, array $data) + { + return $this->tx_service->transaction(function () use ($member, $data) { + + $affiliation = new Affiliation(); + + if (isset($data['is_current'])) + $affiliation->setIsCurrent(boolval($data['is_current'])); + if (isset($data['start_date'])) { + $start_date = intval($data['start_date']); + $affiliation->setStartDate(new DateTime("@$start_date")); + } + if (isset($data['end_date'])) { + $end_date = intval($data['end_date']); + $affiliation->setEndDate($end_date > 0 ? new DateTime("@$end_date") : null); + } + + if (isset($data['organization_id'])) { + $org = $this->organization_repository->getById(intval($data['organization_id'])); + if (is_null($org)) + throw new EntityNotFoundException(sprintf("organization id %s not found", $data['organization_id'])); + $affiliation->setOrganization($org); + } + + if (isset($data['organization_name'])) { + $org = $this->organization_repository->getByName(trim($data['organization_name'])); + if (is_null($org)) { + $org = new Organization(); + $org->setName(trim($data['organization_name'])); + $this->organization_repository->add($org); + } + + $affiliation->setOrganization($org); + } + + if (isset($data['job_title'])) { + $affiliation->setJobTitle(trim($data['job_title'])); + } + + if ($affiliation->isCurrent() && $affiliation->getEndDate() != null) + throw new ValidationException + ( + sprintf + ( + "in order to set affiliation as current end_date should be null" + ) + ); + + $member->addAffiliation($affiliation); + return $affiliation; + }); + } + + /** + * @param $user_external_id + * @param string $email + * @param string $first_name + * @param string $last_name + * @return Member + */ + public function registerExternalUser($user_external_id, string $email, string $first_name, string $last_name): Member + { + return $this->tx_service->transaction(function () use ($user_external_id, $email, $first_name, $last_name) { + Log::debug(sprintf("MemberService::registerExternalUser - user_external_id %s email %s first_name %s last_name %s", $user_external_id, $email, $first_name, $last_name)); + $member = new Member(); + $member->setActive(true); + $member->setEmailVerified(true); + $member->setEmail($email); + $member->setFirstName($first_name); + $member->setLastName($last_name); + $member->setUserExternalId($user_external_id); + $this->member_repository->add($member, true); + Event::fire(new NewMember($member->getId())); + return $member; + }); + } + + /** + * @param $user_external_id + * @return Member + * @throws \Exception + */ + public function registerExternalUserById($user_external_id): Member + { + return $this->tx_service->transaction(function () use ($user_external_id) { + $user_data = $this->user_ext_api->getUserById($user_external_id); + $email = trim($user_data['email']); + // first by external id due email could be updated + Log::debug(sprintf("MemberService::registerExternalUserById trying to get user by external id %s", $user_external_id)); + $member = $this->member_repository->getByExternalIdExclusiveLock(intval($user_external_id)); + // if we dont registered yet a member with that external id try to get by email + if(is_null($member)) { + Log::debug(sprintf("MemberService::registerExternalUserById trying to get user by email %s", $email)); + $member = $this->member_repository->getByEmail($email); + } + $is_new = false; + if(is_null($member)) { + Log::debug(sprintf("MemberService::registerExternalUserById %s does not exists , creating it ...", $email)); + $member = new Member(); + $member->setActive(true); + $member->setEmailVerified(true); + $member->setEmail($email); + $member->setFirstName(trim($user_data['first_name'])); + $member->setLastName(trim($user_data['last_name'])); + $member->setBio($user_data['bio']); + $member->setUserExternalId($user_external_id); + if(isset($user_data['pic'])) + $member->setExternalPic($user_data['pic']); + $this->member_repository->add($member, true); + $is_new = true; + } + else { + Log::debug(sprintf("MemberService::registerExternalUserById %s already exists", $email)); + $member->setEmailVerified(true); + $member->setEmail($email); + $member->setFirstName(trim($user_data['first_name'])); + $member->setLastName(trim($user_data['last_name'])); + $member->setBio($user_data['bio']); + if(isset($user_data['pic'])) + $member->setExternalPic($user_data['pic']); + $member->setUserExternalId($user_external_id); + } + + $this->synchronizeGroups($member, $user_data['groups']); + if($is_new) + Event::fire(new NewMember($member->getId())); + + return $member; + }); + } + + /** + * @param Member $member + * @param array $groups + * @return Member + * @throws \Exception + */ + public function synchronizeGroups(Member $member, array $groups): Member + { + return $this->tx_service->transaction(function () use ($member, $groups) { + + $val = $this->cache_service->getSingleValue(sprintf("member_%s_sync_groups", $member->getId())); + + if(!empty($val)){ + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s synch already done", $member->getId(), $member->getEmail())); + return $member; + } + + $groups2Remove = []; + + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s", $member->getId(), $member->getEmail())); + + foreach($member->getGroups() as $group){ + // if this group was added from idp, clear it, just in case we were deleted from that group + if(!in_array($group->getCode(), $groups)){ + // do not remove if we are super admins, since we do need this group too ( backward compatibility with SS CMS) + if($group->getCode() == IGroup::Administrators && in_array(IGroup::SuperAdmins, $groups)) + continue; + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s marking group %s to remove (external) dues is not on member current groups", $member->getId(), $member->getEmail(), $group->getCode())); + $groups2Remove[] = $group; + } + } + + // remove all groups that arent on our IDP profile anymore ... + foreach ($groups2Remove as $externalGroup){ + if($externalGroup->getCode() === IGroup::SuperAdmins && $member->belongsToGroup(IGroup::Administrators)){ + $group = $this->group_repository->getBySlug(IGroup::Administrators); + if(!is_null($group)) { + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s removing from group %s due is also a super admin", $member->getId(), $member->getEmail(), $group->getCode())); + $member->removeFromGroup($group); + } + } + $member->removeFromGroup($externalGroup); + } + + // sync + + foreach ($groups as $code) { + + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s processing group code %s", $member->getId(), $member->getEmail(), $code)); + + if(!$member->belongsToGroup($code)){ + $group = $this->group_repository->getBySlug($code); + if (is_null($group)) { + // create it + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s - group %s does not exists!, .. creating it ", $member->getId(), $member->getEmail(), $code)); + $group = new Group(); + $group->setCode($code); + $group->setExternal(); + $group->setDescription($code); + $group->setTitle($code); + $this->group_repository->add($group, true); + } + $group->setExternal(); + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s adding to group %s", $member->getId(), $member->getEmail(), $code)); + $member->add2Group($group); + } + + // map from super admin to admin ( special case ) + if ($code === IGroup::SuperAdmins) { + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s is on group %s, should be added to group %s", $member->getId(), $member->getEmail(), $code, IGroup::Administrators)); + if(!$member->belongsToGroup(IGroup::Administrators)) { + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s is not on group %s", $member->getId(), $member->getEmail(), IGroup::Administrators)); + $group = $this->group_repository->getBySlug(IGroup::Administrators); + if (is_null($group)) { + // create it + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s - group %s does not exists!, .. creating it ", $member->getId(), $member->getEmail(), $code)); + $group = new Group(); + $group->setCode(IGroup::Administrators); + $group->setDescription(IGroup::Administrators); + $group->setTitle(IGroup::Administrators); + $this->group_repository->add($group, true); + } + $group->setExternal(); + Log::debug(sprintf("MemberService::synchronizeGroups member %s email %s adding to group %s", $member->getId(), $member->getEmail(), $group->getCode())); + $member->add2Group($group); + } + } + + } + + $this->cache_service->setSingleValue(sprintf("member_%s_sync_groups", $member->getId()), 1, self::SYNCH_GROUPS_TTL); + return $member; + }); + } + + /** + * @param string $email + * @return array|null + * @throws \Exception + */ + public function checkExternalUser(string $email) { + Log::debug(sprintf("MemberService::checkExternalUser - trying to get member %s from user api", $email)); + $user = $this->external_user_api->getUserByEmail($email); + // check if primary email is the same if not disregard + Log::debug(sprintf("MemberService::checkExternalUser got entity %s for email %s", json_encode($user), $email)); + $primary_email = $user['email'] ?? null; + if (strcmp(strtolower($primary_email), strtolower($email)) !== 0) { + Log::debug + ( + sprintf + ( + "MemberService::checkExternalUser primary email %s differs from original email %s", + $primary_email, + $email + ) + ); + + // email are not equals , then is not the user bc primary emails differs ( could be a + // match on a secondary email) + $user = null; // set null on user and proceed to emit a registration request. + } + + return $user; + } + + /** + * @param string $email + * @param string $first_name + * @param string $last_name + * @return array + * @throws \Exception + */ + public function emitRegistrationRequest(string $email, string $first_name, string $last_name):array{ + // user does not exists , emit a registration request + return $this->external_user_api->registerUser + ( + $email, + $first_name, + $last_name + ); + } +} \ No newline at end of file diff --git a/app/Services/Model/OrganizationService.php b/app/Services/Model/Imp/OrganizationService.php similarity index 100% rename from app/Services/Model/OrganizationService.php rename to app/Services/Model/Imp/OrganizationService.php diff --git a/app/Services/Model/Imp/PaymentGatewayProfileService.php b/app/Services/Model/Imp/PaymentGatewayProfileService.php new file mode 100644 index 00000000..83b24c5d --- /dev/null +++ b/app/Services/Model/Imp/PaymentGatewayProfileService.php @@ -0,0 +1,93 @@ +tx_service->transaction(function() use($summit, $payload){ + $profile = PaymentGatewayProfileFactory::build($payload['provider'], $payload); + $formerProfile = $summit->getPaymentGateWayProfilePerApp($profile->getApplicationType()); + if($profile->isActive() && !is_null($formerProfile) && $formerProfile->isActive()){ + throw new ValidationException + ( + sprintf("There is already an active Payment Profile for application type %s,", $formerProfile->getApplicationType()) + ); + } + $summit->addPaymentProfile($profile); + if(isset($payload['active']) && boolval($payload['active']) == true){ + // force activation ( rebuild web hook) + $profile->activate(); + } + return $profile; + }); + } + + /** + * @inheritDoc + */ + public function deletePaymentProfile(Summit $summit, int $child_id): void + { + $this->tx_service->transaction(function() use($summit, $child_id){ + $profile = $summit->getPaymentProfileById($child_id); + if(is_null($profile)) + throw new EntityNotFoundException(); + $summit->removePaymentProfile($profile); + }); + } + + /** + * @inheritDoc + */ + public function updatePaymentProfile(Summit $summit, int $child_id, array $payload): ?PaymentGatewayProfile + { + return $this->tx_service->transaction(function() use($summit, $child_id, $payload){ + + $profile = $summit->getPaymentProfileById($child_id); + if(is_null($profile)) + throw new EntityNotFoundException(); + + $formerProfile = $summit->getPaymentGateWayProfilePerApp($profile->getApplicationType()); + // if we are activating this profile, check if there is not already one activated + if(isset($payload['active']) && boolval($payload['active']) == true && + !is_null($formerProfile) && $formerProfile->getId() != $profile->getId() + && $formerProfile->isActive()){ + throw new ValidationException + ( + sprintf("There is already an active Payment Profile for application type %s.", $formerProfile->getApplicationType()) + ); + } + + $profile = PaymentGatewayProfileFactory::populate($profile, $payload); + + return $profile; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/PresentationCategoryGroupService.php b/app/Services/Model/Imp/PresentationCategoryGroupService.php similarity index 100% rename from app/Services/Model/PresentationCategoryGroupService.php rename to app/Services/Model/Imp/PresentationCategoryGroupService.php diff --git a/app/Services/Model/PresentationService.php b/app/Services/Model/Imp/PresentationService.php similarity index 79% rename from app/Services/Model/PresentationService.php rename to app/Services/Model/Imp/PresentationService.php index ad9b5155..f28d68c3 100644 --- a/app/Services/Model/PresentationService.php +++ b/app/Services/Model/Imp/PresentationService.php @@ -14,25 +14,29 @@ use App\Events\PresentationMaterialDeleted; use App\Events\PresentationMaterialUpdated; use App\Http\Utils\IFileUploader; +use App\Jobs\Emails\PresentationSubmissions\PresentationCreatorNotificationEmail; +use App\Jobs\Emails\PresentationSubmissions\PresentationSpeakerNotificationEmail; use App\Models\Foundation\Summit\Factories\PresentationLinkFactory; use App\Models\Foundation\Summit\Factories\PresentationSlideFactory; use App\Models\Foundation\Summit\Factories\PresentationVideoFactory; use App\Models\Foundation\Summit\SelectionPlan; +use App\Models\Utils\IStorageTypesConstants; +use App\Services\FileSystem\FileNameSanitizer; +use App\Services\Filesystem\FileUploadStrategyFactory; use App\Services\Model\AbstractService; use App\Models\Foundation\Summit\Events\Presentations\TrackQuestions\TrackAnswer; +use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Event; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; -use models\main\IEmailCreationRequestRepository; use models\main\IFolderRepository; use models\main\ITagRepository; use models\main\Member; -use models\main\PresentationCreatorNotificationEmailRequest; -use models\main\PresentationSpeakerNotificationEmailRequest; use models\summit\ISpeakerRepository; use models\summit\ISummitEventRepository; use models\summit\Presentation; use models\summit\PresentationLink; +use models\summit\PresentationMediaUpload; use models\summit\PresentationSlide; use models\summit\PresentationSpeaker; use models\summit\PresentationType; @@ -41,7 +45,6 @@ use libs\utils\ITransactionService; use models\summit\Summit; use Illuminate\Http\Request as LaravelRequest; use App\Services\Model\IFolderService; -use Illuminate\Http\UploadedFile; /** * Class PresentationService * @package services\model @@ -80,11 +83,6 @@ final class PresentationService */ private $folder_repository; - /** - * @var IEmailCreationRequestRepository - */ - private $email_creation_request_repository; - /** * PresentationService constructor. * @param ISummitEventRepository $presentation_repository @@ -93,7 +91,6 @@ final class PresentationService * @param IFolderService $folder_service * @param IFileUploader $file_uploader * @param IFolderRepository $folder_repository - * @param IEmailCreationRequestRepository $email_creation_request_repository * @param ITransactionService $tx_service */ public function __construct @@ -104,7 +101,6 @@ final class PresentationService IFolderService $folder_service, IFileUploader $file_uploader, IFolderRepository $folder_repository, - IEmailCreationRequestRepository $email_creation_request_repository, ITransactionService $tx_service ) { @@ -115,7 +111,6 @@ final class PresentationService $this->folder_service = $folder_service; $this->file_uploader = $file_uploader; $this->folder_repository = $folder_repository; - $this->email_creation_request_repository = $email_creation_request_repository; } /** @@ -264,6 +259,12 @@ final class PresentationService 'validation_errors.PresentationService.submitPresentation.NotValidSelectionPlan' )); + if(!$current_selection_plan->IsEnabled()){ + throw new ValidationException(sprintf("Submission Period is Closed.")); + } + if(!$current_selection_plan->isSubmissionOpen()){ + throw new ValidationException(sprintf("Submission Period is Closed.")); + } // check qty $limit = $this->getSubmissionLimitFor($summit); @@ -334,8 +335,14 @@ final class PresentationService 'validation_errors.PresentationService.updatePresentationSubmission.NotValidSelectionPlan' )); - $presentation = $summit->getEvent($presentation_id); + if(!$current_selection_plan->IsEnabled()){ + throw new ValidationException(sprintf("Submission Period is Closed.")); + } + if(!$current_selection_plan->isSubmissionOpen()){ + throw new ValidationException(sprintf("Submission Period is Closed.")); + } + $presentation = $summit->getEvent($presentation_id); if (is_null($presentation)) throw new EntityNotFoundException(trans( @@ -582,10 +589,23 @@ final class PresentationService { return $this->tx_service->transaction(function () use ($summit, $member, $presentation_id) { + $current_selection_plan = $summit->getCurrentSelectionPlanByStatus(SelectionPlan::STATUS_SUBMISSION); $current_speaker = $this->speaker_repository->getByMember($member); if (is_null($current_speaker)) throw new EntityNotFoundException(sprintf("member %s does not has a speaker profile", $member->getId())); + if (is_null($current_selection_plan)) + throw new ValidationException(trans( + 'validation_errors.PresentationService.updatePresentationSubmission.NotValidSelectionPlan' + )); + + if(!$current_selection_plan->IsEnabled()){ + throw new ValidationException(sprintf("Submission Period is Closed.")); + } + if(!$current_selection_plan->isSubmissionOpen()){ + throw new ValidationException(sprintf("Submission Period is Closed.")); + } + $presentation = $summit->getEvent($presentation_id); if (is_null($presentation)) throw new EntityNotFoundException(sprintf("presentation %s not found", $presentation_id)); @@ -615,39 +635,30 @@ final class PresentationService } $title = $presentation->getTitle(); - $abtract = $presentation->getAbstract(); + $abstract = $presentation->getAbstract(); $level = $presentation->getLevel(); if (empty($title)) { throw new ValidationException('Title is Mandatory!'); } - if (empty($abtract)) { + if (empty($abstract)) { throw new ValidationException('Abstract is mandatory!'); } if (empty($level)) { - throw new ValidationException('Level is mandatory!'); + throw new ValidationException('Level is mandatory.'); } $presentation->setProgress(Presentation::PHASE_COMPLETE); $presentation->setStatus(Presentation::STATUS_RECEIVED); - // create email requests - foreach($presentation->getSpeakers() as $speaker){ if($speaker->getMemberId() == $presentation->getCreatorId()) continue; - - $email = new PresentationSpeakerNotificationEmailRequest(); - - $email->setSpeaker($speaker); - $email->setPresentation($presentation); - $this->email_creation_request_repository->add($email); + PresentationSpeakerNotificationEmail::dispatch($speaker, $presentation); } - $email = new PresentationCreatorNotificationEmailRequest(); - $email->setPresentation($presentation); - $this->email_creation_request_repository->add($email); + PresentationCreatorNotificationEmail::dispatch($presentation); return $presentation; }); @@ -952,4 +963,195 @@ final class PresentationService Event::fire(new PresentationMaterialDeleted($presentation, $link_id, 'PresentationLink')); }); } + + // media uploads + + /** + * @param LaravelRequest $request + * @param Summit $summit + * @param $presentation_id + * @param array $payload + * @return PresentationMediaUpload + * @throws \Exception + */ + public function addMediaUploadTo + ( + LaravelRequest $request, + Summit $summit, + int $presentation_id, + array $payload + ):PresentationMediaUpload + { + return $this->tx_service->transaction(function () use ( + $request, + $summit, + $presentation_id, + $payload + ) { + + $presentation = $this->presentation_repository->getById($presentation_id); + + if (is_null($presentation) || !$presentation instanceof Presentation) + throw new EntityNotFoundException('Presentation not found.'); + + $hasFile = $request->hasFile('file'); + + if(!$hasFile){ + throw new ValidationException("You must provide a file."); + } + + $media_upload_type_id = intval($payload['media_upload_type_id']); + + $media_upload_type = $summit->getMediaUploadTypeById($media_upload_type_id); + + if(is_null($media_upload_type)) + throw new EntityNotFoundException(sprintf("Media Upload Type %s not found.", $media_upload_type_id)); + + if(!$media_upload_type->isPresentationTypeAllowed($presentation->getType())){ + throw new ValidationException(sprintf("Presentation Type %s is not allowed on Media Upload %s", $presentation->getTypeId(), $media_upload_type_id)); + } + + $file = $request->file('file'); + // get in bytes should be converted to KB + $size = $file->getSize(); + if($size == 0) + throw new ValidationException("File size is zero."); + $size = $size/1024; + $fileName = $file->getClientOriginalName(); + $fileExt = pathinfo($fileName, PATHINFO_EXTENSION); + + // normalize fileName + $fileName = FileNameSanitizer::sanitize($fileName); + + if($media_upload_type->getMaxSize() < $size){ + throw new ValidationException(sprintf("Max Size is %s KB.", $media_upload_type->getMaxSize())); + } + + if(!$media_upload_type->isValidExtension($fileExt)){ + throw new ValidationException(sprintf("File Extension %s is not valid", $fileExt)); + } + + $mediaUpload = new PresentationMediaUpload(); + $mediaUpload->setMediaUploadType($media_upload_type); + $mediaUpload->setPresentation($presentation); + + $strategy = FileUploadStrategyFactory::build($media_upload_type->getPrivateStorageType()); + if(!is_null($strategy)){ + $strategy->save($file, $mediaUpload->getPath(IStorageTypesConstants::PrivateType), $fileName); + } + + $strategy = FileUploadStrategyFactory::build($media_upload_type->getPublicStorageType()); + if(!is_null($strategy)){ + $strategy->save($file, $mediaUpload->getPath(IStorageTypesConstants::PublicType), $fileName); + } + + $mediaUpload->setFilename($fileName); + $presentation->addMediaUpload($mediaUpload); + + return $mediaUpload; + }); + } + + /** + * @param LaravelRequest $request + * @param Summit $summit + * @param int $presentation_id + * @param int $media_upload_id + * @return PresentationMediaUpload + * @throws \Exception + */ + public function updateMediaUploadFrom + ( + LaravelRequest $request, + Summit $summit, + int $presentation_id, + int $media_upload_id + ): PresentationMediaUpload + { + return $this->tx_service->transaction(function () use ( + $request, + $summit, + $presentation_id, + $media_upload_id + ) { + + $presentation = $this->presentation_repository->getById($presentation_id); + + if (is_null($presentation) || !$presentation instanceof Presentation) + throw new EntityNotFoundException('Presentation not found.'); + + $mediaUpload = $presentation->getMediaUploadBy($media_upload_id); + + if (is_null($mediaUpload)) + throw new EntityNotFoundException('Presentation Media Upload not found.'); + + $hasFile = $request->hasFile('file'); + + if(!$hasFile){ + throw new ValidationException("You must provide a file."); + } + + $file = $request->file('file'); + // get in bytes should be converted to KB + $size = $file->getSize(); + if($size == 0) + throw new ValidationException("File size is zero."); + $size = $size/1024; + $fileName = $file->getClientOriginalName(); + $fileExt = pathinfo($fileName, PATHINFO_EXTENSION); + // normalize fileName + $fileName = FileNameSanitizer::sanitize($fileName); + + $mediaUploadType = $mediaUpload->getMediaUploadType(); + if(is_null($mediaUploadType)) + throw new ValidationException("Media Upload Type is not set."); + + if($mediaUploadType->getMaxSize() < $size){ + throw new ValidationException(sprintf("Max Size is %s KB.", $mediaUploadType->getMaxSize())); + } + + if(!$mediaUploadType->isValidExtension($fileExt)){ + throw new ValidationException(sprintf("File Extension %s is not valid", $fileExt)); + } + + $strategy = FileUploadStrategyFactory::build($mediaUploadType->getPrivateStorageType()); + if(!is_null($strategy)){ + $strategy->save($file, $mediaUpload->getPath(IStorageTypesConstants::PrivateType), $fileName); + } + + $strategy = FileUploadStrategyFactory::build($mediaUploadType->getPublicStorageType()); + if(!is_null($strategy)){ + $strategy->save($file, $mediaUpload->getPath(IStorageTypesConstants::PublicType), $fileName); + } + + $mediaUpload->setFilename($fileName); + + return $mediaUpload; + }); + } + + + /** + * @inheritDoc + */ + public function deleteMediaUpload(Summit $summit, int $presentation_id, int $media_upload_id): void + { + $this->tx_service->transaction(function () use ( + $summit, + $presentation_id, + $media_upload_id + ) { + $presentation = $this->presentation_repository->getById($presentation_id); + + if (is_null($presentation) || !$presentation instanceof Presentation) + throw new EntityNotFoundException('Presentation not found.'); + + $mediaUpload = $presentation->getMediaUploadBy($media_upload_id); + if(is_null($mediaUpload)){ + throw new EntityNotFoundException("Media Upload not found."); + } + + $presentation->removeMediaUpload($mediaUpload); + }); + } } \ No newline at end of file diff --git a/app/Services/Model/RSVPTemplateService.php b/app/Services/Model/Imp/RSVPTemplateService.php similarity index 100% rename from app/Services/Model/RSVPTemplateService.php rename to app/Services/Model/Imp/RSVPTemplateService.php diff --git a/app/Services/Model/Imp/RegistrationIngestionService.php b/app/Services/Model/Imp/RegistrationIngestionService.php new file mode 100644 index 00000000..4cd530eb --- /dev/null +++ b/app/Services/Model/Imp/RegistrationIngestionService.php @@ -0,0 +1,332 @@ +summit_repository = $summit_repository; + $this->feed_factory = $feed_factory; + $this->order_repository = $order_repository; + $this->ticket_repository = $ticket_repository; + $this->member_repository = $member_repository; + $this->attendee_repository = $attendee_repository; + } + + public function ingestAllSummits(): void + { + + $summits = $this->tx_service->transaction(function () { + return $this->summit_repository->getAllWithExternalRegistrationFeed(); + }); + + foreach ($summits as $summit) { + $this->ingestSummit($summit); + } + } + + /** + * @param Summit $summit + * @throws \Exception + */ + public function ingestSummit(Summit $summit): void + { + try { + $start = time(); + $summit_id = $summit->getId(); + $page = 1; + $has_more_items = false; + Log::debug(sprintf("RegistrationIngestionService::ingestSummit: ingesting summit %s", $summit_id)); + $feed = $this->feed_factory->build($summit); + + if (is_null($feed)) + throw new ValidationException("invalid feed"); + + if (!$summit->hasDefaultBadgeType()) + throw new ValidationException(sprintf("summit %s has not default badge type set", $summit_id)); + + do { + Log::debug(sprintf("RegistrationIngestionService::ingestSummit: getting external attendees page %s", $page)); + $response = $feed->getAttendees($page); + if (!$response->hasData()) return; + $has_more_items = $response->hasMoreItems(); + + foreach ($response as $index => $external_attendee) { + + $this->tx_service->transaction(function () use ($summit_id, $external_attendee) { + $summit = $this->summit_repository->getById($summit_id); + if (!$summit instanceof Summit) return; + $default_badge_type = $summit->getDefaultBadgeType(); + + if (!$summit instanceof Summit) return; + $external_attendee_profile = $external_attendee['profile']; + $external_promo_code = $external_attendee['promotional_code']; + $ticket_class = $external_attendee['ticket_class']; + $external_order = $external_attendee['order']; + $refunded = $external_attendee['refunded']; + $cancelled = $external_attendee['cancelled']; + + Log::debug(sprintf("RegistrationIngestionService::ingestSummit: proccessing external attendee %s - external order id %s", $external_attendee['id'], $external_order['id'])); + + $ticket_type = $summit->getTicketTypeByExternalId($ticket_class['id']); + if (is_null($ticket_type)) { + // create ticket type if does not exists + Log::debug(sprintf("RegistrationIngestionService::ingestSummit: ticket class %s does not exists", $ticket_class['id'])); + $ticket_type = SummitTicketTypeFactory::build( + $summit, [ + 'name' => $ticket_class['name'], + 'description' => $ticket_class['description'], + 'external_id' => $ticket_class['id'], + 'cost' => $ticket_class['cost']['major_value'], + 'currency' => $ticket_class['cost']['currency'], + 'quantity_2_sell' => $ticket_class['quantity_total'], + ] + ); + + $summit->addTicketType($ticket_type); + } + + $order = $this->order_repository->getByExternalIdAndSummitLockExclusive($summit, $external_order['id']); + if (is_null($order)) { + Log::debug(sprintf("RegistrationIngestionService::ingestSummit: order %s does not exists", $external_order['id'])); + $order = SummitOrderFactory::build($summit, [ + 'external_id' => $external_order['id'], + 'owner_first_name' => $external_order['first_name'], + 'owner_last_name' => $external_order['last_name'], + 'owner_email' => $external_order['email'], + ]); + + $order->setSummit($summit); + + $order->generateNumber(); + + $owner = $this->member_repository->getByEmail($external_order['email']); + if (!is_null($owner)) { + $owner->addSummitRegistrationOrder($order); + } + + do { + if (!$summit->existOrderNumber($order->getNumber())) + break; + $order->generateNumber(); + } while (1); + + // generate the key to access + $order->generateHash(); + $order->generateQRCode(); + + $summit->addOrder($order); + } + + $ticket = $this->ticket_repository->getBySummitAndExternalOrderIdAndExternalAttendeeIdExclusiveLock + ( + $summit, + $external_order['id'], + $external_attendee['id'] + ); + + if (is_null($ticket)) { + + Log::debug(sprintf("RegistrationIngestionService::ingestSummit: ticket %s - %s does not exists", $external_order['id'], $external_attendee['id'])); + $ticket = new SummitAttendeeTicket(); + $ticket->setExternalAttendeeId($external_attendee['id']); + $ticket->setExternalOrderId($external_order['id']); + $ticket->setBoughtDate(new \DateTime($external_attendee['created'], new \DateTimeZone('UTC'))); + $ticket->setOrder($order); + $ticket->generateNumber(); + + do { + + if (!$this->ticket_repository->existNumber($ticket->getNumber())) + break; + $ticket->generateNumber(); + } while (1); + + $ticket->setTicketType($ticket_type); + } + + if (count($external_promo_code)) { + // has promo code + $promo_code = $summit->getPromoCodeByCode($external_promo_code['code']); + if (is_null($promo_code)) { + + Log::debug(sprintf("RegistrationIngestionService::ingestSummit: promo code %s - %s does not exists", $external_promo_code['id'], $external_promo_code['code'])); + + $promo_code_params = [ + 'class_name' => $external_promo_code['promotion_type'] == 'discount' ? SummitRegistrationDiscountCode::ClassName : SummitRegistrationPromoCode::ClassName, + 'code' => trim($external_promo_code['code']), + 'external_id' => trim($external_promo_code['id']) + ]; + + if ($external_promo_code['promotion_type'] == 'discount') { + if (isset($external_promo_code['percent_off'])) { + $promo_code_params['rate'] = floatval($external_promo_code['percent_off']); + } + if (isset($external_promo_code['amount_off'])) { + $amount_off = $external_promo_code['amount_off']; + if (isset($amount_off['major_value'])) + $promo_code_params['amount'] = floatval($amount_off['major_value']); + } + } + + $promo_code = SummitPromoCodeFactory::build($summit, $promo_code_params); + $summit->addPromoCode($promo_code); + } + + $promo_code->applyTo($ticket); + } + + // default badge + if (!$ticket->hasBadge()) { + $badge = new SummitAttendeeBadge(); + $badge->setType($default_badge_type); + $ticket->setBadge($badge); + } + + // assign attendee + // check if we have already an attendee on this summit + $attendee_email = trim($external_attendee_profile['email']); + $first_name = trim($external_attendee_profile['first_name']); + $last_name = trim($external_attendee_profile['last_name']); + $company = isset($external_attendee_profile['company']) ? trim($external_attendee_profile['company']) : ''; + Log::debug(sprintf("RegistrationIngestionService::ingestSummit: looking for attendee %s , %s (%s)", $first_name, $last_name, $attendee_email)); + $attendee = $this->attendee_repository->getBySummitAndEmailAndFirstNameAndLastNameAndExternalId($summit, $attendee_email, $first_name, $last_name, $external_attendee['id']); + + if (is_null($attendee)) { + Log::debug(sprintf("RegistrationIngestionService::ingestSummit: attendee %s does not exists", $attendee_email)); + $attendee = SummitAttendeeFactory::build($summit, [ + 'external_id' => $external_attendee['id'], + 'first_name' => $first_name, + 'last_name' => $last_name, + 'company' => $company, + 'email' => $attendee_email + ], $this->member_repository->getByEmail($attendee_email)); + + $summit->addAttendee($attendee); + } else { + SummitAttendeeFactory::populate($summit, $attendee, [ + 'external_id' => $external_attendee['id'], + 'first_name' => $first_name, + 'last_name' => $last_name, + 'company' => $company, + 'email' => $attendee_email + ]); + } + + $ticket->setOwner($attendee); + if (!$cancelled && !$refunded) { + $ticket->setPaid(); + $order->setPaidStatus(); + } + if ($cancelled) { + $ticket->setCancelled(); + } + if ($refunded) { + $ticket->setRefunded(); + } + + $order->addTicket($ticket); + $ticket->generateQRCode(); + $ticket->generateHash(); + }); + } + + ++$page; + } while ($has_more_items); + + $end = time(); + $delta = $end - $start; + log::debug(sprintf("RegistrationIngestionService::ingestSummit execution call %s seconds - summit %s", $delta, $summit_id)); + } catch (Exception $ex) { + Log::warning(sprintf("error external feed for summit id %s", $summit->getId())); + Log::warning($ex); + } + } +} \ No newline at end of file diff --git a/app/Services/Model/ScheduleIngestionService.php b/app/Services/Model/Imp/ScheduleIngestionService.php similarity index 81% rename from app/Services/Model/ScheduleIngestionService.php rename to app/Services/Model/Imp/ScheduleIngestionService.php index 67545f66..96ad9c0a 100644 --- a/app/Services/Model/ScheduleIngestionService.php +++ b/app/Services/Model/Imp/ScheduleIngestionService.php @@ -83,6 +83,18 @@ final class ScheduleIngestionService */ private $location_repository; + /** + * ScheduleIngestionService constructor. + * @param ISummitRepository $summit_repository + * @param IMemberRepository $member_repository + * @param ISpeakerRepository $speaker_repository + * @param IOrganizationRepository $org_repository + * @param ISummitEventRepository $event_repository + * @param ISummitLocationRepository $location_repository + * @param IExternalScheduleFeedFactory $feed_factory + * @param ITagRepository $tag_repository + * @param ITransactionService $tx_service + */ public function __construct ( ISummitRepository $summit_repository, @@ -121,15 +133,25 @@ final class ScheduleIngestionService $processedExternalIds = $this->ingestSummit($summit); - $this->tx_service->transaction(function () use ($summit, $processedExternalIds) { - foreach ($this->event_repository->getPublishedEventsBySummitNotInExternalIds($summit, $processedExternalIds) as $presentation) { + Log::debug(sprintf( "ScheduleIngestionService::ingestAllSummits trying to get all events to delete for summit %s...", $summit->getId())); + + $summit_events = $this->tx_service->transaction(function () use ($summit, $processedExternalIds) { + return $this->event_repository->getPublishedEventsBySummitNotInExternalIds($summit, $processedExternalIds); + }); + + //Log::debug(sprintf( "ScheduleIngestionService::ingestAllSummits got %s events to delete for summit %s...", $summit_events->count(), $summit->getId())); + + foreach ($summit_events as $summit_event) { + $this->tx_service->transaction(function () use ($summit_event) { try { - $this->event_repository->delete($presentation); + Log::debug(sprintf( "ScheduleIngestionService::ingestAllSummits trying to delete event %s...", $summit_event->getId())); + $this->event_repository->delete($summit_event); } catch (Exception $ex) { Log::error($ex); } - } - }); + + }); + } } } @@ -157,10 +179,9 @@ final class ScheduleIngestionService $this->tx_service->transaction(function () use ($summit_id) { $summit = $this->summit_repository->getById($summit_id); $mainVenues = $summit->getMainVenues(); - if (count($mainVenues) == 0) + if ($mainVenues->count() == 0) throw new ValidationException(sprintf("summit %s does not has a main venue set!", $summit->getId())); - if (is_null($summit->getBeginDate()) || is_null($summit->getEndDate())) throw new ValidationException(sprintf("summit %s does not has set begin date/end date", $summit->getId())); @@ -169,6 +190,7 @@ final class ScheduleIngestionService // get presentation type from summit $presentationType = $summit->getEventTypeByType(IPresentationType::Presentation); + if (is_null($presentationType)) { // create it $presentationType = new PresentationType(); @@ -194,15 +216,24 @@ final class ScheduleIngestionService $summit = $this->summit_repository->getById($summit_id); if (is_null($summit) || !$summit instanceof Summit) return null; $mainVenues = $summit->getMainVenues(); - $mainVenue = $mainVenues[0]; + + if ($mainVenues->count() == 0) + throw new ValidationException(sprintf("summit %s does not has a main venue set!", $summit->getId())); + + $mainVenue = $mainVenues->first(); + + if(is_null($mainVenue)) + throw new ValidationException(sprintf("summit %s does not has a main venue set!", $summit->getId())); + $presentationType = $summit->getEventTypeByType(IPresentationType::Presentation); - $track_title = $event['track']; - if(empty($track_title)) $track_title = 'TBD'; - $track = $summit->getPresentationCategoryByTitle($track_title); + $track_title = $event['track']; + if (empty($track_title)) $track_title = 'TBD'; + $track_title = str_limit($track_title, 255); + $track = $summit->getPresentationCategoryByTitle($track_title); if (is_null($track)) { $track = new PresentationCategory(); - $track->setTitle($event['track']); + $track->setTitle($track_title); $summit->addPresentationCategory($track); } @@ -225,6 +256,8 @@ final class ScheduleIngestionService $speakerLastName = trim(trim(array_pop($speakerFullNameParts))); $speakerFirstName = trim(implode(" ", $speakerFullNameParts)); + Log::debug(sprintf("processing event %s - %s for summit %s - speaker %s", $event['external_id'], $event['title'], $summit_id, $speakerFullName)); + $foundSpeaker = isset($speakers[$speakerFullName]) ? $speakers[$speakerFullName] : null; if (is_null($foundSpeaker)) { // partial match @@ -235,6 +268,9 @@ final class ScheduleIngestionService } $speakerEmail = $foundSpeaker && isset($foundSpeaker['email']) ? $foundSpeaker['email'] : null; + + Log::debug(sprintf("ScheduleIngestionService::ingestSummit event %s - %s for summit %s speakerEmail %s", $event['external_id'], $event['title'], $summit_id, $speakerEmail )); + $companyName = $foundSpeaker && isset($foundSpeaker['company']) ? $foundSpeaker['company'] : null; $companyPosition = $foundSpeaker && isset($foundSpeaker['position']) ? $foundSpeaker['position'] : null;; $speakerTitle = !empty($companyName) && !empty($companyPosition) ? sprintf("%s, %s", $companyName, $companyPosition) : null; @@ -248,6 +284,7 @@ final class ScheduleIngestionService $member->setLastName($speakerLastName); $this->member_repository->add($member, true); } + $member->setEmail($speakerEmail); $member->setFirstName($speakerFirstName); $member->setLastName($speakerLastName); @@ -272,6 +309,14 @@ final class ScheduleIngestionService // speaker $speaker = $this->speaker_repository->getByFullName($speakerFullName); + if(!is_null($speaker)){ + // we got an existent speaker for that full name, check if has a member assigned + if($speaker->hasMember() && $speaker->getMemberId() !== $member->getId()){ + // speaker already belongs to another user, so we need to create a new one + Log::debug(sprintf("ScheduleIngestionService::ingestSummit speaker alredy belongs to another user (%s) creating a new one", $speaker->getMemberId())); + $speaker = null; + } + } if (is_null($speaker)) { $speaker = new PresentationSpeaker(); diff --git a/app/Services/Model/SpeakerService.php b/app/Services/Model/Imp/SpeakerService.php similarity index 86% rename from app/Services/Model/SpeakerService.php rename to app/Services/Model/Imp/SpeakerService.php index 8fe4dc2c..ddcc95b6 100644 --- a/app/Services/Model/SpeakerService.php +++ b/app/Services/Model/Imp/SpeakerService.php @@ -12,13 +12,17 @@ * limitations under the License. **/ -use App\Mail\SpeakerEditPermissionApprovedEmail; -use App\Mail\SpeakerEditPermissionRejectedEmail; -use App\Mail\SpeakerEditPermissionRequestedEmail; +use App\Jobs\Emails\PresentationSubmissions\SelectionProcess\PresentationSpeakerSelectionProcessEmailFactory; +use App\Jobs\Emails\PresentationSubmissions\SpeakerCreationEmail; +use App\Jobs\Emails\Registration\PromoCodeEmailFactory; +use App\Jobs\Emails\PresentationSubmissions\SpeakerEditPermissionApprovedEmail; +use App\Jobs\Emails\PresentationSubmissions\SpeakerEditPermissionRejectedEmail; +use App\Jobs\Emails\PresentationSubmissions\SpeakerEditPermissionRequestedEmail; use App\Models\Foundation\Main\CountryCodes; use App\Models\Foundation\Main\Repositories\ILanguageRepository; use App\Models\Foundation\Summit\Factories\PresentationSpeakerSummitAssistanceConfirmationRequestFactory; use App\Models\Foundation\Summit\Factories\SpeakerEditPermissionRequestFactory; +use App\Models\Foundation\Summit\PromoCodes\PromoCodesConstants; use App\Models\Foundation\Summit\Repositories\IPresentationSpeakerSummitAssistanceConfirmationRequestRepository; use App\Models\Foundation\Summit\Repositories\ISpeakerActiveInvolvementRepository; use App\Models\Foundation\Summit\Repositories\ISpeakerEditPermissionRequestRepository; @@ -28,18 +32,12 @@ use App\Services\Model\AbstractService; use App\Services\Model\IFolderService; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Log; -use Illuminate\Support\Facades\Mail; use libs\utils\ITransactionService; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; -use models\main\EmailCreationRequest; use models\main\File; -use models\main\IEmailCreationRequestRepository; use models\main\IMemberRepository; use models\main\Member; -use models\main\MemberPromoCodeEmailCreationRequest; -use models\main\SpeakerCreationEmailCreationRequest; -use models\main\SpeakerSelectionAnnouncementEmailCreationRequest; use models\summit\factories\SpeakerSelectionAnnouncementEmailTypeFactory; use models\summit\ISpeakerRegistrationRequestRepository; use models\summit\ISpeakerRepository; @@ -87,11 +85,6 @@ final class SpeakerService */ private $registration_code_repository; - /** - * @var IEmailCreationRequestRepository - */ - private $email_creation_request_repository; - /** * @var IPresentationSpeakerSummitAssistanceConfirmationRequestRepository */ @@ -128,7 +121,6 @@ final class SpeakerService * @param IMemberRepository $member_repository * @param ISpeakerRegistrationRequestRepository $speaker_registration_request_repository * @param ISpeakerSummitRegistrationPromoCodeRepository $registration_code_repository - * @param IEmailCreationRequestRepository $email_creation_request_repository * @param IFolderService $folder_service * @param IPresentationSpeakerSummitAssistanceConfirmationRequestRepository $speakers_assistance_repository * @param ILanguageRepository $language_repository @@ -144,7 +136,6 @@ final class SpeakerService IMemberRepository $member_repository, ISpeakerRegistrationRequestRepository $speaker_registration_request_repository, ISpeakerSummitRegistrationPromoCodeRepository $registration_code_repository, - IEmailCreationRequestRepository $email_creation_request_repository, IFolderService $folder_service, IPresentationSpeakerSummitAssistanceConfirmationRequestRepository $speakers_assistance_repository, ILanguageRepository $language_repository, @@ -161,7 +152,6 @@ final class SpeakerService $this->folder_service = $folder_service; $this->speaker_registration_request_repository = $speaker_registration_request_repository; $this->registration_code_repository = $registration_code_repository; - $this->email_creation_request_repository = $email_creation_request_repository; $this->speakers_assistance_repository = $speakers_assistance_repository; $this->language_repository = $language_repository; $this->speaker_organizational_role_repository = $speaker_organizational_role_repository; @@ -181,8 +171,7 @@ final class SpeakerService return $this->tx_service->transaction(function () use ($data, $creator) { - $speaker = new PresentationSpeaker(); - $speaker->setCreatedFromApi(true); + $member_id = intval($data['member_id'] ?? 0); $email = trim($data['email'] ?? ''); @@ -193,6 +182,23 @@ final class SpeakerService new ValidationException (trans("validation_errors.SpeakerService.addSpeaker.MissingMemberOrEmail")); + $speaker = new PresentationSpeaker(); + $speaker->setCreatedFromApi(true); + + // check if we have a previous registration request and user it + + $formerRegistrationRequest = null; + if(!empty($email)) { + $formerRegistrationRequest = $this->speaker_registration_request_repository->getByEmail($email); + if(!is_null($formerRegistrationRequest)){ + if($formerRegistrationRequest->isConfirmed()){ + throw new ValidationException(sprintf("Speaker already exists and its confirmed.")); + } + $speaker = $formerRegistrationRequest->getSpeaker(); + } + } + + // if we pass the member , honor that and override email if ($member_id > 0) { $member = $this->member_repository->getById($member_id); if (is_null($member) || !$member instanceof Member) @@ -212,6 +218,7 @@ final class SpeakerService $speaker->setMember($member); } + // if we dont pass the member , try to get member by email if ($member_id == 0 && !empty($email)) { Log::debug(sprintf("SpeakerService::addSpeaker: member id is zero email is %s", $email)); $member = $this->member_repository->getByEmail($email); @@ -230,7 +237,8 @@ final class SpeakerService ); $speaker->setMember($member); } - if (is_null($member)) { + // if member does not exists and we dont have a former registration request + if (is_null($member) && is_null($formerRegistrationRequest)) { Log::debug(sprintf("SpeakerService::addSpeaker: member %s not found", $email)); $request = $this->registerSpeaker($speaker, $email); if(!is_null($creator)) @@ -242,9 +250,13 @@ final class SpeakerService $this->speaker_repository->add($this->updateSpeakerRelations($speaker, $data)); - $email_request = new SpeakerCreationEmailCreationRequest(); - $email_request->setSpeaker($speaker); - $this->email_creation_request_repository->add($email_request); + // only send the email if we dont have a former registration request + if(is_null($formerRegistrationRequest)) + SpeakerCreationEmail::dispatch($speaker); + + if(!is_null($formerRegistrationRequest)){ + $formerRegistrationRequest->confirm(); + } if(!is_null($creator)){ // create edit permission for creator @@ -368,7 +380,7 @@ final class SpeakerService do { $registration_request->generateConfirmationToken(); - } while ($this->speaker_registration_request_repository->existByHash($registration_request->getConfirmationHash())); + } while($this->speaker_registration_request_repository->existByHash($registration_request->getConfirmationHash())); $speaker->setRegistrationRequest($registration_request); return $registration_request; @@ -414,12 +426,9 @@ final class SpeakerService $new_code->setSummit($summit); $new_code->setCode($reg_code); $new_code->setSourceAdmin(); - // create email request - $email_request = new MemberPromoCodeEmailCreationRequest(); - $email_request->setPromoCode($new_code); - $email_request->setEmail($speaker->getEmail()); - $email_request->setName($speaker->getFullName()); - $this->email_creation_request_repository->add($email_request); + $new_code->setSpeaker($speaker); + + PromoCodeEmailFactory::send($new_code); } $speaker->addPromoCode($new_code); @@ -428,6 +437,7 @@ final class SpeakerService } return $new_code; }); + } /** @@ -476,6 +486,12 @@ final class SpeakerService if (isset($data['country'])) $speaker->setCountry(trim($data['country'])); + if (isset($data['company'])) + $speaker->setCompany(trim($data['company'])); + + if (isset($data['phone_number'])) + $speaker->setPhoneNumber(trim($data['phone_number'])); + return $speaker; } @@ -580,41 +596,6 @@ final class SpeakerService return $speaker; } - /** - * @param int $speaker_id - * @param UploadedFile $file - * @param int $max_file_size - * @throws ValidationException - * @throws EntityNotFoundException - * @return File - */ - public function addSpeakerPhoto($speaker_id, UploadedFile $file, $max_file_size = 10485760) - { - return $this->tx_service->transaction(function () use ($speaker_id, $file, $max_file_size) { - - $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'pdf']; - - $speaker = $this->speaker_repository->getById($speaker_id); - - if (is_null($speaker)) { - throw new EntityNotFoundException('speaker not found!'); - } - - if (!in_array($file->extension(), $allowed_extensions)) { - throw new ValidationException("file does not has a valid extension ('png','jpg','jpeg','gif','pdf')."); - } - - if ($file->getSize() > $max_file_size) { - throw new ValidationException(sprintf("file exceeds max_file_size (%s MB).", ($max_file_size / 1024) / 1024)); - } - - $photo = $this->file_uploader->build($file, 'profile-images', true); - $speaker->setPhoto($photo); - - return $photo; - }); - } - /** * @param PresentationSpeaker $speaker_from * @param PresentationSpeaker $speaker_to @@ -898,13 +879,12 @@ final class SpeakerService /** * @param Summit $summit * @param int $assistance_id - * @return EmailCreationRequest * @throws EntityNotFoundException * @throws ValidationException */ public function sendSpeakerSummitAssistanceAnnouncementMail(Summit $summit, $assistance_id) { - return $this->tx_service->transaction(function () use ($summit, $assistance_id) { + $this->tx_service->transaction(function () use ($summit, $assistance_id) { $speaker_assistance = $summit->getSpeakerAssistanceById($assistance_id); @@ -925,21 +905,6 @@ final class SpeakerService $role = $speaker->isModeratorFor($summit) ? PresentationSpeaker::RoleModerator : PresentationSpeaker::RoleSpeaker; - /* - if($speaker->announcementEmailAlreadySent($summit)) - throw new ValidationException - ( - trans - ( - 'validation_errors.send_speaker_summit_assistance_announcement_mail_email_already_sent', - [ - 'summit_id' => $summit->getId(), - 'speaker_id' => $speaker->getId() - ] - ) - ); - */ - $promo_code = $speaker->getPromoCodeFor($summit); if (is_null($promo_code)) { @@ -954,7 +919,7 @@ final class SpeakerService $promo_code = $this->registration_code_repository->getNextAvailableByType ( $summit, - SpeakerSummitRegistrationPromoCode::TypeAccepted + PromoCodesConstants::SpeakerSummitRegistrationPromoCodeTypeAccepted ); if (is_null($promo_code)) throw new ValidationException @@ -965,7 +930,7 @@ final class SpeakerService [ 'summit_id' => $summit->getId(), 'speaker_id' => $speaker->getId(), - 'type' => SpeakerSummitRegistrationPromoCode::TypeAccepted + 'type' => PromoCodesConstants::SpeakerSummitRegistrationPromoCodeTypeAccepted ] ) ); @@ -975,7 +940,7 @@ final class SpeakerService $promo_code = $this->registration_code_repository->getNextAvailableByType ( $summit, - SpeakerSummitRegistrationPromoCode::TypeAlternate + PromoCodesConstants::SpeakerSummitRegistrationPromoCodeTypeAlternate ); if (is_null($promo_code)) throw new ValidationException @@ -986,7 +951,7 @@ final class SpeakerService [ 'summit_id' => $summit->getId(), 'speaker_id' => $speaker->getId(), - 'type' => SpeakerSummitRegistrationPromoCode::TypeAccepted + 'type' => PromoCodesConstants::SpeakerSummitRegistrationPromoCodeTypeAccepted ] ) @@ -1023,7 +988,7 @@ final class SpeakerService ) ); - if (!SpeakerSelectionAnnouncementEmailCreationRequest::isValidType($type)) + if (!PresentationSpeakerSelectionProcessEmailFactory::isValidType($type)) throw new ValidationException ( trans @@ -1035,17 +1000,44 @@ final class SpeakerService ) ); - // create email request - $email_request = new SpeakerSelectionAnnouncementEmailCreationRequest(); - $email_request->setPromoCode($promo_code); - $email_request->setSummit($summit); - $email_request->setSpeaker($speaker); - $email_request->setType($type); - $email_request->setSpeakerRole($role); - $this->email_creation_request_repository->add($email_request); + $assistance = $this->generateSpeakerAssistance($summit, $speaker); + PresentationSpeakerSelectionProcessEmailFactory::send + ( + $summit, + $speaker, + $role, + $type, + $promo_code, + $assistance + ); $promo_code->setEmailSent(true); - return $email_request; + }); + } + + /** + * @param Summit $summit + * @param PresentationSpeaker $speaker + * @return PresentationSpeakerSummitAssistanceConfirmationRequest + * @throws \Exception + */ + public function generateSpeakerAssistance(Summit $summit, PresentationSpeaker $speaker):PresentationSpeakerSummitAssistanceConfirmationRequest{ + return $this->tx_service->transaction(function () use ($summit, $speaker) { + $assistance = $this->speakers_assistance_repository->getBySpeaker($speaker, $summit); + + if (is_null($assistance)){ + $assistance = new PresentationSpeakerSummitAssistanceConfirmationRequest(); + $assistance->setSummit($summit); + $assistance->setSpeaker($speaker); + } + + do { + $assistance->generateConfirmationToken(); + } while($this->speakers_assistance_repository->existByHash($assistance)); + + $speaker->addSummitAssistance($assistance); + + return $assistance; }); } @@ -1074,8 +1066,8 @@ final class SpeakerService // build request with factory $request = SpeakerEditPermissionRequestFactory::build($speaker, $requestor); - $token = $request->generateConfirmationToken(); - Mail::to($request->getSpeaker()->getEmail())->send(new SpeakerEditPermissionRequestedEmail($request, $token)); + $token = $request->generateConfirmationToken(); + SpeakerEditPermissionRequestedEmail::dispatch($request, $token); $this->speaker_edit_permisssion_repository->add($request); return $request; @@ -1133,7 +1125,7 @@ final class SpeakerService if($request->isApproved()) throw new ValidationException(); $request->approve(); - Mail::to($request->getRequestedBy()->getEmail())->send(new SpeakerEditPermissionApprovedEmail($request)); + SpeakerEditPermissionApprovedEmail::dispatch($request); return $request; }); } @@ -1154,8 +1146,110 @@ final class SpeakerService if($request->isActionTaken()) throw new ValidationException(); $request->reject(); - Mail::to($request->getRequestedBy()->getEmail())->send(new SpeakerEditPermissionRejectedEmail($request)); + SpeakerEditPermissionRejectedEmail::dispatch($request); return $request; }); } + + /** + * @param int $speaker_id + * @param UploadedFile $file + * @param int $max_file_size + * @throws ValidationException + * @throws EntityNotFoundException + * @return File + */ + public function addSpeakerPhoto($speaker_id, UploadedFile $file, $max_file_size = 10485760) + { + return $this->tx_service->transaction(function () use ($speaker_id, $file, $max_file_size) { + + $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'pdf']; + + $speaker = $this->speaker_repository->getById($speaker_id); + + if (is_null($speaker) || !$speaker instanceof PresentationSpeaker) { + throw new EntityNotFoundException('speaker not found!'); + } + + if (!in_array($file->extension(), $allowed_extensions)) { + throw new ValidationException("file does not has a valid extension ('png','jpg','jpeg','gif','pdf')."); + } + + if ($file->getSize() > $max_file_size) { + throw new ValidationException(sprintf("file exceeds max_file_size (%s MB).", ($max_file_size / 1024) / 1024)); + } + + $photo = $this->file_uploader->build($file, 'profile-images', true); + $speaker->setPhoto($photo); + + return $photo; + }); + } + + + /** + * @inheritDoc + */ + public function deleteSpeakerPhoto($speaker_id): void + { + $this->tx_service->transaction(function () use ($speaker_id) { + + $speaker = $this->speaker_repository->getById($speaker_id); + + if (is_null($speaker) || !$speaker instanceof PresentationSpeaker) { + throw new EntityNotFoundException('speaker not found!'); + } + + $speaker->clearPhoto(); + + }); + } + + /** + * @inheritDoc + */ + public function addSpeakerBigPhoto($speaker_id, UploadedFile $file, $max_file_size = 10485760) + { + return $this->tx_service->transaction(function () use ($speaker_id, $file, $max_file_size) { + + $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'pdf']; + + $speaker = $this->speaker_repository->getById($speaker_id); + + if (is_null($speaker) || !$speaker instanceof PresentationSpeaker) { + throw new EntityNotFoundException('speaker not found!'); + } + + if (!in_array($file->extension(), $allowed_extensions)) { + throw new ValidationException("file does not has a valid extension ('png','jpg','jpeg','gif','pdf')."); + } + + if ($file->getSize() > $max_file_size) { + throw new ValidationException(sprintf("file exceeds max_file_size (%s MB).", ($max_file_size / 1024) / 1024)); + } + + $photo = $this->file_uploader->build($file, 'profile-images', true); + $speaker->setBigPhoto($photo); + + return $photo; + }); + } + + /** + * @inheritDoc + */ + public function deleteSpeakerBigPhoto($speaker_id): void + { + $this->tx_service->transaction(function () use ($speaker_id) { + + + $speaker = $this->speaker_repository->getById($speaker_id); + + if (is_null($speaker) || !$speaker instanceof PresentationSpeaker) { + throw new EntityNotFoundException('speaker not found!'); + } + + $speaker->clearBigPhoto(); + }); + } } \ No newline at end of file diff --git a/app/Services/Model/Imp/SponsorBadgeScanService.php b/app/Services/Model/Imp/SponsorBadgeScanService.php new file mode 100644 index 00000000..ef4444cb --- /dev/null +++ b/app/Services/Model/Imp/SponsorBadgeScanService.php @@ -0,0 +1,118 @@ +repository = $repository; + $this->badge_repository = $badge_repository; + } + + /** + * @param Summit $summit + * @param Member $current_member + * @param array $data + * @return SponsorBadgeScan + * @throws \Exception + */ + public function addBadgeScan(Summit $summit, Member $current_member, array $data): SponsorBadgeScan + { + return $this->tx_service->transaction(function() use($summit, $current_member, $data){ + + $qr_code = trim($data['qr_code']); + $fields = SummitAttendeeBadge::parseQRCode($qr_code); + $prefix = $fields['prefix']; + $scan_date_epoch = intval($data['scan_date']); + $scan_date = new \DateTime("@$scan_date_epoch"); + $begin_date = $summit->getBeginDate(); + $end_date = $summit->getEndDate(); + + if(!($scan_date >= $begin_date && $scan_date <= $end_date)) + throw new ValidationException("scan_date is does not belong to summit period"); + + if($summit->getBadgeQRPrefix() != $prefix) + throw new ValidationException + ( + sprintf + ( + "%s qr code is not valid for summit %s", + $qr_code, + $summit->getId() + ) + ); + + $ticket_number = $fields['ticket_number']; + + $badge = $this->badge_repository->getBadgeByTicketNumber($ticket_number); + + if(is_null($badge)) + throw new EntityNotFoundException("badge not found"); + + $sponsor = $current_member->getSponsorBySummit($summit); + + if(is_null($sponsor)) + throw new ValidationException("current member does not belongs to any summit sponsor"); + + $scan = new SponsorBadgeScan(); + + $scan->setScanDate($scan_date); + $scan->setQRCode($qr_code); + $scan->setUser($current_member); + $scan->setBadge($badge); + $sponsor->addBadgeScan($scan); + + return $scan; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SponsorshipTypeService.php b/app/Services/Model/Imp/SponsorshipTypeService.php new file mode 100644 index 00000000..3c42334c --- /dev/null +++ b/app/Services/Model/Imp/SponsorshipTypeService.php @@ -0,0 +1,134 @@ +repository = $repository; + } + + + /** + * @param array $payload + * @return SponsorshipType + * @throws ValidationException + */ + public function addSponsorShipType(array $payload): SponsorshipType + { + return $this->tx_service->transaction(function() use($payload){ + + $name = trim($payload['name']); + $former_sponsorship_type = $this->repository->getByName($name); + if(!is_null($former_sponsorship_type)) + throw new ValidationException("sponsorship type name already exists"); + + + $label = trim($payload['label']); + $former_sponsorship_type = $this->repository->getByLabel($label); + if(!is_null($former_sponsorship_type)) + throw new ValidationException("sponsorship type label already exists"); + + $sponsorship_type = SponsorshipTypeFactory::build($payload); + $max_order = $this->repository->getMaxOrder(); + $sponsorship_type->setOrder($max_order + 1); + $this->repository->add($sponsorship_type); + return $sponsorship_type; + }); + } + + /** + * @param int $sponsorship_type_id + * @param array $payload + * @return SponsorshipType + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function updateSponsorShipType(int $sponsorship_type_id, array $payload): SponsorshipType + { + return $this->tx_service->transaction(function() use($sponsorship_type_id, $payload){ + $sponsorship_type = $this->repository->getById($sponsorship_type_id); + if(is_null($sponsorship_type)) + throw new EntityNotFoundException("sponsorship not found"); + + if(isset($payload['name'])) { + $name = trim($payload['name']); + $former_sponsorship_type = $this->repository->getByName($name); + if (!is_null($former_sponsorship_type) && $former_sponsorship_type->getId() != $sponsorship_type_id) + throw new ValidationException("sponsorship type name already exists"); + } + + + if(isset($payload['label'])) { + $label = trim($payload['label']); + $former_sponsorship_type = $this->repository->getByLabel($label); + if (!is_null($former_sponsorship_type) && $former_sponsorship_type->getId() != $sponsorship_type_id) + throw new ValidationException("sponsorship type label already exists"); + } + + if (isset($payload['order']) && intval($payload['order']) != $sponsorship_type->getOrder()) { + // request to update order + self::recalculateOrderForCollection($this->repository->getAll(), $sponsorship_type, intval($payload['order'])); + } + + return SponsorshipTypeFactory::populate($sponsorship_type, $payload); + }); + } + + /** + * @param int $sponsorship_type_id + * @throws EntityNotFoundException + */ + public function deleteSponsorShipType(int $sponsorship_type_id): void + { + $this->tx_service->transaction(function() use($sponsorship_type_id){ + $sponsorship_type = $this->repository->getById($sponsorship_type_id); + if(is_null($sponsorship_type)) + throw new EntityNotFoundException("sponsorship not found"); + + $this->repository->delete($sponsorship_type); + + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitAccessLevelTypeService.php b/app/Services/Model/Imp/SummitAccessLevelTypeService.php new file mode 100644 index 00000000..70be32b2 --- /dev/null +++ b/app/Services/Model/Imp/SummitAccessLevelTypeService.php @@ -0,0 +1,120 @@ +repository = $repository; + } + + + /** + * @param Summit $summit + * @param array $data + * @return SummitAccessLevelType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addAccessLevelType(Summit $summit, array $data): SummitAccessLevelType + { + return $this->tx_service->transaction(function() use($summit, $data){ + $name = trim($data['name']); + $former_level = $this->repository->getByName($name); + if(!is_null($former_level) && $former_level->getSummitId() == $summit->getId()){ + throw new ValidationException(sprintf("access level with name %s already exists!", $name)); + } + + $access_level = SummitAccessLevelTypeFactory::build($data); + + $summit->addBadgeAccessLevelType($access_level); + + return $access_level; + + }); + } + + /** + * @param Summit $summit + * @param int $level_id + * @param array $data + * @return SummitAccessLevelType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateAccessLevelType(Summit $summit, int $level_id, array $data): SummitAccessLevelType + { + return $this->tx_service->transaction(function() use($summit, $level_id, $data){ + + $access_level = $summit->getBadgeAccessLevelTypeById($level_id); + if(is_null($access_level)) + throw new EntityNotFoundException; + + if(isset($data['name'])){ + $name = trim($data['name']); + $former_level = $this->repository->getByName($name); + + if (!is_null($former_level) && $former_level->getId() != $level_id && $former_level->getSummitId() == $summit->getId() ) { + throw new ValidationException(sprintf("access level with name %s already exists!", $name)); + } + } + + return SummitAccessLevelTypeFactory::populate($access_level, $data); + + }); + } + + /** + * @param Summit $summit + * @param int $level_id + * @throws EntityNotFoundException + */ + public function deleteAccessLevelType(Summit $summit, int $level_id): void + { + $this->tx_service->transaction(function() use($summit, $level_id){ + $access_level = $summit->getBadgeAccessLevelTypeById($level_id); + if(is_null($access_level)) + throw new EntityNotFoundException; + + $summit->removeBadgeAccessLevelType($access_level); + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitAdministratorPermissionGroupService.php b/app/Services/Model/Imp/SummitAdministratorPermissionGroupService.php new file mode 100644 index 00000000..252ae729 --- /dev/null +++ b/app/Services/Model/Imp/SummitAdministratorPermissionGroupService.php @@ -0,0 +1,221 @@ +repository = $repository; + $this->summit_repository = $summit_repository; + $this->member_repository = $member_repository; + } + + /** + * @inheritDoc + */ + public function create(array $payload): SummitAdministratorPermissionGroup + { + return $this->tx_service->transaction(function () use($payload){ + + $group = $this->repository->getByTitle($payload['title']); + + if(!is_null($group)){ + throw new ValidationException(sprintf("Group %s already exists.", $group->getTitle())); + } + + $group = new SummitAdministratorPermissionGroup(); + + $group->setTitle(trim($payload['title'])); + + foreach ($payload['summits'] as $summit_id){ + $summit = $this->summit_repository->getById(intval($summit_id)); + if(is_null($summit)) continue; + if(!$summit instanceof Summit) continue; + $group->addSummit($summit); + } + + foreach ($payload['members'] as $member_id){ + $member = $this->member_repository->getById(intval($member_id)); + if(is_null($member)) continue; + if(!$member instanceof Member) continue; + $group->addMember($member); + } + + $this->repository->add($group); + + return $group; + }); + } + + /** + * @inheritDoc + */ + public function update(int $id, array $payload): SummitAdministratorPermissionGroup + { + return $this->tx_service->transaction(function () use($id, $payload){ + + if(isset($payload['title'])) { + $former_group = $this->repository->getByTitle($payload['title']); + + if (!is_null($former_group) && $former_group->getId() != $id) { + throw new ValidationException(sprintf("Group %s already exists.", $former_group->getTitle())); + } + } + + $group = $this->repository->getById($id); + + if(is_null($group)) + throw new EntityNotFoundException(); + + if(isset($payload['title'])) { + $group->setTitle(trim($payload['title'])); + } + + if(isset($payload['summits'])) { + $group->clearSummits(); + foreach ($payload['summits'] as $summit_id) { + $summit = $this->summit_repository->getById(intval($summit_id)); + if (is_null($summit)) continue; + if (!$summit instanceof Summit) continue; + $group->addSummit($summit); + } + } + + if(isset($payload['members'])) { + $group->clearMembers(); + foreach ($payload['members'] as $member_id) { + $member = $this->member_repository->getById(intval($member_id)); + if (is_null($member)) continue; + if (!$member instanceof Member) continue; + $group->addMember($member); + } + } + + return $group; + }); + } + + /** + * @inheritDoc + */ + public function delete(int $id): void + { + $this->tx_service->transaction(function () use($id){ + $group = $this->repository->getById($id); + + if(is_null($group)) + throw new EntityNotFoundException(); + + $this->repository->delete($group); + }); + } + + /** + * @inheritDoc + */ + public function addMemberTo(SummitAdministratorPermissionGroup $group, int $member_id): SummitAdministratorPermissionGroup + { + return $this->tx_service->transaction(function () use($group, $member_id){ + $member = $this->member_repository->getById($member_id); + + if(is_null($member) || !$member instanceof Member) + throw new EntityNotFoundException(); + + $group->addMember($member); + }); + } + + /** + * @inheritDoc + */ + public function removeMemberFrom(SummitAdministratorPermissionGroup $group, int $member_id): SummitAdministratorPermissionGroup + { + return $this->tx_service->transaction(function () use($group, $member_id){ + $member = $this->member_repository->getById($member_id); + + if(is_null($member) || !$member instanceof Member) + throw new EntityNotFoundException(); + + $group->removeMember($member); + }); + } + + /** + * @inheritDoc + */ + public function addSummitTo(SummitAdministratorPermissionGroup $group, int $summit_id): SummitAdministratorPermissionGroup + { + return $this->tx_service->transaction(function () use($group, $summit_id){ + $summit = $this->summit_repository->getById($summit_id); + if(is_null($summit) || !$summit instanceof Summit) + throw new EntityNotFoundException(); + + $group->addSummit($summit); + }); + } + + /** + * @inheritDoc + */ + public function removeSummitFrom(SummitAdministratorPermissionGroup $group, int $summit_id): SummitAdministratorPermissionGroup + { + return $this->tx_service->transaction(function () use($group, $summit_id){ + $summit = $this->summit_repository->getById($summit_id); + if(is_null($summit) || !$summit instanceof Summit) + throw new EntityNotFoundException(); + + $group->removeSummit($summit); + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitBadgeFeatureTypeService.php b/app/Services/Model/Imp/SummitBadgeFeatureTypeService.php new file mode 100644 index 00000000..1167c0d4 --- /dev/null +++ b/app/Services/Model/Imp/SummitBadgeFeatureTypeService.php @@ -0,0 +1,104 @@ +tx_service->transaction(function() use($summit, $data){ + $name = trim($data['name']); + $former_feature = $summit->getFeatureTypeByName($name); + if(!is_null($former_feature)){ + throw new ValidationException("feature type name already exists"); + } + + $feature = SummitBadgeFeatureTypeFactory::build($data); + + $summit->addFeatureType($feature); + + return $feature; + + }); + } + + /** + * @param Summit $summit + * @param int $feature_id + * @param array $data + * @return SummitBadgeFeatureType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateBadgeFeatureType(Summit $summit, int $feature_id, array $data): SummitBadgeFeatureType + { + return $this->tx_service->transaction(function() use($summit, $feature_id, $data){ + + $feature = $summit->getFeatureTypeById($feature_id); + if(is_null($feature)) + throw new EntityNotFoundException('feature not found'); + + if(isset($data['name'])) { + $name = trim($data['name']); + $former_feature = $summit->getFeatureTypeByName($name); + if (!is_null($former_feature) && $former_feature->getId() != $feature_id) { + throw new ValidationException("feature type name already exists"); + } + } + + return SummitBadgeFeatureTypeFactory::populate($feature, $data); + + }); + } + + /** + * @param Summit $summit + * @param int $feature_id + * @throws EntityNotFoundException + */ + public function deleteBadgeFeatureType(Summit $summit, int $feature_id): void + { + $this->tx_service->transaction(function() use($summit, $feature_id){ + + $feature = $summit->getFeatureTypeById($feature_id); + if(is_null($feature)) + throw new EntityNotFoundException('feature not found'); + + $summit->removeFeatureType($feature); + + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitBadgeTypeService.php b/app/Services/Model/Imp/SummitBadgeTypeService.php new file mode 100644 index 00000000..2a839354 --- /dev/null +++ b/app/Services/Model/Imp/SummitBadgeTypeService.php @@ -0,0 +1,200 @@ +tx_service->transaction(function () use ($summit, $data) { + $name = trim($data['name']); + + $former_badge_type = $summit->getBadgeTypeByName($name); + if (!is_null($former_badge_type)) { + throw new ValidationException("badge type name already exists"); + } + $is_default = boolval($data['is_default']); + if($is_default && $summit->hasDefaultBadgeType()){ + throw new ValidationException("there is already a default badge type"); + } + $badge_type = SummitBadgeTypeFactory::build($data); + $summit->addBadgeType($badge_type); + return $badge_type; + }); + } + + /** + * @param Summit $summit + * @param int $badge_type_id + * @param array $data + * @return SummitBadgeType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateBadgeType(Summit $summit, int $badge_type_id, array $data): SummitBadgeType + { + return $this->tx_service->transaction(function () use ($summit, $badge_type_id, $data) { + $badge_type = $summit->getBadgeTypeById($badge_type_id); + if (is_null($badge_type)) + throw new EntityNotFoundException("badge type not found"); + + if(isset($data['name'])) { + $name = trim($data['name']); + $former_badge_type = $summit->getBadgeTypeByName($name); + if (!is_null($former_badge_type) && $former_badge_type->getId() != $badge_type_id) { + throw new ValidationException("badge type name already exists"); + } + } + if(isset($data['is_default'])) { + $is_default = boolval($data['is_default']); + if ($is_default && $summit->hasDefaultBadgeType() && !$badge_type->isDefault()) { + throw new ValidationException("there is already a default badge type"); + } + } + + return SummitBadgeTypeFactory::populate($badge_type, $data); + }); + } + + /** + * @param Summit $summit + * @param int $badge_type_id + * @throws EntityNotFoundException + */ + public function deleteBadgeType(Summit $summit, int $badge_type_id): void + { + $this->tx_service->transaction(function () use ($summit, $badge_type_id) { + $badge_type = $summit->getBadgeTypeById($badge_type_id); + if (is_null($badge_type)) + throw new EntityNotFoundException("badge type not found"); + + $summit->removeBadgeType($badge_type); + }); + } + + /** + * @param Summit $summit + * @param int $badge_type_id + * @param int $access_level_id + * @return SummitBadgeType + */ + public function addAccessLevelToBadgeType(Summit $summit, int $badge_type_id, int $access_level_id): SummitBadgeType + { + return $this->tx_service->transaction(function () use ($summit, $badge_type_id, $access_level_id) { + $badge_type = $summit->getBadgeTypeById($badge_type_id); + if (is_null($badge_type)) + throw new EntityNotFoundException("badge type not found"); + + $access_level = $summit->getBadgeAccessLevelTypeById($access_level_id); + if (is_null($access_level)) + throw new EntityNotFoundException("access level type not found"); + + $badge_type->addAccessLevel($access_level); + + return $badge_type; + }); + } + + /** + * @param Summit $summit + * @param int $badge_type_id + * @param int $access_level_id + * @return SummitBadgeType + */ + public function removeAccessLevelFromBadgeType(Summit $summit, int $badge_type_id, int $access_level_id): SummitBadgeType + { + return $this->tx_service->transaction(function () use ($summit, $badge_type_id, $access_level_id) { + $badge_type = $summit->getBadgeTypeById($badge_type_id); + if (is_null($badge_type)) + throw new EntityNotFoundException("badge type not found"); + + $access_level = $summit->getBadgeAccessLevelTypeById($access_level_id); + if (is_null($access_level)) + throw new EntityNotFoundException("access level type not found"); + + $badge_type->removeAccessLevel($access_level); + + return $badge_type; + }); + } + + /** + * @param Summit $summit + * @param int $badge_type_id + * @param int $feature_id + * @return SummitBadgeType + * @throws \Exception + */ + public function addFeatureToBadgeType(Summit $summit, int $badge_type_id, int $feature_id): SummitBadgeType + { + return $this->tx_service->transaction(function () use ($summit, $badge_type_id, $feature_id) { + $badge_type = $summit->getBadgeTypeById($badge_type_id); + if (is_null($badge_type)) + throw new EntityNotFoundException("badge type not found"); + + $feature = $summit->getFeatureTypeById($feature_id); + if (is_null($feature)) + throw new EntityNotFoundException("feature not found"); + + $badge_type->addBadgeFeatureType($feature); + + return $badge_type; + }); + } + + /** + * @param Summit $summit + * @param int $badge_type_id + * @param int $feature_id + * @return SummitBadgeType + * @throws \Exception + */ + public function removeFeatureFromBadgeType(Summit $summit, int $badge_type_id, int $feature_id): SummitBadgeType + { + return $this->tx_service->transaction(function () use ($summit, $badge_type_id, $feature_id) { + $badge_type = $summit->getBadgeTypeById($badge_type_id); + if (is_null($badge_type)) + throw new EntityNotFoundException("badge type not found"); + + $feature = $summit->getFeatureTypeById($feature_id); + if (is_null($feature)) + throw new EntityNotFoundException("feature not found"); + + $badge_type->removeBadgeFeatureType($feature); + + return $badge_type; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitDocumentService.php b/app/Services/Model/Imp/SummitDocumentService.php new file mode 100644 index 00000000..1b69a571 --- /dev/null +++ b/app/Services/Model/Imp/SummitDocumentService.php @@ -0,0 +1,240 @@ +file_uploader = $file_uploader; + $this->folder_repository = $folder_repository; + } + + /** + * @param Summit $summit + * @param array $payload + * @return SummitDocument + * @throws \Exception + */ + public function addSummitDocument(Summit $summit, array $payload): SummitDocument + { + return $this->tx_service->transaction(function() use($summit, $payload){ + + if(isset($payload['name'])){ + $former_document = $summit->getSummitDocumentByName($payload['name']); + if(!is_null($former_document)) + throw new ValidationException(sprintf("name %s already exists.", $payload['name'])); + } + + if(isset($payload['label'])){ + $former_document = $summit->getSummitDocumentByLabel($payload['label']); + if(!is_null($former_document) ) + throw new ValidationException(sprintf("label %s already exists.", $payload['label'])); + } + + $document = SummitDocumentFactory::build($summit, $payload); + + if(isset($payload['event_types'])){ + $document->clearEventTypes(); + foreach($payload['event_types'] as $event_type_id){ + $event_type = $summit->getEventType(intval($event_type_id)); + if(is_null($event_type)){ + throw new EntityNotFoundException(); + } + $document->addEventType($event_type); + } + } + + $file = $payload['file']; + $attachment = $this->file_uploader->build + ( + $file, + sprintf('summits/%s/documents', $summit->getId()), + false + ); + + $document->setFile($attachment); + + $summit->addSummitDocument($document); + + return $document; + + }); + } + + /** + * @param Summit $summit + * @param int $document_id + * @param array $payload + * @return SummitDocument + * @throws \Exception + */ + public function updateSummitDocument(Summit $summit, int $document_id, array $payload): SummitDocument + { + return $this->tx_service->transaction(function() use($summit, $document_id, $payload){ + + $document = $summit->getSummitDocumentById($document_id); + if(is_null($document)) + throw new EntityNotFoundException(); + + if(isset($payload['name'])){ + $former_document = $summit->getSummitDocumentByName($payload['name']); + if(!is_null($former_document) && $former_document->getId() !== $document_id) + throw new ValidationException(sprintf("name %s already exists.", $payload['name'])); + } + + if(isset($payload['label'])){ + $former_document = $summit->getSummitDocumentByLabel($payload['label']); + if(!is_null($former_document) && $former_document->getId() !== $document_id) + throw new ValidationException(sprintf("label %s already exists.", $payload['label'])); + } + + $document = SummitDocumentFactory::populate($summit, $document, $payload); + + if(isset($payload['event_types'])){ + $document->clearEventTypes(); + foreach($payload['event_types'] as $event_type_id){ + $event_type = $summit->getEventType(intval($event_type_id)); + if(is_null($event_type)){ + throw new EntityNotFoundException(); + } + $document->addEventType($event_type); + } + } + + if(isset($payload['file'])){ + + if($document->hasFile()){ + // drop file + $attachment = $document->getFile(); + $this->folder_repository->delete($attachment); + $document->clearFile(); + $attachment = null; + } + + $attachment = $this->file_uploader->build + ( + $payload['file'], + sprintf('summits/%s/documents', $summit->getId()), + false + ); + + $document->setFile($attachment); + } + + return $document; + }); + } + + /** + * @param Summit $summit + * @param int $document_id + * @throws \Exception + */ + public function deleteSummitDocument(Summit $summit, int $document_id): void + { + $this->tx_service->transaction(function() use($summit, $document_id){ + $document = $summit->getSummitDocumentById($document_id); + if(is_null($document)) + throw new EntityNotFoundException(); + + $summit->removeSummitDocument($document); + }); + } + + /** + * @param Summit $summit + * @param int $document_id + * @param int $event_type_id + * @return SummitDocument + * @throws \Exception + */ + public function addEventTypeToSummitDocument(Summit $summit, int $document_id, int $event_type_id): SummitDocument + { + return $this->tx_service->transaction(function() use($summit, $document_id, $event_type_id){ + $document = $summit->getSummitDocumentById($document_id); + if(is_null($document)) + throw new EntityNotFoundException(); + + $event_type = $summit->getEventType($event_type_id); + if(is_null($event_type)) + throw new EntityNotFoundException(); + + $document->addEventType($event_type); + + return $document; + }); + } + + /** + * @param Summit $summit + * @param int $document_id + * @param int $event_type_id + * @return SummitDocument + * @throws \Exception + */ + public function removeEventTypeFromSummitDocument(Summit $summit, int $document_id, int $event_type_id): SummitDocument + { + return $this->tx_service->transaction(function() use($summit, $document_id, $event_type_id){ + $document = $summit->getSummitDocumentById($document_id); + if(is_null($document)) + throw new EntityNotFoundException(); + + $event_type = $summit->getEventType($event_type_id); + if(is_null($event_type)) + throw new EntityNotFoundException(); + + $document->removeEventType($event_type); + + return $document; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitEmailEventFlowService.php b/app/Services/Model/Imp/SummitEmailEventFlowService.php new file mode 100644 index 00000000..340a55a9 --- /dev/null +++ b/app/Services/Model/Imp/SummitEmailEventFlowService.php @@ -0,0 +1,65 @@ +tx_service->transaction(function () use ($summit, $event_id, $data) { + $event = $summit->getEmailEventById($event_id); + if (is_null($event)) + throw new EntityNotFoundException("Email Event not found"); + + $event->setEmailTemplateIdentifier(trim($data['email_template_identifier'])); + + return $event; + }); + } + + /** + * @param Summit $summit + * @param int $event_id + * @throws \Exception + */ + public function deleteEmailEventFlow(Summit $summit, int $event_id): void + { + $this->tx_service->transaction(function () use ($summit, $event_id) { + $event = $summit->getEmailEventById($event_id); + if (is_null($event)) + throw new EntityNotFoundException("Email Event not found"); + + $summit->removeEmailEventFlow($event); + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/SummitEventTypeService.php b/app/Services/Model/Imp/SummitEventTypeService.php similarity index 82% rename from app/Services/Model/SummitEventTypeService.php rename to app/Services/Model/Imp/SummitEventTypeService.php index 992bdad9..6d1b23fd 100644 --- a/app/Services/Model/SummitEventTypeService.php +++ b/app/Services/Model/Imp/SummitEventTypeService.php @@ -232,4 +232,52 @@ final class SummitEventTypeService return $added_types; } + + /** + * @param Summit $summit + * @param int $event_type_id + * @param int $document_id + * @return SummitEventType + * @throws \Exception + */ + public function addSummitDocumentToEventType(Summit $summit, int $event_type_id, int $document_id): SummitEventType + { + return $this->tx_service->transaction(function() use($summit, $event_type_id, $document_id){ + $document = $summit->getSummitDocumentById($document_id); + if(is_null($document)) + throw new EntityNotFoundException(); + + $event_type = $summit->getEventType($event_type_id); + if(is_null($event_type)) + throw new EntityNotFoundException(); + + $document->addEventType($event_type); + + return $event_type; + }); + } + + /** + * @param Summit $summit + * @param int $event_type_id + * @param int $document_id + * @return SummitEventType + * @throws \Exception + */ + public function removeSummitDocumentFromEventType(Summit $summit, int $event_type_id, int $document_id): SummitEventType + { + return $this->tx_service->transaction(function() use($summit, $event_type_id, $document_id){ + $document = $summit->getSummitDocumentById($document_id); + if(is_null($document)) + throw new EntityNotFoundException(); + + $event_type = $summit->getEventType($event_type_id); + if(is_null($event_type)) + throw new EntityNotFoundException(); + + $document->removeEventType($event_type); + + return $event_type; + }); + } } \ No newline at end of file diff --git a/app/Services/Model/SummitLocationService.php b/app/Services/Model/Imp/SummitLocationService.php similarity index 93% rename from app/Services/Model/SummitLocationService.php rename to app/Services/Model/Imp/SummitLocationService.php index 13d7aca6..368ee2c6 100644 --- a/app/Services/Model/SummitLocationService.php +++ b/app/Services/Model/Imp/SummitLocationService.php @@ -31,11 +31,11 @@ use App\Models\Foundation\Summit\Factories\SummitLocationImageFactory; use App\Models\Foundation\Summit\Factories\SummitRoomReservationFactory; use App\Models\Foundation\Summit\Factories\SummitVenueFloorFactory; use App\Models\Foundation\Summit\Locations\Banners\SummitLocationBanner; +use App\Models\Foundation\Summit\Registration\IBuildDefaultPaymentGatewayProfileStrategy; use App\Models\Foundation\Summit\Repositories\ISummitLocationRepository; use App\Models\Foundation\Summit\Repositories\ISummitRoomReservationRepository; use App\Services\Apis\GeoCodingApiException; use App\Services\Apis\IGeoCodingAPI; -use App\Services\Apis\IPaymentGatewayAPI; use App\Services\Model\Strategies\GeoLocation\GeoLocationStrategyFactory; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Event; @@ -46,6 +46,7 @@ use models\exceptions\ValidationException; use models\main\File; use models\main\IMemberRepository; use models\main\Member; +use models\summit\IPaymentConstants; use models\summit\Summit; use models\summit\SummitAbstractLocation; use models\summit\SummitBookableVenueRoom; @@ -78,11 +79,6 @@ final class SummitLocationService */ private $folder_service; - /** - * @var IPaymentGatewayAPI - */ - private $payment_gateway; - /** * @var IMemberRepository */ @@ -98,6 +94,11 @@ final class SummitLocationService */ private $file_uploader; + /** + * @var IBuildDefaultPaymentGatewayProfileStrategy + */ + private $default_payment_gateway_strategy; + /** * SummitLocationService constructor. * @param ISummitLocationRepository $location_repository @@ -106,7 +107,7 @@ final class SummitLocationService * @param IGeoCodingAPI $geo_coding_api * @param IFolderService $folder_service * @param IFileUploader $file_uploader - * @param IPaymentGatewayAPI $payment_gateway + * @param IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy * @param ITransactionService $tx_service */ public function __construct @@ -117,7 +118,7 @@ final class SummitLocationService IGeoCodingAPI $geo_coding_api, IFolderService $folder_service, IFileUploader $file_uploader, - IPaymentGatewayAPI $payment_gateway, + IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy, ITransactionService $tx_service ) { @@ -129,7 +130,7 @@ final class SummitLocationService $this->geo_coding_api = $geo_coding_api; $this->file_uploader = $file_uploader; $this->folder_service = $folder_service; - $this->payment_gateway = $payment_gateway; + $this->default_payment_gateway_strategy = $default_payment_gateway_strategy; } /** @@ -1697,7 +1698,16 @@ final class SummitLocationService { return $this->tx_service->transaction(function () use ($summit, $room_id, $payload) { - $room = $this->location_repository->find($room_id, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE); + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeBookableRooms, + $this->default_payment_gateway_strategy + ); + + if(is_null($payment_gateway)) + throw new ValidationException(sprintf("Payment configuration is not set for summit %s", $summit->getId())); + + $room = $this->location_repository->getByIdExclusiveLock($room_id); if (is_null($room)) { throw new EntityNotFoundException("room not found"); @@ -1753,15 +1763,16 @@ final class SummitLocationService $room->addReservation($reservation); - $result = $this->payment_gateway->generatePayment + $result = $payment_gateway->generatePayment ( [ "amount" => $reservation->getAmount(), "currency" => $reservation->getCurrency(), "receipt_email" => $reservation->getOwner()->getEmail(), "metadata" => [ - "type" => "bookable_room_reservation", - "room_id" => $room->getId(), + "type" => IPaymentConstants::ApplicationTypeBookableRooms, + "room_id" => $room->getId(), + "summit_id" => $summit->getId(), ] ] ); @@ -1781,32 +1792,44 @@ final class SummitLocationService /** * @param array $payload + * @param Summit|null $summit * @throws \Exception */ - public function processBookableRoomPayment(array $payload): void + public function processPayment(array $payload, ?Summit $summit = null): void { - $this->tx_service->transaction(function () use ($payload) { + $this->tx_service->transaction(function () use ($summit, $payload) { + + Log::debug(sprintf("SummitLocationService::processPayment cart_id %s", $payload['cart_id'])); $reservation = $this->reservation_repository->getByPaymentGatewayCartIdExclusiveLock($payload['cart_id']); if (is_null($reservation)) { - throw new EntityNotFoundException(sprintf("there is no reservation with cart_id %s", $payload['cart_id'])); + throw new EntityNotFoundException(sprintf("There is no reservation with cart_id %s.", $payload['cart_id'])); } - try { - if ($this->payment_gateway->isSuccessFullPayment($payload)) { - Log::debug("SummitLocationService::processBookableRoomPayment: payment is sucessfull"); - $reservation->setPaid(); - return; - } - } catch (ValidationException $ex) { - Log::error($ex); - Log::warning("doing refund of cancelled reservation"); - $reservation->setStatus(SummitRoomReservation::RequestedRefundStatus); - $this->refundReservation($reservation->getRoom(), $reservation->getId(), $reservation->getAmount()); + if(!is_null($summit) && $reservation->getRoom()->getSummitId() != $summit->getId()){ + throw new EntityNotFoundException(sprintf("There is no reservation with cart_id %s.", $payload['cart_id'])); } - $reservation->setPaymentError($this->payment_gateway->getPaymentError($payload)); + $summit = $reservation->getRoom()->getSummit(); + + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeBookableRooms, + $this->default_payment_gateway_strategy + ); + + if(is_null($payment_gateway)){ + throw new ValidationException(sprintf("Payment configuration is not set for summit %s", $summit->getId())); + } + + if ($payment_gateway->isSuccessFullPayment($payload)) { + Log::debug("SummitLocationService::processPayment: payment is successful"); + $reservation->setPaid(); + return; + } + + $reservation->setPaymentError($payment_gateway->getPaymentError($payload)); }); } @@ -1863,6 +1886,14 @@ final class SummitLocationService if (is_null($reservation)) { throw new EntityNotFoundException(); } + $summit = $room->getSummit(); + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeBookableRooms, + $this->default_payment_gateway_strategy + ); + if(is_null($payment_gateway)) + throw new ValidationException(sprintf("Payment configuration is not set for summit %s", $summit->getId())); $status = $reservation->getStatus(); $validStatuses = [SummitRoomReservation::RequestedRefundStatus, SummitRoomReservation::PaidStatus]; @@ -1885,7 +1916,7 @@ final class SummitLocationService } try { - $this->payment_gateway->refundPayment($reservation->getPaymentGatewayCartId(), $amount, $reservation->getCurrency()); + $payment_gateway->refundPayment($reservation->getPaymentGatewayCartId(), $amount, $reservation->getCurrency()); } catch (\Exception $ex) { throw new ValidationException($ex->getMessage()); } @@ -2361,19 +2392,37 @@ final class SummitLocationService $reservation = $this->reservation_repository->getByIdExclusiveLock($reservation->getId()); if (!$reservation instanceof SummitRoomReservation) return; - Log::warning(sprintf("cancelling reservation %s created at %s", $reservation->getId(), $reservation->getCreated()->format("Y-m-d h:i:sa"))); - $status = $this->payment_gateway->getCartStatus($reservation->getPaymentGatewayCartId()); - if (!$this->payment_gateway->canAbandon($status)) { - Log::warning(sprintf("reservation %s created at %s can not be cancelled external status %s", $reservation->getId(), $reservation->getCreated()->format("Y-m-d h:i:sa"), $status)); - if($this->payment_gateway->isSucceeded($status)){ - $reservation->setPaid(); - } + $summit = $reservation->getRoom()->getSummit(); + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeBookableRooms, + $this->default_payment_gateway_strategy + ); + + if(is_null($payment_gateway)){ + Log::warning(sprintf("Payment configuration is not set for summit %s", $summit->getId())); return; } - $this->payment_gateway->abandonCart($reservation->getPaymentGatewayCartId()); + Log::debug(sprintf("[SummitLocationService::revokeBookableRoomsReservedOlderThanNMinutes] cancelling reservation %s created at %s", $reservation->getId(), $reservation->getCreated()->format("Y-m-d h:i:sa"))); + $status = $payment_gateway->getCartStatus($reservation->getPaymentGatewayCartId()); + if(!is_null($status)) { + Log::debug(sprintf("[SummitLocationService::revokeBookableRoomsReservedOlderThanNMinutes] got status %s for reservation %s", $status, $reservation->getId())); + if (!$payment_gateway->canAbandon($status)) { + Log::warning(sprintf("[SummitLocationService::revokeBookableRoomsReservedOlderThanNMinutes] reservation %s created at %s can not be cancelled external status %s", $reservation->getId(), $reservation->getCreated()->format("Y-m-d h:i:sa"), $status)); + if ($payment_gateway->isSucceeded($status)) { + Log::debug(sprintf("[SummitLocationService::revokeBookableRoomsReservedOlderThanNMinutes] set reservation %s as paid", $status, $reservation->getId())); + $reservation->setPaid(); + } + return; + } + + $payment_gateway->abandonCart($reservation->getPaymentGatewayCartId()); + } $reservation->cancel(); + + Log::debug(sprintf("[SummitLocationService::revokeBookableRoomsReservedOlderThanNMinutes] reservation %s created at %s canceled", $reservation->getId(), $reservation->getCreated()->format("Y-m-d h:i:sa"))); } catch (\Exception $ex) { Log::warning($ex); } diff --git a/app/Services/Model/Imp/SummitMediaFileTypeService.php b/app/Services/Model/Imp/SummitMediaFileTypeService.php new file mode 100644 index 00000000..772471af --- /dev/null +++ b/app/Services/Model/Imp/SummitMediaFileTypeService.php @@ -0,0 +1,99 @@ +repository = $repository; + } + + /** + * @inheritDoc + */ + public function add(array $payload): SummitMediaFileType + { + return $this->tx_service->transaction(function() use($payload){ + $type = $this->repository->getByName(trim($payload['name'])); + if(!is_null($type)) + throw new ValidationException(sprintf("Name %s already exists.", $payload['name'])); + $type = SummitMediaFileTypeFactory::build($payload); + $this->repository->add($type); + return $type; + }); + } + + /** + * @inheritDoc + */ + public function update(int $id, array $payload): SummitMediaFileType + { + return $this->tx_service->transaction(function() use($id, $payload){ + $type = $this->repository->getById($id); + if(is_null($type)) + throw new EntityNotFoundException(); + if($type->IsSystemDefined()) + throw new ValidationException("You can not modify a system defined type."); + + if(isset($payload['name'])){ + $type = $this->repository->getByName(trim($payload['name'])); + if(!is_null($type) && $type->getId() != $id) + throw new ValidationException(sprintf("Name %s already exists.", $payload['name'])); + } + + return SummitMediaFileTypeFactory::populate($type, $payload); + }); + } + + /** + * @inheritDoc + */ + public function delete(int $id): void + { + $this->tx_service->transaction(function() use($id){ + $type = $this->repository->getById($id); + if(is_null($type)) + throw new EntityNotFoundException(); + if($type->IsSystemDefined()) + throw new ValidationException("You can not delete a system defined type."); + + $this->repository->delete($type); + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitMediaUploadTypeService.php b/app/Services/Model/Imp/SummitMediaUploadTypeService.php new file mode 100644 index 00000000..2bd597b3 --- /dev/null +++ b/app/Services/Model/Imp/SummitMediaUploadTypeService.php @@ -0,0 +1,248 @@ +media_file_type_repository = $media_file_type_repository; + } + + /** + * @inheritDoc + */ + public function add(Summit $summit, array $data): SummitMediaUploadType + { + return $this->tx_service->transaction(function() use($summit, $data){ + + // name should be unique per summit + if(isset($data['name'])) { + $media_upload = $summit->getMediaUploadTypeByName($data['name']); + if(!is_null($media_upload)){ + throw new ValidationException(sprintf("Media upload name %s already exists at summit %s", $data['name'], $summit->getId())); + } + } + + $type = $this->media_file_type_repository->find(intval($data['type_id'])); + if(is_null($type)) + throw new EntityNotFoundException("Media File Type not found."); + + $media_upload = SummitMediaUploadTypeFactory::build($data); + + if(!$media_upload->hasStorageSet()){ + throw new ValidationException("You must set a Public or Private Storage Type."); + } + + $media_upload->setType($type); + + $summit->addMediaUploadType($media_upload); + + if(isset($data['presentation_types'])){ + foreach($data['presentation_types'] as $event_type_id){ + $presentation_type = $summit->getEventType(intval($event_type_id)); + if(is_null($presentation_type) || !$presentation_type instanceof PresentationType) + throw new EntityNotFoundException(sprintf("Presentation Type %s not found", $event_type_id)); + $media_upload->addPresentationType($presentation_type); + } + } + + return $media_upload; + }); + } + + /** + * @inheritDoc + */ + public function update(Summit $summit, int $media_upload_type_id, array $data): SummitMediaUploadType + { + return $this->tx_service->transaction(function() use($summit, $media_upload_type_id, $data){ + + // name should be unique per summit + if(isset($data['name'])) { + $media_upload = $summit->getMediaUploadTypeByName($data['name']); + if(!is_null($media_upload) && $media_upload->getId() != $media_upload_type_id){ + throw new ValidationException(sprintf("Media upload name %s already exists at summit %s", $data['name'], $summit->getId())); + } + } + + $media_upload = $summit->getMediaUploadTypeById($media_upload_type_id); + if(is_null($media_upload)) + throw new EntityNotFoundException(sprintf("Media upload %s not found at summit %s", $media_upload_type_id, $summit->getId())); + + $media_upload = SummitMediaUploadTypeFactory::populate($media_upload, $data); + + if(!$media_upload->hasStorageSet()){ + throw new ValidationException("You must set a Public or Private Storage Type."); + } + + if(isset($data['type_id'])) { + $type = $this->media_file_type_repository->find(intval($data['type_id'])); + if (is_null($type)) + throw new EntityNotFoundException("Media File Type not found."); + $media_upload->setType($type); + } + + if(isset($data['presentation_types'])){ + $media_upload->clearPresentationTypes(); + foreach($data['presentation_types'] as $event_type_id){ + $presentation_type = $summit->getEventType(intval($event_type_id)); + if(is_null($presentation_type) || !$presentation_type instanceof PresentationType) + throw new EntityNotFoundException(sprintf("Presentation Type %s not found", $event_type_id)); + $media_upload->addPresentationType($presentation_type); + } + } + + return $media_upload; + }); + } + + /** + * @inheritDoc + */ + public function delete(Summit $summit, int $media_upload_type_id): void + { + $this->tx_service->transaction(function() use($summit, $media_upload_type_id){ + $media_upload = $summit->getMediaUploadTypeById($media_upload_type_id); + if(is_null($media_upload)) + throw new EntityNotFoundException(sprintf("Media upload %s not found at summit %s", $media_upload_type_id, $summit->getId())); + + $summit->removeMediaUploadType($media_upload); + }); + } + + /** + * @inheritDoc + */ + public function addToPresentationType(Summit $summit, int $media_upload_type_id, int $presentation_type_id): SummitMediaUploadType + { + return $this->tx_service->transaction(function() use($summit, $media_upload_type_id, $presentation_type_id){ + $media_upload = $summit->getMediaUploadTypeById($media_upload_type_id); + if(is_null($media_upload)) + throw new EntityNotFoundException(sprintf("Media upload %s not found at summit %s", $media_upload_type_id, $summit->getId())); + + $presentation_type = $summit->getEventType(intval($presentation_type_id)); + if(is_null($presentation_type) || !$presentation_type instanceof PresentationType) + throw new EntityNotFoundException(sprintf("Presentation Type %s not found", $presentation_type_id)); + + $media_upload->addPresentationType($presentation_type); + + return $media_upload; + }); + } + + /** + * @inheritDoc + */ + public function deleteFromPresentationType(Summit $summit, int $media_upload_type_id, int $presentation_type_id): SummitMediaUploadType + { + return $this->tx_service->transaction(function() use($summit, $media_upload_type_id, $presentation_type_id){ + $media_upload = $summit->getMediaUploadTypeById($media_upload_type_id); + if(is_null($media_upload)) + throw new EntityNotFoundException(sprintf("Media upload %s not found at summit %s", $media_upload_type_id, $summit->getId())); + + $presentation_type = $summit->getEventType(intval($presentation_type_id)); + if(is_null($presentation_type) || !$presentation_type instanceof PresentationType) + throw new EntityNotFoundException(sprintf("Presentation Type %s not found", $presentation_type_id)); + + $media_upload->removePresentationType($presentation_type); + + return $media_upload; + }); + } + + /** + * @param Summit $fromSummit + * @param Summit $toSummit + * @return Summit + * @throws \Exception + */ + public function cloneMediaUploadTypes(Summit $fromSummit, Summit $toSummit): Summit + { + return $this->tx_service->transaction(function() use($fromSummit, $toSummit){ + + foreach($fromSummit->getMediaUploadTypes() as $mediaUploadType){ + if($toSummit->getMediaUploadTypeByName($mediaUploadType->getName())) continue; + + $newMediaUploadType = new SummitMediaUploadType(); + $newMediaUploadType->setName($mediaUploadType->getName()); + $newMediaUploadType->setDescription($mediaUploadType->getDescription()); + $newMediaUploadType->setType($mediaUploadType->getType()); + $newMediaUploadType->setMaxSize($mediaUploadType->getMaxSize()); + $newMediaUploadType->setPublicStorageType($mediaUploadType->getPublicStorageType()); + $newMediaUploadType->setPrivateStorageType($mediaUploadType->getPrivateStorageType()); + + foreach ($mediaUploadType->getPresentationTypes() as $presentationType){ + $newPresentationType = $toSummit->getEventTypeByType($presentationType->getType()); + if(is_null($newPresentationType)){ + $newPresentationType = new PresentationType(); + $newPresentationType->setType($presentationType->getType()); + $newPresentationType->setColor($presentationType->getColor()); + $newPresentationType->setIsPrivate($presentationType->isPrivate()); + $newPresentationType->setAllowsAttachment($presentationType->isAllowsAttachment()); + $newPresentationType->setAreSpeakersMandatory($presentationType->isAreSpeakersMandatory()); + $newPresentationType->setUseSpeakers($presentationType->isUseSpeakers()); + $newPresentationType->setAreSponsorsMandatory($presentationType->isAreSponsorsMandatory()); + $newPresentationType->setUseSponsors($presentationType->isUseSponsors()); + $newPresentationType->setBlackoutTimes($presentationType->isBlackoutTimes()); + $newPresentationType->setShouldBeAvailableOnCfp($presentationType->isShouldBeAvailableOnCfp()); + $newPresentationType->setIsModeratorMandatory($presentationType->isModeratorMandatory()); + $newPresentationType->setUseModerator($presentationType->isUseModerator()); + $newPresentationType->setMaxModerators($presentationType->getMaxModerators()); + $newPresentationType->setMaxSpeakers($presentationType->getMaxSpeakers()); + $newPresentationType->setMinModerators($presentationType->getMinModerators()); + $newPresentationType->setMinSpeakers($presentationType->getMinSpeakers()); + $newPresentationType->setModeratorLabel($presentationType->getModeratorLabel()); + $toSummit->addEventType($newPresentationType); + } + $newMediaUploadType->addPresentationType($newPresentationType); + } + + $toSummit->addMediaUploadType($newMediaUploadType); + } + + return $toSummit; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitOrderExtraQuestionTypeService.php b/app/Services/Model/Imp/SummitOrderExtraQuestionTypeService.php new file mode 100644 index 00000000..b982a4ee --- /dev/null +++ b/app/Services/Model/Imp/SummitOrderExtraQuestionTypeService.php @@ -0,0 +1,254 @@ +repository = $repository; + } + + /** + * @param Summit $summit + * @param array $payload + * @return SummitOrderExtraQuestionType + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function addOrderExtraQuestion(Summit $summit, array $payload): SummitOrderExtraQuestionType + { + return $this->tx_service->transaction(function () use ($summit, $payload) { + $name = trim($payload['name']); + $former_question = $summit->getOrderExtraQuestionByName($name); + if(!is_null($former_question)) + throw new ValidationException("question name already exists for summit"); + + $label = trim($payload['label']); + $former_question = $summit->getOrderExtraQuestionByLabel($label); + if(!is_null($former_question)) + throw new ValidationException("question label already exists for summit"); + + $question = SummitOrderExtraQuestionTypeFactory::build($payload); + + $summit->addOrderExtraQuestion($question); + + return $question; + }); + } + + /** + * @param Summit $summit + * @param int $question_id + * @param array $payload + * @return SummitOrderExtraQuestionType + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function updateOrderExtraQuestion(Summit $summit, int $question_id, array $payload): SummitOrderExtraQuestionType + { + return $this->tx_service->transaction(function () use ($summit, $question_id, $payload) { + + $question = $summit->getOrderExtraQuestionById($question_id); + if(is_null($question)) + throw new EntityNotFoundException("question not found"); + + if(isset($payload['name'])) { + $name = trim($payload['name']); + $former_question = $summit->getOrderExtraQuestionByName($name); + if (!is_null($former_question) && $former_question->getId() != $question_id) + throw new ValidationException("question name already exists for summit"); + } + + if(isset($payload['label'])) { + $label = trim($payload['label']); + $former_question = $summit->getOrderExtraQuestionByLabel($label); + if (!is_null($former_question) && $former_question->getId() != $question_id) + throw new ValidationException("question label already exists for summit"); + } + + if (isset($payload['order']) && intval($payload['order']) != $question->getOrder()) { + // request to update order + $summit->recalculateQuestionOrder($question, intval($payload['order']) ); + } + + return SummitOrderExtraQuestionTypeFactory::populate($question, $payload); + }); + } + + /** + * @param Summit $summit + * @param int $question_id + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function deleteOrderExtraQuestion(Summit $summit, int $question_id): void + { + $this->tx_service->transaction(function () use ($summit, $question_id) { + + $question = $summit->getOrderExtraQuestionById($question_id); + if(is_null($question)) + throw new EntityNotFoundException("question not found"); + + // check if question has answers + + if($this->repository->hasAnswers($question)){ + //throw new ValidationException(sprintf("you can not delete question %s bc already has answers from attendees", $question_id)); + $this->repository->deleteAnswersFrom($question); + } + + $summit->removeOrderExtraQuestion($question); + }); + } + + /** + * @param Summit $summit + * @param int $question_id + * @param array $payload + * @return SummitOrderExtraQuestionValue + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function addOrderExtraQuestionValue(Summit $summit, int $question_id, array $payload): SummitOrderExtraQuestionValue + { + return $this->tx_service->transaction(function () use ($summit, $question_id, $payload) { + $question = $summit->getOrderExtraQuestionById($question_id); + if(is_null($question)) + throw new EntityNotFoundException("question not found"); + + $name = trim($payload['value']); + $former_value = $question->getValueByName($name); + if(!is_null($former_value)) + throw new ValidationException("value already exists"); + + if(isset($payload['label'])) { + $label = trim($payload['label']); + $former_value = $question->getValueByLabel($label); + if (!is_null($former_value)) + throw new ValidationException("value already exists"); + } + + $value = SummitOrderExtraQuestionValueFactory::build($payload); + + $question->addValue($value); + + return $value; + + }); + } + + /** + * @param Summit $summit + * @param int $question_id + * @param int $value_id + * @param array $payload + * @return SummitOrderExtraQuestionValue + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function updateOrderExtraQuestionValue(Summit $summit, int $question_id, int $value_id, array $payload): SummitOrderExtraQuestionValue + { + return $this->tx_service->transaction(function () use ($summit, $question_id, $value_id, $payload) { + $question = $summit->getOrderExtraQuestionById($question_id); + if(is_null($question)) + throw new EntityNotFoundException("question not found"); + + $value = $question->getValueById($value_id); + if(is_null($value)) + throw new EntityNotFoundException("value not found"); + + if(isset($payload['value'])) { + $name = trim($payload['value']); + $former_value = $question->getValueByName($name); + if (!is_null($former_value) && $former_value->getId() != $value_id) + throw new ValidationException("value already exists"); + } + + if(isset($payload['label'])) { + $label = trim($payload['label']); + $former_value = $question->getValueByLabel($label); + if (!is_null($former_value) && $former_value->getId() != $value_id) + throw new ValidationException("value already exists"); + } + + + if (isset($payload['order']) && intval($payload['order']) != $value->getOrder()) { + // request to update order + $question->recalculateValueOrder($value, intval($payload['order']) ); + } + + return SummitOrderExtraQuestionValueFactory::populate($value, $payload); + }); + } + + /** + * @param Summit $summit + * @param int $question_id + * @param int $value_id + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function deleteOrderExtraQuestionValue(Summit $summit, int $question_id, int $value_id): void + { + $this->tx_service->transaction(function () use ($summit, $question_id, $value_id) { + $question = $summit->getOrderExtraQuestionById($question_id); + if(is_null($question)) + throw new EntityNotFoundException("question not found"); + + $value = $question->getValueById($value_id); + + if(is_null($value)) + throw new EntityNotFoundException("value not found"); + + // check if question has answers + + if($this->repository->hasAnswers($question)){ + throw new ValidationException(sprintf("you can not delete question value %s bc already has answers from attendees", $value_id)); + } + + $question->removeValue($value); + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitOrderService.php b/app/Services/Model/Imp/SummitOrderService.php new file mode 100644 index 00000000..d9cfb607 --- /dev/null +++ b/app/Services/Model/Imp/SummitOrderService.php @@ -0,0 +1,3303 @@ +tasks[] = $task; + return $this; + } + + private function markAsRan(AbstractTask $task) + { + $this->already_run_tasks[] = $task; + } + + + private function abort() + { + foreach (array_reverse($this->already_run_tasks) as $task) { + $task->undo(); + } + } + + /** + * @throws \Exception + */ + public function run(): array + { + try { + $formerState = []; + foreach ($this->tasks as $task) { + $formerState = $task->run($formerState); + $this->markAsRan($task); + } + return $formerState; + } catch (\Exception $ex) { + Log::warning($ex); + $this->abort(); + throw $ex; + } + } +} + +/** + * Class ReserveOrderTask + * @package App\Services\Model + */ +final class ReserveOrderTask extends AbstractTask +{ + + /** + * @var ITransactionService + */ + private $tx_service; + + /** + * @var Summit + */ + private $summit; + + /** + * @var array + */ + private $formerState; + + /** + * @var array + */ + private $payload; + + /** + * @var IMemberRepository + */ + private $member_repository; + + /** + * @var ISummitAttendeeRepository + */ + private $attendee_repository; + + /** + * @var ISummitAttendeeTicketRepository + */ + private $ticket_repository; + + /** + * @var Member + */ + private $owner; + + /** + * @var IBuildDefaultPaymentGatewayProfileStrategy + */ + private $default_payment_gateway_strategy; + + /** + * ReserveOrderTask constructor. + * @param Member|null $owner + * @param Summit $summit + * @param array $payload + * @param IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy + * @param IMemberRepository $member_repository + * @param ISummitAttendeeRepository $attendee_repository + * @param ISummitAttendeeTicketRepository $ticket_repository + * @param ITransactionService $tx_service + */ + public function __construct + ( + ?Member $owner, + Summit $summit, + array $payload, + IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy, + IMemberRepository $member_repository, + ISummitAttendeeRepository $attendee_repository, + ISummitAttendeeTicketRepository $ticket_repository, + ITransactionService $tx_service) + { + + $this->tx_service = $tx_service; + $this->summit = $summit; + $this->payload = $payload; + $this->member_repository = $member_repository; + $this->attendee_repository = $attendee_repository; + $this->ticket_repository = $ticket_repository; + $this->default_payment_gateway_strategy = $default_payment_gateway_strategy; + $this->owner = $owner; + } + + public function run(array $formerState): array + { + $this->formerState = $formerState; + + return $this->tx_service->transaction(function () { + + $owner_email = $this->payload['owner_email']; + $owner_first_name = $this->payload['owner_first_name']; + $owner_last_name = $this->payload['owner_last_name']; + $owner_company = $this->payload['owner_company'] ?? null; + $tickets = $this->payload['tickets']; + + if (!is_null($this->owner) && strtolower($this->owner->getEmail()) != strtolower($owner_email)) { + throw new ValidationException(sprintf("owner email differs from logged user email")); + } + + $payment_gateway = $this->summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeRegistration, + $this->default_payment_gateway_strategy + ); + if (is_null($payment_gateway)) { + throw new ValidationException(sprintf("Payment configuration is not set for summit %s", $this->summit->getId())); + } + + Log::info(sprintf("ReserveOrderTask::run - email %s first_name %s last_name %s company %s", $owner_email, $owner_first_name, $owner_last_name, $owner_company)); + $order = SummitOrderFactory::build($this->summit, $this->payload); + + $order->generateNumber(); + + do { + if (!$this->summit->existOrderNumber($order->getNumber())) + break; + $order->generateNumber(); + } while (1); + + $default_badge_type = $this->summit->getDefaultBadgeType(); + // local tx attendees storage + $local_attendees = []; + // tickets + foreach ($tickets as $ticket_dto) { + + if (!isset($ticket_dto['type_id'])) + throw new ValidationException('type_id is mandatory'); + + $type_id = $ticket_dto['type_id']; + $promo_code_value = isset($ticket_dto['promo_code']) ? $ticket_dto['promo_code'] : null; + $attendee_first_name = isset($ticket_dto['attendee_first_name']) ? $ticket_dto['attendee_first_name'] : null; + $attendee_last_name = isset($ticket_dto['attendee_last_name']) ? $ticket_dto['attendee_last_name'] : null; + $attendee_email = isset($ticket_dto['attendee_email']) ? $ticket_dto['attendee_email'] : null; + $attendee_company = isset($ticket_dto['attendee_company']) ? $ticket_dto['attendee_company'] : null; + + // if attendee is order owner , and company is null , set the company order + if (!empty($attendee_email) && $attendee_email == $owner_email) { + if (empty($attendee_company)) + $attendee_company = $owner_company; + if (empty($attendee_first_name)) + $attendee_first_name = $owner_first_name; + if (empty($attendee_last_name)) + $attendee_last_name = $owner_last_name; + } + + $ticket_type = $this->summit->getTicketTypeById($type_id); + if (is_null($ticket_type)) { + throw new EntityNotFoundException('ticket type not found'); + } + + $ticket = new SummitAttendeeTicket(); + $ticket->setOrder($order); + $ticket->generateNumber(); + + do { + + if (!$this->ticket_repository->existNumber($ticket->getNumber())) + break; + $ticket->generateNumber(); + } while (1); + + $ticket->setTicketType($ticket_type); + + $promo_code = !empty($promo_code_value) ? $this->summit->getPromoCodeByCode($promo_code_value) : null; + if (!is_null($promo_code)) { + $promo_code->applyTo($ticket); + } + if (!$ticket->hasBadge()) { + $badge = SummitBadgeType::buildBadgeFromType($default_badge_type); + $ticket->setBadge($badge); + } + + $ticket->applyTaxes($this->summit->getTaxTypes()->toArray()); + + if (!empty($attendee_email)) { + + $attendee_email = strtolower(trim($attendee_email)); + Log::debug(sprintf("ReserveOrderTask::run - attendee_email %s", $attendee_email)); + // assign attendee + // check if we have already an attendee on this summit + $attendee = $this->attendee_repository->getBySummitAndEmail($this->summit, $attendee_email); + // check on local reservation + + if (is_null($attendee) && isset($local_attendees[$attendee_email])) { + Log::debug(sprintf("ReserveOrderTask::run - attendee_email %s not fund in repo getting it from local tx", $attendee_email)); + $attendee = $local_attendees[$attendee_email]; + } + + if (is_null($attendee)) { + Log::debug(sprintf("ReserveOrderTask::run - creating attendee %s for summit %s", $attendee_email, $this->summit->getId())); + $attendee = SummitAttendeeFactory::build($this->summit, [ + 'first_name' => $attendee_first_name, + 'last_name' => $attendee_last_name, + 'email' => $attendee_email, + 'company' => $attendee_company + ], $this->member_repository->getByEmail($attendee_email)); + } + + $attendee = SummitAttendeeFactory::populate + ( + $this->summit, + $attendee, + [ + 'first_name' => $attendee_first_name, + 'last_name' => $attendee_last_name, + 'email' => $attendee_email, + 'company' => $attendee_company + ], + $this->member_repository->getByEmail($attendee_email) + ); + + $local_attendees[$attendee_email] = $attendee; + $ticket->setOwner($attendee); + } + + $order->addTicket($ticket); + $ticket->generateQRCode(); + $ticket->generateHash(); + } + + if (is_null($this->owner)) { + Log::debug(sprintf("ReserveOrderTask::run is null trying to get owner by email %s", $owner_email)); + $this->owner = $this->member_repository->getByEmail($owner_email); + } + + if (!is_null($this->owner)) { + Log::debug(sprintf("ReserveOrderTask::run owner is set to owner id %s", $this->owner->getId())); + $this->owner->addSummitRegistrationOrder($order); + } + + $this->summit->addOrder($order); + // generate payment if cost > 0 + if ($order->getFinalAmount() > 0) { + $result = $payment_gateway->generatePayment( + [ + "amount" => $order->getFinalAmount(), + "currency" => $order->getCurrency(), + "receipt_email" => $order->getOwnerEmail(), + "metadata" => [ + "type" => IPaymentConstants::ApplicationTypeRegistration, + "summit_id" => $this->summit->getId(), + ] + ] + ); + + if (!isset($result['cart_id'])) + throw new ValidationException("payment gateway error"); + + if (!isset($result['client_token'])) + throw new ValidationException("payment gateway error"); + + $order->setPaymentGatewayCartId($result['cart_id']); + $order->setPaymentGatewayClientToken($result['client_token']); + } + + // generate the key to access + $order->generateHash(); + $order->generateQRCode(); + Event::fire(new CreatedSummitRegistrationOrder($order->getId())); + return ['order' => $order]; + }); + } + + public function undo() + { + // TODO: Implement undo() method. + } +} + +/** + * Class ApplyPromoCodeTask + * @package App\Services\Model + */ +final class ApplyPromoCodeTask extends AbstractTask +{ + + /** + * @var ITransactionService + */ + private $tx_service; + + /** + * @var Summit + */ + private $summit; + + /** + * @var array + */ + private $formerState; + + /** + * @var array + */ + private $payload; + + /** + * @var ISummitRegistrationPromoCodeRepository + */ + private $promo_code_repository; + + /** + * ApplyPromoCodeTask constructor. + * @param Summit $summit + * @param array $payload + * @param ISummitRegistrationPromoCodeRepository $promo_code_repository + * @param ITransactionService $tx_service + */ + public function __construct + ( + Summit $summit, + array $payload, + ISummitRegistrationPromoCodeRepository $promo_code_repository, + ITransactionService $tx_service + ) + { + $this->tx_service = $tx_service; + $this->summit = $summit; + $this->payload = $payload; + $this->promo_code_repository = $promo_code_repository; + } + + /** + * @param array $formerState + * @return array + * @throws \Exception + */ + public function run(array $formerState): array + { + $this->formerState = $formerState; + $promo_codes_usage = $this->formerState['promo_codes_usage']; + $owner_email = $this->payload['owner_email']; + $owner_company = $this->payload['owner_company'] ?? null; + + foreach ($promo_codes_usage as $promo_code_value => $info) { + + $this->tx_service->transaction(function () use ($owner_email, $owner_company, $promo_code_value, $info) { + + $promo_code = $this->promo_code_repository->getByValueExclusiveLock($this->summit, $promo_code_value); + + if (is_null($promo_code) || !$promo_code instanceof SummitRegistrationPromoCode) { + throw new EntityNotFoundException(sprintf('The Promo Code “%s” is not a valid code.', $promo_code_value)); + } + + if ($promo_code->getSummitId() != $this->summit->getId()) { + throw new EntityNotFoundException(sprintf("promo code %s not found on summit %s", $promo_code->getCode(), $this->summit->getId())); + } + + $qty = $info['qty']; + + $promo_code->checkSubject($owner_email, $owner_company); + + if (!$promo_code->canUse()) { + throw new ValidationException(sprintf('The Promo Code “%s” is not a valid code.', $promo_code->getCode())); + } + + foreach ($info['types'] as $ticket_type_id) { + $ticket_type = $this->summit->getTicketTypeById($ticket_type_id); + if (is_null($ticket_type)) { + throw new ValidationException(sprintf("ticket type %s not found on summit %s", $ticket_type_id, $this->summit->getId())); + } + if (!$promo_code->canBeAppliedTo($ticket_type)) { + throw new ValidationException(sprintf("promo code %s can not be applied to ticket type %s", $promo_code->getCode(), $ticket_type->getName())); + } + } + Log::debug(sprintf("adding %s usage to promo code %s", $qty, $promo_code->getId())); + $promo_code->addUsage($qty); + }); + // mark a done + $promo_codes_usage[$promo_code_value]['redeem'] = true; + } + + return $this->formerState; + } + + public function undo() + { + Log::info("ApplyPromoCodeTask::undo: compensating transaction"); + $promo_codes_usage = $this->formerState['promo_codes_usage']; + foreach ($promo_codes_usage as $code => $info) { + $this->tx_service->transaction(function () use ($code, $info) { + $promo_code = $this->promo_code_repository->getByValueExclusiveLock($this->summit, $code); + if (is_null($promo_code)) return; + if (!isset($info['redeem'])) return; + $promo_code->removeUsage($info['qty']); + }); + } + } +} + +/** + * Class ReserveTicketsTask + * @package App\Services\Model + */ +final class ReserveTicketsTask extends AbstractTask +{ + + /** + * @var ITransactionService + */ + private $tx_service; + + /** + * @var Summit + */ + private $summit; + + /** + * @var array + */ + private $formerState; + + /** + * @var ISummitTicketTypeRepository + */ + private $ticket_type_repository; + + /** + * ReserveTicketsTask constructor. + * @param Summit $summit + * @param ISummitTicketTypeRepository $ticket_type_repository + * @param ITransactionService $tx_service + */ + public function __construct(Summit $summit, ISummitTicketTypeRepository $ticket_type_repository, ITransactionService $tx_service) + { + $this->tx_service = $tx_service; + $this->summit = $summit; + $this->ticket_type_repository = $ticket_type_repository; + } + + public function run(array $formerState): array + { + $this->formerState = $formerState; + // reserve all tix on a tx ( all or nothing) + $this->tx_service->transaction(function () { + $ticket_types_ids = $this->formerState['ticket_types_ids']; + $reservations = $this->formerState['reservations']; + $ticket_types = $this->ticket_type_repository->getByIdsExclusiveLock($this->summit, $ticket_types_ids); + $former_currency = null; + + foreach ($ticket_types as $ticket_type) { + + if (!empty($former_currency) && $ticket_type->getCurrency() != $former_currency) { + throw new ValidationException("order should have tickets with same currency"); + } + + $former_currency = $ticket_type->getCurrency(); + if (!$ticket_type instanceof SummitTicketType) { + throw new EntityNotFoundException("ticket type not found"); + } + if (!$ticket_type->canSell()) { + throw new ValidationException(sprintf('The ticket “%s” is not available. Please go back and select a different ticket.', $ticket_type->getName())); + } + $ticket_type->sell($reservations[$ticket_type->getId()]); + } + }); + return $formerState; + } + + public function undo() + { + Log::info("ReserveTicketsTask::undo: compensating transaction"); + $reservations = $this->formerState['reservations']; + foreach ($reservations as $ticket_id => $qty) { + $this->tx_service->transaction(function () use ($ticket_id, $qty) { + $ticket_type = $this->ticket_type_repository->getByIdExclusiveLock($ticket_id); + if (is_null($ticket_type)) return; + $ticket_type->restore($qty); + }); + } + } +} + +/** + * Class PreProcessReservationTask + * @package App\Services\Model + */ +final class PreProcessReservationTask extends AbstractTask +{ + + /** + * @var array + */ + private $payload; + + /** + * PreProcessReservationTask constructor. + * @param array $payload + */ + public function __construct(array $payload) + { + $this->payload = $payload; + } + + /** + * @param array $formerState + * @return array + */ + public function run(array $formerState): array + { + $reservations = []; + $promo_codes_usage = []; + $ticket_types_ids = []; + + // sum reservations by tix types to check availability + $tickets = $this->payload['tickets']; + + foreach ($tickets as $ticket_dto) { + if (!isset($ticket_dto['type_id'])) + throw new ValidationException('type_id is mandatory'); + + $type_id = intval($ticket_dto['type_id']); + + if (!in_array($type_id, $ticket_types_ids)) + $ticket_types_ids[] = $type_id; + + $promo_code_value = isset($ticket_dto['promo_code']) ? strtoupper(trim($ticket_dto['promo_code'])) : null; + + if (!isset($reservations[$type_id])) + $reservations[$type_id] = 0; + + $reservations[$type_id] = $reservations[$type_id] + 1; + + if (!empty($promo_code_value)) { + + if (!isset($promo_codes_usage[$promo_code_value])) { + $promo_codes_usage[$promo_code_value] = [ + 'qty' => 0, + 'types' => [], + ]; + } + + $info = $promo_codes_usage[$promo_code_value]; + $info['qty'] = $info['qty'] + 1; + + if (!in_array($type_id, $info['types'])) + $info['types'] = array_merge($info['types'], [$type_id]); + + $promo_codes_usage[$promo_code_value] = $info; + } + } + return [ + "reservations" => $reservations, + "promo_codes_usage" => $promo_codes_usage, + "ticket_types_ids" => $ticket_types_ids, + ]; + } + + public function undo() + { + // TODO: Implement undo() method. + } +} + +/** + * Class PreOrderValidationTask + * @package App\Services\Model + */ +final class PreOrderValidationTask extends AbstractTask +{ + /** + * @var ITransactionService + */ + private $tx_service; + + /** + * @var Summit + */ + private $summit; + + /** + * @var array + */ + private $payload; + + /** + * PreOrderValidationTask constructor. + * @param Summit $summit + * @param array $payload + * @param ITransactionService $tx_service + */ + public function __construct(Summit $summit, array $payload, ITransactionService $tx_service) + { + $this->tx_service = $tx_service; + $this->summit = $summit; + $this->payload = $payload; + } + + public function run(array $formerState): array + { + // pre checks + $this->tx_service->transaction(function () { + $extra_questions = isset($this->payload['extra_questions']) ? $this->payload['extra_questions'] : []; + // check if we have at least a default badge template + if (!$this->summit->hasDefaultBadgeType()) + throw new ValidationException(sprintf("Summit %s has not default badge type set", $this->summit->getId())); + // check if we are on registration period + if (!$this->summit->isRegistrationPeriodOpen()) + throw new ValidationException(sprintf("Summit %s registration period is closed", $this->summit->getId())); + $owner_email = $this->payload['owner_email']; + + if (!$this->summit->canBuyRegistrationTickets($owner_email)) { + throw new ValidationException(sprintf("email %s can not buy registration tickets for summit %s", $owner_email, $this->summit->getId())); + } + + // check extra question for order ( if they exists and if they are mandatory) + + $mandatory_per_order = $this->summit->getMandatoryOrderExtraQuestionsByUsage(SummitOrderExtraQuestionTypeConstants::OrderQuestionUsage); + + if ($mandatory_per_order->count() != count($extra_questions)) { + throw new ValidationException("extra_questions is mandatory"); + } + + if ($mandatory_per_order->count() > 0) { + // check if we have all mandatories filled up + foreach ($mandatory_per_order as $question) { + $found = false; + foreach ($extra_questions as $question_answer) { + if ($question_answer['question_id'] == $question->getId() && !empty($question_answer['answer'])) { + $found = true; + break; + } + } + + if (!$found) { + throw new ValidationException(sprintf("question %s is mandatory", $question->getId())); + } + } + } + + }); + return []; + } + + public function undo() + { + // TODO: Implement undo() method. + } +} + +/** + * Class SummitOrderService + * @package App\Services\Model + */ +final class SummitOrderService + extends AbstractService implements ISummitOrderService +{ + /** + * @var IMemberRepository + */ + private $member_repository; + + /** + * @var ISummitTicketTypeRepository + */ + private $ticket_type_repository; + + /** + * @var ISummitRegistrationPromoCodeRepository + */ + private $promo_code_repository; + + /** + * @var ISummitAttendeeRepository + */ + private $attendee_repository; + + /** + * @var ISummitOrderRepository + */ + private $order_repository; + + /** + * @var ISummitAttendeeTicketRepository + */ + private $ticket_repository; + + /** + * @var ISummitAttendeeBadgeRepository + */ + private $badge_repository; + + /** + * @var ISummitRepository + */ + private $summit_repository; + + /** + * @var ISummitAttendeeBadgePrintRuleRepository + */ + private $print_rules_repository; + + /** + * @var IMemberService + */ + private $member_service; + + /** + * @var IBuildDefaultPaymentGatewayProfileStrategy + */ + private $default_payment_gateway_strategy; + + /** + * SummitOrderService constructor. + * @param ISummitTicketTypeRepository $ticket_type_repository + * @param IMemberRepository $member_repository + * @param ISummitRegistrationPromoCodeRepository $promo_code_repository + * @param ISummitAttendeeRepository $attendee_repository + * @param ISummitOrderRepository $order_repository + * @param ISummitAttendeeTicketRepository $ticket_repository + * @param ISummitAttendeeBadgeRepository $badge_repository + * @param ISummitRepository $summit_repository + * @param ISummitAttendeeBadgePrintRuleRepository $print_rules_repository + * @param IMemberService $member_service + * @param IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy + * @param ITransactionService $tx_service + */ + public function __construct + ( + ISummitTicketTypeRepository $ticket_type_repository, + IMemberRepository $member_repository, + ISummitRegistrationPromoCodeRepository $promo_code_repository, + ISummitAttendeeRepository $attendee_repository, + ISummitOrderRepository $order_repository, + ISummitAttendeeTicketRepository $ticket_repository, + ISummitAttendeeBadgeRepository $badge_repository, + ISummitRepository $summit_repository, + ISummitAttendeeBadgePrintRuleRepository $print_rules_repository, + IMemberService $member_service, + IBuildDefaultPaymentGatewayProfileStrategy $default_payment_gateway_strategy, + ITransactionService $tx_service + ) + { + parent::__construct($tx_service); + $this->member_repository = $member_repository; + $this->ticket_type_repository = $ticket_type_repository; + $this->promo_code_repository = $promo_code_repository; + $this->attendee_repository = $attendee_repository; + $this->order_repository = $order_repository; + $this->ticket_repository = $ticket_repository; + $this->badge_repository = $badge_repository; + $this->summit_repository = $summit_repository; + $this->print_rules_repository = $print_rules_repository; + $this->member_service = $member_service; + $this->default_payment_gateway_strategy = $default_payment_gateway_strategy; + } + + /** + * @param Member|null $owner + * @param Summit $summit + * @param array $payload + * @return SummitOrder + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function reserve(?Member $owner, Summit $summit, array $payload): SummitOrder + { + + try { + $state = Saga::start() + ->addTask(new PreOrderValidationTask($summit, $payload, $this->tx_service)) + ->addTask(new PreProcessReservationTask($payload)) + ->addTask(new ReserveTicketsTask($summit, $this->ticket_type_repository, $this->tx_service)) + ->addTask(new ApplyPromoCodeTask($summit, $payload, $this->promo_code_repository, $this->tx_service)) + ->addTask(new ReserveOrderTask + ( + $owner, + $summit, + $payload, + $this->default_payment_gateway_strategy, + $this->member_repository, + $this->attendee_repository, + $this->ticket_repository, + $this->tx_service + ) + ) + ->run(); + + return $state['order']; + } catch (ValidationException $ex) { + Log::warning($ex); + throw $ex; + } catch (\Exception $ex) { + Log::error($ex); + throw $ex; + } + } + + /** + * @param Summit $summit + * @param string $order_hash + * @param array $payload + * @return SummitOrder + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function checkout(Summit $summit, string $order_hash, array $payload): SummitOrder + { + return $this->tx_service->transaction(function () use ($summit, $order_hash, $payload) { + $order = $this->order_repository->getByHashLockExclusive($order_hash); + + if (is_null($order) || !$order instanceof SummitOrder || $summit->getId() != $order->getSummitId()) + throw new EntityNotFoundException("order not found"); + + SummitOrderFactory::populate($summit, $order, $payload); + if ($order->isFree()) { + // free order + $order->setPaid(); + } else { + $order->setConfirmed(); + } + return $order; + + }); + } + + /** + * @param Member $current_user + * @param int $order_id + * @param array $payload + * @return SummitOrder + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateMyOrder(Member $current_user, int $order_id, array $payload): SummitOrder + { + return $this->tx_service->transaction(function () use ($current_user, $order_id, $payload) { + $order = $this->order_repository->getByIdExclusiveLock($order_id); + if (is_null($order) || !$order instanceof SummitOrder) + throw new EntityNotFoundException("order not found"); + + if (!$order->hasOwner() && $order->getOwnerEmail() == $current_user->getEmail()) { + $current_user->addSummitRegistrationOrder($order); + } + + if (!$order->hasOwner()) { + throw new EntityNotFoundException("order not found"); + } + + if ($order->getOwner()->getId() != $current_user->getId()) { + throw new EntityNotFoundException("order not found"); + } + + SummitOrderFactory::populate($order->getSummit(), $order, $payload); + + return $order; + }); + } + + /** + * @param Member $current_user + * @param int $order_id + * @param int $ticket_id + * @return SummitAttendeeTicket + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function revokeTicket(Member $current_user, int $order_id, int $ticket_id): SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($current_user, $order_id, $ticket_id) { + $order = $this->order_repository->getByIdExclusiveLock($order_id); + if (is_null($order) || !$order instanceof SummitOrder) + throw new EntityNotFoundException("order not found"); + + if (!$order->hasOwner() && $order->getOwnerEmail() == $current_user->getEmail()) { + $current_user->addSummitRegistrationOrder($order); + } + + if (!$order->hasOwner()) { + throw new EntityNotFoundException("order not found"); + } + + if ($order->getOwner()->getId() != $current_user->getId()) { + throw new EntityNotFoundException("order not found"); + } + + $summit = $order->getSummit(); + if ($summit->hasReassignTicketLimit()) { + $now = new \DateTime('now', new \DateTimeZone('UTC')); + if ($now > $summit->getReassignTicketTillDate()) { + throw new ValidationException('revoked ticket period expired'); + } + } + + $ticket = $order->getTicketById($ticket_id); + + if (is_null($ticket)) + throw new EntityNotFoundException("ticket not found"); + + if (!$ticket->hasOwner()) { + throw new ValidationException("You attempted to assign or reassign a ticket that you don’t have permission to assign."); + } + + $attendee = $ticket->getOwner(); + + if ($ticket->hasBadge() && $ticket->getBadge()->isPrinted()) { + throw new ValidationException("ticket can not be revoked due badge its already printed"); + } + + $attendee->sendRevocationTicketEmail($ticket); + + $attendee->removeTicket($ticket); + + return $ticket; + + }); + } + + /** + * @param Member $current_user + * @param int $order_id + * @param int $ticket_id + * @param array $payload + * @return SummitAttendeeTicket + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function ownerAssignTicket(Member $current_user, int $order_id, int $ticket_id, array $payload): SummitAttendeeTicket + { + Log::debug("SummitOrderService::ownerAssignTicket"); + return $this->_assignTicket($order_id, $ticket_id, $payload, + function (array $payload) { + $first_name = $payload['attendee_first_name'] ?? null; + $last_name = $payload['attendee_last_name'] ?? null; + $company = $payload['attendee_company'] ?? null; + $email = $payload['attendee_email'] ?? ''; + $extra_questions = $payload['extra_questions'] ?? []; + + $basic_payload = [ + 'email' => trim($email), + 'extra_questions' => $extra_questions + ]; + + if (!is_null($first_name)) + $basic_payload['first_name'] = trim($first_name); + + if (!is_null($last_name)) + $basic_payload['last_name'] = trim($last_name); + + if (!is_null($company)) + $basic_payload['company'] = trim($company); + + return $basic_payload; + }, + function (SummitOrder $order) use ($current_user) { + + if (!$order->hasOwner() && $order->getOwnerEmail() == $current_user->getEmail()) { + $current_user->addSummitRegistrationOrder($order); + } + if (!$order->hasOwner()) { + throw new EntityNotFoundException("order not found"); + } + + if ($order->getOwner()->getId() != $current_user->getId()) { + throw new EntityNotFoundException("order not found"); + } + + $summit = $order->getSummit(); + if ($summit->hasReassignTicketLimit()) { + $now = new \DateTime('now', new \DateTimeZone('UTC')); + if ($now > $summit->getReassignTicketTillDate()) { + throw new ValidationException('reassign ticket period expired'); + } + } + } + ); + } + + /** + * @param int $order_id + * @param int $ticket_id + * @param array $payload + * @param callable $getPayloadFn + * @param callable|null $validationFn + * @return SummitAttendeeTicket + * @throws \Exception + */ + private function _assignTicket + ( + int $order_id, + int $ticket_id, + array $payload, + callable $getPayloadFn, + ?callable $validationFn = null + ): SummitAttendeeTicket + { + + return $this->tx_service->transaction(function () use ($order_id, $ticket_id, $payload, $getPayloadFn, $validationFn) { + + Log::debug(sprintf("SummitOrderService::_assignTicket order id %s ticket id %s", $order_id, $ticket_id)); + // lock and get the order + $order = $this->order_repository->getByIdExclusiveLock($order_id); + + if (is_null($order) || !$order instanceof SummitOrder) + throw new EntityNotFoundException("order not found"); + + // apply validation rules + if (!is_null($validationFn)) { + call_user_func($validationFn, $order); + } + + $summit = $order->getSummit(); + $ticket = $order->getTicketById($ticket_id); + + if (is_null($ticket)) + throw new EntityNotFoundException("ticket not found"); + + if (!$ticket->isPaid()) + throw new ValidationException("ticket is not paid"); + + // check attendee email + $email = $payload['attendee_email'] ?? ''; + + if ($ticket->hasOwner()) { + $owner = $ticket->getOwner(); + if ($owner->getEmail() != $email) + throw new ValidationException("ticket already had been assigned to another attendee, please revoke it before to assign it again."); + } + // try to get member and attendee by email + $member = $this->member_repository->getByEmail($email); + $attendee = $summit->getAttendeeByEmail($email); + + if (is_null($attendee) && !is_null($member)) { + // if we have a member, try to get attendee by member + $attendee = $summit->getAttendeeByMember($member); + } + + if (is_null($attendee)) { + // if attendee does not exists , create a new one + Log::debug(sprintf("SummitOrderService::_assignTicket - attendee does not exists for email %s creating it", $email)); + $attendee = SummitAttendeeFactory::build($summit, [ + 'email' => trim($email), + ], $member); + } + // update attendee data with custom payload + $attendee = SummitAttendeeFactory::populate + ( + $summit, + $attendee, + call_user_func($getPayloadFn, $payload), + $member + ); + + $attendee->addTicket($ticket); + + $ticket->generateQRCode(); + $ticket->generateHash(); + + $attendee->sendInvitationEmail($ticket); + + return $ticket; + + }); + } + + /** + * @param int $order_id + * @param int $ticket_id + * @return SummitAttendeeTicket + * @throws \Exception + */ + public function reInviteAttendee(int $order_id, int $ticket_id): SummitAttendeeTicket + { + + return $this->tx_service->transaction(function () use ($order_id, $ticket_id) { + + $order = $this->order_repository->getByIdExclusiveLock($order_id); + + if (is_null($order) || !$order instanceof SummitOrder) + throw new EntityNotFoundException("order not found"); + + $ticket = $order->getTicketById($ticket_id); + + if (is_null($ticket)) + throw new EntityNotFoundException("ticket not found"); + + if (!$ticket->isPaid()) + throw new ValidationException("ticket is not paid"); + + $attendee = $ticket->getOwner(); + + if (is_null($attendee)) + throw new EntityNotFoundException("attendee not found"); + + $ticket->generateQRCode(); + $ticket->generateHash(); + + $attendee->sendInvitationEmail($ticket); + + return $ticket; + }); + } + + /** + * @param int $order_id + * @return SummitOrder + * @throws \Exception + */ + public function reSendOrderEmail(int $order_id):SummitOrder { + + return $this->tx_service->transaction(function () use ($order_id) { + $order = $this->order_repository->getByIdExclusiveLock($order_id); + + if (is_null($order) || !$order instanceof SummitOrder) + throw new EntityNotFoundException("order not found"); + + Log::debug(sprintf("SummitOrderService:: reSendOrderEmail order %s", $order_id)); + + if (!$order->hasOwner()) { + // owner is not registered ... + Log::debug("SummitOrderService::reSendOrderEmail - order has not owner set"); + $ownerEmail = $order->getOwnerEmail(); + // check if we have a member on db + Log::debug(sprintf("SummitOrderService::reSendOrderEmail - trying to get email %s from db", $ownerEmail)); + $member = $this->member_repository->getByEmail($ownerEmail); + + if (!is_null($member)) { + // its turns out that email was registered as a member + // set the owner and move on + Log::debug(sprintf("SummitOrderService::reSendOrderEmail - member %s found at db", $ownerEmail)); + $order->setOwner($member); + + Log::debug("SummitOrderService::reSendOrderEmail - sending email to owner"); + // send email to owner; + $this->sendExistentSummitOrderOwnerEmail($order); + + return $order; + } + + Log::debug(sprintf("SummitOrderService::reSendOrderEmail trying to get external user %s", $ownerEmail)); + + $user = $this->member_service->checkExternalUser($ownerEmail); + + if (is_null($user)) { + + Log::debug + ( + sprintf + ( + "SummitOrderService::reSendOrderEmail - user %s does not exist at IDP, emiting a registration request on idp", + $ownerEmail + ) + ); + + // user does not exists , emit a registration request + // need to send email with set password link + + $this->sendSummitOrderOwnerInvitationEmail($order, $this->member_service->emitRegistrationRequest + ( + $ownerEmail, + $order->getOwnerFirstName(), + $order->getOwnerSurname() + )); + + return $order; + } + + Log::debug + ( + sprintf + ( + "SummitOrderService::reSendOrderEmail - Creating a local user for %s", + $ownerEmail + ) + ); + + // we have an user on idp + $member = $this->member_service->registerExternalUser + ( + $user['id'], + $user['email'], + $user['first_name'], + $user['last_name'] + ); + + // add the order to newly created member + $member->addSummitRegistrationOrder($order); + } + + // send email to owner + $this->sendExistentSummitOrderOwnerEmail($order); + return $order; + }); + } + + /** + * @param Member $current_user , + * @param int $order_id + * @return SummitOrder + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function requestRefundOrder(Member $current_user, int $order_id): SummitOrder + { + return $this->tx_service->transaction(function () use ($current_user, $order_id) { + $order = $current_user->getSummitRegistrationOrderById($order_id); + if (is_null($order)) + throw new EntityNotFoundException('order not found'); + if ($order->isFree()) { + throw new ValidationException("you can not request a refund because order is free"); + } + $order->requestRefund(); + + // recalculate order status + $order->recalculateOrderStatus(); + + return $order; + }); + } + + /** + * @param Member $current_user , + * @param int $order_id + * @param int $ticket_id + * @return SummitAttendeeTicket + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function requestRefundTicket(Member $current_user, int $order_id, int $ticket_id): SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($current_user, $order_id, $ticket_id) { + $order = $current_user->getSummitRegistrationOrderById($order_id); + if (is_null($order)) + throw new EntityNotFoundException('order not found'); + + $ticket = $order->getTicketById($ticket_id); + if (is_null($ticket)) + throw new EntityNotFoundException('ticket not found'); + + if ($ticket->isFree()) { + throw new ValidationException("you can not request a refund because ticket is free"); + } + + $ticket->requestRefund(); + + // recalculate order status + $order->recalculateOrderStatus(); + + return $ticket; + }); + } + + /** + * @param Summit $summit + * @param string $order_hash + * @return SummitOrder + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function cancel(Summit $summit, string $order_hash): SummitOrder + { + return $this->tx_service->transaction(function () use ($summit, $order_hash) { + + $order = $this->order_repository->getByHashLockExclusive($order_hash); + + if (is_null($order) || !$order instanceof SummitOrder || $summit->getId() != $order->getSummitId()) + throw new EntityNotFoundException("order not found"); + + $order->setCancelled(false); + + return $order; + }); + } + + /** + * @param array $payload + * @param Summit|null $summit + * @throws \Exception + */ + public function processPayment(array $payload, ?Summit $summit = null): void + { + $this->tx_service->transaction(function () use ($summit, $payload) { + + Log::debug(sprintf("SummitOrderService::processPayment cart_id %s", $payload['cart_id'])); + + $order = $this->order_repository->getByPaymentGatewayCartIdExclusiveLock($payload['cart_id']); + + if (is_null($order) || !$order instanceof SummitOrder || (!is_null($summit) && $order->getSummitId() != $summit->getId())) { + throw new EntityNotFoundException + ( + sprintf("There is no order with cart_id %s.", $payload['cart_id']) + ); + } + + $summit = $order->getSummit(); + + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeRegistration, + $this->default_payment_gateway_strategy + ); + + if (is_null($payment_gateway)) { + throw new ValidationException(sprintf("Payment configuration is not set for summit %s.", $summit->getId())); + } + + if ($payment_gateway->isSuccessFullPayment($payload)) { + Log::debug("SummitOrderService::processPayment: payment is successful"); + $order->setPaid(); + return; + } + + $order->setPaymentError($payment_gateway->getPaymentError($payload)); + }); + } + + /** + * @param int $minutes + * @param int $max + * @throws \Exception + */ + public function confirmOrdersOlderThanNMinutes(int $minutes, int $max = 100): void + { + // done in this way to avoid db lock contention + $orders = $this->tx_service->transaction(function () use ($minutes, $max) { + return $this->order_repository->getAllConfirmedOlderThanXMinutes($minutes, $max); + }); + + foreach ($orders as $order) { + $this->tx_service->transaction(function () use ($order) { + + try { + if (!$order instanceof SummitOrder) return; + + $order = $this->order_repository->getByIdExclusiveLock($order->getId()); + if (!$order instanceof SummitOrder) return; + Log::debug(sprintf("SummitOrderService::confirmOrdersOlderThanNMinutes processing order %s", $order->getId())); + $summit = $order->getSummit(); + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeRegistration, + $this->default_payment_gateway_strategy + ); + if (is_null($payment_gateway)) { + Log::warning(sprintf("SummitOrderService::confirmOrdersOlderThanNMinutes Payment configuration is not set for summit %s", $summit->getId())); + return; + } + + $cart_id = $order->getPaymentGatewayCartId(); + if (!empty($cart_id)) { + + $status = $payment_gateway->getCartStatus($cart_id); + + if (!is_null($status) && $payment_gateway->isSucceeded($status)) { + Log::info(sprintf("SummitOrderService::confirmOrdersOlderThanNMinutes marking as paid order %s create at %s", $order->getNumber(), $order->getCreated()->format("Y-m-d h:i:sa"))); + $order->setPaid(); + } + + } + } catch (\Exception $ex) { + Log::warning($ex); + } + }); + } + } + + /** + * @param int $minutes + * @param int $max + * @throws \Exception + */ + public function revokeReservedOrdersOlderThanNMinutes(int $minutes, int $max = 100): void + { + // done in this way to avoid db lock contention + $orders = $this->tx_service->transaction(function () use ($minutes, $max) { + return $this->order_repository->getAllReservedOlderThanXMinutes($minutes, $max); + }); + + foreach ($orders as $order) { + $this->tx_service->transaction(function () use ($order) { + + try { + if (!$order instanceof SummitOrder) return; + + $order = $this->order_repository->getByIdExclusiveLock($order->getId()); + if (!$order instanceof SummitOrder) return; + $summit = $order->getSummit(); + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeRegistration, + $this->default_payment_gateway_strategy + ); + if (is_null($payment_gateway)) { + Log::warning(sprintf("SummitOrderService::revokeReservedOrdersOlderThanNMinutes Payment configuration is not set for summit %s", $summit->getId())); + return; + } + + Log::warning(sprintf("SummitOrderService::revokeReservedOrdersOlderThanNMinutes cancelling order reservation %s create at %s", $order->getNumber(), $order->getCreated()->format("Y-m-d h:i:sa"))); + + $cart_id = $order->getPaymentGatewayCartId(); + if (!empty($cart_id)) { + + $status = $payment_gateway->getCartStatus($cart_id); + if (!is_null($status)) { + if (!$payment_gateway->canAbandon($status)) { + Log::warning(sprintf("SummitOrderService::revokeReservedOrdersOlderThanNMinutes reservation %s created at %s can not be cancelled external status %s", $order->getId(), $order->getCreated()->format("Y-m-d h:i:sa"), $status)); + if ($payment_gateway->isSucceeded($status)) { + $order->setPaid(); + } + return; + } + $payment_gateway->abandonCart($cart_id); + } + } + + $order->setCancelled(); + Log::warning(sprintf("SummitOrderService::revokeReservedOrdersOlderThanNMinutes order %s got cancelled", $order->getId())); + } catch (\Exception $ex) { + Log::warning($ex); + } + }); + } + } + + /** + * @param $ticket_id + * @param string $format + * @param Member|null $current_user + * @param int|null $order_id + * @param Summit|null $summit + * @return string + */ + public function renderTicketByFormat($ticket_id, string $format = "pdf", ?Member $current_user = null, ?int $order_id = null, ?Summit $summit = null): string + { + return $this->tx_service->transaction(function () use ($ticket_id, $current_user, $format, $order_id, $summit) { + + //try first by id + $ticket = null; + if (is_integer($ticket_id)) { + Log::debug(sprintf("SummitOrderService::renderTicketByFormattrying to get ticket by id %s", $ticket_id)); + $ticket = $this->ticket_repository->getByIdExclusiveLock(intval($ticket_id)); + } + + if (is_null($ticket) && is_null($current_user)) { + // try to get by hash + Log::debug(sprintf("SummitOrderService::renderTicketByFormat trying to get ticket by hash %s", $ticket_id)); + $ticket = $this->ticket_repository->getByHashExclusiveLock(strval($ticket_id)); + + if (is_null($ticket) || !$ticket->hasOwner()) + throw new EntityNotFoundException("ticket not found"); + + if (!$ticket->canPubliclyEdit()) { + // check hash lifetime + throw new ValidationException("ticket hash is not valid"); + } + } + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException("ticket not found"); + + Log::debug(sprintf("SummitOrderService::renderTicketByFormat ticket id %s ticket status %s", $ticket->getId(), $ticket->getStatus())); + if (!is_null($summit) && $ticket->getOrder()->getSummitId() !== $summit->getId()) + throw new EntityNotFoundException("ticket not found"); + + if (!is_null($order_id) && $ticket->getOrderId() !== $order_id) + throw new EntityNotFoundException("ticket not found"); + + + if (!$ticket->isPaid()) + throw new ValidationException("ticket is not paid"); + + if (!is_null($current_user)) { + // if current user is present + // check rendering permissions ( order owner or ticket owner only) + $allow_2_render = false; + $order = $ticket->getOrder(); + + if ($order->hasOwner() && $order->getOwnerEmail() == $current_user->getEmail()) { + $allow_2_render = true; + } + + if ($ticket->hasOwner() && $ticket->getOwnerEmail() == $current_user->getEmail()) { + $allow_2_render = true; + } + + if (!$allow_2_render) + throw new ValidationException("ticket does not belong to member"); + + } + + $renderer = new SummitAttendeeTicketPDFRenderer($ticket); + return $renderer->render(); + }); + } + + /** + * @param string $hash + */ + public function regenerateTicketHash(string $hash): void + { + $this->tx_service->transaction(function () use ($hash) { + + $ticket = $this->ticket_repository->getByHashExclusiveLock($hash); + + if (is_null($ticket)) { + $ticket = $this->ticket_repository->getByFormerHashExclusiveLock($hash); + } + + if (is_null($ticket)) + throw new EntityNotFoundException("ticket not found"); + + if (!$ticket->isPaid()) + throw new ValidationException("ticket is not paid"); + + if (!$ticket->hasOwner()) + throw new ValidationException("ticket must have an assigned owner"); + + $ticket->generateQRCode(); + $ticket->generateHash(); + + SummitAttendeeTicketRegenerateHashEmail::dispatch($ticket); + }); + } + + /** + * @param string $hash + * @return SummitAttendeeTicket + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function getTicketByHash(string $hash): SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($hash) { + $ticket = $this->ticket_repository->getByHashExclusiveLock($hash); + + if (is_null($ticket)) { + $ticket = $this->ticket_repository->getByFormerHashExclusiveLock($hash); + if (!is_null($ticket)) + throw new ValidationException("ticket hash is not valid"); + } + + if (is_null($ticket)) + throw new EntityNotFoundException("ticket not found"); + + if (!$ticket->isPaid()) + throw new ValidationException("ticket is not paid"); + + if (!$ticket->hasOwner()) + throw new ValidationException("ticket must have an assigned owner"); + + if (!$ticket->canPubliclyEdit()) + throw new ValidationException("ticket hash is not valid"); + + return $ticket; + }); + } + + /** + * @param Summit $summit + * @param array $payload + * @return SummitOrder + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function createOrderSingleTicket(Summit $summit, array $payload): SummitOrder + { + $order = $this->tx_service->transaction(function () use ($summit, $payload) { + Log::debug(sprintf("SummitOrderService::createOrderSingleTicket summit %s payload %s", $summit->getId(), json_encode($payload))); + // lock ticket type stock + $owner = null; + $ticket_type = $this->ticket_type_repository->getByIdExclusiveLock(intval($payload['ticket_type_id'])); + + if (is_null($ticket_type) || !$ticket_type instanceof SummitTicketType || $ticket_type->getSummitId() != $summit->getId()) + throw new EntityNotFoundException("ticket type not found"); + + // check owner + if (isset($payload['owner_id'])) { + Log::debug(sprintf("SummitOrderService::createOrderSingleTicket trying to get member by id %s", $payload['owner_id'])); + $owner = $this->member_repository->getById(intval($payload['owner_id'])); + if (is_null($owner)) { + throw new EntityNotFoundException("owner not found"); + } + } + + if (is_null($owner) && isset($payload['owner_email'])) { + Log::debug(sprintf("SummitOrderService::createOrderSingleTicket trying to get member by email %s", $payload['owner_email'])); + // if not try by email + $owner = $this->member_repository->getByEmail(trim($payload['owner_email'])); + } + + // try to get attendee + $attendee = !is_null($owner) ? $summit->getAttendeeByMember($owner) : null; + + if (is_null($attendee) && isset($payload['owner_email'])) { + Log::debug(sprintf("SummitOrderService::createOrderSingleTicket trying to get attendee by email %s", $payload['owner_email'])); + $attendee = $summit->getAttendeeByEmail(trim($payload['owner_email'])); + } + + if (is_null($attendee)) { + // create it + Log::debug(sprintf("SummitOrderService::createOrderSingleTicket attendee is null")); + //first name + $first_name = isset($payload['owner_first_name']) ? trim($payload['owner_first_name']) : null; + if (empty($first_name) && !is_null($owner)) $first_name = $owner->getFirstName(); + if (empty($first_name)) + throw new ValidationException("you must provide an owner_first_name or a valid owner_id"); + // surname + $surname = isset($payload['owner_last_name']) ? trim($payload['owner_last_name']) : null; + if (empty($surname) && !is_null($owner)) $surname = $owner->getLastName(); + if (empty($surname)) + throw new ValidationException("you must provide an owner_last_name or a valid owner_id"); + // mail + $email = isset($payload['owner_email']) ? trim($payload['owner_email']) : null; + + $company = isset($payload['owner_company']) ? trim($payload['owner_company']) : null; + + if (empty($email) && !is_null($owner)) $email = $owner->getEmail(); + if (empty($email)) + throw new ValidationException("you must provide an owner_email or a valid owner_id"); + + $attendee = SummitAttendeeFactory::build($summit, [ + 'first_name' => $first_name, + 'last_name' => $surname, + 'email' => $email, + 'company' => $company + ], $owner); + } + + // create order + + $order = SummitOrderFactory::build($summit, $payload); + $order->generateNumber(); + do { + if (!$summit->existOrderNumber($order->getNumber())) + break; + $order->generateNumber(); + } while (1); + + Log::debug(sprintf("SummitOrderService::createOrderSingleTicket order number %s", $order->getNumber())); + $default_badge_type = $summit->getDefaultBadgeType(); + + if (is_null($default_badge_type)) + throw new ValidationException(sprintf("summit %s does not has a default badge type", $summit->getId())); + + $order->setPaymentMethodOffline(); + + // create ticket + + $ticket = new SummitAttendeeTicket(); + $ticket->setOrder($order); + $ticket->setOwner($attendee); + $ticket->setTicketType($ticket_type); + $ticket->generateNumber(); + $ticket_type->sell(1); + + do { + if (!$this->ticket_repository->existNumber($ticket->getNumber())) + break; + $ticket->generateNumber(); + } while (1); + + Log::debug(sprintf("SummitOrderService::createOrderSingleTicket ticket number %s", $ticket->getNumber())); + + // promo code usage + $promo_code = isset($payload['promo_code']) ? $this->promo_code_repository->getByValueExclusiveLock($summit, trim($payload['promo_code'])) : null; + if (!is_null($promo_code)) { + $promo_code->addUsage(1); + $promo_code->applyTo($ticket); + } + + if (!$ticket->hasBadge()) { + $badge = SummitBadgeType::buildBadgeFromType($default_badge_type); + $ticket->setBadge($badge); + } + + $ticket->applyTaxes($summit->getTaxTypes()->toArray()); + $order->addTicket($ticket); + if (!is_null($owner)) { + $owner->addSummitRegistrationOrder($order); + } + + $ticket->generateHash(); + $ticket->generateQRCode(); + + $summit->addAttendee($attendee); + $summit->addOrder($order); + $order->generateHash(); + $order->generateQRCode(); + + return $order; + }); + + return $this->tx_service->transaction(function () use ($order) { + $order->setPaid(); + Log::debug(sprintf("SummitOrderService::createOrderSingleTicket order number %s mark as paid", $order->getNumber())); + return $order; + }); + } + + /** + * @param Summit $summit + * @param int $order_id + * @param array $payload + * @return SummitOrder + */ + public function updateOrder(Summit $summit, int $order_id, array $payload): SummitOrder + { + return $this->tx_service->transaction(function () use ($summit, $order_id, $payload) { + $order = $this->order_repository->getByIdExclusiveLock($order_id); + if (is_null($order) || !$order instanceof SummitOrder) + throw new EntityNotFoundException("order not found"); + + SummitOrderFactory::populate($summit, $order, $payload); + + return $order; + }); + } + + /** + * @param Summit $summit + * @param int $order_id + * @return void + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function deleteOrder(Summit $summit, int $order_id) + { + $this->tx_service->transaction(function () use ($summit, $order_id) { + $order = $this->order_repository->getByIdExclusiveLock($order_id); + + if (is_null($order) || !$order instanceof SummitOrder) + throw new EntityNotFoundException("order not found"); + + list($tickets_to_return, $promo_codes_to_return) = $order->calculateTicketsAndPromoCodesToReturn(); + + foreach ($order->getTickets() as $ticket) { + $ticket->setCancelled(); + } + + $summit->removeOrder($order); + + Event::fire(new OrderDeleted($order->getId(), $summit->getId(), $tickets_to_return, $promo_codes_to_return)); + + }); + } + + /** + * @param Summit $summit + * @param int $order_id + * @param float $amount + * @return SummitOrder + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function refundOrder(Summit $summit, int $order_id, float $amount): SummitOrder + { + return $this->tx_service->transaction(function () use ($summit, $order_id, $amount) { + $order = $this->order_repository->getByIdExclusiveLock($order_id); + if (is_null($order) || !$order instanceof SummitOrder) + throw new EntityNotFoundException('order not found'); + + if ($amount <= 0.0) { + throw new ValidationException("can not refund an amount lower than zero!"); + } + + if ($amount > intval($order->getFinalAmount())) { + throw new ValidationException("can not refund an amount greater than paid one!"); + } + + if (!$order->canRefund()) + throw new ValidationException + ( + sprintf + ( + "can not emit a refund on order %s", + $order->getId() + ) + ); + + $summit = $order->getSummit(); + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeRegistration, + $this->default_payment_gateway_strategy + ); + if (is_null($payment_gateway)) { + throw new ValidationException(sprintf("Payment configuration is not set for summit %s", $summit->getId())); + } + + $cart_id = $order->getPaymentGatewayCartId(); + + if (!empty($cart_id)) { + try { + $payment_gateway->refundPayment($order->getPaymentGatewayCartId(), $amount, $order->getCurrency()); + } catch (\Exception $ex) { + throw new ValidationException($ex->getMessage()); + } + } + + $order->refund($amount); + + // recalculate order status + $order->recalculateOrderStatus(); + + return $order; + }); + } + + /** + * @param Summit $summit + * @param $ticket_id + * @return SummitAttendeeTicket + * @throws \Exception + */ + public function getTicket(Summit $summit, $ticket_id): SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($summit, $ticket_id) { + $ticket = $this->ticket_repository->getById(intval($ticket_id)); + if (is_null($ticket)) { + $ticket = $this->ticket_repository->getByNumber(strval($ticket_id)); + } + if (is_null($ticket)) { + // get by qr code + $qr_code = strval($ticket_id); + $fields = SummitAttendeeBadge::parseQRCode($qr_code); + $prefix = $fields['prefix']; + if ($summit->getBadgeQRPrefix() != $prefix) + throw new ValidationException + ( + sprintf + ( + "%s qr code is not valid for summit %s", + $qr_code, + $summit->getId() + ) + ); + + $ticket_number = $fields['ticket_number']; + $ticket = $this->ticket_repository->getByNumber($ticket_number); + } + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException("ticket not found"); + if ($ticket->getOrder()->getSummitId() != $summit->getId()) { + throw new ValidationException("ticket does not belong to summit"); + } + return $ticket; + }); + } + + /** + * @param Summit $summit + * @param int|string $ticket_id + * @param float $amount + * @return SummitAttendeeTicket + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function refundTicket(Summit $summit, $ticket_id, float $amount): SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($summit, $ticket_id, $amount) { + + $ticket = $this->ticket_repository->getByIdExclusiveLock(intval($ticket_id)); + + if (is_null($ticket)) + $this->ticket_repository->getByNumberExclusiveLock(strval($ticket_id)); + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException('ticket not found'); + + if ($amount <= 0.0) { + throw new ValidationException("can not refund an amount lower than zero!"); + } + + if ($amount > intval($ticket->getFinalAmount())) { + throw new ValidationException("can not refund an amount greater than paid one!"); + } + + $order = $ticket->getOrder(); + + if ($order->getSummitId() != $summit->getId()) + throw new EntityNotFoundException('ticket not found'); + + if (!$ticket->canRefund()) + throw new ValidationException + ( + sprintf + ( + "can not emit a refund on ticket %s", + $ticket->getId() + ) + ); + + $cart_id = $order->getPaymentGatewayCartId(); + + $payment_gateway = $summit->getPaymentGateWayPerApp + ( + IPaymentConstants::ApplicationTypeRegistration, + $this->default_payment_gateway_strategy + ); + if (is_null($payment_gateway)) { + throw new ValidationException(sprintf("Payment configuration is not set for summit %s", $summit->getId())); + } + + if (!empty($cart_id)) { + try { + $payment_gateway->refundPayment($cart_id, $amount, $ticket->getOrder()->getCurrency()); + } catch (\Exception $ex) { + throw new ValidationException($ex->getMessage()); + } + } + + $ticket->refund($amount); + + // recalculate order status + $order->recalculateOrderStatus(); + + return $ticket; + }); + } + + /** + * @param Summit $summit + * @param int|string $ticket_id + * @param int $type_id + * @return SummitAttendeeBadge + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateBadgeType(Summit $summit, $ticket_id, int $type_id): SummitAttendeeBadge + { + return $this->tx_service->transaction(function () use ($summit, $ticket_id, $type_id) { + $badge_type = $summit->getBadgeTypeById($type_id); + if (is_null($badge_type)) + throw new EntityNotFoundException("badge type not found"); + + $ticket = $this->ticket_repository->getByIdExclusiveLock(intval($ticket_id)); + if (is_null($ticket)) + $this->ticket_repository->getByNumberExclusiveLock(strval($ticket_id)); + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException('ticket not found'); + + $order = $ticket->getOrder(); + + if ($order->getSummitId() != $summit->getId()) + throw new EntityNotFoundException('ticket not found'); + + if (!$ticket->hasBadge()) + throw new EntityNotFoundException('badge not found'); + + $badge = $ticket->getBadge(); + + $badge->setType($badge_type); + + return $badge; + }); + } + + /** + * @param Summit $summit + * @param int $ticket_id + * @param int $feature_id + * @return SummitAttendeeBadge + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addAttendeeBadgeFeature(Summit $summit, $ticket_id, int $feature_id): SummitAttendeeBadge + { + return $this->tx_service->transaction(function () use ($summit, $ticket_id, $feature_id) { + $feature_type = $summit->getFeatureTypeById($feature_id); + if (is_null($feature_type)) + throw new EntityNotFoundException("feature type not found"); + + $ticket = $this->ticket_repository->getByIdExclusiveLock(intval($ticket_id)); + if (is_null($ticket)) + $this->ticket_repository->getByNumberExclusiveLock(strval($ticket_id)); + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException('ticket not found'); + + $order = $ticket->getOrder(); + + if ($order->getSummitId() != $summit->getId()) + throw new EntityNotFoundException('ticket not found'); + + if (!$ticket->hasBadge()) + throw new EntityNotFoundException('badge not found'); + + $badge = $ticket->getBadge(); + + $badge->addFeature($feature_type); + + return $badge; + }); + } + + /** + * @param Summit $summit + * @param int|string $ticket_id + * @param int $feature_id + * @return SummitAttendeeBadge + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function removeAttendeeBadgeFeature(Summit $summit, $ticket_id, int $feature_id): SummitAttendeeBadge + { + return $this->tx_service->transaction(function () use ($summit, $ticket_id, $feature_id) { + $feature_type = $summit->getFeatureTypeById($feature_id); + if (is_null($feature_type)) + throw new EntityNotFoundException("feature type not found"); + + $ticket = $this->ticket_repository->getByIdExclusiveLock(intval($ticket_id)); + if (is_null($ticket)) + $this->ticket_repository->getByNumberExclusiveLock(strval($ticket_id)); + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException('ticket not found'); + + $order = $ticket->getOrder(); + + if ($order->getSummitId() != $summit->getId()) + throw new EntityNotFoundException('ticket not found'); + + if (!$ticket->hasBadge()) + throw new EntityNotFoundException('badge not found'); + + $badge = $ticket->getBadge(); + + $badge->removeFeature($feature_type); + + return $badge; + }); + } + + /** + * @param Summit $summit + * @param int|string $ticket_id + * @param Member $requestor + * @return SummitAttendeeBadge + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function printAttendeeBadge(Summit $summit, $ticket_id, Member $requestor): SummitAttendeeBadge + { + return $this->tx_service->transaction(function () use ($summit, $ticket_id, $requestor) { + $ticket = null; + // check by id + if (is_integer($ticket_id)) + $ticket = $this->ticket_repository->getByIdExclusiveLock(intval($ticket_id)); + + if (is_string($ticket_id)) { + if (is_null($ticket)) + $ticket = $this->ticket_repository->getByNumberExclusiveLock(strval($ticket_id)); + + if (is_null($ticket)) + $ticket = $this->ticket_repository->getByExternalAttendeeIdExclusiveLock($summit, strval($ticket_id)); + } + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException('ticket not found'); + + $order = $ticket->getOrder(); + $summit = $order->getSummit(); + + if ($order->getSummitId() != $summit->getId()) + throw new EntityNotFoundException('ticket not found'); + + if (!$ticket->hasBadge()) + throw new EntityNotFoundException('badge not found'); + + $badge = $this->badge_repository->getByIdExclusiveLock($ticket->getBadgeId()); + + if (is_null($badge) && !$badge instanceof SummitAttendeeBadge) + throw new EntityNotFoundException('badge not found'); + + // check rules + + if (!$requestor->isAdmin()) { + + $rules = $this->print_rules_repository->getByGroupsSlugs($requestor->getGroupsCodes()); + if (count($rules) == 0) + throw new ValidationException("Your user has no rights to print badges."); + + $canPrint = false; + + foreach ($rules as $rule) { + if (!$rule instanceof SummitAttendeeBadgePrintRule) continue; + $canPrint = $rule->canPrintBadge($badge); + if ($canPrint) + break; + } + + if (!$canPrint) { + throw new ValidationException("This badge has already been printed."); + } + } + + $badge->printIt($requestor); + + // do checkin on print + $attendee = $ticket->getOwner(); + if (!$attendee->getSummitHallCheckedIn()) { + $attendee->setSummitHallCheckedIn(true); + $attendee->setSummitHallCheckedInDate(new \DateTime('now', new \DateTimeZone('UTC'))); + } + return $badge; + }); + } + + /** + * @param Summit $summit + * @param int|string $ticket_id + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function deleteBadge(Summit $summit, $ticket_id): void + { + $this->tx_service->transaction(function () use ($summit, $ticket_id) { + $ticket = $this->ticket_repository->getByIdExclusiveLock(intval($ticket_id)); + if (is_null($ticket)) + $this->ticket_repository->getByNumberExclusiveLock(strval($ticket_id)); + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException('ticket not found'); + + $order = $ticket->getOrder(); + $summit = $order->getSummit(); + + if ($order->getSummitId() != $summit->getId()) + throw new EntityNotFoundException('ticket not found'); + + if (!$ticket->hasBadge()) + throw new EntityNotFoundException('badge not found'); + + $badge = $this->badge_repository->getByIdExclusiveLock($ticket->getBadgeId()); + + $this->badge_repository->delete($badge); + }); + } + + /** + * @param Summit $summit + * @param int|string $ticket_id + * @param array $payload + * @return SummitAttendeeBadge + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function createBadge(Summit $summit, $ticket_id, array $payload): SummitAttendeeBadge + { + return $this->tx_service->transaction(function () use ($summit, $ticket_id, $payload) { + $ticket = $this->ticket_repository->getByIdExclusiveLock(intval($ticket_id)); + if (is_null($ticket)) + $this->ticket_repository->getByNumberExclusiveLock(strval($ticket_id)); + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException('ticket not found'); + + $order = $ticket->getOrder(); + $summit = $order->getSummit(); + + if ($order->getSummitId() != $summit->getId()) + throw new EntityNotFoundException('ticket not found'); + + if ($ticket->hasBadge()) + throw new ValidationException('ticket already has a badge'); + + $badge = new SummitAttendeeBadge(); + $badge_type = $summit->getDefaultBadgeType(); + if (isset($payload['badge_type_id'])) { + $badge_type = $summit->getBadgeTypeById(intval($payload['badge_type_id'])); + + } + if (is_null($badge_type)) { + throw new EntityNotFoundException("badge type not found"); + } + $badge->setType($badge_type); + if (isset($payload['features'])) { + foreach ($payload['features'] as $feature_id) { + $feature = $summit->getFeatureTypeById($feature_id); + if (is_null($feature)) + throw new EntityNotFoundException("feature type not found"); + $badge->addFeature($feature); + } + } + $ticket->setBadge($badge); + return $badge; + }); + } + + /** + * @param Summit $summit + * @param int $order_id + * @param array $payload + * @return SummitAttendeeTicket + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addTicket(Summit $summit, int $order_id, array $payload): SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($summit, $order_id, $payload) { + + }); + } + + /** + * @param Summit $summit + * @param int $order_id + * @param int $ticket_id + * @param array $payload + * @return SummitAttendeeTicket + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateTicket(Summit $summit, int $order_id, int $ticket_id, array $payload): SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($summit, $order_id, $ticket_id, $payload) { + $ticket = $this->_assignTicket($order_id, $ticket_id, $payload, + function (array $payload) { + $first_name = $payload['attendee_first_name'] ?? null; + $last_name = $payload['attendee_last_name'] ?? null; + $company = $payload['attendee_company'] ?? null; + $extra_questions = $payload['extra_questions'] ?? []; + + $basic_payload = [ + 'extra_questions' => $extra_questions + ]; + + if (!is_null($first_name)) + $basic_payload['first_name'] = trim($first_name); + + if (!is_null($last_name)) + $basic_payload['last_name'] = trim($last_name); + + if (!is_null($company)) + $basic_payload['company'] = trim($company); + + return array_merge($payload, $basic_payload); + }, + function (SummitOrder $order) use ($summit) { + if ($order->getSummitId() != $summit->getId()) { + throw new EntityNotFoundException("order not found"); + } + }); + + if (isset($payload['ticket_type_id'])) { + // set ticket type + $ticket_type_id = intval($payload['ticket_type_id']); + $ticket_type = $summit->getTicketTypeById($ticket_type_id); + if (is_null($ticket_type)) + throw new EntityNotFoundException("ticket type not found"); + + $ticket_type->applyTo($ticket); + } + + if (isset($payload['badge_type_id'])) { + // set badge type + $badge_type_id = intval($payload['badge_type_id']); + $badge_type = $summit->getBadgeTypeById($badge_type_id); + if (is_null($badge_type)) + throw new EntityNotFoundException("badge type not found"); + $badge = $ticket->hasBadge() ? $ticket->getBadge() : new SummitAttendeeBadge(); + $badge->setType($badge_type); + $ticket->setBadge($badge); + } + + return $ticket; + }); + } + + + /** + * @param string $hash + * @param array $payload + * @return SummitAttendeeTicket + * @throws \Exception + */ + public function updateTicketByHash(string $hash, array $payload): SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($hash, $payload) { + + $ticket = $this->ticket_repository->getByHashExclusiveLock($hash); + + if (is_null($ticket)) + throw new EntityNotFoundException("ticket not found"); + + if (!$ticket->isPaid()) + throw new ValidationException("ticket is not paid"); + + if (!$ticket->hasOwner()) + throw new ValidationException("ticket must have an assigned owner"); + + if (!$ticket->canPubliclyEdit()) + throw new ValidationException("ticket hash is not valid"); + + $attendee = $ticket->getOwner(); + $summit = $ticket->getOrder()->getSummit(); + + if ($summit->isRegistrationDisclaimerMandatory()) { + $disclaimer_accepted = boolval($payload['disclaimer_accepted'] ?? false); + if (!$disclaimer_accepted) + throw new ValidationException("disclaimer_accepted is mandatory"); + } + + $first_name = $payload['attendee_first_name'] ?? ''; + $company = $payload['attendee_company'] ?? ''; + $last_name = $payload['attendee_last_name'] ?? ''; + $extra_questions = $payload['extra_questions'] ?? []; + + $disclaimer_accepted = $payload['disclaimer_accepted'] ?? null; + $reduced_payload = [ + 'first_name' => $first_name, + 'last_name' => $last_name, + 'company' => $company, + 'extra_questions' => $extra_questions + ]; + + if (!is_null($disclaimer_accepted)) { + $reduced_payload['disclaimer_accepted'] = boolval($disclaimer_accepted); + } + + // update it + SummitAttendeeFactory::populate($summit, $attendee, $reduced_payload); + + $attendee->sendInvitationEmail($ticket); + + return $ticket; + }); + } + + /** + * @param Member $current_user + * @param int $ticket_id + * @param array $payload + * @return SummitAttendeeTicket + * @throws \Exception + */ + public function updateTicketById(Member $current_user, int $ticket_id, array $payload): SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($current_user, $ticket_id, $payload) { + $ticket = $this->ticket_repository->getByIdExclusiveLock($ticket_id); + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException("ticket not found"); + + if (!$ticket->canEditTicket($current_user)) { + throw new ValidationException(sprintf("Ticket %s can not be edited by current member", $ticket_id)); + } + + $order = $ticket->getOrder(); + $summit = $order->getSummit(); + $first_name = $payload['attendee_first_name'] ?? null; + $last_name = $payload['attendee_last_name'] ?? null; + $email = $payload['attendee_email'] ?? null; + $company = $payload['attendee_company'] ?? null; + $extra_questions = $payload['extra_questions'] ?? []; + $disclaimer_accepted = $payload['disclaimer_accepted'] ?? null; + + if ($summit->isRegistrationDisclaimerMandatory()) { + $disclaimer_accepted = boolval($payload['disclaimer_accepted'] ?? false); + if (!$disclaimer_accepted) + throw new ValidationException("Disclaimer is Mandatory."); + } + + $attendee = $ticket->getOwner(); + + $payload = [ + 'first_name' => $first_name, + 'last_name' => $last_name, + 'company' => $company, + 'email' => $email, + 'extra_questions' => $extra_questions + ]; + + if (!is_null($disclaimer_accepted)) { + $payload['disclaimer_accepted'] = boolval($disclaimer_accepted); + } + + if (is_null($attendee) && !empty($attendee_email)) { + // try to create it + $attendee = $this->attendee_repository->getBySummitAndEmail($summit, $attendee_email); + if (is_null($attendee)) { + $attendee = new SummitAttendee(); + } + } + + // update it + SummitAttendeeFactory::populate($summit, $attendee, $payload, !empty($email) ? $this->member_repository->getByEmail($email) : null); + + if (is_null($attendee)) { + $attendee->addTicket($ticket); + $attendee->sendInvitationEmail($ticket); + } + + return $ticket; + }); + } + + + /** + * @param string $order_hash + * @param array $payload + * @return SummitOrder + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateTicketsByOrderHash(string $order_hash, array $payload): SummitOrder + { + return $this->tx_service->transaction(function () use ($order_hash, $payload) { + + Log::debug(sprintf("SummitOrderService::updateTicketsByOrderHash order hash %s", $order_hash)); + + $tickets = $payload['tickets'] ?? []; + $order = $this->order_repository->getByHashLockExclusive($order_hash); + if (is_null($order)) + throw new EntityNotFoundException("order not found"); + + if (!$order->canPubliclyEdit()) { + // check hash lifetime + throw new ValidationException("order hash is not valid"); + } + + foreach ($tickets as $ticket_payload) { + + Log::debug + ( + sprintf + ( + "SummitOrderService::updateTicketsByOrderHash order hash %s ticket payload %s", + $order_hash, + json_encode($ticket_payload) + ) + ); + + $ticket_id = intval($ticket_payload['id']); + $ticket = $order->getTicketById($ticket_id); + + if (is_null($ticket) || !$ticket instanceof SummitAttendeeTicket) + throw new EntityNotFoundException("ticket not found"); + + $summit = $order->getSummit(); + + $first_name = $ticket_payload['attendee_first_name'] ?? null; + $last_name = $ticket_payload['attendee_last_name'] ?? null; + $email = $ticket_payload['attendee_email'] ?? null; + $company = $ticket_payload['attendee_company'] ?? null; + $extra_questions = $ticket_payload['extra_questions'] ?? []; + $disclaimer_accepted = $ticket_payload['disclaimer_accepted'] ?? null; + + if ($summit->isRegistrationDisclaimerMandatory()) { + $disclaimer_accepted = boolval($ticket_payload['disclaimer_accepted'] ?? false); + if (!$disclaimer_accepted) + throw new ValidationException("Disclaimer is Mandatory."); + } + + $attendee = $ticket->getOwner(); + + $payload = [ + 'first_name' => $first_name, + 'last_name' => $last_name, + 'company' => $company, + 'email' => $email, + 'extra_questions' => $extra_questions + ]; + + if (!is_null($disclaimer_accepted)) { + $payload['disclaimer_accepted'] = boolval($disclaimer_accepted); + } + + if (is_null($attendee) && !empty($email)) { + Log::debug(sprintf("SummitOrderService::updateTicketsByOrderHash attendee does not exists")); + // try to create it + $attendee = $this->attendee_repository->getBySummitAndEmail($summit, $email); + if (is_null($attendee)) { + Log::debug(sprintf("SummitOrderService::updateTicketsByOrderHash creating new attendee for email %s", $email)); + $attendee = new SummitAttendee(); + } + } + + // update it + SummitAttendeeFactory::populate($summit, $attendee, $payload, !empty($email) ? $this->member_repository->getByEmail($email) : null); + + if (is_null($attendee)) { + $attendee->addTicket($ticket); + $attendee->sendInvitationEmail($ticket); + } + } + + return $order; + }); + } + + /** + * @param Summit $summit + * @param UploadedFile $csv_file + * @throws ValidationException + */ + public function importTicketData(Summit $summit, UploadedFile $csv_file): void + { + + Log::debug(sprintf("SummitOrderService::importTicketData - summit %s", $summit->getId())); + + $allowed_extensions = ['txt']; + + if (!in_array($csv_file->extension(), $allowed_extensions)) { + throw new ValidationException("file does not has a valid extension ('csv')."); + } + + $real_path = $csv_file->getRealPath(); + $filename = pathinfo($real_path); + $filename = $filename['filename'] ?? sprintf("file%s", time()); + $basename = sprintf("%s_%s.csv", $filename, time()); + $filename = $csv_file->storeAs(sprintf("%s/tickets_imports", sys_get_temp_dir()), $basename); + $csv_data = File::get($real_path); + if (empty($csv_data)) + throw new ValidationException("file content is empty!"); + + $reader = CSVReader::buildFrom($csv_data); + + // check needed columns (headers names) + /* + columns + * id + * number + * attendee_email ( mandatory if id and number are missing) + * attendee_first_name (mandatory) + * attendee_last_name (mandatory) + * attendee_company (optional) + * ticket_type_name ( mandatory if id and number are missing) + * ticket_type_id ( mandatory if id and number are missing) + * badge_type_id (optional) + * badge_type_name (optional) + * one col per feature + */ + + // validate format with col names + $ticket_data_present = $reader->hasColumn("id") || $reader->hasColumn("number"); + $attendee_data_present = $reader->hasColumn("attendee_email") || + $reader->hasColumn("attendee_first_name") || + $reader->hasColumn("attendee_last_name"); + + if (!$ticket_data_present && !$attendee_data_present) + throw new ValidationException + ( + "you must define a ticket id [id], ticket number [number] or + attendee data [attendee_email, attendee_first_name, attendee_last_name] on csv columns" + ); + + ProcessTicketDataImport::dispatch($summit->getId(), $filename); + } + + /** + * @param int $summit_id + * @param string $filename + * @throws EntityNotFoundException + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function processTicketData(int $summit_id, string $filename) + { + + Log::debug(sprintf("SummitOrderService::processTicketData summit %s filename %s", $summit_id, $filename)); + + if (!Storage::disk('local')->exists($filename)) { + throw new ValidationException(sprintf("file %s does not exists.", $filename)); + } + + $csv_data = Storage::disk('local')->get($filename); + + $summit = $this->tx_service->transaction(function () use($summit_id) { + $summit = $this->summit_repository->getById($summit_id); + if (is_null($summit) || !$summit instanceof Summit) + throw new EntityNotFoundException(sprintf("summit %s does not exists.", $summit_id)); + return $summit; + }); + + $reader = CSVReader::buildFrom($csv_data); + + $ticket_data_present = $reader->hasColumn("id") || $reader->hasColumn("number"); + $attendee_data_present = $reader->hasColumn("attendee_email") || + $reader->hasColumn("attendee_first_name") || + $reader->hasColumn("attendee_last_name"); + + $badge_data_present = $reader->hasColumn("badge_type_id") || $reader->hasColumn("badge_type_name"); + + foreach ($reader as $idx => $row) { + + $this->tx_service->transaction(function () use ($summit, $reader, $row, $ticket_data_present, $attendee_data_present, $badge_data_present) { + + Log::debug(sprintf("SummitOrderService::processTicketData processing row %s", json_encode($row))); + $ticket = null; + + if ($ticket_data_present) { + Log::debug("SummitOrderService::processTicketData - has ticket data present ... trying to get ticket"); + + // edit already existent ticket ( could be assigned or not) + if ($reader->hasColumn("number")) { + Log::debug(sprintf("SummitOrderService::processTicketData trying to get ticket by number %s", $row['number'])); + $ticket = $this->ticket_repository->getByNumberExclusiveLock($row['number']); + } + + if (is_null($ticket) && $reader->hasColumn("id")) { + Log::debug(sprintf("SummitOrderService::processTicketData trying to get ticket by id %s", $row['id'])); + $ticket = $this->ticket_repository->getByIdExclusiveLock(intval($row['id'])); + } + + if (!is_null($ticket) && !$ticket->isPaid()) { + Log::debug("SummitOrderService::processTicketData - ticket is not paid"); + return; + } + } + + if ($attendee_data_present) { + Log::debug(sprintf("SummitOrderService::processTicketData - has attendee data present ... trying to get attendee %s", $row['attendee_email'])); + // check if attendee exists + $attendee = $this->attendee_repository->getBySummitAndEmail($summit, $row['attendee_email']); + $member = $this->member_repository->getByEmail($row['attendee_email']); + + if (is_null($attendee)) { + + Log::debug(sprintf("SummitOrderService::processTicketData - attendee %s does not exists", $row['attendee_email'])); + // create attendee ( populate payload) + $payload = [ + 'email' => $row['attendee_email'], + 'first_name' => $row['attendee_first_name'], + 'last_name' => $row['attendee_last_name'], + ]; + + if ($reader->hasColumn('attendee_company')) { + $payload['company'] = $row['attendee_company']; + } + + Log::debug(sprintf("SummitOrderService::processTicketData creating attendee with payload %s", json_encode($payload))); + + $attendee = SummitAttendeeFactory::build($summit, $payload, $member); + + $this->attendee_repository->add($attendee, true); + } + + if (is_null($ticket)) { + Log::debug(sprintf("SummitOrderService::processTicketData ticket is null, trying to create a new one")); + + if ($attendee->hasTickets()) { + Log::debug(sprintf("SummitOrderService::processTicketData - attendee %s already has ticket", $row['attendee_email'])); + return; + } + + Log::debug("SummitOrderService::processTicketData - ticket does not exists, creating it ..."); + // create ticket + // first try to get ticket type + $ticket_type = null; + + if ($reader->hasColumn('ticket_type_name')) { + Log::debug(sprintf("SummitOrderService::importTicketData trying to get ticket type by name %s", $row['ticket_type_name'])); + $ticket_type = $this->ticket_type_repository->getByType($summit, $row['ticket_type_name']); + } + + if (is_null($ticket_type) && $reader->hasColumn('ticket_type_id')) { + Log::debug(sprintf("SummitOrderService::processTicketData trying to get ticket type by id %s", $row['ticket_type_id'])); + $ticket_type = $this->ticket_type_repository->getById(intval($row['ticket_type_id'])); + } + + if (is_null($ticket_type)) { + Log::debug(sprintf("SummitOrderService::processTicketData - ticket type is not provide, ticket can not be created for attendee")); + return; + } + + $order = $this->createOrderSingleTicket($summit, [ + 'ticket_type_id' => $ticket_type->getId(), + 'owner_email' => $attendee->getEmail(), + 'owner_first_name' => $attendee->getFirstName(), + 'owner_last_name' => $attendee->getSurname(), + 'owner_company' => $attendee->getCompanyName(), + ]); + + $ticket = $order->getFirstTicket(); + + } else { + // ticket exists try to re assign it + Log::debug(sprintf("SummitOrderService::processTicketData ticket exists. trying to re assign it ...")); + + if ($ticket->hasOwner() && $ticket->getOwnerEmail() != $attendee->getEmail()) { + Log::debug(sprintf("SummitOrderService::processTicketData - reasigning ticket to attendee %s", $attendee->getEmail())); + $ticket->getOwner()->sendRevocationTicketEmail($ticket); + + $ticket->getOwner()->removeTicket($ticket); + } + + Log::debug(sprintf("SummitOrderService::processTicketData assigning ticket %s to attendee %s", $ticket->getNumber(), $attendee->getEmail())); + + $attendee->addTicket($ticket); + + $ticket->generateQRCode(); + $ticket->generateHash(); + + Log::debug(sprintf("SummitOrderService::processTicketData sending invitation email to attendee %s", $attendee->getEmail())); + $attendee->sendInvitationEmail($ticket); + } + } + + if (is_null($ticket)) { + Log::warning("SummitOrderService::processTicketData ticket is null stop current row processing."); + return; + } + + Log::debug(sprintf("SummitOrderService::processTicketData - got ticket %s (%s)", $ticket->getId(), $ticket->getNumber())); + + // badge data + if (!$badge_data_present) { + Log::warning("SummitOrderService::processTicketData badge data is not present stop current row processing."); + return; + } + + $badge_type = null; + + if ($reader->hasColumn("badge_type_id")) { + Log::debug(sprintf("SummitOrderService::processTicketData trying to get badge type by id %s", $row['badge_type_id'])); + $badge_type = $summit->getBadgeTypeById(intval($row['badge_type_id'])); + } + + if (is_null($badge_type) && $reader->hasColumn("badge_type_name")) { + Log::debug(sprintf("SummitOrderService::processTicketData trying to get badge type by name %s", $row['badge_type_name'])); + $badge_type = $summit->getBadgeTypeByName(trim($row['badge_type_name'])); + } + + if (!is_null($badge_type)) + Log::debug(sprintf("SummitOrderService::processTicketData - got badge type %s (%s)", $badge_type->getId(), $badge_type->getName())); + + if (!$ticket->hasBadge()) { + // create it + if (!is_null($badge_type)) { + Log::warning("SummitOrderService::processTicketData badge type is null stop current row processing."); + return; + } + Log::debug(sprintf("SummitOrderService::processTicketData - ticket %s (%s) has not badge ... creating it", $ticket->getId(), $ticket->getNumber())); + $badge = SummitBadgeType::buildBadgeFromType($badge_type); + $ticket->setBadge($badge); + } + + $badge = $ticket->getBadge(); + + if (!is_null($badge_type)) + $badge->setType($badge_type); + + $clearedFeatures = false; + // check if we are setting any badge feature + Log::debug("SummitOrderService::processTicketData processing badge type features"); + foreach ($summit->getBadgeFeaturesTypes() as $featuresType) { + $feature_name = $featuresType->getName(); + Log::debug(sprintf("SummitOrderService::processTicketData processing badge type feature %s for ticket %s", $feature_name, $ticket->getId())); + if (!$reader->hasColumn($feature_name)) { + Log::debug(sprintf("SummitOrderService::processTicketData badge type feature %s does not exists as column", $feature_name)); + continue; + } + + if (!$clearedFeatures) { + $badge->clearFeatures(); + $clearedFeatures = true; + } + + $mustAdd = intval($row[$feature_name]) === 1; + if (!$mustAdd) { + Log::debug(sprintf("SummitOrderService::processTicketData badge type feature %s not set for ticket %s", $feature_name, $ticket->getId())); + continue; + } + Log::debug(sprintf("SummitOrderService::processTicketData - ticket %s (%s) - trying to add new features to ticket badge (%s)", $ticket->getId(), $ticket->getNumber(), $feature_name)); + $feature = $summit->getFeatureTypeByName(trim($feature_name)); + if (is_null($feature)){ + Log::warning(sprintf("SummitOrderService::processTicketData feature %s does not exist on summit %s", $feature, $summit->getId())); + continue; + } + Log::debug(sprintf("SummitOrderService::processTicketData badge type feature %s set for ticket %s", $feature_name, $ticket->getId())); + $badge->addFeature($feature); + } + }); + } + } + + /** + * @param Summit $summit + * @param array $payload + * @throws ValidationException + */ + public function ingestExternalTicketData(Summit $summit, array $payload): void + { + + $email_to = $payload['email_to'] ?? null; + + if (!$summit->hasDefaultBadgeType()) { + throw new ValidationException("need to define a default badge type"); + } + + if (empty($summit->getExternalSummitId())) { + throw new ValidationException("need to set a value for external_summit_id"); + } + + if (empty($summit->getExternalRegistrationFeedType())) { + throw new ValidationException("need to set a value for external_registration_feed_type"); + } + + if (empty($summit->getExternalRegistrationFeedApiKey())) { + throw new ValidationException("need to set a value for external_registration_feed_api_key"); + } + + IngestSummitExternalRegistrationData::dispatch( + $summit->getId(), + $email_to + ); + } + + + public function processAllOrderReminder(): void + { + $summits = $this->tx_service->transaction(function () { + return $this->summit_repository->getNotEnded(); + }); + + foreach ($summits as $summit) { + Log::debug + ( + sprintf + ( + "SummitOrderService::processAllOrderReminder calling processSummitOrderReminders for summit %s", + $summit->getId() + ) + ); + $this->processSummitOrderReminders($summit); + } + } + + /** + * @param Summit $summit + * @throws \Exception + */ + public function processSummitOrderReminders(Summit $summit): void + { + + Log::debug(sprintf("SummitOrderService::processSummitOrderReminders summit %s", $summit->getId())); + + if ($summit->isEnded()) { + Log::warning(sprintf("SummitOrderService::processSummitOrderReminders - summit %s has ended already", $summit->getId())); + return; + } + + $page = 1; + $has_more_items = true; + + do { + // done in this way to avoid db lock contention + + $orders = $this->tx_service->transaction(function () use ($summit, $page) { + return $this->order_repository->getAllOrderThatNeedsEmailActionReminder($summit, new PagingInfo($page, 100)); + }); + + $has_more_items = $orders->hasMoreItems(); + + foreach ($orders->getItems() as $order) { + if (!$order instanceof SummitOrder) continue; + Log::debug(sprintf("SummitOrderService::processSummitOrderReminders - summit %s order %s", $summit->getId(), $order->getId())); + try { + $this->processOrderReminder($order); + } catch (\Exception $ex) { + Log::error($ex); + } + foreach ($order->getTickets() as $ticket) { + try { + $this->processTicketReminder($ticket); + } catch (\Exception $ex) { + Log::error($ex); + } + } + } + + ++$page; + + } while ($has_more_items); + } + + /** + * @param SummitOrder $order + * @throws \Exception + */ + public function processOrderReminder(SummitOrder $order): void + { + $this->tx_service->transaction(function () use ($order) { + + $summit = $order->getSummit(); + if ($summit->isEnded()) { + Log::warning(sprintf("SummitOrderService::processOrderReminder - summit %s has ended already", $summit->getId())); + return; + } + + if (!$order->isPaid()) { + Log::warning(sprintf("SummitOrderService::processOrderReminder - order %s no need email reminder", $order->getId())); + return; + } + + $needs_action = false; + + foreach ($order->getTickets() as $ticket) { + if (!$ticket->hasOwner()) { + $needs_action = true; + break; + } + $attendee = $ticket->getOwner(); + $attendee->updateStatus(); + if (!$attendee->isComplete()) { + $needs_action = true; + break; + } + } + + if (!$needs_action) { + Log::warning(sprintf("SummitOrderService::processOrderReminder - order %s no need email reminder", $order->getId())); + return; + } + + $last_action_date = $order->getLastReminderEmailSentDate(); + $summit = $order->getSummit(); + $days_interval = $summit->getRegistrationReminderEmailDaysInterval(); + + if ($days_interval <= 0) return; + $utc_now = new \DateTime('now', new \DateTimeZone('UTC')); + Log::debug(sprintf("SummitOrderService::processOrderReminder - last_action_date %s utc_now %s", $last_action_date->format("Y-m-d H:i:s"), $utc_now->format("Y-m-d H:i:s"))); + $last_action_date->add(new \DateInterval("P" . $days_interval . 'D')); + Log::debug(sprintf("SummitOrderService::processOrderReminder - last action date plus %s days %s utc_now %s", $days_interval, $last_action_date->format("Y-m-d H:i:s"), $utc_now->format("Y-m-d H:i:s"))); + + if ($last_action_date <= $utc_now) { + + $order->setLastReminderEmailSentDate($utc_now); + Log::debug(sprintf("SummitOrderService::processOrderReminder - sending reminder email for order %s", $order->getId())); + SummitOrderReminderEmail::dispatch($order); + } + }); + } + + /** + * @param SummitAttendeeTicket $ticket + * @throws \Exception + */ + public function processTicketReminder(SummitAttendeeTicket $ticket): void + { + $this->tx_service->transaction(function () use ($ticket) { + + if (!$ticket->hasOwner()) { + Log::warning(sprintf("ticket %s no need email reminder ( no owner )", $ticket->getId())); + return; + } + + if (!$ticket->isPaid()) { + Log::warning(sprintf("ticket %s no need email reminder (not paid )", $ticket->getId())); + return; + } + + if (!$ticket->hasTicketType()) { + Log::warning(sprintf("ticket %s no need email reminder ( no type )", $ticket->getId())); + return; + } + + $attendee = $ticket->getOwner(); + + if ($attendee->isComplete()) { + Log::warning(sprintf("ticket %s no need email reminder", $ticket->getId())); + return; + } + + $last_action_date = $attendee->getLastReminderEmailSentDate(); + $order = $ticket->getOrder(); + $summit = $order->getSummit(); + + if ($summit->isEnded()) { + Log::warning(sprintf("SummitOrderService::processTicketReminder - summit %s has ended already", $summit->getId())); + return; + } + + $days_interval = $summit->getRegistrationReminderEmailDaysInterval(); + + if ($days_interval <= 0) return; + $utc_now = new \DateTime('now', new \DateTimeZone('UTC')); + $last_action_date->add(new \DateInterval("P" . $days_interval . 'D')); + + if ($last_action_date <= $utc_now) { + + $attendee->setLastReminderEmailSentDate($utc_now); + Log::debug(sprintf("sending reminder email for ticket %s", $ticket->getId())); + // regenerate hash + $ticket->generateHash(); + SummitTicketReminderEmail::dispatch($ticket); + } + }); + } + + /** + * @param Summit $summit + * @param string $order_hash + * @return SummitAttendeeTicket|null + */ + public function getMyTicketByOrderHash(Summit $summit, string $order_hash): ?SummitAttendeeTicket + { + return $this->tx_service->transaction(function () use ($summit, $order_hash) { + $order = $this->order_repository->getByHashLockExclusive($order_hash); + + if (is_null($order) || !$order instanceof SummitOrder || $summit->getId() != $order->getSummitId()) + throw new EntityNotFoundException("order not found"); + + if (!$order->isSingleOrder()) { + throw new ValidationException("order is not single ticket or owner is equal to attendee"); + } + + $ticket = $order->getTickets()->first(); + if (!$ticket instanceof SummitAttendeeTicket) { + throw new EntityNotFoundException("ticket not found"); + } + + if (!$ticket->canPubliclyEdit()) { + Log::debug(sprintf("SummitOrderService::getMyTicketByOrderHash regenerating hash for ticket %s", $ticket->getId())); + $ticket->generateHash(); + } + + return $ticket; + }); + } + + /** + * @param SummitOrder $order + */ + private function sendAttendeesInvitationEmail(SummitOrder $order) + { + Log::debug(sprintf("SummitOrderService::sendAttendeesInvitationEmail order %s", $order->getId())); + foreach ($order->getTickets() as $ticket) { + try { + Log::debug(sprintf("SummitOrderService::sendAttendeesInvitationEmail order %s ticket %s", $order->getId(), $ticket->getNumber())); + if (!$ticket->hasOwner()) { + Log::debug(sprintf("SummitOrderService::sendAttendeesInvitationEmail ticket %s has not owner set", $ticket->getNumber())); + continue; + } + $ticket->generateQRCode(); + $ticket->generateHash(); + $ticket->getOwner()->sendInvitationEmail($ticket); + } catch (\Exception $ex) { + Log::warning($ex); + } + } + } + + /** + * @param SummitOrder $order + */ + private function sendExistentSummitOrderOwnerEmail(SummitOrder $order) + { + Log::debug(sprintf("SummitOrderService::sendExistentSummitOrderOwnerEmail for order %s", $order->getId())); + RegisteredMemberOrderPaidMail::dispatch($order); + } + + /** + * @param SummitOrder $order + * @param array $user_registration_request + */ + private function sendSummitOrderOwnerInvitationEmail(SummitOrder $order, array $user_registration_request) + { + Log::debug(sprintf("SummitOrderService::sendSummitOrderOwnerInvitationEmail for order %s", $order->getId())); + UnregisteredMemberOrderPaidMail::dispatch($order, $user_registration_request['set_password_link']); + } + + /** + * @param int $orderId + * @throws \Exception + */ + public function processOrderPaymentConfirmation(int $orderId): void + { + + $this->tx_service->transaction(function () use ($orderId) { + + Log::debug(sprintf("SummitOrderService::processOrderPaymentConfirmation - trying to get order id %s", $orderId)); + + $order = $this->order_repository->getByIdExclusiveLock($orderId); + if (is_null($order) || !$order instanceof SummitOrder){ + Log::warning(sprintf("SummitOrderService::processOrderPaymentConfirmation order %s not found.", $orderId)); + } + + Log::debug(sprintf("SummitOrderService::processOrderPaymentConfirmation - got order id %s nbr %s", $orderId, $order->getNumber())); + $order->generateQRCode(); + + if (!$order->hasOwner()) { + // owner is not registered ... + Log::debug("SummitOrderService::processOrderPaymentConfirmation - order has not owner set"); + $ownerEmail = $order->getOwnerEmail(); + // check if we have a member on db + Log::debug(sprintf("SummitOrderService::processOrderPaymentConfirmation - trying to get email %s from db", $ownerEmail)); + $member = $this->member_repository->getByEmail($ownerEmail); + + if (!is_null($member)) { + // its turns out that email was registered as a member + // set the owner and move on + Log::debug(sprintf("SummitOrderService::processOrderPaymentConfirmation - member %s found at db", $ownerEmail)); + $order->setOwner($member); + + Log::debug("SummitOrderService::processOrderPaymentConfirmation - sending email to owner"); + // send email to owner; + $this->sendExistentSummitOrderOwnerEmail($order); + + Log::debug("SummitOrderService::processOrderPaymentConfirmation - sending email to attendees"); + $this->sendAttendeesInvitationEmail($order); + return; + } + + $user = $this->member_service->checkExternalUser($ownerEmail); + + if (is_null($user)) { + + Log::debug + ( + sprintf + ( + "SummitOrderService::processOrderPaymentConfirmation - user %s does not exist at IDP, emiting a registration request on idp", + $ownerEmail + ) + ); + + // user does not exists , emit a registration request + // need to send email with set password link + + $this->sendSummitOrderOwnerInvitationEmail($order, $this->member_service->emitRegistrationRequest + ( + $ownerEmail, + $order->getOwnerFirstName(), + $order->getOwnerSurname() + )); + + $this->sendAttendeesInvitationEmail($order); + return; + } + + Log::debug + ( + sprintf + ( + "SummitOrderService::processOrderPaymentConfirmation - Creating a local user for %s", + $ownerEmail + ) + ); + + // we have an user on idp + $member = $this->member_service->registerExternalUser + ( + $user['id'], + $user['email'], + $user['first_name'], + $user['last_name'] + ); + // add the order to newly created member + $member->addSummitRegistrationOrder($order); + } + + // send email to owner + $this->sendExistentSummitOrderOwnerEmail($order); + // send email to owner; + $this->sendAttendeesInvitationEmail($order); + + $summit = $order->getSummit(); + if ($summit->isInviteOnlyRegistration()) { + // we should mark the associated invitation as processed + $invitation = $summit->getSummitRegistrationInvitationByEmail($order->getOwnerEmail()); + if (is_null($invitation)) { + Log::warning(sprintf("order %s has not valid invitation for email %s.", $order->getId(), $order->getOwnerEmail())); + return; + } + $invitation->setOrder($order); + $invitation->markAsAccepted(); + } + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/SummitPromoCodeService.php b/app/Services/Model/Imp/SummitPromoCodeService.php similarity index 51% rename from app/Services/Model/SummitPromoCodeService.php rename to app/Services/Model/Imp/SummitPromoCodeService.php index 46f75033..b26d1c29 100644 --- a/app/Services/Model/SummitPromoCodeService.php +++ b/app/Services/Model/Imp/SummitPromoCodeService.php @@ -11,21 +11,21 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use App\Jobs\Emails\Registration\PromoCodeEmailFactory; use App\Models\Foundation\Summit\Factories\SummitPromoCodeFactory; +use App\Models\Foundation\Summit\Factories\SummitRegistrationDiscountCodeTicketTypeRuleFactory; use libs\utils\ITransactionService; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; -use models\main\EmailCreationRequest; use models\main\ICompanyRepository; -use models\main\IEmailCreationRequestRepository; use models\main\IMemberRepository; use models\main\Member; -use models\main\MemberPromoCodeEmailCreationRequest; +use models\summit\IOwnablePromoCode; use models\summit\ISpeakerRepository; use models\summit\ISummitRegistrationPromoCodeRepository; -use models\summit\MemberSummitRegistrationPromoCode; -use models\summit\SpeakerSummitRegistrationPromoCode; use models\summit\Summit; +use models\summit\SummitRegistrationDiscountCode; use models\summit\SummitRegistrationPromoCode; use services\model\ISummitPromoCodeService; /** @@ -56,18 +56,12 @@ final class SummitPromoCodeService */ private $speaker_repository; - /** - * @var IEmailCreationRequestRepository - */ - private $email_creation_request_repository; - /** * SummitPromoCodeService constructor. * @param ISummitRegistrationPromoCodeRepository $promo_code_repository * @param IMemberRepository $member_repository * @param ICompanyRepository $company_repository * @param ISpeakerRepository $speaker_repository - * @param IEmailCreationRequestRepository $email_creation_request_repository * @param ITransactionService $tx_service */ public function __construct @@ -76,7 +70,6 @@ final class SummitPromoCodeService IMemberRepository $member_repository, ICompanyRepository $company_repository, ISpeakerRepository $speaker_repository, - IEmailCreationRequestRepository $email_creation_request_repository, ITransactionService $tx_service ) { @@ -85,16 +78,40 @@ final class SummitPromoCodeService $this->member_repository = $member_repository; $this->company_repository = $company_repository; $this->speaker_repository = $speaker_repository; - $this->email_creation_request_repository = $email_creation_request_repository; } /** + * @param Summit $summit * @param array $data * @return array * @throws EntityNotFoundException */ - private function getPromoCodeParams(array $data){ - $params = []; + private function getPromoCodeParams(Summit $summit, array $data){ + $params = []; + + if(isset($data['allowed_ticket_types'])){ + $allowed_ticket_types = []; + foreach($data['allowed_ticket_types'] as $ticket_type_id){ + $ticket_type = $summit->getTicketTypeById(intval($ticket_type_id)); + if(is_null($ticket_type)) + throw new EntityNotFoundException(sprintf("ticket type %s not found", $ticket_type_id)); + $allowed_ticket_types[] = $ticket_type; + + } + $params['allowed_ticket_types'] = $allowed_ticket_types; + } + + if(isset($data['badge_features'])){ + $badge_features = []; + foreach($data['badge_features'] as $feature_id){ + $feature = $summit->getFeatureTypeById(intval($feature_id)); + if(is_null($feature)) + throw new EntityNotFoundException(sprintf("badge feature %s not found", $feature_id)); + $badge_features[] = $feature; + + } + $params['badge_features'] = $badge_features; + } if(isset($data['owner_id'])){ $owner = $this->member_repository->getById(intval($data['owner_id'])); @@ -110,7 +127,6 @@ final class SummitPromoCodeService $params['speaker'] = $speaker; } - if(isset($data['sponsor_id'])){ $sponsor = $this->company_repository->getById(intval($data['sponsor_id'])); if(is_null($sponsor)) @@ -118,6 +134,13 @@ final class SummitPromoCodeService $params['sponsor'] = $sponsor; } + if(isset($data['badge_type_id'])){ + $badge_type = $summit->getBadgeTypeById(intval($data['badge_type_id'])); + if(is_null($badge_type)) + throw new EntityNotFoundException(sprintf("badge_type_id %s not found", $data['badge_type_id'])); + $params['badge_type'] = $badge_type; + } + return $params; } /** @@ -132,12 +155,18 @@ final class SummitPromoCodeService { return $this->tx_service->transaction(function() use($summit, $data, $current_user){ - $old_promo_code = $summit->getPromoCodeByCode(trim($data['code'])); + $code = trim($data['code']); + if(empty($code)) + { + throw new ValidationException("code can not be empty!"); + } + + $old_promo_code = $summit->getPromoCodeByCode($code); if(!is_null($old_promo_code)) throw new ValidationException(sprintf("promo code %s already exits on summit id %s", trim($data['code']), $summit->getId())); - $promo_code = SummitPromoCodeFactory::build($summit, $data, $this->getPromoCodeParams($data)); + $promo_code = SummitPromoCodeFactory::build($summit, $data, $this->getPromoCodeParams($summit, $data)); if(is_null($promo_code)) throw new ValidationException(sprintf("class_name %s is invalid", $data['class_name'])); @@ -163,20 +192,22 @@ final class SummitPromoCodeService { return $this->tx_service->transaction(function() use($promo_code_id, $summit, $data, $current_user){ - $old_promo_code = $summit->getPromoCodeByCode(trim($data['code'])); - - if(!is_null($old_promo_code) && $old_promo_code->getId() != $promo_code_id) - throw new ValidationException(sprintf("promo code %s already exits on summit id %s for promo code id %s", trim($data['code']), $summit->getId(), $old_promo_code->getId())); - $promo_code = $summit->getPromoCodeById($promo_code_id); if(is_null($promo_code)) throw new EntityNotFoundException(sprintf("promo code id %s does not belongs to summit id %s", $promo_code_id, $summit->getId())); - $promo_code = SummitPromoCodeFactory::populate($promo_code, $summit, $data, $this->getPromoCodeParams($data)); + if(isset($data['code'])) { + $old_promo_code = $summit->getPromoCodeByCode(trim($data['code'])); + + if (!is_null($old_promo_code) && $old_promo_code->getId() != $promo_code_id) + throw new ValidationException(sprintf("promo code %s already exits on summit id %s for promo code id %s", trim($data['code']), $summit->getId(), $old_promo_code->getId())); + + } + + $promo_code = SummitPromoCodeFactory::populate($promo_code, $summit, $data, $this->getPromoCodeParams($summit, $data)); if(!is_null($current_user)) $promo_code->setCreator($current_user); - $promo_code->setSourceAdmin(); return $promo_code; @@ -192,7 +223,7 @@ final class SummitPromoCodeService */ public function deletePromoCode(Summit $summit, $promo_code_id) { - return $this->tx_service->transaction(function() use($promo_code_id, $summit){ + $this->tx_service->transaction(function() use($promo_code_id, $summit){ $promo_code = $summit->getPromoCodeById($promo_code_id); if(is_null($promo_code)) @@ -219,13 +250,12 @@ final class SummitPromoCodeService /** * @param Summit $summit * @param int $promo_code_id - * @return EmailCreationRequest * @throws EntityNotFoundException * @throws ValidationException */ public function sendPromoCodeMail(Summit $summit, $promo_code_id) { - return $this->tx_service->transaction(function() use($promo_code_id, $summit){ + $this->tx_service->transaction(function() use($promo_code_id, $summit){ $promo_code = $summit->getPromoCodeById($promo_code_id); if(is_null($promo_code)) @@ -234,13 +264,9 @@ final class SummitPromoCodeService $name = null; $email = null; - if($promo_code instanceof SpeakerSummitRegistrationPromoCode && $promo_code->hasSpeaker()){ - $name = $promo_code->getSpeaker()->getFullName(); - $email = $promo_code->getSpeaker()->getEmail(); - } - if($promo_code instanceof MemberSummitRegistrationPromoCode && $promo_code->hasOwner()){ - $name = $promo_code->getFullName(); - $email = $promo_code->getEmail(); + if($promo_code instanceof IOwnablePromoCode && $promo_code->hasOwner()){ + $name = $promo_code->getOwnerFullname(); + $email = $promo_code->getOwnerEmail(); } if(empty($email)){ @@ -251,14 +277,123 @@ final class SummitPromoCodeService throw new ValidationException(trans("validation_errors.promo_code_email_send_empty_name")); } - // create email request - $email_request = new MemberPromoCodeEmailCreationRequest(); - $email_request->setPromoCode($promo_code); - $email_request->setEmail($email); - $email_request->setName($name); - $this->email_creation_request_repository->add($email_request); + PromoCodeEmailFactory::send($promo_code); $promo_code->setEmailSent(true); - return $email_request; + }); + } + + /** + * @param Summit $summit + * @param int $promo_code_id + * @param int $ticket_type_id + * @param array $data + * @return SummitRegistrationPromoCode + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addPromoCodeTicketTypeRule(Summit $summit, int $promo_code_id, int $ticket_type_id, array $data): SummitRegistrationPromoCode + { + return $this->tx_service->transaction(function() use($summit, $promo_code_id, $ticket_type_id, $data){ + $promo_code = $summit->getPromoCodeById($promo_code_id); + if(is_null($promo_code)) + throw new EntityNotFoundException("promo code not found"); + + $ticket_type = $summit->getTicketTypeById($ticket_type_id); + if(is_null($ticket_type)) + throw new EntityNotFoundException("ticket type not found"); + + if($promo_code instanceof SummitRegistrationDiscountCode){ + $data['ticket_type'] = $ticket_type; + $rule = SummitRegistrationDiscountCodeTicketTypeRuleFactory::build($data); + $promo_code->addTicketTypeRule($rule); + + return $promo_code; + } + + $promo_code->addAllowedTicketType($ticket_type); + + return $promo_code; + + }); + } + + /** + * @param Summit $summit + * @param int $promo_code_id + * @param int $ticket_type_id + * @return SummitRegistrationPromoCode + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function removePromoCodeTicketTypeRule(Summit $summit, int $promo_code_id, int $ticket_type_id): SummitRegistrationPromoCode + { + return $this->tx_service->transaction(function() use($summit, $promo_code_id, $ticket_type_id){ + $promo_code = $summit->getPromoCodeById($promo_code_id); + if(is_null($promo_code)) + throw new EntityNotFoundException("promo code not found"); + + $ticket_type = $summit->getTicketTypeById($ticket_type_id); + if(is_null($ticket_type)) + throw new EntityNotFoundException("ticket type not found"); + + if($promo_code instanceof SummitRegistrationDiscountCode){ + $promo_code->removeTicketTypeRuleForTicketType($ticket_type); + return $promo_code; + } + + $promo_code->removeAllowedTicketType($ticket_type); + + return $promo_code; + }); + } + + /** + * @param Summit $summit + * @param int $promo_code_id + * @param int $badge_feature_id + * @return SummitRegistrationPromoCode + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addPromoCodeBadgeFeature(Summit $summit, int $promo_code_id, int $badge_feature_id): SummitRegistrationPromoCode + { + return $this->tx_service->transaction(function() use($summit, $promo_code_id, $badge_feature_id){ + $promo_code = $summit->getPromoCodeById($promo_code_id); + if(is_null($promo_code)) + throw new EntityNotFoundException("promo code not found"); + + $badge_feature = $summit->getFeatureTypeById($badge_feature_id); + if(is_null($badge_feature)) + throw new EntityNotFoundException("badge feature not found"); + + $promo_code->addBadgeFeatureType($badge_feature); + + return $promo_code; + }); + } + + /** + * @param Summit $summit + * @param int $promo_code_id + * @param int $badge_feature_id + * @return SummitRegistrationPromoCode + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function removePromoCodeBadgeFeature(Summit $summit, int $promo_code_id, int $badge_feature_id): SummitRegistrationPromoCode + { + return $this->tx_service->transaction(function() use($summit, $promo_code_id, $badge_feature_id){ + $promo_code = $summit->getPromoCodeById($promo_code_id); + if(is_null($promo_code)) + throw new EntityNotFoundException("promo code not found"); + + $badge_feature = $summit->getFeatureTypeById($badge_feature_id); + if(is_null($badge_feature)) + throw new EntityNotFoundException("badge feature not found"); + + $promo_code->removeBadgeFeatureType($badge_feature); + + return $promo_code; }); } } \ No newline at end of file diff --git a/app/Services/Model/SummitPushNotificationService.php b/app/Services/Model/Imp/SummitPushNotificationService.php similarity index 100% rename from app/Services/Model/SummitPushNotificationService.php rename to app/Services/Model/Imp/SummitPushNotificationService.php diff --git a/app/Services/Model/Imp/SummitRefundPolicyTypeService.php b/app/Services/Model/Imp/SummitRefundPolicyTypeService.php new file mode 100644 index 00000000..c0ad836d --- /dev/null +++ b/app/Services/Model/Imp/SummitRefundPolicyTypeService.php @@ -0,0 +1,107 @@ +tx_service->transaction(function() use($summit, $payload){ + $name = trim($payload['name']); + $days = intval($payload['until_x_days_before_event_starts']); + $former_policy = $summit->getRefundPolicyByName($name); + if(!is_null($former_policy)) + throw new ValidationException(sprintf("%s refund policy name already exists", $name)); + $former_policy = $summit->getRefundPolicyByDays($days); + if(!is_null($former_policy)) + throw new ValidationException(sprintf("refund policy for %s days already exists", $days)); + + $policy = SummitRefundPolicyTypeFactory::build($payload); + + $summit->addRefundPolicy($policy); + + return $policy; + }); + } + + /** + * @param Summit $summit + * @param int $policy_id + * @param array $payload + * @return SummitRefundPolicyType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updatePolicy(Summit $summit, int $policy_id, array $payload): SummitRefundPolicyType + { + return $this->tx_service->transaction(function() use($summit, $policy_id, $payload){ + $policy = $summit->getRefundPolicyById($policy_id); + if(is_null($policy)) + throw new EntityNotFoundException("policy not found"); + + if(isset($payload['name'])) { + $name = trim($payload['name']); + $former_policy = $summit->getRefundPolicyByName($name); + if (!is_null($former_policy) && $former_policy->getId() != $policy_id) + throw new ValidationException(sprintf("%s refund policy name already exists", $name)); + } + + if(isset($payload['until_x_days_before_event_starts'])) { + $days = intval($payload['until_x_days_before_event_starts']); + $former_policy = $summit->getRefundPolicyByDays($days); + if (!is_null($former_policy) && $former_policy->getId() != $policy_id) + throw new ValidationException(sprintf("refund policy for %s days already exists", $days)); + } + + return SummitRefundPolicyTypeFactory::populate($policy, $payload); + }); + } + + /** + * @param Summit $summit + * @param int $policy_id + * @return void + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function deletePolicy(Summit $summit, int $policy_id): void + { + $this->tx_service->transaction(function() use($summit, $policy_id){ + $policy = $summit->getRefundPolicyById($policy_id); + if(is_null($policy)) + throw new EntityNotFoundException("policy not found"); + + $summit->removeRefundPolicy($policy); + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitRegistrationInvitationService.php b/app/Services/Model/Imp/SummitRegistrationInvitationService.php new file mode 100644 index 00000000..8a0aad16 --- /dev/null +++ b/app/Services/Model/Imp/SummitRegistrationInvitationService.php @@ -0,0 +1,397 @@ +member_repository = $member_repository; + $this->external_user_api = $external_user_api; + $this->invitation_repository = $invitation_repository; + $this->member_service = $member_service; + } + + /** + * @param Summit $summit + * @param UploadedFile $csv_file + * @throws ValidationException + */ + public function importInvitationData(Summit $summit, UploadedFile $csv_file): void + { + Log::debug(sprintf("SummitRegistrationInvitationService::importInvitationData - summit %s", $summit->getId())); + + $allowed_extensions = ['txt']; + + if (!in_array($csv_file->extension(), $allowed_extensions)) { + throw new ValidationException("File does not has a valid extension ('csv')."); + } + + $csv_data = File::get($csv_file->getRealPath()); + + if (empty($csv_data)) + throw new ValidationException("File content is empty."); + + $reader = CSVReader::buildFrom($csv_data); + + // check needed columns (headers names) + /*********************************************************** + columns + * email (mandatory) + * first_name (mandatory) + * last_name (mandatory) + ***********************************************************/ + + if(!$reader->hasColumn("email")) + throw new ValidationException("File is missing email column."); + if(!$reader->hasColumn("first_name")) + throw new ValidationException("File is missing first_name column."); + if(!$reader->hasColumn("last_name")) + throw new ValidationException("File is missing last_name column."); + + foreach ($reader as $idx => $row) { + $this->tx_service->transaction(function () use ($summit, $reader, $row) { + try{ + $this->add($summit, $row); + } + catch (\Exception $ex){ + Log::warning($ex); + } + }); + } + + } + + /** + * @inheritDoc + */ + public function delete(Summit $summit, int $invitation_id): void + { + $this->tx_service->transaction(function() use($summit, $invitation_id){ + $invitation = $summit->getSummitRegistrationInvitationById($invitation_id); + if(is_null($invitation)){ + throw new EntityNotFoundException("Invitation not found."); + } + + $summit->removeRegistrationInvitation($invitation); + }); + } + + /** + * @inheritDoc + */ + public function add(Summit $summit, array $payload): SummitRegistrationInvitation + { + return $this->tx_service->transaction(function() use($summit, $payload){ + $email = trim($payload['email']); + $former_invitation = $summit->getSummitRegistrationInvitationByEmail($email); + if(!is_null($former_invitation)){ + throw new ValidationException(sprintf("Email %s already has been invited for summit %s", $email, $summit->getId())); + } + + $invitation = SummitRegistrationInvitationFactory::build($payload); + + $invitation = $this->setInvitationMember($invitation, $email); + + $summit->addRegistrationInvitation($invitation); + + return $invitation; + }); + } + + /** + * @param SummitRegistrationInvitation $invitation + * @param string $email + * @return SummitRegistrationInvitation + * @throws \Exception + */ + private function setInvitationMember(SummitRegistrationInvitation $invitation, string $email):SummitRegistrationInvitation { + return $this->tx_service->transaction(function() use($invitation, $email){ + $member = $this->member_repository->getByEmail($email); + // try to get an user externally , user does not exits locally + if(is_null($member)){ + // check if user exists by email at idp + Log::debug(sprintf("SummitRegistrationInvitationService::setInvitationMember - trying to get member %s from user api", $email)); + $user = $this->external_user_api->getUserByEmail($email); + // check if primary email is the same if not disregard + $primary_email = $user['email'] ?? null; + if(strcmp(strtolower($primary_email), strtolower($email)) !== 0){ + Log::debug + ( + sprintf + ( + "SummitRegistrationInvitationService::setInvitationMember primary email %s differs from order owner email %s", + $primary_email, + $email + ) + ); + + // email are not equals , then is not the user bc primary emails differs ( could be a + // match on a secondary email) + $user = null; // set null on user and proceed to emit a registration request. + } + + if(is_null($user)){ + + Log::debug + ( + sprintf + ( + "SummitRegistrationInvitationService::setInvitationMember - user %s does not exist at IDP, emiting a registration request on idp", + $email + ) + ); + + // user does not exists , emit a registration request + $user_registration_request = $this->external_user_api->registerUser + ( + $email, + $invitation->getFirstName(), + $invitation->getLastName() + ); + + $invitation->setSetPasswordLink($user_registration_request['set_password_link']); + } + + if(!is_null($user)) { + Log::debug + ( + sprintf + ( + "SummitRegistrationInvitationService::setInvitationMember - Creating a local user for %s", + $email + ) + ); + + // we have an user on idp + $member = $this->member_service->registerExternalUser + ( + $user['id'], + $user['email'], + $user['first_name'], + $user['last_name'] + ); + } + } + + if(!is_null($member)) + $invitation->setMember($member); + + return $invitation; + }); + } + /** + * @inheritDoc + */ + public function update(Summit $summit, int $invitation_id, array $payload): SummitRegistrationInvitation + { + return $this->tx_service->transaction(function() use($summit, $payload, $invitation_id){ + $invitation = $summit->getSummitRegistrationInvitationById($invitation_id); + if(is_null($invitation)) + throw new EntityNotFoundException(sprintf("Invitation %s not found at Summit %s", $invitation_id, $summit->getId())); + + if(isset($payload['email'])) { + $email = trim($payload['email']); + $former_invitation = $summit->getSummitRegistrationInvitationByEmail($email); + if (!is_null($former_invitation) && $former_invitation->getId() !== $invitation_id) { + throw new ValidationException(sprintf("Email %s already has been invited for summit %s", $email, $summit->getId())); + } + } + + $invitation = SummitRegistrationInvitationFactory::populate($invitation, $payload); + + if(isset($payload['email'])) { + $email = trim($payload['email']); + $invitation = $this->setInvitationMember($invitation, $email); + } + + return $invitation; + }); + } + + /** + * @param Member $current_member + * @param string $token + * @return SummitRegistrationInvitation + * @throws \Exception + */ + public function getInvitationByToken(Member $current_member, string $token): SummitRegistrationInvitation + { + return $this->tx_service->transaction(function () use ($current_member, $token) { + + $invitation = $this->invitation_repository->getByHashExclusiveLock(SummitRegistrationInvitation::HashConfirmationToken($token)); + + if(is_null($invitation)) + throw new EntityNotFoundException("Invitation not found."); + Log::debug(sprintf("got invitation %s for email %s", $invitation->getId(), $invitation->getEmail())); + if($invitation->getEmail() !== $current_member->getEmail()) + throw new ValidationException("Invitation belongs to another User."); + + $invitation->setMember($current_member); + + if($invitation->isAccepted()){ + throw new ValidationException("Invitation is already accepted."); + } + + return $invitation; + }); + } + + /** + * @param Summit $summit + * @param string $email + * @return SummitRegistrationInvitation|null + * @throws \Exception + */ + public function getInvitationByEmail(Summit $summit, string $email):?SummitRegistrationInvitation + { + return $this->tx_service->transaction(function () use ($summit, $email) { + if(!$summit->isInviteOnlyRegistration()) + throw new ValidationException(sprintf("Summit %s is not invite only.", $summit->getId())); + + return $summit->getSummitRegistrationInvitationByEmail($email); + }); + } + + /** + * @inheritDoc + */ + public function deleteAll(Summit $summit): void + { + $this->tx_service->transaction(function() use($summit){ + $summit->clearRegistrationInvitations(); + }); + } + + /** + * @param Summit $summit + * @param array $payload + * @param Filter|null $filter + */ + public function triggerSend(Summit $summit, array $payload, $filter = null): void + { + ProcessRegistrationInvitationsJob::dispatch($summit, $payload, $filter); + } + + /** + * @inheritDoc + */ + public function send(int $summit_id, array $payload, Filter $filter = null): void + { + $flow_event = trim($payload['email_flow_event']); + + Log::debug(sprintf("SummitRegistrationInvitationService::send summit id %s flow_event %s", $summit_id, $flow_event)); + + $ids = $this->tx_service->transaction(function() use($summit_id, $payload, $filter){ + if(isset($payload['invitations_ids'])) { + Log::debug(sprintf("SummitRegistrationInvitationService::send summit id %s invitations_ids %s", $summit_id, json_encode($payload['invitations_ids']))); + return $payload['invitations_ids']; + } + Log::debug(sprintf("SummitRegistrationInvitationService::send summit id %s getting by filter", $summit_id)); + if(is_null($filter)){ + $filter = new Filter(); + } + $filter->addFilterCondition(FilterElement::makeEqual('summit_id', $summit_id)); + return $this->invitation_repository->getAllIdsByPage(new PagingInfo(1, PHP_INT_MAX), $filter); + }); + + foreach ($ids as $invitation_id) + $this->tx_service->transaction(function() use($flow_event, $invitation_id){ + + Log::debug(sprintf("SummitRegistrationInvitationService::send processing invitation id %s", $invitation_id)); + + $invitation = $this->invitation_repository->getByIdExclusiveLock(intval($invitation_id)); + if(is_null($invitation) || !$invitation instanceof SummitRegistrationInvitation) return; + + $summit = $invitation->getSummit(); + + while(true) { + $invitation->generateConfirmationToken(); + $former_invitation = $summit->getSummitRegistrationInvitationByHash($invitation->getHash()); + if(is_null($former_invitation) || $former_invitation->getId() == $invitation->getId()) break; + } + + // send email + if($flow_event == InviteSummitRegistrationEmail::EVENT_SLUG) + InviteSummitRegistrationEmail::dispatch($invitation); + if($flow_event == ReInviteSummitRegistrationEmail::EVENT_SLUG) + ReInviteSummitRegistrationEmail::dispatch($invitation); + + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/SummitSelectionPlanService.php b/app/Services/Model/Imp/SummitSelectionPlanService.php similarity index 78% rename from app/Services/Model/SummitSelectionPlanService.php rename to app/Services/Model/Imp/SummitSelectionPlanService.php index 0f91dcdc..f5c4eda1 100644 --- a/app/Services/Model/SummitSelectionPlanService.php +++ b/app/Services/Model/Imp/SummitSelectionPlanService.php @@ -11,6 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + use App\Models\Foundation\Summit\Factories\SummitSelectionPlanFactory; use App\Models\Foundation\Summit\SelectionPlan; use libs\utils\ITransactionService; @@ -18,6 +19,7 @@ use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; use models\summit\ISummitRepository; use models\summit\Summit; + /** * Class SummitSelectionPlanService * @package App\Services\Model @@ -45,13 +47,13 @@ final class SummitSelectionPlanService */ public function addSelectionPlan(Summit $summit, array $payload) { - return $this->tx_service->transaction(function() use($summit, $payload){ + return $this->tx_service->transaction(function () use ($summit, $payload) { $selection_plan = SummitSelectionPlanFactory::build($payload, $summit); $former_selection_plan = $summit->getSelectionPlanByName($selection_plan->getName()); - if(!is_null($former_selection_plan)){ + if (!is_null($former_selection_plan)) { throw new ValidationException(trans( 'validation_errors.SummitSelectionPlanService.addSelectionPlan.alreadyExistName', [ @@ -61,10 +63,8 @@ final class SummitSelectionPlanService } // validate selection plan + $summit->checkSelectionPlanConflicts($selection_plan); - foreach($this->summit_repository->getCurrentAndFutureSummits() as $cur_summit){ - $cur_summit->checkSelectionPlanConflicts($selection_plan); - } $summit->addSelectionPlan($selection_plan); @@ -82,10 +82,10 @@ final class SummitSelectionPlanService */ public function updateSelectionPlan(Summit $summit, $selection_plan_id, array $payload) { - return $this->tx_service->transaction(function() use($summit, $selection_plan_id, $payload){ + return $this->tx_service->transaction(function () use ($summit, $selection_plan_id, $payload) { $selection_plan = $summit->getSelectionPlanById($selection_plan_id); - if(is_null($selection_plan)) + if (is_null($selection_plan)) throw new EntityNotFoundException(trans ('not_found_errors.SummitSelectionPlanService.updateSelectionPlan.SelectionPlanNotFound', [ @@ -94,7 +94,7 @@ final class SummitSelectionPlanService ] )); - if(isset($payload['name'])) { + if (isset($payload['name'])) { $former_selection_plan = $summit->getSelectionPlanByName($payload['name']); if (!is_null($former_selection_plan) && $former_selection_plan->getId() != $selection_plan_id) { throw new ValidationException(trans( @@ -107,12 +107,9 @@ final class SummitSelectionPlanService } SummitSelectionPlanFactory::populate($selection_plan, $payload, $summit); - - // validate selection plan + // check conflict on current summits ( selections plans can not conflict inside summit) $summit->checkSelectionPlanConflicts($selection_plan); - foreach($this->summit_repository->getCurrentAndFutureSummits() as $cur_summit){ - $cur_summit->checkSelectionPlanConflicts($selection_plan); - } + return $selection_plan; }); } @@ -120,15 +117,15 @@ final class SummitSelectionPlanService /** * @param Summit $summit * @param int $selection_plan_id - * @throws EntityNotFoundException * @return void + * @throws EntityNotFoundException */ public function deleteSelectionPlan(Summit $summit, $selection_plan_id) { - return $this->tx_service->transaction(function() use($summit, $selection_plan_id){ + return $this->tx_service->transaction(function () use ($summit, $selection_plan_id) { $selection_plan = $summit->getSelectionPlanById($selection_plan_id); - if(is_null($selection_plan)) + if (is_null($selection_plan)) throw new EntityNotFoundException(trans ('not_found_errors.SummitSelectionPlanService.deleteSelectionPlan.SelectionPlanNotFound', [ @@ -145,16 +142,16 @@ final class SummitSelectionPlanService * @param Summit $summit * @param int $selection_plan_id * @param int $track_group_id - * @throws EntityNotFoundException - * @throws ValidationException * @return void + * @throws ValidationException + * @throws EntityNotFoundException */ public function addTrackGroupToSelectionPlan(Summit $summit, $selection_plan_id, $track_group_id) { - return $this->tx_service->transaction(function() use($summit, $selection_plan_id, $track_group_id){ + return $this->tx_service->transaction(function () use ($summit, $selection_plan_id, $track_group_id) { $selection_plan = $summit->getSelectionPlanById($selection_plan_id); - if(is_null($selection_plan)) + if (is_null($selection_plan)) throw new EntityNotFoundException(trans ('not_found_errors.SummitSelectionPlanService.addTrackGroupToSelectionPlan.SelectionPlanNotFound', [ @@ -164,12 +161,12 @@ final class SummitSelectionPlanService )); $track_group = $summit->getCategoryGroupById($track_group_id); - if(is_null($track_group)) + if (is_null($track_group)) throw new EntityNotFoundException(trans ('not_found_errors.SummitSelectionPlanService.addTrackGroupToSelectionPlan.TrackGroupNotFound', [ 'track_group_id' => $track_group_id, - 'summit_id' => $summit->getId() + 'summit_id' => $summit->getId() ] )); $selection_plan->addTrackGroup($track_group); @@ -180,16 +177,16 @@ final class SummitSelectionPlanService * @param Summit $summit * @param int $selection_plan_id * @param int $track_group_id - * @throws EntityNotFoundException - * @throws ValidationException * @return void + * @throws ValidationException + * @throws EntityNotFoundException */ public function deleteTrackGroupToSelectionPlan(Summit $summit, $selection_plan_id, $track_group_id) { - return $this->tx_service->transaction(function() use($summit, $selection_plan_id, $track_group_id){ + return $this->tx_service->transaction(function () use ($summit, $selection_plan_id, $track_group_id) { $selection_plan = $summit->getSelectionPlanById($selection_plan_id); - if(is_null($selection_plan)) + if (is_null($selection_plan)) throw new EntityNotFoundException(trans ('not_found_errors.SummitSelectionPlanService.deleteTrackGroupToSelectionPlan.SelectionPlanNotFound', [ @@ -199,12 +196,12 @@ final class SummitSelectionPlanService )); $track_group = $summit->getCategoryGroupById($track_group_id); - if(is_null($track_group)) + if (is_null($track_group)) throw new EntityNotFoundException(trans ('not_found_errors.SummitSelectionPlanService.deleteTrackGroupToSelectionPlan.TrackGroupNotFound', [ 'track_group_id' => $track_group_id, - 'summit_id' => $summit->getId() + 'summit_id' => $summit->getId() ] )); $selection_plan->removeTrackGroup($track_group); @@ -212,24 +209,20 @@ final class SummitSelectionPlanService } /** + * @param Summit $summit * @param string $status * @return SelectionPlan|null * @throws \Exception */ - public function getCurrentSelectionPlanByStatus($status) + public function getCurrentSelectionPlanByStatus(Summit $summit, $status) { - return $this->tx_service->transaction(function() use($status) { - // first get current summit plus future summits - $summits = $this->summit_repository->getCurrentAndFutureSummits(); - - foreach($summits as $summit){ - $selection_plan = $summit->getCurrentSelectionPlanByStatus($status); - if(is_null($selection_plan)) continue; - if(!$selection_plan->IsEnabled()) continue; - return $selection_plan; - } - - return null; + return $this->tx_service->transaction(function () use ($summit, $status) { + $selection_plan = $summit->getCurrentSelectionPlanByStatus($status); + if (is_null($selection_plan)) + throw new EntityNotFoundException("Selection Plan not Found"); + if (!$selection_plan->IsEnabled()) + throw new EntityNotFoundException("Selection Plan not Found"); + return $selection_plan; }); } } \ No newline at end of file diff --git a/app/Services/Model/SummitService.php b/app/Services/Model/Imp/SummitService.php similarity index 87% rename from app/Services/Model/SummitService.php rename to app/Services/Model/Imp/SummitService.php index d2795657..7c31c324 100644 --- a/app/Services/Model/SummitService.php +++ b/app/Services/Model/Imp/SummitService.php @@ -21,8 +21,7 @@ use App\Events\RSVPUpdated; use App\Events\SummitDeleted; use App\Events\SummitUpdated; use App\Http\Utils\IFileUploader; -use App\Mail\BookableRoomReservationCanceledEmail; -use App\Mail\Schedule\ShareEventEmail; +use App\Jobs\Emails\Schedule\ShareEventEmail; use App\Models\Foundation\Summit\Factories\SummitEventFeedbackFactory; use App\Models\Foundation\Summit\Factories\SummitFactory; use App\Models\Foundation\Summit\Factories\SummitRSVPFactory; @@ -36,7 +35,6 @@ use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use GuzzleHttp\Exception\ClientException; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Event; -use Illuminate\Support\Facades\Mail; use models\exceptions\EntityNotFoundException; use models\exceptions\ValidationException; use models\main\File; @@ -49,6 +47,7 @@ use Models\foundation\summit\EntityEvents\SummitEntityEventProcessContext; use models\main\Member; use models\main\PersonalCalendarShareInfo; use models\main\Tag; +use models\oauth2\IResourceServerContext; use models\summit\CalendarSync\WorkQueue\AbstractCalendarSyncWorkRequest; use models\summit\CalendarSync\WorkQueue\MemberEventScheduleSummitActionSyncWorkRequest; use models\summit\ConfirmationExternalOrderRequest; @@ -186,6 +185,11 @@ final class SummitService extends AbstractService implements ISummitService */ private $file_uploader; + /** + * @var IResourceServerContext + */ + private $resource_server_context; + /** * SummitService constructor. * @param ISummitRepository $summit_repository @@ -205,6 +209,7 @@ final class SummitService extends AbstractService implements ISummitService * @param IDefaultSummitEventTypeRepository $default_event_types_repository * @param IPermissionsManager $permissions_manager * @param IFileUploader $file_uploader + * @param IResourceServerContext $resource_server_context * @param ITransactionService $tx_service */ public function __construct @@ -226,6 +231,7 @@ final class SummitService extends AbstractService implements ISummitService IDefaultSummitEventTypeRepository $default_event_types_repository, IPermissionsManager $permissions_manager, IFileUploader $file_uploader, + IResourceServerContext $resource_server_context, ITransactionService $tx_service ) { @@ -247,6 +253,7 @@ final class SummitService extends AbstractService implements ISummitService $this->default_event_types_repository = $default_event_types_repository; $this->permissions_manager = $permissions_manager; $this->file_uploader = $file_uploader; + $this->resource_server_context = $resource_server_context; } /** @@ -690,7 +697,7 @@ final class SummitService extends AbstractService implements ISummitService return $this->tx_service->transaction(function () use ($summit, $data, $event_id, $current_member) { if (!is_null($current_member) && !$this->permissions_manager->canEditFields($current_member, 'SummitEvent', $data)) { - throw new ValidationException(sprintf("user %s cant set requested summit event fields", $current_member->getId())); + throw new ValidationException(sprintf("user %s cant set requested summit event fields", $current_member->getEmail())); } $event_type = null; @@ -765,6 +772,18 @@ final class SummitService extends AbstractService implements ISummitService $event->setRSVPLink(html_entity_decode(trim($data['rsvp_link']))); } + if (isset($data['streaming_url'])) { + $event->setStreamingUrl(html_entity_decode(trim($data['streaming_url']))); + } + + if (isset($data['etherpad_link'])) { + $event->setEtherpadLink(html_entity_decode(trim($data['etherpad_link']))); + } + + if (isset($data['meeting_url'])) { + $event->setMeetingUrl(html_entity_decode(trim($data['meeting_url']))); + } + if (isset($data['rsvp_template_id'])) { $rsvp_template = $summit->getRSVPTemplateById(intval($data['rsvp_template_id'])); @@ -943,6 +962,19 @@ final class SummitService extends AbstractService implements ISummitService } } + // selection plan + + if (isset($data['selection_plan_id'])) { + $selection_plan_id = intval($data['selection_plan_id']); + $selection_plan = $event->getSummit()->getSelectionPlanById($selection_plan_id); + if (!is_null($selection_plan)) { + $track = $event->getCategory(); + if (!$selection_plan->hasTrack($track)) { + throw new ValidationException(sprintf("Track %s (%s) does not belongs to Selection Plan %s (%s)", $track->getTitle(), $track->getId(), $selection_plan->getName(), $selection_plan->getId())); + } + $event->setSelectionPlan($selection_plan); + } + } } /** @@ -1249,7 +1281,7 @@ final class SummitService extends AbstractService implements ISummitService $attendee->setMember($this->member_repository->getById($request->getMemberId())); $attendee->setSummit($request->getSummit()); $attendee->addTicket($ticket); - + $attendee->updateStatus(); $this->attendee_repository->add($attendee); return $attendee; @@ -1571,11 +1603,12 @@ final class SummitService extends AbstractService implements ISummitService } $summit = SummitFactory::build($data); + // seed default event types foreach ($this->default_event_types_repository->getAll() as $default_event_type) { $summit->addEventType($default_event_type->buildType($summit)); } - + $summit->seedDefaultEmailFlowEvents(); $this->summit_repository->add($summit); return $summit; @@ -1884,6 +1917,8 @@ final class SummitService extends AbstractService implements ISummitService $eventClone->setStartDate($event->getLocalStartDate()); $eventClone->setEndDate($event->getLocalEndDate()); $eventClone->setCategory($event->getCategory()); + $eventClone->setEtherpadLink($event->getEtherpadLink()); + $eventClone->setStreamingUrl($event->getStreamingUrl()); if ($event->hasRSVPTemplate()) { $eventClone->setRSVPTemplate($event->getRSVPTemplate()); @@ -2086,7 +2121,7 @@ final class SummitService extends AbstractService implements ISummitService { return $this->tx_service->transaction(function () use ($summit_id, $file, $max_file_size) { - $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'pdf']; + $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'svg','jfif']; $summit = $this->summit_repository->getById($summit_id); @@ -2095,7 +2130,7 @@ final class SummitService extends AbstractService implements ISummitService } if (!in_array($file->extension(), $allowed_extensions)) { - throw new ValidationException("file does not has a valid extension ('png','jpg','jpeg','gif','pdf')."); + throw new ValidationException(sprintf("file does not has a valid extension (%s).", implode(",", $allowed_extensions))); } if ($file->getSize() > $max_file_size) { @@ -2403,12 +2438,12 @@ final class SummitService extends AbstractService implements ISummitService throw new ValidationException(sprintf("Property event_url is empty.")); } - Mail::send(new ShareEventEmail( + ShareEventEmail::dispatch( trim($data['from']), trim($data['to']), $event_uri, $event - )); + ); }); } @@ -2433,7 +2468,7 @@ final class SummitService extends AbstractService implements ISummitService try { Log::debug(sprintf("SummitService::calculateFeedbackAverageForOngoingSummits processing event %s", $event_id)); $event = $this->event_repository->getById($event_id); - if (is_null($event) || !$event instanceof SummitEvent){ + if (is_null($event) || !$event instanceof SummitEvent) { Log::debug(sprintf("SummitService::calculateFeedbackAverageForOngoingSummits event %s not found", $event_id)); return; } @@ -2450,12 +2485,268 @@ final class SummitService extends AbstractService implements ISummitService $old_avg_rate = $event->getAvgFeedbackRate(); Log::debug(sprintf("SummitService::calculateFeedbackAverageForOngoingSummits new avg rate %s - old avg rate %s - for event id %s", $avg_rate, $old_avg_rate, $event->getId())); $event->setAvgFeedbackRate($avg_rate); - } - catch (Exception $ex){ + } catch (Exception $ex) { Log::error($ex); } }); } } } + + /** + * @inheritDoc + */ + public function enterTo(Summit $summit, Member $current_member, int $event_id): SummitEvent + { + return $this->tx_service->transaction(function () use ($summit, $current_member, $event_id) { + + $event = $summit->getEvent($event_id); + if (is_null($event)) { + throw new EntityNotFoundException(sprintf("Event %s does not belongs to summit %s.", $event_id, $summit->getId())); + } + + if (!$event->isPublished()) { + throw new ValidationException(sprintf("Event %s is not published.", $event->getId())); + } + + $event->enter($current_member); + + return $event; + + }); + } + + /** + * @inheritDoc + */ + public function leaveFrom(Summit $summit, Member $current_member, int $event_id): SummitEvent + { + return $this->tx_service->transaction(function () use ($summit, $current_member, $event_id) { + $event = $summit->getEvent($event_id); + if (is_null($event)) { + throw new EntityNotFoundException(sprintf("Event %s does not belongs to summit %s.", $event_id, $summit->getId())); + } + + if (!$event->isPublished()) { + throw new ValidationException(sprintf("Event %s is not published.", $event->getId())); + } + + $event->leave($current_member); + + return $event; + }); + } + + /** + * @inheritDoc + */ + public function addEventImage(Summit $summit, $event_id, UploadedFile $file, $max_file_size = 10485760) + { + return $this->tx_service->transaction(function () use ($summit, $event_id, $file, $max_file_size) { + + $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'pdf']; + + $event = $summit->getEvent($event_id); + + if (is_null($event) || !$event instanceof SummitEvent) { + throw new EntityNotFoundException('event not found on summit!'); + } + + if (!in_array($file->extension(), $allowed_extensions)) { + throw new ValidationException("file does not has a valid extension ('png','jpg','jpeg','gif','pdf')."); + } + + if ($file->getSize() > $max_file_size) { + throw new ValidationException(sprintf("file exceeds max_file_size (%s MB).", ($max_file_size / 1024) / 1024)); + } + + $file = $this->file_uploader->build($file, 'summit-event-images', true); + $event->setImage($file); + + return $file; + }); + } + + /** + * @inheritDoc + */ + public function removeEventImage(Summit $summit, $event_id): void + { + $this->tx_service->transaction(function () use ($summit, $event_id) { + + $event = $summit->getEvent($event_id); + + if (is_null($event) || !$event instanceof SummitEvent) { + throw new EntityNotFoundException('event not found on summit!'); + } + $event->clearImage(); + + }); + } + + /** + * @param int $summit_id + * @param int $days + * @param bool $negative + * @param bool $check_summit_ends + * @throws Exception + */ + public function advanceSummit(int $summit_id, int $days, bool $negative = false, $check_summit_ends = true):void + { + $interval = new DateInterval(sprintf("P%sD", $days)); + + Log::debug(sprintf("SummitService::advanceSummit summit_id %s days %s negative %s check_summit_ends %s", $summit_id, $days, $negative, $check_summit_ends)); + + $events_ids = $this->tx_service->transaction(function () use ($summit_id, $interval, $negative, $check_summit_ends) { + + $summit = $this->summit_repository->getByIdExclusiveLock($summit_id); + + if(is_null($summit) || !$summit instanceof Summit) + throw new EntityNotFoundException("Summit not found"); + if($check_summit_ends && !$summit->isEnded()) { + Log::debug(sprintf("SummitService::advanceSummit summit %s has not ended !.", $summit_id)); + return []; + } + + // summit period + $summitBeginDate = $summit->getBeginDate(); + $summitEndDate = $summit->getEndDate(); + + if (!is_null($summitBeginDate)) { + Log::debug(sprintf("SummitService::advanceSummit Current Summit begin date for summit %s is %s", $summit_id, $summitBeginDate->format("Ymd His"))); + if($negative){ + $summit->setRawBeginDate(clone $summitBeginDate->sub($interval)); + } + else { + $summit->setRawBeginDate(clone $summitBeginDate->add($interval)); + } + Log::debug(sprintf("SummitService::advanceSummit New Summit begin date for summit %s is %s", $summit_id, $summit->getBeginDate()->format("Ymd His"))); + } + + if (!is_null($summitEndDate)) { + Log::debug(sprintf("SummitService::advanceSummit Current Summit end date for summit %s is %s", $summit_id, $summitEndDate->format("Ymd His"))); + if($negative) { + $summit->setRawEndDate(clone $summitEndDate->sub($interval)); + } + else{ + $summit->setRawEndDate(clone $summitEndDate->add($interval)); + } + Log::debug(sprintf("SummitService::advanceSummit New Summit end date for summit %s is %s", $summit_id, $summit->getEndDate()->format("Ymd His"))); + } + + // registration period + + $summitRegistrationBeginDate = $summit->getRegistrationBeginDate(); + $summitRegistrationEndDate = $summit->getRegistrationEndDate(); + + if(!is_null($summitRegistrationBeginDate)){ + Log::debug(sprintf("SummitService::advanceSummit Current Summit registration begin date for summit %s is %s", $summit_id, $summitRegistrationBeginDate->format("Ymd His"))); + if($negative) { + $summit->setRawRegistrationBeginDate(clone $summitRegistrationBeginDate->add($interval)); + } + else { + $summit->setRawRegistrationBeginDate(clone $summitRegistrationBeginDate->sub($interval)); + } + Log::debug(sprintf("SummitService::advanceSummit New Summit registration begin date for summit %s is %s", $summit_id, $summit->getRegistrationBeginDate()->format("Ymd His"))); + } + + if(!is_null($summitRegistrationEndDate)){ + Log::debug(sprintf("SummitService::advanceSummit Current Summit registration end date for summit %s is %s", $summit_id, $summitRegistrationEndDate->format("Ymd His"))); + $summit->setRawRegistrationEndDate(clone $summitRegistrationEndDate->add($interval)); + Log::debug(sprintf("SummitService::advanceSummit New Summit registration end date for summit %s is %s", $summit_id, $summit->getRegistrationEndDate()->format("Ymd His"))); + } + + // random dates + + $summitReassignTicketTillDate = $summit->getReassignTicketTillDate(); + if(!is_null($summitReassignTicketTillDate)){ + if($negative){ + $summit->setRawReassignTicketTillDate(clone $summitReassignTicketTillDate->sub($interval)); + } + else { + $summit->setRawReassignTicketTillDate(clone $summitReassignTicketTillDate->add($interval)); + } + } + + $summitStartShowingVenuesDate = $summit->getStartShowingVenuesDate(); + if(!is_null($summitStartShowingVenuesDate)){ + if($negative){ + $summit->setRawStartShowingVenuesDate(clone $summitStartShowingVenuesDate->sub($interval)); + } + else { + $summit->setRawStartShowingVenuesDate(clone $summitStartShowingVenuesDate->add($interval)); + } + } + + $summitScheduleDefaultStartDate = $summit->getScheduleDefaultStartDate(); + if(!is_null($summitScheduleDefaultStartDate)){ + if($negative){ + $summit->setRawScheduleDefaultStartDate(clone $summitScheduleDefaultStartDate->sub($interval)); + } + else { + $summit->setRawScheduleDefaultStartDate(clone $summitScheduleDefaultStartDate->add($interval)); + } + } + + $summitBeginAllowBookingDate = $summit->getBeginAllowBookingDate(); + if(!is_null($summitBeginAllowBookingDate)){ + if($negative) { + $summit->setRawBeginAllowBookingDate(clone $summitBeginAllowBookingDate->sub($interval)); + } + else{ + $summit->setRawBeginAllowBookingDate(clone $summitBeginAllowBookingDate->add($interval)); + } + } + + $summitEndAllowBookingDate = $summit->getEndAllowBookingDate(); + if(!is_null($summitEndAllowBookingDate)){ + if($negative) { + $summit->setRawEndAllowBookingDate(clone $summitEndAllowBookingDate->sub($interval)); + } + else{ + $summit->setRawEndAllowBookingDate(clone $summitEndAllowBookingDate->add($interval)); + } + + } + + // schedule + $event_ids = []; + foreach($summit->getPublishedEvents() as $event){ + if(!$event instanceof SummitEvent) continue; + $event_ids[] = $event->getId(); + } + + return $event_ids; + }); + + foreach ($events_ids as $event_id){ + $this->tx_service->transaction(function() use($summit_id, $event_id, $interval, $negative){ + $event = $this->event_repository->getByIdExclusiveLock($event_id); + $eventBeginDate = $event->getStartDate(); + $eventEndDate = $event->getEndDate(); + if(is_null($eventBeginDate) || is_null($eventEndDate)){ + Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s ( has not set dates but is published!), skipping it", $summit_id, $event->getId())); + return; + } + Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s current start date %s", $summit_id, $event->getId(), $eventBeginDate->format("Ymd His"))); + if($negative){ + $event->setRawStartDate(clone $eventBeginDate->sub($interval)); + } + else { + $event->setRawStartDate(clone $eventBeginDate->add($interval)); + } + Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s new start date %s", $summit_id, $event->getId(), $event->getStartDate()->format("Ymd His"))); + + Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s current end date %s", $summit_id, $event->getId(), $eventEndDate->format("Ymd His"))); + if($negative) { + $event->setRawEndDate(clone $eventEndDate->sub($interval)); + } + else{ + $event->setRawEndDate(clone $eventEndDate->add($interval)); + } + Log::debug(sprintf("SummitService::advanceSummit summit id %s event id %s new end date %s", $summit_id, $event->getId(), $event->getEndDate()->format("Ymd His"))); + + }); + } + } } \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitSponsorService.php b/app/Services/Model/Imp/SummitSponsorService.php new file mode 100644 index 00000000..4c8641c9 --- /dev/null +++ b/app/Services/Model/Imp/SummitSponsorService.php @@ -0,0 +1,247 @@ +member_repository = $member_repository; + $this->company_repository = $company_repository; + $this->sponsorship_type_repository = $sponsorship_type_repository; + } + + + /** + * @param Summit $summit + * @param array $payload + * @return Sponsor + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addSponsor(Summit $summit, array $payload): Sponsor + { + return $this->tx_service->transaction(function () use ($summit, $payload) { + $company_id = intval($payload['company_id']); + $sponsorship_id = intval($payload['sponsorship_id']); + $company = $this->company_repository->getById($company_id); + if (is_null($company)) + throw new EntityNotFoundException("company not found"); + $sponsorship_type = $this->sponsorship_type_repository->getById($sponsorship_id); + if (is_null($sponsorship_type)) + throw new EntityNotFoundException("sponsorship type not found"); + + $former_sponsor = $summit->getSummitSponsorByCompany($company); + if (!is_null($former_sponsor)) { + throw new ValidationException("company already is sponsor on summit"); + } + + $payload['company'] = $company; + $payload['sponsorship'] = $sponsorship_type; + $sponsor = SponsorFactory::build($payload); + + $summit->addSummitSponsor($sponsor); + + return $sponsor; + }); + } + + /** + * @param Summit $summit + * @param int $sponsor_id + * @param array $payload + * @return Sponsor + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateSponsor(Summit $summit, int $sponsor_id, array $payload): Sponsor + { + return $this->tx_service->transaction(function () use ($summit, $sponsor_id, $payload) { + $summit_sponsor = $summit->getSummitSponsorById($sponsor_id); + if (is_null($summit_sponsor)) + throw new EntityNotFoundException("sponsor not found"); + $company = null; + $sponsorship_type = null; + + if(isset($payload['company_id'])) { + $company_id = intval($payload['company_id']); + $company = $this->company_repository->getById($company_id); + if (is_null($company)) + throw new EntityNotFoundException("company not found"); + } + + if(isset($payload['sponsorship_id'])) { + $sponsorship_id = intval($payload['sponsorship_id']); + $sponsorship_type = $this->sponsorship_type_repository->getById($sponsorship_id); + if (is_null($sponsorship_type)) + throw new EntityNotFoundException("sponsorship type not found"); + } + + if(!is_null($company)) { + $former_sponsor = $summit->getSummitSponsorByCompany($company); + if (!is_null($former_sponsor) && $former_sponsor->getId() != $sponsor_id) { + throw new ValidationException("company already is sponsor on summit"); + } + } + if(!is_null($company)) + $payload['company'] = $company; + if(!is_null($sponsorship_type)) + $payload['sponsorship'] = $sponsorship_type; + $sponsor = SponsorFactory::populate($summit_sponsor, $payload); + + if (isset($payload['order']) && intval($payload['order']) != $sponsor->getOrder()) { + // request to update order + $summit->recalculateSummitSponsorOrder($sponsor, $payload['order']); + } + + return $sponsor; + }); + } + + /** + * @param Summit $summit + * @param int $sponsor_id + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function deleteSponsor(Summit $summit, int $sponsor_id): void + { + $this->tx_service->transaction(function () use ($summit, $sponsor_id) { + $summit_sponsor = $summit->getSummitSponsorById($sponsor_id); + if (is_null($summit_sponsor)) + throw new EntityNotFoundException("sponsor not found"); + + $summit->removeSummitSponsor($summit_sponsor); + }); + } + + /** + * @param Summit $summit + * @param int $sponsor_id + * @param int $member_id + * @return Sponsor + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addSponsorUser(Summit $summit, int $sponsor_id, int $member_id): Sponsor + { + return $this->tx_service->transaction(function () use ($summit, $sponsor_id, $member_id) { + $summit_sponsor = $summit->getSummitSponsorById($sponsor_id); + + if (is_null($summit_sponsor)) + throw new EntityNotFoundException("sponsor not found"); + + $member = $this->member_repository->getById($member_id); + $current_summit_begin_date = $summit->getBeginDate(); + $current_summit_end_date = $summit->getEndDate(); + + if (is_null($member) || !$member instanceof Member) + throw new EntityNotFoundException("member not found"); + + foreach($member->getSponsorMemberships() as $former_sponsor){ + + $former_summit = $former_sponsor->getSummit(); + $former_summit_begin_date = $former_summit->getBeginDate(); + $former_summit_end_date = $former_summit->getEndDate(); + + // check that current summit does not intersect with a former one + // due a member could be on 2 diff places at same time ... + // (StartA <= EndB) and (EndA >= StartB) + + if($current_summit_begin_date <= $former_summit_end_date && $current_summit_end_date >=$former_summit_begin_date){ + throw new ValidationException + ( + sprintf + ( + "you can not add member %s as sponsor user on summit %s bc its already sponsor user on another concurrent summit (%s)", + $member_id, + $summit->getId(), + $former_summit->getId() + ) + ); + } + } + + $summit_sponsor->addUser($member); + + return $summit_sponsor; + + }); + } + + /** + * @param Summit $summit + * @param int $sponsor_id + * @param int $member_id + * @return Sponsor + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function removeSponsorUser(Summit $summit, int $sponsor_id, int $member_id): Sponsor + { + return $this->tx_service->transaction(function () use ($summit, $sponsor_id, $member_id) { + $summit_sponsor = $summit->getSummitSponsorById($sponsor_id); + if (is_null($summit_sponsor)) + throw new EntityNotFoundException("sponsor not found"); + + $member = $this->member_repository->getById($member_id); + + if (is_null($member)) + throw new EntityNotFoundException("member not found"); + + $summit_sponsor->removeUser($member); + + return $summit_sponsor; + + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/Imp/SummitTaxTypeService.php b/app/Services/Model/Imp/SummitTaxTypeService.php new file mode 100644 index 00000000..f5fd7b83 --- /dev/null +++ b/app/Services/Model/Imp/SummitTaxTypeService.php @@ -0,0 +1,172 @@ +repository = $repository; + parent::__construct($tx_service); + } + + + /** + * @param Summit $summit + * @param array $data + * @return SummitTaxType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addTaxType(Summit $summit, array $data): SummitTaxType + { + return $this->tx_service->transaction(function() use($summit, $data){ + $name = trim($data['name']); + + $former_tax = $summit->getTaxTypeByName($name); + + if(!is_null($former_tax)) throw new ValidationException("there is another tax type with same name!"); + + $tax_type = SummitTaxTypeFactory::build($data); + + $summit->addTaxType($tax_type); + + return $tax_type; + }); + } + + /** + * @param Summit $summit + * @param int $tax_type_id + * @param array $data + * @return SummitTicketType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function updateTaxType(Summit $summit, int $tax_type_id, array $data): SummitTaxType + { + return $this->tx_service->transaction(function() use($summit, $tax_type_id, $data){ + + $tax_type = $summit->getTaxTypeById($tax_type_id); + if(is_null($tax_type)) + throw new EntityNotFoundException(); + + if(isset($data['name'])) { + $name = trim($data['name']); + + $former_tax = $summit->getTaxTypeByName($name); + + if (!is_null($former_tax)) throw new ValidationException("there is another tax type with same name!"); + } + + return SummitTaxTypeFactory::populate($tax_type, $data); + + }); + } + + /** + * @param Summit $summit + * @param int $tax_type + * @return void + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function deleteTaxType(Summit $summit, int $tax_type_id) + { + $this->tx_service->transaction(function() use($summit, $tax_type_id){ + $tax_type = $summit->getTaxTypeById($tax_type_id); + if(is_null($tax_type)) + throw new EntityNotFoundException(); + + $summit->removeTaxType($tax_type); + }); + } + + /** + * @param Summit $summit + * @param int $tax_type_id + * @param int $ticket_type_id + * @return SummitTaxType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addTaxTypeToTicketType(Summit $summit, int $tax_type_id, int $ticket_type_id): SummitTaxType + { + return $this->tx_service->transaction(function() use($summit, $tax_type_id, $ticket_type_id){ + $tax_type = $summit->getTaxTypeById($tax_type_id); + if(is_null($tax_type)) + throw new EntityNotFoundException(); + + $ticket_type = $summit->getTicketTypeById($ticket_type_id); + if(is_null($ticket_type)) + throw new EntityNotFoundException(); + + $tax_type->addTicketType($ticket_type); + + return $tax_type; + }); + } + + /** + * @param Summit $summit + * @param int $tax_type_id + * @param int $ticket_type_id + * @return SummitTaxType + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function removeTaxTypeFromTicketType(Summit $summit, int $tax_type_id, int $ticket_type_id): SummitTaxType + { + return $this->tx_service->transaction(function() use($summit, $tax_type_id, $ticket_type_id){ + $tax_type = $summit->getTaxTypeById($tax_type_id); + if(is_null($tax_type)) + throw new EntityNotFoundException(); + + $ticket_type = $summit->getTicketTypeById($ticket_type_id); + if(is_null($ticket_type)) + throw new EntityNotFoundException(); + + $tax_type->removeTicketType($ticket_type); + + return $tax_type; + }); + } +} \ No newline at end of file diff --git a/app/Services/Model/SummitTicketTypeService.php b/app/Services/Model/Imp/SummitTicketTypeService.php similarity index 80% rename from app/Services/Model/SummitTicketTypeService.php rename to app/Services/Model/Imp/SummitTicketTypeService.php index 17230653..580deb13 100644 --- a/app/Services/Model/SummitTicketTypeService.php +++ b/app/Services/Model/Imp/SummitTicketTypeService.php @@ -60,6 +60,22 @@ final class SummitTicketTypeService $this->eventbrite_api = $eventbrite_api; } + + /** + * @param Summit $summit + * @param array $data + * @return array + * @throws EntityNotFoundException + */ + static private function getPromoCodeParams(Summit $summit, array $data):array{ + if(isset($data['badge_type_id'])){ + $badge_type = $summit->getBadgeTypeById(intval($data['badge_type_id'])); + if(is_null($badge_type)) + throw new EntityNotFoundException(sprintf("badge_type_id %s not found", $data['badge_type_id'])); + $data['badge_type'] = $badge_type; + } + return $data; + } /** * @param Summit $summit * @param array $data @@ -87,22 +103,32 @@ final class SummitTicketTypeService ); } - $former_ticket_type = $summit->getTicketTypeByExternalId(trim($data['external_id'])); - if(!is_null($former_ticket_type)){ - throw new ValidationException - ( - trans + if(isset($data['external_id'])) { + $former_ticket_type = $summit->getTicketTypeByExternalId(trim($data['external_id'])); + if (!is_null($former_ticket_type)) { + throw new ValidationException ( - 'validation_errors.SummitTicketTypeService.addTicketType.ExternalIdAlreadyExists' - ), - [ - 'external_id' => trim($data['external_id']), - 'summit_id' => $summit->getId() - ] - ); + trans + ( + 'validation_errors.SummitTicketTypeService.addTicketType.ExternalIdAlreadyExists' + ), + [ + 'external_id' => trim($data['external_id']), + 'summit_id' => $summit->getId() + ] + ); + } } - $ticket_type = SummitTicketTypeFactory::build($data); + $ticket_type = SummitTicketTypeFactory::build($summit, self::getPromoCodeParams($summit, $data)); + + if($summit->hasTicketTypes()){ + // before add check if we have the same currency + $currency = $ticket_type->getCurrency(); + $summit_currency = $summit->getDefaultTicketTypeCurrency(); + if(!empty($currency) && !empty($summit_currency) && $summit_currency != $currency) + throw new ValidationException(sprintf("ticket type should have same currency as summit (%s)", $summit_currency)); + } $summit->addTicketType($ticket_type); return $ticket_type; @@ -184,7 +210,12 @@ final class SummitTicketTypeService ); } - $ticket_type = SummitTicketTypeFactory::populate($ticket_type, $data); + $summit_currency = $summit->getDefaultTicketTypeCurrency(); + $currency = $ticket_type->getCurrency(); + if(!empty($currency) && !empty($summit_currency) && $summit_currency != $currency) + throw new ValidationException(sprintf("ticket type should have same currency as summit (%s)", $summit_currency)); + + $ticket_type = SummitTicketTypeFactory::populate($ticket_type, self::getPromoCodeParams($summit, $data)); Event::fire ( diff --git a/app/Services/Model/SummitTrackService.php b/app/Services/Model/Imp/SummitTrackService.php similarity index 99% rename from app/Services/Model/SummitTrackService.php rename to app/Services/Model/Imp/SummitTrackService.php index 4a26ad17..747b6ce6 100644 --- a/app/Services/Model/SummitTrackService.php +++ b/app/Services/Model/Imp/SummitTrackService.php @@ -234,6 +234,7 @@ final class SummitTrackService $data = [ 'name' => $track_2_copy->getTitle(), 'code' => $track_2_copy->getCode(), + 'color' => $track_2_copy->getColor(), 'description' => $track_2_copy->getDescription(), 'session_count' => $track_2_copy->getSessionCount(), 'alternate_count' => $track_2_copy->getAlternateCount(), diff --git a/app/Services/Model/SummitTrackTagGroupService.php b/app/Services/Model/Imp/SummitTrackTagGroupService.php similarity index 100% rename from app/Services/Model/SummitTrackTagGroupService.php rename to app/Services/Model/Imp/SummitTrackTagGroupService.php diff --git a/app/Services/Model/TagService.php b/app/Services/Model/Imp/TagService.php similarity index 100% rename from app/Services/Model/TagService.php rename to app/Services/Model/Imp/TagService.php diff --git a/app/Services/Model/TrackQuestionTemplateService.php b/app/Services/Model/Imp/TrackQuestionTemplateService.php similarity index 100% rename from app/Services/Model/TrackQuestionTemplateService.php rename to app/Services/Model/Imp/TrackQuestionTemplateService.php diff --git a/app/Services/Model/MemberService.php b/app/Services/Model/MemberService.php deleted file mode 100644 index 428c0f8d..00000000 --- a/app/Services/Model/MemberService.php +++ /dev/null @@ -1,229 +0,0 @@ -organization_repository = $organization_repository; - $this->member_repository = $member_repository; - } - - /** - * @param Member $member - * @param int $affiliation_id - * @param array $data - * @return Affiliation - */ - public function updateAffiliation(Member $member, $affiliation_id, array $data) - { - return $this->tx_service->transaction(function() use($member, $affiliation_id, $data){ - $affiliation = $member->getAffiliationById($affiliation_id); - if(is_null($affiliation)) - throw new EntityNotFoundException(sprintf("affiliation id %s does not belongs to member id %s", $affiliation_id, $member->getId())); - - if(isset($data['is_current'])) { - $affiliation->setIsCurrent(boolval($data['is_current'])); - } - - if(isset($data['start_date'])) { - $start_date = intval($data['start_date']); - $affiliation->setStartDate(new DateTime("@$start_date")); - } - - if(!$affiliation->isCurrent() && isset($data['end_date'])) { - $end_date = intval($data['end_date']); - $affiliation->setEndDate($end_date > 0 ? new DateTime("@$end_date") : null); - } - - if(isset($data['organization_id'])) { - $org = $this->organization_repository->getById(intval($data['organization_id'])); - if(is_null($org)) - throw new EntityNotFoundException(sprintf("organization id %s not found", $data['organization_id'])); - $affiliation->setOrganization($org); - } - - if(isset($data['organization_name'])) { - $org = $this->organization_repository->getByName(trim($data['organization_name'])); - if(is_null($org)){ - $org = new Organization(); - $org->setName(trim($data['organization_name'])); - $this->organization_repository->add($org); - } - - $affiliation->setOrganization($org); - } - - if(isset($data['job_title'])) { - $affiliation->setJobTitle(trim($data['job_title'])); - } - - if($affiliation->isCurrent()){ - $affiliation->clearEndDate(); - } - - return $affiliation; - }); - } - - /** - * @param Member $member - * @param $affiliation_id - * @return void - */ - public function deleteAffiliation(Member $member, $affiliation_id) - { - return $this->tx_service->transaction(function() use($member, $affiliation_id){ - $affiliation = $member->getAffiliationById($affiliation_id); - if(is_null($affiliation)) - throw new EntityNotFoundException(sprintf("affiliation id %s does not belongs to member id %s", $affiliation_id, $member->getId())); - - $member->removeAffiliation($affiliation); - }); - } - - /** - * @param Member $member - * @param int $rsvp_id - * @return void - */ - public function deleteRSVP(Member $member, $rsvp_id) - { - return $this->tx_service->transaction(function() use($member, $rsvp_id){ - $rsvp = $member->getRsvpById($rsvp_id); - if(is_null($rsvp)) - throw new EntityNotFoundException(sprintf("rsvp id %s does not belongs to member id %s", $rsvp_id, $member->getId())); - - $member->removeRsvp($rsvp); - }); - } - - /** - * @param Member $member - * @param array $data - * @return Affiliation - */ - public function addAffiliation(Member $member, array $data) - { - return $this->tx_service->transaction(function() use($member, $data){ - - $affiliation = new Affiliation(); - - if(isset($data['is_current'])) - $affiliation->setIsCurrent(boolval($data['is_current'])); - if(isset($data['start_date'])) { - $start_date = intval($data['start_date']); - $affiliation->setStartDate(new DateTime("@$start_date")); - } - if(isset($data['end_date'])) { - $end_date = intval($data['end_date']); - $affiliation->setEndDate($end_date > 0 ? new DateTime("@$end_date") : null); - } - - if(isset($data['organization_id'])) { - $org = $this->organization_repository->getById(intval($data['organization_id'])); - if(is_null($org)) - throw new EntityNotFoundException(sprintf("organization id %s not found", $data['organization_id'])); - $affiliation->setOrganization($org); - } - - if(isset($data['organization_name'])) { - $org = $this->organization_repository->getByName(trim($data['organization_name'])); - if(is_null($org)){ - $org = new Organization(); - $org->setName(trim($data['organization_name'])); - $this->organization_repository->add($org); - } - - $affiliation->setOrganization($org); - } - - if(isset($data['job_title'])) { - $affiliation->setJobTitle(trim($data['job_title'])); - } - - if($affiliation->isCurrent() && $affiliation->getEndDate() != null) - throw new ValidationException - ( - sprintf - ( - "in order to set affiliation as current end_date should be null" - ) - ); - - $member->addAffiliation($affiliation); - return $affiliation; - }); - } - - /** - * @param $user_external_id - * @param string $email - * @param string $first_name - * @param string $last_name - * @return Member - */ - public function registerExternalUser($user_external_id, string $email, string $first_name, string $last_name): Member - { - return $this->tx_service->transaction(function() use($user_external_id, $email, $first_name, $last_name){ - Log::debug(sprintf("MemberService::registerExternalUser - user_external_id %s email %s first_name %s last_name %s", $user_external_id, $email, $first_name, $last_name)); - $member = new Member(); - $member->setEmail($email); - $member->setFirstName($first_name); - $member->setLastName($last_name); - $member->setUserExternalId($user_external_id); - $this->member_repository->add($member, true); - //Event::fire(new NewMember($member->getId())); - return $member; - }); - } -} \ No newline at end of file diff --git a/app/Services/ModelServicesProvider.php b/app/Services/ModelServicesProvider.php new file mode 100644 index 00000000..51e09846 --- /dev/null +++ b/app/Services/ModelServicesProvider.php @@ -0,0 +1,441 @@ +needs(ICalendarSyncWorkRequestQueueManager::class) + ->give(MemberScheduleWorkQueueManager::class); + + App::when(AdminActionsCalendarSyncPreProcessor::class) + ->needs(ICalendarSyncWorkRequestQueueManager::class) + ->give(AdminScheduleWorkQueueManager::class); + + // work request process services + + App::when(MemberActionsCalendarSyncProcessingService::class) + ->needs(ICalendarSyncWorkRequestPreProcessor::class) + ->give(MemberActionsCalendarSyncPreProcessor::class); + + App::singleton + ( + IMemberActionsCalendarSyncProcessingService::class, + MemberActionsCalendarSyncProcessingService::class + ); + + App::when(AdminActionsCalendarSyncProcessingService::class) + ->needs(ICalendarSyncWorkRequestPreProcessor::class) + ->give(AdminActionsCalendarSyncPreProcessor::class); + + App::singleton + ( + IAdminActionsCalendarSyncProcessingService::class, + AdminActionsCalendarSyncProcessingService::class + ); + + App::singleton( + IMemberService::class, + MemberService::class + ); + + App::singleton + ( + ISummitPromoCodeService::class, + SummitPromoCodeService::class + ); + + App::singleton + ( + ISummitEventTypeService::class, + SummitEventTypeService::class + ); + + App::singleton + ( + ISummitTrackService::class, + SummitTrackService::class + ); + + App::singleton + ( + ILocationService::class, + SummitLocationService::class + ); + + App::singleton + ( + IRSVPTemplateService::class, + RSVPTemplateService::class + ); + + App::singleton + ( + ISummitTicketTypeService::class, + SummitTicketTypeService::class + ); + + App::singleton + ( + IPresentationCategoryGroupService::class, + PresentationCategoryGroupService::class + ); + + App::singleton( + ISummitPushNotificationService::class, + SummitPushNotificationService::class + ); + + App::singleton( + ISummitSelectionPlanService::class, + SummitSelectionPlanService::class + ); + + App::singleton( + IOrganizationService::class, + OrganizationService::class + ); + + App::singleton( + ICompanyService::class, + CompanyService::class + ); + + App::singleton( + ISummitTrackTagGroupService::class, + SummitTrackTagGroupService::class + ); + + App::singleton( + ITrackQuestionTemplateService::class, + TrackQuestionTemplateService::class + ); + + App::singleton( + ITagService::class, + TagService::class + ); + + App::singleton( + IExternalScheduleFeedFactory::class, + ExternalScheduleFeedFactory::class + ); + + App::singleton( + IScheduleIngestionService::class, + ScheduleIngestionService::class + ); + + App::singleton + ( + ISummitAccessLevelTypeService::class, + SummitAccessLevelTypeService::class + ); + + App::singleton + ( + ISummitTaxTypeService::class, + SummitTaxTypeService::class + ); + + App::singleton + ( + ISummitBadgeFeatureTypeService::class, + SummitBadgeFeatureTypeService::class + ); + + App::singleton + ( + ISummitBadgeTypeService::class, + SummitBadgeTypeService::class + ); + + App::singleton( + ISummitSponsorService::class, + SummitSponsorService::class + ); + + App::singleton( + ISummitRefundPolicyTypeService::class, + SummitRefundPolicyTypeService::class + ); + + App::singleton( + ISummitOrderExtraQuestionTypeService::class, + SummitOrderExtraQuestionTypeService::class + ); + + App::singleton( + ISponsorshipTypeService::class, + SponsorshipTypeService::class + ); + + App::singleton(ISummitOrderService::class, SummitOrderService::class); + + App::singleton(ISponsorBadgeScanService::class, SponsorBadgeScanService::class); + + App::singleton( + IRegistrationIngestionService::class, + RegistrationIngestionService::class + ); + + App::singleton( + IExternalRegistrationFeedFactory::class, + ExternalRegistrationFeedFactory::class + ); + + App::singleton( + IPaymentGatewayProfileService::class, + PaymentGatewayProfileService::class + ); + + App::singleton( + IBuildDefaultPaymentGatewayProfileStrategy::class, + BuildDefaultPaymentGatewayProfileStrategy::class + ); + + App::singleton( + ISummitEmailEventFlowService::class, + SummitEmailEventFlowService::class + ); + + App::singleton( + ISummitDocumentService::class, + SummitDocumentService::class + ); + + App::singleton + ( + ISummitRegistrationInvitationService::class, + SummitRegistrationInvitationService::class + ); + + App::singleton + ( + ISummitAdministratorPermissionGroupService::class, + SummitAdministratorPermissionGroupService::class + ); + + App::singleton + ( + ISummitMediaFileTypeService::class, + SummitMediaFileTypeService::class + ); + + App::singleton + ( + ISummitMediaUploadTypeService::class, + SummitMediaUploadTypeService::class + ); + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return [ + ISummitService::class, + ISpeakerService::class, + IPresentationService::class, + IChatTeamService::class, + IAttendeeService::class, + ICalendarSyncRemoteFacadeFactory::class, + ICalendarSyncWorkRequestPreProcessorStrategyFactory::class, + ICalendarSyncWorkRequestQueueManager::class, + ICalendarSyncWorkRequestPreProcessor::class, + IMemberActionsCalendarSyncProcessingService::class, + ICalendarSyncWorkRequestPreProcessor::class, + IAdminActionsCalendarSyncProcessingService::class, + IMemberService::class, + ISummitPromoCodeService::class, + ISummitEventTypeService::class, + ISummitTrackService::class, + ILocationService::class, + IRSVPTemplateService::class, + ISummitTicketTypeService::class, + IPresentationCategoryGroupService::class, + ISummitPushNotificationService::class, + ISummitSelectionPlanService::class, + IOrganizationService::class, + ICompanyService::class, + ISummitTrackTagGroupService::class, + ITrackQuestionTemplateService::class, + ITagService::class, + IExternalScheduleFeedFactory::class, + IScheduleIngestionService::class, + ISummitAccessLevelTypeService::class, + ISummitTaxTypeService::class, + ISummitBadgeFeatureTypeService::class, + ISummitBadgeTypeService::class, + ISummitSponsorService::class, + ISummitRefundPolicyTypeService::class, + ISummitOrderExtraQuestionTypeService::class, + ISponsorshipTypeService::class, + ISummitOrderService::class, + ISponsorBadgeScanService::class, + IRegistrationIngestionService::class, + IExternalRegistrationFeedFactory::class, + IPaymentGatewayProfileService::class, + IBuildDefaultPaymentGatewayProfileStrategy::class, + ISummitEmailEventFlowService::class, + ISummitDocumentService::class, + ISummitRegistrationInvitationService::class, + ISummitAdministratorPermissionGroupService::class, + ISummitMediaFileTypeService::class, + ISummitMediaUploadTypeService::class, + ]; + } +} \ No newline at end of file diff --git a/app/Services/ServicesProvider.php b/app/Services/ServicesProvider.php deleted file mode 100644 index 2243e4c0..00000000 --- a/app/Services/ServicesProvider.php +++ /dev/null @@ -1,298 +0,0 @@ -setCredentials(array('token' => Config::get("server.eventbrite_oauth2_personal_token", null))); - return $api; - }); - - App::singleton(IPushNotificationApi::class, function(){ - $api = new FireBaseGCMApi(Config::get("server.firebase_gcm_server_key", null)); - return $api; - }); - - App::singleton(IPaymentGatewayAPI::class, function(){ - return new StripeApi( - Config::get("stripe.private_key", null), - Config::get("stripe.endpoint_secret", null) - ); - }); - - App::singleton - ( - IAttendeeService::class, - AttendeeService::class - ); - - App::singleton - ( - ICalendarSyncRemoteFacadeFactory::class, - CalendarSyncRemoteFacadeFactory::class - ); - - // work request pre processors - - App::singleton - ( - 'App\Services\Model\Strategies\ICalendarSyncWorkRequestPreProcessorStrategyFactory', - 'App\Services\Model\Strategies\CalendarSyncWorkRequestPreProcessorStrategyFactory' - ); - - App::when('App\Services\Model\MemberActionsCalendarSyncPreProcessor') - ->needs('App\Services\Model\ICalendarSyncWorkRequestQueueManager') - ->give('App\Services\Model\MemberScheduleWorkQueueManager'); - - App::when('App\Services\Model\AdminActionsCalendarSyncPreProcessor') - ->needs('App\Services\Model\ICalendarSyncWorkRequestQueueManager') - ->give('App\Services\Model\AdminScheduleWorkQueueManager'); - - // work request process services - - App::when('App\Services\Model\MemberActionsCalendarSyncProcessingService') - ->needs('App\Services\Model\ICalendarSyncWorkRequestPreProcessor') - ->give('App\Services\Model\MemberActionsCalendarSyncPreProcessor'); - - App::singleton - ( - 'App\Services\Model\IMemberActionsCalendarSyncProcessingService', - 'App\Services\Model\MemberActionsCalendarSyncProcessingService' - ); - - App::when('App\Services\Model\AdminActionsCalendarSyncProcessingService') - ->needs('App\Services\Model\ICalendarSyncWorkRequestPreProcessor') - ->give('App\Services\Model\AdminActionsCalendarSyncPreProcessor'); - - App::singleton - ( - 'App\Services\Model\IAdminActionsCalendarSyncProcessingService', - 'App\Services\Model\AdminActionsCalendarSyncProcessingService' - ); - - App::singleton( - IMemberService::class, - MemberService::class - ); - - App::singleton - ( - ISummitPromoCodeService::class, - SummitPromoCodeService::class - ); - - App::singleton - ( - ISummitEventTypeService::class, - SummitEventTypeService::class - ); - - App::singleton - ( - ISummitTrackService::class, - SummitTrackService::class - ); - - App::singleton - ( - ILocationService::class, - SummitLocationService::class - ); - - App::singleton - ( - IFolderService::class, - FolderService::class - ); - - App::singleton - ( - IRSVPTemplateService::class, - RSVPTemplateService::class - ); - - App::singleton - ( - ISummitTicketTypeService::class, - SummitTicketTypeService::class - ); - - App::singleton - ( - IPresentationCategoryGroupService::class, - PresentationCategoryGroupService::class - ); - - App::singleton( - ISummitPushNotificationService::class, - SummitPushNotificationService::class - ); - - App::singleton(IGeoCodingAPI::class, function(){ - return new GoogleGeoCodingAPI - ( - Config::get("server.google_geocoding_api_key", null) - ); - }); - - - App::singleton( - ISummitSelectionPlanService::class, - SummitSelectionPlanService::class - ); - - App::singleton( - IOrganizationService::class, - OrganizationService::class - ); - - App::singleton( - ISummitTrackTagGroupService::class, - SummitTrackTagGroupService::class - ); - - App::singleton( - ITrackQuestionTemplateService::class, - TrackQuestionTemplateService::class - ); - - App::singleton( - ITagService::class, - TagService::class - ); - - App::singleton( - IExternalScheduleFeedFactory::class, - ExternalScheduleFeedFactory::class - ); - - App::singleton( - IScheduleIngestionService::class, - ScheduleIngestionService::class - ); - } -} \ No newline at end of file diff --git a/app/Services/Utils/CSVReader.php b/app/Services/Utils/CSVReader.php new file mode 100644 index 00000000..d199b29a --- /dev/null +++ b/app/Services/Utils/CSVReader.php @@ -0,0 +1,141 @@ +header = $header; + $this->lines = $lines; + } + + /** + * @param string $content + * @return array + */ + public static function buildFrom(string $content):CSVReader + { + $data = str_getcsv($content,"\n" ); + $idx = 0; + $header = []; + foreach($data as $row) + { + $row = str_getcsv($row, ","); + ++$idx; + if($idx === 1) { + + foreach($row as $idx => $val){ + // check the encoding of the header values + if(mb_detect_encoding($val) == 'UTF-8') + $val = iconv('utf-8', 'ascii//TRANSLIT', $val); + $header[] = $val; + } + continue; + } + $line = []; + if(count($row) != count($header)) continue; + for($i = 0; $i < count($header); $i++){ + $line[$header[$i]] = trim($row[$i]); + } + $lines[] = $line; + + } //parse the items in rows + return new CSVReader($header, $lines); + } + + /** + * @param string $colName + * @return bool + */ + public function hasColumn(string $colName):bool { + if(mb_detect_encoding($colName) == 'UTF-8') + $colName = iconv('utf-8', 'ascii//TRANSLIT', $colName); + return in_array(trim($colName), $this->header); + } + + /** + * Return the current element + * @link https://php.net/manual/en/iterator.current.php + * @return mixed Can return any type. + * @since 5.0.0 + */ + public function current() + { + return $this->lines[$this->position]; + } + + /** + * Move forward to next element + * @link https://php.net/manual/en/iterator.next.php + * @return void Any returned value is ignored. + * @since 5.0.0 + */ + public function next() + { + ++$this->position; + } + + /** + * Return the key of the current element + * @link https://php.net/manual/en/iterator.key.php + * @return mixed scalar on success, or null on failure. + * @since 5.0.0 + */ + public function key() + { + return $this->position; + } + + /** + * Checks if current position is valid + * @link https://php.net/manual/en/iterator.valid.php + * @return boolean The return value will be casted to boolean and then evaluated. + * Returns true on success or false on failure. + * @since 5.0.0 + */ + public function valid() + { + return isset($this->lines[$this->position]); + } + + /** + * Rewind the Iterator to the first element + * @link https://php.net/manual/en/iterator.rewind.php + * @return void Any returned value is ignored. + * @since 5.0.0 + */ + public function rewind() + { + $this->position = 0; + } +} \ No newline at end of file diff --git a/app/Services/Utils/DoctrineTransactionService.php b/app/Services/Utils/DoctrineTransactionService.php index 39c09028..527a2730 100644 --- a/app/Services/Utils/DoctrineTransactionService.php +++ b/app/Services/Utils/DoctrineTransactionService.php @@ -92,13 +92,13 @@ final class DoctrineTransactionService implements ITransactionService } } catch (Exception $ex) { Log::warning("rolling back transaction"); + Log::warning($ex); $em->close(); $con->rollBack(); - Log::error($ex); throw $ex; } } return $result; } -} +} \ No newline at end of file diff --git a/app/Services/Utils/IBaseService.php b/app/Services/Utils/IBaseService.php new file mode 100644 index 00000000..65241e38 --- /dev/null +++ b/app/Services/Utils/IBaseService.php @@ -0,0 +1,47 @@ +=5.3.2" }, "require-dev": { - "phpunit/phpunit": "@stable" + "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" }, - "type": "project", + "type": "library", "autoload": { "psr-4": { "XdgBaseDir\\": "src/" @@ -145,34 +192,35 @@ "MIT" ], "description": "implementation of xdg base directory specification for php", - "time": "2014-10-24T07:27:01+00:00" + "time": "2019-12-04T15:06:13+00:00" }, { "name": "doctrine/annotations", - "version": "v1.6.1", + "version": "1.10.3", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "53120e0eb10355388d6ccbe462f1fea34ddadb24" + "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/53120e0eb10355388d6ccbe462f1fea34ddadb24", - "reference": "53120e0eb10355388d6ccbe462f1fea34ddadb24", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/5db60a4969eba0e0c197a19c077780aadbc43c5d", + "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^7.1" + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^7.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.9.x-dev" } }, "autoload": { @@ -185,6 +233,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -193,10 +245,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -213,31 +261,31 @@ "docblock", "parser" ], - "time": "2019-03-25T19:12:02+00:00" + "time": "2020-05-25T17:24:27+00:00" }, { "name": "doctrine/cache", - "version": "v1.8.0", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "d768d58baee9a4862ca783840eca1b9add7a7f57" + "reference": "35a4a70cd94e09e2259dfae7488afc6b474ecbd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/d768d58baee9a4862ca783840eca1b9add7a7f57", - "reference": "d768d58baee9a4862ca783840eca1b9add7a7f57", + "url": "https://api.github.com/repos/doctrine/cache/zipball/35a4a70cd94e09e2259dfae7488afc6b474ecbd3", + "reference": "35a4a70cd94e09e2259dfae7488afc6b474ecbd3", "shasum": "" }, "require": { - "php": "~7.1" + "php": "~7.1 || ^8.0" }, "conflict": { "doctrine/common": ">2.2,<2.4" }, "require-dev": { "alcaeus/mongo-php-adapter": "^1.1", - "doctrine/coding-standard": "^4.0", + "doctrine/coding-standard": "^6.0", "mongodb/mongodb": "^1.1", "phpunit/phpunit": "^7.0", "predis/predis": "~1.0" @@ -248,7 +296,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.9.x-dev" } }, "autoload": { @@ -261,6 +309,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -269,10 +321,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -282,43 +330,45 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Caching library offering an object-oriented API for many cache backends", - "homepage": "https://www.doctrine-project.org", + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", "keywords": [ + "abstraction", + "apcu", "cache", - "caching" + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" ], - "time": "2018-08-21T18:01:43+00:00" + "time": "2020-05-27T16:24:54+00:00" }, { "name": "doctrine/collections", - "version": "v1.6.1", + "version": "1.6.5", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "d2ae4ef05e25197343b6a39bae1d3c427a2f6956" + "reference": "fc0206348e17e530d09463fef07ba8968406cd6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/d2ae4ef05e25197343b6a39bae1d3c427a2f6956", - "reference": "d2ae4ef05e25197343b6a39bae1d3c427a2f6956", + "url": "https://api.github.com/repos/doctrine/collections/zipball/fc0206348e17e530d09463fef07ba8968406cd6d", + "reference": "fc0206348e17e530d09463fef07ba8968406cd6d", "shasum": "" }, "require": { - "php": "^7.1.3" + "php": "^7.1.3 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^6.0", "phpstan/phpstan-shim": "^0.9.2", "phpunit/phpunit": "^7.0", - "vimeo/psalm": "^3.2.2" + "vimeo/psalm": "^3.8.1" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" @@ -329,6 +379,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -337,10 +391,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -358,20 +408,20 @@ "iterators", "php" ], - "time": "2019-03-25T19:03:48+00:00" + "time": "2020-05-25T19:24:35+00:00" }, { "name": "doctrine/common", - "version": "v2.10.0", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "30e33f60f64deec87df728c02b107f82cdafad9d" + "reference": "2053eafdf60c2172ee1373d1b9289ba1db7f1fc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/30e33f60f64deec87df728c02b107f82cdafad9d", - "reference": "30e33f60f64deec87df728c02b107f82cdafad9d", + "url": "https://api.github.com/repos/doctrine/common/zipball/2053eafdf60c2172ee1373d1b9289ba1db7f1fc6", + "reference": "2053eafdf60c2172ee1373d1b9289ba1db7f1fc6", "shasum": "" }, "require": { @@ -387,14 +437,16 @@ }, "require-dev": { "doctrine/coding-standard": "^1.0", - "phpunit/phpunit": "^6.3", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpunit/phpunit": "^7.0", "squizlabs/php_codesniffer": "^3.0", "symfony/phpunit-bridge": "^4.0.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.10.x-dev" + "dev-master": "2.11.x-dev" } }, "autoload": { @@ -407,6 +459,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -415,10 +471,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -439,35 +491,36 @@ "doctrine", "php" ], - "time": "2018-11-21T01:24:55+00:00" + "time": "2020-01-10T15:49:25+00:00" }, { "name": "doctrine/dbal", - "version": "v2.9.2", + "version": "2.10.2", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9" + "reference": "aab745e7b6b2de3b47019da81e7225e14dcfdac8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9", - "reference": "22800bd651c1d8d2a9719e2a3dc46d5108ebfcc9", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/aab745e7b6b2de3b47019da81e7225e14dcfdac8", + "reference": "aab745e7b6b2de3b47019da81e7225e14dcfdac8", "shasum": "" }, "require": { "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0", "ext-pdo": "*", - "php": "^7.1" + "php": "^7.2" }, "require-dev": { - "doctrine/coding-standard": "^5.0", - "jetbrains/phpstorm-stubs": "^2018.1.2", - "phpstan/phpstan": "^0.10.1", - "phpunit/phpunit": "^7.4", - "symfony/console": "^2.0.5|^3.0|^4.0", - "symfony/phpunit-bridge": "^3.4.5|^4.0.5" + "doctrine/coding-standard": "^6.0", + "jetbrains/phpstorm-stubs": "^2019.1", + "nikic/php-parser": "^4.4", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^8.4.1", + "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", + "vimeo/psalm": "^3.11" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -478,7 +531,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.9.x-dev", + "dev-master": "2.10.x-dev", "dev-develop": "3.0.x-dev" } }, @@ -492,6 +545,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -500,10 +557,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -514,27 +567,38 @@ "keywords": [ "abstraction", "database", + "db2", "dbal", + "mariadb", + "mssql", "mysql", - "persistence", + "oci8", + "oracle", + "pdo", "pgsql", - "php", - "queryobject" + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlanywhere", + "sqlite", + "sqlserver", + "sqlsrv" ], - "time": "2018-12-31T03:27:51+00:00" + "time": "2020-04-20T17:19:26+00:00" }, { "name": "doctrine/event-manager", - "version": "v1.0.0", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3" + "reference": "629572819973f13486371cb611386eb17851e85c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/a520bc093a0170feeb6b14e9d83f3a14452e64b3", - "reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/629572819973f13486371cb611386eb17851e85c", + "reference": "629572819973f13486371cb611386eb17851e85c", "shasum": "" }, "require": { @@ -544,7 +608,7 @@ "doctrine/common": "<2.9@dev" }, "require-dev": { - "doctrine/coding-standard": "^4.0", + "doctrine/coding-standard": "^6.0", "phpunit/phpunit": "^7.0" }, "type": "library", @@ -563,6 +627,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -571,10 +639,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -588,44 +652,51 @@ "email": "ocramius@gmail.com" } ], - "description": "Doctrine Event Manager component", + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", "homepage": "https://www.doctrine-project.org/projects/event-manager.html", "keywords": [ "event", - "eventdispatcher", - "eventmanager" + "event dispatcher", + "event manager", + "event system", + "events" ], - "time": "2018-06-11T11:59:03+00:00" + "time": "2019-11-10T09:48:07+00:00" }, { "name": "doctrine/inflector", - "version": "v1.3.0", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "5527a48b7313d15261292c149e55e26eae771b0a" + "reference": "4650c8b30c753a76bf44fb2ed00117d6f367490c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a", - "reference": "5527a48b7313d15261292c149e55e26eae771b0a", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/4650c8b30c753a76bf44fb2ed00117d6f367490c", + "reference": "4650c8b30c753a76bf44fb2ed00117d6f367490c", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "doctrine/coding-standard": "^7.0", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { - "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector", + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" } }, "notification-url": "https://packagist.org/downloads/", @@ -633,6 +704,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -641,10 +716,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -654,32 +725,38 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Common String Manipulations with regard to casing and singular/plural rules.", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", "keywords": [ "inflection", - "pluralize", - "singularize", - "string" + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" ], - "time": "2018-01-09T20:05:19+00:00" + "time": "2020-05-29T07:19:59+00:00" }, { "name": "doctrine/instantiator", - "version": "1.2.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "a2c590166b2133a4633738648b6b064edae0814a" + "reference": "f350df0268e904597e3bd9c4685c53e0e333feea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", - "reference": "a2c590166b2133a4633738648b6b064edae0814a", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea", + "reference": "f350df0268e904597e3bd9c4685c53e0e333feea", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { "doctrine/coding-standard": "^6.0", @@ -718,34 +795,39 @@ "constructor", "instantiate" ], - "time": "2019-03-17T17:37:11+00:00" + "time": "2020-05-29T17:27:14+00:00" }, { "name": "doctrine/lexer", - "version": "v1.0.1", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042", + "reference": "e864bbf5904cb8f5bb334f99209b48018522f042", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" } }, "notification-url": "https://packagist.org/downloads/", @@ -753,26 +835,29 @@ "MIT" ], "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" } ], - "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", "keywords": [ + "annotations", + "docblock", "lexer", - "parser" + "parser", + "php" ], - "time": "2014-09-09T13:34:57+00:00" + "time": "2020-05-25T17:44:05+00:00" }, { "name": "doctrine/migrations", @@ -850,16 +935,16 @@ }, { "name": "doctrine/orm", - "version": "v2.6.3", + "version": "v2.6.4", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "434820973cadf2da2d66e7184be370084cc32ca8" + "reference": "b52ef5a1002f99ab506a5a2d6dba5a2c236c5f43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/434820973cadf2da2d66e7184be370084cc32ca8", - "reference": "434820973cadf2da2d66e7184be370084cc32ca8", + "url": "https://api.github.com/repos/doctrine/orm/zipball/b52ef5a1002f99ab506a5a2d6dba5a2c236c5f43", + "reference": "b52ef5a1002f99ab506a5a2d6dba5a2c236c5f43", "shasum": "" }, "require": { @@ -874,9 +959,8 @@ "symfony/console": "~3.0|~4.0" }, "require-dev": { - "doctrine/coding-standard": "^1.0", - "phpunit/phpunit": "^6.5", - "squizlabs/php_codesniffer": "^3.2", + "doctrine/coding-standard": "^5.0", + "phpunit/phpunit": "^7.5", "symfony/yaml": "~3.4|~4.0" }, "suggest": { @@ -901,6 +985,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -909,10 +997,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -928,20 +1012,20 @@ "database", "orm" ], - "time": "2018-11-20T23:46:46+00:00" + "time": "2019-09-20T14:30:26+00:00" }, { "name": "doctrine/persistence", - "version": "v1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "c0f1c17602afc18b4cbd8e1c8125f264c9cf7d38" + "reference": "3da7c9d125591ca83944f477e65ed3d7b4617c48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/c0f1c17602afc18b4cbd8e1c8125f264c9cf7d38", - "reference": "c0f1c17602afc18b4cbd8e1c8125f264c9cf7d38", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/3da7c9d125591ca83944f477e65ed3d7b4617c48", + "reference": "3da7c9d125591ca83944f477e65ed3d7b4617c48", "shasum": "" }, "require": { @@ -1010,20 +1094,20 @@ "orm", "persistence" ], - "time": "2018-11-21T00:33:13+00:00" + "time": "2019-04-23T08:28:24+00:00" }, { "name": "doctrine/reflection", - "version": "v1.0.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/reflection.git", - "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6" + "reference": "55e71912dfcd824b2fdd16f2d9afe15684cfce79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/reflection/zipball/02538d3f95e88eb397a5f86274deb2c6175c2ab6", - "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6", + "url": "https://api.github.com/repos/doctrine/reflection/zipball/55e71912dfcd824b2fdd16f2d9afe15684cfce79", + "reference": "55e71912dfcd824b2fdd16f2d9afe15684cfce79", "shasum": "" }, "require": { @@ -1031,18 +1115,20 @@ "ext-tokenizer": "*", "php": "^7.1" }, + "conflict": { + "doctrine/common": "<2.9" + }, "require-dev": { - "doctrine/coding-standard": "^4.0", - "doctrine/common": "^2.8", - "phpstan/phpstan": "^0.9.2", - "phpstan/phpstan-phpunit": "^0.9.4", - "phpunit/phpunit": "^7.0", - "squizlabs/php_codesniffer": "^3.0" + "doctrine/coding-standard": "^5.0", + "doctrine/common": "^2.10", + "phpstan/phpstan": "^0.11.0", + "phpstan/phpstan-phpunit": "^0.11.0", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1055,6 +1141,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -1063,10 +1153,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -1080,12 +1166,13 @@ "email": "ocramius@gmail.com" } ], - "description": "Doctrine Reflection component", + "description": "The Doctrine Reflection project is a simple library used by the various Doctrine projects which adds some additional functionality on top of the reflection functionality that comes with PHP. It allows you to get the reflection information about classes, methods and properties statically.", "homepage": "https://www.doctrine-project.org/projects/reflection.html", "keywords": [ - "reflection" + "reflection", + "static" ], - "time": "2018-06-14T14:45:07+00:00" + "time": "2020-03-27T11:06:43+00:00" }, { "name": "dragonmantank/cron-expression", @@ -1143,25 +1230,26 @@ }, { "name": "egulias/email-validator", - "version": "2.1.7", + "version": "2.1.18", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e" + "reference": "cfa3d44471c7f5bfb684ac2b0da7114283d78441" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/709f21f92707308cdf8f9bcfa1af4cb26586521e", - "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/cfa3d44471c7f5bfb684ac2b0da7114283d78441", + "reference": "cfa3d44471c7f5bfb684ac2b0da7114283d78441", "shasum": "" }, "require": { "doctrine/lexer": "^1.0.1", - "php": ">= 5.5" + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.10" }, "require-dev": { - "dominicsayers/isemail": "dev-master", - "phpunit/phpunit": "^4.8.35||^5.7||^6.0", + "dominicsayers/isemail": "^3.0.7", + "phpunit/phpunit": "^4.8.36|^7.5.15", "satooshi/php-coveralls": "^1.0.1" }, "suggest": { @@ -1170,12 +1258,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.1.x-dev" } }, "autoload": { "psr-4": { - "Egulias\\EmailValidator\\": "EmailValidator" + "Egulias\\EmailValidator\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1196,7 +1284,7 @@ "validation", "validator" ], - "time": "2018-12-04T22:38:24+00:00" + "time": "2020-06-16T20:11:17+00:00" }, { "name": "eluceo/ical", @@ -1234,13 +1322,13 @@ "authors": [ { "name": "Maciej Łebkowski", - "role": "Contributor", - "email": "m.lebkowski@gmail.com" + "email": "m.lebkowski@gmail.com", + "role": "Contributor" }, { "name": "Markus Poerschke", - "role": "Developer", - "email": "markus@eluceo.de" + "email": "markus@eluceo.de", + "role": "Developer" } ], "description": "The eluceo/iCal package offers a abstraction layer for creating iCalendars. You can easily create iCal files by using PHP object instead of typing your *.ics file by hand. The output will follow RFC 2445 as best as possible.", @@ -1256,16 +1344,16 @@ }, { "name": "erusev/parsedown", - "version": "1.7.3", + "version": "1.7.4", "source": { "type": "git", "url": "https://github.com/erusev/parsedown.git", - "reference": "6d893938171a817f4e9bc9e86f2da1e370b7bcd7" + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/6d893938171a817f4e9bc9e86f2da1e370b7bcd7", - "reference": "6d893938171a817f4e9bc9e86f2da1e370b7bcd7", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", "shasum": "" }, "require": { @@ -1298,7 +1386,7 @@ "markdown", "parser" ], - "time": "2019-03-17T18:48:37+00:00" + "time": "2019-12-30T22:54:17+00:00" }, { "name": "ezyang/htmlpurifier", @@ -1346,25 +1434,25 @@ }, { "name": "fideloper/proxy", - "version": "4.1.0", + "version": "4.4.0", "source": { "type": "git", "url": "https://github.com/fideloper/TrustedProxy.git", - "reference": "177c79a2d1f9970f89ee2fb4c12b429af38b6dfb" + "reference": "9beebf48a1c344ed67c1d36bb1b8709db7c3c1a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/177c79a2d1f9970f89ee2fb4c12b429af38b6dfb", - "reference": "177c79a2d1f9970f89ee2fb4c12b429af38b6dfb", + "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/9beebf48a1c344ed67c1d36bb1b8709db7c3c1a8", + "reference": "9beebf48a1c344ed67c1d36bb1b8709db7c3c1a8", "shasum": "" }, "require": { - "illuminate/contracts": "~5.0", + "illuminate/contracts": "^5.0|^6.0|^7.0|^8.0", "php": ">=5.4.0" }, "require-dev": { - "illuminate/http": "~5.6", - "mockery/mockery": "~1.0", + "illuminate/http": "^5.0|^6.0|^7.0|^8.0", + "mockery/mockery": "^1.0", "phpunit/phpunit": "^6.0" }, "type": "library", @@ -1396,27 +1484,27 @@ "proxy", "trusted proxy" ], - "time": "2019-01-10T14:06:47+00:00" + "time": "2020-06-23T01:36:47+00:00" }, { "name": "firebase/php-jwt", - "version": "v5.0.0", + "version": "v5.2.0", "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", - "reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e" + "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/9984a4d3a32ae7673d6971ea00bae9d0a1abba0e", - "reference": "9984a4d3a32ae7673d6971ea00bae9d0a1abba0e", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/feb0e820b8436873675fd3aca04f3728eb2185cb", + "reference": "feb0e820b8436873675fd3aca04f3728eb2185cb", "shasum": "" }, "require": { "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": " 4.8.35" + "phpunit/phpunit": ">=4.8 <=9" }, "type": "library", "autoload": { @@ -1442,7 +1530,11 @@ ], "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", "homepage": "https://github.com/firebase/php-jwt", - "time": "2017-06-27T22:17:23+00:00" + "keywords": [ + "jwt", + "php" + ], + "time": "2020-03-25T18:49:23+00:00" }, { "name": "glenscott/url-normalizer", @@ -1483,31 +1575,33 @@ }, { "name": "google/apiclient", - "version": "v2.2.2", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client.git", - "reference": "4e0fd83510e579043e10e565528b323b7c2b3c81" + "reference": "9ab9cc07f66e2c7274ea2753f102ae24d1271410" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/4e0fd83510e579043e10e565528b323b7c2b3c81", - "reference": "4e0fd83510e579043e10e565528b323b7c2b3c81", + "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/9ab9cc07f66e2c7274ea2753f102ae24d1271410", + "reference": "9ab9cc07f66e2c7274ea2753f102ae24d1271410", "shasum": "" }, "require": { - "firebase/php-jwt": "~2.0|~3.0|~4.0|~5.0", + "firebase/php-jwt": "~2.0||~3.0||~4.0||~5.0", "google/apiclient-services": "~0.13", - "google/auth": "^1.0", - "guzzlehttp/guzzle": "~5.3.1|~6.0", + "google/auth": "^1.9", + "guzzlehttp/guzzle": "~5.3.1||~6.0", "guzzlehttp/psr7": "^1.2", - "monolog/monolog": "^1.17", + "monolog/monolog": "^1.17|^2.0", "php": ">=5.4", - "phpseclib/phpseclib": "~0.3.10|~2.0" + "phpseclib/phpseclib": "~0.3.10||~2.0" }, "require-dev": { "cache/filesystem-adapter": "^0.3.2", - "phpunit/phpunit": "~4.8.36", + "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", + "phpcompatibility/php-compatibility": "^9.2", + "phpunit/phpunit": "^4.8|^5.0", "squizlabs/php_codesniffer": "~2.3", "symfony/css-selector": "~2.1", "symfony/dom-crawler": "~2.1" @@ -1538,27 +1632,27 @@ "keywords": [ "google" ], - "time": "2018-06-20T15:52:20+00:00" + "time": "2020-05-26T22:29:38+00:00" }, { "name": "google/apiclient-services", - "version": "v0.93", + "version": "v0.139", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "c40ae41ebde3a0f5435ddd855ecbdf04c1783de0" + "reference": "84e99f792cae7bd92b8b54c75b0ad3502d628db6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/c40ae41ebde3a0f5435ddd855ecbdf04c1783de0", - "reference": "c40ae41ebde3a0f5435ddd855ecbdf04c1783de0", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/84e99f792cae7bd92b8b54c75b0ad3502d628db6", + "reference": "84e99f792cae7bd92b8b54c75b0ad3502d628db6", "shasum": "" }, "require": { "php": ">=5.4" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "phpunit/phpunit": "^4.8|^5" }, "type": "library", "autoload": { @@ -1575,20 +1669,20 @@ "keywords": [ "google" ], - "time": "2019-04-06T00:22:58+00:00" + "time": "2020-06-08T00:24:31+00:00" }, { "name": "google/auth", - "version": "v1.4.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-auth-library-php.git", - "reference": "196237248e636a3554a7d9e4dfddeb97f450ab5c" + "reference": "af4abf63988b8c74f589bee1e69ba310d3e43c6c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/196237248e636a3554a7d9e4dfddeb97f450ab5c", - "reference": "196237248e636a3554a7d9e4dfddeb97f450ab5c", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/af4abf63988b8c74f589bee1e69ba310d3e43c6c", + "reference": "af4abf63988b8c74f589bee1e69ba310d3e43c6c", "shasum": "" }, "require": { @@ -1600,10 +1694,15 @@ "psr/http-message": "^1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^1.11", "guzzlehttp/promises": "0.1.1|^1.3", + "kelvinmo/simplejwt": "^0.2.5", + "phpseclib/phpseclib": "^2", "phpunit/phpunit": "^4.8.36|^5.7", - "sebastian/comparator": ">=1.2.3" + "sebastian/comparator": ">=1.2.3", + "squizlabs/php_codesniffer": "^3.5" + }, + "suggest": { + "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2." }, "type": "library", "autoload": { @@ -1622,31 +1721,87 @@ "google", "oauth2" ], - "time": "2018-09-17T20:29:21+00:00" + "time": "2020-05-18T17:02:59+00:00" }, { - "name": "guzzlehttp/guzzle", - "version": "6.3.3", + "name": "graham-campbell/guzzle-factory", + "version": "v3.0.4", "source": { "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + "url": "https://github.com/GrahamCampbell/Guzzle-Factory.git", + "reference": "618cf7220b177c6d9939a36331df937739ffc596" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "url": "https://api.github.com/repos/GrahamCampbell/Guzzle-Factory/zipball/618cf7220b177c6d9939a36331df937739ffc596", + "reference": "618cf7220b177c6d9939a36331df937739ffc596", "shasum": "" }, "require": { + "guzzlehttp/guzzle": "^6.2", + "php": "^7.0|^8.0" + }, + "require-dev": { + "graham-campbell/analyzer": "^2.4", + "phpunit/phpunit": "^6.5|^7.0|^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "GrahamCampbell\\GuzzleFactory\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "graham@alt-three.com" + } + ], + "description": "Provides A Simple Guzzle Factory With Good Defaults", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Guzzle", + "Guzzle Factory", + "Guzzle-Factory", + "http" + ], + "time": "2020-05-02T14:45:48+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.5", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "shasum": "" + }, + "require": { + "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4", - "php": ">=5.5" + "guzzlehttp/psr7": "^1.6.1", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17.0" }, "require-dev": { "ext-curl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" + "psr/log": "^1.1" }, "suggest": { "psr/log": "Required for using the Log middleware" @@ -1654,16 +1809,16 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.3-dev" + "dev-master": "6.5-dev" } }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\": "src/" - } + }, + "files": [ + "src/functions_include.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1687,7 +1842,7 @@ "rest", "web service" ], - "time": "2018-04-22T15:46:56+00:00" + "time": "2020-06-16T21:01:06+00:00" }, { "name": "guzzlehttp/promises", @@ -1742,33 +1897,37 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.5.2", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "9f83dded91781a01c63574e387eaa769be769115" + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115", - "reference": "9f83dded91781a01c63574e387eaa769be769115", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", "shasum": "" }, "require": { "php": ">=5.4.0", "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5" + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { + "ext-zlib": "*", "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -1805,59 +1964,7 @@ "uri", "url" ], - "time": "2018-12-04T20:46:45+00:00" - }, - { - "name": "idct/sftp-client", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/ideaconnect/idct-sftp-client.git", - "reference": "74775640940a53dd43c6e9176f73acdbaced0cea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ideaconnect/idct-sftp-client/zipball/74775640940a53dd43c6e9176f73acdbaced0cea", - "reference": "74775640940a53dd43c6e9176f73acdbaced0cea", - "shasum": "" - }, - "require": { - "ext-ssh2": ">=0.12", - "php": ">=5.4.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.11" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ], - "psr-4": { - "IDCT\\Networking\\Ssh\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bartosz Pachołek", - "role": "lead", - "email": "bartosz@idct.pl" - } - ], - "description": "Library that provides wrapper methods around SSH2 and SFTP to simplify file download/upload over SSH/SCP/SFTP.", - "homepage": "https://github.com/ideaconnect/idct-sftp-client", - "keywords": [ - "idct", - "scp", - "sftp", - "ssh", - "ssh2" - ], - "time": "2018-11-18T12:45:12+00:00" + "time": "2019-07-01T23:21:34+00:00" }, { "name": "jakub-onderka/php-console-color", @@ -1899,6 +2006,7 @@ "email": "jakub.onderka@gmail.com" } ], + "abandoned": "php-parallel-lint/php-console-color", "time": "2018-09-29T17:23:10+00:00" }, { @@ -1945,27 +2053,28 @@ } ], "description": "Highlight PHP code in terminal", + "abandoned": "php-parallel-lint/php-console-highlighter", "time": "2018-09-29T18:48:56+00:00" }, { "name": "justinrainbow/json-schema", - "version": "5.2.8", + "version": "5.2.10", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4" + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/dcb6e1006bb5fd1e392b4daa68932880f37550d4", - "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", + "reference": "2ba9c8c862ecd5510ed16c6340aa9f6eadb4f31b", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20", + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", "json-schema/json-schema-test-suite": "1.2.0", "phpunit/phpunit": "^4.8.35" }, @@ -2011,7 +2120,52 @@ "json", "schema" ], - "time": "2019-01-14T23:55:14+00:00" + "time": "2020-05-27T16:41:55+00:00" + }, + { + "name": "kylekatarnls/update-helper", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/kylekatarnls/update-helper.git", + "reference": "429be50660ed8a196e0798e5939760f168ec8ce9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kylekatarnls/update-helper/zipball/429be50660ed8a196e0798e5939760f168ec8ce9", + "reference": "429be50660ed8a196e0798e5939760f168ec8ce9", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0.0", + "php": ">=5.3.0" + }, + "require-dev": { + "codeclimate/php-test-reporter": "dev-master", + "composer/composer": "2.0.x-dev || ^2.0.0-dev", + "phpunit/phpunit": ">=4.8.35 <6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "UpdateHelper\\ComposerPlugin" + }, + "autoload": { + "psr-0": { + "UpdateHelper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kyle", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Update helper", + "time": "2020-04-07T20:44:10+00:00" }, { "name": "laravel-doctrine/extensions", @@ -2136,16 +2290,16 @@ }, { "name": "laravel-doctrine/orm", - "version": "v1.4.10", + "version": "1.4.18", "source": { "type": "git", "url": "https://github.com/laravel-doctrine/orm.git", - "reference": "7b45d97b8345d532747b8b946c36eb0926018fcc" + "reference": "e3d8692c0c0f1fe1c180afc85e0fab5a185df879" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel-doctrine/orm/zipball/7b45d97b8345d532747b8b946c36eb0926018fcc", - "reference": "7b45d97b8345d532747b8b946c36eb0926018fcc", + "url": "https://api.github.com/repos/laravel-doctrine/orm/zipball/e3d8692c0c0f1fe1c180afc85e0fab5a185df879", + "reference": "e3d8692c0c0f1fe1c180afc85e0fab5a185df879", "shasum": "" }, "require": { @@ -2160,7 +2314,7 @@ "illuminate/validation": "5.5.*|5.6.*|5.7.*|5.8.*", "illuminate/view": "5.5.*|5.6.*|5.7.*|5.8.*", "php": ">=7.0", - "symfony/serializer": "^2.7|~3.0|~4.0" + "symfony/serializer": "^2.7|^3.0|^4.0|^5.0" }, "require-dev": { "barryvdh/laravel-debugbar": "~2.0|~3.0", @@ -2218,20 +2372,20 @@ "laravel", "orm" ], - "time": "2019-03-14T08:26:16+00:00" + "time": "2020-05-17T10:22:40+00:00" }, { "name": "laravel/framework", - "version": "v5.6.39", + "version": "v5.6.40", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "37bb306f516669ab4f888c16003f694313ab299e" + "reference": "5ceadf91f13be89a3338c3d4166a4676272a23bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/37bb306f516669ab4f888c16003f694313ab299e", - "reference": "37bb306f516669ab4f888c16003f694313ab299e", + "url": "https://api.github.com/repos/laravel/framework/zipball/5ceadf91f13be89a3338c3d4166a4676272a23bf", + "reference": "5ceadf91f13be89a3338c3d4166a4676272a23bf", "shasum": "" }, "require": { @@ -2242,7 +2396,7 @@ "ext-openssl": "*", "league/flysystem": "^1.0.8", "monolog/monolog": "~1.12", - "nesbot/carbon": "1.25.*", + "nesbot/carbon": "1.26.*", "php": "^7.1.3", "psr/container": "~1.0", "psr/simple-cache": "^1.0", @@ -2357,26 +2511,26 @@ "framework", "laravel" ], - "time": "2018-10-04T14:50:41+00:00" + "time": "2020-04-14T14:16:50+00:00" }, { "name": "laravel/tinker", - "version": "v1.0.8", + "version": "v1.0.10", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "cafbf598a90acde68985660e79b2b03c5609a405" + "reference": "ad571aacbac1539c30d480908f9d0c9614eaf1a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/cafbf598a90acde68985660e79b2b03c5609a405", - "reference": "cafbf598a90acde68985660e79b2b03c5609a405", + "url": "https://api.github.com/repos/laravel/tinker/zipball/ad571aacbac1539c30d480908f9d0c9614eaf1a7", + "reference": "ad571aacbac1539c30d480908f9d0c9614eaf1a7", "shasum": "" }, "require": { - "illuminate/console": "~5.1", - "illuminate/contracts": "~5.1", - "illuminate/support": "~5.1", + "illuminate/console": "~5.1|^6.0", + "illuminate/contracts": "~5.1|^6.0", + "illuminate/support": "~5.1|^6.0", "php": ">=5.5.9", "psy/psysh": "0.7.*|0.8.*|0.9.*", "symfony/var-dumper": "~3.0|~4.0" @@ -2420,20 +2574,20 @@ "laravel", "psysh" ], - "time": "2018-10-12T19:39:35+00:00" + "time": "2019-08-07T15:10:45+00:00" }, { "name": "league/flysystem", - "version": "1.0.51", + "version": "1.0.69", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "755ba7bf3fb9031e6581d091db84d78275874396" + "reference": "7106f78428a344bc4f643c233a94e48795f10967" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/755ba7bf3fb9031e6581d091db84d78275874396", - "reference": "755ba7bf3fb9031e6581d091db84d78275874396", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/7106f78428a344bc4f643c233a94e48795f10967", + "reference": "7106f78428a344bc4f643c233a94e48795f10967", "shasum": "" }, "require": { @@ -2445,7 +2599,7 @@ }, "require-dev": { "phpspec/phpspec": "^3.4", - "phpunit/phpunit": "^5.7.10" + "phpunit/phpunit": "^5.7.26" }, "suggest": { "ext-fileinfo": "Required for MimeType", @@ -2504,7 +2658,7 @@ "sftp", "storage" ], - "time": "2019-03-30T13:22:34+00:00" + "time": "2020-05-18T15:13:39+00:00" }, { "name": "league/oauth2-client", @@ -2550,14 +2704,14 @@ "authors": [ { "name": "Alex Bilbie", - "role": "Developer", "email": "hello@alexbilbie.com", - "homepage": "http://www.alexbilbie.com" + "homepage": "http://www.alexbilbie.com", + "role": "Developer" }, { "name": "Woody Gilk", - "role": "Contributor", - "homepage": "https://github.com/shadowhand" + "homepage": "https://github.com/shadowhand", + "role": "Contributor" } ], "description": "OAuth 2.0 Client Library", @@ -2575,16 +2729,16 @@ }, { "name": "monolog/monolog", - "version": "1.24.0", + "version": "1.25.4", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" + "reference": "3022efff205e2448b560c833c6fbbf91c3139168" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/3022efff205e2448b560c833c6fbbf91c3139168", + "reference": "3022efff205e2448b560c833c6fbbf91c3139168", "shasum": "" }, "require": { @@ -2598,11 +2752,10 @@ "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", - "jakub-onderka/php-parallel-lint": "0.9", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", + "php-parallel-lint/php-parallel-lint": "^1.0", "phpunit/phpunit": "~4.5", - "phpunit/phpunit-mock-objects": "2.3.0", "ruflin/elastica": ">=0.90 <3.0", "sentry/sentry": "^0.13", "swiftmailer/swiftmailer": "^5.3|^6.0" @@ -2649,39 +2802,42 @@ "logging", "psr-3" ], - "time": "2018-11-05T09:00:11+00:00" + "time": "2020-05-22T07:31:27+00:00" }, { "name": "nesbot/carbon", - "version": "1.25.0", + "version": "1.26.6", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4" + "reference": "c6820f814496d71da7498d423427e6193d1f57c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cbcf13da0b531767e39eb86e9687f5deba9857b4", - "reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/c6820f814496d71da7498d423427e6193d1f57c9", + "reference": "c6820f814496d71da7498d423427e6193d1f57c9", "shasum": "" }, "require": { + "kylekatarnls/update-helper": "^1.1", "php": ">=5.3.9", "symfony/translation": "~2.6 || ~3.0 || ~4.0" }, "require-dev": { + "composer/composer": "^1.2", "friendsofphp/php-cs-fixer": "~2", "phpunit/phpunit": "^4.8.35 || ^5.7" }, + "bin": [ + "bin/upgrade-carbon" + ], "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.23-dev" - } + "update-helper": "Carbon\\Upgrade" }, "autoload": { "psr-4": { - "Carbon\\": "src/Carbon/" + "": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2702,20 +2858,20 @@ "datetime", "time" ], - "time": "2018-03-19T15:50:49+00:00" + "time": "2019-06-03T15:42:58+00:00" }, { "name": "nikic/php-parser", - "version": "v4.2.1", + "version": "v4.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "5221f49a608808c1e4d436df32884cbc1b821ac0" + "reference": "c346bbfafe2ff60680258b631afb730d186ed864" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/5221f49a608808c1e4d436df32884cbc1b821ac0", - "reference": "5221f49a608808c1e4d436df32884cbc1b821ac0", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c346bbfafe2ff60680258b631afb730d186ed864", + "reference": "c346bbfafe2ff60680258b631afb730d186ed864", "shasum": "" }, "require": { @@ -2723,7 +2879,8 @@ "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^6.5 || ^7.0" + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" }, "bin": [ "bin/php-parse" @@ -2731,7 +2888,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -2753,20 +2910,20 @@ "parser", "php" ], - "time": "2019-02-16T20:54:15+00:00" + "time": "2020-07-02T17:12:47+00:00" }, { "name": "ocramius/package-versions", - "version": "1.4.0", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/Ocramius/PackageVersions.git", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb" + "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", - "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", + "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", "shasum": "" }, "require": { @@ -2778,7 +2935,7 @@ "doctrine/coding-standard": "^5.0.1", "ext-zip": "*", "infection/infection": "^0.7.1", - "phpunit/phpunit": "^7.0.0" + "phpunit/phpunit": "^7.5.17" }, "type": "composer-plugin", "extra": { @@ -2803,20 +2960,20 @@ } ], "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "time": "2019-02-21T12:16:21+00:00" + "time": "2019-11-15T16:17:10+00:00" }, { "name": "ocramius/proxy-manager", - "version": "2.2.2", + "version": "2.2.3", "source": { "type": "git", "url": "https://github.com/Ocramius/ProxyManager.git", - "reference": "14b137b06b0f911944132df9d51e445a35920ab1" + "reference": "4d154742e31c35137d5374c998e8f86b54db2e2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/14b137b06b0f911944132df9d51e445a35920ab1", - "reference": "14b137b06b0f911944132df9d51e445a35920ab1", + "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/4d154742e31c35137d5374c998e8f86b54db2e2f", + "reference": "4d154742e31c35137d5374c998e8f86b54db2e2f", "shasum": "" }, "require": { @@ -2873,7 +3030,7 @@ "proxy pattern", "service proxies" ], - "time": "2018-09-27T13:45:01+00:00" + "time": "2019-08-10T08:37:15+00:00" }, { "name": "paragonie/random_compat", @@ -2920,6 +3077,83 @@ ], "time": "2018-07-02T15:55:56+00:00" }, + { + "name": "php-amqplib/php-amqplib", + "version": "v2.11.3", + "source": { + "type": "git", + "url": "https://github.com/php-amqplib/php-amqplib.git", + "reference": "6353c5d2d3021a301914bc6566e695c99cfeb742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/6353c5d2d3021a301914bc6566e695c99cfeb742", + "reference": "6353c5d2d3021a301914bc6566e695c99cfeb742", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-sockets": "*", + "php": ">=5.6.3", + "phpseclib/phpseclib": "^2.0.0" + }, + "conflict": { + "php": "7.4.0 - 7.4.1" + }, + "replace": { + "videlalvaro/php-amqplib": "self.version" + }, + "require-dev": { + "ext-curl": "*", + "nategood/httpful": "^0.2.20", + "phpunit/phpunit": "^5.7|^6.5|^7.0", + "squizlabs/php_codesniffer": "^2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.11-dev" + } + }, + "autoload": { + "psr-4": { + "PhpAmqpLib\\": "PhpAmqpLib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Alvaro Videla", + "role": "Original Maintainer" + }, + { + "name": "Raúl Araya", + "email": "nubeiro@gmail.com", + "role": "Maintainer" + }, + { + "name": "Luke Bakken", + "email": "luke@bakken.io", + "role": "Maintainer" + }, + { + "name": "Ramūnas Dronga", + "email": "github@ramuno.lt", + "role": "Maintainer" + } + ], + "description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.", + "homepage": "https://github.com/php-amqplib/php-amqplib/", + "keywords": [ + "message", + "queue", + "rabbitmq" + ], + "time": "2020-05-13T13:56:11+00:00" + }, { "name": "php-opencloud/openstack", "version": "dev-master", @@ -2993,16 +3227,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "2.0.15", + "version": "2.0.27", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "11cf67cf78dc4acb18dc9149a57be4aee5036ce0" + "reference": "34620af4df7d1988d8f0d7e91f6c8a3bf931d8dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/11cf67cf78dc4acb18dc9149a57be4aee5036ce0", - "reference": "11cf67cf78dc4acb18dc9149a57be4aee5036ce0", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/34620af4df7d1988d8f0d7e91f6c8a3bf931d8dc", + "reference": "34620af4df7d1988d8f0d7e91f6c8a3bf931d8dc", "shasum": "" }, "require": { @@ -3081,7 +3315,7 @@ "x.509", "x509" ], - "time": "2019-03-10T16:53:45+00:00" + "time": "2020-04-04T23:17:33+00:00" }, { "name": "predis/predis", @@ -3280,16 +3514,16 @@ }, { "name": "psr/log", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", "shasum": "" }, "require": { @@ -3298,7 +3532,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -3323,7 +3557,7 @@ "psr", "psr-3" ], - "time": "2018-11-20T15:27:04+00:00" + "time": "2020-03-23T09:12:05+00:00" }, { "name": "psr/simple-cache", @@ -3375,27 +3609,27 @@ }, { "name": "psy/psysh", - "version": "v0.9.9", + "version": "v0.9.12", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "9aaf29575bb8293206bb0420c1e1c87ff2ffa94e" + "reference": "90da7f37568aee36b116a030c5f99c915267edd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/9aaf29575bb8293206bb0420c1e1c87ff2ffa94e", - "reference": "9aaf29575bb8293206bb0420c1e1c87ff2ffa94e", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/90da7f37568aee36b116a030c5f99c915267edd4", + "reference": "90da7f37568aee36b116a030c5f99c915267edd4", "shasum": "" }, "require": { - "dnoegel/php-xdg-base-dir": "0.1", + "dnoegel/php-xdg-base-dir": "0.1.*", "ext-json": "*", "ext-tokenizer": "*", "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", "nikic/php-parser": "~1.3|~2.0|~3.0|~4.0", "php": ">=5.4.0", - "symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0", - "symfony/var-dumper": "~2.7|~3.0|~4.0" + "symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0|~5.0", + "symfony/var-dumper": "~2.7|~3.0|~4.0|~5.0" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.2", @@ -3445,28 +3679,28 @@ "interactive", "shell" ], - "time": "2018-10-13T15:16:03+00:00" + "time": "2019-12-06T14:19:43+00:00" }, { "name": "ralouphie/getallheaders", - "version": "2.0.5", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa" + "reference": "120b605dfeb996808c31b6477290a714d356e822" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa", - "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", "shasum": "" }, "require": { - "php": ">=5.3" + "php": ">=5.6" }, "require-dev": { - "phpunit/phpunit": "~3.7.0", - "satooshi/php-coveralls": ">=1.0" + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" }, "type": "library", "autoload": { @@ -3485,48 +3719,50 @@ } ], "description": "A polyfill for getallheaders.", - "time": "2016-02-11T07:05:27+00:00" + "time": "2019-03-08T08:55:37+00:00" }, { "name": "ramsey/uuid", - "version": "3.8.0", + "version": "3.9.3", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3" + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/d09ea80159c1929d75b3f9c60504d613aeb4a1e3", - "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/7e1633a6964b48589b142d60542f9ed31bd37a92", + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92", "shasum": "" }, "require": { - "paragonie/random_compat": "^1.0|^2.0|9.99.99", - "php": "^5.4 || ^7.0", + "ext-json": "*", + "paragonie/random_compat": "^1 | ^2 | 9.99.99", + "php": "^5.4 | ^7 | ^8", "symfony/polyfill-ctype": "^1.8" }, "replace": { "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^1.0 | ~2.0.0", - "doctrine/annotations": "~1.2.0", - "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0", - "ircmaxell/random-lib": "^1.1", - "jakub-onderka/php-parallel-lint": "^0.9.0", - "mockery/mockery": "^0.9.9", + "codeception/aspect-mock": "^1 | ^2", + "doctrine/annotations": "^1.2", + "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1", + "jakub-onderka/php-parallel-lint": "^1", + "mockery/mockery": "^0.9.11 | ^1", "moontoast/math": "^1.1", - "php-mock/php-mock-phpunit": "^0.3|^1.1", - "phpunit/phpunit": "^4.7|^5.0|^6.5", - "squizlabs/php_codesniffer": "^2.3" + "paragonie/random-lib": "^2", + "php-mock/php-mock-phpunit": "^0.3 | ^1.1", + "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5", + "squizlabs/php_codesniffer": "^3.5" }, "suggest": { "ext-ctype": "Provides support for PHP Ctype functions", "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator", "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", - "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." }, @@ -3539,13 +3775,21 @@ "autoload": { "psr-4": { "Ramsey\\Uuid\\": "src/" - } + }, + "files": [ + "src/functions.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + }, { "name": "Marijn Huizendveld", "email": "marijn.huizendveld@gmail.com" @@ -3553,11 +3797,6 @@ { "name": "Thibaud Fabre", "email": "thibaud@aztech.io" - }, - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" } ], "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", @@ -3567,29 +3806,29 @@ "identifier", "uuid" ], - "time": "2018-07-19T23:38:55+00:00" + "time": "2020-02-21T04:36:14+00:00" }, { "name": "s-ichikawa/laravel-sendgrid-driver", - "version": "2.0.6", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/s-ichikawa/laravel-sendgrid-driver.git", - "reference": "5092c3f856581bd61b691d7e86ebb9fcb6867683" + "reference": "116a6e624323883ddcc56bfaf92ef19f9218f6fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/s-ichikawa/laravel-sendgrid-driver/zipball/5092c3f856581bd61b691d7e86ebb9fcb6867683", - "reference": "5092c3f856581bd61b691d7e86ebb9fcb6867683", + "url": "https://api.github.com/repos/s-ichikawa/laravel-sendgrid-driver/zipball/116a6e624323883ddcc56bfaf92ef19f9218f6fd", + "reference": "116a6e624323883ddcc56bfaf92ef19f9218f6fd", "shasum": "" }, "require": { "guzzlehttp/guzzle": "~5.3|~6.2", - "illuminate/mail": "~5.5" + "illuminate/mail": ">=5.5" }, "require-dev": { - "illuminate/container": "~5.5", - "illuminate/filesystem": "~5.5", + "illuminate/container": ">=5.5", + "illuminate/filesystem": ">=5.5", "phpunit/phpunit": "~5.7" }, "suggest": { @@ -3623,7 +3862,7 @@ "laravel", "sendgrid" ], - "time": "2019-04-09T14:22:02+00:00" + "time": "2019-09-04T15:31:39+00:00" }, { "name": "sabre/uri", @@ -3662,9 +3901,9 @@ "authors": [ { "name": "Evert Pot", - "role": "Developer", "email": "me@evertpot.com", - "homepage": "http://evertpot.com/" + "homepage": "http://evertpot.com/", + "role": "Developer" } ], "description": "Functions for making sense out of URIs.", @@ -3719,14 +3958,14 @@ "authors": [ { "name": "Evert Pot", - "role": "Developer", "email": "me@evertpot.com", - "homepage": "http://evertpot.com/" + "homepage": "http://evertpot.com/", + "role": "Developer" }, { "name": "Markus Staab", - "role": "Developer", - "email": "markus.staab@redaxo.de" + "email": "markus.staab@redaxo.de", + "role": "Developer" } ], "description": "sabre/xml is an XML library that you may not hate.", @@ -3739,6 +3978,67 @@ ], "time": "2016-10-09T22:57:52+00:00" }, + { + "name": "simplesoftwareio/simple-qrcode", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/SimpleSoftwareIO/simple-qrcode.git", + "reference": "90b2282dd29be1e52565e9832dc23af41610ea07" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SimpleSoftwareIO/simple-qrcode/zipball/90b2282dd29be1e52565e9832dc23af41610ea07", + "reference": "90b2282dd29be1e52565e9832dc23af41610ea07", + "shasum": "" + }, + "require": { + "bacon/bacon-qr-code": "1.0.*", + "ext-gd": "*", + "illuminate/support": ">=5.0.0", + "php": ">=7.0" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "~6" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "SimpleSoftwareIO\\QrCode\\QrCodeServiceProvider" + ], + "aliases": { + "QrCode": "SimpleSoftwareIO\\QrCode\\Facades\\QrCode" + } + } + }, + "autoload": { + "psr-0": { + "SimpleSoftwareIO\\QrCode\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simple Software LLC", + "email": "support@simplesoftware.io" + } + ], + "description": "Simple QrCode is a QR code generator made for Laravel.", + "homepage": "http://www.simplesoftware.io", + "keywords": [ + "Simple", + "generator", + "laravel", + "qrcode", + "wrapper" + ], + "time": "2017-11-26T15:27:12+00:00" + }, { "name": "smarcet/caldavclient", "version": "1.1.6", @@ -3837,17 +4137,175 @@ "time": "2017-08-05T01:36:59+00:00" }, { - "name": "stripe/stripe-php", - "version": "v6.37.0", + "name": "sokil/php-isocodes", + "version": "3.0.5", "source": { "type": "git", - "url": "https://github.com/stripe/stripe-php.git", - "reference": "6915bed0b988ca837f3e15a1f31517a6172a663a" + "url": "https://github.com/sokil/php-isocodes.git", + "reference": "89b1c153afd1e27c48634a06469a4cab27858833" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stripe/stripe-php/zipball/6915bed0b988ca837f3e15a1f31517a6172a663a", - "reference": "6915bed0b988ca837f3e15a1f31517a6172a663a", + "url": "https://api.github.com/repos/sokil/php-isocodes/zipball/89b1c153afd1e27c48634a06469a4cab27858833", + "reference": "89b1c153afd1e27c48634a06469a4cab27858833", + "shasum": "" + }, + "require": { + "ext-gettext": "*", + "ext-json": "*", + "php": ">=7.1" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", + "php-coveralls/php-coveralls": "^2.1", + "phpbench/phpbench": "^0.16.9", + "phpmd/phpmd": "@stable", + "phpunit/phpunit": "^7.0", + "slevomat/coding-standard": "^5.0", + "squizlabs/php_codesniffer": "^3.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Sokil\\IsoCodes\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dmytro Sokil", + "email": "dmytro.sokil@gmail.com" + } + ], + "description": "ISO country, subdivision, language, currency and script definitions and their translations. Based on pythons pycountry and Debian's iso-codes.", + "time": "2020-05-28T22:28:43+00:00" + }, + { + "name": "spatie/dropbox-api", + "version": "1.15.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/dropbox-api.git", + "reference": "0cac9d3b613514cba2fef7b8f00b41a7b9d2b2a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/dropbox-api/zipball/0cac9d3b613514cba2fef7b8f00b41a7b9d2b2a3", + "reference": "0cac9d3b613514cba2fef7b8f00b41a7b9d2b2a3", + "shasum": "" + }, + "require": { + "graham-campbell/guzzle-factory": "^3.0||^4.0", + "guzzlehttp/guzzle": "^6.2||^7.0", + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5.15|^8.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Dropbox\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Vanderbist", + "email": "alex.vanderbist@gmail.com", + "homepage": "https://spatie.be", + "role": "Developer" + }, + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A minimal implementation of Dropbox API v2", + "homepage": "https://github.com/spatie/dropbox-api", + "keywords": [ + "Dropbox-API", + "api", + "dropbox", + "spatie", + "v2" + ], + "time": "2020-07-10T15:17:57+00:00" + }, + { + "name": "spatie/flysystem-dropbox", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/flysystem-dropbox.git", + "reference": "512e8d59b3f9b8a6710f932c421032cb490e9869" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/flysystem-dropbox/zipball/512e8d59b3f9b8a6710f932c421032cb490e9869", + "reference": "512e8d59b3f9b8a6710f932c421032cb490e9869", + "shasum": "" + }, + "require": { + "league/flysystem": "^1.0.20", + "php": "^7.0", + "spatie/dropbox-api": "^1.1.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\FlysystemDropbox\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Vanderbist", + "email": "alex.vanderbist@gmail.com", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Flysystem Adapter for the Dropbox v2 API", + "homepage": "https://github.com/spatie/flysystem-dropbox", + "keywords": [ + "Flysystem", + "api", + "dropbox", + "flysystem-dropbox", + "spatie", + "v2" + ], + "time": "2019-12-04T08:18:17+00:00" + }, + { + "name": "stripe/stripe-php", + "version": "v6.43.1", + "source": { + "type": "git", + "url": "https://github.com/stripe/stripe-php.git", + "reference": "42fcdaf99c44bb26937223f8eae1f263491d5ab8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stripe/stripe-php/zipball/42fcdaf99c44bb26937223f8eae1f263491d5ab8", + "reference": "42fcdaf99c44bb26937223f8eae1f263491d5ab8", "shasum": "" }, "require": { @@ -3890,20 +4348,20 @@ "payment processing", "stripe" ], - "time": "2019-05-23T23:59:23+00:00" + "time": "2019-08-29T16:56:12+00:00" }, { "name": "swiftmailer/swiftmailer", - "version": "v6.2.0", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "6fa3232ff9d3f8237c0fae4b7ff05e1baa4cd707" + "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/6fa3232ff9d3f8237c0fae4b7ff05e1baa4cd707", - "reference": "6fa3232ff9d3f8237c0fae4b7ff05e1baa4cd707", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/149cfdf118b169f7840bbe3ef0d4bc795d1780c9", + "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9", "shasum": "" }, "require": { @@ -3952,29 +4410,33 @@ "mail", "mailer" ], - "time": "2019-03-10T07:52:41+00:00" + "time": "2019-11-12T09:31:26+00:00" }, { "name": "symfony/console", - "version": "v4.2.5", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "24206aff3efe6962593297e57ef697ebb220e384" + "reference": "326b064d804043005526f5a0494cfb49edb59bb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/24206aff3efe6962593297e57ef697ebb220e384", - "reference": "24206aff3efe6962593297e57ef697ebb220e384", + "url": "https://api.github.com/repos/symfony/console/zipball/326b064d804043005526f5a0494cfb49edb59bb0", + "reference": "326b064d804043005526f5a0494cfb49edb59bb0", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/contracts": "^1.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.15", + "symfony/service-contracts": "^1.1|^2" }, "conflict": { "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", "symfony/process": "<3.3" }, "provide": { @@ -3982,11 +4444,12 @@ }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/event-dispatcher": "~3.4|~4.0", - "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" }, "suggest": { "psr/log": "For using the console logger", @@ -3997,7 +4460,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4024,88 +4487,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-04-01T07:32:59+00:00" - }, - { - "name": "symfony/contracts", - "version": "v1.0.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/contracts.git", - "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf", - "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf", - "shasum": "" - }, - "require": { - "php": "^7.1.3" - }, - "require-dev": { - "psr/cache": "^1.0", - "psr/container": "^1.0" - }, - "suggest": { - "psr/cache": "When using the Cache contracts", - "psr/container": "When using the Service contracts", - "symfony/cache-contracts-implementation": "", - "symfony/service-contracts-implementation": "", - "symfony/translation-contracts-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\": "" - }, - "exclude-from-classmap": [ - "**/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A set of abstractions extracted out of the Symfony components", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "time": "2018-12-05T08:06:11+00:00" + "time": "2020-05-30T20:06:45+00:00" }, { "name": "symfony/css-selector", - "version": "v4.2.5", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "48eddf66950fa57996e1be4a55916d65c10c604a" + "reference": "afc26133a6fbdd4f8842e38893e0ee4685c7c94b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/48eddf66950fa57996e1be4a55916d65c10c604a", - "reference": "48eddf66950fa57996e1be4a55916d65c10c604a", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/afc26133a6fbdd4f8842e38893e0ee4685c7c94b", + "reference": "afc26133a6fbdd4f8842e38893e0ee4685c7c94b", "shasum": "" }, "require": { @@ -4114,7 +4509,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4130,14 +4525,14 @@ "MIT" ], "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" @@ -4145,36 +4540,37 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2019-01-16T20:31:39+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/debug", - "version": "v4.2.5", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "43ce8ab34c734dcc8a4af576cb86711daab964c5" + "reference": "28f92d08bb6d1fddf8158e02c194ad43870007e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/43ce8ab34c734dcc8a4af576cb86711daab964c5", - "reference": "43ce8ab34c734dcc8a4af576cb86711daab964c5", + "url": "https://api.github.com/repos/symfony/debug/zipball/28f92d08bb6d1fddf8158e02c194ad43870007e6", + "reference": "28f92d08bb6d1fddf8158e02c194ad43870007e6", "shasum": "" }, "require": { - "php": "^7.1.3", - "psr/log": "~1.0" + "php": ">=7.1.3", + "psr/log": "~1.0", + "symfony/polyfill-php80": "^1.15" }, "conflict": { "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~3.4|~4.0" + "symfony/http-kernel": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4201,35 +4597,98 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2019-03-10T17:09:50+00:00" + "time": "2020-05-24T08:33:35+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v4.2.5", + "name": "symfony/error-handler", + "version": "v4.4.10", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "ca5af306fbc37f3cf597e91bc9cfa0c7d3f33544" + "url": "https://github.com/symfony/error-handler.git", + "reference": "0df9a23c0f9eddbb6682479fee6fd58b88add75b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ca5af306fbc37f3cf597e91bc9cfa0c7d3f33544", - "reference": "ca5af306fbc37f3cf597e91bc9cfa0c7d3f33544", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/0df9a23c0f9eddbb6682479fee6fd58b88add75b", + "reference": "0df9a23c0f9eddbb6682479fee6fd58b88add75b", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/contracts": "^1.0" + "php": ">=7.1.3", + "psr/log": "~1.0", + "symfony/debug": "^4.4.5", + "symfony/polyfill-php80": "^1.15", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ErrorHandler Component", + "homepage": "https://symfony.com", + "time": "2020-05-28T10:39:14+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.10", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "a5370aaa7807c7a439b21386661ffccf3dff2866" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a5370aaa7807c7a439b21386661ffccf3dff2866", + "reference": "a5370aaa7807c7a439b21386661ffccf3dff2866", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { "symfony/dependency-injection": "<3.4" }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/expression-language": "~3.4|~4.0", - "symfony/stopwatch": "~3.4|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/dependency-injection": "", @@ -4238,7 +4697,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4265,20 +4724,78 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2019-03-30T15:58:42+00:00" + "time": "2020-05-20T08:37:50+00:00" }, { - "name": "symfony/finder", - "version": "v4.2.5", + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.7", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/267b7002c1b70ea80db0833c3afe05f0fbde580a", - "reference": "267b7002c1b70ea80db0833c3afe05f0fbde580a", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T09:54:03+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.10", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "5729f943f9854c5781984ed4907bbb817735776b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/5729f943f9854c5781984ed4907bbb817735776b", + "reference": "5729f943f9854c5781984ed4907bbb817735776b", "shasum": "" }, "require": { @@ -4287,7 +4804,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4314,34 +4831,35 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-02-23T15:42:05+00:00" + "time": "2020-03-27T16:54:36+00:00" }, { "name": "symfony/http-foundation", - "version": "v4.2.5", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "5b7ab6beaa5b053b8d3c9b13367ada9b292e12e1" + "reference": "3adfbd7098c850b02d107330b7b9deacf2581578" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5b7ab6beaa5b053b8d3c9b13367ada9b292e12e1", - "reference": "5b7ab6beaa5b053b8d3c9b13367ada9b292e12e1", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3adfbd7098c850b02d107330b7b9deacf2581578", + "reference": "3adfbd7098c850b02d107330b7b9deacf2581578", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { "predis/predis": "~1.0", - "symfony/expression-language": "~3.4|~4.0" + "symfony/expression-language": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4368,36 +4886,38 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2019-03-30T15:58:42+00:00" + "time": "2020-05-23T09:11:46+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.2.5", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "e8b940bbeebf0f96789b5d17d9d77f8b2613960b" + "reference": "81d42148474e1852a333ed7a732f2a014af75430" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e8b940bbeebf0f96789b5d17d9d77f8b2613960b", - "reference": "e8b940bbeebf0f96789b5d17d9d77f8b2613960b", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/81d42148474e1852a333ed7a732f2a014af75430", + "reference": "81d42148474e1852a333ed7a732f2a014af75430", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "psr/log": "~1.0", - "symfony/contracts": "^1.0.2", - "symfony/debug": "~3.4|~4.0", - "symfony/event-dispatcher": "~4.1", - "symfony/http-foundation": "^4.1.1", - "symfony/polyfill-ctype": "~1.8" + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.15" }, "conflict": { + "symfony/browser-kit": "<4.3", "symfony/config": "<3.4", - "symfony/dependency-injection": "<4.2", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", "symfony/translation": "<4.2", - "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" }, "provide": { @@ -4405,32 +4925,32 @@ }, "require-dev": { "psr/cache": "~1.0", - "symfony/browser-kit": "~3.4|~4.0", - "symfony/config": "~3.4|~4.0", - "symfony/console": "~3.4|~4.0", - "symfony/css-selector": "~3.4|~4.0", - "symfony/dependency-injection": "^4.2", - "symfony/dom-crawler": "~3.4|~4.0", - "symfony/expression-language": "~3.4|~4.0", - "symfony/finder": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0", - "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~3.4|~4.0", - "symfony/templating": "~3.4|~4.0", - "symfony/translation": "~4.2", - "symfony/var-dumper": "^4.1.1" + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.34|^2.4|^3.0" }, "suggest": { "symfony/browser-kit": "", "symfony/config": "", "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/var-dumper": "" + "symfony/dependency-injection": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4457,20 +4977,83 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2019-04-02T19:03:51+00:00" + "time": "2020-06-12T11:15:37+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.11.0", + "name": "symfony/mime", + "version": "v5.1.2", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "82ebae02209c21113908c229e9883c419720738a" + "url": "https://github.com/symfony/mime.git", + "reference": "c0c418f05e727606e85b482a8591519c4712cf45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", - "reference": "82ebae02209c21113908c229e9883c419720738a", + "url": "https://api.github.com/repos/symfony/mime/zipball/c0c418f05e727606e85b482a8591519c4712cf45", + "reference": "c0c418f05e727606e85b482a8591519c4712cf45", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10", + "symfony/dependency-injection": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A library to manipulate MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "time": "2020-06-09T15:07:35+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.17.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d", + "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d", "shasum": "" }, "require": { @@ -4482,7 +5065,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -4498,13 +5085,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -4515,20 +5102,20 @@ "polyfill", "portable" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.11.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "f037ea22acfaee983e271dd9c3b8bb4150bd8ad7" + "reference": "ba6c9c18db36235b859cc29b8372d1c01298c035" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/f037ea22acfaee983e271dd9c3b8bb4150bd8ad7", - "reference": "f037ea22acfaee983e271dd9c3b8bb4150bd8ad7", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/ba6c9c18db36235b859cc29b8372d1c01298c035", + "reference": "ba6c9c18db36235b859cc29b8372d1c01298c035", "shasum": "" }, "require": { @@ -4540,7 +5127,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -4574,26 +5165,26 @@ "portable", "shim" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.11.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "c766e95bec706cdd89903b1eda8afab7d7a6b7af" + "reference": "a57f8161502549a742a63c09f0a604997bf47027" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c766e95bec706cdd89903b1eda8afab7d7a6b7af", - "reference": "c766e95bec706cdd89903b1eda8afab7d7a6b7af", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a57f8161502549a742a63c09f0a604997bf47027", + "reference": "a57f8161502549a742a63c09f0a604997bf47027", "shasum": "" }, "require": { "php": ">=5.3.3", "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php72": "^1.9" + "symfony/polyfill-php72": "^1.10" }, "suggest": { "ext-intl": "For best performance" @@ -4601,7 +5192,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -4617,13 +5212,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Laurent Bassin", "email": "laurent@bassin.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", @@ -4636,20 +5231,20 @@ "portable", "shim" ], - "time": "2019-03-04T13:44:35+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.11.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609" + "reference": "7110338d81ce1cbc3e273136e4574663627037a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609", - "reference": "fe5e94c604826c35a32fa832f35bd036b6799609", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7110338d81ce1cbc3e273136e4574663627037a7", + "reference": "7110338d81ce1cbc3e273136e4574663627037a7", "shasum": "" }, "require": { @@ -4661,7 +5256,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -4695,20 +5294,20 @@ "portable", "shim" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.11.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c" + "reference": "f048e612a3905f34931127360bdd2def19a5e582" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/ab50dcf166d5f577978419edd37aa2bb8eabce0c", - "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/f048e612a3905f34931127360bdd2def19a5e582", + "reference": "f048e612a3905f34931127360bdd2def19a5e582", "shasum": "" }, "require": { @@ -4717,7 +5316,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -4750,20 +5349,148 @@ "portable", "shim" ], - "time": "2019-02-06T07:57:58+00:00" + "time": "2020-05-12T16:47:27+00:00" }, { - "name": "symfony/process", - "version": "v4.2.5", + "name": "symfony/polyfill-php73", + "version": "v1.17.1", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "1e6cbb41dadcaf29e0db034d6ad0d039a9df06e6" + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/1e6cbb41dadcaf29e0db034d6ad0d039a9df06e6", - "reference": "1e6cbb41dadcaf29e0db034d6ad0d039a9df06e6", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fa0837fe02d617d31fbb25f990655861bb27bd1a", + "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-06-06T08:46:27+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.17.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2", + "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2", + "shasum": "" + }, + "require": { + "php": ">=7.0.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-06-06T08:46:27+00:00" + }, + { + "name": "symfony/process", + "version": "v4.4.10", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "c714958428a85c86ab97e3a0c96db4c4f381b7f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/c714958428a85c86ab97e3a0c96db4c4f381b7f5", + "reference": "c714958428a85c86ab97e3a0c96db4c4f381b7f5", "shasum": "" }, "require": { @@ -4772,7 +5499,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4799,20 +5526,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2019-03-10T20:07:02+00:00" + "time": "2020-05-30T20:06:45+00:00" }, { "name": "symfony/routing", - "version": "v4.2.5", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "319f600c1ea0f981f6bdc2f042cfc1690957c0e0" + "reference": "0f557911dde75c2a9652b8097bd7c9f54507f646" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/319f600c1ea0f981f6bdc2f042cfc1690957c0e0", - "reference": "319f600c1ea0f981f6bdc2f042cfc1690957c0e0", + "url": "https://api.github.com/repos/symfony/routing/zipball/0f557911dde75c2a9652b8097bd7c9f54507f646", + "reference": "0f557911dde75c2a9652b8097bd7c9f54507f646", "shasum": "" }, "require": { @@ -4824,13 +5551,13 @@ "symfony/yaml": "<3.4" }, "require-dev": { - "doctrine/annotations": "~1.0", + "doctrine/annotations": "~1.2", "psr/log": "~1.0", - "symfony/config": "~4.2", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/expression-language": "~3.4|~4.0", - "symfony/http-foundation": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "doctrine/annotations": "For using the annotation loader", @@ -4842,7 +5569,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4875,24 +5602,24 @@ "uri", "url" ], - "time": "2019-03-30T15:58:42+00:00" + "time": "2020-05-30T20:07:26+00:00" }, { "name": "symfony/serializer", - "version": "v4.2.5", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "d7c959be961d05d78931c0f739abec9903e006b1" + "reference": "a91ceee34fc690a824770085192ffdeaa4476a8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/d7c959be961d05d78931c0f739abec9903e006b1", - "reference": "d7c959be961d05d78931c0f739abec9903e006b1", + "url": "https://api.github.com/repos/symfony/serializer/zipball/a91ceee34fc690a824770085192ffdeaa4476a8c", + "reference": "a91ceee34fc690a824770085192ffdeaa4476a8c", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -4905,22 +5632,24 @@ "require-dev": { "doctrine/annotations": "~1.0", "doctrine/cache": "~1.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0", - "symfony/cache": "~3.4|~4.0", - "symfony/config": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/http-foundation": "~3.4|~4.0", - "symfony/property-access": "~3.4|~4.0", - "symfony/property-info": "~3.4|~4.0", - "symfony/validator": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "phpdocumentor/reflection-docblock": "^3.2|^4.0", + "symfony/cache": "^3.4|^4.0|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/property-access": "^3.4|^4.0|^5.0", + "symfony/property-info": "^3.4.13|~4.0|^5.0", + "symfony/validator": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", "doctrine/cache": "For using the default cached annotation reader and metadata cache.", "psr/cache-implementation": "For using the metadata cache.", "symfony/config": "For using the XML mapping loader.", - "symfony/http-foundation": "To use the DataUriNormalizer.", + "symfony/http-foundation": "For using a MIME type guesser within the DataUriNormalizer.", "symfony/property-access": "For using the ObjectNormalizer.", "symfony/property-info": "To deserialize relations.", "symfony/yaml": "For using the default YAML mapping loader." @@ -4928,7 +5657,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4955,43 +5684,104 @@ ], "description": "Symfony Serializer Component", "homepage": "https://symfony.com", - "time": "2019-04-01T16:12:17+00:00" + "time": "2020-06-01T17:29:37+00:00" }, { - "name": "symfony/translation", - "version": "v4.2.5", + "name": "symfony/service-contracts", + "version": "v2.1.2", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "e46933cc31b68f51f7fc5470fb55550407520f56" + "url": "https://github.com/symfony/service-contracts.git", + "reference": "66a8f0957a3ca54e4f724e49028ab19d75a8918b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e46933cc31b68f51f7fc5470fb55550407520f56", - "reference": "e46933cc31b68f51f7fc5470fb55550407520f56", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/66a8f0957a3ca54e4f724e49028ab19d75a8918b", + "reference": "66a8f0957a3ca54e4f724e49028ab19d75a8918b", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/contracts": "^1.0.2", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2020-05-20T17:43:50+00:00" + }, + { + "name": "symfony/translation", + "version": "v4.4.10", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "79d3ef9096a6a6047dbc69218b68c7b7f63193af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/79d3ef9096a6a6047dbc69218b68c7b7f63193af", + "reference": "79d3ef9096a6a6047dbc69218b68c7b7f63193af", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^1.1.6|^2" }, "conflict": { "symfony/config": "<3.4", "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4", "symfony/yaml": "<3.4" }, "provide": { - "symfony/translation-contracts-implementation": "1.0" + "symfony/translation-implementation": "1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/console": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/intl": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/finder": "~2.8|~3.0|~4.0|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/intl": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1.2|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "psr/log-implementation": "To use logging capability in translator", @@ -5001,7 +5791,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5028,26 +5818,84 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2019-04-01T14:13:08+00:00" + "time": "2020-05-30T20:06:45+00:00" }, { - "name": "symfony/var-dumper", - "version": "v4.2.5", + "name": "symfony/translation-contracts", + "version": "v2.1.2", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "9f87189ac10b42edf7fb8edc846f1937c6d157cf" + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "e5ca07c8f817f865f618aa072c2fe8e0e637340e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9f87189ac10b42edf7fb8edc846f1937c6d157cf", - "reference": "9f87189ac10b42edf7fb8edc846f1937c6d157cf", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/e5ca07c8f817f865f618aa072c2fe8e0e637340e", + "reference": "e5ca07c8f817f865f618aa072c2fe8e0e637340e", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.2.5" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2020-05-20T17:43:50+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.10", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "56b3aa5eab0ac6720dcd559fd1d590ce301594ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/56b3aa5eab0ac6720dcd559fd1d590ce301594ac", + "reference": "56b3aa5eab0ac6720dcd559fd1d590ce301594ac", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php72": "~1.5" + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.15" }, "conflict": { "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", @@ -5055,9 +5903,9 @@ }, "require-dev": { "ext-iconv": "*", - "symfony/console": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0", - "twig/twig": "~1.34|~2.4" + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.34|^2.4|^3.0" }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", @@ -5070,7 +5918,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -5104,7 +5952,7 @@ "debug", "dump" ], - "time": "2019-02-23T15:17:42+00:00" + "time": "2020-05-30T20:06:45+00:00" }, { "name": "symfony/yaml", @@ -5166,22 +6014,86 @@ "time": "2019-01-03T09:07:35+00:00" }, { - "name": "tijsverkoyen/css-to-inline-styles", - "version": "2.2.1", + "name": "tecnickcom/tcpdf", + "version": "6.3.5", "source": { "type": "git", - "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757" + "url": "https://github.com/tecnickcom/TCPDF.git", + "reference": "19a535eaa7fb1c1cac499109deeb1a7a201b4549" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757", - "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757", + "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/19a535eaa7fb1c1cac499109deeb1a7a201b4549", + "reference": "19a535eaa7fb1c1cac499109deeb1a7a201b4549", "shasum": "" }, "require": { + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "config", + "include", + "tcpdf.php", + "tcpdf_parser.php", + "tcpdf_import.php", + "tcpdf_barcodes_1d.php", + "tcpdf_barcodes_2d.php", + "include/tcpdf_colors.php", + "include/tcpdf_filters.php", + "include/tcpdf_font_data.php", + "include/tcpdf_fonts.php", + "include/tcpdf_images.php", + "include/tcpdf_static.php", + "include/barcodes/datamatrix.php", + "include/barcodes/pdf417.php", + "include/barcodes/qrcode.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-only" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "role": "lead" + } + ], + "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", + "homepage": "http://www.tcpdf.org/", + "keywords": [ + "PDFD32000-2008", + "TCPDF", + "barcodes", + "datamatrix", + "pdf", + "pdf417", + "qrcode" + ], + "time": "2020-02-14T14:20:12+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "2.2.2", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "dda2ee426acd6d801d5b7fd1001cde9b5f790e15" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/dda2ee426acd6d801d5b7fd1001cde9b5f790e15", + "reference": "dda2ee426acd6d801d5b7fd1001cde9b5f790e15", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", "php": "^5.5 || ^7.0", - "symfony/css-selector": "^2.7 || ^3.0 || ^4.0" + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" @@ -5204,34 +6116,40 @@ "authors": [ { "name": "Tijs Verkoyen", - "role": "Developer", - "email": "css_to_inline_styles@verkoyen.eu" + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" } ], "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", - "time": "2017-11-27T11:13:29+00:00" + "time": "2019-10-24T08:53:34+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v2.6.1", + "version": "v2.6.5", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5" + "reference": "2e977311ffb17b2f82028a9c36824647789c6365" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2a7dcf7e3e02dc5e701004e51a6f304b713107d5", - "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2e977311ffb17b2f82028a9c36824647789c6365", + "reference": "2e977311ffb17b2f82028a9c36824647789c6365", "shasum": "" }, "require": { - "php": ">=5.3.9", - "symfony/polyfill-ctype": "^1.9" + "php": "^5.3.9 || ^7.0 || ^8.0", + "symfony/polyfill-ctype": "^1.16" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.0" + "ext-filter": "*", + "ext-pcre": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7.27" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator.", + "ext-pcre": "Required to use most of the library." }, "type": "library", "extra": { @@ -5249,10 +6167,15 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "homepage": "https://gjcampbell.co.uk/" + }, { "name": "Vance Lucas", "email": "vance@vancelucas.com", - "homepage": "http://www.vancelucas.com" + "homepage": "https://vancelucas.com/" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -5261,31 +6184,34 @@ "env", "environment" ], - "time": "2019-01-29T11:11:52+00:00" + "time": "2020-06-02T14:06:52+00:00" }, { "name": "zendframework/zend-code", - "version": "3.3.1", + "version": "3.4.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-code.git", - "reference": "c21db169075c6ec4b342149f446e7b7b724f95eb" + "reference": "268040548f92c2bfcba164421c1add2ba43abaaa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-code/zipball/c21db169075c6ec4b342149f446e7b7b724f95eb", - "reference": "c21db169075c6ec4b342149f446e7b7b724f95eb", + "url": "https://api.github.com/repos/zendframework/zend-code/zipball/268040548f92c2bfcba164421c1add2ba43abaaa", + "reference": "268040548f92c2bfcba164421c1add2ba43abaaa", "shasum": "" }, "require": { "php": "^7.1", "zendframework/zend-eventmanager": "^2.6 || ^3.0" }, + "conflict": { + "phpspec/prophecy": "<1.9.0" + }, "require-dev": { - "doctrine/annotations": "~1.0", + "doctrine/annotations": "^1.7", "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "zendframework/zend-coding-standard": "^1.0.0", + "phpunit/phpunit": "^7.5.16 || ^8.4", + "zendframework/zend-coding-standard": "^1.0", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "suggest": { @@ -5295,8 +6221,9 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3.x-dev", - "dev-develop": "3.4.x-dev" + "dev-master": "3.4.x-dev", + "dev-develop": "3.5.x-dev", + "dev-dev-4.0": "4.0.x-dev" } }, "autoload": { @@ -5308,13 +6235,14 @@ "license": [ "BSD-3-Clause" ], - "description": "provides facilities to generate arbitrary code using an object oriented interface", - "homepage": "https://github.com/zendframework/zend-code", + "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", "keywords": [ + "ZendFramework", "code", - "zf2" + "zf" ], - "time": "2018-08-13T20:36:59+00:00" + "abandoned": "laminas/laminas-code", + "time": "2019-12-10T19:21:15+00:00" }, { "name": "zendframework/zend-eventmanager", @@ -5368,22 +6296,23 @@ "events", "zf2" ], + "abandoned": "laminas/laminas-eventmanager", "time": "2018-04-25T15:33:34+00:00" } ], "packages-dev": [ { "name": "filp/whoops", - "version": "2.3.1", + "version": "2.7.3", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "bc0fd11bc455cc20ee4b5edabc63ebbf859324c7" + "reference": "5d5fe9bb3d656b514d455645b3addc5f7ba7714d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/bc0fd11bc455cc20ee4b5edabc63ebbf859324c7", - "reference": "bc0fd11bc455cc20ee4b5edabc63ebbf859324c7", + "url": "https://api.github.com/repos/filp/whoops/zipball/5d5fe9bb3d656b514d455645b3addc5f7ba7714d", + "reference": "5d5fe9bb3d656b514d455645b3addc5f7ba7714d", "shasum": "" }, "require": { @@ -5392,8 +6321,8 @@ }, "require-dev": { "mockery/mockery": "^0.9 || ^1.0", - "phpunit/phpunit": "^4.8.35 || ^5.7", - "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" }, "suggest": { "symfony/var-dumper": "Pretty print complex values better with var-dumper available", @@ -5402,7 +6331,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -5431,20 +6360,20 @@ "throwable", "whoops" ], - "time": "2018-10-23T09:00:00+00:00" + "time": "2020-06-14T09:00:00+00:00" }, { "name": "fzaninotto/faker", - "version": "v1.8.0", + "version": "v1.9.1", "source": { "type": "git", "url": "https://github.com/fzaninotto/Faker.git", - "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de" + "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/f72816b43e74063c8b10357394b6bba8cb1c10de", - "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/fc10d778e4b84d5bd315dad194661e091d307c6f", + "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f", "shasum": "" }, "require": { @@ -5453,12 +6382,12 @@ "require-dev": { "ext-intl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7", - "squizlabs/php_codesniffer": "^1.5" + "squizlabs/php_codesniffer": "^2.9.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -5481,7 +6410,7 @@ "faker", "fixtures" ], - "time": "2018-07-12T10:23:15+00:00" + "time": "2019-12-12T13:22:17+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -5582,16 +6511,16 @@ }, { "name": "mockery/mockery", - "version": "1.2.2", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2" + "reference": "f69bbde7d7a75d6b2862d9ca8fab1cd28014b4be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2", - "reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2", + "url": "https://api.github.com/repos/mockery/mockery/zipball/f69bbde7d7a75d6b2862d9ca8fab1cd28014b4be", + "reference": "f69bbde7d7a75d6b2862d9ca8fab1cd28014b4be", "shasum": "" }, "require": { @@ -5605,7 +6534,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -5643,24 +6572,24 @@ "test double", "testing" ], - "time": "2019-02-13T09:37:52+00:00" + "time": "2019-12-26T09:49:15+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.9.0", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "78af75148f9fdd34ea727c8b529a9b4a8f7b740c" + "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/78af75148f9fdd34ea727c8b529a9b4a8f7b740c", - "reference": "78af75148f9fdd34ea727c8b529a9b4a8f7b740c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", + "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", "shasum": "" }, "require": { - "php": "^7.2" + "php": "^7.1 || ^8.0" }, "replace": { "myclabs/deep-copy": "self.version" @@ -5668,8 +6597,6 @@ "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpstan/phpstan": "^0.9.2", - "phpstan/phpstan-phpunit": "^0.9.4", "phpunit/phpunit": "^7.1" }, "type": "library", @@ -5693,7 +6620,7 @@ "object", "object graph" ], - "time": "2018-10-30T00:14:44+00:00" + "time": "2020-06-29T13:22:24+00:00" }, { "name": "nunomaduro/collision", @@ -5797,18 +6724,18 @@ "authors": [ { "name": "Arne Blankerts", - "role": "Developer", - "email": "arne@blankerts.de" + "email": "arne@blankerts.de", + "role": "Developer" }, { "name": "Sebastian Heuer", - "role": "Developer", - "email": "sebastian@phpeople.de" + "email": "sebastian@phpeople.de", + "role": "Developer" }, { "name": "Sebastian Bergmann", - "role": "Developer", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "Developer" } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", @@ -5863,35 +6790,30 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", "shasum": "" }, "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.6" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-2.x": "2.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -5913,44 +6835,42 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2020-06-27T09:03:43+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", + "reference": "cd72d394ca794d3466a3b2fc09d5a6c1dc86b47e", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", - "webmozart/assert": "^1.0" + "ext-filter": "^7.1", + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0", + "phpdocumentor/type-resolver": "^1.0", + "webmozart/assert": "^1" }, "require-dev": { - "doctrine/instantiator": "~1.0.5", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" + "doctrine/instantiator": "^1", + "mockery/mockery": "^1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -5961,44 +6881,45 @@ { "name": "Mike van Riel", "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "time": "2020-02-22T12:28:44+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.4.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + "reference": "e878a14a65245fbe78f8080eba03b47c3b705651" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e878a14a65245fbe78f8080eba03b47c3b705651", + "reference": "e878a14a65245fbe78f8080eba03b47c3b705651", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "phpdocumentor/reflection-common": "^1.0" + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "ext-tokenizer": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-1.x": "1.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -6011,42 +6932,43 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14T14:27:02+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2020-06-27T10:12:23+00:00" }, { "name": "phpspec/prophecy", - "version": "1.8.0", + "version": "v1.10.3", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + "reference": "451c3cd1418cf640de218914901e51b064abb093" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", + "phpspec/phpspec": "^2.5 || ^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -6074,7 +6996,7 @@ "spy", "stub" ], - "time": "2018-08-05T17:53:17+00:00" + "time": "2020-03-05T15:02:03+00:00" }, { "name": "phpunit/php-code-coverage", @@ -6177,8 +7099,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "role": "lead", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], "description": "FilterIterator implementation that filters files based on a list of suffixes.", @@ -6219,8 +7141,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "role": "lead", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], "description": "Simple template engine.", @@ -6232,16 +7154,16 @@ }, { "name": "phpunit/php-timer", - "version": "2.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b389aebe1b8b0578430bda0c7c95a829608e059", - "reference": "8b389aebe1b8b0578430bda0c7c95a829608e059", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { @@ -6277,20 +7199,20 @@ "keywords": [ "timer" ], - "time": "2019-02-20T10:12:59+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "3.0.1", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { @@ -6303,7 +7225,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -6326,20 +7248,20 @@ "keywords": [ "tokenizer" ], - "time": "2018-10-30T05:52:18+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "7.5.8", + "version": "7.5.20", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c29c0525cf4572c11efe1db49a8b8aee9dfac58a" + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c29c0525cf4572c11efe1db49a8b8aee9dfac58a", - "reference": "c29c0525cf4572c11efe1db49a8b8aee9dfac58a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c", + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c", "shasum": "" }, "require": { @@ -6410,7 +7332,7 @@ "testing", "xunit" ], - "time": "2019-03-26T13:23:54+00:00" + "time": "2020-01-08T08:45:45+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -6579,16 +7501,16 @@ }, { "name": "sebastian/environment", - "version": "4.1.0", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "6fda8ce1974b62b14935adc02a9ed38252eca656" + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6fda8ce1974b62b14935adc02a9ed38252eca656", - "reference": "6fda8ce1974b62b14935adc02a9ed38252eca656", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "shasum": "" }, "require": { @@ -6603,7 +7525,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -6628,20 +7550,20 @@ "environment", "hhvm" ], - "time": "2019-02-01T05:27:49+00:00" + "time": "2019-11-20T08:46:58+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { @@ -6668,6 +7590,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -6676,17 +7602,13 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -6695,7 +7617,7 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2019-09-14T09:02:43+00:00" }, { "name": "sebastian/global-state", @@ -6970,8 +7892,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "role": "lead", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", @@ -6980,25 +7902,29 @@ }, { "name": "symfony/dom-crawler", - "version": "v4.2.5", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "53c97769814c80a84a8403efcf3ae7ae966d53bb" + "reference": "c18354d5a0bb84c945f6257c51b971d52f10c614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/53c97769814c80a84a8403efcf3ae7ae966d53bb", - "reference": "53c97769814c80a84a8403efcf3ae7ae966d53bb", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c18354d5a0bb84c945f6257c51b971d52f10c614", + "reference": "c18354d5a0bb84c945f6257c51b971d52f10c614", "shasum": "" }, "require": { - "php": "^7.1.3", + "php": ">=7.1.3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0" }, + "conflict": { + "masterminds/html5": "<2.6" + }, "require-dev": { - "symfony/css-selector": "~3.4|~4.0" + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/css-selector": "" @@ -7006,7 +7932,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -7033,20 +7959,20 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2019-02-23T15:17:42+00:00" + "time": "2020-05-23T00:03:06+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "1c42705be2b6c1de5904f8afacef5895cab44bf8" + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/1c42705be2b6c1de5904f8afacef5895cab44bf8", - "reference": "1c42705be2b6c1de5904f8afacef5895cab44bf8", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { @@ -7073,36 +7999,34 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2019-04-04T09:56:43+00:00" + "time": "2019-06-13T22:48:21+00:00" }, { "name": "webmozart/assert", - "version": "1.4.0", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" + "reference": "9dc4f203e36f2b486149058bade43c851dd97451" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", + "url": "https://api.github.com/repos/webmozart/assert/zipball/9dc4f203e36f2b486149058bade43c851dd97451", + "reference": "9dc4f203e36f2b486149058bade43c851dd97451", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0", "symfony/polyfill-ctype": "^1.8" }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<3.9.1" + }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -7124,13 +8048,12 @@ "check", "validate" ], - "time": "2018-12-25T11:19:39+00:00" + "time": "2020-06-16T10:16:42+00:00" } ], "aliases": [], "minimum-stability": "dev", "stability-flags": { - "idct/sftp-client": 20, "php-opencloud/openstack": 20, "smarcet/outlook-rest-client": 20 }, @@ -7138,6 +8061,8 @@ "prefer-lowest": false, "platform": { "php": "^7.1.3", + "ext-gd": "*", + "ext-imagick": "*", "ext-json": "*", "ext-pdo": "*" }, diff --git a/config/app.php b/config/app.php index 523e06c9..f865e613 100644 --- a/config/app.php +++ b/config/app.php @@ -19,6 +19,9 @@ return [ 'env' => env('APP_ENV', 'dev'), + // emails will be send to this email on dev/testing mode + 'dev_email_to' => env('DEV_EMAIL_TO', null), + /* |-------------------------------------------------------------------------- | Application Debug Mode @@ -152,13 +155,18 @@ return [ App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, App\Repositories\RepositoriesProvider::class, - services\ServicesProvider::class, + App\Services\FileSystem\Swift\SwiftServiceProvider::class, + \App\Services\FileSystem\Dropbox\DropboxServiceProvider::class, + services\BaseServicesProvider::class, + services\ModelServicesProvider::class, factories\FactoriesProvider::class, App\Http\Utils\UtilsProvider::class, libs\utils\CustomDoctrineServiceProvider::class, LaravelDoctrine\Extensions\BeberleiExtensionsServiceProvider::class, Sichikawa\LaravelSendgridDriver\SendgridTransportServiceProvider::class, LaravelDoctrine\Migrations\MigrationsServiceProvider::class, + SimpleSoftwareIO\QrCode\QrCodeServiceProvider::class, + \App\Queue\RabbitMQServiceProvider::class, ], /* @@ -206,7 +214,8 @@ return [ 'EntityManager' => LaravelDoctrine\ORM\Facades\EntityManager::class, 'Registry' => LaravelDoctrine\ORM\Facades\Registry::class, 'Doctrine' => LaravelDoctrine\ORM\Facades\Doctrine::class, - 'Encryption' => services\utils\Facades\Encryption::class, + 'Encryption' => services\utils\Facades\Encryption::class, + 'QrCode' => SimpleSoftwareIO\QrCode\Facades\QrCode::class, ], 'app_name' => env('APP_NAME', 'Open Infrastructure Summit'), diff --git a/config/bookable_rooms.php b/config/bookable_rooms.php index 782dee3a..7131d87b 100644 --- a/config/bookable_rooms.php +++ b/config/bookable_rooms.php @@ -11,8 +11,28 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use models\summit\IPaymentConstants; + return [ - 'reservation_lifetime' => env('BOOKABLE_ROOMS_RESERVATION_LIFETIME', 5), - 'admin_email' => env('BOOKABLE_ROOMS_ADMIN_EMAIL'), - 'enable_bookable_rooms_reservation_revocation' => env('ENABLE_BOOKABLE_ROOMS_RESERVATION_REVOCATION', false), + 'reservation_lifetime' => env('BOOKABLE_ROOMS_RESERVATION_LIFETIME', 30), + 'admin_email' => env('BOOKABLE_ROOMS_ADMIN_EMAIL',null), + 'enable_bookable_rooms_reservation_revocation' => env('ENABLE_BOOKABLE_ROOMS_RESERVATION_REVOCATION', false), + 'reservation_canceled_email_subject' => env('BOOKABLE_ROOMS_RESERVATION_CANCELED_EMAIL_SUBJECT', null), + 'reservation_created_email_subject' => env('BOOKABLE_ROOMS_RESERVATION_CREATED_EMAIL_SUBJECT', null), + 'reservation_payment_confirmed_email_subject' => env('BOOKABLE_ROOMS_RESERVATION_PAYMENT_CONFIRMED_EMAIL_SUBJECT', null), + 'reservation_refund_accepted_email_subject' => env('BOOKABLE_ROOMS_RESERVATION_REFUND_ACCEPTED_EMAIL_SUBJECT', null), + 'reservation_refund_requested_admin_email_subject' => env('BOOKABLE_ROOMS_RESERVATION_REFUND_REQUESTED_ADMIN_EMAIL_SUBJECT', null), + 'reservation_refund_requested_owner_email_subject' => env('BOOKABLE_ROOMS_RESERVATION_REFUND_REQUESTED_OWNER_EMAIL_SUBJECT', null), + 'default_payment_provider' => env('BOOKABLE_ROOMS_DEFAULT_PAYMENT_PROVIDER',IPaymentConstants::ProviderStripe), + 'default_payment_provider_config' => [ + IPaymentConstants::ProviderStripe => [ + 'is_test_mode' => env('BOOKABLE_ROOMS_DEFAULT_STRIPE_TEST_MODE', true), + 'live_secret_key' => env('BOOKABLE_ROOMS_DEFAULT_LIVE_STRIPE_PRIVATE_KEY', null), + 'live_publishable_key' => env('BOOKABLE_ROOMS_DEFAULT_LIVE_STRIPE_PUBLISHABLE_KEY', null), + 'live_web_hook_secret' => env('BOOKABLE_ROOMS_DEFAULT_LIVE_WEBHOOK_SECRET', null), + 'test_secret_key' => env('BOOKABLE_ROOMS_DEFAULT_TEST_STRIPE_PRIVATE_KEY', null), + 'test_publishable_key' => env('BOOKABLE_ROOMS_DEFAULT_TEST_STRIPE_PUBLISHABLE_KEY', null), + 'test_web_hook_secret' => env('BOOKABLE_ROOMS_DEFAULT_TEST_WEBHOOK_SECRET', null), + ] + ] ]; \ No newline at end of file diff --git a/config/cfp.php b/config/cfp.php new file mode 100644 index 00000000..833fd31c --- /dev/null +++ b/config/cfp.php @@ -0,0 +1,18 @@ + env('CFP_APP_BASE_URL', null), + 'support_email' => env('CFP_SUPPORT_EMAIL', null), +]; \ No newline at end of file diff --git a/config/cloudstorage.php b/config/cloudstorage.php deleted file mode 100644 index 5b0079b3..00000000 --- a/config/cloudstorage.php +++ /dev/null @@ -1,26 +0,0 @@ - env('CLOUD_STORAGE_BASE_URL', null), - 'assets_container' => env('CLOUD_STORAGE_ASSETS_CONTAINER', null), - 'images_container' => env('CLOUD_STORAGE_IMAGES_CONTAINER', null), - 'auth_url' => env('CLOUD_STORAGE_AUTH_URL', null), - 'user_name' => env('CLOUD_STORAGE_USERNAME', null), - 'api_key' => env('CLOUD_STORAGE_APIKEY', null), - 'project_name' => env('CLOUD_STORAGE_PROJECT_NAME', null), - 'region' => env('CLOUD_STORAGE_REGION', null), - 'app_credential_id' => env('CLOUD_STORAGE_APP_CREDENTIAL_ID', null), - 'app_credential_secret' => env('CLOUD_STORAGE_APP_CREDENTIAL_SECRET', null), -]; \ No newline at end of file diff --git a/config/database.php b/config/database.php index edf0ea8c..0e8ba5f5 100644 --- a/config/database.php +++ b/config/database.php @@ -105,7 +105,7 @@ return [ 'host' => env('REDIS_HOST'), 'port' => env('REDIS_PORT'), 'database' => env('REDIS_DB'), - 'password' => env('REDIS_PASSWORD'), + 'password' => env('REDIS_PASSWORD','1qaz2wsx'), ], ], diff --git a/config/filesystems.php b/config/filesystems.php index 75b50022..cc96c15a 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -54,14 +54,37 @@ return [ 'visibility' => 'public', ], - 's3' => [ - 'driver' => 's3', - 'key' => 'your-key', - 'secret' => 'your-secret', - 'region' => 'your-region', - 'bucket' => 'your-bucket', + 'assets' => [ + 'driver' => 'swift', + 'auth_url' => env('CLOUD_STORAGE_AUTH_URL'), + 'region' => env('CLOUD_STORAGE_REGION'), + 'app_credential_id' => env('CLOUD_STORAGE_APP_CREDENTIAL_ID'), + 'app_credential_secret' => env('CLOUD_STORAGE_APP_CREDENTIAL_SECRET'), + 'container' => env('CLOUD_STORAGE_ASSETS_CONTAINER'), ], + 'static_images' => [ + 'driver' => 'swift', + 'auth_url' => env('CLOUD_STORAGE_AUTH_URL'), + 'region' => env('CLOUD_STORAGE_REGION'), + 'app_credential_id' => env('CLOUD_STORAGE_APP_CREDENTIAL_ID'), + 'app_credential_secret' => env('CLOUD_STORAGE_APP_CREDENTIAL_SECRET'), + 'container' => env('CLOUD_STORAGE_IMAGES_CONTAINER'), + ], + + 'dropbox' => [ + 'driver' => 'dropbox', + 'authorization_token' => env('DROPBOX_ACCESS_TOKEN'), + ], + + 'swift' => [ + 'driver' => 'swift', + 'auth_url' => env('CLOUD_STORAGE_AUTH_URL'), + 'region' => env('CLOUD_STORAGE_REGION'), + 'app_credential_id' => env('CLOUD_STORAGE_APP_CREDENTIAL_ID'), + 'app_credential_secret' => env('CLOUD_STORAGE_APP_CREDENTIAL_SECRET'), + 'container' => env('CLOUD_STORAGE_MEDIA_UPLOADS_CONTAINER'), + ] ], ]; diff --git a/config/idp.php b/config/idp.php new file mode 100644 index 00000000..4de7e73d --- /dev/null +++ b/config/idp.php @@ -0,0 +1,21 @@ + env('IDP_BASE_URI', null), + 'authorization_endpoint' => env('IDP_AUTHORIZATION_ENDPOINT', null), + 'token_endpoint' => env('IDP_TOKEN_ENDPOINT', null), + 'introspection_endpoint' => env('IDP_INTROSPECTION_ENDPOINT', null), + 'userinfo_endpoint' => env('IDP_USERINFO_ENDPOINT', null), +]; \ No newline at end of file diff --git a/config/mail.php b/config/mail.php index e176c14c..efaa9687 100644 --- a/config/mail.php +++ b/config/mail.php @@ -108,5 +108,8 @@ return [ */ 'sendmail' => '/usr/sbin/sendmail -bs', - + 'service_base_url' => env('MAIL_API_BASE_URL'), + 'service_client_id' => env('MAIL_API_OAUTH2_CLIENT_ID'), + 'service_client_secret' => env('MAIL_API_OAUTH2_CLIENT_SECRET'), + 'service_client_scopes' => env('MAIL_API_OAUTH2_CLIENT_SCOPES'), ]; diff --git a/config/mediaupload.php b/config/mediaupload.php new file mode 100644 index 00000000..457464be --- /dev/null +++ b/config/mediaupload.php @@ -0,0 +1,18 @@ + env('MEDIA_UPLOAD_MOUNTING_FOLDER','PresentationMediaUploads') +]; diff --git a/config/queue.php b/config/queue.php index 411eebfe..0a08af2c 100644 --- a/config/queue.php +++ b/config/queue.php @@ -11,11 +11,12 @@ return [ | API, giving you convenient access to each back-end using the same | syntax for each one. Here you may set the default queue driver. | - | Supported: "null", "sync", "database", "beanstalkd", "sqs", "redis" + | Supported: "null", "sync", "database", "beanstalkd", + | "sqs", "redis" | */ - 'default' => env('QUEUE_DRIVER', 'redis'), + 'default' => env('QUEUE_DRIVER', 'database'), /* |-------------------------------------------------------------------------- @@ -30,13 +31,58 @@ return [ 'connections' => [ - 'redis' => [ - 'driver' => 'redis', - 'connection' => 'default', - 'queue' => 'default', - 'expire' => 60, + 'database' => [ + 'connection' => env('QUEUE_CONN', ''), + 'database' => env('QUEUE_DATABASE', ''), + 'driver' => 'database', + 'table' => 'queue_jobs', + 'queue' => 'default', + 'expire' => 60, ], + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + 'queue' => 'default', + 'expire' => 60, + 'block_for' => 5, + ], + + 'message_broker' => [ + 'driver' => 'rabbitmq', + 'queue' => env('RABBITMQ_QUEUE', ''), + 'connection' => env('RABBITMQ_PORT', 5671) === 5671 ? // SSL + PhpAmqpLib\Connection\AMQPSSLConnection::class: + PhpAmqpLib\Connection\AMQPLazyConnection::class + , + 'hosts' => [ + [ + 'host' => env('RABBITMQ_HOST', '127.0.0.1'), + 'port' => env('RABBITMQ_PORT', 5671), + 'user' => env('RABBITMQ_LOGIN', 'guest'), + 'password' => env('RABBITMQ_PASSWORD', 'guest'), + 'vhost' => env('RABBITMQ_VHOST', '/'), + ], + ], + 'options' => [ + 'ssl_options' => [ + // @see https://www.php.net/manual/en/context.ssl.php + 'cafile' => env('RABBITMQ_SSL_CAFILE', null), + 'local_cert' => env('RABBITMQ_SSL_LOCALCERT', null), + 'local_pk' => env('RABBITMQ_SSL_LOCALKEY', null), + 'verify_peer' => env('RABBITMQ_SSL_VERIFY_PEER', true), + 'passphrase' => env('RABBITMQ_SSL_PASSPHRASE', null), + ], + 'queue' => [ + 'exchange' => env('RABBITMQ_EXCHANGE_NAME'), + 'exchange_type' => env('RABBITMQ_EXCHANGE_TYPE', 'fanout'), + 'passive' => env('RABBITMQ_QUEUE_PASSIVE', false), + 'durable' => env('RABBITMQ_QUEUE_DURABLE', true), + 'exclusive' => env('RABBITMQ_QUEUE_EXCLUSIVE', false), + 'auto_delete' => env('RABBITMQ_QUEUE_AUTODELETE', true), + ], + ], + ], ], /* @@ -51,8 +97,9 @@ return [ */ 'failed' => [ - 'database' => env('DB_CONNECTION', 'config'), - 'table' => 'failed_jobs', + 'connection' => env('QUEUE_CONN', ''), + 'database' => env('QUEUE_CONN', ''), + 'table' => 'queue_failed_jobs', ], ]; diff --git a/config/registration.php b/config/registration.php new file mode 100644 index 00000000..6254a81b --- /dev/null +++ b/config/registration.php @@ -0,0 +1,48 @@ + env('REGISTRATION_LIFETIME', 30), + 'admin_email' => env('REGISTRATION_ADMIN_EMAIL',null), + 'service_client_id' => env('REGISTRATION_SERVICE_OAUTH2_CLIENT_ID', null), + 'service_client_secret' => env('REGISTRATION_SERVICE_OAUTH2_CLIENT_SECRET', null), + 'service_client_scopes' => env('REGISTRATION_SERVICE_OAUTH2_SCOPES', null), + 'dashboard_client_id' => env('REGISTRATION_DASHBOARD_OAUTH2_CLIENT_ID', null), + 'dashboard_base_url' => env('REGISTRATION_DASHBOARD_BASE_URL', null), + 'dashboard_back_url' => env('REGISTRATION_DASHBOARD_BACK_URL', null), + 'dashboard_attendee_edit_form_url' => env('REGISTRATION_DASHBOARD_ATTENDEE_EDIT_FORM_URL', null), + 'dashboard_invitation_form_url' => env('REGISTRATION_DASHBOARD_INVITATION_FORM_URL', null), + 'from_email' => env('REGISTRATION_FROM_EMAIL', null), + 'invite_attendee_ticket_edition_email_subject' => env('REGISTRATION_INVITE_ATTENDEE_TICKET_EDITION_EMAIL_SUBJECT', null), + 'registered_member_order_paid_mail_subject' => env('REGISTRATION_REGISTERED_MEMBER_ORDER_PAID_MAIL_SUBJECT', null), + 'unregistered_member_order_paid_email_subject' => env('REGISTRATION_UNREGISTERED_MEMBER_ORDER_PAID_EMAIL_SUBJECT', null), + 'ticket_public_edit_ttl' => env('REGISTRATION_TICKET_PUBLIC_EDIT_TTL', 30),//in minutes + 'support_email' => env('REGISTRATION_SUPPORT_EMAIL', null), + 'reminder_email_days_interval' => env('REGISTRATION_REMINDER_EMAIL_DAYS_INTERVAL', 7),//in days + 'validate_ticket_type_removal' => env('REGISTRATION_VALIDATE_TICKET_TYPE_REMOVAL', true), + 'default_payment_provider' => env('REGISTRATION_DEFAULT_PAYMENT_PROVIDER',IPaymentConstants::ProviderStripe), + 'default_payment_provider_config' => [ + IPaymentConstants::ProviderStripe => [ + 'is_test_mode' => env('REGISTRATION_DEFAULT_STRIPE_TEST_MODE', true), + 'live_secret_key' => env('REGISTRATION_DEFAULT_LIVE_STRIPE_PRIVATE_KEY', null), + 'live_publishable_key' => env('REGISTRATION_DEFAULT_LIVE_STRIPE_PUBLISHABLE_KEY', null), + 'live_web_hook_secret' => env('REGISTRATION_DEFAULT_LIVE_WEBHOOK_SECRET', null), + 'test_secret_key' => env('REGISTRATION_DEFAULT_TEST_STRIPE_PRIVATE_KEY', null), + 'test_publishable_key' => env('REGISTRATION_DEFAULT_TEST_STRIPE_PUBLISHABLE_KEY', null), + 'test_web_hook_secret' => env('REGISTRATION_DEFAULT_TEST_WEBHOOK_SECRET', null), + ] + ], + 'send_ticket_attachments' => env('REGISTRATION_SEND_TICKET_ATTACHMENTS', false), +]; \ No newline at end of file diff --git a/config/stripe.php b/config/stripe.php index 6293d543..287f777c 100644 --- a/config/stripe.php +++ b/config/stripe.php @@ -14,7 +14,12 @@ return [ // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys - "private_key" => env('STRIPE_PRIVATE_KEY', ''), + "booking_private_key" => env('STRIPE_BOOKING_PRIVATE_KEY', ''), // You can find your endpoint's secret in your webhook settings - "endpoint_secret" => env('STRIPE_ENDPOINT_SECRET', ''), + "booking_endpoint_secret" => env('STRIPE_BOOKING_ENDPOINT_SECRET', ''), + // Set your secret key: remember to change this to your live secret key in production + // See your keys here: https://dashboard.stripe.com/account/apikeys + "registration_private_key" => env('STRIPE_REGISTRATION_PRIVATE_KEY', ''), + // You can find your endpoint's secret in your webhook settings + "registration_endpoint_secret" => env('STRIPE_REGISTRATION_ENDPOINT_SECRET', ''), ]; \ No newline at end of file diff --git a/database/migrations/config/Version20190422160409.php b/database/migrations/config/Version20190422160409.php index 8027e43b..8ded1944 100644 --- a/database/migrations/config/Version20190422160409.php +++ b/database/migrations/config/Version20190422160409.php @@ -77,7 +77,6 @@ final class Version20190422160409 extends AbstractMigration $table->bigInteger("api_id")->setUnsigned(true); $table->index('api_id'); $table->foreign('apis','api_id', 'id'); - }); } diff --git a/database/migrations/model/Version20190730022151.php b/database/migrations/model/Version20190730022151.php new file mode 100644 index 00000000..db09e55c --- /dev/null +++ b/database/migrations/model/Version20190730022151.php @@ -0,0 +1,55 @@ +addSql($sql); + + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20190730031422.php b/database/migrations/model/Version20190730031422.php new file mode 100644 index 00000000..4b13e33c --- /dev/null +++ b/database/migrations/model/Version20190730031422.php @@ -0,0 +1,593 @@ +hasTable("SummitAccessLevelType")) { + $builder->create("SummitAccessLevelType", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string("Name")->setNotnull(true); + $table->string("Description")->setNotnull(false); + $table->boolean("IsDefault")->setDefault(false); + $table->text("TemplateContent"); + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + // badge features + if (!$builder->hasTable("SummitBadgeFeatureType")) { + $builder->create("SummitBadgeFeatureType", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string("Name")->setNotnull(true); + $table->string("Description")->setNotnull(false); + $table->text("TemplateContent"); + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + // badge types per summit + if (!$builder->hasTable("SummitBadgeType")) { + $builder->create("SummitBadgeType", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string("Name")->setNotnull(true); + $table->string("Description")->setNotnull(false); + $table->text("TemplateContent"); + $table->boolean("IsDefault")->setDefault(false); + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + $table->integer("FileID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("FileID", "FileID"); + $table->foreign("File", "FileID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + if (!$builder->hasTable("SummitBadgeType_AccessLevels")) { + $builder->create("SummitBadgeType_AccessLevels", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->integer("SummitBadgeTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitBadgeTypeID", "SummitBadgeTypeID"); + //$table->foreign("SummitBadgeType", "SummitBadgeTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitAccessLevelTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitAccessLevelTypeID", "SummitAccessLevelTypeID"); + //$table->foreign("SummitAccessLevelType", "SummitAccessLevelTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->unique(['SummitBadgeTypeID', 'SummitAccessLevelTypeID']); + }); + } + + // tax per summit + if (!$builder->hasTable("SummitTaxType")) { + $builder->create("SummitTaxType", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string("Name"); + $table->string("TaxID"); + $table->decimal("Rate", 9, 2)->setDefault('0.00'); + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + // refund policies + if (!$builder->hasTable("SummitRefundPolicyType")) { + $builder->create("SummitRefundPolicyType", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string("Name"); + $table->integer("UntilXDaysBeforeEventStarts")->setDefault(0); + $table->decimal("RefundRate", 9, 2)->setDefault('0.00'); + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + // update to ticket types + if ($builder->hasTable("SummitTicketType") && !$builder->hasColumn("SummitTicketType", "Cost")) { + $builder->table("SummitTicketType", function (Table $table) { + $table->decimal("Cost", 9, 2)->setDefault('0.00'); + $table->string("Currency", 3)->setDefault('USD'); + $table->integer("QuantityToSell")->setDefault(0); + $table->integer("QuantitySold")->setDefault(0); + $table->integer("MaxQuantityToSellPerOrder")->setDefault(0); + $table->timestamp('SaleStartDate')->setNotnull(false); + $table->timestamp('SaleEndDate')->setNotnull(false); + }); + } + + // taxes associated per tix type + if (!$builder->hasTable("SummitTicketType_Taxes")) { + $builder->create("SummitTicketType_Taxes", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->integer("SummitTicketTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitTicketTypeID", "SummitTicketTypeID"); + //$table->foreign("SummitTicketType", "TicketTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitTaxTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitTaxTypeID", "SummitTaxTypeID"); + //$table->foreign("SummitTaxType", "TaxTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->unique(['SummitTicketTypeID', 'SummitTaxTypeID']); + }); + } + + // promo codes and discount codes + + + // update to promo codes with new fields + if ($builder->hasTable("SummitRegistrationPromoCode") && !$builder->hasColumn("SummitRegistrationPromoCode", "QuantityAvailable")) { + $builder->table("SummitRegistrationPromoCode", function (Table $table) { + $table->integer("QuantityAvailable")->setDefault(0)->setNotnull(false); + $table->integer("QuantityUsed")->setDefault(0)->setNotnull(false); + $table->timestamp('ValidSinceDate')->setNotnull(false); + $table->timestamp('ValidUntilDate')->setNotnull(false); + $table->integer("BadgeTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("BadgeTypeID", "BadgeTypeID"); + $table->foreign("SummitBadgeType", "BadgeTypeID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + // features per promo code + if (!$builder->hasTable("SummitRegistrationPromoCode_BadgeFeatures")) { + $builder->create("SummitRegistrationPromoCode_BadgeFeatures", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->integer("SummitRegistrationPromoCodeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitRegistrationPromoCodeID", "SummitRegistrationPromoCodeID"); + //$table->foreign("SummitRegistrationPromoCode", "SummitRegistrationPromoCodeID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitBadgeFeatureTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitBadgeFeatureTypeID", "SummitBadgeFeatureTypeID"); + //$table->foreign("SummitBadgeFeatureType", "SummitBadgeFeatureTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->unique(['SummitRegistrationPromoCodeID', 'SummitBadgeFeatureTypeID']); + }); + } + + // allowed tix types per promo code + if (!$builder->hasTable("SummitRegistrationPromoCode_AllowedTicketTypes")) { + + $builder->create("SummitRegistrationPromoCode_AllowedTicketTypes", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->integer("SummitRegistrationPromoCodeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitRegistrationPromoCodeID", "SummitRegistrationPromoCodeID"); + //$table->foreign("SummitRegistrationPromoCode", "SummitRegistrationPromoCodeID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitTicketTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitTicketTypeID", "SummitTicketTypeID"); + //$table->foreign("SummitTicketType", "SummitTicketTypeID", "ID", ["onDelete" => "CASCADE"]); + $table->unique(['SummitRegistrationPromoCodeID', 'SummitTicketTypeID']); + }); + } + + // discount codes + if (!$builder->hasTable("SummitRegistrationDiscountCode")) { + + $builder->create("SummitRegistrationDiscountCode", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->decimal("DiscountRate", 9, 2)->setDefault('0.00')->setNotnull(true); + $table->decimal("DiscountAmount", 9, 2)->setDefault('0.00')->setNotnull(true); + + $table->foreign("SummitRegistrationPromoCode", "ID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + if (!$builder->hasTable("MemberSummitRegistrationDiscountCode")) { + $builder->create("MemberSummitRegistrationDiscountCode", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->integer("OwnerID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("OwnerID", "OwnerID"); + $table->foreign("Member", "OwnerID", "ID", ["onDelete" => "CASCADE"]); + $table->string("FirstName"); + $table->string("LastName"); + $table->string("Email"); + $table->string("Type"); + $table->foreign("SummitRegistrationPromoCode", "ID", "ID", ["onDelete" => "CASCADE"]); + }); + + } + + if (!$builder->hasTable("SpeakerSummitRegistrationDiscountCode")) { + $builder->create("SpeakerSummitRegistrationDiscountCode", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->integer("SpeakerID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SpeakerID", "SpeakerID"); + $table->foreign("PresentationSpeaker", "SpeakerID", "ID", ["onDelete" => "CASCADE"]); + $table->string("Type"); + $table->foreign("SummitRegistrationPromoCode", "ID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + if (!$builder->hasTable("SponsorSummitRegistrationDiscountCode")) { + $builder->create("SponsorSummitRegistrationDiscountCode", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->integer("SponsorID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SponsorID", "SponsorID"); + $table->foreign("Company", "SponsorID", "ID", ["onDelete" => "CASCADE"]); + $table->foreign("SummitRegistrationPromoCode", "ID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + // allowed tix types for discount codes + + if (!$builder->hasTable("SummitRegistrationDiscountCode_AllowedTicketTypes")) { + + $builder->create("SummitRegistrationDiscountCode_AllowedTicketTypes", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->decimal("DiscountRate", 9, 2)->setDefault('0.00'); + $table->decimal("DiscountAmount", 9, 2)->setDefault('0.00'); + + $table->integer("SummitRegistrationDiscountCodeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitRegistrationDiscountCodeID", "SummitRegistrationDiscountCodeID"); + //$table->foreign("SummitRegistrationDiscountCode", "SummitRegistrationDiscountCodeID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitTicketTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitTicketTypeID", "SummitTicketTypeID"); + //$table->foreign("SummitTicketType", "SummitTicketTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->unique(['SummitRegistrationDiscountCodeID', 'SummitTicketTypeID']); + }); + } + + if (!$builder->hasTable("SummitOrder")) { + $builder->create("SummitOrder", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + + $table->string("Status"); + $table->string("PaymentMethod"); + $table->string("Number"); + $table->index("Number", "Number"); + $table->unique(["SummitID", "Number"], "SummitID_Number"); + $table->string("QRCode")->setDefault("")->setNotnull(false); + $table->index("QRCode", "QRCode"); + + // owner + $table->string("OwnerFirstName"); + $table->string("OwnerSurname"); + $table->string("OwnerEmail", 100); + $table->string("OwnerCompany"); + + $table->integer("CompanyID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("CompanyID", "CompanyID"); + $table->foreign("Company", "CompanyID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("OwnerID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("OwnerID", "OwnerID"); + $table->foreign("Member", "OwnerID", "ID", ["onDelete" => "CASCADE"]); + $table->timestamp('DisclaimerAcceptedDate')->setNotnull(false); + // billing address + $table->string("BillingAddress1", 100)->setNotnull(false); + $table->string("BillingAddress2", 100)->setNotnull(false); + $table->string("BillingAddressZipCode", 50)->setNotnull(false); + $table->string("BillingAddressCity", 50)->setNotnull(false); + $table->string("BillingAddressState", 50)->setNotnull(false); + $table->string("BillingAddressCountryISOCode", 3)->setNotnull(false); + + //payment gateway + + $table->timestamp('ApprovedPaymentDate')->setNotnull(false); + $table->string("LastError")->setNotnull(false); + $table->text("PaymentGatewayClientToken")->setNotnull(false); + $table->string("PaymentGatewayCartId", 512)->setNotnull(false); + $table->index("PaymentGatewayCartId", "PaymentGatewayCartId"); + + $table->string("Hash", 255)->setNotnull(false); + $table->unique("Hash", "Hash"); + $table->timestamp('HashCreationDate')->setNotnull(false); + }); + } + + if ($builder->hasTable("SummitAttendeeTicket") && !$builder->hasColumn("SummitAttendeeTicket","OrderID")) { + $builder->table("SummitAttendeeTicket", function (Table $table) { + + $table->integer("OrderID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("OrderID", "OrderID"); + $table->foreign("SummitOrder", "OrderID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("PromoCodeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("PromoCodeID", "PromoCodeID"); + $table->foreign("SummitRegistrationPromoCode", "PromoCodeID", "ID", ["onDelete" => "CASCADE"]); + + $table->foreign("SummitAttendee", "OwnerID", "ID", ["onDelete" => "CASCADE"]); + + $table->decimal("RawCost", 9, 2)->setDefault('0.00'); + $table->decimal("Discount", 9, 2)->setDefault('0.00'); + $table->string("Status"); + $table->string("Number")->setNotnull(false); + $table->unique("Number", "Number"); + $table->decimal("RefundedAmount", 9, 2)->setDefault('0.00'); + $table->string("Currency", 3)->setDefault('USD'); + + $table->string("QRCode")->setDefault("")->setNotnull(false); + $table->index("QRCode", "QRCode"); + + $table->string("Hash", 255)->setNotnull(false); + $table->unique("Hash", "Hash"); + $table->timestamp('HashCreationDate')->setNotnull(false); + + }); + + } + + if (!$builder->hasTable("SummitAttendeeTicket_Taxes")) { + $builder->create("SummitAttendeeTicket_Taxes", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->integer("SummitAttendeeTicketID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitAttendeeTicketID", "SummitAttendeeTicketID"); + //$table->foreign("SummitAttendeeTicket", "TicketID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitTaxTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitTaxTypeID", "SummitTaxTypeID"); + //$table->foreign("SummitTaxType", "TaxTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->decimal("Amount", 9, 2)->setDefault('0.00'); + + $table->unique(['SummitAttendeeTicketID', 'SummitTaxTypeID']); + }); + } + + if ($builder->hasTable("SummitAttendee") && !$builder->hasColumn("SummitAttendee", "FirstName")) { + $builder->table("SummitAttendee", function (Table $table) { + $table->string("FirstName", 255)->setNotnull(false); + $table->string("Surname", 255)->setNotnull(false); + $table->string("Email", 100)->setNotnull(false); + $table->index("Email", "Email"); + $table->timestamp('DisclaimerAcceptedDate')->setNotnull(false); + }); + } + + if (!$builder->hasTable("SummitAttendeeBadge")) { + $builder->create("SummitAttendeeBadge", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + + $table->timestamp('PrintDate')->setNotnull(false); + $table->boolean('IsVoid')->setDefault(false); + $table->string("QRCode")->setDefault("")->setNotnull(false); + $table->index("QRCode", "QRCode"); + + $table->integer("TicketID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("TicketID", "TicketID"); + $table->foreign("SummitAttendeeTicket", "TicketID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("BadgeTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("BadgeTypeID", "BadgeTypeID"); + $table->foreign("SummitBadgeType", "BadgeTypeID", "ID", ["onDelete" => "CASCADE"]); + + }); + } + + if (!$builder->hasTable("SummitAttendeeBadge_Features")) { + $builder->create("SummitAttendeeBadge_Features", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->integer("SummitAttendeeBadgeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitAttendeeBadgeID", "SummitAttendeeBadgeID"); + //$table->foreign("SummitAttendeeBadge", "BadgeID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitBadgeFeatureTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitBadgeFeatureTypeID", "SummitBadgeFeatureTypeID"); + //$table->foreign("SummitBadgeFeatureType", "SummitBadgeFeatureTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->unique(['SummitAttendeeBadgeID', 'SummitBadgeFeatureTypeID']); + }); + } + + + // order extra question types + + if (!$builder->hasTable("SummitOrderExtraQuestionType")) { + + $builder->create("SummitOrderExtraQuestionType", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + + $table->string("Name", 100); + $table->string("Type"); + $table->string("Label"); + $table->integer("Order")->setDefault(0); + + $table->boolean("Mandatory")->setDefault(false); + $table->string("Usage", 50); + $table->string("Placeholder", 50); + $table->boolean("Printable")->setDefault(false); + + }); + } + + if (!$builder->hasTable("SummitOrderExtraQuestionValue")) { + $builder->create("SummitOrderExtraQuestionValue", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + + $table->integer("QuestionID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("QuestionID", "QuestionID"); + $table->foreign("SummitOrderExtraQuestionType", "QuestionID", "ID", ["onDelete" => "CASCADE"]); + + $table->string("Value"); + $table->string("Label"); + $table->integer("Order")->setDefault(0); + }); + } + + + if (!$builder->hasTable("SummitOrderExtraQuestionAnswer")) { + + $builder->create("SummitOrderExtraQuestionAnswer", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + + $table->text("Value"); + + $table->integer("QuestionID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("QuestionID", "QuestionID"); + $table->foreign("SummitOrderExtraQuestionType", "QuestionID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("OrderID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("OrderID", "OrderID"); + $table->foreign("SummitOrder", "OrderID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitAttendeeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitAttendeeID", "SummitAttendeeID"); + $table->foreign("SummitAttendee", "SummitAttendeeID", "ID", ["onDelete" => "CASCADE"]); + + }); + } + + // sponsors users + + if (!$builder->hasTable("Sponsor_Users")) { + + $builder->create("Sponsor_Users", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + + $table->integer("SponsorID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SponsorID", "SponsorID"); + //$table->foreign("Sponsor", "SponsorID", "ID", ["onDelete" => "CASCADE"]); + + + $table->integer("MemberID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("MemberID", "MemberID"); + //$table->foreign("Member", "UserID", "ID", ["onDelete" => "CASCADE"]); + + $table->unique(['SponsorID', 'MemberID']); + + }); + } + + // sponsors badge scans + + + if (!$builder->hasTable("SponsorBadgeScan")) { + + $builder->create("SponsorBadgeScan", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + + $table->integer("SponsorID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SponsorID", "SponsorID"); + $table->foreign("Sponsor", "SponsorID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("UserID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("UserID", "UserID"); + $table->foreign("Member", "UserID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("BadgeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("BadgeID", "BadgeID"); + $table->foreign("SummitAttendeeBadge", "BadgeID", "ID", ["onDelete" => "CASCADE"]); + + $table->string("QRCode"); + + }); + } + + if ($builder->hasTable("Summit") && !$builder->hasColumn("Summit", "ReAssignTicketTillDate")) { + $builder->table("Summit", function (Table $table) { + $table->timestamp('ReAssignTicketTillDate')->setNotnull(false); + $table->text('RegistrationDisclaimerContent')->setNotnull(false); + $table->boolean('RegistrationDisclaimerMandatory')->setNotnull(false)->setDefault(false); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20190801211505.php b/database/migrations/model/Version20190801211505.php new file mode 100644 index 00000000..786a069b --- /dev/null +++ b/database/migrations/model/Version20190801211505.php @@ -0,0 +1,141 @@ +addSql($sql); + + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + + + $sql = <<addSql($sql); + + + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + + // promo codes + + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20190911132806.php b/database/migrations/model/Version20190911132806.php new file mode 100644 index 00000000..9a871d53 --- /dev/null +++ b/database/migrations/model/Version20190911132806.php @@ -0,0 +1,51 @@ +hasTable("SummitOrder") && !$builder->hasColumn("SummitOrder", "RefundedAmount")) { + $builder->table("SummitOrder", function (Table $table) { + $table->decimal("RefundedAmount", 9, 2)->setDefault('0.00'); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if ($builder->hasTable("SummitOrder")) { + $builder->table("SummitOrder", function (Table $table) { + $table->dropColumn("RefundedAmount"); + }); + } + } +} diff --git a/database/migrations/model/Version20190918111958.php b/database/migrations/model/Version20190918111958.php new file mode 100644 index 00000000..db563d64 --- /dev/null +++ b/database/migrations/model/Version20190918111958.php @@ -0,0 +1,61 @@ +hasTable("SummitAttendeeBadge") && !$builder->hasColumn("SummitAttendeeBadge", "PrintedTimes")) { + $builder->table("SummitAttendeeBadge", function (Table $table) { + $table->integer("PrintedTimes")->setNotnull(false)->setDefault(0); + }); + } + + if ($builder->hasTable("SummitTicketType") && !$builder->hasColumn("SummitTicketType", "BadgeTypeID")) { + $builder->table("SummitTicketType", function (Table $table) { + $table->integer("BadgeTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("BadgeTypeID", "BadgeTypeID"); + $table->foreign("SummitBadgeType", "BadgeTypeID", "ID", ["onDelete" => "CASCADE"]); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if ($builder->hasTable("SummitAttendeeBadge") && $builder->hasColumn("SummitAttendeeBadge", "PrintedTimes")) { + $builder->table("SummitAttendeeBadge", function (Table $table) { + $table->dropColumn("PrintedTimes"); + }); + } + + } +} diff --git a/database/migrations/model/Version20191016014630.php b/database/migrations/model/Version20191016014630.php new file mode 100644 index 00000000..e7d0426f --- /dev/null +++ b/database/migrations/model/Version20191016014630.php @@ -0,0 +1,53 @@ +hasTable("SponsorBadgeScan") && !$builder->hasColumn("SponsorBadgeScan", "ScanDate")) { + $builder->table("SponsorBadgeScan", function (Table $table) { + $table->timestamp('ScanDate'); + }); + } + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if ($builder->hasTable("SponsorBadgeScan") && $builder->hasColumn("SponsorBadgeScan", "ScanDate")) { + $builder->table("SponsorBadgeScan", function (Table $table) { + $table->dropColumn('ScanDate'); + }); + } + } +} diff --git a/database/migrations/model/Version20191116183316.php b/database/migrations/model/Version20191116183316.php new file mode 100644 index 00000000..755bb298 --- /dev/null +++ b/database/migrations/model/Version20191116183316.php @@ -0,0 +1,91 @@ +hasTable("Summit") && !$builder->hasColumn("Summit", "ExternalRegistrationFeedType")) { + $builder->table("Summit", function (Table $table) { + $table->string('ExternalRegistrationFeedType')->setNotnull(false); + $table->string('ExternalRegistrationFeedApiKey')->setNotnull(false); + }); + } + + if ($builder->hasTable("SummitOrder") && !$builder->hasColumn("SummitOrder", "ExternalId")) { + $builder->table("SummitOrder", function (Table $table) { + $table->string('ExternalId')->setNotnull(false); + }); + } + + if ($builder->hasTable("SummitAttendee") && !$builder->hasColumn("SummitAttendee", "ExternalId")) { + $builder->table("SummitAttendee", function (Table $table) { + $table->string('ExternalId')->setNotnull(false); + }); + } + + if ($builder->hasTable("SummitRegistrationPromoCode") && !$builder->hasColumn("SummitRegistrationPromoCode", "ExternalId")) { + $builder->table("SummitRegistrationPromoCode", function (Table $table) { + $table->string('ExternalId')->setNotnull(false); + }); + } + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if ($builder->hasTable("Summit") && $builder->hasColumn("Summit", "ExternalRegistrationFeedType")) { + $builder->table("Summit", function (Table $table) { + $table->dropColumn('ExternalRegistrationFeedType'); + $table->dropColumn('ExternalRegistrationFeedApiKey'); + }); + } + + if ($builder->hasTable("SummitOrder") && $builder->hasColumn("SummitOrder", "ExternalId")) { + $builder->table("SummitOrder", function (Table $table) { + $table->dropColumn('ExternalId'); + }); + } + + if ($builder->hasTable("SummitRegistrationPromoCode") && $builder->hasColumn("SummitRegistrationPromoCode", "ExternalId")) { + $builder->table("SummitRegistrationPromoCode", function (Table $table) { + $table->dropColumn('ExternalId'); + }); + } + + if ($builder->hasTable("SummitAttendee") && $builder->hasColumn("SummitAttendee", "ExternalId")) { + $builder->table("SummitAttendee", function (Table $table) { + $table->dropColumn('ExternalId'); + }); + } + } +} diff --git a/database/migrations/model/Version20191125210134.php b/database/migrations/model/Version20191125210134.php new file mode 100644 index 00000000..0bcbf696 --- /dev/null +++ b/database/migrations/model/Version20191125210134.php @@ -0,0 +1,70 @@ +addSql($sql); + + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + + + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + + + $sql = <<addSql($sql); + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20191202223721.php b/database/migrations/model/Version20191202223721.php new file mode 100644 index 00000000..b67ba09b --- /dev/null +++ b/database/migrations/model/Version20191202223721.php @@ -0,0 +1,51 @@ +hasTable("SummitAttendee") && !$builder->hasColumn("SummitAttendee", "Company")) { + $builder->table("SummitAttendee", function (Table $table) { + $table->string("Company", 255)->setNotnull(false); + $table->index("Company", "Company"); + $table->integer("CompanyID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("CompanyID", "CompanyID"); + $table->foreign("Company", "CompanyID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20191206163423.php b/database/migrations/model/Version20191206163423.php new file mode 100644 index 00000000..b2ba1bc2 --- /dev/null +++ b/database/migrations/model/Version20191206163423.php @@ -0,0 +1,58 @@ +hasTable("SummitBadgeType_BadgeFeatures")) { + $builder->create("SummitBadgeType_BadgeFeatures", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->integer("SummitBadgeTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitBadgeTypeID", "SummitBadgeTypeID"); + + $table->integer("SummitBadgeFeatureTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitBadgeFeatureTypeID", "SummitBadgeFeatureTypeID"); + + $table->unique(['SummitBadgeTypeID', 'SummitBadgeFeatureTypeID']); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + if ($builder->hasTable("SummitBadgeType_BadgeFeatures")) { + $builder->drop("SummitBadgeType_BadgeFeatures"); + } + } +} diff --git a/database/migrations/model/Version20191220223248.php b/database/migrations/model/Version20191220223248.php new file mode 100644 index 00000000..bb9020f5 --- /dev/null +++ b/database/migrations/model/Version20191220223248.php @@ -0,0 +1,52 @@ +hasTable("SummitAttendee") && !$builder->hasColumn("SummitAttendee", "Status")) { + $builder->table("SummitAttendee", function (Table $table) { + $table->string("Status", 255)->setNotnull(false)->setDefault(SummitAttendee::StatusIncomplete); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if ($builder->hasTable("SummitAttendee") && !$builder->hasColumn("SummitAttendee", "Status")) { + $builder->table("SummitAttendee", function (Table $table) { + $table->dropColumn("Status"); + }); + } + } +} diff --git a/database/migrations/model/Version20191220223253.php b/database/migrations/model/Version20191220223253.php new file mode 100644 index 00000000..abd81ad6 --- /dev/null +++ b/database/migrations/model/Version20191220223253.php @@ -0,0 +1,48 @@ +addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20191224021722.php b/database/migrations/model/Version20191224021722.php new file mode 100644 index 00000000..554713b2 --- /dev/null +++ b/database/migrations/model/Version20191224021722.php @@ -0,0 +1,63 @@ +hasTable("SummitAttendee") && !$builder->hasColumn("SummitAttendee", "LastReminderEmailSentDate")) { + $builder->table("SummitAttendee", function (Table $table) { + $table->timestamp("LastReminderEmailSentDate")->setNotnull(false); + }); + } + + if ($builder->hasTable("SummitOrder") && !$builder->hasColumn("SummitOrder", "LastReminderEmailSentDate")) { + $builder->table("SummitOrder", function (Table $table) { + $table->timestamp("LastReminderEmailSentDate")->setNotnull(false); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if ($builder->hasTable("SummitAttendee") && $builder->hasColumn("SummitAttendee", "LastReminderEmailSentDate")) { + $builder->table("SummitAttendee", function (Table $table) { + $table->dropColumn("LastReminderEmailSentDate"); + }); + } + + if ($builder->hasTable("SummitOrder") && $builder->hasColumn("SummitOrder", "LastReminderEmailSentDate")) { + $builder->table("SummitOrder", function (Table $table) { + $table->dropColumn("LastReminderEmailSentDate"); + }); + } + } +} diff --git a/database/migrations/model/Version20191224022307.php b/database/migrations/model/Version20191224022307.php new file mode 100644 index 00000000..d3ebdf20 --- /dev/null +++ b/database/migrations/model/Version20191224022307.php @@ -0,0 +1,53 @@ +hasTable("Summit") && !$builder->hasColumn("Summit", "RegistrationReminderEmailsDaysInterval")) { + $builder->table("Summit", function (Table $table) { + $table->integer("RegistrationReminderEmailsDaysInterval")->setNotnull(false); + }); + } + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + $builder = new Builder($schema); + + if ($builder->hasTable("Summit") && $builder->hasColumn("Summit", "RegistrationReminderEmailsDaysInterval")) { + $builder->table("Summit", function (Table $table) { + $table->dropColumn("RegistrationReminderEmailsDaysInterval"); + }); + } + } +} diff --git a/database/migrations/model/Version20191229173636.php b/database/migrations/model/Version20191229173636.php new file mode 100644 index 00000000..b82e85d9 --- /dev/null +++ b/database/migrations/model/Version20191229173636.php @@ -0,0 +1,58 @@ +addSql($sql); + + $sql = <<addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $sql = <<addSql($sql); + $sql = <<addSql($sql); + } +} diff --git a/database/migrations/model/Version20200109171923.php b/database/migrations/model/Version20200109171923.php new file mode 100644 index 00000000..c9195cb5 --- /dev/null +++ b/database/migrations/model/Version20200109171923.php @@ -0,0 +1,52 @@ +hasTable("Summit") && !$builder->hasColumn("Summit", "RegistrationSlugPrefix")) { + $builder->table("Summit", function (Table $table) { + $table->string("RegistrationSlugPrefix")->setNotnull(false)->setDefault(null); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if ($builder->hasTable("Summit") && $builder->hasColumn("Summit", "RegistrationSlugPrefix")) { + $builder->table("Summit", function (Table $table) { + $table->dropColumn("RegistrationSlugPrefix"); + }); + } + } +} diff --git a/database/migrations/model/Version20200110184019.php b/database/migrations/model/Version20200110184019.php new file mode 100644 index 00000000..0888f7bb --- /dev/null +++ b/database/migrations/model/Version20200110184019.php @@ -0,0 +1,55 @@ +hasTable("SummitAttendeeTicketFormerHash")) { + $builder->create("SummitAttendeeTicketFormerHash", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string("Hash", 255)->setNotnull(false); + $table->unique("Hash", "Hash"); + $table->integer("SummitAttendeeTicketID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitAttendeeTicketID", "SummitAttendeeTicketID"); + $table->foreign("SummitAttendeeTicket", "SummitAttendeeTicketID", "ID", ["onDelete" => "CASCADE"]); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + $builder->dropIfExists("SummitAttendeeTicketFormerHash"); + } +} diff --git a/database/migrations/model/Version20200123133515.php b/database/migrations/model/Version20200123133515.php new file mode 100644 index 00000000..7ea1bac5 --- /dev/null +++ b/database/migrations/model/Version20200123133515.php @@ -0,0 +1,100 @@ +hasTable("SummitAttendeeBadge") && $builder->hasColumn("SummitAttendeeBadge", "PrintedTimes")) { + $builder->table("SummitAttendeeBadge", function (Table $table) { + $table->dropColumn("PrintedTimes"); + $table->dropColumn("PrintDate"); + }); + } + + if (!$builder->hasTable("SummitAttendeeBadgePrint")) { + $builder->create("SummitAttendeeBadgePrint", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + + $table->timestamp('PrintDate')->setNotnull(false); + + $table->integer("BadgeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("BadgeID", "BadgeID"); + $table->foreign("SummitAttendeeBadge", "BadgeID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("RequestorID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("RequestorID", "RequestorID"); + $table->foreign("Member", "RequestorID", "ID", ["onDelete" => "CASCADE"]); + + }); + } + + if (!$builder->hasTable("SummitAttendeeBadgePrintRule")) { + $builder->create("SummitAttendeeBadgePrintRule", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + + $table->integer('MaxPrintTimes',false, false)->setNotnull(true)->setDefault(0); + + $table->integer("GroupID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("GroupID", "GroupID"); + $table->foreign("Group", "GroupID", "ID", ["onDelete" => "CASCADE"]); + + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if ($builder->hasTable("SummitAttendeeBadge") && !$builder->hasColumn("SummitAttendeeBadge", "PrintedTimes")) { + $builder->table("SummitAttendeeBadge", function (Table $table) { + $table->timestamp('PrintDate')->setNotnull(false); + $table->integer("PrintedTimes")->setNotnull(false)->setDefault(0); + }); + } + + $builder->dropIfExists("SummitAttendeeBadgePrint"); + + $builder->dropIfExists("SummitAttendeeBadgePrintRule"); + } +} diff --git a/database/migrations/model/Version20200128184149.php b/database/migrations/model/Version20200128184149.php new file mode 100644 index 00000000..ff34fbe4 --- /dev/null +++ b/database/migrations/model/Version20200128184149.php @@ -0,0 +1,88 @@ +hasTable("PaymentGatewayProfile")) { + $builder->create("PaymentGatewayProfile", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + $table->string('ApplicationType'); + $table->string('Provider'); + $table->boolean("IsActive"); + + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + + }); + } + + if (!$builder->hasTable("StripePaymentProfile")) { + $builder->create("StripePaymentProfile", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->foreign("PaymentGatewayProfile", "ID", "ID", ["onDelete" => "CASCADE"]); + + $table->boolean("IsTestModeEnabled")->setDefault(false); + + /** + * Stripe isn’t exclusively in test or live mode at any given point in time. + * Instead, Stripe stores test and live transactions and other data completely separate from each other. + */ + + $table->text("LiveSecretKey")->setDefault('NULL')->setNotnull(false); + $table->text("LivePublishableKey")->setDefault('NULL')->setNotnull(false); + $table->text("LiveWebHookSecretKey")->setDefault('NULL')->setNotnull(false); + $table->text("LiveWebHookId")->setDefault('NULL')->setNotnull(false); + + $table->text("TestSecretKey")->setDefault('NULL')->setNotnull(false); + $table->text("TestPublishableKey")->setDefault('NULL')->setNotnull(false); + $table->text("TestWebHookSecretKey")->setDefault('NULL')->setNotnull(false); + $table->text("TestWebHookId")->setDefault('NULL')->setNotnull(false); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + $builder->dropIfExists("StripePaymentProfile"); + + $builder->dropIfExists("PaymentGatewayProfile"); + } +} diff --git a/database/migrations/model/Version20200128191140.php b/database/migrations/model/Version20200128191140.php new file mode 100644 index 00000000..77e6c59c --- /dev/null +++ b/database/migrations/model/Version20200128191140.php @@ -0,0 +1,73 @@ +addSql($sql); + + // make enum + $sql = <<addSql($sql); + + // make enum + $sql = <<addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20200212023535.php b/database/migrations/model/Version20200212023535.php new file mode 100644 index 00000000..90bc137f --- /dev/null +++ b/database/migrations/model/Version20200212023535.php @@ -0,0 +1,49 @@ +addSql($sql); + + $sql = <<addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20200403191418.php b/database/migrations/model/Version20200403191418.php new file mode 100644 index 00000000..977e4d14 --- /dev/null +++ b/database/migrations/model/Version20200403191418.php @@ -0,0 +1,42 @@ +addSql($sentence); + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20200512132942.php b/database/migrations/model/Version20200512132942.php new file mode 100644 index 00000000..003e4ad1 --- /dev/null +++ b/database/migrations/model/Version20200512132942.php @@ -0,0 +1,90 @@ +hasTable("SummitEmailFlowType")) { + $builder->create("SummitEmailFlowType", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + $table->string('Name'); + + }); + + $builder->create("SummitEmailEventFlowType", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + $table->string('Slug'); + $table->string('Name'); + $table->string('DefaultEmailTemplateIdentifier'); + $table->integer("SummitEmailFlowTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitEmailFlowTypeID", "SummitEmailFlowTypeID"); + $table->foreign("SummitEmailFlowType", "SummitEmailFlowTypeID", "ID", ["onDelete" => "CASCADE"]); + }); + + $builder->create("SummitEmailEventFlow", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + $table->string('EmailTemplateIdentifier'); + $table->integer("SummitEmailEventFlowTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitEmailEventFlowTypeID", "SummitEmailEventFlowTypeID"); + $table->foreign("SummitEmailEventFlowType", "SummitEmailEventFlowTypeID", "ID", ["onDelete" => "CASCADE"]); + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + $builder->dropIfExists("SummitEmailEventFlow"); + + $builder->dropIfExists("SummitEmailEventFlowType"); + + $builder->dropIfExists("SummitEmailFlowType"); + } +} diff --git a/database/migrations/model/Version20200512174027.php b/database/migrations/model/Version20200512174027.php new file mode 100644 index 00000000..e484168a --- /dev/null +++ b/database/migrations/model/Version20200512174027.php @@ -0,0 +1,54 @@ +addSql($sentence); + + $sentence = <<addSql($sentence); + + $sentence = <<addSql($sentence); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20200523235306.php b/database/migrations/model/Version20200523235306.php new file mode 100644 index 00000000..5991a785 --- /dev/null +++ b/database/migrations/model/Version20200523235306.php @@ -0,0 +1,52 @@ +hasTable("Summit") && !$builder->hasColumn("Summit", "DefaultPageUrl")) { + $builder->table('Summit', function (Table $table) { + $table->text("DefaultPageUrl")->setNotnull(false); + $table->text("SpeakerConfirmationDefaultPageUrl")->setNotnull(false); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + $builder = new Builder($schema); + if($schema->hasTable("Summit") && $builder->hasColumn("Summit", "DefaultPageUrl")) { + $builder->table('Summit', function (Table $table) { + $table->dropColumn("DefaultPageUrl"); + $table->dropColumn("SpeakerConfirmationDefaultPageUrl"); + }); + } + } +} diff --git a/database/migrations/model/Version20200526174904.php b/database/migrations/model/Version20200526174904.php new file mode 100644 index 00000000..0a6821bd --- /dev/null +++ b/database/migrations/model/Version20200526174904.php @@ -0,0 +1,78 @@ +hasTable("SummitDocument")) { + $builder->create("SummitDocument", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + $table->string('Name'); + $table->string('Description'); + $table->string('Label'); + $table->integer("FileID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("FileID", "FileID"); + $table->foreign("File", "FileID", "ID", ["onDelete" => "CASCADE"]); + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + }); + } + + if (!$builder->hasTable("SummitDocument_EventTypes")) { + $builder->create("SummitDocument_EventTypes", function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->integer("SummitDocumentID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitDocumentID", "SummitDocumentID"); + + $table->integer("SummitEventTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitEventTypeID", "SummitEventTypeID"); + + $table->unique(['SummitDocumentID', 'SummitEventTypeID']); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + $builder->dropIfExists("SummitDocument_EventTypes"); + + $builder->dropIfExists("SummitDocument"); + } +} diff --git a/database/migrations/model/Version20200601211446.php b/database/migrations/model/Version20200601211446.php new file mode 100644 index 00000000..2126dbea --- /dev/null +++ b/database/migrations/model/Version20200601211446.php @@ -0,0 +1,52 @@ +hasTable("SummitEvent") && !$builder->hasColumn("SummitEvent", "StreamingUrl")) { + $builder->table('SummitEvent', function (Table $table) { + $table->text("StreamingUrl")->setNotnull(false); + $table->text("EtherpadLink")->setNotnull(false); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + if($schema->hasTable("SummitEvent") && $builder->hasColumn("SummitEvent", "StreamingUrl")) { + $builder->table('SummitEvent', function (Table $table) { + $table->dropColumn("StreamingUrl"); + $table->dropColumn("EtherpadLink"); + }); + } + } +} diff --git a/database/migrations/model/Version20200602212951.php b/database/migrations/model/Version20200602212951.php new file mode 100644 index 00000000..6aef21cf --- /dev/null +++ b/database/migrations/model/Version20200602212951.php @@ -0,0 +1,80 @@ +hasTable("SummitRegistrationInvitation")) { + + $builder->create("SummitRegistrationInvitation", function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + + $table->string("Hash", 255)->setNotnull(false); + $table->unique("Hash", "Hash"); + $table->timestamp("AcceptedDate")->setNotnull(false); + $table->string('Email')->setLength(255)->setNotnull(true); + $table->string('FirstName')->setLength(100)->setNotnull(true); + $table->string('LastName')->setLength(100)->setNotnull(true); + $table->string('SetPasswordLink')->setLength(255)->setNotnull(false); + // FK + + $table->integer("MemberID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("MemberID", "MemberID"); + $table->foreign("Member", "MemberID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitOrderID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitOrderID", "SummitOrderID"); + $table->foreign("SummitOrder", "SummitOrderID", "ID", ["onDelete" => "CASCADE"]); + + // Index + + $table->unique(["Email", "SummitID"]); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + $builder->dropIfExists("SummitRegistrationInvitation"); + + } +} diff --git a/database/migrations/model/Version20200609105105.php b/database/migrations/model/Version20200609105105.php new file mode 100644 index 00000000..705f7372 --- /dev/null +++ b/database/migrations/model/Version20200609105105.php @@ -0,0 +1,50 @@ +hasTable("SummitEvent") && !$builder->hasColumn("SummitEvent", "MeetingUrl")) { + $builder->table('SummitEvent', function (Table $table) { + $table->text("MeetingUrl")->setNotnull(false); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + if($schema->hasTable("SummitEvent") && $builder->hasColumn("SummitEvent", "MeetingUrl")) { + $builder->table('SummitEvent', function (Table $table) { + $table->dropColumn("MeetingUrl"); + }); + } + } +} diff --git a/database/migrations/model/Version20200616144713.php b/database/migrations/model/Version20200616144713.php new file mode 100644 index 00000000..cc31f76e --- /dev/null +++ b/database/migrations/model/Version20200616144713.php @@ -0,0 +1,45 @@ +addSql($sql); + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20200618192655.php b/database/migrations/model/Version20200618192655.php new file mode 100644 index 00000000..462955cb --- /dev/null +++ b/database/migrations/model/Version20200618192655.php @@ -0,0 +1,96 @@ +hasTable("SummitAdministratorPermissionGroup")) { + $builder->create('SummitAdministratorPermissionGroup', function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + $table->string('Title')->setNotnull(true); + $table->unique(['Title']); + }); + } + + if(!$schema->hasTable("SummitAdministratorPermissionGroup_Members")) { + $builder->create('SummitAdministratorPermissionGroup_Members', function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + + // FK + $table->integer("MemberID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("MemberID", "MemberID"); + //$table->foreign("Member", "MemberID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitAdministratorPermissionGroupID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitAdministratorPermissionGroupID", "SummitAdministratorPermissionGroupID"); + //$table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + + $table->unique(['SummitAdministratorPermissionGroupID', 'MemberID']); + }); + } + + if(!$schema->hasTable("SummitAdministratorPermissionGroup_Summits")) { + $builder->create('SummitAdministratorPermissionGroup_Summits', function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + + // FK + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + //$table->foreign("Member", "MemberID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitAdministratorPermissionGroupID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitAdministratorPermissionGroupID", "SummitAdministratorPermissionGroupID"); + //$table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + + $table->unique(['SummitAdministratorPermissionGroupID', 'SummitID']); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + $builder = new Builder($schema); + $builder->dropIfExists("SummitAdministratorPermissionGroup_Members"); + $builder->dropIfExists("SummitAdministratorPermissionGroup_Summits"); + $builder->dropIfExists("SummitAdministratorPermissionGroup"); + } +} diff --git a/database/migrations/model/Version20200623191130.php b/database/migrations/model/Version20200623191130.php new file mode 100644 index 00000000..f383d384 --- /dev/null +++ b/database/migrations/model/Version20200623191130.php @@ -0,0 +1,44 @@ +addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20200623191331.php b/database/migrations/model/Version20200623191331.php new file mode 100644 index 00000000..e076fc7f --- /dev/null +++ b/database/migrations/model/Version20200623191331.php @@ -0,0 +1,67 @@ +hasTable("SummitEventAttendanceMetric")) { + $builder->create('SummitEventAttendanceMetric', function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + + $table->timestamp('IngressDate')->setNotnull(false); + $table->timestamp('OutgressDate')->setNotnull(false); + // FK + + $table->integer("MemberID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("MemberID", "MemberID"); + $table->foreign("Member", "MemberID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitEventID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitEventID", "SummitEventID"); + $table->foreign("SummitEvent", "SummitEventID", "ID", ["onDelete" => "CASCADE"]); + + $table->index(['MemberID', 'SummitEventID' ]); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + $builder->dropIfExists('SummitEventAttendanceMetric'); + } +} diff --git a/database/migrations/model/Version20200623191754.php b/database/migrations/model/Version20200623191754.php new file mode 100644 index 00000000..c696b96a --- /dev/null +++ b/database/migrations/model/Version20200623191754.php @@ -0,0 +1,44 @@ +addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20200624132001.php b/database/migrations/model/Version20200624132001.php new file mode 100644 index 00000000..7eab433f --- /dev/null +++ b/database/migrations/model/Version20200624132001.php @@ -0,0 +1,54 @@ +hasTable("Group") && !$builder->hasColumn("Group", "IsExternal")) { + $builder->table('Group', function (Table $table) { + $table->boolean('IsExternal')->setDefault(false); + }); + } + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + $builder = new Builder($schema); + + if($schema->hasTable("Group") && $builder->hasColumn("Group", "IsExternal")) { + $builder->table('Group', function (Table $table) { + $table->dropColumn("IsExternal"); + }); + } + } +} diff --git a/database/migrations/model/Version20200629142643.php b/database/migrations/model/Version20200629142643.php new file mode 100644 index 00000000..0205541d --- /dev/null +++ b/database/migrations/model/Version20200629142643.php @@ -0,0 +1,57 @@ +hasTable("PresentationSpeaker") && !$builder->hasColumn("PresentationSpeaker", "BigPhotoID")) { + $builder->table('PresentationSpeaker', function (Table $table) { + + $table->integer("BigPhotoID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("BigPhotoID", "BigPhotoID"); + $table->foreign("File", "BigPhotoID", "ID", ["onDelete" => "CASCADE"]); + + }); + } + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if($schema->hasTable("PresentationSpeaker") && $builder->hasColumn("PresentationSpeaker", "BigPhotoID")) { + $builder->table('PresentationSpeaker', function (Table $table) { + $table->dropColumn("BigPhotoID"); + }); + } + } +} diff --git a/database/migrations/model/Version20200629143447.php b/database/migrations/model/Version20200629143447.php new file mode 100644 index 00000000..23537b0d --- /dev/null +++ b/database/migrations/model/Version20200629143447.php @@ -0,0 +1,57 @@ +hasTable("SummitEvent") && !$builder->hasColumn("SummitEvent", "ImageID")) { + $builder->table('SummitEvent', function (Table $table) { + + $table->integer("ImageID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("ImageID", "ImageID"); + $table->foreign("File", "ImageID", "ID", ["onDelete" => "CASCADE"]); + + }); + } + + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if($schema->hasTable("SummitEvent") && $builder->hasColumn("SummitEvent", "ImageID")) { + $builder->table('SummitEvent', function (Table $table) { + $table->dropColumn("ImageID"); + }); + } + } +} diff --git a/database/migrations/model/Version20200713164340.php b/database/migrations/model/Version20200713164340.php new file mode 100644 index 00000000..f2f00bd6 --- /dev/null +++ b/database/migrations/model/Version20200713164340.php @@ -0,0 +1,128 @@ +hasTable("SummitMediaFileType")) { + $builder->create('SummitMediaFileType', function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + + $table->string('Name'); + $table->string('Description')->setNotnull(false); + $table->boolean("IsSystemDefine"); + $table->string('AllowedExtensions'); + + $table->unique(['Name']); + }); + } + + if(!$schema->hasTable("SummitMediaUploadType")) { + $builder->create('SummitMediaUploadType', function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->timestamp('Created'); + $table->timestamp('LastEdited'); + $table->string('ClassName'); + + $table->string('Name'); + $table->string('Description')->setNotnull(false); + $table->integer("MaxSize")->setDefault(1024); + $table->boolean("IsMandatory")->setDefault(false); + $table->string('PrivateStorageType'); + $table->string('PublicStorageType'); + + // FK + + $table->integer("SummitID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitID", "SummitID"); + $table->foreign("Summit", "SummitID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("TypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("TypeID", "TypeID"); + $table->foreign("SummitMediaFileType", "TypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->index(['SummitID']); + $table->index(['TypeID']); + $table->unique(['SummitID', 'Name']); + }); + } + + if(!$schema->hasTable("PresentationType_SummitMediaUploadType")) { + $builder->create('PresentationType_SummitMediaUploadType', function (Table $table) { + + $table->integer("ID", true, false); + $table->primary("ID"); + + $table->integer("PresentationTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("PresentationTypeID", "PresentationTypeID"); + //$table->foreign("PresentationType", "PresentationTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->integer("SummitMediaUploadTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitMediaUploadTypeID", "SummitMediaUploadTypeID"); + //$table->foreign("SummitMediaUploadType", "SummitMediaUploadTypeID", "ID", ["onDelete" => "CASCADE"]); + + $table->unique(['PresentationTypeID', 'SummitMediaUploadTypeID']); + }); + } + + if(!$schema->hasTable("PresentationMediaUpload")) { + $builder->create('PresentationMediaUpload', function (Table $table) { + $table->integer("ID", true, false); + $table->primary("ID"); + $table->string('FileName'); + + $table->integer("SummitMediaUploadTypeID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SummitMediaUploadTypeID", "SummitMediaUploadTypeID"); + $table->foreign("SummitMediaUploadType", "SummitMediaUploadTypeID", "ID", ["onDelete" => "CASCADE"]); + + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + $builder->dropIfExists('PresentationMediaUpload'); + $builder->dropIfExists('PresentationType_SummitMediaUploadType'); + $builder->dropIfExists('SummitMediaUploadType'); + $builder->dropIfExists('SummitMediaFileType'); + } +} diff --git a/database/migrations/model/Version20200713164344.php b/database/migrations/model/Version20200713164344.php new file mode 100644 index 00000000..9215d356 --- /dev/null +++ b/database/migrations/model/Version20200713164344.php @@ -0,0 +1,80 @@ +addSql($sql); + + // make enum + $sql = <<addSql($sql); + + // make enum + $sql = <<addSql($sql); + + // make enum + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + } +} diff --git a/database/migrations/model/Version20200730135823.php b/database/migrations/model/Version20200730135823.php new file mode 100644 index 00000000..96e1fca2 --- /dev/null +++ b/database/migrations/model/Version20200730135823.php @@ -0,0 +1,54 @@ +hasTable("Summit") && !$builder->hasColumn("Summit", "VirtualSiteUrl")) { + $builder->table('Summit', function (Table $table) { + $table->string("VirtualSiteUrl")->setNotnull(false); + $table->string("MarketingSiteUrl")->setNotnull(false); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + + if($schema->hasTable("Summit") && $builder->hasColumn("Summit", "VirtualSiteUrl")) { + $builder->table('Summit', function (Table $table) { + $table->dropColumn("VirtualSiteUrl"); + $table->dropColumn("MarketingSiteUrl"); + }); + } + } +} diff --git a/database/migrations/model/Version20200817180752.php b/database/migrations/model/Version20200817180752.php new file mode 100644 index 00000000..a082be91 --- /dev/null +++ b/database/migrations/model/Version20200817180752.php @@ -0,0 +1,56 @@ +sm->listTableIndexes("Member"); + if(array_key_exists("ExternalUserId", $indexes)) + $this->sm->dropIndex("ExternalUserId", "Member"); + + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + + $sql = <<addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + + } +} diff --git a/database/migrations/model/Version20200818120409.php b/database/migrations/model/Version20200818120409.php new file mode 100644 index 00000000..5ae7036d --- /dev/null +++ b/database/migrations/model/Version20200818120409.php @@ -0,0 +1,51 @@ +hasTable("PresentationSpeaker") && !$builder->hasColumn("PresentationSpeaker",'Company')) { + $builder->table('PresentationSpeaker', function (Table $table) { + $table->text("Company")->setNotnull(false)->setLength(255); + $table->text("PhoneNumber")->setNotnull(false)->setLength(255); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + if($builder->hasTable("PresentationSpeaker") && $builder->hasColumn("PresentationSpeaker",'Company')) { + $builder->table('PresentationSpeaker', function (Table $table) { + $table->dropColumn("Company"); + $table->dropColumn("PhoneNumber"); + }); + } + } +} diff --git a/database/migrations/model/Version20200824140528.php b/database/migrations/model/Version20200824140528.php new file mode 100644 index 00000000..e2fd2248 --- /dev/null +++ b/database/migrations/model/Version20200824140528.php @@ -0,0 +1,49 @@ +hasTable("Member") && !$builder->hasColumn("Member","ExternalPic") ) { + $builder->table('Member', function (Table $table) { + $table->string('ExternalPic')->setNotnull(false)->setLength(512); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + if($schema->hasTable("Member") && $builder->hasColumn("Member","ExternalPic") ) { + $builder->table('Member', function (Table $table) { + $table->dropColumn('ExternalPic'); + }); + } + } +} diff --git a/database/migrations/model/Version20200831193516.php b/database/migrations/model/Version20200831193516.php new file mode 100644 index 00000000..2e158290 --- /dev/null +++ b/database/migrations/model/Version20200831193516.php @@ -0,0 +1,51 @@ +hasTable("Summit") && !$builder->hasColumn("Summit","MarketingSiteOAuth2ClientId") ) { + $builder->table('Summit', function (Table $table) { + $table->string('MarketingSiteOAuth2ClientId')->setNotnull(false)->setLength(255); + $table->string('VirtualSiteOAuth2ClientId')->setNotnull(false)->setLength(255); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + if($schema->hasTable("Summit") && $builder->hasColumn("Summit","MarketingSiteOAuth2ClientId") ) { + $builder->table('Summit', function (Table $table) { + $table->dropColumn('MarketingSiteOAuth2ClientId'); + $table->dropColumn('VirtualSiteOAuth2ClientId'); + }); + } + } +} diff --git a/database/migrations/model/Version20200901160152.php b/database/migrations/model/Version20200901160152.php new file mode 100644 index 00000000..f5e8db33 --- /dev/null +++ b/database/migrations/model/Version20200901160152.php @@ -0,0 +1,49 @@ +hasTable("Summit") && !$builder->hasColumn("Summit","SupportEmail") ) { + $builder->table('Summit', function (Table $table) { + $table->string('SupportEmail')->setNotnull(false)->setLength(255); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + if($schema->hasTable("Summit") && $builder->hasColumn("Summit","SupportEmail") ) { + $builder->table('Summit', function (Table $table) { + $table->dropColumn('SupportEmail'); + }); + } + } +} diff --git a/database/migrations/model/Version20200904155247.php b/database/migrations/model/Version20200904155247.php new file mode 100644 index 00000000..6ccefc29 --- /dev/null +++ b/database/migrations/model/Version20200904155247.php @@ -0,0 +1,37 @@ +hasTable("PresentationCategory") && !$builder->hasColumn("PresentationCategory","Color") ) { + $builder->table('PresentationCategory', function (Table $table) { + $table->string('Color')->setNotnull(false)->setLength(50); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $builder = new Builder($schema); + if($schema->hasTable("PresentationCategory") && $builder->hasColumn("PresentationCategory","Color") ) { + $builder->table('PresentationCategory', function (Table $table) { + $table->dropColumn('Color'); + }); + } + } +} diff --git a/database/migrations/model/Version20200910184756.php b/database/migrations/model/Version20200910184756.php new file mode 100644 index 00000000..593f61bb --- /dev/null +++ b/database/migrations/model/Version20200910184756.php @@ -0,0 +1,32 @@ +addSql($sql); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $sql = <<addSql($sql); + + } +} diff --git a/database/seeds/ApiEndpointsSeeder.php b/database/seeds/ApiEndpointsSeeder.php index ac22d761..3e8fc886 100644 --- a/database/seeds/ApiEndpointsSeeder.php +++ b/database/seeds/ApiEndpointsSeeder.php @@ -41,6 +41,8 @@ class ApiEndpointsSeeder extends Seeder $this->seedRegistrationOrderEndpoints(); $this->seedAttendeeTicketsEndpoints(); $this->seedAttendeeBadgesEndpoints(); + $this->seedSummitAdministratorGroupsEndpoints(); + $this->seedSummitMediaFileTypeEndpoints(); } private function seedAttendeeBadgesEndpoints(){ @@ -302,6 +304,7 @@ class ApiEndpointsSeeder extends Seeder } private function seedRegistrationOrderEndpoints(){ + $current_realm = Config::get('app.scope_base_realm'); $this->seedApiEndpoints('summits', [ @@ -492,6 +495,21 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::UpdateMyRegistrationOrders, $current_realm), ], ], + [ + 'name' => 'resend-order', + 'route' => '/api/v1/summits/all/orders/{order_id}/resend', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::UpdateRegistrationOrders, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], [ 'name' => 'revoke-attendee-from-my-order', 'route' => '/api/v1/summits/all/orders/{order_id}/tickets/{ticket_id}/attendee', @@ -509,11 +527,13 @@ class ApiEndpointsSeeder extends Seeder ], ], [ - 'name' => 'reinvite-attendee-from-my-order', + 'name' => 'reinvite-attendee-from-order', 'route' => '/api/v1/summits/all/orders/{order_id}/tickets/{ticket_id}/attendee/reinvite', 'http_method' => 'PUT', 'scopes' => [ sprintf(SummitScopes::UpdateMyRegistrationOrders, $current_realm), + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::UpdateRegistrationOrders, $current_realm), ], ], [ @@ -577,6 +597,156 @@ class ApiEndpointsSeeder extends Seeder IGroup::SummitRegistrationAdmins ] ], + // invitations + [ + 'name' => 'ingest-registration-invitations', + 'route' => '/api/v1/summits/{id}/registration-invitations/csv', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], + [ + 'name' => 'add-registration-invitation', + 'route' => '/api/v1/summits/{id}/registration-invitations', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], + [ + 'name' => 'send-registration-invitations', + 'route' => '/api/v1/summits/{id}/registration-invitations/all/send', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], + [ + 'name' => 'get-registration-invitations-csv', + 'route' => '/api/v1/summits/{id}/registration-invitations/csv', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm), + sprintf(SummitScopes::ReadRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], + [ + 'name' => 'get-registration-invitations', + 'route' => '/api/v1/summits/{id}/registration-invitations', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm), + sprintf(SummitScopes::ReadRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], + [ + 'name' => 'get-registration-invitation-by-id', + 'route' => '/api/v1/summits/{id}/registration-invitations/{invitation_id}', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm), + sprintf(SummitScopes::ReadRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], + [ + 'name' => 'delete-registration-invitation-by-id', + 'route' => '/api/v1/summits/{id}/registration-invitations/{invitation_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], + [ + 'name' => 'update-registration-invitation', + 'route' => '/api/v1/summits/{id}/registration-invitations/{invitation_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], + [ + 'name' => 'delete-registration-all', + 'route' => '/api/v1/summits/{id}/registration-invitations/all', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WriteRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], + [ + 'name' => 'get-registration-invitation-by-token', + 'route' => '/api/v1/summits/all/registration-invitations/{token}', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadMyRegistrationInvitations, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], ]); } @@ -639,7 +809,6 @@ class ApiEndpointsSeeder extends Seeder 'authz_groups' => [ IGroup::SuperAdmins, IGroup::Administrators, - IGroup::SummitAdministrators, ] ], [ @@ -691,7 +860,6 @@ class ApiEndpointsSeeder extends Seeder 'authz_groups' => [ IGroup::SuperAdmins, IGroup::Administrators, - IGroup::SummitAdministrators, ] ], [ @@ -887,6 +1055,77 @@ class ApiEndpointsSeeder extends Seeder IGroup::SummitAdministrators, ] ], + // payment gateway profiles + [ + 'name' => 'get-payment-gateway-profiles', + 'route' => '/api/v1/summits/{id}/payment-gateway-profiles', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm), + sprintf(SummitScopes::ReadPaymentProfiles, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'add-payment-gateway-profile', + 'route' => '/api/v1/summits/{id}/payment-gateway-profiles', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WritePaymentProfiles, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'get-payment-gateway-profile', + 'route' => '/api/v1/summits/{id}/payment-gateway-profiles/{payment_profile_id}', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm), + sprintf(SummitScopes::ReadPaymentProfiles, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'update-payment-gateway-profile', + 'route' => '/api/v1/summits/{id}/payment-gateway-profiles/{payment_profile_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WritePaymentProfiles, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'delete-payment-gateway-profile', + 'route' => '/api/v1/summits/{id}/payment-gateway-profiles/{payment_profile_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + sprintf(SummitScopes::WritePaymentProfiles, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], // tax types [ 'name' => 'get-tax-types', @@ -1712,6 +1951,15 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::ReadAllSummitData, $current_realm) ], ], + [ + 'name' => 'get-speakers-on-schedule', + 'route' => '/api/v1/summits/{id}/speakers/on-schedule', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadSummitData, $current_realm), + sprintf(SummitScopes::ReadAllSummitData, $current_realm) + ], + ], [ 'name' => 'add-speaker-by-summit', 'route' => '/api/v1/summits/{id}/speakers', @@ -1747,12 +1995,30 @@ class ApiEndpointsSeeder extends Seeder 'scopes' => [ sprintf(SummitScopes::WriteSpeakersData, $current_realm), ], - 'authz_groups' => [ - IGroup::SuperAdmins, - IGroup::Administrators, - IGroup::SummitAdministrators, - IGroup::SummitRegistrationAdmins, - ] + ], + [ + 'name' => 'delete-speaker-photo', + 'route' => '/api/v1/speakers/{speaker_id}/photo', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSpeakersData, $current_realm), + ], + ], + [ + 'name' => 'add-speaker-big-photo', + 'route' => '/api/v1/speakers/{speaker_id}/big-photo', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSpeakersData, $current_realm), + ], + ], + [ + 'name' => 'delete-speaker-big-photo', + 'route' => '/api/v1/speakers/{speaker_id}/big-photo', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSpeakersData, $current_realm), + ], ], [ 'name' => 'add-speaker', @@ -2111,6 +2377,30 @@ class ApiEndpointsSeeder extends Seeder IGroup::SummitRegistrationAdmins, ] ], + [ + 'name' => 'add-event-image', + 'route' => '/api/v1/summits/{id}/events/{event_id}/image', + 'http_method' => 'POST', + 'scopes' => [sprintf(SummitScopes::WriteEventData, $current_realm)], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins, + ] + ], + [ + 'name' => 'delete-event-image', + 'route' => '/api/v1/summits/{id}/events/{event_id}/image', + 'http_method' => 'DELETE', + 'scopes' => [sprintf(SummitScopes::WriteEventData, $current_realm)], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins, + ] + ], [ 'name' => 'clone-event', 'route' => '/api/v1/summits/{id}/events/{event_id}/clone', @@ -3387,6 +3677,35 @@ class ApiEndpointsSeeder extends Seeder IGroup::SummitAdministrators, ] ], + + [ + 'name' => 'add-document-2-event-type', + 'route' => '/api/v1/summits/{id}/event-types/{event_type_id}/summit-documents/{document_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteEventTypeData, $current_realm), + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'remove-document-from-event-type', + 'route' => '/api/v1/summits/{id}/event-types/{event_type_id}/summit-documents/{document_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteEventTypeData, $current_realm), + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], //tracks [ 'name' => 'get-tracks', @@ -3981,6 +4300,52 @@ class ApiEndpointsSeeder extends Seeder IGroup::SummitAdministrators, ] ], + // media uplods + [ + 'name' => 'get-presentation-media-uploads', + 'route' => '/api/v1/summits/{id}/presentations/{presentation_id}/media-uploads', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadSummitData, $current_realm), + sprintf(SummitScopes::ReadAllSummitData, $current_realm) + ], + ], + [ + 'name' => 'get-presentation-media-upload', + 'route' => '/api/v1/summits/{id}/presentations/{presentation_id}/media-uploads/{media_upload_id}', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadSummitData, $current_realm), + sprintf(SummitScopes::ReadAllSummitData, $current_realm) + ], + ], + [ + 'name' => 'create-presentation-media-uploads', + 'route' => '/api/v1/summits/{id}/presentations/{presentation_id}/media-uploads', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WritePresentationMaterialsData, $current_realm), + sprintf(SummitScopes::WritePresentationSlidesData, $current_realm) + ] + ], + [ + 'name' => 'update-presentation-media-uploads', + 'route' => '/api/v1/summits/{id}/presentations/{presentation_id}/media-uploads/{media_upload_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WritePresentationMaterialsData, $current_realm), + sprintf(SummitScopes::WritePresentationSlidesData, $current_realm) + ], + ], + [ + 'name' => 'delete-presentation-media-uploads', + 'route' => '/api/v1/summits/{id}/presentations/{presentation_id}/media-uploads/{media_upload_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WritePresentationMaterialsData, $current_realm), + sprintf(SummitScopes::WritePresentationSlidesData, $current_realm) + ], + ], //members [ 'name' => 'create-schedule-shareable-link', @@ -4075,6 +4440,24 @@ class ApiEndpointsSeeder extends Seeder sprintf(SummitScopes::DeleteMySchedule, $current_realm), ], ], + // enter/leave + [ + 'name' => 'enter-member-to-event', + 'route' => '/api/v1/summits/{id}/members/{member_id}/schedule/{event_id}/enter', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::EnterEvent, $current_realm) + ], + ], + [ + 'name' => 'leave-member-from-event', + 'route' => '/api/v1/summits/{id}/members/{member_id}/schedule/{event_id}/leave', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::LeaveEvent, $current_realm) + ], + ], + // [ 'name' => 'get-member-from-summit', 'route' => '/api/v1/summits/{id}/members', @@ -4469,7 +4852,7 @@ class ApiEndpointsSeeder extends Seeder // selection plans [ 'name' => 'get-current-selection-plan-by-status', - 'route' => '/api/v1/summits/all/selection-plans/current/{status}', + 'route' => '/api/v1/summits/{id}/selection-plans/current/{status}', 'http_method' => 'GET', 'scopes' => [ sprintf(SummitScopes::ReadAllSummitData, $current_realm), @@ -4669,7 +5052,236 @@ class ApiEndpointsSeeder extends Seeder IGroup::SummitAdministrators, ] ], + + // email-flows-events + [ + 'name' => 'get-all-email-flows-events', + 'route' => '/api/v1/summits/{id}/email-flows-events', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'get-email-flows-event-by-id', + 'route' => '/api/v1/summits/{id}/email-flows-events/{event_id}', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'update-email-flows-event', + 'route' => '/api/v1/summits/{id}/email-flows-events/{event_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + // summit documents + [ + 'name' => 'add-summit-document', + 'route' => '/api/v1/summits/{id}/summit-documents', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'get-summit-documents', + 'route' => '/api/v1/summits/{id}/summit-documents', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm) + ], + ], + [ + 'name' => 'get-summit-document', + 'route' => '/api/v1/summits/{id}/summit-documents/{document_id}', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm) + ], + ], + [ + 'name' => 'update-summit-document', + 'route' => '/api/v1/summits/{id}/summit-documents/{document_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'delete-summit-document', + 'route' => '/api/v1/summits/{id}/summit-documents/{document_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'add-event-type-2-summit-document', + 'route' => '/api/v1/summits/{id}/summit-documents/{document_id}/event-types/{event_type_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'remove-event-type-from-summit-document', + 'route' => '/api/v1/summits/{id}/summit-documents/{document_id}/event-types/{event_type_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + // media-upload-types + [ + 'name' => 'get-all-media-upload-types', + 'route' => '/api/v1/summits/{id}/media-upload-types', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'add-media-upload-types', + 'route' => '/api/v1/summits/{id}/media-upload-types', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'get-media-upload-type', + 'route' => '/api/v1/summits/{id}/media-upload-types/{media_upload_type_id}', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'update-media-upload-types', + 'route' => '/api/v1/summits/{id}/media-upload-types/{media_upload_type_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'delete-media-upload-types', + 'route' => '/api/v1/summits/{id}/media-upload-types/{media_upload_type_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'add-event-type-2-media-upload-type', + 'route' => '/api/v1/summits/{id}/media-upload-types/{media_upload_type_id}/presentation-types/{event_type_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'remove-event-type-media-upload-type', + 'route' => '/api/v1/summits/{id}/media-upload-types/{media_upload_type_id}/presentation-types/{event_type_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'clone-media-upload-types', + 'route' => '/api/v1/summits/{id}/media-upload-types/all/clone/{to_summit_id}', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm) + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], ]); + } /** @@ -5126,4 +5738,178 @@ class ApiEndpointsSeeder extends Seeder ); } + public function seedSummitAdministratorGroupsEndpoints(){ + $current_realm = Config::get('app.scope_base_realm'); + + $this->seedApiEndpoints('summit-administrator-groups', [ + [ + 'name' => 'get-summit-administrator-groups', + 'route' => '/api/v1/summit-administrator-groups', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadSummitAdminGroups, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'get-summit-administrator-group', + 'route' => '/api/v1/summit-administrator-groups/{group_id}', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadSummitAdminGroups, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'add-summit-administrator-group', + 'route' => '/api/v1/summit-administrator-groups', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitAdminGroups, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'update-summit-administrator-group', + 'route' => '/api/v1/summit-administrator-groups/{group_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitAdminGroups, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'delete-summit-administrator-group', + 'route' => '/api/v1/summit-administrator-groups/{group_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitAdminGroups, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'add-member-to-summit-administrator-group', + 'route' => '/api/v1/summit-administrator-groups/{group_id}/members/{member_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitAdminGroups, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'remove-member-from-summit-administrator-group', + 'route' => '/api/v1/summit-administrator-groups/{group_id}/members/{member_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitAdminGroups, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'add-summit-to-summit-administrator-group', + 'route' => '/api/v1/summit-administrator-groups/{group_id}/summits/{summit_id}', + 'http_method' => 'PUT', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitAdminGroups, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'remove-summit-from-summit-administrator-group', + 'route' => '/api/v1/summit-administrator-groups/{group_id}/summits/{summit_id}', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitAdminGroups, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + + ] + ); + } + + public function seedSummitMediaFileTypeEndpoints(){ + $current_realm = Config::get('app.scope_base_realm'); + + $this->seedApiEndpoints('summit-media-file-types', [ + [ + 'name' => 'get-summit-media-file-types', + 'route' => '/api/v1/summit-media-file-types', + 'http_method' => 'GET', + 'scopes' => [sprintf(SummitScopes::ReadSummitMediaFileTypes, $current_realm)], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'get-summit-media-file-type-by-id', + 'route' => '/api/v1/summit-media-file-types/{id}', + 'http_method' => 'GET', + 'scopes' => [sprintf(SummitScopes::ReadSummitMediaFileTypes, $current_realm)], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'add-summit-media-file-type', + 'route' => '/api/v1/summit-media-file-types', + 'http_method' => 'POST', + 'scopes' => [sprintf(SummitScopes::WriteSummitMediaFileTypes, $current_realm)], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'update-summit-media-file-type', + 'route' => '/api/v1/summit-media-file-types/{id}', + 'http_method' => 'PUT', + 'scopes' => [sprintf(SummitScopes::WriteSummitMediaFileTypes, $current_realm)], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + [ + 'name' => 'delete-summit-media-file-type', + 'route' => '/api/v1/summit-media-file-types/{id}', + 'http_method' => 'DELETE', + 'scopes' => [sprintf(SummitScopes::WriteSummitMediaFileTypes, $current_realm)], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + ] + ); + } } \ No newline at end of file diff --git a/database/seeds/ApiScopesSeeder.php b/database/seeds/ApiScopesSeeder.php index 89618518..5c578d8a 100644 --- a/database/seeds/ApiScopesSeeder.php +++ b/database/seeds/ApiScopesSeeder.php @@ -37,6 +37,8 @@ final class ApiScopesSeeder extends Seeder $this->seedCompaniesScopes(); $this->seedGroupsScopes(); $this->seedOrganizationScopes(); + $this->seedSummitAdminGroupScopes(); + $this->seedSummitMediaFileTypes(); } private function seedSummitScopes() @@ -71,6 +73,17 @@ final class ApiScopesSeeder extends Seeder 'short_description' => 'Allows to remove Summit events as favorite', 'description' => 'Allows to remove Summit events as favorite', ], + // enter/leave event + [ + 'name' => sprintf(SummitScopes::EnterEvent, $current_realm), + 'short_description' => '', + 'description' => '', + ], + [ + 'name' => sprintf(SummitScopes::LeaveEvent, $current_realm), + 'short_description' => '', + 'description' => '', + ], [ 'name' => sprintf(SummitScopes::AddMyRSVP, $current_realm), 'short_description' => 'Allows to add Summit events as RSVP', @@ -311,6 +324,31 @@ final class ApiScopesSeeder extends Seeder 'short_description' => 'write badge scans', 'description' => 'write badge scans', ], + [ + 'name' => sprintf(SummitScopes::ReadPaymentProfiles, $current_realm), + 'short_description' => 'read summit payment profiles', + 'description' => 'read summit payment profiles', + ], + [ + 'name' => sprintf(SummitScopes::WritePaymentProfiles, $current_realm), + 'short_description' => 'write summit payment profiles', + 'description' => 'write summit payment profiles', + ], + [ + 'name' => sprintf(SummitScopes::WriteRegistrationInvitations, $current_realm), + 'short_description' => 'write summit registration invitation', + 'description' => 'write summit registration invitation', + ], + [ + 'name' => sprintf(SummitScopes::ReadRegistrationInvitations, $current_realm), + 'short_description' => 'read summit registration invitation', + 'description' => 'read summit registration invitation', + ], + [ + 'name' => sprintf(SummitScopes::ReadMyRegistrationInvitations, $current_realm), + 'short_description' => 'read my summit registration invitation', + 'description' => 'read my summit registration invitation', + ], ]; foreach ($scopes as $scope_info) { @@ -519,4 +557,68 @@ final class ApiScopesSeeder extends Seeder EntityManager::flush(); } + private function seedSummitAdminGroupScopes(){ + + $current_realm = Config::get('app.scope_base_realm'); + $api = EntityManager::getRepository(\App\Models\ResourceServer\Api::class)->findOneBy(['name' => 'summit-administrator-groups']); + + $scopes = [ + [ + 'name' => sprintf(SummitScopes::ReadSummitAdminGroups, $current_realm), + 'short_description' => 'Get Summit Admin Groups Data', + 'description' => 'Grants read only access for Summit Admin Groups Data', + ], + [ + 'name' => sprintf(SummitScopes::WriteSummitAdminGroups, $current_realm), + 'short_description' => 'Write Summit Admin Groups Data', + 'description' => 'Grants write access to Summit Admin Groups 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 seedSummitMediaFileTypes(){ + + $current_realm = Config::get('app.scope_base_realm'); + $api = EntityManager::getRepository(\App\Models\ResourceServer\Api::class)->findOneBy(['name' => 'summit-media-file-types']); + + $scopes = [ + [ + 'name' => sprintf(SummitScopes::ReadSummitMediaFileTypes, $current_realm), + 'short_description' => 'Get Summit Media File Types Data', + 'description' => 'Grants read only access for Summit Media File Types Data', + ], + [ + 'name' => sprintf(SummitScopes::WriteSummitMediaFileTypes, $current_realm), + 'short_description' => 'Write Summit Media File Types Data', + 'description' => 'Grants write access to Summit Media File Types 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 53ccca27..53cf869d 100644 --- a/database/seeds/ApiSeeder.php +++ b/database/seeds/ApiSeeder.php @@ -121,5 +121,25 @@ final class ApiSeeder extends Seeder EntityManager::flush(); + // summit administrator groups + + $api = new Api(); + $api->setName('summit-administrator-groups'); + $api->setActive(true); + $api->setDescription('Summit Administrator Groups API'); + + EntityManager::persist($api); + + // summit-media-file-types + + $api = new Api(); + $api->setName('summit-media-file-types'); + $api->setActive(true); + $api->setDescription('Summit Media File Types API'); + + EntityManager::persist($api); + + EntityManager::flush(); + } } \ No newline at end of file diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 1821331c..2e9d3b38 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -22,5 +22,7 @@ final class DatabaseSeeder extends Seeder $this->call('ApiEndpointsSeeder'); // summit $this->call('DefaultEventTypesSeeder'); + $this->call('DefaultPrintRulesSeeder'); + $this->call('SummitMediaFileTypeSeeder'); } } diff --git a/database/seeds/SummitEmailFlowEventSeeder.php b/database/seeds/SummitEmailFlowEventSeeder.php new file mode 100644 index 00000000..237766c1 --- /dev/null +++ b/database/seeds/SummitEmailFlowEventSeeder.php @@ -0,0 +1,35 @@ +getRepository(Summit::class); + foreach ($summit_repository->findAll() as $summit) { + $summit->seedDefaultEmailFlowEvents(); + $em->persist($summit); + } + + $em->flush(); + } + +} \ No newline at end of file diff --git a/database/seeds/SummitEmailFlowTypeSeeder.php b/database/seeds/SummitEmailFlowTypeSeeder.php new file mode 100644 index 00000000..683adcdb --- /dev/null +++ b/database/seeds/SummitEmailFlowTypeSeeder.php @@ -0,0 +1,300 @@ +delete(); + DB::table("SummitEmailEventFlowType")->delete(); + DB::table("SummitEmailEventFlow")->delete(); + + $flow = new SummitEmailFlowType(); + $flow->setName("Registration"); + + self::createEventsTypes([ + [ + 'name' => InviteAttendeeTicketEditionMail::EVENT_NAME, + 'slug' => InviteAttendeeTicketEditionMail::EVENT_SLUG, + 'default_email_template' => InviteAttendeeTicketEditionMail::DEFAULT_TEMPLATE + ], + [ + 'name' => SummitAttendeeTicketRegenerateHashEmail::EVENT_NAME, + 'slug' => SummitAttendeeTicketRegenerateHashEmail::EVENT_SLUG, + 'default_email_template' => SummitAttendeeTicketRegenerateHashEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => RegisteredMemberOrderPaidMail::EVENT_NAME, + 'slug' => RegisteredMemberOrderPaidMail::EVENT_SLUG, + 'default_email_template' => RegisteredMemberOrderPaidMail::DEFAULT_TEMPLATE + ], + [ + 'name' => RevocationTicketEmail::EVENT_NAME, + 'slug' => RevocationTicketEmail::EVENT_SLUG, + 'default_email_template' => RevocationTicketEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => SummitAttendeeTicketEmail::EVENT_NAME, + 'slug' => SummitAttendeeTicketEmail::EVENT_SLUG, + 'default_email_template' => SummitAttendeeTicketEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => UnregisteredMemberOrderPaidMail::EVENT_NAME, + 'slug' => UnregisteredMemberOrderPaidMail::EVENT_SLUG, + 'default_email_template' => UnregisteredMemberOrderPaidMail::DEFAULT_TEMPLATE + ], + // reminders + [ + 'name' => SummitOrderReminderEmail::EVENT_NAME, + 'slug' => SummitOrderReminderEmail::EVENT_SLUG, + 'default_email_template' => SummitOrderReminderEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => SummitTicketReminderEmail::EVENT_NAME, + 'slug' => SummitTicketReminderEmail::EVENT_SLUG, + 'default_email_template' => SummitTicketReminderEmail::DEFAULT_TEMPLATE + ], + // refunds + [ + 'name' => SummitOrderRefundAccepted::EVENT_NAME, + 'slug' => SummitOrderRefundAccepted::EVENT_SLUG, + 'default_email_template' => SummitOrderRefundAccepted::DEFAULT_TEMPLATE + ], + [ + 'name' => SummitOrderRefundRequestAdmin::EVENT_NAME, + 'slug' => SummitOrderRefundRequestAdmin::EVENT_SLUG, + 'default_email_template' => SummitOrderRefundRequestAdmin::DEFAULT_TEMPLATE + ], + [ + 'name' => SummitOrderRefundRequestOwner::EVENT_NAME, + 'slug' => SummitOrderRefundRequestOwner::EVENT_SLUG, + 'default_email_template' => SummitOrderRefundRequestOwner::DEFAULT_TEMPLATE + ], + [ + 'name' => SummitTicketRefundAccepted::EVENT_NAME, + 'slug' => SummitTicketRefundAccepted::EVENT_SLUG, + 'default_email_template' => SummitTicketRefundAccepted::DEFAULT_TEMPLATE + ], + [ + 'name' => SummitTicketRefundRequestAdmin::EVENT_NAME, + 'slug' => SummitTicketRefundRequestAdmin::EVENT_SLUG, + 'default_email_template' => SummitTicketRefundRequestAdmin::DEFAULT_TEMPLATE + ], + [ + 'name' => SummitTicketRefundRequestOwner::EVENT_NAME, + 'slug' => SummitTicketRefundRequestOwner::EVENT_SLUG, + 'default_email_template' => SummitTicketRefundRequestOwner::DEFAULT_TEMPLATE + ], + [ + 'name' => MemberPromoCodeEmail::EVENT_NAME, + 'slug' => MemberPromoCodeEmail::EVENT_SLUG, + 'default_email_template' => MemberPromoCodeEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => SpeakerPromoCodeEMail::EVENT_NAME, + 'slug' => SpeakerPromoCodeEMail::EVENT_SLUG, + 'default_email_template' => SpeakerPromoCodeEMail::DEFAULT_TEMPLATE + ], + [ + 'name' => InviteSummitRegistrationEmail::EVENT_NAME, + 'slug' => InviteSummitRegistrationEmail::EVENT_SLUG, + 'default_email_template' => InviteSummitRegistrationEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => ReInviteSummitRegistrationEmail::EVENT_NAME, + 'slug' => ReInviteSummitRegistrationEmail::EVENT_SLUG, + 'default_email_template' => ReInviteSummitRegistrationEmail::DEFAULT_TEMPLATE + ], + ], $flow); + + $em->persist($flow); + + $flow = new SummitEmailFlowType(); + $flow->setName("Bookable Rooms"); + + self::createEventsTypes([ + [ + 'name' => BookableRoomReservationCanceledEmail::EVENT_NAME, + 'slug' => BookableRoomReservationCanceledEmail::EVENT_SLUG, + 'default_email_template' => BookableRoomReservationCanceledEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => BookableRoomReservationCreatedEmail::EVENT_NAME, + 'slug' => BookableRoomReservationCreatedEmail::EVENT_SLUG, + 'default_email_template' => BookableRoomReservationCreatedEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => BookableRoomReservationPaymentConfirmedEmail::EVENT_NAME, + 'slug' => BookableRoomReservationPaymentConfirmedEmail::EVENT_SLUG, + 'default_email_template' => BookableRoomReservationPaymentConfirmedEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => BookableRoomReservationRefundAcceptedEmail::EVENT_NAME, + 'slug' => BookableRoomReservationRefundAcceptedEmail::EVENT_SLUG, + 'default_email_template' => BookableRoomReservationRefundAcceptedEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => BookableRoomReservationRefundRequestedAdminEmail::EVENT_NAME, + 'slug' => BookableRoomReservationRefundRequestedAdminEmail::EVENT_SLUG, + 'default_email_template' => BookableRoomReservationRefundRequestedAdminEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => BookableRoomReservationRefundRequestedOwnerEmail::EVENT_NAME, + 'slug' => BookableRoomReservationRefundRequestedOwnerEmail::EVENT_SLUG, + 'default_email_template' => BookableRoomReservationRefundRequestedOwnerEmail::DEFAULT_TEMPLATE + ], + ], $flow); + + + $em->persist($flow); + + $flow = new SummitEmailFlowType(); + $flow->setName("Schedule"); + + self::createEventsTypes([ + [ + 'name' => RSVPRegularSeatMail::EVENT_NAME, + 'slug' => RSVPRegularSeatMail::EVENT_SLUG, + 'default_email_template' => RSVPRegularSeatMail::DEFAULT_TEMPLATE + ], + [ + 'name' => RSVPWaitListSeatMail::EVENT_NAME, + 'slug' => RSVPWaitListSeatMail::EVENT_SLUG, + 'default_email_template' => RSVPWaitListSeatMail::DEFAULT_TEMPLATE + ], + [ + 'name' => ShareEventEmail::EVENT_NAME, + 'slug' => ShareEventEmail::EVENT_SLUG, + 'default_email_template' => ShareEventEmail::DEFAULT_TEMPLATE + ], + ], $flow); + + + $em->persist($flow); + + $flow = new SummitEmailFlowType(); + $flow->setName("Presentation Submissions"); + + self::createEventsTypes([ + [ + 'name' => PresentationCreatorNotificationEmail::EVENT_NAME, + 'slug' => PresentationCreatorNotificationEmail::EVENT_SLUG, + 'default_email_template' => PresentationCreatorNotificationEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => PresentationSpeakerNotificationEmail::EVENT_NAME, + 'slug' => PresentationSpeakerNotificationEmail::EVENT_SLUG, + 'default_email_template' => PresentationSpeakerNotificationEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => PresentationSpeakerSelectionProcessAcceptedAlternateEmail::EVENT_NAME, + 'slug' => PresentationSpeakerSelectionProcessAcceptedAlternateEmail::EVENT_SLUG, + 'default_email_template' => PresentationSpeakerSelectionProcessAcceptedAlternateEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => PresentationSpeakerSelectionProcessAcceptedOnlyEmail::EVENT_NAME, + 'slug' => PresentationSpeakerSelectionProcessAcceptedOnlyEmail::EVENT_SLUG, + 'default_email_template' => PresentationSpeakerSelectionProcessAcceptedOnlyEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => PresentationSpeakerSelectionProcessAcceptedRejectedEmail::EVENT_NAME, + 'slug' => PresentationSpeakerSelectionProcessAcceptedRejectedEmail::EVENT_SLUG, + 'default_email_template' => PresentationSpeakerSelectionProcessAcceptedRejectedEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => PresentationSpeakerSelectionProcessAlternateOnlyEmail::EVENT_NAME, + 'slug' => PresentationSpeakerSelectionProcessAlternateOnlyEmail::EVENT_SLUG, + 'default_email_template' => PresentationSpeakerSelectionProcessAlternateOnlyEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => PresentationSpeakerSelectionProcessAlternateRejectedEmail::EVENT_NAME, + 'slug' => PresentationSpeakerSelectionProcessAlternateRejectedEmail::EVENT_SLUG, + 'default_email_template' => PresentationSpeakerSelectionProcessAlternateRejectedEmail::DEFAULT_TEMPLATE + ], + [ + 'name' => PresentationSpeakerSelectionProcessRejectedEmail::EVENT_NAME, + 'slug' => PresentationSpeakerSelectionProcessRejectedEmail::EVENT_SLUG, + 'default_email_template' => PresentationSpeakerSelectionProcessRejectedEmail::DEFAULT_TEMPLATE + ], + + ], $flow); + + $em->persist($flow); + $em->flush(); + } + + /** + * @param array $payload + * @param SummitEmailFlowType $flow + */ + static private function createEventsTypes(array $payload , SummitEmailFlowType $flow){ + foreach($payload as $definition){ + $event_type = new SummitEmailEventFlowType(); + $event_type->setName($definition['name']); + $event_type->setSlug($definition['slug']); + $event_type->setDefaultEmailTemplate($definition['default_email_template']); + $flow->addFlowEventType($event_type); + } + } +} \ No newline at end of file diff --git a/database/seeds/SummitMediaFileTypeSeeder.php b/database/seeds/SummitMediaFileTypeSeeder.php new file mode 100644 index 00000000..5df0c913 --- /dev/null +++ b/database/seeds/SummitMediaFileTypeSeeder.php @@ -0,0 +1,99 @@ +findOneBy(['name' => "Online presence file upload"])) { + $type = new SummitMediaFileType(); + $type->setName("Online presence file upload"); + $type->setDescription("Online presence file upload: JPEG or PNG"); + $type->setAllowedExtensions("JPG|JPEG|PNG"); + $type->markAsSystemDefined(); + $em->persist($type); + } + + if(!$repository->findOneBy(['name' => "Print file upload: PDF, EPS or AI"])) { + $type = new SummitMediaFileType(); + $type->setName("Print file upload: PDF, EPS or AI"); + $type->setDescription("Print file upload: PDF, EPS or AI"); + $type->setAllowedExtensions("EPS|PDF|AI"); + $type->markAsSystemDefined(); + $em->persist($type); + } + + if(!$repository->findOneBy(['name' => "Backdrop file upload: PDF only"])) { + $type = new SummitMediaFileType(); + $type->setName("Backdrop file upload: PDF only"); + $type->setDescription("Backdrop file upload: PDF only"); + $type->setAllowedExtensions("PDF"); + $type->markAsSystemDefined(); + $em->persist($type); + } + + if(!$repository->findOneBy(['name' => "Presentation slides: (Keynote, powerpoint or JPEG)"])) { + $type = new SummitMediaFileType(); + $type->setName("Presentation slides: (Keynote, powerpoint or JPEG)"); + $type->setDescription("Presentation slides: (Keynote, powerpoint or JPEG)"); + $type->setAllowedExtensions("KEYNOTE|JPG|JPEG|PPT|PPTX"); + $type->markAsSystemDefined(); + $em->persist($type); + } + + if(!$repository->findOneBy(['name' => "Video (MOV or MP4)"])) { + $type = new SummitMediaFileType(); + $type->setName("Video (MOV or MP4)"); + $type->setDescription("Video (MOV or MP4)"); + $type->setAllowedExtensions("MOV|MP4"); + $type->markAsSystemDefined(); + $em->persist($type); + } + + if(!$repository->findOneBy(['name' => "Photoshop PSD file or PDF file"])) { + $type = new SummitMediaFileType(); + $type->setName("Photoshop PSD file or PDF file"); + $type->setDescription("Photoshop PSD file or PDF file"); + $type->setAllowedExtensions("PSD|PDF"); + $type->markAsSystemDefined(); + $em->persist($type); + } + + if(!$repository->findOneBy(['name' => "Scalable Vector Graphics file: SVG"])) { + $type = new SummitMediaFileType(); + $type->setName("Scalable Vector Graphics file: SVG"); + $type->setDescription("Scalable Vector Graphics file: SVG"); + $type->setAllowedExtensions("SVG"); + $type->markAsSystemDefined(); + $em->persist($type); + } + + $em->flush(); + } +} \ No newline at end of file diff --git a/database/seeds/TestSeeder.php b/database/seeds/TestSeeder.php index 894773f7..a5bb8a5b 100644 --- a/database/seeds/TestSeeder.php +++ b/database/seeds/TestSeeder.php @@ -28,5 +28,9 @@ final class TestSeeder extends Seeder $this->call('ApiEndpointsSeeder'); // summit $this->call('DefaultEventTypesSeeder'); + $this->call('DefaultPrintRulesSeeder'); + $this->call('SummitEmailFlowTypeSeeder'); + $this->call('SummitEmailFlowEventSeeder'); + $this->call('SummitMediaFileTypeSeeder'); } } \ No newline at end of file diff --git a/database/seeds/summit/DefaultEventTypesSeeder.php b/database/seeds/summit/DefaultEventTypesSeeder.php index 6ac2dc93..15c20575 100644 --- a/database/seeds/summit/DefaultEventTypesSeeder.php +++ b/database/seeds/summit/DefaultEventTypesSeeder.php @@ -12,8 +12,6 @@ * limitations under the License. **/ use Illuminate\Database\Seeder; -use LaravelDoctrine\ORM\Facades\EntityManager; -use Illuminate\Support\Facades\DB; use App\Models\Foundation\Summit\Defaults\DefaultSummitEventType; use App\Models\Foundation\Summit\Defaults\DefaultPresentationType; use LaravelDoctrine\ORM\Facades\Registry; diff --git a/database/seeds/summit/DefaultPrintRulesSeeder.php b/database/seeds/summit/DefaultPrintRulesSeeder.php new file mode 100644 index 00000000..97310f29 --- /dev/null +++ b/database/seeds/summit/DefaultPrintRulesSeeder.php @@ -0,0 +1,55 @@ +getRepository(SummitAttendeeBadgePrintRule::class); + $repo_group = $em->getRepository(Group::class); + $group = $repo_group->getBySlug(IGroup::BadgePrinters); + if(is_null($group)){ + $group = new Group(); + $group->setTitle(IGroup::BadgePrinters); + $group->setCode(IGroup::BadgePrinters); + $group->setDescription(IGroup::BadgePrinters); + $em->persist($group); + $em->flush(); + } + $repo->deleteAll(); + + $em->flush(); + + $rule1 = new SummitAttendeeBadgePrintRule(); + $rule1->setMaxPrintTimes(1); + $rule1->setGroup($group); + + $em->persist($rule1); + $em->flush(); + } +} \ No newline at end of file diff --git a/migrate.sh b/migrate.sh new file mode 100755 index 00000000..df3d9d2c --- /dev/null +++ b/migrate.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +php artisan doctrine:migrations:migrate --connection=config +php artisan doctrine:migrations:migrate --connection=model \ No newline at end of file diff --git a/readme.md b/readme.md index 046034dd..c78a4c1d 100644 --- a/readme.md +++ b/readme.md @@ -34,6 +34,10 @@ Laravel may require some permissions to be configured: folders within storage an php artisan doctrine:schema:create --sql --em=model > ss.sql +## validate SS schema + +php artisan doctrine:schema:validate + ## Doctrine Migrations # For Config Storage @@ -56,4 +60,11 @@ php artisan doctrine:migrations:generate --connection=model --create= - - - - - -

- Dear {!! $owner_fullname !!} -

-

- Your Reservation for room {!! $room_complete_name !!} got canceled because you did not take any action to pay it. -

-

-

    -
  • Id {!! $reservation_id !!}
  • -
  • Owner {!! $owner_fullname!!}
  • -
  • Email {!! $owner_email!!}
  • -
  • From {!! $reservation_start_datetime !!}
  • -
  • To {!! $reservation_end_datetime !!}
  • -
  • Created {!!$reservation_created_datetime !!}
  • -
  • Amount {!! $reservation_currency !!} {!! $reservation_amount !!}
  • -
-

-

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - diff --git a/resources/views/emails/bookable_rooms/reservation_created.blade.php b/resources/views/emails/bookable_rooms/reservation_created.blade.php deleted file mode 100644 index d4246869..00000000 --- a/resources/views/emails/bookable_rooms/reservation_created.blade.php +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - -

- Dear {!! $owner_fullname !!} -

-

- Your Reservation for room {!! $room_complete_name !!} has been created successfully. -

-

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - diff --git a/resources/views/emails/bookable_rooms/reservation_payment_confirmed.blade.php b/resources/views/emails/bookable_rooms/reservation_payment_confirmed.blade.php deleted file mode 100644 index 533ddc56..00000000 --- a/resources/views/emails/bookable_rooms/reservation_payment_confirmed.blade.php +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - -

- Dear {!! $owner_fullname !!} -

-

- Your Reservation for room {!! $room_complete_name !!} has been confirmed. -

-

- Please take note of the reservation info bellow: -

-

-

    -
  • {!! $room_complete_name !!}
  • -
  • From {!! $reservation_start_datetime !!}
  • -
  • To {!! $reservation_end_datetime !!}
  • -
  • Room Capacity {!! $room_capacity !!}
  • -
  • Amount {!! $reservation_currency !!} {!! $reservation_amount !!}
  • -
-

-

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - \ No newline at end of file diff --git a/resources/views/emails/bookable_rooms/reservation_refund_accepted.blade.php b/resources/views/emails/bookable_rooms/reservation_refund_accepted.blade.php deleted file mode 100644 index 6f59a3f9..00000000 --- a/resources/views/emails/bookable_rooms/reservation_refund_accepted.blade.php +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - -

- Dear {!! $owner_fullname!!} -

-

- Your Refund Request Reservation for room {!! $room_complete_name !!} is confirmed. -

-

- Please take note of the reservation info below: -

-

-

    -
  • {!! $room_complete_name !!}
  • -
  • From {!! $reservation_start_datetime !!}
  • -
  • To {!! $reservation_end_datetime !!}
  • -
  • Room Capacity {!! $room_capacity !!}
  • -
  • Amount {!! $reservation_currency !!} {!! $reservation_refunded_amount !!}
  • -
-

-

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - diff --git a/resources/views/emails/bookable_rooms/reservation_refund_requested_admin.blade.php b/resources/views/emails/bookable_rooms/reservation_refund_requested_admin.blade.php deleted file mode 100644 index 2475c30c..00000000 --- a/resources/views/emails/bookable_rooms/reservation_refund_requested_admin.blade.php +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - -

- There is a new reservation refund request available to process -

-

- Please take note of the reservation info below: -

-

-

    -
  • Id {!! $reservation_id!!}
  • -
  • {!! $room_complete_name !!}
  • -
  • Owner {!! $owner_fullname!!}
  • -
  • Email {!! $owner_email !!}
  • -
  • From {!! $reservation_start_datetime !!}
  • -
  • To {!! $reservation_end_datetime !!}
  • -
  • Created {!! $reservation_created_datetime !!}
  • -
  • Amount {!! $reservation_currency !!} {!! $reservation_amount !!}
  • -
-

-

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - diff --git a/resources/views/emails/bookable_rooms/reservation_refund_requested_owner.blade.php b/resources/views/emails/bookable_rooms/reservation_refund_requested_owner.blade.php deleted file mode 100644 index 2a216443..00000000 --- a/resources/views/emails/bookable_rooms/reservation_refund_requested_owner.blade.php +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - -

- Dear {!! $owner_fullname !!} -

-

- You had requested a refund for your reservation. -

-

- Please take note of the reservation info below: -

-

-

    -
  • Id {!! $reservation_id!!}
  • -
  • Owner {!! $owner_fullname!!}
  • -
  • Email {!! $owner_email!!}
  • -
  • From {!! $reservation_start_datetime !!}
  • -
  • To {!! $reservation_end_datetime !!}
  • -
  • Created {!! $reservation_created_datetime !!}
  • -
  • Amount {!! $reservation_currency !!} {!! $reservation_amount !!}
  • -
-

-

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - \ No newline at end of file diff --git a/resources/views/emails/schedule/rsvp_regular_seat.blade.php b/resources/views/emails/schedule/rsvp_regular_seat.blade.php deleted file mode 100644 index bf4f80b4..00000000 --- a/resources/views/emails/schedule/rsvp_regular_seat.blade.php +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - -

Thank you for your RSVP to {!! $event_title !!} at {!! $event_date !!} . For your convenience, we have added this to My Schedule within the Summit Management tool.

-@if(!empty($event_uri)) -

Be sure to synch it to your calendar by going here.

-@endif -Please present a printed copy of this email at the entrance where the event is being held.

- -******************************************************************************************
-

- Attendee: {!! $owner_fullname !!}
- Event: {!! $event_title !!}
- Confirmation #: {!! $confirmation_number !!}
-

-******************************************************************************************
- -

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - diff --git a/resources/views/emails/schedule/rsvp_wait_seat.blade.php b/resources/views/emails/schedule/rsvp_wait_seat.blade.php deleted file mode 100644 index b3bbd8bc..00000000 --- a/resources/views/emails/schedule/rsvp_wait_seat.blade.php +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - -

Thank you for signing up to {!! $event_title !!}< at {!! $event_date !!} At the moment, this class is full. - However, you've been added to the waitlist. If space becomes available, the Workshop presenter will contact you to let you know.

- -

For your convenience, we have added this to My Schedule within the Summit Management tool.

-Be sure to synch it to your calendar by going here. - -If you are removed from the waitlist, please present a printed copy of this email at the entrance where the event is being held.

- -******************************************************************************************
-

- Attendee: {!! $owner_fullname !!}
- Event: {!! $event_title !!}
- Confirmation #: {!! $confirmation_number !!}
-

-******************************************************************************************
- - -

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - diff --git a/resources/views/emails/schedule/share_event.blade.php b/resources/views/emails/schedule/share_event.blade.php deleted file mode 100644 index 332a0c5f..00000000 --- a/resources/views/emails/schedule/share_event.blade.php +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - -

{!! $event_title !!}.

-

{!! $event_description !!}

-

-

-Check it out: {!! $event_url !!} -

- - diff --git a/resources/views/emails/speakers/permissioneditapproved.blade.php b/resources/views/emails/speakers/permissioneditapproved.blade.php deleted file mode 100644 index 8613015f..00000000 --- a/resources/views/emails/speakers/permissioneditapproved.blade.php +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - -

- Dear {{ $request->getRequestedBy()->getFullName() }}, -

-

- User {{ $request->getSpeaker()->getFullName() }} has approved your request to edit his/her Speaker Profile. -

-

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - \ No newline at end of file diff --git a/resources/views/emails/speakers/permissioneditrejected.blade.php b/resources/views/emails/speakers/permissioneditrejected.blade.php deleted file mode 100644 index 33d490e8..00000000 --- a/resources/views/emails/speakers/permissioneditrejected.blade.php +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - -

- Dear {{ $request->getRequestedBy()->getFullName() }}, -

-

- User {{ $request->getSpeaker()->getFullName() }} has rejected your request to edit his/her Speaker Profile. -

-

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - \ No newline at end of file diff --git a/resources/views/emails/speakers/permissioneditrequested.blade.php b/resources/views/emails/speakers/permissioneditrequested.blade.php deleted file mode 100644 index d75840f8..00000000 --- a/resources/views/emails/speakers/permissioneditrequested.blade.php +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - -

- Dear {{ $request->getSpeaker()->getFullName() }}, -

-

- User {{ $request->getRequestedBy()->getFullName() }} has requested to be able to edit your Speaker Profile. -

-

- To Allow that please click on the following link Allow. -

-

Cheers,
{!! Config::get('app.tenant_name') !!} Support Team

- - \ No newline at end of file diff --git a/resources/views/tickets/raw.blade.php b/resources/views/tickets/raw.blade.php new file mode 100644 index 00000000..21c74a75 --- /dev/null +++ b/resources/views/tickets/raw.blade.php @@ -0,0 +1,11 @@ +

{!! $summit_name !!}

+

{!! $ticket_type !!} ( {!! $price !!} )

+

{!!$location_name !!}

+

{!! $dates !!}

+

Order information

+

Order # {!! $order_number !!}

+

Ordered by {!! $owner_full_name !!} on {!! $order_creation_date !!}

+@if(!empty($attendee_name)) +

Attendee

+

{!! $attendee_name!!}

+@endif \ No newline at end of file diff --git a/tests/BrowserKitTestCase.php b/tests/BrowserKitTestCase.php index 31cfdebb..9240b3e1 100644 --- a/tests/BrowserKitTestCase.php +++ b/tests/BrowserKitTestCase.php @@ -31,7 +31,7 @@ abstract class BrowserKitTestCase extends BaseTestCase */ protected $baseUrl = 'http://localhost'; - public function setUp() + protected function setUp() { parent::setUp(); // Don't forget this! $this->redis = Redis::connection(); @@ -39,7 +39,6 @@ abstract class BrowserKitTestCase extends BaseTestCase $this->prepareForTests(); } - /** * Migrates the database and set the mailer to 'pretend'. * This will cause the tests to run quickly. diff --git a/tests/DoctrineTest.php b/tests/DoctrineTest.php index c6b7e829..83efee2b 100644 --- a/tests/DoctrineTest.php +++ b/tests/DoctrineTest.php @@ -1,5 +1,4 @@ assertTrue(count($presentations) > 0); } + + public function testGetTicketTypeLock(){ + + $em1 = Registry::getManager(SilverstripeBaseModel::EntityManager); + $em2 = Registry::getManager(SilverstripeBaseModel::EntityManager); + $con1 = $em1->getConnection(); + $con2 = $em2->getConnection(); + $con1->beginTransaction(); // suspend auto-commit + $repo = EntityManager::getRepository(\models\summit\SummitTicketType::class); + + $type = $repo->getByIdExclusiveLock(103); + + $con2->beginTransaction(); // suspend aut + + $type2 = $repo->getByIdExclusiveLock(103); + + $con2->rollBack(); + } } \ No newline at end of file diff --git a/tests/ExternalFeedIngestionTest.php b/tests/ExternalFeedIngestionTest.php index a42c73b2..c58003f1 100644 --- a/tests/ExternalFeedIngestionTest.php +++ b/tests/ExternalFeedIngestionTest.php @@ -26,6 +26,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; use App\Services\Model\IScheduleIngestionService; use App\Services\Apis\ExternalScheduleFeeds\AbstractExternalScheduleFeed; +use App\Models\Foundation\Summit\ISummitExternalScheduleFeedType; /** * Class ExternalFeedIngestionTest * @package Tests @@ -103,6 +104,13 @@ JSON; $this->assertTrue(count($summitsWithExternalFeeds)>0); } + public function testIngestSummitById($summit_id = 5){ + $repository = EntityManager::getRepository(Summit::class); + $summit = $repository->find($summit_id); + $service = App::make(IScheduleIngestionService::class); + $service->ingestSummit($summit); + } + public function testUTFName(){ $name = "Intel® Firmware Support Package (FSP) + EDK II for Cloud"; @@ -136,7 +144,7 @@ JSON; $summit = new Summit(); $summit->setActive(true); // set feed type (sched) - $summit->setApiFeedType(IExternalScheduleFeedFactory::SchedType); + $summit->setApiFeedType(ISummitExternalScheduleFeedType::SchedType); $summit->setApiFeedUrl(""); $summit->setApiFeedKey(""); $summit->setTimeZoneId("America/Chicago"); diff --git a/tests/ExternalRegistrationIngestionTest.php b/tests/ExternalRegistrationIngestionTest.php new file mode 100644 index 00000000..1d668324 --- /dev/null +++ b/tests/ExternalRegistrationIngestionTest.php @@ -0,0 +1,80 @@ +setActive(true); + // set feed type (sched) + $summit->setExternalRegistrationFeedType(ISummitExternalRegistrationFeedType::Eventbrite); + $summit->setExternalRegistrationFeedApiKey(getenv('SUMMIT_REGISTRATION_EXT_API_KEY')); + $summit->setExternalSummitId(getenv('SUMMIT_REGISTRATION_EXT_SUMMIT_ID')); + $summit->setTimeZoneId("America/Chicago"); + $summit->setBeginDate(new \DateTime("2019-09-1")); + $summit->setEndDate(new \DateTime("2019-09-30")); + + + $mainVenue = new SummitVenue(); + $mainVenue->setIsMain(true); + $summit->addLocation($mainVenue); + + $defaultBadge = new SummitBadgeType(); + $defaultBadge->setName("DEFAULT"); + $defaultBadge->setIsDefault(true); + $summit->addBadgeType($defaultBadge); + + $em = Registry::getManager(SilverstripeBaseModel::EntityManager); + $em->persist($summit); + $em->flush(); + + $service = App::make(IRegistrationIngestionService::class); + + $service->ingestSummit($summit); + } + + /** + * @param int $summit_id + */ + public function testIngestSummitById($summit_id = 29){ + $repo = App::make(ISummitRepository::class); + $summit = $repo->getById($summit_id); + $service = App::make(IRegistrationIngestionService::class); + $service->ingestSummit($summit); + } + +} \ No newline at end of file diff --git a/tests/InsertMemberTestData.php b/tests/InsertMemberTestData.php new file mode 100644 index 00000000..59b864a9 --- /dev/null +++ b/tests/InsertMemberTestData.php @@ -0,0 +1,170 @@ +remove(self::$group); + + self::$group = new Group(); + self::$group->setCode($current_group_slug); + self::$group->setTitle($current_group_slug); + self::$em->persist(self::$group); + + self::$member->add2Group(self::$group); + + self::$em->persist(self::$member); + self::$em->flush(); + } + + + /** + * InsertMemberTestData constructor. + * @param string $current_group_slug + */ + protected static function insertMemberTestData(string $current_group_slug){ + + DB::setDefaultConnection("model"); + DB::table("Group_Members")->delete(); + DB::table("Group")->delete(); + DB::table("Member")->delete(); + DB::table("PresentationSpeaker")->delete(); + + self::$em = Registry::getManager(SilverstripeBaseModel::EntityManager); + if (!self::$em ->isOpen()) { + self::$em = Registry::resetManager(SilverstripeBaseModel::EntityManager); + } + + self::$group_repository = EntityManager::getRepository(Group::class); + self::$member_repository = EntityManager::getRepository(Member::class); + + self::$group = new Group(); + self::$group->setCode($current_group_slug); + self::$group->setTitle($current_group_slug); + self::$em->persist(self::$group); + + self::$group2 = new Group(); + self::$group2->setCode(IGroup::SummitAdministrators); + self::$group2->setTitle(IGroup::SummitAdministrators); + self::$em->persist(self::$group2); + + self::$member = new Member(); + $prefix = str_random(10); + self::$member->setEmail("smarcet+{$prefix}@gmail.com"); + self::$member->setActive(true); + self::$member->setFirstName("Sebastian"); + self::$member->setLastName("Marcet"); + self::$member->setEmailVerified(true); + self::$member->setUserExternalId("1"); + self::$member->add2Group(self::$group); + + self::$member2 = new Member(); + self::$member2->setEmail("smarcet+{$prefix}_admin@gmail.com"); + self::$member2->setActive(true); + self::$member2->setFirstName("Sebastian"); + self::$member2->setLastName("Marcet Summit Admin"); + self::$member2->setEmailVerified(true); + self::$member2->setUserExternalId("2"); + self::$member2->add2Group(self::$group2); + + + PresentationSpeaker::$bypass_events = true; + self::$speaker = new PresentationSpeaker(); + self::$speaker->setFirstName("Sebastian"); + self::$speaker->setLastName("Marcet"); + self::$speaker->setBio("Lorep Ip Sum"); + self::$speaker->setMember(self::$member); + + self::$em->persist(self::$member); + self::$em->persist(self::$member2); + + self::$em->flush(); + + self::$member2->belongsToGroup(IGroup::BadgePrinters); + PresentationSpeaker::$bypass_events = false; + } + + protected static function clearMemberTestData(){ + self::$em = Registry::resetManager(SilverstripeBaseModel::EntityManager); + + self::$member = self::$member_repository->find(self::$member->getId()); + self::$group = self::$group_repository->find(self::$group->getId()); + + self::$member2 = self::$member_repository->find(self::$member2->getId()); + self::$group2 = self::$group_repository->find(self::$group2->getId()); + + self::$em->remove(self::$member); + self::$em->remove(self::$group); + + self::$em->remove(self::$member2); + self::$em->remove(self::$group2); + self::$em->flush(); + } +} \ No newline at end of file diff --git a/tests/InsertSummitTestData.php b/tests/InsertSummitTestData.php new file mode 100644 index 00000000..82342f47 --- /dev/null +++ b/tests/InsertSummitTestData.php @@ -0,0 +1,162 @@ +delete(); + self::$summit_repository = EntityManager::getRepository(Summit::class); + self::$summit = new Summit(); + self::$summit->setActive(true); + // set feed type (sched) + self::$summit->setApiFeedUrl(""); + self::$summit->setApiFeedKey(""); + self::$summit->setTimeZoneId("America/Chicago"); + $time_zone = new DateTimeZone("America/Chicago"); + $begin_date = new \DateTime("now", $time_zone); + self::$summit->setBeginDate($begin_date); + self::$summit->setEndDate((clone $begin_date)->add(new DateInterval("P30D"))); + self::$summit->setRegistrationBeginDate($begin_date); + self::$summit->setRegistrationEndDate((clone $begin_date)->add(new DateInterval("P30D"))); + self::$summit->setName("TEST SUMMIT"); + + $presentation_type = new PresentationType(); + $presentation_type->setType('TEST PRESENTATION TYPE'); + self::$summit->addEventType($presentation_type); + + self::$summit2 = new Summit(); + self::$summit2->setActive(true); + // set feed type (sched) + self::$summit2->setApiFeedUrl(""); + self::$summit2->setApiFeedKey(""); + self::$summit2->setTimeZoneId("America/Chicago"); + $time_zone = new DateTimeZone("America/Chicago"); + $begin_date = new \DateTime("now", $time_zone); + self::$summit2->setBeginDate($begin_date); + self::$summit2->setEndDate((clone $begin_date)->add(new DateInterval("P30D"))); + self::$summit2->setRegistrationBeginDate($begin_date); + self::$summit2->setRegistrationEndDate((clone $begin_date)->add(new DateInterval("P30D"))); + self::$summit2->setName("TEST SUMMIT2"); + + self::$mainVenue = new SummitVenue(); + self::$mainVenue->setIsMain(true); + self::$summit->addLocation(self::$mainVenue); + + self::$defaultTrack = new PresentationCategory(); + self::$defaultTrack->setTitle('DEFAULT TRACK'); + self::$defaultTrack->setCode('DFT'); + self::$defaultTrack->setLightningCount(true); + + $track_group = new PresentationCategoryGroup(); + $track_group->setName("DEFAULT TRACK GROUP"); + $track_group->addCategory(self::$defaultTrack); + self::$summit->addPresentationCategory(self::$defaultTrack); + self::$summit->addCategoryGroup($track_group); + + self::$defaultEventType = new PresentationType(); + self::$defaultEventType->setType(IPresentationType::Presentation); + self::$defaultEventType->setMinSpeakers(1); + self::$defaultEventType->setMaxSpeakers(3); + self::$defaultEventType->setMinModerators(0); + self::$defaultEventType->setMaxModerators(0); + self::$defaultEventType->setUseSpeakers(true); + self::$defaultEventType->setShouldBeAvailableOnCfp(true); + self::$defaultEventType->setAreSpeakersMandatory(false); + self::$defaultEventType->setUseModerator(false); + self::$defaultEventType->setIsModeratorMandatory(false); + self::$summit->addEventType(self::$defaultEventType); + + $selection_plan = new SelectionPlan(); + $selection_plan->setName("TEST_SELECTION_PLAN"); + $submission_begin_date = new DateTime('now', self::$summit->getTimeZone()); + $submission_end_date = (clone $submission_begin_date)->add(new DateInterval("P14D")); + $selection_plan->setSummit(self::$summit); + $selection_plan->setSubmissionBeginDate($submission_begin_date); + $selection_plan->setSubmissionEndDate($submission_end_date); + $selection_plan->setIsEnabled(true); + $selection_plan->addTrackGroup($track_group); + + self::$summit->addSelectionPlan($selection_plan); + + self::$em = Registry::getManager(SilverstripeBaseModel::EntityManager); + if (!self::$em ->isOpen()) { + self::$em = Registry::resetManager(SilverstripeBaseModel::EntityManager); + } + self::$em->persist(self::$summit); + self::$em->persist(self::$summit2); + self::$em->flush(); + } + + protected static function clearTestData(){ + self::$em = Registry::resetManager(SilverstripeBaseModel::EntityManager); + self::$summit = self::$summit_repository->find(self::$summit->getId()); + self::$summit2 = self::$summit_repository->find(self::$summit2->getId()); + self::$em->remove(self::$summit); + self::$em->remove(self::$summit2); + self::$em->flush(); + } +} \ No newline at end of file diff --git a/tests/OAuth2AttendeesApiTest.php b/tests/OAuth2AttendeesApiTest.php index 0ace6801..d128b55f 100644 --- a/tests/OAuth2AttendeesApiTest.php +++ b/tests/OAuth2AttendeesApiTest.php @@ -14,16 +14,16 @@ class OAuth2AttendeesApiTest extends ProtectedApiTest { - public function testGetAttendees(){ + public function testGetAttendees($summit_id=23){ $params = [ - 'id' => 23, + 'id' => $summit_id, 'page' => 1, 'per_page' => 10, 'order' => '+id', 'filter' => 'email=@jimmy', - 'expand' => 'member,schedule,rsvp' + 'expand' => 'member,schedule,rsvp,tickets, tickets.ticket_type' ]; $headers = [ @@ -197,17 +197,24 @@ class OAuth2AttendeesApiTest extends ProtectedApiTest $this->assertResponseStatus(204); } - public function testUpdateAttendee(){ - $attendee = $this->testGetAttendeeByID(12642); + public function testUpdateAttendee($summit_id = 27, $attendee_id = 18502){ + $params = [ - 'id' => 23, - 'attendee_id' => $attendee->id + 'id' => $summit_id, + 'attendee_id' => $attendee_id ]; $data = [ - 'member_id' => $attendee->member->id, - 'share_contact_info' => true + 'share_contact_info' => true, + 'first_name' => 'Sebastian', + 'surname' => 'Marcet', + 'email' => 'smarcet@gmail.com', + 'extra_questions' => [ + ['question_id' => 3, 'answer' => 'XL'], + ['question_id' => 4, 'answer' => 'None'], + ['question_id' => 5, 'answer' => 'None'], + ] ]; $headers = [ @@ -227,7 +234,7 @@ class OAuth2AttendeesApiTest extends ProtectedApiTest ); $content = $response->getContent(); - $this->assertResponseStatus(204); + $this->assertResponseStatus(201); $attendee = json_decode($content); $this->assertTrue(!is_null($attendee)); return $attendee; diff --git a/tests/OAuth2CompaniesApiTest.php b/tests/OAuth2CompaniesApiTest.php index 36df6b24..b54143c2 100644 --- a/tests/OAuth2CompaniesApiTest.php +++ b/tests/OAuth2CompaniesApiTest.php @@ -20,14 +20,14 @@ class OAuth2CompaniesApiTest extends ProtectedApiTest $params = [ //AND FILTER - 'filter' => ['name=@tip'], + 'filter' => ['name=@Dell\,'], 'order' => '-id' ]; $headers = array("HTTP_Authorization" => " Bearer " . $this->access_token); $response = $this->action( "GET", - "OAuth2CompaniesApiController@getAll", + "OAuth2CompaniesApiController@getAllCompanies", $params, array(), array(), @@ -41,4 +41,33 @@ class OAuth2CompaniesApiTest extends ProtectedApiTest $this->assertResponseStatus(200); } + public function testAddCompany(){ + $data = [ + 'name' => str_random(16).'_company', + 'description' => str_random(16).'_description', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2CompaniesApiController@add", + [], + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $company = json_decode($content); + $this->assertTrue(!is_null($company)); + return $company; + } + } \ No newline at end of file diff --git a/tests/OAuth2MembersApiTest.php b/tests/OAuth2MembersApiTest.php index c2704692..77f2a45a 100644 --- a/tests/OAuth2MembersApiTest.php +++ b/tests/OAuth2MembersApiTest.php @@ -352,4 +352,43 @@ final class OAuth2MembersApiTest extends ProtectedApiTest $this->assertResponseStatus(200); } + + use InsertSummitTestData; + + protected function setUp() + { + parent::setUp(); + self::insertTestData(); + } + + public function tearDown() + { + self::clearTestData(); + Mockery::close(); + } + + public function testGetAllSummitPermissions(){ + self::$member2->addSummitEditPermission(self::$summit); + self::$member2->addSummitEditPermission(self::$summit2); + + $params = [ + 'order' => '-id' + ]; + + $headers = ["HTTP_Authorization" => " Bearer " . $this->access_token]; + $response = $this->action( + "GET", + "OAuth2MembersApiController@getAllSummitEditPermissions", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $pemissions = json_decode($content); + $this->assertTrue(!is_null($pemissions)); + $this->assertResponseStatus(200); + } } \ No newline at end of file diff --git a/tests/OAuth2OAuth2SponsorshipTypeApiTest.php b/tests/OAuth2OAuth2SponsorshipTypeApiTest.php new file mode 100644 index 00000000..801d2ab8 --- /dev/null +++ b/tests/OAuth2OAuth2SponsorshipTypeApiTest.php @@ -0,0 +1,154 @@ + $name, + 'label' => $name, + 'size' => \models\summit\ISponsorshipTypeConstants::BigSize, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SponsorshipTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $sponsorship_type = json_decode($content); + $this->assertTrue(!is_null($sponsorship_type)); + $this->assertTrue($sponsorship_type->name == $name); + return $sponsorship_type; + } + + public function testGetAllSponsorShipTypes(){ + $params = [ + 'filter' => 'size==Big' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SponsorshipTypeApiController@getAll", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $page = json_decode($content); + $this->assertTrue(!is_null($page)); + return $page; + } + + /** + * @return mixed + */ + public function testUpdateSponsorShipType(){ + $sponsorship_type = $this->testAddSponsorShipType(); + $params = [ + 'id' => $sponsorship_type->id + ]; + + $data = [ + 'order' => 1 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SponsorshipTypeApiController@update", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $sponsorship_type = json_decode($content); + $this->assertTrue(!is_null($sponsorship_type)); + return $sponsorship_type; + } + + /** + * @return mixed + */ + public function testDeleteSponsorShipType(){ + $sponsorship_type = $this->testAddSponsorShipType(); + $params = [ + 'id' => $sponsorship_type->id + ]; + + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SponsorshipTypeApiController@delete", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + $this->assertTrue(empty($content)); + + } +} \ No newline at end of file diff --git a/tests/OAuth2PaymentGatewayProfileApiTest.php b/tests/OAuth2PaymentGatewayProfileApiTest.php new file mode 100644 index 00000000..7bb9994e --- /dev/null +++ b/tests/OAuth2PaymentGatewayProfileApiTest.php @@ -0,0 +1,332 @@ + IPaymentConstants::ApplicationTypeRegistration, + 'is_test_mode' => true, + 'test_publishable_key' => self::$test_public_key, + 'test_secret_key' => self::$test_secret_key, + 'is_active' => false, + ]); + + // build default badge type + + $defaultBadge = SummitBadgeTypeFactory::build([ + 'name' => 'DEFAULT', + 'is_default' => true, + ]); + + // build ticket type + + $ticketType = SummitTicketTypeFactory::build(self::$summit, [ + 'name' => 'TICKET_1', + 'cost' => 100, + 'quantity_2_sell' => 1000, + ]); + + self::$summit->addPaymentProfile($profile); + self::$summit->addBadgeType($defaultBadge); + self::$summit->addTicketType($ticketType); + self::$em->persist(self::$summit); + self::$em->flush(); + } + + protected function tearDown() + { + self::clearTestData(); + parent::tearDown(); + } + + /** + * @param int $summit_id + */ + public function testGetPaymentProfiles(){ + $params = [ + + 'id' => self::$summit->getId(), + 'page' => 1, + 'per_page' => 10, + //'filter' => 'code=@DISCOUNT_', + 'order' => '-id' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2PaymentGatewayProfileApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $profiles = json_decode($content); + $this->assertTrue(!is_null($profiles)); + $this->assertTrue($profiles->total >= 1); + $aProfile = $profiles->data[0]; + $this->assertTrue(property_exists($aProfile, 'live_secret_key')); + $this->assertTrue(property_exists($aProfile, 'test_secret_key')); + return $profiles; + } + + public function testAddProfileFail(){ + $params = [ + 'id' => self::$summit->getId(), + ]; + + $data = [ + 'active' => false, + 'application_type' => 'test', + 'provider' => 'test', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2PaymentGatewayProfileApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(412); + $errors = json_decode($content); + } + + + public function testAddProfileOK(){ + $params = [ + 'id' => self::$summit->getId(), + ]; + + $data = [ + 'active' => false, + 'application_type' => IPaymentConstants::ApplicationTypeRegistration, + 'provider' => IPaymentConstants::ProviderStripe, + 'test_mode_enabled' => true, + 'test_secret_key' => self::$test_secret_key, + 'test_publishable_key' => self::$test_public_key, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2PaymentGatewayProfileApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $profile = json_decode($content); + $this->assertTrue(!is_null($profile)); + $this->assertTrue($profile->test_secret_key == self::$test_secret_key); + $this->assertTrue($profile->test_publishable_key == self::$test_public_key); + return $profile; + } + + public function testUpdateOK(){ + $params = [ + 'id' => self::$summit->getId(), + ]; + + $data = [ + 'active' => false, + 'application_type' => IPaymentConstants::ApplicationTypeRegistration, + 'provider' => IPaymentConstants::ProviderStripe, + 'test_mode_enabled' => true, + 'test_secret_key' => self::$test_secret_key, + 'test_publishable_key' => self::$test_public_key, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2PaymentGatewayProfileApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $profile = json_decode($content); + + $params = [ + 'id' => self::$summit->getId(), + 'payment_profile_id' => $profile->id, + ]; + + $data = [ + 'active' => true, + 'provider' => IPaymentConstants::ProviderStripe, + 'test_mode_enabled' => true, + 'live_secret_key' => self::$live_secret_key, + 'live_publishable_key' => self::$live_public_key, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2PaymentGatewayProfileApiController@update", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $profile = json_decode($content); + $this->assertTrue(!is_null($profile)); + $this->assertTrue($profile->live_publishable_key == self::$live_public_key); + return $profile; + } + + public function testDelete(){ + + $params = [ + 'id' => self::$summit->getId(), + ]; + + $data = [ + 'active' => false, + 'application_type' => IPaymentConstants::ApplicationTypeRegistration, + 'provider' => IPaymentConstants::ProviderStripe, + 'test_mode_enabled' => true, + 'test_secret_key' => self::$test_secret_key, + 'test_publishable_key' => self::$test_public_key, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2PaymentGatewayProfileApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $profile = json_decode($content); + + $params = [ + 'id' => self::$summit->getId(), + 'payment_profile_id' => $profile->id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2PaymentGatewayProfileApiController@delete", + $params, + [], + [], + [], + $headers + + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + } + +} \ No newline at end of file diff --git a/tests/OAuth2PresentationSubmissionTest.php b/tests/OAuth2PresentationSubmissionTest.php index 2dc0e472..c6338336 100644 --- a/tests/OAuth2PresentationSubmissionTest.php +++ b/tests/OAuth2PresentationSubmissionTest.php @@ -14,13 +14,26 @@ class OAuth2PresentationSubmissionTest extends ProtectedApiTest { - /** - * @param int $summit_id - * @return mixed - */ - public function testSubmitPresentation($summit_id = 25){ + use InsertSummitTestData; + + protected function setUp() + { + parent::setUp(); + + self::insertTestData(); + self::$em->persist(self::$summit); + self::$em->flush(); + } + + protected function tearDown() + { + self::clearTestData(); + parent::tearDown(); + } + + public function testSubmitPresentation(){ $params = [ - 'id' => $summit_id, + 'id' => self::$summit->getId(), ]; $title = str_random(16).'_presentation'; @@ -30,11 +43,11 @@ class OAuth2PresentationSubmissionTest extends ProtectedApiTest 'social_description' => 'this is a social description', 'level' => 'N/A', 'attendees_expected_learnt' => 'super duper', - 'type_id' => 182, - 'track_id' => 262, + 'type_id' => self::$defaultEventType->getId(), + 'track_id' => self::$defaultTrack->getId(), 'attending_media' => true, 'links' => ['https://www.google.com'], - 'tags' => ['Upstream Development'] + //'tags' => ['Upstream Development'] ]; $headers = [ @@ -58,6 +71,22 @@ class OAuth2PresentationSubmissionTest extends ProtectedApiTest $presentation = json_decode($content); $this->assertTrue(!is_null($presentation)); $this->assertEquals($title, $presentation->title); + + $params = [ + 'id' => self::$summit->getId(), + 'presentation_id' => $presentation->id + ]; + + $response = $this->action( + "PUT", + "OAuth2PresentationApiController@completePresentationSubmission", + $params, + [], + [], + [], + $headers + ); + return $presentation; } diff --git a/tests/OAuth2PromoCodesApiTest.php b/tests/OAuth2PromoCodesApiTest.php index cb0a7650..bf24df10 100644 --- a/tests/OAuth2PromoCodesApiTest.php +++ b/tests/OAuth2PromoCodesApiTest.php @@ -11,20 +11,23 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ - +use App\Models\Foundation\Summit\PromoCodes\PromoCodesConstants; /** * Class OAuth2PromoCodesApiTest */ final class OAuth2PromoCodesApiTest extends ProtectedApiTest { - public function testGetPromoCodesDiscount(){ + /** + * @param int $summit_id + */ + public function testGetPromoCodesDiscount($summit_id=27){ $params = [ - 'id' => 23, + 'id' => $summit_id, 'page' => 1, 'per_page' => 10, - 'filter' => 'code=@DISCOUNT_', - 'order' => '+code' + //'filter' => 'code=@DISCOUNT_', + 'order' => '-code' ]; $headers = [ @@ -109,14 +112,14 @@ final class OAuth2PromoCodesApiTest extends ProtectedApiTest $this->assertTrue(!is_null($content)); } - public function testGetPromoCodesByClassNameOR(){ + public function testGetPromoCodesByClassNameOR($summit_id=27){ $params = [ - 'id' => 23, + 'id' => $summit_id, 'page' => 1, 'per_page' => 10, 'filter' => [ - 'class_name=='.\models\summit\SpeakerSummitRegistrationPromoCode::ClassName.','. 'class_name=='.\models\summit\MemberSummitRegistrationPromoCode::ClassName, + 'class_name=='.\models\summit\SummitRegistrationDiscountCode::ClassName.','. 'class_name=='.\models\summit\MemberSummitRegistrationDiscountCode::ClassName, ], 'order' => '+code' ]; @@ -207,7 +210,7 @@ final class OAuth2PromoCodesApiTest extends ProtectedApiTest public function testGetPromoCodesMetadata(){ $params = [ - 'id' => 23, + 'id' => 27, ]; $headers = [ @@ -231,18 +234,91 @@ final class OAuth2PromoCodesApiTest extends ProtectedApiTest $this->assertTrue(!is_null($metadata)); } - public function testAddPromoCode($summit_id = 23, $code = "12344KG_SPEAKER"){ + public function testAddGenericDiscountCode( $summit_id = 27){ + $code = str_random(16).'_DISCOUNT_CODE'; + $params = ['rate' => 50.00]; + return $this->testAddPromoCode + ( + $summit_id, + $code, + \models\summit\SummitRegistrationDiscountCode::ClassName, + $params + ); + } + + public function testAddMemberDiscountCode( $summit_id = 27){ + $code = str_random(16).'_MEMBER_DISCOUNT_CODE'; + $params = [ + 'amount' => 100.00, + 'email' => 'smarcet@gmail.com', + 'first_name' => 'sebastian', + 'last_name' => 'marcet', + 'type' => PromoCodesConstants::MemberSummitRegistrationPromoCodeTypes[0] + ]; + return $this->testAddPromoCode + ( + $summit_id, + $code, + \models\summit\MemberSummitRegistrationDiscountCode::ClassName, + $params + ); + } + + public function testAddPromoCode( + $summit_id = 27, + $code = "PROMOCODE", + $class_name =\models\summit\SummitRegistrationPromoCode::ClassName, + array $extra_params = [] + ){ $params = [ 'id' => $summit_id, ]; + $data = [ + 'code' => $code, + 'class_name' => $class_name, + 'quantity_available' => 100, + ]; + + $data = array_merge($data, $extra_params); + + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitPromoCodesApiController@addPromoCodeBySummit", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $promo_code = json_decode($content); + $this->assertTrue(!is_null($promo_code)); + return $promo_code; + } + + public function testAddDiscountSpeakerCode($summit_id = 27, $code = ""){ + $params = [ + 'id' => $summit_id, + ]; + + if(empty($code)) + $code = str_random(16).'_PROMOCODE'; $data = [ 'code' => $code, - 'class_name' => \models\summit\MemberSummitRegistrationPromoCode::ClassName, - 'first_name' => 'Sebastian', - 'last_name' => 'Marcet', - 'email' => 'test@test.com', - 'type' => \models\summit\MemberSummitRegistrationPromoCode::$valid_type_values[0] + 'class_name' => \models\summit\SpeakerSummitRegistrationDiscountCode::ClassName, + 'quantity_available' => 100, + 'speaker_id' => 1, + 'type' => PromoCodesConstants::SpeakerSummitRegistrationPromoCodeTypeAccepted ]; $headers = [ @@ -268,7 +344,42 @@ final class OAuth2PromoCodesApiTest extends ProtectedApiTest return $promo_code; } - public function testUpdatePromoCode($summit_id = 23){ + public function testAddDiscountSpeakerCodeTicketRule($summit_id = 27){ + $promo_code = $this->testAddDiscountSpeakerCode($summit_id); + $params = [ + 'id' => $summit_id, + 'promo_code_id' => $promo_code->id, + 'ticket_type_id' => 105 + ]; + + $data = [ + 'rate' => 50.50 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitPromoCodesApiController@addTicketTypeToPromoCode", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $promo_code = json_decode($content); + $this->assertTrue(!is_null($promo_code)); + return $promo_code; + } + + public function testUpdatePromoCode($summit_id = 27){ $code = str_random(16).'_PROMOCODE_TEST'; $promo_code = $this->testAddPromoCode($summit_id, $code); @@ -283,7 +394,7 @@ final class OAuth2PromoCodesApiTest extends ProtectedApiTest 'first_name' => 'Sebastian update', 'last_name' => 'Marcet update', 'email' => 'test@test.com', - 'type' => \models\summit\MemberSummitRegistrationPromoCode::$valid_type_values[2] + 'type' => PromoCodesConstants::MemberSummitRegistrationPromoCodeTypes[2] ]; $headers = [ @@ -441,4 +552,84 @@ final class OAuth2PromoCodesApiTest extends ProtectedApiTest $content = $response->getContent(); $this->assertResponseStatus(412); } + + /** + * @param int $summit_id + * @param int $promo_code_id + * @param int $ticket_type_id + * @return mixed + */ + public function testAddDiscountCodeTicketRule($summit_id = 8 , $promo_code_id = 7 , $ticket_type_id = 7){ + $params = [ + 'id' => $summit_id, + 'promo_code_id' => $promo_code_id, + 'ticket_type_id' => $ticket_type_id, + 'expand' => 'ticket_types_rules,ticket_types_rules.discount_code' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $data = [ + 'rate' => 10, + 'amount' => 0, + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitPromoCodesApiController@addTicketTypeToPromoCode", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + $content = $response->getContent(); + $this->assertResponseStatus(201); + $promo_code = json_decode($content); + $this->assertTrue(!is_null($promo_code)); + return $promo_code; + } + + /** + * @param int $summit_id + * @param int $promo_code_id + * @param int $ticket_type_id + * @return mixed + */ + public function testDeleteDiscountCodeTicketRule($summit_id = 8 , $promo_code_id = 7 , $ticket_type_id = 7){ + $params = [ + 'id' => $summit_id, + 'promo_code_id' => $promo_code_id, + 'ticket_type_id' => $ticket_type_id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $data = [ + + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitPromoCodesApiController@removeTicketTypeFromPromoCode", + $params, + [], + [], + [], + $headers + // json_encode($data) + ); + $content = $response->getContent(); + $this->assertResponseStatus(201); + $promo_code = json_decode($content); + $this->assertTrue(!is_null($promo_code)); + return $promo_code; + } } \ No newline at end of file diff --git a/tests/OAuth2SpeakersApiTest.php b/tests/OAuth2SpeakersApiTest.php index 65f6218c..27eed4b7 100644 --- a/tests/OAuth2SpeakersApiTest.php +++ b/tests/OAuth2SpeakersApiTest.php @@ -408,7 +408,7 @@ final class OAuth2SpeakersApiTest extends ProtectedApiTest 'page' => 1, 'per_page' => 10, 'filter' => [ - 'first_name=@b,last_name=@b,email=@b' + 'first_name=@b||a,last_name=@b,email=@b' ], 'order' => '+id' ]; @@ -472,7 +472,7 @@ final class OAuth2SpeakersApiTest extends ProtectedApiTest 'id' => 23, 'page' => 1, 'per_page' => 10, - 'filter' => 'id==13869,id==19' + 'filter[]' => 'id==13869||id==19' ]; $headers = [ @@ -482,7 +482,38 @@ final class OAuth2SpeakersApiTest extends ProtectedApiTest $response = $this->action( "GET", - "OAuth2SummitSpeakersApiController@getSpeakers", + "OAuth2SummitSpeakersApiController@getSpeakersOnSchedule", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $speakers = json_decode($content); + $this->assertTrue(!is_null($speakers)); + } + + public function testGetSpeakersOnSchedule($summit_id = 23) + { + $params = [ + + 'id' => $summit_id, + 'page' => 1, + 'per_page' => 10, + 'filter' => ['start_date>=1509753600','end_date<=1509839999'] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitSpeakersApiController@getSpeakersOnSchedule", $params, [], [], diff --git a/tests/OAuth2SummitAccessLevelTypeTest.php b/tests/OAuth2SummitAccessLevelTypeTest.php new file mode 100644 index 00000000..1d24d428 --- /dev/null +++ b/tests/OAuth2SummitAccessLevelTypeTest.php @@ -0,0 +1,170 @@ + $summit_id, + ]; + + $name = str_random(16).'_access_level'; + $template = << + + + + + + + + + + +HTML; + + $data = [ + 'name' => $name, + 'description' => "this is a description", + 'template_content' => $template, + 'tag_name' => "droid", + 'is_default' => true, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitAccessLevelTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $access_level = json_decode($content); + $this->assertTrue(!is_null($access_level)); + $this->assertTrue($access_level->name == $name); + return $access_level; + } + + public function testUpdateAccessLevel($summit_id = 27){ + + $access_level_old = $this->testAddAccessLevel(); + $params = [ + 'id' => $summit_id, + "level_id" => $access_level_old->id + ]; + + $data = [ + 'description' => "this is a description update", + 'is_default' => false, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitAccessLevelTypeApiController@update", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $access_level = json_decode($content); + $this->assertTrue(!is_null($access_level)); + $this->assertTrue($access_level->name == $access_level_old->name); + return $access_level; + } + + + public function testGetAllBySummit($summit_id=27){ + $params = [ + 'id' => $summit_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitAccessLevelTypeApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $data = json_decode($content); + $this->assertTrue(!is_null($data)); + return $data; + } + + /** + * @param int $summit_id + */ + public function testDeleteAccessLevel($summit_id=27){ + $access_level_old = $this->testAddAccessLevel(); + $params = [ + 'id' => $summit_id, + "level_id" => $access_level_old->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitAccessLevelTypeApiController@delete", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitAdministratorPermissionGroupApiControllerTest.php b/tests/OAuth2SummitAdministratorPermissionGroupApiControllerTest.php new file mode 100644 index 00000000..1c137f7f --- /dev/null +++ b/tests/OAuth2SummitAdministratorPermissionGroupApiControllerTest.php @@ -0,0 +1,171 @@ + 'TEST GROUP '.str_random(16), + 'members' => [self::$member2->getId()], + 'summits' => [self::$summit->getId()], + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitAdministratorPermissionGroupApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $group = json_decode($content); + $this->assertTrue(!is_null($group)); + $this->assertTrue(count($group->members) == 1); + $this->assertTrue(count($group->summits) == 1); + + return $group; + } + + public function testUpdateGroupOk(){ + + $group = $this->testAddGroupOK(); + + $params = [ + 'group_id' => $group->id + ]; + + $data = [ + 'members' => [self::$member2->getId()], + 'summits' => [], + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitAdministratorPermissionGroupApiController@update", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $group = json_decode($content); + $this->assertTrue(!is_null($group)); + $this->assertTrue(count($group->members) == 1); + $this->assertTrue(count($group->summits) == 0); + } + + public function testGetAllOK(){ + $group = $this->testAddGroupOK(); + + $params = [ + 'expand' => 'summits,members' + ]; + + $data = [ + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitAdministratorPermissionGroupApiController@getAll", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $groups = json_decode($content); + $this->assertTrue(!is_null($groups)); + } + + public function testGetByIdOK(){ + $group = $this->testAddGroupOK(); + + $params = [ + 'id' => $group->id, + //'expand' => 'summits,members', + ]; + + $data = [ + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitAdministratorPermissionGroupApiController@get", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $group = json_decode($content); + $this->assertTrue(!is_null($group)); + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitApiTest.php b/tests/OAuth2SummitApiTest.php index f38c5394..4115eb35 100644 --- a/tests/OAuth2SummitApiTest.php +++ b/tests/OAuth2SummitApiTest.php @@ -13,16 +13,25 @@ **/ use LaravelDoctrine\ORM\Facades\EntityManager; use Illuminate\Http\UploadedFile; -use Illuminate\Support\Facades\Storage; use App\Services\Apis\ExternalScheduleFeeds\IExternalScheduleFeedFactory; +use App\Models\Foundation\Main\IGroup; /** * Class OAuth2SummitApiTest */ final class OAuth2SummitApiTest extends ProtectedApiTest { + use InsertSummitTestData; + + protected function setUp() + { + parent::setUp(); + self::insertTestData(); + } + public function tearDown() { + self::clearTestData(); Mockery::close(); } @@ -71,8 +80,66 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $start = time(); $params = [ - 'relations'=>'none', - 'expand' => 'none', + 'relations' => 'none', + 'expand' => 'none', + ]; + + $headers = ["HTTP_Authorization" => " Bearer " . $this->access_token]; + $response = $this->action( + "GET", + "OAuth2SummitApiController@getAllSummits", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $summits = json_decode($content); + $end = time(); + $delta = $end - $start; + echo "execution call " . $delta . " seconds ..."; + $this->assertTrue(!is_null($summits)); + $this->assertTrue($summits->total == 1); + $this->assertResponseStatus(200); + } + + public function testGetAllSummitsNoPermissions() + { + self::setMemberDefaultGroup(IGroup::SummitAdministrators); + + $start = time(); + $params = [ + 'relations' => 'none', + 'expand' => 'none', + ]; + + $headers = ["HTTP_Authorization" => " Bearer " . $this->access_token]; + $response = $this->action( + "GET", + "OAuth2SummitApiController@getAllSummits", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $summits = json_decode($content); + $end = time(); + $delta = $end - $start; + echo "execution call " . $delta . " seconds ..."; + $this->assertResponseStatus(403); + } + + public function testGetAllSummitsAndPaymentProfiles() + { + $start = time(); + $params = [ + 'relations' => 'payment_profiles', + 'expand' => 'none', ]; $headers = ["HTTP_Authorization" => " Bearer " . $this->access_token]; @@ -99,7 +166,6 @@ final class OAuth2SummitApiTest extends ProtectedApiTest { $params = [ - 'expand' => 'schedule', 'id' => $summit_id ]; @@ -140,6 +206,51 @@ final class OAuth2SummitApiTest extends ProtectedApiTest $this->assertResponseStatus(200); } + public function testGetSummit2($summit_id = 12) + { + + $params = [ + + 'expand' => 'event_types,tracks', + 'id' => $summit_id + ]; + + $headers = array("HTTP_Authorization" => " Bearer " . $this->access_token); + $start = time(); + $response = $this->action( + "GET", + "OAuth2SummitApiController@getSummit", + $params, + array(), + array(), + array(), + $headers + ); + $end = time(); + $delta = $end - $start; + echo "execution call " . $delta . " seconds ..."; + $content = $response->getContent(); + $summit = json_decode($content); + $this->assertTrue(!is_null($summit)); + $this->assertResponseStatus(200); + + $response = $this->action( + "GET", + "OAuth2SummitApiController@getSummit", + $params, + array(), + array(), + array(), + $headers + ); + + $content = $response->getContent(); + $summit = json_decode($content); + $this->assertTrue(!is_null($summit)); + $this->assertTrue(count($summit->schedule) > 0); + $this->assertResponseStatus(200); + } + public function testAddSummitAlreadyExistsName(){ $params = [ ]; diff --git a/tests/OAuth2SummitBadgeFeatureTypeApiTest.php b/tests/OAuth2SummitBadgeFeatureTypeApiTest.php new file mode 100644 index 00000000..b7200951 --- /dev/null +++ b/tests/OAuth2SummitBadgeFeatureTypeApiTest.php @@ -0,0 +1,192 @@ + $summit_id, + ]; + + $name = str_random(16).'_feature_type'; + $template = << + + + + + + image/svg+xml + + + + + + + + + +HTML; + + $data = [ + 'name' => $name, + 'description' => "this is a description", + 'template_content' => $template, + 'tag_name' => "vegan", + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitBadgeFeatureTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $feature = json_decode($content); + $this->assertTrue(!is_null($feature)); + $this->assertTrue($feature->name == $name); + return $feature; + } + + public function testUpdateBadgeFeatureType($summit_id = 27){ + + $feature_old = $this->testAddBadgeFeatureType(); + $params = [ + 'id' => $summit_id, + "feature_id" => $feature_old->id + ]; + + $data = [ + 'description' => "this is a description update", + 'is_default' => false, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitBadgeFeatureTypeApiController@update", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $feature = json_decode($content); + $this->assertTrue(!is_null($feature)); + $this->assertTrue($feature->name == $feature_old->name); + return $feature; + } + + + public function testGetAllBySummit($summit_id=27){ + $params = [ + 'id' => $summit_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitBadgeFeatureTypeApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $data = json_decode($content); + $this->assertTrue(!is_null($data)); + return $data; + } + + /** + * @param int $summit_id + */ + public function testDeleteAccessLevel($summit_id=27){ + $feature_old = $this->testAddBadgeFeatureType(); + $params = [ + 'id' => $summit_id, + "feature_id" => $feature_old->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitBadgeFeatureTypeApiController@delete", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitBadgeScanApiControllerTest.php b/tests/OAuth2SummitBadgeScanApiControllerTest.php new file mode 100644 index 00000000..f7e5299b --- /dev/null +++ b/tests/OAuth2SummitBadgeScanApiControllerTest.php @@ -0,0 +1,91 @@ + $summit_id, + ]; + + $data = [ + 'qr_code' => "BADGE_REGISTRATIONDEVSUMMIT2019|REGISTRATIONDEVSUMMIT2019_TICKET_5D7BE0E518E8C161661586|santipalenque@gmail.com|Santiago, Palenque", + "scan_date" => 1572019200, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitBadgeScanApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $scan = json_decode($content); + $this->assertTrue(!is_null($scan)); + return $scan; + } + + /** + * @param int $summit_id + * @return mixed + */ + public function testGetAllMyBadgeScans($summit_id = 1){ + + $params = [ + 'id' => $summit_id, + 'filter'=> 'attendee_email=@santi', + 'expand' => 'sponsor,badge,badge.ticket,badge.ticket.owner' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitBadgeScanApiController@getAllMyBadgeScans", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $data = json_decode($content); + $this->assertTrue(!is_null($data)); + return $data; + } + +} \ No newline at end of file diff --git a/tests/OAuth2SummitBadgeTypeApiTest.php b/tests/OAuth2SummitBadgeTypeApiTest.php new file mode 100644 index 00000000..9aee11cf --- /dev/null +++ b/tests/OAuth2SummitBadgeTypeApiTest.php @@ -0,0 +1,232 @@ + $summit_id, + ]; + + $name = str_random(16).'_badge_type'; + $template = << + +
+

this is a badge

+ +
+ + +HTML; + + $data = [ + 'name' => $name, + 'description' => "this is a description", + 'template_content' => $template, + 'is_default' => $is_default + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitBadgeTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $badge_type = json_decode($content); + $this->assertTrue(!is_null($badge_type)); + $this->assertTrue($badge_type->name == $name); + return $badge_type; + } + + + public function testUpdateBadgeFeatureType($summit_id = 27){ + + $badge_type_old = $this->testAddBadgeType($summit_id, false); + $params = [ + 'id' => $summit_id, + "badge_type_id" => $badge_type_old->id + ]; + + $data = [ + 'description' => "this is a description update", + 'is_default' => true, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitBadgeTypeApiController@update", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $badge_type = json_decode($content); + $this->assertTrue(!is_null($badge_type)); + $this->assertTrue($badge_type->name == $badge_type_old->name); + return $badge_type; + } + + + public function testGetAllBySummit($summit_id=27){ + $params = [ + 'id' => $summit_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitBadgeTypeApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $data = json_decode($content); + $this->assertTrue(!is_null($data)); + return $data; + } + + /** + * @param int $summit_id + */ + public function testDeleteBadgeFeatureType($summit_id=27){ + $badge_type_old = $this->testAddBadgeType(); + $params = [ + 'id' => $summit_id, + "feature_id" => $badge_type_old->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitBadgeTypeApiController@delete", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + } + + public function testAssignAccessLevelToBadgeType($summit_id=27){ + $badge_type_old = $this->testAddBadgeType(); + $params = [ + 'id' => $summit_id, + "feature_id" => $badge_type_old->id, + 'access_level_id' => 1 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitBadgeTypeApiController@addAccessLevelToBadgeType", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + } + + public function testRemoveAccessLevelToBadgeType($summit_id=27){ + $badge_type_old = $this->testAddBadgeType(); + $params = [ + 'id' => $summit_id, + "feature_id" => $badge_type_old->id, + 'access_level_id' => 1 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitBadgeTypeApiController@addAccessLevelToBadgeType", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + + $response = $this->action( + "DELETE", + "OAuth2SummitBadgeTypeApiController@removeAccessLevelFromBadgeType", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitBadgesApiTest.php b/tests/OAuth2SummitBadgesApiTest.php new file mode 100644 index 00000000..f5c6475e --- /dev/null +++ b/tests/OAuth2SummitBadgesApiTest.php @@ -0,0 +1,77 @@ + $summit_id, + 'expand' => 'ticket,ticket.order,type,type.access_levels,features' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitBadgesApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $data = json_decode($content); + $this->assertTrue(!is_null($data)); + return $data; + } + + public function testGetAllBySummitCSV($summit_id=27){ + $params = [ + 'id' => $summit_id, + 'expand' => 'ticket,ticket.order,type,type.access_levels,features' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitBadgesApiController@getAllBySummitCSV", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $data = json_decode($content); + $this->assertTrue(!is_null($data)); + return $data; + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitDocumentsApiControllerTest.php b/tests/OAuth2SummitDocumentsApiControllerTest.php new file mode 100644 index 00000000..e511d00c --- /dev/null +++ b/tests/OAuth2SummitDocumentsApiControllerTest.php @@ -0,0 +1,295 @@ +seedDefaultEmailFlowEvents(); + + $fileUploader = App::make(IFileUploader::class); + + $file1 = $fileUploader->build + ( + UploadedFile::fake()->image('slide.pdf'), + sprintf('summits/%s/documents', self::$summit->getId()), + false + ); + + $doc1 = new SummitDocument(); + $doc1->setName('doc 1'); + $doc1->setLabel("doc 1"); + $doc1->setDescription("this is the doc 1"); + $doc1->setFile($file1); + + self::$summit->addSummitDocument($doc1); + + $file2 = $fileUploader->build + ( + UploadedFile::fake()->image('slide2.pdf'), + sprintf('summits/%s/documents', self::$summit->getId()), + false + ); + + $doc2 = new SummitDocument(); + $doc2->setName('doc 2'); + $doc2->setLabel("doc 2"); + $doc2->setDescription("this is the doc 2"); + $doc2->setFile($file2); + $doc2->addEventType(self::$summit->getEventTypes()[0]); + + self::$summit->addSummitDocument($doc2); + + self::$em->persist(self::$summit); + self::$em->flush(); + } + + protected function tearDown() + { + self::clearTestData(); + parent::tearDown(); + } + + public function testGetAllSummitDocuments(){ + $params = [ + 'id' => self::$summit->getId(), + 'page' => 1, + 'per_page' => 10, + 'order' => '-id', + 'filter' => 'event_type=@'.self::$summit->getEventTypes()[0]->getType() + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitDocumentsApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $documents = json_decode($content); + $this->assertTrue(!is_null($documents)); + $this->assertTrue($documents->total >= 1); + return $documents; + } + + public function testAddSummitDocument(){ + $params = [ + 'id' => self::$summit->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $payload = [ + 'name' => 'doc3', + 'label' => 'doc3', + ]; + + $response = $this->action( + "POST", + "OAuth2SummitDocumentsApiController@add", + $params, + [], + [], + [ + 'file' => UploadedFile::fake()->image('slide1.pdf'), + ], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $document = json_decode($content); + $this->assertResponseStatus(201); + } + + public function testAddSummitDocumentFail412(){ + $params = [ + 'id' => self::$summit->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $payload = [ + 'name' => 'doc 1', + 'label' => 'doc 1', + ]; + + $response = $this->action( + "POST", + "OAuth2SummitDocumentsApiController@add", + $params, + [], + [], + [ + 'file' => UploadedFile::fake()->image('slide1.pdf'), + ], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(412); + } + + public function testUpdateSummitDocument(){ + $document = self::$summit->getSummitDocuments()[0]; + $params = [ + 'id' => self::$summit->getId(), + 'document_id' => $document->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $payload = [ + 'label' => 'doc 4', + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitDocumentsApiController@update", + $params, + [], + [], + [ + 'file' => UploadedFile::fake()->image('slide2.pdf'), + ], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $document = json_decode($content); + $this->assertTrue($document->label == "doc 4"); + } + + public function testDeleteDocument(){ + + $document = self::$summit->getSummitDocuments()[0]; + $params = [ + 'id' => self::$summit->getId(), + 'document_id' => $document->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitDocumentsApiController@delete", + $params, + [], + [], + [ + + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + } + + + public function testAddEventType2SummitDocument(){ + $document = self::$summit->getSummitDocuments()[0]; + $event_type = self::$summit->getEventTypes()[0]; + $params = [ + 'id' => self::$summit->getId(), + 'document_id' => $document->getId(), + 'event_type_id' => $event_type->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitDocumentsApiController@addEventType", + $params, + [], + [], + [ + + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + } + + public function testAddDocument2EventType(){ + $document = self::$summit->getSummitDocuments()[0]; + $event_type = self::$summit->getEventTypes()[0]; + $params = [ + 'id' => self::$summit->getId(), + 'document_id' => $document->getId(), + 'event_type_id' => $event_type->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitsEventTypesApiController@addSummitDocument", + $params, + [], + [], + [ + + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitEmailEventFlowApiControllerTest.php b/tests/OAuth2SummitEmailEventFlowApiControllerTest.php new file mode 100644 index 00000000..ad7dbd34 --- /dev/null +++ b/tests/OAuth2SummitEmailEventFlowApiControllerTest.php @@ -0,0 +1,103 @@ +seedDefaultEmailFlowEvents(); + } + + protected function tearDown() + { + self::clearTestData(); + parent::tearDown(); + } + + /** + * @param int $summit_id + */ + public function testGetAllEmailEvents(){ + $params = [ + 'id' => self::$summit->getId(), + 'page' => 1, + 'per_page' => 10, + 'order' => '-id', + 'filter' => 'flow_name==Schedule' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitEmailEventFlowApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $email_events = json_decode($content); + $this->assertTrue(!is_null($email_events)); + $this->assertTrue($email_events->total >= 1); + return $email_events; + } + + public function testUpdateEmailEvent(){ + $email_events = $this->testGetAllEmailEvents(); + + $params = [ + 'id' => self::$summit->getId(), + 'event_id' => $email_events->data[0]->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $data = [ + 'email_template_identifier' => "NEW_TEMPLATE", + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitEmailEventFlowApiController@update", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $email_event = json_decode($content); + + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitLocationsApiTest.php b/tests/OAuth2SummitLocationsApiTest.php index 6711343c..c38de306 100644 --- a/tests/OAuth2SummitLocationsApiTest.php +++ b/tests/OAuth2SummitLocationsApiTest.php @@ -11,7 +11,11 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ + +use App\Models\Foundation\Summit\Factories\SummitLocationFactory; use LaravelDoctrine\ORM\Facades\EntityManager; +use models\summit\SummitBookableVenueRoom; + /** * Class OAuth2SummitLocationsApiTest */ @@ -22,6 +26,39 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest $folder = $service->findOrMake('summits/1/locations/292/maps'); } + use InsertSummitTestData; + + private static $bookable_room; + + protected function setUp() + { + parent::setUp(); + self::insertTestData(); + + $data = [ + 'name' => 'test bookable room', + 'capacity' => 10, + 'description' => 'test bookable room', + 'time_slot_cost' => 200, + 'currency' => 'USD', + ]; + + $data['class_name'] = SummitBookableVenueRoom::ClassName; + self::$bookable_room = SummitLocationFactory::build($data); + + self::$summit->addLocation(self::$bookable_room); + self::$mainVenue->addRoom(self::$bookable_room); + + self::$em->persist(self::$summit); + self::$em->flush(); + } + + protected function tearDown() + { + self::clearTestData(); + parent::tearDown(); + } + public function testGetCurrentSummitLocations($summit_id = 23) { $params = [ @@ -1353,7 +1390,7 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest // bookable rooms tests - public function testSummitGetBookableRoomsFilterDiffValuesSameColumn($summit_id = 27) + public function testSummitGetBookableRoomsFilterDiffValuesSameColumn($summit_id = 6) { $params = [ 'id' => $summit_id, @@ -1362,8 +1399,9 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest 'order' => '-id', 'expand' => 'venue,attribute_type', 'filter' => [ - "attribute==Beer&&Screen", - "capacity<=20" + "availability_day==1579086000", + "attribute==", + "capacity>=1" ], ]; @@ -1391,7 +1429,7 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest $this->assertTrue(!is_null($rooms)); } - public function testSummitGetBookableRoomAvailability($summit_id = 27, $room_id = 922, $day = 1572829200) + public function testSummitGetBookableRoomAvailability($summit_id = 6, $room_id = 20, $day = 1579172400) { $params = [ 'id' => $summit_id, @@ -1429,18 +1467,17 @@ final class OAuth2SummitLocationsApiTest extends ProtectedApiTest * @param int $start_date * @return mixed */ - public function testBookableRoomReservation($summit_id =27, $start_date = 1572919200, $end_date = 1572922800){ - $bookable_room = $this->testAddBookableRoom($summit_id); + public function testBookableRoomReservation(){ $params = [ - 'id' => $summit_id, - 'room_id' => $bookable_room->id, + 'id' => self::$summit->getId(), + 'room_id' => self::$bookable_room->getId(), ]; $data = [ 'currency' => 'USD', 'amount' => 200, - 'start_datetime' => $start_date, - 'end_datetime' => $end_date, + 'start_datetime' => 1572919200, + 'end_datetime' => 1572922800, ]; $headers = [ diff --git a/tests/OAuth2SummitMediaFileTypeApiControllerTest.php b/tests/OAuth2SummitMediaFileTypeApiControllerTest.php new file mode 100644 index 00000000..41d6b9dd --- /dev/null +++ b/tests/OAuth2SummitMediaFileTypeApiControllerTest.php @@ -0,0 +1,70 @@ + str_random(16).'summit_media_file_type', + 'allowed_extensions' => ['PDF', 'SVG'] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitMediaFileTypeApiController@add", + [], + [], + [], + [], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $response = json_decode($content, true); + $this->assertResponseStatus(201); + $this->assertTrue(isset($response['id'])); + } + + public function testGetAll(){ + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitMediaFileTypeApiController@getAll", + [], + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $response = json_decode($content, true); + $this->assertTrue(isset($response['total'])); + $this->assertTrue(intval($response['total']) > 0); + } + +} \ No newline at end of file diff --git a/tests/OAuth2SummitMediaUploadTypeApiControllerTest.php b/tests/OAuth2SummitMediaUploadTypeApiControllerTest.php new file mode 100644 index 00000000..93f22083 --- /dev/null +++ b/tests/OAuth2SummitMediaUploadTypeApiControllerTest.php @@ -0,0 +1,275 @@ +persist(self::$summit); + self::$em->flush(); + } + + protected function tearDown() + { + self::clearTestData(); + parent::tearDown(); + } + + public function testAddGet(){ + + $types = self::$media_file_type_repository->findAll(); + $params = [ + 'id' => self::$summit->getId(), + 'expand' => 'type,presentation_types' + ]; + + $event_types = self::$summit->getEventTypes(); + + $payload = [ + 'name' => str_random(16).'media_upload_type', + 'type_id' => $types[0]->getId(), + 'description' => 'this is a description', + 'max_size' => 2048, + 'is_mandatory' => false, + 'private_storage_type' => \App\Models\Utils\IStorageTypesConstants::DropBox, + 'public_storage_type' => \App\Models\Utils\IStorageTypesConstants::Swift, + 'presentation_types' => [$event_types[0]->getId()] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitMediaUploadTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $response = json_decode($content, true); + $this->assertResponseStatus(201); + $this->assertTrue(isset($response['id'])); + + $response = $this->action( + "GET", + "OAuth2SummitMediaUploadTypeApiController@getAllBySummit", + [ + 'id' => self::$summit->getId(), + ], + [], + [], + [], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $response = json_decode($content, true); + + $this->assertResponseStatus(200); + + } + + public function testAddAndDeleteCascade(){ + + $types = self::$media_file_type_repository->findAll(); + $params = [ + 'id' => self::$summit->getId(), + 'expand' => 'type,presentation_types' + ]; + + $event_types = self::$summit->getEventTypes(); + + $payload = [ + 'name' => str_random(16).'media_upload_type', + 'type_id' => $types[0]->getId(), + 'description' => 'this is a description', + 'max_size' => 2048, + 'is_mandatory' => false, + 'private_storage_type' => \App\Models\Utils\IStorageTypesConstants::DropBox, + 'public_storage_type' => \App\Models\Utils\IStorageTypesConstants::Swift, + 'presentation_types' => [$event_types[0]->getId()] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitMediaUploadTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $response = json_decode($content, true); + $this->assertResponseStatus(201); + $this->assertTrue(isset($response['id'])); + + self::$em = Registry::resetManager(SilverstripeBaseModel::EntityManager); + $type = self::$media_file_type_repository->find($types[0]->getId()); + self::$em->remove($type); + self::$em->flush(); + } + + public function testAddDelete(){ + $types = self::$media_file_type_repository->findAll(); + $params = [ + 'id' => self::$summit->getId(), + 'expand' => 'type,presentation_types' + ]; + + $event_types = self::$summit->getEventTypes(); + + $payload = [ + 'name' => str_random(16).'media_upload_type', + 'type_id' => $types[0]->getId(), + 'description' => 'this is a description', + 'max_size' => 2048, + 'is_mandatory' => false, + 'private_storage_type' => \App\Models\Utils\IStorageTypesConstants::DropBox, + 'public_storage_type' => \App\Models\Utils\IStorageTypesConstants::Swift, + 'presentation_types' => [ $event_types[0]->getId() ] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitMediaUploadTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $response = json_decode($content, true); + $this->assertResponseStatus(201); + $this->assertTrue(isset($response['id'])); + + + $response = $this->action( + "DELETE", + "OAuth2SummitMediaUploadTypeApiController@delete", + [ + 'id' => self::$summit->getId(), + 'type_id' => intval($response['id']) + ], + [], + [], + [], + $headers, + json_encode($payload) + ); + $this->assertResponseStatus(204); + } + + public function testAddAddPresentationType(){ + + $types = self::$media_file_type_repository->findAll(); + $params = [ + 'id' => self::$summit->getId(), + 'expand' => 'type,presentation_types' + ]; + + $event_types = self::$summit->getEventTypes(); + + $payload = [ + 'name' => str_random(16).'media_upload_type', + 'type_id' => $types[0]->getId(), + 'description' => 'this is a description', + 'max_size' => 2048, + 'is_mandatory' => false, + 'private_storage_type' => \App\Models\Utils\IStorageTypesConstants::DropBox, + 'public_storage_type' => \App\Models\Utils\IStorageTypesConstants::Swift, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitMediaUploadTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $response = json_decode($content, true); + $this->assertResponseStatus(201); + $this->assertTrue(isset($response['id'])); + + $response = $this->action( + "PUT", + "OAuth2SummitMediaUploadTypeApiController@addToPresentationType", + [ + 'id' => self::$summit->getId(), + 'type_id' => intval($response['id']), + 'presentation_type_id' => $event_types[0]->getId() + ], + [], + [], + [], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $response = json_decode($content, true); + $this->assertResponseStatus(201); + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitOrderExtraQuestionTypeApiTest.php b/tests/OAuth2SummitOrderExtraQuestionTypeApiTest.php new file mode 100644 index 00000000..073b3648 --- /dev/null +++ b/tests/OAuth2SummitOrderExtraQuestionTypeApiTest.php @@ -0,0 +1,102 @@ + $summit_id + ]; + + $name = str_random(16).'_question'; + + $data = [ + 'name' => $name, + 'type' => SummitOrderExtraQuestionTypeConstants::ComboBoxQuestionType, + 'label' => $name, + 'usage' => SummitOrderExtraQuestionTypeConstants::BothQuestionUsage, + 'mandatory' => true, + 'printable' => true, + 'placeholder' => $name, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitOrderExtraQuestionTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $question = json_decode($content); + $this->assertTrue(!is_null($question)); + return $question; + } + + public function testAddQuestionValue($summit_id=27){ + $question = $this->testAddExtraOrderQuestion($summit_id); + $params = [ + 'id' => $summit_id, + 'question_id' => $question->id + ]; + + $name = str_random(16).'_question'; + + $data = [ + 'value' => $name, + 'label' => $name, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitOrderExtraQuestionTypeApiController@addQuestionValue", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $question = json_decode($content); + $this->assertTrue(!is_null($question)); + return $question; + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitOrdersApiTest.php b/tests/OAuth2SummitOrdersApiTest.php new file mode 100644 index 00000000..813dd861 --- /dev/null +++ b/tests/OAuth2SummitOrdersApiTest.php @@ -0,0 +1,899 @@ + IPaymentConstants::ApplicationTypeRegistration, + 'is_test_mode' => true, + 'test_publishable_key' => self::$test_public_key, + 'test_secret_key' => self::$test_secret_key, + 'is_active' => false, + ]); + + // build default badge type + + $defaultBadge = SummitBadgeTypeFactory::build([ + 'name' => 'DEFAULT', + 'is_default' => true, + ]); + + // build ticket type + + self::$ticketType = SummitTicketTypeFactory::build(self::$summit, [ + 'name' => 'TICKET_1', + 'cost' => 100, + 'quantity_2_sell' => 1000, + ]); + + self::$summit->addPaymentProfile(self::$profile); + self::$summit->addBadgeType($defaultBadge); + self::$summit->addTicketType(self::$ticketType); + + self::$em->persist(self::$summit); + self::$em->flush(); + } + + protected function tearDown() + { + //self::clearTestData(); + parent::tearDown(); + } + + /** + * @return mixed + */ + public function testGetAllMyOrders(){ + $params = [ + + 'page' => 1, + 'per_page' => 10, + 'order' => '+number', + 'expand' => 'tickets,tickets.owner,tickets.badge' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitOrdersApiController@getAllMyOrders", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $my_orders = json_decode($content); + $this->assertTrue(!is_null($my_orders)); + return $my_orders; + } + + /** + * @return mixed + */ + public function testGetAllMyTickets(){ + $params = [ + + 'page' => 1, + 'per_page' => 10, + 'order' => '+number', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitTicketApiController@getAllMyTickets", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $my_orders = json_decode($content); + $this->assertTrue(!is_null($my_orders)); + return $my_orders; + } + + public function testRefundOrderWithEmptyPayload($summit_id = 27, $order_id = 5){ + $params = [ + 'id' => $summit_id, + 'order_id' => $order_id + ]; + + $data = []; + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitOrdersApiController@refundOrder", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $this->assertResponseStatus(412); + + } + + public function testRefundTicketWithEmptyPayload($summit_id = 27, $ticket_id = 5){ + $params = [ + 'id' => $summit_id, + 'ticket_id' => $ticket_id + ]; + + $data = []; + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitTicketApiController@refundTicket", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $this->assertResponseStatus(412); + + } + + public function testRefundOrderWithoutPayload($summit_id = 27, $order_id = 5){ + $params = [ + 'id' => $summit_id, + 'order_id' => $order_id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitOrdersApiController@refundOrder", + $params, + [], + [], + [], + $headers + //json_encode($data) + ); + + $this->assertResponseStatus(412); + + } + /** + * @return mixed + */ + public function testUpdateMyOrder(){ + + $params = [ + 'order_id' => 7 + ]; + + $data = [ + 'owner_company' => 'OpenStack', + 'billing_address_1' => 'Siempre Viva Av.', + 'extra_questions' => [ + ['question_id' => 1, 'answer' => 'test'], + ] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitOrdersApiController@updateMyOrder", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $order = json_decode($content); + $this->assertTrue(!is_null($order)); + return $order; + } + + /** + * @return mixed + */ + public function testUpdateOrder($summit_id = 27, $order_id =7){ + + $params = [ + 'id' => $summit_id, + 'order_id' => $order_id + ]; + + $data = [ + 'owner_first_name' => 'Sebastian', + 'owner_last_name' => 'Sebastian', + 'owner_email' => 'smarcet@gmail.com', + 'owner_company' => 'OpenStack', + 'billing_address_1' => 'Siempre Viva Av.', + 'extra_questions' => [ + ['question_id' => 3, 'answer' => '1'], + ['question_id' => 4, 'answer' => ''], + ['question_id' => 5, 'answer' => ''], + ] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitOrdersApiController@update", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $order = json_decode($content); + $this->assertTrue(!is_null($order)); + return $order; + } + + public function testReserveWithoutActivePaymentProfile(){ + + self::$profile->disable(); + self::$em->persist(self::$profile); + self::$em->flush(); + + $params = [ + 'id' => self::$summit->getId(), + ]; + + $data = [ + "owner_email" => "smarcet@gmail.com", + "owner_first_name" => "Sebastian", + "owner_last_name" => "Marcet", + "owner_company"=>"Pumant", + "tickets" => [ + ["type_id" => self::$ticketType->getId()], + ["type_id" => self::$ticketType->getId()], + ["type_id" => self::$ticketType->getId()], + ] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitOrdersApiController@reserve", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + //$this->assertResponseStatus(412); + $this->assertResponseStatus(201); + $order = json_decode($content); + $this->assertTrue(!is_null($order)); + return $order; + } + + public function testReserveWithActivePaymentProfile(){ + + self::$profile->activate(); + self::$em->persist(self::$profile); + self::$em->flush(); + + $params = [ + 'id' => self::$summit->getId(), + ]; + + $data = [ + "owner_email" => "smarcet@gmail.com", + "owner_first_name" => "Sebastian", + "owner_last_name" => "Marcet", + "owner_company"=>"Pumant", + "tickets" => [ + ["type_id" => self::$ticketType->getId()], + ["type_id" => self::$ticketType->getId()], + ["type_id" => self::$ticketType->getId()], + ] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitOrdersApiController@reserve", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $order = json_decode($content); + $this->assertTrue(!is_null($order)); + return $order; + } + + public function testReserveFailingPromoCode(){ + $params = [ + 'id' => self::$summit->getId(), + ]; + + $data = [ + "owner_email" => "smarcet@gmail.com", + "owner_first_name" => "Sebastian", + "owner_last_name" => "Marcet", + "owner_company"=>"Pumant", + "tickets" => [ + ["type_id" => self::$ticketType->getId(), "promo_code"=>"test100"], + ["type_id" => self::$ticketType->getId(), "promo_code"=>"Test100"], + ["type_id" => self::$ticketType->getId(), "promo_code"=>"TesT100"], + ] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitOrdersApiController@reserve", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(412); + } + + public function testTicketAssignmentWithoutExtraQuestions(){ + $params = [ + 'order_id' => 23, + 'ticket_id' => 21, + ]; + + $data = [ + "attendee_email" => "sebastian.jose@gmail.com", + "attendee_first_name" => "sebastian", + "attendee_last_name" => 'marcet', + "attendee_company" => "pumant", + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitOrdersApiController@assignAttendee", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(412); + } + + /** + * @param int $summit_id + * @param string $hash + */ + public function testCheckoutFailedCountryValidation($summit_id= 27, $hash = 'ab45277bd50ba2d3284e56f06f2710049e5950927ec304fb7f8ea36e43cea931'){ + + $params = [ + 'id' => $summit_id, + 'hash' => $hash + ]; + + $data = [ + 'billing_address_1' => 'test', + 'billing_address_2' => 'test', + 'billing_address_zip_code' => 'test', + 'billing_address_city' => 'test', + 'billing_address_state' => 'test', + 'billing_address_country' => 'test', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitOrdersApiController@checkout", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(412); + $this->assertTrue(str_contains($content, "billing_address_country")); + } + + /** + * @param int $summit_id + * @param string $hash + */ + public function testGetTicketForEditionByOrderHash($summit_id = 1, $hash = 'eb758846226109a736c512a6e0d682bdc6a3af67a0ad316315158f49c5f8f7e9'){ + + $params = [ + 'id' => $summit_id, + 'hash' => $hash + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "GET", + "OAuth2SummitOrdersApiController@getMyTicketByOrderHash", + $params, + [], + [], + [], + $headers, + [] + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $ticket = json_decode($content); + $this->assertTrue(!is_null($ticket)); + return $ticket; + } + + /** + * @param int $summit_id + * @param int $order_id + * @param int $ticket_id + * @return mixed + */ + public function testUpdateTicket($summit_id = 1, $order_id = 23 , $ticket_id = 21){ + + $params = [ + 'id' => $summit_id, + 'order_id' => $order_id, + 'ticket_id' => $ticket_id, + ]; + + $data = [ + 'attendee_first_name' => 'Jose Arturo', + 'attendee_last_name' => 'Campanella', + 'attendee_email' => 'jcampanella@gmail.com', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitOrdersApiController@updateTicket", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $ticket = json_decode($content); + $this->assertTrue(!is_null($ticket)); + return $ticket; + } + + /** + * @return mixed + */ + public function testRevokeAttendee(){ + + $params = [ + 'order_id' => 6, + 'ticket_id' => 18925, + ]; + + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitOrdersApiController@removeAttendee", + $params, + [], + [], + [], + $headers + + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $ticket = json_decode($content); + $this->assertTrue(!is_null($ticket)); + return $ticket; + } + + public function testRegenerateTicketHash(){ + + $params = [ + 'hash' => '25f6d007523cc64b52fc513c49176119ef431f955eb8ace8cd3cdc959ab77893', + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitOrdersApiController@regenerateTicketHash", + $params, + [], + [], + [] + ); + + $this->assertResponseStatus(200); + } + + public function testGetTicketByHash(){ + + $params = [ + 'hash' => '87fb1166e8c41cfb4457dc1f5d11413549aeca833691bbbd6563f6335a948562', + 'expand' => 'owner,order,applied_taxes, applied_taxes.tax' + ]; + + $response = $this->action( + "GET", + "OAuth2SummitOrdersApiController@getTicketByHash", + $params, + [], + [], + [] + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $ticket = json_decode($content); + $this->assertTrue(!is_null($ticket)); + return $ticket; + } + + public function testCreateSingleTicketOrder(){ + + $params = [ + 'summit_id' => self::$summit->getId() + ]; + + $data = [ + 'owner_first_name' => 'Sebastian', + 'owner_last_name' => 'Marcet', + 'owner_email' => 'smarcet@gmail.com', + 'ticket_type_id' => self::$ticketType->getId(), + "owner_company" => "Pumant", + //'promo_code' => 'STAFF' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitOrdersApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $order = json_decode($content); + $this->assertTrue(!is_null($order)); + return $order; + } + + public function testCreateSingleTicketOrderNotComplete(){ + + $params = [ + 'summit_id' => self::$summit->getId() + ]; + + $data = [ + 'owner_first_name' => 'Sebastian', + 'owner_last_name' => 'Marcet', + 'owner_email' => 'smarcet@gmail.com', + 'ticket_type_id' => self::$ticketType->getId(), + "owner_company" => "Pumant", + //'promo_code' => 'STAFF' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitOrdersApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $order = json_decode($content); + $this->assertTrue(!is_null($order)); + return $order; + } + + /** + * @param int $summit_id + * @param int $order_id + */ + public function testDeleteOrder($summit_id=27, $order_id = 6){ + $params = [ + 'summit_id' => $summit_id, + 'order_id' => $order_id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitOrdersApiController@delete", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + } + + public function testGetAllOrders($summit_id=3){ + $params = [ + 'summit_id' => $summit_id, + 'page' => 1, + 'per_page' => 10, + 'order' => '+id', + 'expand' => 'tickets,tickets.owner', + //'filter' => 'status<>Cancelled,status<>Reserved', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitOrdersApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $orders = json_decode($content); + $this->assertTrue(!is_null($orders)); + return $orders; + } + + public function testGetTicketPdfByID($ticket_id=21){ + $params = [ + 'ticket_id' => $ticket_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitOrdersApiController@getTicketPDFById", + $params, + [], + [], + [], + $headers + ); + + $pdf_content = $response->getContent(); + $this->assertResponseStatus(200); + $this->assertTrue(!is_null($pdf_content)); + return $pdf_content; + } + + public function testUpdateTicketById($ticket_id = 28){ + $params = [ + '$ticket_id' => $ticket_id + ]; + + $data = [ + 'owner_first_name' => 'Sebastian', + 'owner_last_name' => 'Marcet', + 'owner_email' => 'sebastian@marcet.com.ar', + 'disclaimer_accepted' => true, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitOrdersApiController@updateTicketById", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $order = json_decode($content); + $this->assertTrue(!is_null($order)); + return $order; + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitRefundPolicyTypeApiTest.php b/tests/OAuth2SummitRefundPolicyTypeApiTest.php new file mode 100644 index 00000000..19cca57e --- /dev/null +++ b/tests/OAuth2SummitRefundPolicyTypeApiTest.php @@ -0,0 +1,111 @@ + $summit_id, + ]; + + $name = str_random(16) . '_policy'; + $data = [ + 'name' => $name, + 'until_x_days_before_event_starts' => $until_x_days_before_event_starts, + 'refund_rate' => 90.50 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitRefundPolicyTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $policy = json_decode($content); + $this->assertTrue(!is_null($policy)); + $this->assertTrue($policy->name == $name); + return $policy; + } + + public function testGetAllPoliciesBySummit($summit_id=27){ + $params = [ + 'id' => $summit_id, + 'filter' => 'until_x_days_before_event_starts<=15' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitRefundPolicyTypeApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $data = json_decode($content); + $this->assertTrue(!is_null($data)); + } + + public function testDeletePolicy($summit_id=27){ + $policy = $this->testAddPolicy($summit_id, 2); + + $params = [ + 'id' => $summit_id, + 'policy_id' => $policy->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitRefundPolicyTypeApiController@delete", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitRegistrationInvitationApiControllerTest.php b/tests/OAuth2SummitRegistrationInvitationApiControllerTest.php new file mode 100644 index 00000000..9c9b6495 --- /dev/null +++ b/tests/OAuth2SummitRegistrationInvitationApiControllerTest.php @@ -0,0 +1,212 @@ +seedDefaultEmailFlowEvents(); + } + + protected function tearDown() + { + self::clearTestData(); + parent::tearDown(); + } + + public function testIngestInvitationsAndGet(){ + $csv_content = << self::$summit->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "POST", + "OAuth2SummitRegistrationInvitationApiController@ingestInvitations", + $params, + [], + [], + [ + 'file' => $file + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + + + $params = [ + 'summit_id' => self::$summit->getId(), + 'filter'=> 'is_accepted==true' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "GET", + "OAuth2SummitRegistrationInvitationApiController@getAllBySummit", + $params, + [], + [], + [ + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + } + + public function testIngestInvitationsAndGetCSV(){ + $csv_content = << self::$summit->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "POST", + "OAuth2SummitRegistrationInvitationApiController@ingestInvitations", + $params, + [], + [], + [ + 'file' => $file + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + + + $params = [ + 'summit_id' => self::$summit->getId(), + 'filter'=> 'is_accepted==false' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "GET", + "OAuth2SummitRegistrationInvitationApiController@getAllBySummitCSV", + $params, + [], + [], + [ + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $this->assertTrue(!empty($content)); + } + + + public function testIngestInvitationsAndResend(){ + $csv_content = << self::$summit->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "POST", + "OAuth2SummitRegistrationInvitationApiController@ingestInvitations", + $params, + [], + [], + [ + 'file' => $file + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + + + $response = $this->action( + "PUT", + "OAuth2SummitRegistrationInvitationApiController@resendNonAccepted", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + } + + + +} \ No newline at end of file diff --git a/tests/OAuth2SummitSponsorApiTest.php b/tests/OAuth2SummitSponsorApiTest.php new file mode 100644 index 00000000..402f1f58 --- /dev/null +++ b/tests/OAuth2SummitSponsorApiTest.php @@ -0,0 +1,153 @@ + $summit_id + ]; + + $company_repository = EntityManager::getRepository(\models\main\Company::class); + $sponsorship_type_repository = EntityManager::getRepository(\models\summit\SponsorshipType::class); + $company = $company_repository->find($company_id); + $sponsorship_type = $sponsorship_type_repository->find(1); + + $data = [ + 'company_id' => $company->getId(), + 'sponsorship_id' => $sponsorship_type->getId(), + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitSponsorApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $sponsor = json_decode($content); + $this->assertTrue(!is_null($sponsor)); + return $sponsor; + } + + public function testGetAllSponsorsBySummit($summit_id =27){ + $params = [ + 'id' => $summit_id, + 'filter'=> 'company_name=@Rack', + 'expand' => 'company,sponsorship' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitSponsorApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $page = json_decode($content); + $this->assertTrue(!is_null($page)); + return $page; + } + + public function testDeleteSponsor($summit_id = 27){ + $sponsor = $this->testAddSponsor($summit_id, 10); + $params = [ + 'id' => $summit_id, + 'sponsor_id'=> $sponsor->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitSponsorApiController@delete", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + $this->assertTrue(empty($content)); + } + + /** + * @param int $summit_id + * @param int $sponsor_id + * @param int $member_id + * @return mixed + */ + public function testAddSponsorUserMember($summit_id =27, $sponsor_id = 750, $member_id=1){ + $params = [ + 'id' => $summit_id, + 'sponsor_id' => $sponsor_id, + 'member_id' => $member_id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitSponsorApiController@addSponsorUser", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $sponsor = json_decode($content); + $this->assertTrue(!is_null($sponsor)); + return $sponsor; + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitTaxTypeApiTest.php b/tests/OAuth2SummitTaxTypeApiTest.php new file mode 100644 index 00000000..bac024c1 --- /dev/null +++ b/tests/OAuth2SummitTaxTypeApiTest.php @@ -0,0 +1,130 @@ + $summit_id, + ]; + + $name = str_random(16).'_ticket_type'; + + $data = [ + 'name' => $name, + 'cost' => 250.25, + 'currency' => 'USD', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitsTicketTypesApiController@addTicketTypeBySummit", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $ticket_type = json_decode($content); + $this->assertTrue(!is_null($ticket_type)); + $this->assertTrue($ticket_type->name == $name); + return $ticket_type; + } + + /** + * @param int $summit_id + * @return mixed + */ + public function testAddTaxType($summit_id = 27){ + $this->ticket_type = $this->addTicketType($summit_id); + + $params = [ + 'id' => $summit_id, + ]; + + $name = str_random(16).'_iva'; + $data = [ + 'name' => $name, + 'rate' => 21.0 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitTaxTypeApiController@add", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $tax_type = json_decode($content); + $this->assertTrue(!is_null($tax_type)); + $this->assertTrue($tax_type->name == $name); + + $params = [ + 'id' => $summit_id, + 'tax_id' => $tax_type->id, + 'ticket_type_id' => $this->ticket_type->id + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitTaxTypeApiController@addTaxToTicketType", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $tax_type = json_decode($content); + + return $tax_type; + } +} \ No newline at end of file diff --git a/tests/OAuth2SummitTicketsApiTest.php b/tests/OAuth2SummitTicketsApiTest.php new file mode 100644 index 00000000..d10af786 --- /dev/null +++ b/tests/OAuth2SummitTicketsApiTest.php @@ -0,0 +1,420 @@ + $summit_id, + 'page' => 1, + 'per_page' => 10, + 'order' => '+id', + 'expand' => 'owner,order,ticket_type,badge,promo_code' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitTicketApiController@getAllBySummit", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $tickets = json_decode($content); + $this->assertTrue(!is_null($tickets)); + return $tickets; + } + + /** + * @param int $summit_id + * @return mixed + */ + public function testGetAllTicketsCSV($summit_id = 4){ + + $params = [ + 'summit_id' => $summit_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitTicketApiController@getAllBySummitCSV", + $params, + [], + [], + [], + $headers + ); + + $csv = $response->getContent(); + $this->assertResponseStatus(200); + $this->assertTrue(!empty($csv)); + return $csv; + } + + public function testGetTicketImportTemplate($summit_id = 3){ + + $params = [ + 'summit_id' => $summit_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitTicketApiController@getImportTicketDataTemplate", + $params, + [], + [], + [], + $headers + ); + + $csv = $response->getContent(); + $this->assertResponseStatus(200); + $this->assertTrue(!empty($csv)); + return $csv; + } + + public function testIngestTicketData($summit_id = 1){ + $csv_content = << $summit_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "POST", + "OAuth2SummitTicketApiController@importTicketData", + $params, + [], + [], + [ + 'file' => $file + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + } + + public function testIngestTicketData2($summit_id = 1){ + $csv_content = << $summit_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + ]; + + $response = $this->action( + "POST", + "OAuth2SummitTicketApiController@importTicketData", + $params, + [], + [], + [ + 'file' => $file + ], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + } + + /** + * @param int $summit_id + * @param string $number + * @return mixed + */ + public function testGetTicketByNumber($summit_id = 27, $number = 'SHANGHAI2019_TICKET_5D658DE87978A699249976'){ + $params = [ + 'summit_id' => $summit_id, + 'ticket_id' => $number, + 'expand' => 'order' + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitTicketApiController@get", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + $ticket = json_decode($content); + $this->assertTrue(!is_null($ticket)); + return $ticket; + } + + // badges endpoints + + /** + * @param int $summit_id + * @param string $number + * @return mixed + */ + public function testCreateAttendeeBadge($summit_id = 27, $number = 'SHANGHAI2019_TICKET_5D658F4EF058F555164878'){ + $params = [ + 'id' => $summit_id, + 'ticket_id' => $number + ]; + $data = [ + 'badge_type_id' => 2, + 'features' => [1, 2] + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "POST", + "OAuth2SummitTicketApiController@createAttendeeBadge", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $badge = json_decode($content); + $this->assertTrue(!is_null($badge)); + return $badge; + } + + public function testRemoveAttendeeBadgeFeature($summit_id = 27, $number = 'SHANGHAI2019_TICKET_5D658F4EF058F555164878', $feature_id = 1){ + $params = [ + 'id' => $summit_id, + 'ticket_id' => $number, + 'feature_id' => $feature_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitTicketApiController@removeAttendeeBadgeFeature", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $badge = json_decode($content); + $this->assertTrue(!is_null($badge)); + return $badge; + } + + public function testAddAttendeeBadgeFeature($summit_id = 27, $number = 'SHANGHAI2019_TICKET_5D658F4EF058F555164878', $feature_id = 1){ + $params = [ + 'id' => $summit_id, + 'ticket_id' => $number, + 'feature_id' => $feature_id, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitTicketApiController@addAttendeeBadgeFeature", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $badge = json_decode($content); + $this->assertTrue(!is_null($badge)); + return $badge; + } + + /** + * @param int $summit_id + * @param string $number + * @param int $type + * @return mixed + */ + function testUpdateAttendeeBadgeType($summit_id = 27, $number = 'SHANGHAI2019_TICKET_5D658F4EF058F555164878', $type = 1){ + $params = [ + 'id' => $summit_id, + 'ticket_id' => $number, + 'type_id' => $type, + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitTicketApiController@updateAttendeeBadgeType", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $badge = json_decode($content); + $this->assertTrue(!is_null($badge)); + return $badge; + } + /** + * @param int $summit_id + * @param string $number + * @return mixed + */ + public function testDeleteAttendeeBadge($summit_id = 27, $number = 'SHANGHAI2019_TICKET_5D658F4EF058F555164878'){ + $params = [ + 'id' => $summit_id, + 'ticket_id' => $number + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "DELETE", + "OAuth2SummitTicketApiController@deleteAttendeeBadge", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(204); + } + + + /** + * @param int $summit_id + * @param string $number + * @return mixed + */ + function testPrintAttendeeBadge($summit_id = 1, $number = 'REGISTRATIONDEVSUMMIT2019_TICKET_5D7BE0E518E8C161661586'){ + $params = [ + 'id' => $summit_id, + 'ticket_id' => $number, + 'expand' => 'features', + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitTicketApiController@printAttendeeBadge", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $badge = json_decode($content); + $this->assertTrue(!is_null($badge)); + return $badge; + } +} \ No newline at end of file diff --git a/tests/OAuth2TicketTypesApiTest.php b/tests/OAuth2TicketTypesApiTest.php index d672f32f..5f35dfb9 100644 --- a/tests/OAuth2TicketTypesApiTest.php +++ b/tests/OAuth2TicketTypesApiTest.php @@ -83,6 +83,7 @@ final class OAuth2TicketTypesApiTest extends ProtectedApiTest return $ticket_type; } + /** * @param int $summit_id * @return mixed diff --git a/tests/OAuth2TrackQuestionsTemplateTest.php b/tests/OAuth2TrackQuestionsTemplateTest.php index 04ff6222..a32595ad 100644 --- a/tests/OAuth2TrackQuestionsTemplateTest.php +++ b/tests/OAuth2TrackQuestionsTemplateTest.php @@ -55,7 +55,7 @@ final class OAuth2TrackQuestionsTemplateTest * @return mixed */ public function testAddTrackQuestionTemplate( - $class_name = TrackTextBoxQuestionTemplate::ClassName, $extra_data = []){ + $class_name = TrackTextBoxQuestionTemplate::ClassName, $extra_data = []){ $params = [ 'expand' => 'tracks' ]; diff --git a/tests/OAuth2TrackTagGroupsApiTest.php b/tests/OAuth2TrackTagGroupsApiTest.php index 91866cb5..5d3f1cdb 100644 --- a/tests/OAuth2TrackTagGroupsApiTest.php +++ b/tests/OAuth2TrackTagGroupsApiTest.php @@ -188,7 +188,7 @@ final class OAuth2TrackTagGroupsApiTest extends ProtectedApiTest $params = [ 'id' => $summit_id, //AND FILTER - 'filter' => ['tag=@101'], + 'filter' => ['tag=@101||104'], 'order' => '+id', 'expand' => 'tag,track_tag_group' ]; diff --git a/tests/PresentationMediaUploadsTests.php b/tests/PresentationMediaUploadsTests.php new file mode 100644 index 00000000..417c484a --- /dev/null +++ b/tests/PresentationMediaUploadsTests.php @@ -0,0 +1,111 @@ +findAll(); + self::insertTestData(); + self::$media_upload_type = new SummitMediaUploadType(); + self::$media_upload_type->setType($types[0]); + self::$media_upload_type->setName('TEST'); + self::$media_upload_type->setDescription("TEST"); + + self::$media_upload_type->setMaxSize(2048); + self::$media_upload_type->setPrivateStorageType(\App\Models\Utils\IStorageTypesConstants::DropBox); + self::$media_upload_type->setPublicStorageType(\App\Models\Utils\IStorageTypesConstants::DropBox); + self::$presentation = new Presentation(); + $event_types = self::$summit->getEventTypes(); + self::$presentation->setTitle("TEST PRESENTATION"); + self::$presentation->setType($event_types[0]); + self::$summit->addEvent(self::$presentation); + self::$media_upload_type->addPresentationType($event_types[0]); + self::$summit->addMediaUploadType(self::$media_upload_type); + self::$em->persist(self::$summit); + self::$em->flush(); + } + + protected function tearDown() + { + self::clearTestData(); + parent::tearDown(); + } + + public function testAddMediaUpload(){ + $params = [ + + 'id' => self::$summit->getId(), + 'presentation_id' => self::$presentation->getId(), + 'expand' => 'media_upload_type,media_upload_type.type', + ]; + + $headers = [ + + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "multipart/form-data; boundary=----WebKitFormBoundaryBkSYnzBIiFtZu4pb" + ]; + + $payload = [ + 'media_upload_type_id' => self::$media_upload_type->getId() + ]; + + $response = $this->action + ( + "POST", + "OAuth2PresentationApiController@addPresentationMediaUpload", + $params, + $payload, + [], + [ + 'file' => UploadedFile::fake()->image('slide.png') + ], + $headers, + json_encode($payload) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + $response = json_decode($content, true); + + $this->assertTrue(isset($response['public_url'])); + } +} \ No newline at end of file diff --git a/tests/ProtectedApiTest.php b/tests/ProtectedApiTest.php index b470cb56..876e9d17 100644 --- a/tests/ProtectedApiTest.php +++ b/tests/ProtectedApiTest.php @@ -18,12 +18,32 @@ use App\Models\ResourceServer\IAccessTokenService; use App\Security\SummitScopes; use App\Security\OrganizationScopes; use App\Security\MemberScopes; +use App\Models\Foundation\Main\IGroup; /** * Class AccessTokenServiceStub */ class AccessTokenServiceStub implements IAccessTokenService { + /** + * @param mixed $user_id + */ + public function setUserId($user_id): void + { + $this->user_id = $user_id; + } + /** + * @param mixed $user_external_id + */ + public function setUserExternalId($user_external_id): void + { + $this->user_external_id = $user_external_id; + } + + + private $user_id; + + private $user_external_id; /** * @param string $token_value * @return AccessToken @@ -70,6 +90,22 @@ class AccessTokenServiceStub implements IAccessTokenService sprintf(SummitScopes::ReadMyBookableRoomsReservationData, $url), sprintf(SummitScopes::WriteMyBookableRoomsReservationData, $url), sprintf(SummitScopes::SendMyScheduleMail, $url), + sprintf(SummitScopes::ReadMyRegistrationOrders, $url), + sprintf(SummitScopes::ReadRegistrationOrders, $url), + sprintf(SummitScopes::UpdateRegistrationOrders, $url), + sprintf(SummitScopes::CreateOfflineRegistrationOrders, $url), + sprintf(SummitScopes::DeleteRegistrationOrders, $url), + sprintf(SummitScopes::UpdateRegistrationOrders, $url), + sprintf(SummitScopes::UpdateMyRegistrationOrders, $url), + sprintf(SummitScopes::WriteBadgeScan, $url), + sprintf(SummitScopes::ReadBadgeScan, $url), + sprintf(SummitScopes::CreateRegistrationOrders, $url), + sprintf(SummitScopes::ReadSummitAdminGroups, $url), + sprintf(SummitScopes::WriteSummitAdminGroups, $url), + sprintf(SummitScopes::EnterEvent, $url), + sprintf(SummitScopes::LeaveEvent, $url), + sprintf(SummitScopes::ReadSummitMediaFileTypes, $url), + sprintf(SummitScopes::WriteSummitMediaFileTypes, $url), ); return AccessToken::createFromParams( @@ -78,12 +114,22 @@ class AccessTokenServiceStub implements IAccessTokenService 'scope' => implode(' ', $scopes), 'client_id' => '1', 'audience' => $realm, - 'user_id' => '1', - 'user_external_id' => '13867', + 'user_id' => $this->user_id, + 'user_external_id' => $this->user_external_id, 'expires_in' => 3600, 'application_type' => 'WEB_APPLICATION', 'allowed_return_uris' => 'https://www.openstack.org/OpenStackIdAuthenticator,https://www.openstack.org/Security/login', - 'allowed_origins' => '' + 'allowed_origins' => '', + 'user_groups' => [ + [ + 'slug' => 'badge-printers', + + ], + [ + 'slug' => 'administrators', + + ], + ], ] ); } @@ -136,7 +182,23 @@ class AccessTokenServiceStub2 implements IAccessTokenService sprintf(OrganizationScopes::ReadOrganizationData, $url), sprintf(SummitScopes::WritePresentationMaterialsData, $url), sprintf(SummitScopes::ReadMyBookableRoomsReservationData, $url), + sprintf(SummitScopes::ReadRegistrationOrders, $url), sprintf(SummitScopes::WriteMyBookableRoomsReservationData, $url), + sprintf(SummitScopes::ReadMyRegistrationOrders, $url), + sprintf(SummitScopes::UpdateRegistrationOrders, $url), + sprintf(SummitScopes::UpdateMyRegistrationOrders, $url), + sprintf(SummitScopes::CreateOfflineRegistrationOrders, $url), + sprintf(SummitScopes::DeleteRegistrationOrders, $url), + sprintf(SummitScopes::UpdateRegistrationOrders, $url), + sprintf(SummitScopes::WriteBadgeScan, $url), + sprintf(SummitScopes::ReadBadgeScan, $url), + sprintf(SummitScopes::CreateRegistrationOrders, $url), + sprintf(SummitScopes::ReadSummitAdminGroups, $url), + sprintf(SummitScopes::WriteSummitAdminGroups, $url), + sprintf(SummitScopes::EnterEvent, $url), + sprintf(SummitScopes::LeaveEvent, $url), + sprintf(SummitScopes::ReadSummitMediaFileTypes, $url), + sprintf(SummitScopes::WriteSummitMediaFileTypes, $url), ); return AccessToken::createFromParams( @@ -150,37 +212,61 @@ class AccessTokenServiceStub2 implements IAccessTokenService 'expires_in' => 3600, 'application_type' => 'SERVICE', 'allowed_return_uris' => '', - 'allowed_origins' => '' + 'allowed_origins' => '', + 'user_groups' => [ + [ + //'slug' => 'administrators' + ] + ], ] ); } } + + /** * Class ProtectedApiTest */ abstract class ProtectedApiTest extends \Tests\BrowserKitTestCase { + use InsertMemberTestData; /** * @var string */ protected $access_token; + protected $current_group = IGroup::Administrators; + + static $service; + /** + * @return \Illuminate\Foundation\Application + */ public function createApplication() { $app = parent::createApplication(); - App::singleton('App\Models\ResourceServer\IAccessTokenService', 'AccessTokenServiceStub'); + self::$service = new AccessTokenServiceStub(); + + App::singleton(IAccessTokenService::class, function () { return self::$service; }); return $app; } - public function setUp() - { - $this->access_token = '123456789'; - parent::setUp(); + protected function setCurrentGroup(string $group){ + $this->current_group = $group; } - public function tearDown() + protected function setUp() { + $this->access_token = 'TEST_ACCESS_TOKEN'; + parent::setUp(); + self::insertMemberTestData($this->current_group); + self::$service->setUserId(self::$member->getUserExternalId()); + self::$service->setUserExternalId(self::$member->getUserExternalId()); + } + + protected function tearDown() + { + self::clearMemberTestData(); Mockery::close(); parent::tearDown(); } diff --git a/tests/StripeInterfaceTest.php b/tests/StripeInterfaceTest.php new file mode 100644 index 00000000..42b8d601 --- /dev/null +++ b/tests/StripeInterfaceTest.php @@ -0,0 +1,146 @@ + IPaymentConstants::ApplicationTypeRegistration, + 'is_test_mode' => true, + 'test_publishable_key' => self::$test_public_key, + 'test_secret_key' => self::$test_secret_key, + 'is_active' => false, + ]); + + self::$summit->addPaymentProfile($profile); + self::$em->persist(self::$summit); + self::$em->flush(); + + $summit2 = self::$summit_repository->findOneBy(['id' => self::$summit->getId()]); + + $this->assertTrue(!is_null($summit2)); + $this->assertTrue($summit2 instanceof Summit); + $profile->activate(); + $profile = $summit2->getPaymentGateWayProfilePerApp(IPaymentConstants::ApplicationTypeRegistration); + $this->assertTrue(!is_null($profile)); + $this->assertTrue($profile instanceof StripePaymentProfile); + if($profile instanceof StripePaymentProfile){ + $profile->buildWebHook(); + } + + self::$em->persist($summit2); + self::$em->flush(); + } + + /** + * @throws \models\exceptions\ValidationException + */ + public function testAddPaymentGatewayConfig2SummitAndChangeToLive(){ + + // build payment profile and attach to summit + $profile = PaymentGatewayProfileFactory::build(IPaymentConstants::ProviderStripe, [ + 'application_type' => IPaymentConstants::ApplicationTypeRegistration, + 'is_test_mode' => true, + 'test_publishable_key' => self::$test_public_key, + 'test_secret_key' => self::$test_secret_key, + 'live_publishable_key' => self::$live_public_key, + 'live_secret_key' => self::$live_secret_key, + 'is_active' => true, + ]); + + self::$summit->addPaymentProfile($profile); + self::$em->persist(self::$summit); + self::$em->flush(); + + $summit2 = self::$summit_repository->findOneBy(['id' => self::$summit->getId()]); + + $this->assertTrue(!is_null($summit2)); + $this->assertTrue($summit2 instanceof Summit); + + $profile = $summit2->getPaymentGateWayProfilePerApp(IPaymentConstants::ApplicationTypeRegistration); + $this->assertTrue(!is_null($profile)); + $this->assertTrue($profile instanceof StripePaymentProfile); + if($profile instanceof StripePaymentProfile){ + // build hook on test + $profile->setTestMode(); + $profile->buildWebHook(); + // build hook on live + $profile->setLiveMode(); + $profile->buildWebHook(); + } + + self::$em->persist($summit2); + self::$em->flush(); + } + + +} \ No newline at end of file diff --git a/tests/SummitAttendeeTicketRendererTest.php b/tests/SummitAttendeeTicketRendererTest.php new file mode 100644 index 00000000..fb148368 --- /dev/null +++ b/tests/SummitAttendeeTicketRendererTest.php @@ -0,0 +1,37 @@ +getById(19223); + + $render = new SummitAttendeeTicketPDFRenderer($ticket); + $output = $render->render(); + + $this->assertTrue(!empty($output)); + + $f = TCPDF_STATIC::fopenLocal("/tmp/ticket.pdf", 'wb'); + fwrite($f, $output, strlen($output)); + fclose($f); + } +} \ No newline at end of file diff --git a/tests/SummitDocumentModelTest.php b/tests/SummitDocumentModelTest.php new file mode 100644 index 00000000..ad1e9404 --- /dev/null +++ b/tests/SummitDocumentModelTest.php @@ -0,0 +1,66 @@ +persist(self::$summit); + self::$em->flush(); + } + + protected function tearDown() + { + self::clearTestData(); + parent::tearDown(); + } + + public function testModelRelations(){ + + $fileUploader = App::make(IFileUploader::class); + $file = $fileUploader->build + ( + UploadedFile::fake()->image('slide.pdf'), + sprintf('summits/%s/documents', self::$summit->getId()), + false + ); + + $doc1 = new SummitDocument(); + $doc1->setName('doc 1'); + $doc1->setLabel("doc 1"); + $doc1->setDescription("this is the doc 1"); + $doc1->setFile($file); + + self::$summit->addSummitDocument($doc1); + + self::$em->persist(self::$summit); + self::$em->flush(); + + $link = $file->getCloudLink(); + + $this->assertTrue(!empty($link)); + } + +} \ No newline at end of file diff --git a/tests/SummitEventMetricsTest.php b/tests/SummitEventMetricsTest.php new file mode 100644 index 00000000..49685653 --- /dev/null +++ b/tests/SummitEventMetricsTest.php @@ -0,0 +1,101 @@ +delete(); + DB::table("SummitEvent")->delete(); + self::$event_repository = EntityManager::getRepository(SummitEvent::class); + $time_zone = new DateTimeZone("America/Chicago"); + $now = new \DateTime("now", $time_zone); + self::$event1 = new Presentation(); + self::$event1->setTitle("PRESENTATION 1"); + self::$event1->setStartDate((clone $now)->add(new DateInterval("P1D"))); + self::$event1->setEndDate((clone $now)->add(new DateInterval("P2D"))); + + self::$summit->addEvent(self::$event1); + self::$event1->publish(); + self::$em->persist(self::$event1); + self::$em->flush(); + } + + public function tearDown() + { + self::clearTestData(); + Mockery::close(); + } + + public function testEventEnter(){ + + $params = [ + 'id' => self::$summit->getId(), + 'member_id' => 'me', + 'event_id' => self::$event1->getId() + ]; + + $data = [ + + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "PUT", + "OAuth2SummitMembersApiController@enterToEvent", + $params, + [], + [], + [], + $headers, + json_encode($data) + ); + + $content = $response->getContent(); + $this->assertResponseStatus(201); + } + +} \ No newline at end of file diff --git a/tests/SummitOrderJobsTest.php b/tests/SummitOrderJobsTest.php new file mode 100644 index 00000000..a968336d --- /dev/null +++ b/tests/SummitOrderJobsTest.php @@ -0,0 +1,160 @@ +shouldReceive('getId')->andReturn(1); + $order->shouldReceive('getNumber')->andReturn('ABC_1234'); + $order->shouldReceive('generateQRCode'); + $order->shouldReceive('hasOwner')->andReturnFalse(); + $order->shouldReceive('getOwnerEmail')->andReturn('test@test.com'); + $order->shouldReceive('getOwnerFirstName')->andReturn('test'); + $order->shouldReceive('getOwnerSurname')->andReturn('test'); + $order->shouldReceive('getOwnerFullName')->andReturn('test test'); + $order->shouldReceive('getRawAmount')->andReturn(1000); + $order->shouldReceive('getFinalAmount')->andReturn(1000); + $order->shouldReceive('getTaxesAmount')->andReturn(0); + $order->shouldReceive('getDiscountAmount')->andReturn(0); + $order->shouldReceive('getCurrency')->andReturn('USD'); + $order->shouldReceive('getQRCode')->andReturn('QR_CODE'); + $order->shouldReceive('getSummit')->andReturn(self::$summit); + $order->shouldReceive('getTickets')->andReturn([]); + + $externalUserApi = \Mockery::mock(IExternalUserApi::class) + ->shouldIgnoreMissing(); + + $externalUserApi->shouldReceive('getUserByEmail') + ->with('test@test.com')->andReturn([]); + + $externalUserApi->shouldReceive('registerUser')->andReturn( + [ + 'set_password_link' => 'https://test.com' + ] + ); + + $this->app->instance(IExternalUserApi::class, $externalUserApi); + + $orderRepository = \Mockery::mock(ISummitOrderRepository::class)->shouldIgnoreMissing(); + $orderRepository->shouldReceive('getById')->with(1)->andReturn($order); + + $this->app->instance(ISummitOrderRepository::class, $orderRepository); + + $job = new ProcessSummitOrderPaymentConfirmation($order->getId()); + $job->handle(App::make(ISummitOrderService::class)); + } + catch (\Exception $ex){ + $this->fail($ex->getMessage()); + } + $this->assertTrue(true); + } + + public function testDispatchPaymentConfirmationJobWithExistentUser(){ + try { + + + $order = \Mockery::mock(SummitOrder::class); + $order->shouldReceive('getId')->andReturn(1); + $order->shouldReceive('getNumber')->andReturn('ABC_1234'); + $order->shouldReceive('generateQRCode'); + $order->shouldReceive('hasOwner')->andReturnFalse(); + $order->shouldReceive('getOwnerEmail')->andReturn('test@test.com'); + $order->shouldReceive('getOwnerFirstName')->andReturn('test'); + $order->shouldReceive('getOwnerSurname')->andReturn('test'); + $order->shouldReceive('getOwnerFullName')->andReturn('test test'); + $order->shouldReceive('getRawAmount')->andReturn(1000); + $order->shouldReceive('getFinalAmount')->andReturn(1000); + $order->shouldReceive('getTaxesAmount')->andReturn(0); + $order->shouldReceive('getDiscountAmount')->andReturn(0); + $order->shouldReceive('getCurrency')->andReturn('USD'); + $order->shouldReceive('getQRCode')->andReturn('QR_CODE'); + $order->shouldReceive('getSummit')->andReturn(self::$summit); + $order->shouldReceive('getTickets')->andReturn([]); + $order->shouldReceive('setOwner'); + + $externalUserApi = \Mockery::mock(IExternalUserApi::class) + ->shouldIgnoreMissing(); + + $externalUserApi->shouldReceive('getUserByEmail') + ->with('test@test.com')->andReturn([ + 'email' => 'test@test.com', + 'id' => '1', + 'first_name' => 'test', + 'last_name' => 'test', + ]); + + $externalUserApi->shouldReceive('registerUser')->andReturn( + [ + 'set_password_link' => 'https://test.com' + ] + ); + + $this->app->instance(IExternalUserApi::class, $externalUserApi); + + $orderRepository = \Mockery::mock(ISummitOrderRepository::class)->shouldIgnoreMissing(); + $orderRepository->shouldReceive('getById')->with(1)->andReturn($order); + + $this->app->instance(ISummitOrderRepository::class, $orderRepository); + + $memberRepository = \Mockery::mock(IMemberRepository::class)->shouldIgnoreMissing(); + + $this->app->instance(IMemberRepository::class, $memberRepository); + + $job = new ProcessSummitOrderPaymentConfirmation($order->getId()); + $job->handle(App::make(ISummitOrderService::class)); + } + catch (\Exception $ex){ + $this->fail($ex->getMessage()); + } + $this->assertTrue(true); + } + + public function testDispatchRefund(){ + + \App\Jobs\ProcessOrderRefundRequest::dispatch( + 23, + 10 + ); + } +} \ No newline at end of file diff --git a/update_doctrine.sh b/update_doctrine.sh index acf81ed1..e854698f 100755 --- a/update_doctrine.sh +++ b/update_doctrine.sh @@ -10,3 +10,4 @@ php artisan doctrine:clear:metadata:cache php artisan doctrine:clear:query:cache php artisan doctrine:clear:result:cache php artisan doctrine:generate:proxies +php artisan config:clear