From 372eab70f698dd57bf01f59a0407ce473be07b0b Mon Sep 17 00:00:00 2001 From: "smarcet@gmail.com" Date: Mon, 4 Dec 2023 17:37:51 -0300 Subject: [PATCH 1/3] feat: added summit secondary_logo attribute Added new endpoints POST api/v1/summits/{id}/logo/secondary payload file DELETE api/v1/summits/{id}/logo/secondary Change-Id: I23b9fcf7525b966238c21cf804c82b806e9f89e0 --- .../Summit/OAuth2SummitApiController.php | 55 ++++++++++++++++ .../Summit/SummitSerializer.php | 2 +- app/Models/Foundation/Summit/Summit.php | 61 ++++++++++++++++++ app/Services/Model/ISummitService.php | 17 +++++ app/Services/Model/Imp/SummitService.php | 63 +++++++++++++++++-- .../model/Version20231204203518.php | 53 ++++++++++++++++ database/seeders/ApiEndpointsSeeder.php | 26 ++++++++ routes/api_v1.php | 9 ++- 8 files changed, 278 insertions(+), 8 deletions(-) create mode 100644 database/migrations/model/Version20231204203518.php diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitApiController.php index 9860b2b87..a3789dff9 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitApiController.php @@ -725,6 +725,61 @@ public function deleteSummitLogo($summit_id) }); } + /** + * @param LaravelRequest $request + * @param $summit_id + * @return JsonResponse|mixed + */ + public function addSummitSecondaryLogo(LaravelRequest $request, $summit_id) + { + return $this->processRequest(function () use ($request, $summit_id) { + + $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!')); + } + + $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->addSummitSecondaryLogo($summit_id, $file); + + return $this->created(SerializerRegistry::getInstance()->getSerializer($photo)->serialize + ( + SerializerUtils::getExpand(), + SerializerUtils::getFields(), + SerializerUtils::getRelations() + )); + + }); + } + + /** + * @param $summit_id + * @return JsonResponse|mixed + */ + public function deleteSummitSecondaryLogo($summit_id) + { + return $this->processRequest(function() use($summit_id){ + + $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->deleteSummitSecondaryLogo($summit_id); + + return $this->deleted(); + + }); + } + /** * @param $summit_id * @param $speaker_id diff --git a/app/ModelSerializers/Summit/SummitSerializer.php b/app/ModelSerializers/Summit/SummitSerializer.php index 5ea06b27a..f3c9f668b 100644 --- a/app/ModelSerializers/Summit/SummitSerializer.php +++ b/app/ModelSerializers/Summit/SummitSerializer.php @@ -51,7 +51,7 @@ class SummitSerializer extends SilverStripeSerializer 'BeginAllowBookingDate' => 'begin_allow_booking_date:datetime_epoch', 'EndAllowBookingDate' => 'end_allow_booking_date:datetime_epoch', 'LogoUrl' => 'logo:json_url', - + 'SecondaryLogoUrl' => 'secondary_logo:json_url', // registration 'OrderQRPrefix' => 'order_qr_prefix:json_string', 'TicketQRPrefix' => 'ticket_qr_prefix:json_string', diff --git a/app/Models/Foundation/Summit/Summit.php b/app/Models/Foundation/Summit/Summit.php index 9f28ddff5..2cb037385 100644 --- a/app/Models/Foundation/Summit/Summit.php +++ b/app/Models/Foundation/Summit/Summit.php @@ -601,6 +601,13 @@ public function setMarketingSiteOauth2ClientScopes(string $marketing_site_oauth2 */ private $logo; + /** + * @ORM\ManyToOne(targetEntity="models\main\File", cascade={"persist"}) + * @ORM\JoinColumn(name="SecondaryLogoID", referencedColumnName="ID") + * @var File + */ + private $secondary_logo; + /** * @ORM\Column(name="ApiFeedType", type="string") * @var string @@ -1481,6 +1488,47 @@ public function getLogoId() } } + /** + * @return File + */ + public function getSecondaryLogo() + { + return $this->secondary_logo; + } + + /** + * @param File $secondary_logo + */ + public function setSecondaryLogo(File $secondary_logo): void + { + $this->secondary_logo = $secondary_logo; + } + + public function clearSecondaryLogo(): void + { + $this->secondary_logo = null; + } + + /** + * @return bool + */ + public function hasSecondaryLogo() + { + return $this->getSecondaryLogoId() > 0; + } + + /** + * @return int + */ + public function getSecondaryLogoId() + { + try { + return !is_null($this->secondary_logo) ? $this->secondary_logo->getId() : 0; + } catch (\Exception $ex) { + return 0; + } + } + /** * @param int $location_id * @return SummitAbstractLocation @@ -3985,6 +4033,19 @@ public function getLogoUrl(): ?string return $logoUrl; } + + /** + * @return string + */ + public function getSecondaryLogoUrl(): ?string + { + $logoUrl = null; + if ($this->hasSecondaryLogo() && $logo = $this->getSecondaryLogo()) { + $logoUrl = $logo->getUrl(); + } + return $logoUrl; + } + public function getReassignTicketTillDate(): ?DateTime { return $this->reassign_ticket_till_date; diff --git a/app/Services/Model/ISummitService.php b/app/Services/Model/ISummitService.php index a22ae66e2..38c14cd2d 100644 --- a/app/Services/Model/ISummitService.php +++ b/app/Services/Model/ISummitService.php @@ -377,6 +377,23 @@ public function addSummitLogo(int $summit_id, UploadedFile $file, $max_file_siz */ public function deleteSummitLogo(int $summit_id):void; + /** + * @param int $summit_id + * @param UploadedFile $file + * @param int $max_file_size + * @throws ValidationException + * @throws EntityNotFoundException + * @return File + */ + public function addSummitSecondaryLogo(int $summit_id, UploadedFile $file, $max_file_size = 10485760); + + /** + * @param int $summit + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function deleteSummitSecondaryLogo(int $summit_id):void; + /** * @param Summit $summit * @param Member $member diff --git a/app/Services/Model/Imp/SummitService.php b/app/Services/Model/Imp/SummitService.php index 5bb94d437..0824b6de0 100644 --- a/app/Services/Model/Imp/SummitService.php +++ b/app/Services/Model/Imp/SummitService.php @@ -2129,7 +2129,6 @@ public function deleteBookableRoomAttributeValue(Summit $summit, int $type_id, i }); } - /** * @param int $summit_id * @param UploadedFile $file @@ -2146,8 +2145,8 @@ public function addSummitLogo(int $summit_id, UploadedFile $file, $max_file_size $summit = $this->summit_repository->getById($summit_id); - if (is_null($summit) || !$summit instanceof Summit) { - throw new EntityNotFoundException('summit not found!'); + if (!$summit instanceof Summit) { + throw new EntityNotFoundException('Summit not found.'); } if (!in_array($file->extension(), $allowed_extensions)) { @@ -2176,14 +2175,68 @@ public function deleteSummitLogo(int $summit_id): void $summit = $this->summit_repository->getById($summit_id); - if (is_null($summit) || !$summit instanceof Summit) { - throw new EntityNotFoundException('summit not found!'); + if (!$summit instanceof Summit) { + throw new EntityNotFoundException('Summit not found.'); } $summit->clearLogo(); }); } + /** + * @param int $summit_id + * @param UploadedFile $file + * @param int $max_file_size + * @return File + * @throws EntityNotFoundException + * @throws ValidationException + */ + public function addSummitSecondaryLogo(int $summit_id, UploadedFile $file, $max_file_size = 10485760) + { + return $this->tx_service->transaction(function () use ($summit_id, $file, $max_file_size) { + + $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'svg', 'jfif']; + + $summit = $this->summit_repository->getById($summit_id); + + if (!$summit instanceof Summit) { + throw new EntityNotFoundException('Summit not found.'); + } + + if (!in_array($file->extension(), $allowed_extensions)) { + throw new ValidationException(sprintf("file does not has a valid extension (%s).", implode(",", $allowed_extensions))); + } + + 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, sprintf('summits/%s', $summit->getId()), true); + $summit->setSecondaryLogo($photo); + + return $photo; + }); + } + + /** + * @param int $summit_id + * @throws ValidationException + * @throws EntityNotFoundException + */ + public function deleteSummitSecondaryLogo(int $summit_id): void + { + $this->tx_service->transaction(function () use ($summit_id) { + + $summit = $this->summit_repository->getById($summit_id); + + if (!$summit instanceof Summit) { + throw new EntityNotFoundException('Summit not found.'); + } + + $summit->clearSecondaryLogo(); + }); + } + /** * @param Summit $summit * @param Member $member diff --git a/database/migrations/model/Version20231204203518.php b/database/migrations/model/Version20231204203518.php new file mode 100644 index 000000000..c12be8ac6 --- /dev/null +++ b/database/migrations/model/Version20231204203518.php @@ -0,0 +1,53 @@ +hasTable("Summit")) { + $builder->table('Summit', function (Table $table) { + $table->integer("SecondaryLogoID", false, false)->setNotnull(false)->setDefault('NULL'); + $table->index("SecondaryLogoID", "SecondaryLogoID"); + $table->foreign("File", "SecondaryLogoID", "ID", ["onDelete" => "CASCADE"]); + }); + } + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema): void + { + $builder = new Builder($schema); + if($schema->hasTable("Summit")) { + $builder->table('Summit', function (Table $table) { + $table->dropColumn('SecondaryLogoID'); + }); + } + } +} diff --git a/database/seeders/ApiEndpointsSeeder.php b/database/seeders/ApiEndpointsSeeder.php index 85eaef651..d0f349783 100644 --- a/database/seeders/ApiEndpointsSeeder.php +++ b/database/seeders/ApiEndpointsSeeder.php @@ -1223,6 +1223,32 @@ private function seedSummitEndpoints() IGroup::SummitAdministrators, ] ], + [ + 'name' => 'add-summit-logo-secondary', + 'route' => '/api/v1/summits/{id}/secondary', + 'http_method' => 'POST', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + [ + 'name' => 'delete-summit-logo-secondary', + 'route' => '/api/v1/summits/{id}/logo/secondary', + 'http_method' => 'DELETE', + 'scopes' => [ + sprintf(SummitScopes::WriteSummitData, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], [ 'name' => 'delete-summit', 'route' => '/api/v1/summits/{id}', diff --git a/routes/api_v1.php b/routes/api_v1.php index 983fb730d..d2cf6d29f 100644 --- a/routes/api_v1.php +++ b/routes/api_v1.php @@ -261,8 +261,13 @@ }); 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::group(['prefix' => 'logo'], function () { + Route::post('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@addSummitLogo']); + Route::delete('', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@deleteSummitLogo']); + Route::post('secondary', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitApiController@addSummitLogo']); + Route::delete('secondary', ['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]+'); From 4c74ee58db962c2c23852c1bddc05d503b272563 Mon Sep 17 00:00:00 2001 From: romanetar Date: Thu, 7 Dec 2023 13:29:46 +0100 Subject: [PATCH 2/3] order confirmation email rendering workflow (WIP) Signed-off-by: romanetar --- .../OAuth2SummitOrdersApiController.php | 16 ++ app/Http/Renderers/HTML2PDFRenderer.php | 78 ++++++++++ app/ModelSerializers/SerializerRegistry.php | 2 + ...rderConfirmationEmailPreviewSerializer.php | 83 +++++++++++ app/Services/Apis/EmailTemplatesApi.php | 141 ++++++++++++++++++ app/Services/Apis/IEmailTemplatesApi.php | 35 +++++ app/Services/BaseServicesProvider.php | 8 + app/Services/Model/ISummitOrderService.php | 9 ++ app/Services/Model/Imp/SummitOrderService.php | 49 +++++- config/app.php | 2 +- database/seeders/ApiEndpointsSeeder.php | 15 ++ routes/api_v1.php | 1 + tests/OAuth2SummitOrdersApiTest.php | 129 ++++++++++------ 13 files changed, 518 insertions(+), 50 deletions(-) create mode 100644 app/Http/Renderers/HTML2PDFRenderer.php create mode 100644 app/ModelSerializers/Summit/Registration/SummitOrderConfirmationEmailPreviewSerializer.php create mode 100644 app/Services/Apis/EmailTemplatesApi.php create mode 100644 app/Services/Apis/IEmailTemplatesApi.php diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php index 6e612f757..11b6c1820 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php @@ -1172,4 +1172,20 @@ public function deActivateTicket($summit_id, $order_id, $ticket_id) )); }); } + + /** + * @param $summit_id + * @param $order_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getOrderConfirmationEmailPDF($summit_id, $order_id) + { + return $this->processRequest(function () use ($summit_id, $order_id) { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $content = $this->service->renderOrderConfirmationEmail($summit, intval($order_id)); + return $this->pdf("order_{$order_id}_confirmation_email.pdf", $content); + }); + } } \ No newline at end of file diff --git a/app/Http/Renderers/HTML2PDFRenderer.php b/app/Http/Renderers/HTML2PDFRenderer.php new file mode 100644 index 000000000..a42e5742f --- /dev/null +++ b/app/Http/Renderers/HTML2PDFRenderer.php @@ -0,0 +1,78 @@ +html = $html; + } + + public function render(): string + { + // 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(''); + + // 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', '', 10); + + // add a page + $pdf->AddPage(); + + $pdf->writeHTML($this->html, true, false, true, false, ''); + + //Close and output PDF document + return $pdf->Output('', 'S'); + } +} \ No newline at end of file diff --git a/app/ModelSerializers/SerializerRegistry.php b/app/ModelSerializers/SerializerRegistry.php index bbd04b28f..4be7e8c83 100644 --- a/app/ModelSerializers/SerializerRegistry.php +++ b/app/ModelSerializers/SerializerRegistry.php @@ -151,6 +151,7 @@ final class SerializerRegistry const SerializerType_Admin_Voteable_CSV = "ADMIN_VOTEABLE_CSV"; const SerializerType_CSV = 'CSV'; const SerializerType_Admin_Registration_Stats = 'ADMIN_REG_STATS'; + const SerializerType_Admin_Email_Preview = 'ADMIN_EMAIL_PREVIEW'; private function __clone() { @@ -429,6 +430,7 @@ private function __construct() $this->registry['SummitOrder'] = [ self::SerializerType_Public => SummitOrderBaseSerializer::class, + self::SerializerType_Admin_Email_Preview => SummitOrderConfirmationEmailPreviewSerializer::class, ISummitOrderSerializerTypes::CheckOutType => SummitOrderBaseSerializer::class, ISummitOrderSerializerTypes::ReservationType => SummitOrderReservationSerializer::class, ISummitOrderSerializerTypes::AdminType => SummitOrderAdminSerializer::class, diff --git a/app/ModelSerializers/Summit/Registration/SummitOrderConfirmationEmailPreviewSerializer.php b/app/ModelSerializers/Summit/Registration/SummitOrderConfirmationEmailPreviewSerializer.php new file mode 100644 index 000000000..6557133a5 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitOrderConfirmationEmailPreviewSerializer.php @@ -0,0 +1,83 @@ + 'order_credit_card_type:json_string', + 'CreditCard4Number' => 'order_credit_card_4number:json_string', + 'Currency' => 'order_currency:json_string', + 'CurrencySymbol' => 'order_currency_symbol:json_string', + 'Number' => 'order_number:json_string', + 'FinalAmountAdjusted' => 'order_amount:json_float', + 'OwnerFullName' => 'owner_full_name:json_string', + 'OwnerCompanyName' => 'owner_company:json_string', + ]; + + protected static $allowed_relations = [ + 'member', + '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); + + $values["summit_name"] = $order->getSummit()->getName(); + + if (!count($relations)) $relations = $this->getAllowedRelations(); + + if (in_array('tickets', $relations)) { + $tickets = []; + foreach ($order->getTickets() as $ticket) { + $ticket_dic = [ + "currency" => $ticket->getCurrency(), + "currency_symbol" => $ticket->getCurrencySymbol(), + "has_owner" => $ticket->hasOwner(), + "need_details" => false, + "ticket_type_name" => $ticket->getTicketTypeName(), + "owner_email" => $ticket->getOwnerEmail(), + "price" => $ticket->getFinalAmount() + ]; + + $promo_code = $ticket->getPromoCode(); + if (!is_null($promo_code)) { + $ticket_dic["promo_code"] = ["code" => $promo_code->getCode()]; + } + + $tickets[] = $ticket_dic; + } + $values['tickets'] = $tickets; + } + + return $values; + } +} \ No newline at end of file diff --git a/app/Services/Apis/EmailTemplatesApi.php b/app/Services/Apis/EmailTemplatesApi.php new file mode 100644 index 000000000..55dc488bd --- /dev/null +++ b/app/Services/Apis/EmailTemplatesApi.php @@ -0,0 +1,141 @@ +push(GuzzleRetryMiddleware::factory()); + + $this->client = new Client([ + 'handler' => $stack, + '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 string + */ + public function getAppName(): string + { + return self::AppName; + } + + /** + * @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 string $template_id + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException + */ + public function getEmailTemplate(string $template_id) { + Log::debug("EmailTemplatesApi::getEmailTemplate"); + + try { + $query = [ + 'access_token' => $this->getAccessToken() + ]; + + $response = $this->client->get("/api/v1/mail-templates/{$template_id}", [ + 'query' => $query, + ] + ); + return json_decode($response->getBody()->getContents(), true); + } + catch (Exception $ex) { + $this->cleanAccessToken(); + Log::error($ex); + throw $ex; + } + } + + /** + * @param array $payload + * @param string $html_template + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException|\League\OAuth2\Client\Provider\Exception\IdentityProviderException + */ + public function getEmailPreview(array $payload, string $html_template) + { + Log::debug("EmailTemplatesApi::getEmailPreview"); + + try { + $query = [ + 'access_token' => $this->getAccessToken() + ]; + + $response = $this->client->put('/api/v1/mail-templates/all/render', [ + 'query' => $query, + RequestOptions::JSON => [ + "html" => $html_template, + "payload" => $payload + ] + ] + ); + return json_decode($response->getBody()->getContents(), true); + } + catch (Exception $ex) { + $this->cleanAccessToken(); + Log::error($ex); + throw $ex; + } + } +} + diff --git a/app/Services/Apis/IEmailTemplatesApi.php b/app/Services/Apis/IEmailTemplatesApi.php new file mode 100644 index 000000000..7ba839990 --- /dev/null +++ b/app/Services/Apis/IEmailTemplatesApi.php @@ -0,0 +1,35 @@ +company_repository = $company_repository; $this->company_service = $company_service; $this->ticket_finder_strategy_factory = $ticket_finder_strategy_factory; + $this->email_templates_api = $email_templates_api; } /** @@ -4338,4 +4349,40 @@ public function deActivateTicket(Summit $summit, int $order_id, int $ticket_id): return $ticket; }); } + + /** + * @inheritDoc + */ + public function renderOrderConfirmationEmail(Summit $summit, int $order_id): string + { + try { + Log::debug("SummitOrderService::renderOrderConfirmationEmail order id {$order_id}"); + + $order = $summit->getOrderById($order_id); + + if (!$order instanceof SummitOrder) + throw new EntityNotFoundException("order not found"); + + $payload = SerializerRegistry::getInstance() + ->getSerializer($order, SerializerRegistry::SerializerType_Admin_Email_Preview) + ->serialize(); + + $template_id = $summit->getEmailIdentifierPerEmailEventFlowSlug(RegisteredMemberOrderPaidMail::EVENT_SLUG); + + if (is_null($template_id)) + throw new EntityNotFoundException("order confirmation email template not found"); + + $template = $this->email_templates_api->getEmailTemplate($template_id); + + $preview = $this->email_templates_api->getEmailPreview($payload, $template['html_content']); + + preg_match("/]*>(.*?)<\/body>/is", $preview['html_content'], $matches); + + $renderer = new HTML2PDFRenderer(trim($matches[1])); + return $renderer->render(); + } catch (\Exception $ex) { + Log::warning($ex); + throw $ex; + } + } } diff --git a/config/app.php b/config/app.php index 892329882..3668df4a8 100644 --- a/config/app.php +++ b/config/app.php @@ -224,5 +224,5 @@ 'app_name' => env('APP_NAME', 'Open Infrastructure Summit'), 'tenant_name' => env('TENANT_NAME', 'OpenStack'), - "default_profile_image" => env('DEFAULT_PROFILE_IMAGE', null), + 'default_profile_image' => env('DEFAULT_PROFILE_IMAGE', null), ]; diff --git a/database/seeders/ApiEndpointsSeeder.php b/database/seeders/ApiEndpointsSeeder.php index d0f349783..a1f886d53 100644 --- a/database/seeders/ApiEndpointsSeeder.php +++ b/database/seeders/ApiEndpointsSeeder.php @@ -515,6 +515,21 @@ private function seedRegistrationOrderEndpoints() IGroup::SummitRegistrationAdmins ] ], + [ + 'name' => 'get-order-confirmation-email-pdf', + 'route' => '/api/v1/summits/{id}/orders/{order_id}/pdf', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm), + sprintf(SummitScopes::ReadRegistrationOrders, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], // purchase flow [ 'name' => 'reserve-registration-order', diff --git a/routes/api_v1.php b/routes/api_v1.php index d2cf6d29f..1ea2f945f 100644 --- a/routes/api_v1.php +++ b/routes/api_v1.php @@ -1368,6 +1368,7 @@ Route::get('pdf', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrdersApiController@getTicketPDFBySummit']); }); }); + Route::get('pdf', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrdersApiController@getOrderConfirmationEmailPDF']); }); Route::post('reserve', 'OAuth2SummitOrdersApiController@reserve'); Route::group(['prefix' => '{hash}', 'where' => [ diff --git a/tests/OAuth2SummitOrdersApiTest.php b/tests/OAuth2SummitOrdersApiTest.php index c052d6aa2..47f6ad7a8 100644 --- a/tests/OAuth2SummitOrdersApiTest.php +++ b/tests/OAuth2SummitOrdersApiTest.php @@ -18,6 +18,7 @@ use App\Models\Foundation\Summit\Factories\SummitTicketTypeFactory; use App\Models\Foundation\Summit\Factories\SummitBadgeTypeFactory; use services\model\ISummitService; +use TCPDF_STATIC; /** * Class OAuth2SummitOrdersApiTest @@ -58,54 +59,54 @@ final class OAuth2SummitOrdersApiTest extends ProtectedApiTest use InsertOrdersTestData; - protected function setUp():void - { - parent::setUp(); - self::$test_secret_key = env('TEST_STRIPE_SECRET_KEY'); - self::$test_public_key = env('TEST_STRIPE_PUBLISHABLE_KEY'); - self::$live_secret_key = env('LIVE_STRIPE_SECRET_KEY'); - self::$live_public_key = env('LIVE_STRIPE_PUBLISHABLE_KEY'); - - self::insertSummitTestData(); - self::InsertOrdersTestData(); - // build payment profile and attach to summit - self::$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, - '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():void - { - self::clearSummitTestData(); - parent::tearDown(); - } +// protected function setUp():void +// { +// parent::setUp(); +// self::$test_secret_key = env('TEST_STRIPE_SECRET_KEY'); +// self::$test_public_key = env('TEST_STRIPE_PUBLISHABLE_KEY'); +// self::$live_secret_key = env('LIVE_STRIPE_SECRET_KEY'); +// self::$live_public_key = env('LIVE_STRIPE_PUBLISHABLE_KEY'); +// +// self::insertSummitTestData(); +// self::InsertOrdersTestData(); +// // build payment profile and attach to summit +// self::$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, +// '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():void +// { +// self::clearSummitTestData(); +// parent::tearDown(); +// } /** * @return mixed @@ -930,4 +931,36 @@ public function testUpdateTicketById($ticket_id = 28){ $this->assertTrue(!is_null($order)); return $order; } + + /** + * @return mixed + */ + public function testGetOrderConfirmationEmailPDF(){ + $params = [ + 'id' => 3783, //self::$summit->getId(), + 'order_id' => 6658 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitOrdersApiController@getOrderConfirmationEmailPDF", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + + $f = TCPDF_STATIC::fopenLocal("/tmp/order_confirmation_email.pdf", 'wb'); + fwrite($f, $content, strlen($content)); + fclose($f); + } } \ No newline at end of file From 23f4af2e09938169bac60480f068c0fe8ce3dace Mon Sep 17 00:00:00 2001 From: romanetar Date: Thu, 7 Dec 2023 13:29:46 +0100 Subject: [PATCH 3/3] order confirmation email rendering workflow (WIP) Signed-off-by: romanetar --- .../OAuth2SummitOrdersApiController.php | 16 ++ app/Http/Renderers/HTML2PDFRenderer.php | 78 ++++++++++ app/ModelSerializers/SerializerRegistry.php | 2 + ...rderConfirmationEmailPreviewSerializer.php | 83 +++++++++++ app/Services/Apis/EmailTemplatesApi.php | 141 ++++++++++++++++++ app/Services/Apis/IEmailTemplatesApi.php | 35 +++++ app/Services/BaseServicesProvider.php | 8 + app/Services/Model/ISummitOrderService.php | 9 ++ app/Services/Model/Imp/SummitOrderService.php | 49 +++++- config/app.php | 2 +- database/seeders/ApiEndpointsSeeder.php | 15 ++ routes/api_v1.php | 1 + tests/OAuth2SummitOrdersApiTest.php | 129 ++++++++++------ 13 files changed, 518 insertions(+), 50 deletions(-) create mode 100644 app/Http/Renderers/HTML2PDFRenderer.php create mode 100644 app/ModelSerializers/Summit/Registration/SummitOrderConfirmationEmailPreviewSerializer.php create mode 100644 app/Services/Apis/EmailTemplatesApi.php create mode 100644 app/Services/Apis/IEmailTemplatesApi.php diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php index 776f8e342..3bee659c5 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitOrdersApiController.php @@ -1183,4 +1183,20 @@ public function deActivateTicket($summit_id, $order_id, $ticket_id) )); }); } + + /** + * @param $summit_id + * @param $order_id + * @return \Illuminate\Http\JsonResponse|mixed + */ + public function getOrderConfirmationEmailPDF($summit_id, $order_id) + { + return $this->processRequest(function () use ($summit_id, $order_id) { + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); + if (is_null($summit)) return $this->error404(); + + $content = $this->service->renderOrderConfirmationEmail($summit, intval($order_id)); + return $this->pdf("order_{$order_id}_confirmation_email.pdf", $content); + }); + } } \ No newline at end of file diff --git a/app/Http/Renderers/HTML2PDFRenderer.php b/app/Http/Renderers/HTML2PDFRenderer.php new file mode 100644 index 000000000..a42e5742f --- /dev/null +++ b/app/Http/Renderers/HTML2PDFRenderer.php @@ -0,0 +1,78 @@ +html = $html; + } + + public function render(): string + { + // 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(''); + + // 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', '', 10); + + // add a page + $pdf->AddPage(); + + $pdf->writeHTML($this->html, true, false, true, false, ''); + + //Close and output PDF document + return $pdf->Output('', 'S'); + } +} \ No newline at end of file diff --git a/app/ModelSerializers/SerializerRegistry.php b/app/ModelSerializers/SerializerRegistry.php index bbd04b28f..4be7e8c83 100644 --- a/app/ModelSerializers/SerializerRegistry.php +++ b/app/ModelSerializers/SerializerRegistry.php @@ -151,6 +151,7 @@ final class SerializerRegistry const SerializerType_Admin_Voteable_CSV = "ADMIN_VOTEABLE_CSV"; const SerializerType_CSV = 'CSV'; const SerializerType_Admin_Registration_Stats = 'ADMIN_REG_STATS'; + const SerializerType_Admin_Email_Preview = 'ADMIN_EMAIL_PREVIEW'; private function __clone() { @@ -429,6 +430,7 @@ private function __construct() $this->registry['SummitOrder'] = [ self::SerializerType_Public => SummitOrderBaseSerializer::class, + self::SerializerType_Admin_Email_Preview => SummitOrderConfirmationEmailPreviewSerializer::class, ISummitOrderSerializerTypes::CheckOutType => SummitOrderBaseSerializer::class, ISummitOrderSerializerTypes::ReservationType => SummitOrderReservationSerializer::class, ISummitOrderSerializerTypes::AdminType => SummitOrderAdminSerializer::class, diff --git a/app/ModelSerializers/Summit/Registration/SummitOrderConfirmationEmailPreviewSerializer.php b/app/ModelSerializers/Summit/Registration/SummitOrderConfirmationEmailPreviewSerializer.php new file mode 100644 index 000000000..6557133a5 --- /dev/null +++ b/app/ModelSerializers/Summit/Registration/SummitOrderConfirmationEmailPreviewSerializer.php @@ -0,0 +1,83 @@ + 'order_credit_card_type:json_string', + 'CreditCard4Number' => 'order_credit_card_4number:json_string', + 'Currency' => 'order_currency:json_string', + 'CurrencySymbol' => 'order_currency_symbol:json_string', + 'Number' => 'order_number:json_string', + 'FinalAmountAdjusted' => 'order_amount:json_float', + 'OwnerFullName' => 'owner_full_name:json_string', + 'OwnerCompanyName' => 'owner_company:json_string', + ]; + + protected static $allowed_relations = [ + 'member', + '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); + + $values["summit_name"] = $order->getSummit()->getName(); + + if (!count($relations)) $relations = $this->getAllowedRelations(); + + if (in_array('tickets', $relations)) { + $tickets = []; + foreach ($order->getTickets() as $ticket) { + $ticket_dic = [ + "currency" => $ticket->getCurrency(), + "currency_symbol" => $ticket->getCurrencySymbol(), + "has_owner" => $ticket->hasOwner(), + "need_details" => false, + "ticket_type_name" => $ticket->getTicketTypeName(), + "owner_email" => $ticket->getOwnerEmail(), + "price" => $ticket->getFinalAmount() + ]; + + $promo_code = $ticket->getPromoCode(); + if (!is_null($promo_code)) { + $ticket_dic["promo_code"] = ["code" => $promo_code->getCode()]; + } + + $tickets[] = $ticket_dic; + } + $values['tickets'] = $tickets; + } + + return $values; + } +} \ No newline at end of file diff --git a/app/Services/Apis/EmailTemplatesApi.php b/app/Services/Apis/EmailTemplatesApi.php new file mode 100644 index 000000000..55dc488bd --- /dev/null +++ b/app/Services/Apis/EmailTemplatesApi.php @@ -0,0 +1,141 @@ +push(GuzzleRetryMiddleware::factory()); + + $this->client = new Client([ + 'handler' => $stack, + '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 string + */ + public function getAppName(): string + { + return self::AppName; + } + + /** + * @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 string $template_id + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException + */ + public function getEmailTemplate(string $template_id) { + Log::debug("EmailTemplatesApi::getEmailTemplate"); + + try { + $query = [ + 'access_token' => $this->getAccessToken() + ]; + + $response = $this->client->get("/api/v1/mail-templates/{$template_id}", [ + 'query' => $query, + ] + ); + return json_decode($response->getBody()->getContents(), true); + } + catch (Exception $ex) { + $this->cleanAccessToken(); + Log::error($ex); + throw $ex; + } + } + + /** + * @param array $payload + * @param string $html_template + * @return mixed + * @throws \GuzzleHttp\Exception\GuzzleException|\League\OAuth2\Client\Provider\Exception\IdentityProviderException + */ + public function getEmailPreview(array $payload, string $html_template) + { + Log::debug("EmailTemplatesApi::getEmailPreview"); + + try { + $query = [ + 'access_token' => $this->getAccessToken() + ]; + + $response = $this->client->put('/api/v1/mail-templates/all/render', [ + 'query' => $query, + RequestOptions::JSON => [ + "html" => $html_template, + "payload" => $payload + ] + ] + ); + return json_decode($response->getBody()->getContents(), true); + } + catch (Exception $ex) { + $this->cleanAccessToken(); + Log::error($ex); + throw $ex; + } + } +} + diff --git a/app/Services/Apis/IEmailTemplatesApi.php b/app/Services/Apis/IEmailTemplatesApi.php new file mode 100644 index 000000000..7ba839990 --- /dev/null +++ b/app/Services/Apis/IEmailTemplatesApi.php @@ -0,0 +1,35 @@ +company_repository = $company_repository; $this->company_service = $company_service; $this->ticket_finder_strategy_factory = $ticket_finder_strategy_factory; + $this->email_templates_api = $email_templates_api; } /** @@ -4338,4 +4349,40 @@ public function deActivateTicket(Summit $summit, int $order_id, int $ticket_id): return $ticket; }); } + + /** + * @inheritDoc + */ + public function renderOrderConfirmationEmail(Summit $summit, int $order_id): string + { + try { + Log::debug("SummitOrderService::renderOrderConfirmationEmail order id {$order_id}"); + + $order = $summit->getOrderById($order_id); + + if (!$order instanceof SummitOrder) + throw new EntityNotFoundException("order not found"); + + $payload = SerializerRegistry::getInstance() + ->getSerializer($order, SerializerRegistry::SerializerType_Admin_Email_Preview) + ->serialize(); + + $template_id = $summit->getEmailIdentifierPerEmailEventFlowSlug(RegisteredMemberOrderPaidMail::EVENT_SLUG); + + if (is_null($template_id)) + throw new EntityNotFoundException("order confirmation email template not found"); + + $template = $this->email_templates_api->getEmailTemplate($template_id); + + $preview = $this->email_templates_api->getEmailPreview($payload, $template['html_content']); + + preg_match("/]*>(.*?)<\/body>/is", $preview['html_content'], $matches); + + $renderer = new HTML2PDFRenderer(trim($matches[1])); + return $renderer->render(); + } catch (\Exception $ex) { + Log::warning($ex); + throw $ex; + } + } } diff --git a/config/app.php b/config/app.php index 892329882..3668df4a8 100644 --- a/config/app.php +++ b/config/app.php @@ -224,5 +224,5 @@ 'app_name' => env('APP_NAME', 'Open Infrastructure Summit'), 'tenant_name' => env('TENANT_NAME', 'OpenStack'), - "default_profile_image" => env('DEFAULT_PROFILE_IMAGE', null), + 'default_profile_image' => env('DEFAULT_PROFILE_IMAGE', null), ]; diff --git a/database/seeders/ApiEndpointsSeeder.php b/database/seeders/ApiEndpointsSeeder.php index 0e9b95e92..5693acdbf 100644 --- a/database/seeders/ApiEndpointsSeeder.php +++ b/database/seeders/ApiEndpointsSeeder.php @@ -515,6 +515,21 @@ private function seedRegistrationOrderEndpoints() IGroup::SummitRegistrationAdmins ] ], + [ + 'name' => 'get-order-confirmation-email-pdf', + 'route' => '/api/v1/summits/{id}/orders/{order_id}/pdf', + 'http_method' => 'GET', + 'scopes' => [ + sprintf(SummitScopes::ReadAllSummitData, $current_realm), + sprintf(SummitScopes::ReadRegistrationOrders, $current_realm), + ], + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + IGroup::SummitRegistrationAdmins + ] + ], // purchase flow [ 'name' => 'reserve-registration-order', diff --git a/routes/api_v1.php b/routes/api_v1.php index 4b3096fc5..c45e0b395 100644 --- a/routes/api_v1.php +++ b/routes/api_v1.php @@ -1368,6 +1368,7 @@ Route::get('pdf', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrdersApiController@getTicketPDFBySummit']); }); }); + Route::get('pdf', ['middleware' => 'auth.user', 'uses' => 'OAuth2SummitOrdersApiController@getOrderConfirmationEmailPDF']); }); Route::post('reserve', 'OAuth2SummitOrdersApiController@reserve'); Route::group(['prefix' => '{hash}', 'where' => [ diff --git a/tests/OAuth2SummitOrdersApiTest.php b/tests/OAuth2SummitOrdersApiTest.php index c052d6aa2..47f6ad7a8 100644 --- a/tests/OAuth2SummitOrdersApiTest.php +++ b/tests/OAuth2SummitOrdersApiTest.php @@ -18,6 +18,7 @@ use App\Models\Foundation\Summit\Factories\SummitTicketTypeFactory; use App\Models\Foundation\Summit\Factories\SummitBadgeTypeFactory; use services\model\ISummitService; +use TCPDF_STATIC; /** * Class OAuth2SummitOrdersApiTest @@ -58,54 +59,54 @@ final class OAuth2SummitOrdersApiTest extends ProtectedApiTest use InsertOrdersTestData; - protected function setUp():void - { - parent::setUp(); - self::$test_secret_key = env('TEST_STRIPE_SECRET_KEY'); - self::$test_public_key = env('TEST_STRIPE_PUBLISHABLE_KEY'); - self::$live_secret_key = env('LIVE_STRIPE_SECRET_KEY'); - self::$live_public_key = env('LIVE_STRIPE_PUBLISHABLE_KEY'); - - self::insertSummitTestData(); - self::InsertOrdersTestData(); - // build payment profile and attach to summit - self::$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, - '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():void - { - self::clearSummitTestData(); - parent::tearDown(); - } +// protected function setUp():void +// { +// parent::setUp(); +// self::$test_secret_key = env('TEST_STRIPE_SECRET_KEY'); +// self::$test_public_key = env('TEST_STRIPE_PUBLISHABLE_KEY'); +// self::$live_secret_key = env('LIVE_STRIPE_SECRET_KEY'); +// self::$live_public_key = env('LIVE_STRIPE_PUBLISHABLE_KEY'); +// +// self::insertSummitTestData(); +// self::InsertOrdersTestData(); +// // build payment profile and attach to summit +// self::$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, +// '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():void +// { +// self::clearSummitTestData(); +// parent::tearDown(); +// } /** * @return mixed @@ -930,4 +931,36 @@ public function testUpdateTicketById($ticket_id = 28){ $this->assertTrue(!is_null($order)); return $order; } + + /** + * @return mixed + */ + public function testGetOrderConfirmationEmailPDF(){ + $params = [ + 'id' => 3783, //self::$summit->getId(), + 'order_id' => 6658 + ]; + + $headers = [ + "HTTP_Authorization" => " Bearer " . $this->access_token, + "CONTENT_TYPE" => "application/json" + ]; + + $response = $this->action( + "GET", + "OAuth2SummitOrdersApiController@getOrderConfirmationEmailPDF", + $params, + [], + [], + [], + $headers + ); + + $content = $response->getContent(); + $this->assertResponseStatus(200); + + $f = TCPDF_STATIC::fopenLocal("/tmp/order_confirmation_email.pdf", 'wb'); + fwrite($f, $content, strlen($content)); + fclose($f); + } } \ No newline at end of file