Skip to content

Commit c070afa

Browse files
smarcetCopilot
andauthored
feat: add new endpoint to resend (#350)
* feat: add new endppint to resend PUT api/v1/summits/{id}/events/{event_id}/rsvps/resend * Update app/Http/Controllers/Apis/Protected/Summit/OAuth2RSVPApiController.php Co-authored-by: Copilot <[email protected]> * Update database/seeders/ApiEndpointsSeeder.php Co-authored-by: Copilot <[email protected]> * Update app/Services/Model/Imp/SummitRSVPService.php Co-authored-by: Copilot <[email protected]> * Update app/Http/Controllers/Apis/Protected/Summit/OAuth2RSVPApiController.php Co-authored-by: Copilot <[email protected]> * Update app/Http/Controllers/Apis/Protected/Summit/OAuth2RSVPApiController.php Co-authored-by: Copilot <[email protected]> * chore: added missing flag * chore: add debug info * chore: fix missing email_flow_event --------- Co-authored-by: Copilot <[email protected]>
1 parent 3fe2e63 commit c070afa

File tree

13 files changed

+522
-2
lines changed

13 files changed

+522
-2
lines changed

app/Http/Controllers/Apis/Protected/Summit/OAuth2RSVPApiController.php

Lines changed: 163 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@
1313
**/
1414

1515
use App\Http\Controllers\Utils\Assertions;
16-
use App\Http\Utils\BooleanCellFormatter;
1716
use App\Http\Utils\EpochCellFormatter;
1817
use App\Models\Foundation\Main\IGroup;
1918
use App\ModelSerializers\SerializerUtils;
2019
use App\Security\SummitScopes;
2120
use App\Services\Model\ISummitRSVPService;
2221
use Illuminate\Http\Response;
22+
use Illuminate\Support\Facades\Request;
23+
use Illuminate\Support\Facades\Validator;
2324
use models\oauth2\IResourceServerContext;
2425
use models\summit\IRSVPRepository;
2526
use models\summit\ISummitEventRepository;
@@ -29,6 +30,7 @@
2930
use OpenApi\Attributes as OA;
3031
use utils\Filter;
3132
use utils\FilterElement;
33+
use utils\FilterParser;
3234

3335

3436
class OAuth2RSVPApiController extends OAuth2ProtectedController
@@ -427,6 +429,166 @@ function () {
427429
});
428430
}
429431

