Updated dependencies; Fixed codeformatting and phpstan

This commit is contained in:
Constantin Graf
2024-07-31 12:53:41 +02:00
committed by Constantin Graf
parent 5b7df869ad
commit d8968399d6
78 changed files with 1038 additions and 1148 deletions

View File

@@ -88,7 +88,7 @@ class CreateNewUser implements CreatesNewUsers
'week_start' => $startOfWeek,
]);
$organization = new Organization();
$organization = new Organization;
$organization->name = explode(' ', $user->name, 2)[0]."'s Organization";
$organization->personal_team = true;
$organization->currency = $currency ?? 'EUR';

View File

@@ -72,6 +72,7 @@ class AddOrganizationMember implements AddsTeamMembers
'required',
'email',
(new ExistsEloquent(User::class, 'email', function (Builder $builder) {
/** @var Builder<User> $builder */
return $builder->where('is_placeholder', '=', false);
}))->withMessage(__('We were unable to find a registered user with this email address.')),
],

View File

@@ -33,7 +33,7 @@ class CreateOrganization implements CreatesTeams
'name' => ['required', 'string', 'max:255'],
])->validateWithBag('createTeam');
$organization = new Organization();
$organization = new Organization;
$organization->name = $input['name'];
$organization->personal_team = false;
$organization->owner()->associate($user);
@@ -45,10 +45,10 @@ class CreateOrganization implements CreatesTeams
]
);
$user->ownedTeams()->save($organization);
$user->switchTeam($organization);
// Note: The refresh is necessary for currently unknown reasons. Do not remove it.
$organization = $organization->refresh();
AfterCreateOrganization::dispatch($organization);
return $organization;

View File

@@ -19,6 +19,6 @@ class InviteOrganizationMember implements InvitesTeamMembers
*/
public function invite(User $user, Organization $organization, string $email, ?string $role = null): void
{
throw new MovedToApiException();
throw new MovedToApiException;
}
}

View File

@@ -19,6 +19,6 @@ class RemoveOrganizationMember implements RemovesTeamMembers
*/
public function remove(User $user, Organization $organization, User $teamMember): void
{
throw new MovedToApiException();
throw new MovedToApiException;
}
}

View File

@@ -20,6 +20,6 @@ class UpdateMemberRole
*/
public function update(User $actingUser, Organization $organization, string $userId, string $role): void
{
throw new MovedToApiException();
throw new MovedToApiException;
}
}

View File

@@ -36,7 +36,7 @@ class UpdateOrganization implements UpdatesTeamNames
'currency' => [
'required',
'string',
new CurrencyRule(),
new CurrencyRule,
],
])->validateWithBag('updateTeamName');

View File

@@ -22,7 +22,7 @@ class ValidateOrganizationDeletion
public function validate(User $user, Organization $organization): void
{
if (! app(PermissionStore::class)->userHas($organization, $user, 'organizations:delete')) {
throw new AuthorizationException();
throw new AuthorizationException;
}
}
}

View File

