Skip to content

Commit

Permalink
Merge branch 'feature/import' into feature/add_frontend_dashboard
Browse files Browse the repository at this point in the history
# Conflicts:
#	app/Http/Controllers/Api/V1/TimeEntryController.php
#	app/Providers/JetstreamServiceProvider.php
  • Loading branch information
korridor committed Mar 12, 2024
2 parents 8a2aeff + 91d7069 commit e15b7b9
Show file tree
Hide file tree
Showing 96 changed files with 3,442 additions and 107 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="[email protected]"
MAIL_FROM_ADDRESS="[email protected]"
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ yarn-error.log
/blob-report/
/playwright/.cache/
/coverage
/extensions/*
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Add the following entry to your `/etc/hosts`
```
127.0.0.1 solidtime.test
127.0.0.1 playwright.solidtime.test
127.0.0.1 mail.solidtime.test
```

## Running E2E Tests
Expand Down
22 changes: 20 additions & 2 deletions app/Actions/Fortify/CreateNewUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@

use App\Models\Organization;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
use Laravel\Fortify\Contracts\CreatesNewUsers;
use Laravel\Jetstream\Jetstream;

Expand All @@ -20,12 +23,27 @@ class CreateNewUser implements CreatesNewUsers
* Create a newly registered user.
*
* @param array<string, string> $input
*
* @throws ValidationException
*/
public function create(array $input): User
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'name' => [
'required',
'string',
'max:255',
],
'email' => [
'required',
'string',
'email',
'max:255',
new UniqueEloquent(User::class, 'email', function (Builder $builder): Builder {
/** @var Builder<User> $builder */
return $builder->where('is_placeholder', '=', false);
}),
],
'password' => $this->passwordRules(),
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['accepted', 'required'] : '',
])->validate();
Expand Down
34 changes: 22 additions & 12 deletions app/Actions/Jetstream/AddOrganizationMember.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
use App\Models\User;
use Closure;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
use Laravel\Jetstream\Contracts\AddsTeamMembers;
use Laravel\Jetstream\Events\AddingTeamMember;
use Laravel\Jetstream\Events\TeamMemberAdded;
Expand All @@ -21,21 +24,24 @@ class AddOrganizationMember implements AddsTeamMembers
/**
* Add a new team member to the given team.
*/
public function add(User $user, Organization $organization, string $email, ?string $role = null): void
public function add(User $owner, Organization $organization, string $email, ?string $role = null): void
{
Gate::forUser($user)->authorize('addTeamMember', $organization);
Gate::forUser($owner)->authorize('addTeamMember', $organization);

$this->validate($organization, $email, $role);

$newTeamMember = Jetstream::findUserByEmailOrFail($email);
$newOrganizationMember = User::query()
->where('email', $email)
->where('is_placeholder', '=', false)
->firstOrFail();

AddingTeamMember::dispatch($organization, $newTeamMember);
AddingTeamMember::dispatch($organization, $newOrganizationMember);

$organization->users()->attach(
$newTeamMember, ['role' => $role]
$newOrganizationMember, ['role' => $role]
);

TeamMemberAdded::dispatch($organization, $newTeamMember);
TeamMemberAdded::dispatch($organization, $newOrganizationMember);
}