432+
#[OA\Put(
433+
path: "/api/v1/summits/{id}/events/{event_id}/rsvps/resend",
434+
description: "required-groups " . IGroup::SummitAdministrators . ", " . IGroup::SuperAdmins . ", " . IGroup::Administrators,
435+
summary: 'Resend RSVP Confirmation Emails for event',
436+
operationId: 'resendRSVP',
437+
tags: ['RSVP'],
438+
x: [
439+
'required-groups' => [
440+
IGroup::SummitAdministrators,
441+
IGroup::SuperAdmins,
442+
IGroup::Administrators
443+
]
444+
],
445+
security: [['summit_rsvp_oauth2' => [
446+
SummitScopes::WriteSummitData,
447+
]]],
448+
parameters: [
449+
new OA\Parameter(
450+
name: 'access_token',
451+
in: 'query',
452+
required: false,
453+
description: 'OAuth2 access token (alternative to Authorization: Bearer)',
454+
schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'),
455+
),
456+
new OA\Parameter(
457+
name: 'summit_id',
458+
in: 'path',
459+
required: true,
460+
schema: new OA\Schema(type: 'integer'),
461+
description: 'The summit id'
462+
),
463+
new OA\Parameter(
464+
name: 'event_id',
465+
in: 'path',
466+
required: true,
467+
schema: new OA\Schema(type: 'string'),
468+
description: 'The event id'
469+
),
470+
// query string params
471+
new OA\Parameter(
472+
name: 'filter[]',
473+
in: 'query',
474+
required: false,
475+
description: 'Filter expressions in the format field<op>value. Operators: @@, ==, =@.',
476+
style: 'form',
477+
explode: true,
478+
schema: new OA\Schema(
479+
type: 'array',
480+
items: new OA\Items(type: 'string', example: 'owner_email@@[email protected]')
481+
)
482+
),
483+
new OA\Parameter(
484+
name: 'order',
485+
in: 'query',
486+
required: false,
487+
description: 'Order by field(s)',
488+
schema: new OA\Schema(type: 'string', example: 'id,-seat_type')
489+
),
490+
new OA\Parameter(
491+
name: 'expand',
492+
in: 'query',
493+
required: false,
494+
description: 'Comma-separated list of related resources to include',
495+
schema: new OA\Schema(type: 'string', example: 'event,owner')
496+
),
497+
new OA\Parameter(
498+
name: 'relations',
499+
in: 'query',
500+
required: false,
501+
description: 'Relations to load eagerly',
502+
schema: new OA\Schema(type: 'string', example: 'event,owner')
503+
),
504+
new OA\Parameter(
505+
name: 'fields',
506+
in: 'query',
507+
required: false,
508+
description: 'Comma-separated list of fields to return',
509+
schema: new OA\Schema(type: 'string', example: 'id,seat_type,owner.first_name,owner.last_name')
510+
),
511+
],
512+
requestBody: new OA\RequestBody(
513+
required: true,
514+
content: new OA\JsonContent(ref: "#/components/schemas/ReSendRSVPConfirmationRequest")
515+
),
516+
responses: [
517+
new OA\Response(
518+
response: 200,
519+
description: 'RSVP Confirmation send success',
520+
),
521+
new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"),
522+
new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"),
523+
new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"),
524+
new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error")
525+
]
526+
)]
527+
528+
public function resend($summit_id, $event_id)
529+
{
530+
return $this->processRequest(function () use ($summit_id, $event_id) {
531+
532+
if (!Request::isJson()) return $this->error400();
533+
$data = Request::json();
534+
535+
$summit = $this->getSummitOr404($summit_id);
536+
$summit_event = $this->getEventOr404($summit, $event_id);
537+
$this->getCurrentMemberOr403();
538+
539+
$payload = $data->all();
540+
541+
// Creates a Validator instance and validates the data.
542+
$validation = Validator::make($payload, [
543+
'rsvps_ids' => 'sometimes|int_array',
544+
'excluded_rsvps_ids' => 'sometimes|int_array',
545+
'test_email_recipient' => 'sometimes|email',
546+
'outcome_email_recipient' => 'sometimes|email',
547+
]);
548+
549+
if ($validation->fails()) {
550+
$messages = $validation->messages()->toArray();
551+
552+
return $this->error412
553+
(
554+
$messages
555+
);
556+
}
557+
558+
$filter = null;
559+
560+
if (Request::has('filter')) {
561+
$filter = FilterParser::parse(Request::input('filter'), [
562+
'id' => ['=='],
563+
'not_id' => ['=='],
564+
'owner_email' => ['@@', '=@', '=='],
565+
'owner_first_name' => ['@@', '=@', '=='],
566+
'owner_last_name' => ['@@', '=@', '=='],
567+
'owner_full_name' => ['@@', '=@', '=='],
568+
'seat_type' => ['=='],
569+
]);
570+
}
571+
572+
if (is_null($filter))
573+
$filter = new Filter();
574+
575+
$filter->validate([
576+
'id' => 'sometimes|integer',
577+
'not_id' => 'sometimes|integer',
578+
'owner_email' => 'sometimes|required|string',
579+
'owner_first_name' => 'sometimes|required|string',
580+
'owner_last_name' => 'sometimes|required|string',
581+
'owner_full_name' => 'sometimes|required|string',
582+
'seat_type' => 'sometimes|required|string|in:' . join(",", RSVP::ValidSeatTypes),
583+
]);
584+
585+
$this->service->triggerReSend($summit_event, $payload, Request::input('filter'));
586+
587+
return $this->ok();
588+
589+
});
590+
}
591+
430592
#[OA\Get(
431593
path: "/api/v1/summits/{id}/events/{event_id}/rsvps/csv",
432594
description: "required-groups " . IGroup::SummitAdministrators . ", " . IGroup::SuperAdmins . ", " . IGroup::Administrators,
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php namespace App\Jobs\Emails\Schedule\RSVP;
2+
3+
use App\Services\Model\ISummitRSVPService;
4+
use Illuminate\Bus\Queueable;
5+
use Illuminate\Contracts\Queue\ShouldQueue;
6+
use Illuminate\Foundation\Bus\Dispatchable;
7+
use Illuminate\Queue\InteractsWithQueue;
8+
use Illuminate\Queue\SerializesModels;
9+
use Illuminate\Support\Facades\Log;
10+
use models\summit\SummitEvent;
11+
use utils\FilterParser;
12+
13+
class ProcessRSVPConfirmationEmailsJob implements ShouldQueue
14+
{
15+
public $tries = 1;
16+
17+
// no timeout
18+
public $timeout = 0;
19+
20+
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
21+
22+
private $payload;
23+
24+
private $filter;
25+
26+
private $summit_event_id;
27+
28+
/**
29+
* ProcessRSVPInvitationsJob constructor.
30+
* @param SummitEvent $summit_event
31+
* @param array $payload
32+
* @param $filter
33+
*/
34+
public function __construct(SummitEvent $summit_event, array $payload, $filter)
35+
{
36+
$this->summit_event_id = $summit_event->getId();
37+
$this->payload = $payload;
38+
$this->filter = $filter;
39+
}
40+
41+
/**
42+
* @param ISummitRSVPService $service
43+
* @return void
44+
* @throws \utils\FilterParserException
45+
*/
46+
public function handle(ISummitRSVPService $service){
47+
Log::debug(sprintf("ProcessRSVPConfirmationEmailsJob::handle summit event id %s", $this->summit_event_id));
48+
49+
$filter = !is_null($this->filter) ? FilterParser::parse($this->filter, [
50+
'id' => ['=='],
51+
'not_id' => ['=='],
52+
'owner_email' => ['@@', '=@', '=='],
53+
'owner_first_name' => ['@@', '=@', '=='],
54+
'owner_last_name' => ['@@', '=@', '=='],
55+
'owner_full_name' => ['@@', '=@', '=='],
56+
'seat_type' => ['=='],
57+
]) : null;
58+
59+
$service->resend($this->summit_event_id, $this->payload, $filter);
60+
61+
Log::debug(sprintf("ProcessRSVPConfirmationEmailsJob::handle summit event id %s has finished", $this->summit_event_id));
62+
}
63+
64+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php namespace App\Jobs\Emails\Schedule\RSVP;
2+
3+
use App\Jobs\Emails\AbstractExcerptEmailJob;
4+
5+
class RSVPConfirmationExcerptEmail extends AbstractExcerptEmailJob
6+
{
7+
protected function getEmailEventSlug(): string
8+
{
9+
return self::EVENT_SLUG;
10+
}
11+
12+
// metadata
13+
const EVENT_SLUG = 'SUMMIT_REGISTRATION_RSVP_CONFIRMATION_EXCERPT';
14+
const EVENT_NAME = 'SUMMIT_REGISTRATION_RSVP_CONFIRMATION_EXCERPT';
15+
const DEFAULT_TEMPLATE = 'SUMMIT_REGISTRATION_RSVP_CONFIRMATION_EXCERPT';
16+
}

app/Models/Foundation/Summit/Events/RSVP/RSVP.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ public function activate():void{
339339
$this->action_date = new \DateTime('now', new \DateTimeZone('UTC'));
340340
}
341341

342+
public function isActive():bool{
343+
return $this->status == self::Status_Active;
344+
}
345+
342346
public function ticketReassigned():void{
343347
$this->status = self::Status_TicketReassigned;
344348
$this->action_date = new \DateTime('now', new \DateTimeZone('UTC'));

app/Services/Model/ISummitRSVPService.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use models\summit\RSVP;
1616
use models\summit\Summit;
1717
use models\summit\SummitEvent;
18+
use utils\Filter;
1819

1920
interface ISummitRSVPService
2021
{
@@ -58,4 +59,17 @@ public function delete(SummitEvent $event, int $rsvp_id): void;
5859
* @return RSVP
5960
*/
6061
public function createRSVPFromPayload(Summit $summit, int $event_id, array $payload):RSVP;
62+
/**
63+
* @param SummitEvent $summit_event
64+
* @param array $payload
65+
* @param mixed $filter
66+
*/
67+
public function triggerReSend(SummitEvent $summit_event, array $payload, $filter = null):void;
68+
69+
/**
70+
* @param int $event_id
71+
* @param array $payload
72+
* @param Filter|null $filter
73+
*/
74+
public function resend(int $event_id, array $payload, Filter $filter = null):void;
6175
}

0 commit comments

Comments
 (0)