Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ on:
branches:
- main
- develop
pull_request:
types: [closed]
branches:
- main
- develop
workflow_dispatch:
inputs:
environment:
Expand All @@ -25,6 +30,8 @@ jobs:
backend:
name: Deploy Backend
runs-on: ubuntu-latest
# Only run this job when a PR is merged (not when closed without merging)
if: github.event_name != 'pull_request' || github.event.pull_request.merged == true

steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -60,7 +67,7 @@ jobs:
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "VAPOR_ENV=${{ github.event.inputs.environment }}" >> "$GITHUB_ENV"
echo "TEST_MODE=${{ github.event.inputs.test_mode }}" >> "$GITHUB_ENV"
elif [[ "${{ github.ref_name }}" == "develop" ]]; then
elif [[ "${{ github.base_ref }}" == "develop" || "${{ github.ref_name }}" == "develop" ]]; then
echo "VAPOR_ENV=staging" >> "$GITHUB_ENV"
echo "TEST_MODE=false" >> "$GITHUB_ENV"
else
Expand All @@ -70,7 +77,7 @@ jobs:

- name: Log Branch and Environment
run: |
echo "🚀 Deploying branch ${{ github.ref_name }} to Vapor environment: ${{ env.VAPOR_ENV }}"
echo "🚀 Deploying to Vapor environment: ${{ env.VAPOR_ENV }}"
echo "🧪 Test mode: ${{ env.TEST_MODE }}"

- name: Validate Deployment Configuration
Expand All @@ -92,6 +99,8 @@ jobs:
name: Deploy Frontend
runs-on: ubuntu-latest
needs: backend
# Only run this job when a PR is merged (not when closed without merging)
if: github.event_name != 'pull_request' || github.event.pull_request.merged == true

steps:
- uses: actions/checkout@v3
Expand All @@ -105,7 +114,7 @@ jobs:
echo "DO_APP_ID=${{ secrets.DIGITALOCEAN_PRODUCTION_APP_ID }}" >> "$GITHUB_ENV"
fi
echo "TEST_MODE=${{ github.event.inputs.test_mode }}" >> "$GITHUB_ENV"
elif [[ "${{ github.ref_name }}" == "develop" ]]; then
elif [[ "${{ github.base_ref }}" == "develop" || "${{ github.ref_name }}" == "develop" ]]; then
echo "DO_APP_ID=${{ secrets.DIGITALOCEAN_STAGING_APP_ID }}" >> "$GITHUB_ENV"
echo "TEST_MODE=false" >> "$GITHUB_ENV"
else
Expand Down
8 changes: 8 additions & 0 deletions backend/app/DomainObjects/Enums/QuestionTypeEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,12 @@ enum QuestionTypeEnum
case DROPDOWN;
case MULTI_SELECT_DROPDOWN;
case DATE;

public static function getMultipleChoiceTypes(): array
{
return [
self::CHECKBOX,
self::MULTI_SELECT_DROPDOWN,
];
}
}
72 changes: 72 additions & 0 deletions backend/app/DomainObjects/QuestionAndAnswerViewDomainObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@ class QuestionAndAnswerViewDomainObject extends AbstractDomainObject
private int $question_id;
private ?int $order_id;
private string $title;
private bool $question_required;
private ?string $question_description = null;
private ?string $first_name = null;
private ?string $last_name = null;
private array|string $answer;
private string $belongs_to;
private ?int $attendee_id = null;
private ?string $attendee_public_id = null;
private string $question_type;
private int $event_id;
private int $question_answer_id;
private ?array $question_options = null;

private ?AttendeeDomainObject $attendee = null;

Expand Down Expand Up @@ -183,19 +188,86 @@ public function setQuestion(?QuestionDomainObject $question): static
return $this;
}

public function getQuestionAnswerId(): int
{
return $this->question_answer_id;
}

public function setQuestionAnswerId(int $question_answer_id): QuestionAndAnswerViewDomainObject
{
$this->question_answer_id = $question_answer_id;

return $this;
}

public function getQuestionDescription(): ?string
{
return $this->question_description;
}

public function setQuestionDescription(?string $question_description): QuestionAndAnswerViewDomainObject
{
$this->question_description = $question_description;

return $this;
}

public function getQuestionRequired(): bool
{
return $this->question_required;
}

public function setQuestionRequired(bool $question_required): QuestionAndAnswerViewDomainObject
{
$this->question_required = $question_required;

return $this;
}

public function getQuestionOptions(): ?array
{
return $this->question_options;
}

public function setQuestionOptions(?array $question_options): QuestionAndAnswerViewDomainObject
{
$this->question_options = $question_options;

return $this;
}

public function getAttendeePublicId(): ?string
{
return $this->attendee_public_id;
}

public function setAttendeePublicId(?string $attendee_public_id): QuestionAndAnswerViewDomainObject
{
$this->attendee_public_id = $attendee_public_id;

return $this;
}

public function toArray(): array
{
return [
'question_id' => $this->question_id ?? null,
'order_id' => $this->order_id ?? null,
'title' => $this->title ?? null,
'question_description' => $this->question_description ?? null,
'question_required' => $this->question_required ?? null,
'last_name' => $this->last_name ?? null,
'answer' => $this->answer ?? null,
'belongs_to' => $this->belongs_to ?? null,
'attendee_id' => $this->attendee_id ?? null,
'attendee_public_id' => $this->attendee_public_id ?? null,
'question_type' => $this->question_type ?? null,
'first_name' => $this->first_name ?? null,
'event_id' => $this->event_id ?? null,
'product_id' => $this->product_id ?? null,
'product_title' => $this->product_title ?? null,
'question_answer_id' => $this->question_answer_id ?? null,
'question_options' => $this->question_options ?? null,
];
}
}
29 changes: 29 additions & 0 deletions backend/app/DomainObjects/QuestionAnswerDomainObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@