/**
Expand All @@ -46,22 +52,26 @@ protected function validate(Organization $organization, string $email, ?string $
Validator::make([
'email' => $email,
'role' => $role,
], $this->rules(), [
'email.exists' => __('We were unable to find a registered user with this email address.'),
])->after(
], $this->rules())->after(
$this->ensureUserIsNotAlreadyOnTeam($organization, $email)
)->validateWithBag('addTeamMember');
}

/**
* Get the validation rules for adding a team member.
*
* @return array<string, array<Rule|string>>
* @return array<string, array<ValidationRule|Rule|string>>
*/
protected function rules(): array
{
return array_filter([
'email' => ['required', 'email', 'exists:users'],
'email' => [
'required',
'email',
(new ExistsEloquent(User::class, 'email', function (Builder $builder) {
return $builder->where('is_placeholder', '=', false);
}))->withMessage(__('We were unable to find a registered user with this email address.')),
],
'role' => Jetstream::hasRoles()
? ['required', 'string', new Role]
: null,
Expand All @@ -75,7 +85,7 @@ protected function ensureUserIsNotAlreadyOnTeam(Organization $team, string $emai
{
return function ($validator) use ($team, $email) {
$validator->errors()->addIf(
$team->hasUserWithEmail($email),
$team->hasRealUserWithEmail($email),
'email',
__('This user already belongs to the team.')
);
Expand Down
11 changes: 5 additions & 6 deletions app/Actions/Jetstream/InviteOrganizationMember.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public function invite(User $user, Organization $organization, string $email, ?s

InvitingTeamMember::dispatch($organization, $email, $role);

/** @var OrganizationInvitation $invitation */
$invitation = $organization->teamInvitations()->create([
'email' => $email,
'role' => $role,
Expand All @@ -50,9 +51,7 @@ protected function validate(Organization $organization, string $email, ?string $
Validator::make([
'email' => $email,
'role' => $role,
], $this->rules($organization), [
'email.unique' => __('This user has already been invited to the team.'),
])->after(
], $this->rules($organization))->after(
$this->ensureUserIsNotAlreadyOnTeam($organization, $email)
)->validateWithBag('addTeamMember');
}
Expand All @@ -68,10 +67,10 @@ protected function rules(Organization $organization): array
'email' => [
'required',
'email',
new UniqueEloquent(OrganizationInvitation::class, 'email', function (Builder $builder) use ($organization) {
(new UniqueEloquent(OrganizationInvitation::class, 'email', function (Builder $builder) use ($organization) {
/** @var Builder<OrganizationInvitation> $builder */
return $builder->whereBelongsTo($organization, 'organization');
}),
}))->withMessage(__('This user has already been invited to the team.')),
],
'role' => Jetstream::hasRoles()
? ['required', 'string', new Role]
Expand All @@ -86,7 +85,7 @@ protected function ensureUserIsNotAlreadyOnTeam(Organization $organization, stri
{
return function ($validator) use ($organization, $email) {
$validator->errors()->addIf(
$organization->hasUserWithEmail($email),
$organization->hasRealUserWithEmail($email),
'email',
__('This user already belongs to the team.')
);
Expand Down
50 changes: 50 additions & 0 deletions app/Exceptions/Api/ApiException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace App\Exceptions\Api;

use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use LogicException;

abstract class ApiException extends Exception
{
public const string KEY = 'api_exception';

/**
* Render the exception into an HTTP response.
*/
public function render(Request $request): JsonResponse
{
return response()
->json([
'error' => true,
'key' => $this->getKey(),
'message' => $this->getTranslatedMessage(),
], 400);
}

/**
* Get the key for the exception.
*/
public function getKey(): string
{
$key = static::KEY;

if ($key === ApiException::KEY) {
throw new LogicException('API exceptions need the KEY constant defined.');
}

return $key;
}

/**
* Get the translated message for the exception.
*/
public function getTranslatedMessage(): string
{
return __('exceptions.api.'.$this->getKey());
}
}
10 changes: 10 additions & 0 deletions app/Exceptions/Api/TimeEntryStillRunningApiException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace App\Exceptions\Api;

class TimeEntryStillRunningApiException extends ApiException
{
public const string KEY = 'time_entry_still_running';
}
10 changes: 10 additions & 0 deletions app/Exceptions/Api/UserNotPlaceholderApiException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace App\Exceptions\Api;

class UserNotPlaceholderApiException extends ApiException
{
public const string KEY = 'user_not_placeholder';
}
24 changes: 0 additions & 24 deletions app/Exceptions/ApiException.php

This file was deleted.

9 changes: 0 additions & 9 deletions app/Exceptions/TimeEntryStillRunning.php

This file was deleted.

11 changes: 10 additions & 1 deletion app/Filament/Resources/ClientResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use App\Filament\Resources\ClientResource\Pages;
use App\Models\Client;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
Expand All @@ -26,7 +28,14 @@ public static function form(Form $form): Form
{
return $form
->schema([
//
TextInput::make('name')
->label('Name')
->required(),
Select::make('organization_id')
->relationship(name: 'organization', titleAttribute: 'name')
->label('Organization')
->searchable(['name'])
->required(),
]);
}

Expand Down
Loading

0 comments on commit e15b7b9

Please sign in to comment.