mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-06-15 05:22:44 +01:00
Compare commits
2 Commits
c2a8eac65f
...
5b756be058
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b756be058 | ||
|
|
dc70eb7130 |
@@ -50,7 +50,7 @@ class FailedJobResource extends Resource
|
||||
TextInput::make('queue')->disabled(),
|
||||
|
||||
// make text a little bit smaller because often a complete Stack Trace is shown:
|
||||
TextArea::make('exception')->disabled()->columnSpan(4)->extraInputAttributes(['style' => 'font-size: 80%;']),
|
||||
Textarea::make('exception')->disabled()->columnSpan(4)->extraInputAttributes(['style' => 'font-size: 80%;']),
|
||||
PrettyJsonField::make('payload')->disabled()->columnSpan(4),
|
||||
])->columns(4);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class OrganizationInvitationResource extends Resource
|
||||
->required(),
|
||||
Select::make('role')
|
||||
->options(Role::class),
|
||||
Forms\Components\Select::make('organization_id')
|
||||
Select::make('organization_id')
|
||||
->label('Organization')
|
||||
->relationship(name: 'organization', titleAttribute: 'name')
|
||||
->searchable(['name'])
|
||||
|
||||
@@ -55,7 +55,7 @@ class OrganizationResource extends Resource
|
||||
->label('Is personal?')
|
||||
->hiddenOn(['create'])
|
||||
->required(),
|
||||
Forms\Components\Select::make('user_id')
|
||||
Select::make('user_id')
|
||||
->label('Owner')
|
||||
->relationship(name: 'owner', titleAttribute: 'email')
|
||||
->searchable(['name', 'email'])
|
||||
@@ -76,7 +76,7 @@ class OrganizationResource extends Resource
|
||||
Select::make('time_format')
|
||||
->options(TimeFormat::toSelectArray())
|
||||
->required(),
|
||||
Forms\Components\Select::make('currency')
|
||||
Select::make('currency')
|
||||
->label('Currency')
|
||||
->options(function (): array {
|
||||
$currencies = ISOCurrencyProvider::getInstance()->getAvailableCurrencies();
|
||||
@@ -114,22 +114,22 @@ class OrganizationResource extends Resource
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
TextColumn::make('name')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
Tables\Columns\IconColumn::make('personal_team')
|
||||
->boolean()
|
||||
->label('Is personal?')
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('owner.email')
|
||||
TextColumn::make('owner.email')
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('currency'),
|
||||
TextColumn::make('currency'),
|
||||
TextColumn::make('billable_rate')
|
||||
->money(fn (Organization $resource) => $resource->currency, divideBy: 100),
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('updated_at')
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
@@ -223,7 +223,7 @@ class OrganizationResource extends Resource
|
||||
|
||||
return $select;
|
||||
}),
|
||||
Forms\Components\Select::make('timezone')
|
||||
Select::make('timezone')
|
||||
->label('Timezone')
|
||||
->options(fn (): array => app(TimezoneService::class)->getSelectOptions())
|
||||
->searchable()
|
||||
|
||||
@@ -49,13 +49,13 @@ class UsersRelationManager extends RelationManager
|
||||
return $table
|
||||
->recordTitleAttribute('name')
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name'),
|
||||
Tables\Columns\TextColumn::make('role'),
|
||||
TextColumn::make('name'),
|
||||
TextColumn::make('role'),
|
||||
TextColumn::make('billable_rate')
|
||||
->money($organization->currency, divideBy: 100),
|
||||
])
|
||||
->headerActions([
|
||||
Tables\Actions\AttachAction::make()
|
||||
AttachAction::make()
|
||||
->recordTitle(fn (User $record): string => "{$record->name} ({$record->email})")
|
||||
->form(fn (AttachAction $action): array => [
|
||||
$action->getRecordSelect(),
|
||||
|
||||
@@ -63,11 +63,11 @@ class ReportResource extends Resource
|
||||
return $record->getRawOriginal('properties');
|
||||
})
|
||||
->disabled(),
|
||||
Forms\Components\DateTimePicker::make('created_at')
|
||||
DateTimePicker::make('created_at')
|
||||
->label('Created At')
|
||||
->hiddenOn(['create'])
|
||||
->disabled(),
|
||||
Forms\Components\DateTimePicker::make('updated_at')
|
||||
DateTimePicker::make('updated_at')
|
||||
->label('Updated At')
|
||||
->hiddenOn(['create'])
|
||||
->disabled(),
|
||||
@@ -78,10 +78,10 @@ class ReportResource extends Resource
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
TextColumn::make('name')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('description')
|
||||
TextColumn::make('description')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
ToggleColumn::make('is_public')
|
||||
@@ -90,10 +90,10 @@ class ReportResource extends Resource
|
||||
TextColumn::make('organization.name')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
TextColumn::make('created_at')
|
||||
->dateTime()
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('updated_at')
|
||||
TextColumn::make('updated_at')
|
||||
->dateTime()
|
||||
->sortable()
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
|
||||
@@ -93,11 +93,11 @@ class TimeEntryResource extends Resource
|
||||
($record->end?->toDateTimeString('minute') ?? '...').')';
|
||||
})
|
||||
->label('Time'),
|
||||
Tables\Columns\TextColumn::make('organization.name')
|
||||
TextColumn::make('organization.name')
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('created_at')
|
||||
TextColumn::make('created_at')
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('updated_at')
|
||||
TextColumn::make('updated_at')
|
||||
->sortable(),
|
||||
])
|
||||
->filters([
|
||||
|
||||
@@ -47,17 +47,17 @@ class UserResource extends Resource
|
||||
return $form
|
||||
->columns(1)
|
||||
->schema([
|
||||
Forms\Components\TextInput::make('id')
|
||||
TextInput::make('id')
|
||||
->label('ID')
|
||||
->disabled()
|
||||
->visibleOn(['update', 'show'])
|
||||
->readOnly()
|
||||
->maxLength(255),
|
||||
Forms\Components\TextInput::make('name')
|
||||
TextInput::make('name')
|
||||
->label('Name')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Forms\Components\TextInput::make('email')
|
||||
TextInput::make('email')
|
||||
->label('Email')
|
||||
->required()
|
||||
->rules($record?->is_placeholder ? [] : [
|
||||
|
||||
@@ -59,7 +59,7 @@ use Spatie\TemporaryDirectory\TemporaryDirectory;
|
||||
|
||||
class TimeEntryController extends Controller
|
||||
{
|
||||
private function assertNoOverlap(Organization $organization, Member $member, \Illuminate\Support\Carbon $start, ?\Illuminate\Support\Carbon $end, ?TimeEntry $exclude = null): void
|
||||
private function assertNoOverlap(Organization $organization, Member $member, Carbon $start, ?Carbon $end, ?TimeEntry $exclude = null): void
|
||||
{
|
||||
if (! $organization->prevent_overlapping_time_entries) {
|
||||
return;
|
||||
|
||||
@@ -4,9 +4,37 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\Authenticate;
|
||||
use App\Http\Middleware\CheckOrganizationBlocked;
|
||||
use App\Http\Middleware\EncryptCookies;
|
||||
use App\Http\Middleware\EnsureEmailIsVerified;
|
||||
use App\Http\Middleware\ForceHttps;
|
||||
use App\Http\Middleware\ForceJsonResponse;
|
||||
use App\Http\Middleware\HandleInertiaRequests;
|
||||
use App\Http\Middleware\PreventRequestsDuringMaintenance;
|
||||
use App\Http\Middleware\RedirectIfAuthenticated;
|
||||
use App\Http\Middleware\ShareInertiaData;
|
||||
use App\Http\Middleware\TrimStrings;
|
||||
use App\Http\Middleware\TrustProxies;
|
||||
use App\Http\Middleware\ValidateSignature;
|
||||
use App\Http\Middleware\VerifyCsrfToken;
|
||||
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
|
||||
use Illuminate\Auth\Middleware\Authorize;
|
||||
use Illuminate\Auth\Middleware\RequirePassword;
|
||||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
|
||||
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
|
||||
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
|
||||
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
|
||||
use Illuminate\Http\Middleware\HandleCors;
|
||||
use Illuminate\Http\Middleware\SetCacheHeaders;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Session\Middleware\AuthenticateSession;
|
||||
use Illuminate\Session\Middleware\StartSession;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
use Laravel\Passport\Http\Middleware\CreateFreshApiToken;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
@@ -18,13 +46,13 @@ class Kernel extends HttpKernel
|
||||
* @var array<int, class-string|string>
|
||||
*/
|
||||
protected $middleware = [
|
||||
\App\Http\Middleware\ForceHttps::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
ForceHttps::class,
|
||||
TrustProxies::class,
|
||||
HandleCors::class,
|
||||
PreventRequestsDuringMaintenance::class,
|
||||
ValidatePostSize::class,
|
||||
TrimStrings::class,
|
||||
ConvertEmptyStringsToNull::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -34,21 +62,21 @@ class Kernel extends HttpKernel
|
||||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\HandleInertiaRequests::class,
|
||||
\App\Http\Middleware\ShareInertiaData::class,
|
||||
\Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets::class,
|
||||
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
|
||||
EncryptCookies::class,
|
||||
AddQueuedCookiesToResponse::class,
|
||||
StartSession::class,
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
SubstituteBindings::class,
|
||||
HandleInertiaRequests::class,
|
||||
ShareInertiaData::class,
|
||||
AddLinkHeadersForPreloadedAssets::class,
|
||||
CreateFreshApiToken::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
ThrottleRequests::class.':api',
|
||||
SubstituteBindings::class,
|
||||
ForceJsonResponse::class,
|
||||
],
|
||||
|
||||
@@ -64,17 +92,17 @@ class Kernel extends HttpKernel
|
||||
* @var array<string, class-string|string>
|
||||
*/
|
||||
protected $middlewareAliases = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
|
||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \App\Http\Middleware\EnsureEmailIsVerified::class,
|
||||
'auth' => Authenticate::class,
|
||||
'auth.basic' => AuthenticateWithBasicAuth::class,
|
||||
'auth.session' => AuthenticateSession::class,
|
||||
'cache.headers' => SetCacheHeaders::class,
|
||||
'can' => Authorize::class,
|
||||
'guest' => RedirectIfAuthenticated::class,
|
||||
'password.confirm' => RequirePassword::class,
|
||||
'precognitive' => HandlePrecognitiveRequests::class,
|
||||
'signed' => ValidateSignature::class,
|
||||
'throttle' => ThrottleRequests::class,
|
||||
'verified' => EnsureEmailIsVerified::class,
|
||||
'check-organization-blocked' => CheckOrganizationBlocked::class,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class ForceHttps
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string ...$guards): Response
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ class ForceJsonResponse
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string ...$guards): Response
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ class RedirectIfAuthenticated
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string ...$guards): Response
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace App\Http\Requests\V1\Member;
|
||||
use App\Http\Requests\V1\BaseFormRequest;
|
||||
use App\Models\Member;
|
||||
use App\Models\Organization;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||
@@ -19,7 +20,7 @@ class MemberMergeIntoRequest extends BaseFormRequest
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, array<string|ValidationRule|\Illuminate\Contracts\Validation\Rule>>
|
||||
* @return array<string, array<string|ValidationRule|Rule>>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace App\Http\Requests\V1\Organization;
|
||||
|
||||
use App\Http\Requests\V1\BaseFormRequest;
|
||||
use App\Models\Organization;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
/**
|
||||
* @property Organization $organization Organization from model binding
|
||||
@@ -15,7 +16,7 @@ class OrganizationStoreRequest extends BaseFormRequest
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, array<string|\Illuminate\Contracts\Validation\Rule>>
|
||||
* @return array<string, array<string|Rule>>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@ use Illuminate\Support\Str;
|
||||
use Laravel\Jetstream\Events\TeamCreated;
|
||||
use Laravel\Jetstream\Events\TeamDeleted;
|
||||
use Laravel\Jetstream\Events\TeamUpdated;
|
||||
use Laravel\Jetstream\Team;
|
||||
use Laravel\Jetstream\Team as JetstreamTeam;
|
||||
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
|
||||
|
||||
@@ -177,7 +178,7 @@ class Organization extends JetstreamTeam implements AuditableContract
|
||||
*
|
||||
* @param array<string> $columns
|
||||
*/
|
||||
public function findOrFail(string $id, array $columns = ['*']): \Laravel\Jetstream\Team
|
||||
public function findOrFail(string $id, array $columns = ['*']): Team
|
||||
{
|
||||
if (! Str::isUuid($id)) {
|
||||
throw (new ModelNotFoundException)->setModel(
|
||||
|
||||
@@ -10,6 +10,9 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\File;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use League\Csv\CannotInsertRecord;
|
||||
use League\Csv\Exception;
|
||||
use League\Csv\UnavailableStream;
|
||||
use League\Csv\Writer;
|
||||
use Spatie\TemporaryDirectory\TemporaryDirectory;
|
||||
|
||||
@@ -58,9 +61,9 @@ abstract class CsvExport
|
||||
abstract public function mapRow(Model $model): array;
|
||||
|
||||
/**
|
||||
* @throws \League\Csv\CannotInsertRecord
|
||||
* @throws \League\Csv\Exception
|
||||
* @throws \League\Csv\UnavailableStream
|
||||
* @throws CannotInsertRecord
|
||||
* @throws Exception
|
||||
* @throws UnavailableStream
|
||||
*/
|
||||
public function export(): void
|
||||
{
|
||||
@@ -72,6 +75,7 @@ abstract class CsvExport
|
||||
$writer->insertOne(static::HEADER);
|
||||
|
||||
$this->builder->chunk($this->chunk, function (Collection $models) use ($writer): void {
|
||||
/** @var T $model */
|
||||
foreach ($models as $model) {
|
||||
$data = $this->mapRow($model);
|
||||
$row = $this->convertRow($data);
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
use App\Exceptions\Handler;
|
||||
use App\Http\Kernel;
|
||||
use Illuminate\Contracts\Debug\ExceptionHandler;
|
||||
use Illuminate\Foundation\Application;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -13,7 +17,7 @@ declare(strict_types=1);
|
||||
|
|
||||
*/
|
||||
|
||||
$app = new Illuminate\Foundation\Application(
|
||||
$app = new Application(
|
||||
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
|
||||
);
|
||||
|
||||
@@ -30,7 +34,7 @@ $app = new Illuminate\Foundation\Application(
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Http\Kernel::class,
|
||||
App\Http\Kernel::class
|
||||
Kernel::class
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
@@ -39,8 +43,8 @@ $app->singleton(
|
||||
);
|
||||
|
||||
$app->singleton(
|
||||
Illuminate\Contracts\Debug\ExceptionHandler::class,
|
||||
App\Exceptions\Handler::class
|
||||
ExceptionHandler::class,
|
||||
Handler::class
|
||||
);
|
||||
|
||||
/*
|
||||
|
||||
3383
composer.lock
generated
3383
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,13 @@ use App\Enums\DateFormat;
|
||||
use App\Enums\IntervalFormat;
|
||||
use App\Enums\NumberFormat;
|
||||
use App\Enums\TimeFormat;
|
||||
use App\Providers\AppServiceProvider;
|
||||
use App\Providers\AuthServiceProvider;
|
||||
use App\Providers\EventServiceProvider;
|
||||
use App\Providers\Filament\AdminPanelProvider;
|
||||
use App\Providers\FortifyServiceProvider;
|
||||
use App\Providers\JetstreamServiceProvider;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Nwidart\Modules\LaravelModulesServiceProvider;
|
||||
@@ -190,13 +197,13 @@ return [
|
||||
/*
|
||||
* Application Service Providers...
|
||||
*/
|
||||
App\Providers\AppServiceProvider::class,
|
||||
App\Providers\AuthServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\Filament\AdminPanelProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
App\Providers\FortifyServiceProvider::class,
|
||||
App\Providers\JetstreamServiceProvider::class,
|
||||
AppServiceProvider::class,
|
||||
AuthServiceProvider::class,
|
||||
EventServiceProvider::class,
|
||||
AdminPanelProvider::class,
|
||||
RouteServiceProvider::class,
|
||||
FortifyServiceProvider::class,
|
||||
JetstreamServiceProvider::class,
|
||||
// Warning: Do not add TelescopeServiceProvider here since it is already conditionally registered in AppServiceProvider
|
||||
LaravelModulesServiceProvider::class,
|
||||
])->toArray(),
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
use App\Extensions\Auditing\Resolvers\CustomIpAddressResolver;
|
||||
use OwenIt\Auditing\Models\Audit;
|
||||
use OwenIt\Auditing\Resolvers\UrlResolver;
|
||||
use OwenIt\Auditing\Resolvers\UserAgentResolver;
|
||||
use OwenIt\Auditing\Resolvers\UserResolver;
|
||||
|
||||
return [
|
||||
|
||||
@@ -15,7 +20,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'implementation' => OwenIt\Auditing\Models\Audit::class,
|
||||
'implementation' => Audit::class,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -32,7 +37,7 @@ return [
|
||||
'web',
|
||||
'api',
|
||||
],
|
||||
'resolver' => OwenIt\Auditing\Resolvers\UserResolver::class,
|
||||
'resolver' => UserResolver::class,
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -44,9 +49,9 @@ return [
|
||||
|
|
||||
*/
|
||||
'resolvers' => [
|
||||
'ip_address' => App\Extensions\Auditing\Resolvers\CustomIpAddressResolver::class,
|
||||
'user_agent' => OwenIt\Auditing\Resolvers\UserAgentResolver::class,
|
||||
'url' => OwenIt\Auditing\Resolvers\UrlResolver::class,
|
||||
'ip_address' => CustomIpAddressResolver::class,
|
||||
'user_agent' => UserAgentResolver::class,
|
||||
'url' => UrlResolver::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
use App\Models\User;
|
||||
|
||||
return [
|
||||
|
||||
@@ -69,7 +70,7 @@ return [
|
||||
'providers' => [
|
||||
'users' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => App\Models\User::class,
|
||||
'model' => User::class,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Maatwebsite\Excel\DefaultValueBinder;
|
||||
use Maatwebsite\Excel\Excel;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Csv;
|
||||
|
||||
@@ -226,7 +227,7 @@ return [
|
||||
|
|
||||
*/
|
||||
'value_binder' => [
|
||||
'default' => Maatwebsite\Excel\DefaultValueBinder::class,
|
||||
'default' => DefaultValueBinder::class,
|
||||
],
|
||||
|
||||
'cache' => [
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Enums\Weekday;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Http\FileHelpers;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
@@ -90,7 +91,7 @@ class UserFactory extends Factory
|
||||
public function withProfilePicture(): static
|
||||
{
|
||||
$profilePhoto = $this->faker->image(null, 500, 500);
|
||||
/** @see \Illuminate\Http\FileHelpers::hashName */
|
||||
/** @see FileHelpers::hashName */
|
||||
$path = 'profile-photos/'.Str::random(40).'.png';
|
||||
Storage::disk(config('jetstream.profile_photo_disk', 'public'))->put($path, $profilePhoto);
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ return new class extends Migration
|
||||
if ($duplicateEmails->isNotEmpty()) {
|
||||
$duplicateEmailMessage = $duplicateEmails
|
||||
->take(20)
|
||||
->map(fn (\stdClass $duplicateEmail): string => sprintf(
|
||||
->map(fn (stdClass $duplicateEmail): string => sprintf(
|
||||
'%s (%d users: %s)',
|
||||
$duplicateEmail->normalized_email,
|
||||
$duplicateEmail->user_count,
|
||||
|
||||
@@ -14,5 +14,4 @@ parameters:
|
||||
noEnvCallsOutsideOfConfig: true
|
||||
|
||||
ignoreErrors:
|
||||
- '# is not subtype of native type Illuminate\\Database\\Eloquent\\Builder#'
|
||||
- '# is not subtype of native type Illuminate\\Database\\Eloquent\\Relations\\Relation#'
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Endpoint\Api\V1;
|
||||
|
||||
use App\Enums\Role;
|
||||
use App\Http\Controllers\Api\V1\TaskController;
|
||||
use App\Models\Project;
|
||||
use App\Models\ProjectMember;
|
||||
@@ -755,7 +756,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_store_endpoint_allows_employee_to_create_task_in_public_project_when_employees_can_manage_tasks_is_enabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = true;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPublic()->create();
|
||||
@@ -779,7 +780,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_store_endpoint_allows_employee_to_create_task_in_accessible_private_project_when_employees_can_manage_tasks_is_enabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = true;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPrivate()->create();
|
||||
@@ -804,7 +805,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_store_endpoint_fails_for_employee_creating_task_in_inaccessible_private_project_when_employees_can_manage_tasks_is_enabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = true;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPrivate()->create();
|
||||
@@ -827,7 +828,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_store_endpoint_fails_for_employee_when_employees_can_manage_tasks_is_disabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = false;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPublic()->create();
|
||||
@@ -849,7 +850,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_update_endpoint_allows_employee_to_update_task_in_public_project_when_employees_can_manage_tasks_is_enabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = true;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPublic()->create();
|
||||
@@ -872,7 +873,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_update_endpoint_allows_employee_to_update_task_in_accessible_private_project_when_employees_can_manage_tasks_is_enabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = true;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPrivate()->create();
|
||||
@@ -896,7 +897,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_update_endpoint_fails_for_employee_updating_task_in_inaccessible_private_project_when_employees_can_manage_tasks_is_enabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = true;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPrivate()->create();
|
||||
@@ -920,7 +921,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_update_endpoint_fails_for_employee_when_employees_can_manage_tasks_is_disabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = false;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPublic()->create();
|
||||
@@ -944,7 +945,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_delete_endpoint_allows_employee_to_delete_task_in_public_project_when_employees_can_manage_tasks_is_enabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = true;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPublic()->create();
|
||||
@@ -964,7 +965,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_delete_endpoint_allows_employee_to_delete_task_in_accessible_private_project_when_employees_can_manage_tasks_is_enabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = true;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPrivate()->create();
|
||||
@@ -985,7 +986,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_delete_endpoint_fails_for_employee_deleting_task_in_inaccessible_private_project_when_employees_can_manage_tasks_is_enabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = true;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPrivate()->create();
|
||||
@@ -1005,7 +1006,7 @@ class TaskEndpointTest extends ApiEndpointTestAbstract
|
||||
public function test_delete_endpoint_fails_for_employee_when_employees_can_manage_tasks_is_disabled(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithRole(\App\Enums\Role::Employee);
|
||||
$data = $this->createUserWithRole(Role::Employee);
|
||||
$data->organization->employees_can_manage_tasks = false;
|
||||
$data->organization->save();
|
||||
$project = Project::factory()->forOrganization($data->organization)->isPublic()->create();
|
||||
|
||||
@@ -240,6 +240,22 @@ class UserEndpointTest extends ApiEndpointTestAbstract
|
||||
$response->assertJsonValidationErrors(['name']);
|
||||
}
|
||||
|
||||
public function test_update_fails_if_given_user_is_not_the_authenticated_user(): void
|
||||
{
|
||||
// Arrange
|
||||
$data = $this->createUserWithPermission();
|
||||
$otherData = $this->createUserWithPermission();
|
||||
Passport::actingAs($otherData->user);
|
||||
|
||||
// Act
|
||||
$response = $this->putJson(route('api.v1.users.update', $data->user->getKey()), [
|
||||
'name' => 'Updated Name',
|
||||
]);
|
||||
|
||||
// Assert
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_update_fails_if_name_is_too_long(): void
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -251,4 +251,27 @@ class OrganizationInvitationEndpointTest extends EndpointTestAbstract
|
||||
// Assert
|
||||
$response->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_fails_if_invitation_has_owner_role(): void
|
||||
{
|
||||
// Arrange
|
||||
$user = $this->createUserWithPermission();
|
||||
$invitation = OrganizationInvitation::factory()
|
||||
->forOrganization($user->organization)
|
||||
->create([
|
||||
'role' => Role::Owner->value,
|
||||
]);
|
||||
|
||||
// Act
|
||||
$acceptUrl = URL::to(URL::temporarySignedRoute(
|
||||
'organization-invitations.accept',
|
||||
now()->addMinutes(60),
|
||||
[$invitation->getKey()],
|
||||
false
|
||||
));
|
||||
$response = $this->get($acceptUrl);
|
||||
|
||||
// Assert
|
||||
$response->assertStatus(500);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user