namespace HiEvents\DomainObjects;

use HiEvents\DomainObjects\Generated\OrderDomainObjectAbstract;

class QuestionAnswerDomainObject extends Generated\QuestionAnswerDomainObjectAbstract
{
private ?OrderDomainObjectAbstract $order = null;

private ?QuestionDomainObject $question = null;

public function setOrder(?OrderDomainObjectAbstract $order): QuestionAnswerDomainObject
{
$this->order = $order;

return $this;
}

public function getOrder(): ?OrderDomainObjectAbstract
{
return $this->order;
}

public function setQuestion(?QuestionDomainObject $question): QuestionAnswerDomainObject
{
$this->question = $question;

return $this;
}

public function getQuestion(): ?QuestionDomainObject
{
return $this->question;
}
}
16 changes: 16 additions & 0 deletions backend/app/DomainObjects/QuestionDomainObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,20 @@ public function setOptions(array|string|null $options): self
return $this;
}

public function isAnswerValid(mixed $answer): bool
{
if (!isset($answer)) {
return false;
}

if (!$this->isPreDefinedChoice()) {
return true;
}

if (is_string($answer)) {
return in_array($answer, $this->getOptions(), true);
}

return array_diff((array)$answer, $this->getOptions()) === [];
}
}
2 changes: 1 addition & 1 deletion backend/app/Http/Actions/Auth/LoginAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function __invoke(LoginRequest $request): JsonResponse
$loginResponse = $this->loginHandler->handle(new LoginCredentialsDTO(
email: strtolower($request->validated('email')),
password: $request->validated('password'),
accountId: $request->validated('account_id'),
accountId: (int)$request->validated('account_id'),
));
} catch (UnauthorizedException $e) {
return $this->errorResponse(
Expand Down
2 changes: 1 addition & 1 deletion backend/app/Http/Actions/Auth/RefreshTokenAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ class RefreshTokenAction extends BaseAuthAction
{
public function __invoke(): JsonResponse
{
return $this->respondWithToken(auth()->refresh(), auth()->user()->accounts);
return $this->respondWithToken(auth()->refresh(), $this->getAuthenticatedUser()->accounts ?? collect());
}
}
6 changes: 5 additions & 1 deletion backend/app/Http/Actions/Orders/GetOrderAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use HiEvents\DomainObjects\OrderItemDomainObject;
use HiEvents\DomainObjects\QuestionAndAnswerViewDomainObject;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Repository\Eloquent\Value\OrderAndDirection;
use HiEvents\Repository\Eloquent\Value\Relationship;
use HiEvents\Repository\Interfaces\OrderRepositoryInterface;
use HiEvents\Resources\Order\OrderResource;
use Illuminate\Http\JsonResponse;
Expand All @@ -27,7 +29,9 @@ public function __invoke(int $eventId, int $orderId): JsonResponse
$order = $this->orderRepository
->loadRelation(OrderItemDomainObject::class)
->loadRelation(AttendeeDomainObject::class)
->loadRelation(QuestionAndAnswerViewDomainObject::class)
->loadRelation(new Relationship(domainObject: QuestionAndAnswerViewDomainObject::class, orderAndDirections: [
new OrderAndDirection(order: 'question_id'),
]))
->findById($orderId);

return $this->resourceResponse(OrderResource::class, $order);
Expand Down
43 changes: 43 additions & 0 deletions backend/app/Http/Actions/Questions/EditQuestionAnswerAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace HiEvents\Http\Actions\Questions;

use HiEvents\DomainObjects\EventDomainObject;
use HiEvents\Http\Actions\BaseAction;
use HiEvents\Http\Request\Questions\EditQuestionAnswerRequest;
use HiEvents\Services\Application\Handlers\Question\DTO\EditQuestionAnswerDTO;
use HiEvents\Services\Application\Handlers\Question\EditQuestionAnswerHandler;
use HiEvents\Services\Domain\Question\Exception\InvalidAnswerException;
use Illuminate\Http\Response;
use Illuminate\Validation\ValidationException;

class EditQuestionAnswerAction extends BaseAction
{
public function __construct(
private readonly EditQuestionAnswerHandler $editQuestionAnswerHandler,
)
{
}

public function __invoke(
int $eventId,
int $questionId,
int $questionAnswerId,
EditQuestionAnswerRequest $request,
): Response
{
$this->isActionAuthorized($eventId, EventDomainObject::class);

try {
$this->editQuestionAnswerHandler->handle(new EditQuestionAnswerDTO(
questionAnswerId: $questionAnswerId,
eventId: $eventId,
answer: $request->validated('answer'),
));
} catch (InvalidAnswerException $e) {
throw ValidationException::withMessages(['answer.answer' => $e->getMessage()]);
}

return $this->noContentResponse();
}
}
39 changes: 0 additions & 39 deletions backend/app/Http/Actions/Users/DeactivateUsersAction.php

This file was deleted.

22 changes: 22 additions & 0 deletions backend/app/Http/Request/Questions/EditQuestionAnswerRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace HiEvents\Http\Request\Questions;

use HiEvents\Http\Request\BaseRequest;

class EditQuestionAnswerRequest extends BaseRequest
{
public function rules(): array
{
return [
'answer' => [
'nullable',
function ($attribute, $value, $fail) {
if (!is_string($value) && !is_array($value)) {
$fail("The {$attribute} must be a string or an array.");
}
}
],
];
}
}
1 change: 1 addition & 0 deletions backend/app/Models/QuestionAndAnswerView.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class QuestionAndAnswerView extends Model

protected $casts = [
'answer' => 'array',
'question_options' => 'array',
];

public function attendee(): BelongsTo
Expand Down
Loading
Loading