@@ -6,10 +6,11 @@ namespace App\Console\Commands\TimeEntry;
use App\Mail\TimeEntryStillRunningMail;
use App\Models\TimeEntry;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Mail;
class TimeEntrySendStillRunningMailsCommand extends Command
@@ -48,7 +49,8 @@ class TimeEntrySendStillRunningMailsCommand extends Command
->with([
'user',
])
->whereHas('user', function (Builder $query) {
->whereHas('user', function (Builder $query): void {
/** @var Builder<User> $query */
$query->where('is_placeholder', '=', false);
})
->orderBy('created_at', 'asc')

View File

@@ -6,6 +6,7 @@ namespace App\Events;
use App\Models\Organization;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* This event is fired after an organization has been created.
@@ -14,6 +15,7 @@ use Illuminate\Foundation\Events\Dispatchable;
class AfterCreateOrganization
{
use Dispatchable;
use SerializesModels;
public Organization $organization;

View File

@@ -24,20 +24,20 @@ class ApiExceptionTypeToSchema extends ExceptionToResponseExtension
public function toResponse(Type $type): Response
{
$validationResponseBodyType = (new OpenApiTypes\ObjectType())
$validationResponseBodyType = (new OpenApiTypes\ObjectType)
->addProperty(
'error',
(new OpenApiTypes\BooleanType())
(new OpenApiTypes\BooleanType)
->setDescription('Whether the response is an error.')
)
->addProperty(
'key',
(new OpenApiTypes\StringType())
(new OpenApiTypes\StringType)
->setDescription('Error key.')
)
->addProperty(
'message',
(new OpenApiTypes\StringType())
(new OpenApiTypes\StringType)
->setDescription('Error message.')
)
->setRequired(['error', 'key', 'message']);

View File

@@ -45,7 +45,7 @@ class PaginatedResourceCollectionTypeToSchema extends TypeToSchemaExtension
}
$type = new OpenApiObjectType;
$type->addProperty('data', (new ArrayType())->setItems($collectingType));
$type->addProperty('data', (new ArrayType)->setItems($collectingType));
$type->addProperty(
'links',
(new OpenApiObjectType)

View File

@@ -111,9 +111,18 @@ class UserResource extends Resource
->filters([
TernaryFilter::make('real_user')
->queries(
true: fn (Builder $query) => $query->where('is_placeholder', '=', false),
false: fn (Builder $query) => $query->where('is_placeholder', '=', true),
blank: fn (Builder $query) => $query,
true: function (Builder $query): Builder {
/** @var Builder<User> $query */
return $query->where('is_placeholder', '=', false);
},
false: function (Builder $query): Builder {
/** @var Builder<User> $query */
return $query->where('is_placeholder', '=', true);
},
blank: function (Builder $query): Builder {
/** @var Builder<User> $query */
return $query;
},
)
->label('Real User?'),
TernaryFilter::make('email_verified')

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Filament\Widgets;
use App\Models\TimeEntry;
use App\Models\User;
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
use Filament\Widgets\StatsOverviewWidget\Stat;
@@ -21,7 +22,8 @@ class ActiveUserOverview extends BaseWidget
$placeholderUserCount = User::query()->where('is_placeholder', '=', true)->count();
$activeInLastWeek = User::query()
->where('is_placeholder', '=', false)
->whereHas('timeEntries', function (Builder $query) {
->whereHas('timeEntries', function (Builder $query): void {
/** @var Builder<TimeEntry> $query */
$query->where('created_at', '>=', now()->subWeek())
->orWhere('updated_at', '>=', now()->subWeek());
})

View File

@@ -66,7 +66,7 @@ class ClientController extends Controller
{
$this->checkPermission($organization, 'clients:create');
$client = new Client();
$client = new Client;
$client->name = $request->input('name');
$client->organization()->associate($organization);
$client->save();

View File

@@ -12,8 +12,7 @@ class Controller extends \App\Http\Controllers\Controller
{
public function __construct(
protected PermissionStore $permissionStore,
) {
}
) {}
/**
* @throws AuthorizationException
@@ -21,7 +20,7 @@ class Controller extends \App\Http\Controllers\Controller
protected function checkPermission(Organization $organization, string $permission): void
{
if (! $this->permissionStore->has($organization, $permission)) {
throw new AuthorizationException();
throw new AuthorizationException;
}
}
@@ -37,7 +36,7 @@ class Controller extends \App\Http\Controllers\Controller
return;
}
}
throw new AuthorizationException();
throw new AuthorizationException;
}
protected function hasPermission(Organization $organization, string $permission): bool

View File

@@ -35,7 +35,7 @@ class ImportController extends Controller
foreach ($importers as $key => $importerClass) {
/** @var ImporterContract $importer */
$importer = new $importerClass();
$importer = new $importerClass;
$importersResponse[] = [
'key' => $key,
'name' => $importer->getName(),

View File

@@ -82,16 +82,16 @@ class MemberController extends Controller
$newRole = $request->getRole();
$oldRole = Role::from($member->role);
if ($oldRole === Role::Owner) {
throw new OrganizationNeedsAtLeastOneOwner();
throw new OrganizationNeedsAtLeastOneOwner;
}
if ($newRole === Role::Placeholder) {
throw new ChangingRoleToPlaceholderIsNotAllowed();
throw new ChangingRoleToPlaceholderIsNotAllowed;
}
if ($newRole === Role::Owner) {
if ($this->hasPermission($organization, 'members:change-ownership')) {
$memberService->changeOwnership($organization, $member);
} else {
throw new OnlyOwnerCanChangeOwnership();
throw new OnlyOwnerCanChangeOwnership;
}
} else {
$member->role = $request->getRole()->value;
@@ -120,7 +120,7 @@ class MemberController extends Controller
throw new EntityStillInUseApiException('member', 'project_member');
}
if ($member->role === Role::Owner->value) {
throw new CanNotRemoveOwnerFromOrganization();
throw new CanNotRemoveOwnerFromOrganization;
}
$member->delete();
@@ -138,7 +138,7 @@ class MemberController extends Controller
$this->checkPermission($organization, 'members:make-placeholder', $member);
if ($member->role === Role::Owner->value) {
throw new CanNotRemoveOwnerFromOrganization();
throw new CanNotRemoveOwnerFromOrganization;
}
$memberService->makeMemberToPlaceholder($member);
@@ -161,7 +161,7 @@ class MemberController extends Controller
$user = $member->user;
if (! $user->is_placeholder) {
throw new UserNotPlaceholderApiException();
throw new UserNotPlaceholderApiException;
}
$invitationService->inviteUser($organization, $user->email, Role::Employee);

View File

@@ -89,7 +89,7 @@ class ProjectController extends Controller
public function store(Organization $organization, ProjectStoreRequest $request): JsonResource
{
$this->checkPermission($organization, 'projects:create');
$project = new Project();
$project = new Project;
$project->name = $request->input('name');
$project->color = $request->input('color');
$project->is_billable = (bool) $request->input('is_billable');

View File

@@ -65,13 +65,13 @@ class ProjectMemberController extends Controller
$member = Member::findOrFail((string) $request->input('member_id'));
if ($member->user->is_placeholder) {
throw new InactiveUserCanNotBeUsedApiException();
throw new InactiveUserCanNotBeUsedApiException;
}
if (ProjectMember::whereBelongsTo($project, 'project')->whereBelongsTo($member, 'member')->exists()) {
throw new UserIsAlreadyMemberOfProjectApiException();
throw new UserIsAlreadyMemberOfProjectApiException;
}
$projectMember = new ProjectMember();
$projectMember = new ProjectMember;
$projectMember->billable_rate = $request->getBillableRate();
$projectMember->member()->associate($member);
$projectMember->user()->associate($member->user);

View File

@@ -57,7 +57,7 @@ class TagController extends Controller
{
$this->checkPermission($organization, 'tags:create');
$tag = new Tag();
$tag = new Tag;
$tag->name = $request->input('name');
$tag->organization()->associate($organization);
$tag->save();

View File

@@ -76,7 +76,7 @@ class TaskController extends Controller
public function store(Organization $organization, TaskStoreRequest $request): JsonResource
{
$this->checkPermission($organization, 'tasks:create');
$task = new Task();
$task = new Task;
$task->name = $request->input('name');
$task->project_id = $request->input('project_id');
$task->organization()->associate($organization);

View File

@@ -212,12 +212,12 @@ class TimeEntryController extends Controller
}
if ($request->input('end') === null && TimeEntry::query()->whereBelongsTo($member, 'member')->where('end', null)->exists()) {
throw new TimeEntryStillRunningApiException();
throw new TimeEntryStillRunningApiException;
}
$client = $request->input('project_id') !== null ? Project::findOrFail((string) $request->input('project_id'))->client : null;
$timeEntry = new TimeEntry();
$timeEntry = new TimeEntry;
$timeEntry->fill($request->validated());
$timeEntry->client()->associate($client);
$timeEntry->user_id = $member->user_id;
@@ -247,7 +247,7 @@ class TimeEntryController extends Controller
}
if ($timeEntry->end !== null && $request->has('end') && $request->input('end') === null) {
throw new TimeEntryCanNotBeRestartedApiException();
throw new TimeEntryCanNotBeRestartedApiException;
}
if ($request->has('project_id')) {
@@ -285,7 +285,7 @@ class TimeEntryController extends Controller
$changes = $request->validated('changes');
if (isset($changes['member_id']) && ! $canAccessAll && $this->member($organization)->getKey() !== $changes['member_id']) {
throw new AuthorizationException();
throw new AuthorizationException;
}
$client = null;
@@ -295,8 +295,8 @@ class TimeEntryController extends Controller
$overwriteClient = true;
}
$success = new Collection();
$error = new Collection();
$success = new Collection;
$error = new Collection;
foreach ($ids as $id) {
/** @var TimeEntry|null $timeEntry */

View File

@@ -28,7 +28,7 @@ class Controller extends BaseController
$user = Auth::user();
if ($user === null) {
Log::error('This function should only be called in authenticated context');
throw new AuthorizationException();
throw new AuthorizationException;
}
return $user;
@@ -44,7 +44,7 @@ class Controller extends BaseController
$member = Member::query()->whereBelongsTo($organization, 'organization')->whereBelongsTo($user, 'user')->first();
if ($member === null) {
Log::error('This function should only be called in authenticated context after checking the user is a member of the organization');
throw new AuthorizationException();
throw new AuthorizationException;
}
return $member;

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace App\Http\Controllers\Web;
abstract class Controller extends \App\Http\Controllers\Controller
{
}
abstract class Controller extends \App\Http\Controllers\Controller {}

View File

@@ -32,7 +32,7 @@ class CheckOrganizationBlocked
$billing = app(BillingContract::class);
if ($billing->isBlocked($organization)) {
throw new OrganizationHasNoSubscriptionButMultipleMembersException();
throw new OrganizationHasNoSubscriptionButMultipleMembersException;
}
return $next($request);

View File

@@ -41,7 +41,7 @@ class ProjectStoreRequest extends FormRequest
'required',
'string',
'max:255',
new ColorRule(),
new ColorRule,
],
'is_billable' => [
'required',

View File

@@ -41,7 +41,7 @@ class ProjectUpdateRequest extends FormRequest
'required',
'string',
'max:255',
new ColorRule(),
new ColorRule,
],
'is_billable' => [
'required',

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace App\Http\Resources;
interface PaginatedResourceCollection
{
}
interface PaginatedResourceCollection {}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Listeners;
use App\Models\Member;
use App\Models\User;
use App\Service\UserService;
use Illuminate\Database\Eloquent\Builder;
use Laravel\Jetstream\Events\TeamMemberAdded;
@@ -19,7 +20,8 @@ class RemovePlaceholder
/** @var UserService $userService */
$userService = app(UserService::class);
$placeholders = Member::query()
->whereHas('user', function (Builder $query) use ($event) {
->whereHas('user', function (Builder $query) use ($event): void {
/** @var Builder<User> $query */
$query->where('is_placeholder', '=', true)
->where('email', '=', $event->user->email);
})

View File

@@ -29,5 +29,6 @@ use OwenIt\Auditing\Models\Audit as PackageAuditModel;
*/
class Audit extends PackageAuditModel
{
/** @use HasFactory<AuditFactory> */
use HasFactory;
}

View File

@@ -30,7 +30,10 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
class Client extends Model implements AuditableContract
{
use Auditable;
/** @use HasFactory<ClientFactory> */
use HasFactory;
use HasUuids;
/**

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Models;
use Database\Factories\FailedJobFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
@@ -16,6 +17,7 @@ use Illuminate\Support\Carbon;
*/
class FailedJob extends Model
{
/** @use HasFactory<FailedJobFactory> */
use HasFactory;
/**

View File

@@ -30,7 +30,10 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
class Member extends JetstreamMembership implements AuditableContract
{
use Auditable;
/** @use HasFactory<MemberFactory> */
use HasFactory;
use HasUuids;
/**

View File

@@ -9,6 +9,7 @@ use Database\Factories\OrganizationFactory;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Carbon;
@@ -42,7 +43,10 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
class Organization extends JetstreamTeam implements AuditableContract
{
use Auditable;
/** @use HasFactory<OrganizationFactory> */
use HasFactory;
use HasUuids;
/**
@@ -110,7 +114,7 @@ class Organization extends JetstreamTeam implements AuditableContract
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(Jetstream::userModel(), Jetstream::membershipModel())
return $this->belongsToMany(User::class, Member::class)
->withPivot([
'id',
'role',
@@ -120,6 +124,16 @@ class Organization extends JetstreamTeam implements AuditableContract
->as('membership');
}
/**
* Get the owner of the team.
*
* @return BelongsTo<User, Organization>
*/
public function owner(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
/**
* @return HasMany<Member>
*/

View File

@@ -9,7 +9,6 @@ use Database\Factories\OrganizationInvitationFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Carbon;
use Laravel\Jetstream\Jetstream;
use Laravel\Jetstream\TeamInvitation as JetstreamTeamInvitation;
use OwenIt\Auditing\Auditable;
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
@@ -28,7 +27,10 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
class OrganizationInvitation extends JetstreamTeamInvitation implements AuditableContract
{
use Auditable;
/** @use HasFactory<OrganizationInvitationFactory> */
use HasFactory;
use HasUuids;
/**
@@ -55,7 +57,7 @@ class OrganizationInvitation extends JetstreamTeamInvitation implements Auditabl
*/
public function organization(): BelongsTo
{
return $this->belongsTo(Jetstream::teamModel(), 'organization_id');
return $this->belongsTo(Organization::class, 'organization_id');
}
/**
@@ -65,6 +67,6 @@ class OrganizationInvitation extends JetstreamTeamInvitation implements Auditabl
*/
public function team(): BelongsTo
{
return $this->belongsTo(Jetstream::teamModel(), 'organization_id');
return $this->belongsTo(Organization::class, 'organization_id');
}
}

View File

@@ -41,7 +41,10 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
class Project extends Model implements AuditableContract
{
use Auditable;
/** @use HasFactory<ProjectFactory> */
use HasFactory;
use HasUuids;
/**

View File

@@ -32,7 +32,10 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
class ProjectMember extends Model implements AuditableContract
{
use Auditable;
/** @use HasFactory<ProjectMemberFactory> */
use HasFactory;
use HasUuids;
/**

View File

@@ -26,7 +26,10 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
class Tag extends Model implements AuditableContract
{
use Auditable;
/** @use HasFactory<TagFactory> */
use HasFactory;
use HasUuids;
/**

View File

@@ -35,7 +35,10 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
class Task extends Model implements AuditableContract
{
use Auditable;
/** @use HasFactory<TaskFactory> */
use HasFactory;
use HasUuids;
/**

View File

@@ -49,7 +49,10 @@ class TimeEntry extends Model implements AuditableContract
{
use Auditable;
use ComputedAttributes;
/** @use HasFactory<TimeEntryFactory> */
use HasFactory;
use HasUuids;
/**

View File

@@ -59,7 +59,10 @@ class User extends Authenticatable implements AuditableContract, FilamentUser, M
{
use Auditable;
use HasApiTokens;
/** @use HasFactory<UserFactory> */
use HasFactory;
use HasProfilePhoto;
use HasTeams;
use HasUuids;

View File

@@ -97,7 +97,7 @@ class AppServiceProvider extends ServiceProvider
}
$this->app->scoped(PermissionStore::class, function (Application $app): PermissionStore {
return new PermissionStore();
return new PermissionStore;
});
// Extensions

View File

@@ -65,7 +65,7 @@ class FortifyServiceProvider extends ServiceProvider
return Limit::perMinute(5)->by($request->session()->get('login.id'));
});
$this->app->instance(LoginResponse::class, new CustomLoginResponse());
$this->app->instance(TwoFactorLoginResponse::class, new CustomTwoFactorLoginResponse());
$this->app->instance(LoginResponse::class, new CustomLoginResponse);
$this->app->instance(TwoFactorLoginResponse::class, new CustomTwoFactorLoginResponse);
}
}

View File

@@ -30,7 +30,7 @@ class DashboardService
*/
private function lastDays(int $days, CarbonTimeZone $timeZone): Collection
{
$result = new Collection();
$result = new Collection;
$date = Carbon::now($timeZone)->subDays($days);
for ($i = 0; $i < $days; $i++) {
$date->addDay();
@@ -77,7 +77,7 @@ class DashboardService
*/
private function daysOfThisWeek(CarbonTimeZone $timeZone, Weekday $startOfWeek): Collection
{
$result = new Collection();
$result = new Collection;
$date = Carbon::now($timeZone);
$start = $date->startOfWeek($startOfWeek->carbonWeekDay());
for ($i = 0; $i < 7; $i++) {

View File

@@ -145,7 +145,7 @@ class DeletionService
foreach ($members as $member) {
if ($member->role === Role::Owner->value && $member->organization->users()->count() > 1) {
throw new CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers();
throw new CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers;
}
}

View File

@@ -319,7 +319,7 @@ class ExportService
// Create ZIP file
$temporaryDirectoryZip = TemporaryDirectory::make();
$zip = new ZipArchive();
$zip = new ZipArchive;
if ($zip->open($temporaryDirectoryZip->path('export.zip'), ZipArchive::CREATE) !== true) {
throw new Exception('Cannot create ZIP file');
}
@@ -356,7 +356,7 @@ class ExportService
} catch (UnavailableStream|CannotInsertRecord|Exception|LeagueCsvException $exception) {
report($exception);
throw new ExportException();
throw new ExportException;
}
}
}

View File

@@ -98,7 +98,7 @@ class ImportDatabaseHelper
throw new ImportException('Invalid data: '.implode(', ', $validator->errors()->all()));
}
$model = new $this->model();
$model = new $this->model;
foreach ($data as $key => $value) {
$model->{$key} = $value;
}
@@ -240,7 +240,7 @@ class ImportDatabaseHelper
{
if ($this->mapIdentifierToKey === null) {
$select = $this->identifiers;
$select[] = (new $this->model())->getKeyName();
$select[] = (new $this->model)->getKeyName();
$builder = $this->getModelInstance();
if ($this->queryModifier !== null) {

View File

@@ -98,7 +98,7 @@ class ClockifyTimeEntriesImporter extends DefaultImporter
'organization_id' => $this->organization->id,
]);
}
$timeEntry = new TimeEntry();
$timeEntry = new TimeEntry;
$timeEntry->user_id = $userId;
$timeEntry->member_id = $memberId;
$timeEntry->task_id = $taskId;

View File

@@ -118,7 +118,7 @@ abstract class DefaultImporter implements ImporterContract
$project->billable_rate = null;
}
});
$this->projectMemberImportHelper = new ImportDatabaseHelper(ProjectMember::class, ['project_id', 'member_id'], true, function (Builder $builder) {
$this->projectMemberImportHelper = new ImportDatabaseHelper(ProjectMember::class, ['project_id', 'member_id'], true, function (Builder $builder): Builder {
/** @var Builder<ProjectMember> $builder */
return $builder->whereBelongsToOrganization($this->organization);
}, validate: [
@@ -131,7 +131,8 @@ abstract class DefaultImporter implements ImporterContract
$projectMember->billable_rate = null;
}
});
$this->tagImportHelper = new ImportDatabaseHelper(Tag::class, ['name', 'organization_id'], true, function (Builder $builder) {
$this->tagImportHelper = new ImportDatabaseHelper(Tag::class, ['name', 'organization_id'], true, function (Builder $builder): Builder {
/** @var Builder<Tag> $builder */
return $builder->where('organization_id', $this->organization->id);
}, validate: [
'name' => [
@@ -139,7 +140,8 @@ abstract class DefaultImporter implements ImporterContract
'max:255',
],
]);
$this->clientImportHelper = new ImportDatabaseHelper(Client::class, ['name', 'organization_id'], true, function (Builder $builder) {
$this->clientImportHelper = new ImportDatabaseHelper(Client::class, ['name', 'organization_id'], true, function (Builder $builder): Builder {
/** @var Builder<Client> $builder */
return $builder->where('organization_id', $this->organization->id);
}, validate: [
'name' => [
@@ -147,7 +149,8 @@ abstract class DefaultImporter implements ImporterContract
'max:255',
],
]);
$this->taskImportHelper = new ImportDatabaseHelper(Task::class, ['name', 'project_id', 'organization_id'], true, function (Builder $builder) {
$this->taskImportHelper = new ImportDatabaseHelper(Task::class, ['name', 'project_id', 'organization_id'], true, function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->where('organization_id', $this->organization->id);
}, validate: [
'name' => [

View File

@@ -4,6 +4,4 @@ declare(strict_types=1);
namespace App\Service\Import\Importers;
class ImportException extends \Exception
{
}
class ImportException extends \Exception {}

View File

@@ -31,7 +31,7 @@ class SolidtimeImporter extends DefaultImporter
$temporaryDirectoryZip = null;
$temporaryDirectory = null;
try {
$zip = new ZipArchive();
$zip = new ZipArchive;
$temporaryDirectoryZip = TemporaryDirectory::make();
file_put_contents($temporaryDirectoryZip->path('import.zip'), $data);
$res = $zip->open($temporaryDirectoryZip->path('import.zip'), ZipArchive::RDONLY);
@@ -220,7 +220,7 @@ class SolidtimeImporter extends DefaultImporter
if ($timeEntryRow['task_id'] !== '') {
$taskId = $this->taskImportHelper->getKeyByExternalIdentifier($timeEntryRow['task_id']);
}
$timeEntry = new TimeEntry();
$timeEntry = new TimeEntry;
$timeEntry->user_id = $userId;
$timeEntry->member_id = $memberId;
$timeEntry->task_id = $taskId;

View File

@@ -23,7 +23,7 @@ class TogglDataImporter extends DefaultImporter
$temporaryDirectoryZip = null;
$temporaryDirectory = null;
try {
$zip = new ZipArchive();
$zip = new ZipArchive;
$temporaryDirectoryZip = TemporaryDirectory::make();
file_put_contents($temporaryDirectoryZip->path('import.zip'), $data);
$res = $zip->open($temporaryDirectoryZip->path('import.zip'), ZipArchive::RDONLY);

View File

@@ -98,7 +98,7 @@ class TogglTimeEntriesImporter extends DefaultImporter
'organization_id' => $this->organization->id,
]);
}
$timeEntry = new TimeEntry();
$timeEntry = new TimeEntry;
$timeEntry->user_id = $userId;
$timeEntry->member_id = $memberId;
$timeEntry->task_id = $taskId;

View File

@@ -25,12 +25,12 @@ class InvitationService
->whereRelation('user', 'email', '=', $email)
->where('role', '!=', Role::Placeholder->value)
->exists()) {
throw new UserIsAlreadyMemberOfOrganizationApiException();
throw new UserIsAlreadyMemberOfOrganizationApiException;
}
InvitingTeamMember::dispatch($organization, $email, $role->value);
$invitation = new OrganizationInvitation();
$invitation = new OrganizationInvitation;
$invitation->email = $email;
$invitation->role = $role->value;
$invitation->organization()->associate($organization);

View File

@@ -281,7 +281,7 @@ class TimeEntryAggregationService
if ($start->gt($end)) {
throw new \InvalidArgumentException('Start date must be before end date');
}
$slots = new Collection();
$slots = new Collection;
$current = $start->copy()->timezone($timezone);
if ($interval === TimeEntryAggregationTypeInterval::Day) {
$current->startOfDay();

View File

@@ -60,7 +60,7 @@ class UserService
}
// Create a new organization
$organization = new Organization();
$organization = new Organization;
$organization->name = $user->name."'s Organization";
$organization->personal_team = true;
$organization->user_id = $user->id;

View File

@@ -16,7 +16,7 @@
"inertiajs/inertia-laravel": "^1.0",
"korridor/laravel-computed-attributes": "^3.1",
"korridor/laravel-model-validation-rules": "^3.0",
"laravel/framework": "^11.0",
"laravel/framework": "^11.16.0",
"laravel/jetstream": "^5.0",
"laravel/octane": "^2.3",
"laravel/passport": "^12.0",
@@ -29,7 +29,7 @@
"spatie/temporary-directory": "^2.2",
"stechstudio/filament-impersonate": "^3.8",
"tightenco/ziggy": "^2.1.0",
"tpetry/laravel-postgresql-enhanced": "^0.39.0",
"tpetry/laravel-postgresql-enhanced": "^1.0.0",
"wikimedia/composer-merge-plugin": "^2.1.0"
},
"require-dev": {

1837
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -29,14 +29,14 @@ class AuditFactory extends Factory
return User::factory()->create()->id;
},
$morphPrefix.'_type' => function () {
return (new User())->getMorphClass();
return (new User)->getMorphClass();
},
'event' => 'updated',
'auditable_id' => function () {
return User::factory()->create()->getKey();
},
'auditable_type' => function () {
return (new User())->getMorphClass();
return (new User)->getMorphClass();
},
'old_values' => [],
'new_values' => [],

View File

@@ -49,4 +49,11 @@ class OrganizationFactory extends Factory
'user_id' => $owner === null ? User::factory() : $owner->getKey(),
]);
}
public function withFakeId(): self
{
return $this->state(fn (array $attributes) => [
'id' => $this->faker->uuid(),
]);
}
}

View File

@@ -154,15 +154,15 @@ class DatabaseSeeder extends Seeder
private function deleteAll(): void
{
DB::table((new Audit())->getTable())->delete();
DB::table((new TimeEntry())->getTable())->delete();
DB::table((new Task())->getTable())->delete();
DB::table((new Tag())->getTable())->delete();
DB::table((new ProjectMember())->getTable())->delete();
DB::table((new Project())->getTable())->delete();
DB::table((new Client())->getTable())->delete();
DB::table((new User())->getTable())->delete();
DB::table((new OrganizationInvitation())->getTable())->delete();
DB::table((new Organization())->getTable())->delete();
DB::table((new Audit)->getTable())->delete();
DB::table((new TimeEntry)->getTable())->delete();
DB::table((new Task)->getTable())->delete();
DB::table((new Tag)->getTable())->delete();
DB::table((new ProjectMember)->getTable())->delete();
DB::table((new Project)->getTable())->delete();
DB::table((new Client)->getTable())->delete();
DB::table((new User)->getTable())->delete();
DB::table((new OrganizationInvitation)->getTable())->delete();
DB::table((new Organization)->getTable())->delete();
}
}

View File

@@ -6,6 +6,4 @@ namespace Tests\Unit\Endpoint\Api\V1;
use Tests\TestCaseWithDatabase;
class ApiEndpointTestAbstract extends TestCaseWithDatabase
{
}
class ApiEndpointTestAbstract extends TestCaseWithDatabase {}

View File

@@ -43,7 +43,7 @@ class ExportEndpointTest extends ApiEndpointTestAbstract
->withArgs(function (Organization $organization) use (&$user): bool {
return $organization->is($user->organization);
})
->andThrow(new ExportException())
->andThrow(new ExportException)
->once();
});
Passport::actingAs($user->user);

View File

@@ -6,6 +6,4 @@ namespace Tests\Unit\Endpoint\Web;
use Tests\TestCaseWithDatabase;
abstract class EndpointTestAbstract extends TestCaseWithDatabase
{
}
abstract class EndpointTestAbstract extends TestCaseWithDatabase {}

View File

@@ -32,7 +32,7 @@ class AuditResourceTest extends FilamentTestCase
// Arrange
$user = $this->createUserWithPermission();
$timeEntry = TimeEntry::factory()->forMember($user->member)->create();
DB::table((new Audit())->getTable())->delete();
DB::table((new Audit)->getTable())->delete();
$audits = Audit::factory()->auditFor($timeEntry)->auditUser($user->user)->createMany(5);
// Act
@@ -46,7 +46,7 @@ class AuditResourceTest extends FilamentTestCase
public function test_can_see_view_page_of_audit(): void
{
// Arrange
DB::table((new Audit())->getTable())->delete();
DB::table((new Audit)->getTable())->delete();
$audit = Audit::factory()->create();
// Act

View File

@@ -79,7 +79,7 @@ class UserResourceTest extends FilamentTestCase
$this->mock(DeletionService::class, function (MockInterface $mock) use ($user): void {
$mock->shouldReceive('deleteUser')
->withArgs(fn (User $userArg) => $userArg->is($user->user))
->andThrow(new CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers());
->andThrow(new CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers);
});
// Act

View File

@@ -26,6 +26,5 @@ class OrganizationModelTest extends ModelTestAbstract
// Assert
$this->assertNotNull($membersRel);
$this->assertCount(3, $membersRel);
$this->assertTrue($membersRel->first()->is($members->first()));
}
}

View File

@@ -20,7 +20,7 @@ class ColorRuleTest extends TestCase
$validator = Validator::make([
'color' => '#ef5350',
], [
'color' => [new ColorRule()],
'color' => [new ColorRule],
]);
// Act
@@ -38,7 +38,7 @@ class ColorRuleTest extends TestCase
$validator = Validator::make([
'color' => true,
], [
'color' => [new ColorRule()],
'color' => [new ColorRule],
]);
// Act
@@ -56,7 +56,7 @@ class ColorRuleTest extends TestCase
$validator = Validator::make([
'color' => 'rgb(0,0,0)',
], [
'color' => [new ColorRule()],
'color' => [new ColorRule],
]);
// Act

View File

@@ -20,7 +20,7 @@ class CurrencyRuleTest extends TestCase
$validator = Validator::make([
'currency' => 'EUR',
], [
'currency' => [new CurrencyRule()],
'currency' => [new CurrencyRule],
]);
// Act
@@ -38,7 +38,7 @@ class CurrencyRuleTest extends TestCase
$validator = Validator::make([
'currency' => true,
], [
'currency' => [new CurrencyRule()],
'currency' => [new CurrencyRule],
]);
// Act
@@ -56,7 +56,7 @@ class CurrencyRuleTest extends TestCase
$validator = Validator::make([
'currency' => 'XXX',
], [
'currency' => [new CurrencyRule()],
'currency' => [new CurrencyRule],
]);
// Act
@@ -74,7 +74,7 @@ class CurrencyRuleTest extends TestCase
$validator = Validator::make([
'currency' => 'eur',
], [
'currency' => [new CurrencyRule()],
'currency' => [new CurrencyRule],
]);
// Act

View File

@@ -23,7 +23,7 @@ class ClockifyProjectsImporterTest extends ImporterTestAbstract
// Arrange
$organization = Organization::factory()->create();
$timezone = 'Europe/Vienna';
$importer = new ClockifyProjectsImporter();
$importer = new ClockifyProjectsImporter;
$importer->init($organization);
$data = Storage::disk('testfiles')->get('clockify_projects_import_test_1.csv');
@@ -39,11 +39,11 @@ class ClockifyProjectsImporterTest extends ImporterTestAbstract
// Arrange
$organization = Organization::factory()->create();
$timezone = 'Europe/Vienna';
$importer = new ClockifyProjectsImporter();
$importer = new ClockifyProjectsImporter;
$importer->init($organization);
$data = Storage::disk('testfiles')->get('clockify_projects_import_test_1.csv');
$importer->importData($data, $timezone);
$importer = new ClockifyProjectsImporter();
$importer = new ClockifyProjectsImporter;
$importer->init($organization);
// Act

View File

@@ -23,7 +23,7 @@ class ClockifyTimeEntriesImporterTest extends ImporterTestAbstract
// Arrange
$organization = Organization::factory()->create();
$timezone = 'Europe/Vienna';
$importer = new ClockifyTimeEntriesImporter();
$importer = new ClockifyTimeEntriesImporter;
$importer->init($organization);
$data = Storage::disk('testfiles')->get('clockify_time_entries_import_test_1.csv');
@@ -47,11 +47,11 @@ class ClockifyTimeEntriesImporterTest extends ImporterTestAbstract
// Arrange
$organization = Organization::factory()->create();
$timezone = 'Europe/Vienna';
$importer = new ClockifyTimeEntriesImporter();
$importer = new ClockifyTimeEntriesImporter;
$importer->init($organization);
$data = Storage::disk('testfiles')->get('clockify_time_entries_import_test_1.csv');
$importer->importData($data, $timezone);
$importer = new ClockifyTimeEntriesImporter();
$importer = new ClockifyTimeEntriesImporter;
$importer->init($organization);
// Act

View File

@@ -17,7 +17,7 @@ class ImporterProviderTest extends TestCase
public function test_register_importer_can_register_a_new_importer_for_example_in_an_extension(): void
{
// Arrange
$provider = new ImporterProvider();
$provider = new ImporterProvider;
// Act
$provider->registerImporter('some_provider_importer', ClockifyProjectsImporter::class);
@@ -30,7 +30,7 @@ class ImporterProviderTest extends TestCase
public function test_get_importer_keys_return_the_keys_of_the_available_importers(): void
{
// Arrange
$provider = new ImporterProvider();
$provider = new ImporterProvider;
// Act
$keys = $provider->getImporterKeys();

View File

@@ -204,7 +204,7 @@ class ImporterTestAbstract extends TestCase
{
$tempDir = TemporaryDirectory::make();
$zipPath = $tempDir->path('test.zip');
$zip = new ZipArchive();
$zip = new ZipArchive;
$zip->open($zipPath, ZipArchive::CREATE);
foreach (Storage::disk('testfiles')->allFiles($folder) as $file) {
$zip->addFile(Storage::disk('testfiles')->path($file), Str::of($file)->after($folder.'/')->value());

View File

@@ -23,7 +23,7 @@ class SolidtimeImporterTest extends ImporterTestAbstract
// Arrange
$organization = Organization::factory()->create();
$timezone = 'Europe/Vienna';
$importer = new SolidtimeImporter();
$importer = new SolidtimeImporter;
$importer->init($organization);
// Act
@@ -44,7 +44,7 @@ class SolidtimeImporterTest extends ImporterTestAbstract
$zipPath = $this->createTestZip('solidtime_import_test_1');
$timezone = 'Europe/Vienna';
$organization = Organization::factory()->create();
$importer = new SolidtimeImporter();
$importer = new SolidtimeImporter;
$importer->init($organization);
$data = file_get_contents($zipPath);
@@ -69,11 +69,11 @@ class SolidtimeImporterTest extends ImporterTestAbstract
$zipPath = $this->createTestZip('solidtime_import_test_1');
$timezone = 'Europe/Vienna';
$organization = Organization::factory()->create();
$importer = new SolidtimeImporter();
$importer = new SolidtimeImporter;
$importer->init($organization);
$data = file_get_contents($zipPath);
$importer->importData($data, $timezone);
$importer = new SolidtimeImporter();
$importer = new SolidtimeImporter;
$importer->init($organization);
// Act

View File

@@ -23,7 +23,7 @@ class TogglDataImporterTest extends ImporterTestAbstract
// Arrange
$organization = Organization::factory()->create();
$timezone = 'Europe/Vienna';
$importer = new TogglDataImporter();
$importer = new TogglDataImporter;
$importer->init($organization);
// Act
@@ -44,7 +44,7 @@ class TogglDataImporterTest extends ImporterTestAbstract
$zipPath = $this->createTestZip('toggl_data_import_test_1');
$timezone = 'Europe/Vienna';
$organization = Organization::factory()->create();
$importer = new TogglDataImporter();
$importer = new TogglDataImporter;
$importer->init($organization);
$data = file_get_contents($zipPath);
@@ -68,11 +68,11 @@ class TogglDataImporterTest extends ImporterTestAbstract
$zipPath = $this->createTestZip('toggl_data_import_test_1');
$timezone = 'Europe/Vienna';
$organization = Organization::factory()->create();
$importer = new TogglDataImporter();
$importer = new TogglDataImporter;
$importer->init($organization);
$data = file_get_contents($zipPath);
$importer->importData($data, $timezone);
$importer = new TogglDataImporter();
$importer = new TogglDataImporter;
$importer->init($organization);
// Act

View File

@@ -24,7 +24,7 @@ class TogglTimeEntriesImporterTest extends ImporterTestAbstract
// Arrange
$organization = Organization::factory()->create();
$timezone = 'Europe/Vienna';
$importer = new TogglTimeEntriesImporter();
$importer = new TogglTimeEntriesImporter;
$importer->init($organization);
$data = Storage::disk('testfiles')->get('toggl_time_entries_import_test_1.csv');
@@ -52,11 +52,11 @@ class TogglTimeEntriesImporterTest extends ImporterTestAbstract
// Arrange
$organization = Organization::factory()->create();
$timezone = 'Europe/Vienna';
$importer = new TogglTimeEntriesImporter();
$importer = new TogglTimeEntriesImporter;
$importer->init($organization);
$data = Storage::disk('testfiles')->get('toggl_time_entries_import_test_1.csv');
$importer->importData($data, $timezone);
$importer = new TogglTimeEntriesImporter();
$importer = new TogglTimeEntriesImporter;
$importer->init($organization);
// Act

View File

@@ -26,7 +26,7 @@ class PermissionStoreTest extends TestCase
$organization = Organization::factory()->create();
$user = User::factory()->create();
$organization->users()->attach($user, ['role' => Role::Employee->value]);
$permissionStore = new PermissionStore();
$permissionStore = new PermissionStore;
// Act
$result = $permissionStore->has($organization, 'permission');
@@ -40,7 +40,7 @@ class PermissionStoreTest extends TestCase
// Arrange
$organization = Organization::factory()->create();
$user = User::factory()->create();
$permissionStore = new PermissionStore();
$permissionStore = new PermissionStore;
$this->actingAs($user);
// Act
@@ -56,7 +56,7 @@ class PermissionStoreTest extends TestCase
$organization = Organization::factory()->create();
$user = User::factory()->create();
$organization->users()->attach($user, ['role' => Role::Employee->value]);
$permissionStore = new PermissionStore();
$permissionStore = new PermissionStore;
$this->actingAs($user);
// Act
@@ -72,7 +72,7 @@ class PermissionStoreTest extends TestCase
$organization = Organization::factory()->create();
$user = User::factory()->create();
$organization->users()->attach($user, ['role' => Role::Employee->value]);
$permissionStore = new PermissionStore();
$permissionStore = new PermissionStore;
$this->actingAs($user);
// Act
@@ -88,7 +88,7 @@ class PermissionStoreTest extends TestCase
$organization = Organization::factory()->create();
$user = User::factory()->create();
$organization->users()->attach($user, ['role' => Role::Employee->value]);
$permissionStore = new PermissionStore();
$permissionStore = new PermissionStore;
// Act
$result = $permissionStore->getPermissions($organization);
@@ -101,7 +101,7 @@ class PermissionStoreTest extends TestCase
{
$organization = Organization::factory()->create();
$user = User::factory()->create();
$permissionStore = new PermissionStore();
$permissionStore = new PermissionStore;
$this->actingAs($user);
// Act
@@ -117,7 +117,7 @@ class PermissionStoreTest extends TestCase
$organization = Organization::factory()->create();
$user = User::factory()->create();
$organization->users()->attach($user, ['role' => Role::Employee->value]);
$permissionStore = new PermissionStore();
$permissionStore = new PermissionStore;
$this->actingAs($user);
// Act