mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-08 16:22:16 +01:00
Compare commits
2 Commits
feature/de
...
feature/ch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9070f6cd7e | ||
|
|
919399e828 |
24
.github/workflows/build-private.yml
vendored
24
.github/workflows/build-private.yml
vendored
@@ -10,8 +10,6 @@ on:
|
|||||||
- '.github/workflows/build-private.yml'
|
- '.github/workflows/build-private.yml'
|
||||||
- 'docker/prod/**'
|
- 'docker/prod/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
name: Build - Private
|
name: Build - Private
|
||||||
jobs:
|
jobs:
|
||||||
@@ -19,7 +17,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "Check out code"
|
- name: "Check out code"
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -110,24 +107,6 @@ jobs:
|
|||||||
- name: "Install npm dependencies in services extension"
|
- name: "Install npm dependencies in services extension"
|
||||||
run: cd extensions/Services && npm ci
|
run: cd extensions/Services && npm ci
|
||||||
|
|
||||||
- name: "Checkout invoicing extension"
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: solidtime-io/extension-invoicing
|
|
||||||
path: extensions/Invoicing
|
|
||||||
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_INVOICING_EXTENSION }}
|
|
||||||
|
|
||||||
- name: "Install composer dependencies in invoicing extension"
|
|
||||||
uses: php-actions/composer@v6
|
|
||||||
with:
|
|
||||||
working_dir: "extensions/Invoicing"
|
|
||||||
command: install
|
|
||||||
only_args: --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
|
|
||||||
php_version: 8.3
|
|
||||||
|
|
||||||
- name: "Install npm dependencies in invoicing extension"
|
|
||||||
run: cd extensions/Invoicing && npm ci
|
|
||||||
|
|
||||||
- name: "Setup PHP with PECL extension"
|
- name: "Setup PHP with PECL extension"
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
@@ -148,9 +127,6 @@ jobs:
|
|||||||
- name: "Activate services extension"
|
- name: "Activate services extension"
|
||||||
run: php artisan module:enable Services
|
run: php artisan module:enable Services
|
||||||
|
|
||||||
- name: "Activate invoicing extension"
|
|
||||||
run: php artisan module:enable Invoicing
|
|
||||||
|
|
||||||
- name: "Install npm dependencies"
|
- name: "Install npm dependencies"
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
|||||||
16
.github/workflows/build-public.yml
vendored
16
.github/workflows/build-public.yml
vendored
@@ -11,12 +11,6 @@ on:
|
|||||||
- 'docker/prod/**'
|
- 'docker/prod/**'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
|
||||||
packages: write
|
|
||||||
contents: read
|
|
||||||
attestations: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DOCKERHUB_REPO: solidtime/solidtime
|
DOCKERHUB_REPO: solidtime/solidtime
|
||||||
GHCR_REPO: ghcr.io/solidtime-io/solidtime
|
GHCR_REPO: ghcr.io/solidtime-io/solidtime
|
||||||
@@ -32,6 +26,11 @@ jobs:
|
|||||||
- runs-on: "ubuntu-24.04"
|
- runs-on: "ubuntu-24.04"
|
||||||
platform: "linux/amd64"
|
platform: "linux/amd64"
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
timeout-minutes: 90
|
timeout-minutes: 90
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -164,6 +163,11 @@ jobs:
|
|||||||
|
|
||||||
merge:
|
merge:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
timeout-minutes: 90
|
timeout-minutes: 90
|
||||||
needs:
|
needs:
|
||||||
- build
|
- build
|
||||||
|
|||||||
3
.github/workflows/generate-api-docs.yml
vendored
3
.github/workflows/generate-api-docs.yml
vendored
@@ -3,9 +3,6 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
api_docs:
|
api_docs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
2
.github/workflows/npm-build.yml
vendored
2
.github/workflows/npm-build.yml
vendored
@@ -1,8 +1,6 @@
|
|||||||
name: NPM Build
|
name: NPM Build
|
||||||
|
|
||||||
on: [push]
|
on: [push]
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
2
.github/workflows/npm-lint.yml
vendored
2
.github/workflows/npm-lint.yml
vendored
@@ -1,8 +1,6 @@
|
|||||||
name: NPM Lint
|
name: NPM Lint
|
||||||
|
|
||||||
on: [push]
|
on: [push]
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
2
.github/workflows/npm-publish-api.yml
vendored
2
.github/workflows/npm-publish-api.yml
vendored
@@ -1,8 +1,6 @@
|
|||||||
name: Publish API package to NPM
|
name: Publish API package to NPM
|
||||||
on:
|
on:
|
||||||
workflow_dispatch
|
workflow_dispatch
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
2
.github/workflows/npm-publish-ui.yml
vendored
2
.github/workflows/npm-publish-ui.yml
vendored
@@ -1,8 +1,6 @@
|
|||||||
name: Publish UI package to NPM
|
name: Publish UI package to NPM
|
||||||
on:
|
on:
|
||||||
workflow_dispatch
|
workflow_dispatch
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
3
.github/workflows/npm-typecheck.yml
vendored
3
.github/workflows/npm-typecheck.yml
vendored
@@ -1,8 +1,7 @@
|
|||||||
name: NPM Typecheck
|
name: NPM Typecheck
|
||||||
|
|
||||||
on: [push]
|
on: [push]
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
2
.github/workflows/phpstan.yml
vendored
2
.github/workflows/phpstan.yml
vendored
@@ -1,7 +1,5 @@
|
|||||||
name: Static code analysis (PHPStan)
|
name: Static code analysis (PHPStan)
|
||||||
on: push
|
on: push
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
jobs:
|
jobs:
|
||||||
phpstan:
|
phpstan:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
9
.github/workflows/phpunit.yml
vendored
9
.github/workflows/phpunit.yml
vendored
@@ -1,18 +1,13 @@
|
|||||||
name: PHPUnit Tests
|
name: PHPUnit Tests
|
||||||
on: push
|
on: push
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
jobs:
|
jobs:
|
||||||
phpunit:
|
phpunit:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
postgres_version: [ 15, 16, 17 ]
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
pgsql_test:
|
pgsql_test:
|
||||||
image: postgres:${{ matrix.postgres_version }}
|
image: postgres:15
|
||||||
env:
|
env:
|
||||||
PGPASSWORD: 'root'
|
PGPASSWORD: 'root'
|
||||||
POSTGRES_DB: 'laravel'
|
POSTGRES_DB: 'laravel'
|
||||||
@@ -68,7 +63,7 @@ jobs:
|
|||||||
run: php artisan test --stop-on-failure --coverage-text --coverage-clover=coverage.xml
|
run: php artisan test --stop-on-failure --coverage-text --coverage-clover=coverage.xml
|
||||||
|
|
||||||
- name: "Upload coverage reports to Codecov"
|
- name: "Upload coverage reports to Codecov"
|
||||||
uses: codecov/codecov-action@v5.4.3
|
uses: codecov/codecov-action@v5.4.0
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
slug: solidtime-io/solidtime
|
slug: solidtime-io/solidtime
|
||||||
|
|||||||
2
.github/workflows/pint.yml
vendored
2
.github/workflows/pint.yml
vendored
@@ -1,7 +1,5 @@
|
|||||||
name: PHP Linting
|
name: PHP Linting
|
||||||
on: push
|
on: push
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
jobs:
|
jobs:
|
||||||
pint:
|
pint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
2
.github/workflows/playwright.yml
vendored
2
.github/workflows/playwright.yml
vendored
@@ -1,7 +1,5 @@
|
|||||||
name: Playwright Tests
|
name: Playwright Tests
|
||||||
on: [push]
|
on: [push]
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class CreateNewUser implements CreatesNewUsers
|
|||||||
/**
|
/**
|
||||||
* Create a newly registered user.
|
* Create a newly registered user.
|
||||||
*
|
*
|
||||||
* @param array<string, mixed> $input
|
* @param array<string, string> $input
|
||||||
*
|
*
|
||||||
* @throws ValidationException
|
* @throws ValidationException
|
||||||
*/
|
*/
|
||||||
@@ -76,11 +76,6 @@ class CreateNewUser implements CreatesNewUsers
|
|||||||
$ipLookupResponse = app(IpLookupServiceContract::class)->lookup(request()->ip());
|
$ipLookupResponse = app(IpLookupServiceContract::class)->lookup(request()->ip());
|
||||||
|
|
||||||
$startOfWeek = Weekday::Monday;
|
$startOfWeek = Weekday::Monday;
|
||||||
$numberFormat = null;
|
|
||||||
$currencyFormat = null;
|
|
||||||
$dateFormat = null;
|
|
||||||
$intervalFormat = null;
|
|
||||||
$timeFormat = null;
|
|
||||||
$currency = null;
|
$currency = null;
|
||||||
if ($ipLookupResponse !== null) {
|
if ($ipLookupResponse !== null) {
|
||||||
$startOfWeek = $ipLookupResponse->startOfWeek ?? Weekday::Monday;
|
$startOfWeek = $ipLookupResponse->startOfWeek ?? Weekday::Monday;
|
||||||
@@ -90,7 +85,7 @@ class CreateNewUser implements CreatesNewUsers
|
|||||||
$currency = $ipLookupResponse->currency;
|
$currency = $ipLookupResponse->currency;
|
||||||
}
|
}
|
||||||
$user = null;
|
$user = null;
|
||||||
DB::transaction(function () use (&$user, $input, $timezone, $startOfWeek, $currency, $numberFormat, $currencyFormat, $dateFormat, $intervalFormat, $timeFormat): void {
|
DB::transaction(function () use (&$user, $input, $timezone, $startOfWeek, $currency): void {
|
||||||
$userService = app(UserService::class);
|
$userService = app(UserService::class);
|
||||||
$user = $userService->createUser(
|
$user = $userService->createUser(
|
||||||
$input['name'],
|
$input['name'],
|
||||||
@@ -98,12 +93,7 @@ class CreateNewUser implements CreatesNewUsers
|
|||||||
$input['password'],
|
$input['password'],
|
||||||
$timezone ?? 'UTC',
|
$timezone ?? 'UTC',
|
||||||
$startOfWeek,
|
$startOfWeek,
|
||||||
$currency,
|
$currency ?? 'EUR',
|
||||||
$numberFormat,
|
|
||||||
$currencyFormat,
|
|
||||||
$dateFormat,
|
|
||||||
$intervalFormat,
|
|
||||||
$timeFormat
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace App\Actions\Fortify;
|
|||||||
|
|
||||||
use App\Enums\Weekday;
|
use App\Enums\Weekday;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
@@ -58,7 +59,8 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
|||||||
$user->updateProfilePhoto($input['photo']);
|
$user->updateProfilePhoto($input['photo']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($input['email'] !== $user->email) {
|
if ($input['email'] !== $user->email &&
|
||||||
|
$user instanceof MustVerifyEmail) {
|
||||||
$user->forceFill([
|
$user->forceFill([
|
||||||
'name' => $input['name'],
|
'name' => $input['name'],
|
||||||
'email' => $input['email'],
|
'email' => $input['email'],
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class AddOrganizationMember implements AddsTeamMembers
|
|||||||
*/
|
*/
|
||||||
protected function rules(): array
|
protected function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return array_filter([
|
||||||
'email' => [
|
'email' => [
|
||||||
'required',
|
'required',
|
||||||
'email',
|
'email',
|
||||||
@@ -75,7 +75,7 @@ class AddOrganizationMember implements AddsTeamMembers
|
|||||||
Role::Employee->value,
|
Role::Employee->value,
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Actions\Jetstream;
|
namespace App\Actions\Jetstream;
|
||||||
|
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Events\AfterCreateOrganization;
|
use App\Events\AfterCreateOrganization;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Service\IpLookup\IpLookupServiceContract;
|
|
||||||
use App\Service\OrganizationService;
|
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
@@ -34,18 +33,16 @@ class CreateOrganization implements CreatesTeams
|
|||||||
'name' => ['required', 'string', 'max:255'],
|
'name' => ['required', 'string', 'max:255'],
|
||||||
])->validateWithBag('createTeam');
|
])->validateWithBag('createTeam');
|
||||||
|
|
||||||
$ipLookupResponse = app(IpLookupServiceContract::class)->lookup(request()->ip());
|
$organization = new Organization;
|
||||||
|
$organization->name = $input['name'];
|
||||||
|
$organization->personal_team = false;
|
||||||
|
$organization->owner()->associate($user);
|
||||||
|
$organization->save();
|
||||||
|
|
||||||
$currency = null;
|
$organization->users()->attach(
|
||||||
if ($ipLookupResponse !== null) {
|
$user, [
|
||||||
$currency = $ipLookupResponse->currency;
|
'role' => Role::Owner->value,
|
||||||
}
|
]
|
||||||
|
|
||||||
$organization = app(OrganizationService::class)->createOrganization(
|
|
||||||
$input['name'],
|
|
||||||
$user,
|
|
||||||
false,
|
|
||||||
$currency
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$user->switchTeam($organization);
|
$user->switchTeam($organization);
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ class UserCreateCommand extends Command
|
|||||||
$password,
|
$password,
|
||||||
'UTC',
|
'UTC',
|
||||||
Weekday::Monday,
|
Weekday::Monday,
|
||||||
null,
|
'EUR',
|
||||||
verifyEmail: $verifyEmail
|
$verifyEmail
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
/** @var Organization|null $organization */
|
/** @var Organization|null $organization */
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Console\Commands\SelfHost;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Illuminate\Database\Query\Builder;
|
|
||||||
use Illuminate\Database\Query\JoinClause;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
class SelfHostDatabaseConsistency extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'self-host:database-consistency';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle(): int
|
|
||||||
{
|
|
||||||
$hadAProblem = false;
|
|
||||||
|
|
||||||
// Task need to be part of project in time entries
|
|
||||||
$problems = DB::table('time_entries')
|
|
||||||
->select(['time_entries.id as id'])
|
|
||||||
->join('tasks', 'time_entries.task_id', '=', 'tasks.id')
|
|
||||||
->where('tasks.project_id', '!=', DB::raw('time_entries.project_id'))
|
|
||||||
->get();
|
|
||||||
$this->logProblems($problems, 'Time entries have a task that does not belong to the project of the time entry', $hadAProblem);
|
|
||||||
|
|
||||||
// Client id is the client id of the project
|
|
||||||
$problems = DB::table('time_entries')
|
|
||||||
->select(['time_entries.id as id'])
|
|
||||||
->join('projects', 'time_entries.project_id', '=', 'projects.id')
|
|
||||||
->where(DB::raw('coalesce(projects.client_id::varchar, \'\')'), '!=', DB::raw('coalesce(time_entries.client_id::varchar, \'\')'))
|
|
||||||
->get();
|
|
||||||
$this->logProblems($problems, 'Time entries have a client that does not match the client of the project', $hadAProblem);
|
|
||||||
|
|
||||||
// Client id can only be not null if the project id is not null
|
|
||||||
$problems = DB::table('time_entries')
|
|
||||||
->select(['time_entries.id as id'])
|
|
||||||
->whereNotNull('client_id')
|
|
||||||
->whereNull('project_id')
|
|
||||||
->get();
|
|
||||||
$this->logProblems($problems, 'Time entries have a client but no project', $hadAProblem);
|
|
||||||
|
|
||||||
// Every user needs to be a member of at least one organization
|
|
||||||
$problems = DB::table('users')
|
|
||||||
->select(['users.id as id'])
|
|
||||||
->leftJoin('members', 'users.id', '=', 'members.user_id')
|
|
||||||
->whereNull('members.id')
|
|
||||||
->get();
|
|
||||||
$this->logProblems($problems, 'Users are not member of any organization', $hadAProblem);
|
|
||||||
|
|
||||||
// Every organization needs at least an owner
|
|
||||||
$problems = DB::table('organizations')
|
|
||||||
->select(['organizations.id as id'])
|
|
||||||
->leftJoin('members', function (JoinClause $join): void {
|
|
||||||
$join->on('organizations.id', '=', 'members.organization_id')
|
|
||||||
->where('members.role', '=', 'owner');
|
|
||||||
})
|
|
||||||
->whereNull('members.id')
|
|
||||||
->get();
|
|
||||||
$this->logProblems($problems, 'Organizations without an owner', $hadAProblem);
|
|
||||||
|
|
||||||
// Every member can only have one running time entry
|
|
||||||
$problems = DB::table('time_entries')
|
|
||||||
->select(['user_id as id'])
|
|
||||||
->whereNull('end')
|
|
||||||
->groupBy('user_id')
|
|
||||||
->havingRaw('count(*) > 1')
|
|
||||||
->get(['user_id', DB::raw('count(*) as count')]);
|
|
||||||
$this->logProblems($problems, 'Users with more than one running time entry', $hadAProblem);
|
|
||||||
|
|
||||||
// Users have a current organization that they are not a member of
|
|
||||||
$problems = DB::table('users')
|
|
||||||
->select(['users.id as id'])
|
|
||||||
->whereNotNull('current_team_id')
|
|
||||||
->whereNotIn('current_team_id', function (Builder $query): void {
|
|
||||||
$query->select('organization_id')
|
|
||||||
->from('members')
|
|
||||||
->whereColumn('members.user_id', 'users.id');
|
|
||||||
})->get();
|
|
||||||
$this->logProblems($problems, 'Users have a current organization that they are not a member of', $hadAProblem);
|
|
||||||
|
|
||||||
return $hadAProblem ? self::FAILURE : self::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection<int, \stdClass> $problems
|
|
||||||
*/
|
|
||||||
private function logProblems(Collection $problems, string $message, bool &$hadAProblem): void
|
|
||||||
{
|
|
||||||
$message = 'Consistency problem: '.$message;
|
|
||||||
if ($problems->isNotEmpty()) {
|
|
||||||
$ids = $problems->pluck('id');
|
|
||||||
$hadAProblem = true;
|
|
||||||
Log::error($message, [
|
|
||||||
'ids' => $ids,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$error = $message;
|
|
||||||
foreach ($ids as $id) {
|
|
||||||
$error .= "\n - ".$id;
|
|
||||||
}
|
|
||||||
$this->error($error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -25,10 +25,6 @@ class Kernel extends ConsoleKernel
|
|||||||
$schedule->command('self-host:telemetry')
|
$schedule->command('self-host:telemetry')
|
||||||
->when(fn (): bool => config('scheduling.tasks.self_hosting_telemetry'))
|
->when(fn (): bool => config('scheduling.tasks.self_hosting_telemetry'))
|
||||||
->twiceDaily();
|
->twiceDaily();
|
||||||
|
|
||||||
$schedule->command('self-host:database-consistency')
|
|
||||||
->when(fn (): bool => config('scheduling.tasks.self_hosting_database_consistency'))
|
|
||||||
->everySixHours();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
|
|
||||||
|
|
||||||
enum CurrencyFormat: string
|
|
||||||
{
|
|
||||||
use LaravelEnumHelper;
|
|
||||||
|
|
||||||
case ISOCodeBeforeWithSpace = 'iso-code-before-with-space';
|
|
||||||
case ISOCodeAfterWithSpace = 'iso-code-after-with-space';
|
|
||||||
|
|
||||||
case SymbolBefore = 'symbol-before';
|
|
||||||
|
|
||||||
case SymbolAfter = 'symbol-after';
|
|
||||||
|
|
||||||
case SymbolBeforeWithSpace = 'symbol-before-with-space';
|
|
||||||
|
|
||||||
case SymbolAfterWithSpace = 'symbol-after-with-space';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array<string, string>
|
|
||||||
*/
|
|
||||||
public static function toSelectArray(): array
|
|
||||||
{
|
|
||||||
$selectArray = [];
|
|
||||||
foreach (self::values() as $value) {
|
|
||||||
$selectArray[(string) $value] = (string) __('enum.currency_format.'.$value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $selectArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
|
|
||||||
|
|
||||||
enum DateFormat: string
|
|
||||||
{
|
|
||||||
use LaravelEnumHelper;
|
|
||||||
|
|
||||||
case PointSeparatedDMYYYY = 'point-separated-d-m-yyyy';
|
|
||||||
case SlashSeparatedMMDDYYYY = 'slash-separated-mm-dd-yyyy';
|
|
||||||
|
|
||||||
case SlashSeparatedDDMMYYYY = 'slash-separated-dd-mm-yyyy';
|
|
||||||
|
|
||||||
case HyphenSeparatedDDMMYYY = 'hyphen-separated-dd-mm-yyyy';
|
|
||||||
|
|
||||||
case HyphenSeparatedMMDDDYYYY = 'hyphen-separated-mm-dd-yyyy';
|
|
||||||
|
|
||||||
case HyphenSeparatedYYYYMMDD = 'hyphen-separated-yyyy-mm-dd';
|
|
||||||
|
|
||||||
public function toCarbonFormat(): string
|
|
||||||
{
|
|
||||||
return match ($this->value) {
|
|
||||||
self::PointSeparatedDMYYYY->value => 'j.n.Y',
|
|
||||||
self::SlashSeparatedMMDDYYYY->value => 'm/d/Y',
|
|
||||||
self::SlashSeparatedDDMMYYYY->value => 'd/m/Y',
|
|
||||||
self::HyphenSeparatedDDMMYYY->value => 'd-m-Y',
|
|
||||||
self::HyphenSeparatedMMDDDYYYY->value => 'm-d-Y',
|
|
||||||
self::HyphenSeparatedYYYYMMDD->value => 'Y-m-d',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array<string, string>
|
|
||||||
*/
|
|
||||||
public static function toSelectArray(): array
|
|
||||||
{
|
|
||||||
$selectArray = [];
|
|
||||||
foreach (self::values() as $value) {
|
|
||||||
$selectArray[(string) $value] = (string) __('enum.date_format.'.$value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $selectArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
|
|
||||||
|
|
||||||
enum IntervalFormat: string
|
|
||||||
{
|
|
||||||
use LaravelEnumHelper;
|
|
||||||
|
|
||||||
case Decimal = 'decimal';
|
|
||||||
case HoursMinutes = 'hours-minutes';
|
|
||||||
|
|
||||||
case HoursMinutesColonSeparated = 'hours-minutes-colon-separated';
|
|
||||||
|
|
||||||
case HoursMinutesSecondsColonSeparated = 'hours-minutes-seconds-colon-separated';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array<string, string>
|
|
||||||
*/
|
|
||||||
public static function toSelectArray(): array
|
|
||||||
{
|
|
||||||
$selectArray = [];
|
|
||||||
foreach (self::values() as $value) {
|
|
||||||
$selectArray[(string) $value] = (string) __('enum.interval_format.'.$value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $selectArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @info https://en.wikipedia.org/wiki/Decimal_separator
|
|
||||||
*/
|
|
||||||
enum NumberFormat: string
|
|
||||||
{
|
|
||||||
use LaravelEnumHelper;
|
|
||||||
|
|
||||||
case ThousandsPointDecimalComma = 'point-comma';
|
|
||||||
|
|
||||||
case ThousandsCommaDecimalPoint = 'comma-point';
|
|
||||||
case ThousandsSpaceDecimalComma = 'space-comma';
|
|
||||||
|
|
||||||
case ThousandsSpaceDecimalPoint = 'space-point';
|
|
||||||
|
|
||||||
case ThousandsApostropheDecimalPoint = 'apostrophe-point';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array<string, string>
|
|
||||||
*/
|
|
||||||
public static function toSelectArray(): array
|
|
||||||
{
|
|
||||||
$selectArray = [];
|
|
||||||
foreach (self::values() as $value) {
|
|
||||||
$selectArray[(string) $value] = (string) __('enum.number_format.'.$value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $selectArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
|
|
||||||
|
|
||||||
enum TimeFormat: string
|
|
||||||
{
|
|
||||||
use LaravelEnumHelper;
|
|
||||||
|
|
||||||
case TwelveHours = '12-hours';
|
|
||||||
case TwentyFourHours = '24-hours';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array<string, string>
|
|
||||||
*/
|
|
||||||
public static function toSelectArray(): array
|
|
||||||
{
|
|
||||||
$selectArray = [];
|
|
||||||
foreach (self::values() as $value) {
|
|
||||||
$selectArray[(string) $value] = (string) __('enum.time_format.'.$value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $selectArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Events;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
|
||||||
|
|
||||||
class DatabaseSeederAfterSeed
|
|
||||||
{
|
|
||||||
use Dispatchable;
|
|
||||||
|
|
||||||
public function __construct() {}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Events;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
|
||||||
|
|
||||||
class DatabaseSeederBeforeDelete
|
|
||||||
{
|
|
||||||
use Dispatchable;
|
|
||||||
|
|
||||||
public function __construct() {}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Exceptions\Api;
|
|
||||||
|
|
||||||
class InvitationForTheEmailAlreadyExistsApiException extends ApiException
|
|
||||||
{
|
|
||||||
public const string KEY = 'invitation_for_the_email_already_exists';
|
|
||||||
}
|
|
||||||
@@ -41,7 +41,9 @@ class PaginatedResourceCollectionTypeToSchema extends TypeToSchemaExtension
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$collectingType = $this->openApiTransformer->transform($collectingClassType);
|
if (! ($collectingType = $this->openApiTransformer->transform($collectingClassType))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$newType = new OpenApiObjectType;
|
$newType = new OpenApiObjectType;
|
||||||
$newType->addProperty('data', (new ArrayType)->setItems($collectingType));
|
$newType->addProperty('data', (new ArrayType)->setItems($collectingType));
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use Filament\Tables;
|
|||||||
use Filament\Tables\Columns\IconColumn;
|
use Filament\Tables\Columns\IconColumn;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Novadaemon\FilamentPrettyJson\Form\PrettyJsonField;
|
use Novadaemon\FilamentPrettyJson\PrettyJson;
|
||||||
|
|
||||||
class AuditResource extends Resource
|
class AuditResource extends Resource
|
||||||
{
|
{
|
||||||
@@ -38,8 +38,8 @@ class AuditResource extends Resource
|
|||||||
->maxLength(255),
|
->maxLength(255),
|
||||||
Forms\Components\TextInput::make('auditable_id')
|
Forms\Components\TextInput::make('auditable_id')
|
||||||
->required(),
|
->required(),
|
||||||
PrettyJsonField::make('old_values'),
|
PrettyJson::make('old_values'),
|
||||||
PrettyJsonField::make('new_values'),
|
PrettyJson::make('new_values'),
|
||||||
Forms\Components\Textarea::make('url'),
|
Forms\Components\Textarea::make('url'),
|
||||||
Forms\Components\TextInput::make('ip_address'),
|
Forms\Components\TextInput::make('ip_address'),
|
||||||
Forms\Components\TextInput::make('user_agent')
|
Forms\Components\TextInput::make('user_agent')
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use Filament\Tables\Columns\TextColumn;
|
|||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Novadaemon\FilamentPrettyJson\Form\PrettyJsonField;
|
use Novadaemon\FilamentPrettyJson\PrettyJson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @source https://gitlab.com/amvisor/filament-failed-jobs
|
* @source https://gitlab.com/amvisor/filament-failed-jobs
|
||||||
@@ -50,7 +50,7 @@ class FailedJobResource extends Resource
|
|||||||
|
|
||||||
// make text a little bit smaller because often a complete Stack Trace is shown:
|
// 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),
|
PrettyJson::make('payload')->disabled()->columnSpan(4),
|
||||||
])->columns(4);
|
])->columns(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Filament\Resources;
|
namespace App\Filament\Resources;
|
||||||
|
|
||||||
use App\Enums\CurrencyFormat;
|
|
||||||
use App\Enums\DateFormat;
|
|
||||||
use App\Enums\IntervalFormat;
|
|
||||||
use App\Enums\NumberFormat;
|
|
||||||
use App\Enums\TimeFormat;
|
|
||||||
use App\Filament\Resources\OrganizationResource\Pages;
|
use App\Filament\Resources\OrganizationResource\Pages;
|
||||||
use App\Filament\Resources\OrganizationResource\RelationManagers\InvitationsRelationManager;
|
use App\Filament\Resources\OrganizationResource\RelationManagers\InvitationsRelationManager;
|
||||||
use App\Filament\Resources\OrganizationResource\RelationManagers\UsersRelationManager;
|
use App\Filament\Resources\OrganizationResource\RelationManagers\UsersRelationManager;
|
||||||
@@ -61,21 +56,6 @@ class OrganizationResource extends Resource
|
|||||||
->searchable(['name', 'email'])
|
->searchable(['name', 'email'])
|
||||||
->disabledOn(['edit'])
|
->disabledOn(['edit'])
|
||||||
->required(),
|
->required(),
|
||||||
Select::make('date_format')
|
|
||||||
->options(DateFormat::toSelectArray())
|
|
||||||
->required(),
|
|
||||||
Select::make('currency_format')
|
|
||||||
->options(CurrencyFormat::toSelectArray())
|
|
||||||
->required(),
|
|
||||||
Select::make('interval_format')
|
|
||||||
->options(IntervalFormat::toSelectArray())
|
|
||||||
->required(),
|
|
||||||
Select::make('number_format')
|
|
||||||
->options(NumberFormat::toSelectArray())
|
|
||||||
->required(),
|
|
||||||
Select::make('time_format')
|
|
||||||
->options(TimeFormat::toSelectArray())
|
|
||||||
->required(),
|
|
||||||
Forms\Components\Select::make('currency')
|
Forms\Components\Select::make('currency')
|
||||||
->label('Currency')
|
->label('Currency')
|
||||||
->options(function (): array {
|
->options(function (): array {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use Filament\Tables\Columns\TextColumn;
|
|||||||
use Filament\Tables\Columns\ToggleColumn;
|
use Filament\Tables\Columns\ToggleColumn;
|
||||||
use Filament\Tables\Filters\SelectFilter;
|
use Filament\Tables\Filters\SelectFilter;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Novadaemon\FilamentPrettyJson\Form\PrettyJsonField;
|
use Novadaemon\FilamentPrettyJson\PrettyJson;
|
||||||
|
|
||||||
class ReportResource extends Resource
|
class ReportResource extends Resource
|
||||||
{
|
{
|
||||||
@@ -58,7 +58,7 @@ class ReportResource extends Resource
|
|||||||
Forms\Components\TextInput::make('share_secret')
|
Forms\Components\TextInput::make('share_secret')
|
||||||
->label('Share Secret')
|
->label('Share Secret')
|
||||||
->nullable(),
|
->nullable(),
|
||||||
PrettyJsonField::make('properties')
|
PrettyJson::make('properties')
|
||||||
->formatStateUsing(function (ReportPropertiesDto $state, Report $record): string {
|
->formatStateUsing(function (ReportPropertiesDto $state, Report $record): string {
|
||||||
return $record->getRawOriginal('properties');
|
return $record->getRawOriginal('properties');
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class TokenResource extends Resource
|
|||||||
->label('Name')
|
->label('Name')
|
||||||
->required()
|
->required()
|
||||||
->maxLength(255),
|
->maxLength(255),
|
||||||
Forms\Components\Select::make('owner_id')
|
Forms\Components\Select::make('user_id')
|
||||||
->label('User')
|
->label('User')
|
||||||
->relationship(name: 'user', titleAttribute: 'name')
|
->relationship(name: 'user', titleAttribute: 'name')
|
||||||
->searchable(['name'])
|
->searchable(['name'])
|
||||||
@@ -79,12 +79,10 @@ class TokenResource extends Resource
|
|||||||
Tables\Columns\TextColumn::make('client.name')
|
Tables\Columns\TextColumn::make('client.name')
|
||||||
->searchable()
|
->searchable()
|
||||||
->sortable(),
|
->sortable(),
|
||||||
Tables\Columns\IconColumn::make('personal_access_client')
|
Tables\Columns\IconColumn::make('client.personal_access_client')
|
||||||
->state(function (Token $token): bool {
|
|
||||||
return in_array('personal_access', $token->client->grant_types ?? [], true);
|
|
||||||
})
|
|
||||||
->boolean()
|
->boolean()
|
||||||
->label('API token?'),
|
->label('API token?')
|
||||||
|
->sortable(),
|
||||||
Tables\Columns\IconColumn::make('revoked')
|
Tables\Columns\IconColumn::make('revoked')
|
||||||
->boolean()
|
->boolean()
|
||||||
->label('Revoked?')
|
->label('Revoked?')
|
||||||
@@ -108,14 +106,14 @@ class TokenResource extends Resource
|
|||||||
/** @var Builder<Token> $query */
|
/** @var Builder<Token> $query */
|
||||||
return $query->whereHas('client', function (Builder $query) {
|
return $query->whereHas('client', function (Builder $query) {
|
||||||
/** @var Builder<Client> $query */
|
/** @var Builder<Client> $query */
|
||||||
return $query->whereJsonContains('grant_types', 'personal_access');
|
return $query->where('personal_access_client', true);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
false: function (Builder $query) {
|
false: function (Builder $query) {
|
||||||
/** @var Builder<Token> $query */
|
/** @var Builder<Token> $query */
|
||||||
return $query->whereHas('client', function (Builder $query) {
|
return $query->whereHas('client', function (Builder $query) {
|
||||||
/** @var Builder<Client> $query */
|
/** @var Builder<Client> $query */
|
||||||
return $query->whereJsonDoesntContain('grant_types', 'personal_access');
|
return $query->where('personal_access_client', false);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
blank: function (Builder $query) {
|
blank: function (Builder $query) {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ use Filament\Tables;
|
|||||||
use Filament\Tables\Filters\TernaryFilter;
|
use Filament\Tables\Filters\TernaryFilter;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
@@ -208,14 +207,6 @@ class UserResource extends Resource
|
|||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
->bulkActions([
|
->bulkActions([
|
||||||
Tables\Actions\BulkAction::make('Resend verification email')
|
|
||||||
->icon('heroicon-o-paper-airplane')
|
|
||||||
->action(function (Collection $records): void {
|
|
||||||
foreach ($records as $user) {
|
|
||||||
/** @var User $user */
|
|
||||||
$user->sendEmailVerificationNotification();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class CreateUser extends CreateRecord
|
|||||||
$data['timezone'],
|
$data['timezone'],
|
||||||
Weekday::from($data['week_start']),
|
Weekday::from($data['week_start']),
|
||||||
$data['currency'],
|
$data['currency'],
|
||||||
verifyEmail: (bool) $data['is_email_verified']
|
(bool) $data['is_email_verified']
|
||||||
);
|
);
|
||||||
|
|
||||||
return $user;
|
return $user;
|
||||||
|
|||||||
@@ -8,12 +8,9 @@ use App\Exceptions\Api\PersonalAccessClientIsNotConfiguredException;
|
|||||||
use App\Http\Requests\V1\ApiToken\ApiTokenStoreRequest;
|
use App\Http\Requests\V1\ApiToken\ApiTokenStoreRequest;
|
||||||
use App\Http\Resources\V1\ApiToken\ApiTokenCollection;
|
use App\Http\Resources\V1\ApiToken\ApiTokenCollection;
|
||||||
use App\Http\Resources\V1\ApiToken\ApiTokenWithAccessTokenResource;
|
use App\Http\Resources\V1\ApiToken\ApiTokenWithAccessTokenResource;
|
||||||
use App\Models\Passport\Client;
|
|
||||||
use App\Models\Passport\Token;
|
use App\Models\Passport\Token;
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class ApiTokenController extends Controller
|
class ApiTokenController extends Controller
|
||||||
{
|
{
|
||||||
@@ -31,10 +28,7 @@ class ApiTokenController extends Controller
|
|||||||
$user = $this->user();
|
$user = $this->user();
|
||||||
|
|
||||||
$tokens = $user->tokens()
|
$tokens = $user->tokens()
|
||||||
->whereHas('client', function (Builder $query): void {
|
->where('client_id', '=', config('passport.personal_access_client.id'))
|
||||||
/** @var Builder<Client> $query */
|
|
||||||
$query->whereJsonContains('grant_types', 'personal_access');
|
|
||||||
})
|
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
return new ApiTokenCollection($tokens);
|
return new ApiTokenCollection($tokens);
|
||||||
@@ -54,21 +48,15 @@ class ApiTokenController extends Controller
|
|||||||
{
|
{
|
||||||
$user = $this->user();
|
$user = $this->user();
|
||||||
|
|
||||||
try {
|
if (config('passport.personal_access_client.id') === null || config('passport.personal_access_client.secret') === null) {
|
||||||
$token = $user->createToken($request->getName(), ['*']);
|
throw new PersonalAccessClientIsNotConfiguredException;
|
||||||
|
|
||||||
/** @var Token $tokenModel */
|
|
||||||
$tokenModel = $token->getToken();
|
|
||||||
|
|
||||||
return new ApiTokenWithAccessTokenResource($tokenModel, $token->accessToken);
|
|
||||||
} catch (\RuntimeException $exception) {
|
|
||||||
report($exception);
|
|
||||||
if (Str::contains($exception->getMessage(), ['Personal access client not found'])) {
|
|
||||||
throw new PersonalAccessClientIsNotConfiguredException;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw $exception;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$token = $user->createToken($request->getName(), ['*']);
|
||||||
|
/** @var Token $tokenModel */
|
||||||
|
$tokenModel = $token->token;
|
||||||
|
|
||||||
|
return new ApiTokenWithAccessTokenResource($tokenModel, $token->accessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,10 +71,13 @@ class ApiTokenController extends Controller
|
|||||||
{
|
{
|
||||||
$user = $this->user();
|
$user = $this->user();
|
||||||
|
|
||||||
|
if (config('passport.personal_access_client.id') === null || config('passport.personal_access_client.secret') === null) {
|
||||||
|
throw new PersonalAccessClientIsNotConfiguredException;
|
||||||
|
}
|
||||||
if ($apiToken->user_id !== $user->getKey()) {
|
if ($apiToken->user_id !== $user->getKey()) {
|
||||||
throw new AuthorizationException('API token does not belong to user');
|
throw new AuthorizationException('API token does not belong to user');
|
||||||
}
|
}
|
||||||
if (! ($apiToken->client?->hasGrantType('personal_access') ?? false)) {
|
if ($apiToken->client_id !== config('passport.personal_access_client.id')) {
|
||||||
throw new AuthorizationException('API token is not a personal access token');
|
throw new AuthorizationException('API token is not a personal access token');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,10 +97,13 @@ class ApiTokenController extends Controller
|
|||||||
{
|
{
|
||||||
$user = $this->user();
|
$user = $this->user();
|
||||||
|
|
||||||
|
if (config('passport.personal_access_client.id') === null || config('passport.personal_access_client.secret') === null) {
|
||||||
|
throw new PersonalAccessClientIsNotConfiguredException;
|
||||||
|
}
|
||||||
if ($apiToken->user_id !== $user->getKey()) {
|
if ($apiToken->user_id !== $user->getKey()) {
|
||||||
throw new AuthorizationException('API token does not belong to user');
|
throw new AuthorizationException('API token does not belong to user');
|
||||||
}
|
}
|
||||||
if (! ($apiToken->client?->hasGrantType('personal_access') ?? false)) {
|
if ($apiToken->client_id !== config('passport.personal_access_client.id')) {
|
||||||
throw new AuthorizationException('API token is not a personal access token');
|
throw new AuthorizationException('API token is not a personal access token');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V1;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Service\CurrencyService;
|
|
||||||
use Brick\Money\Currency;
|
|
||||||
use Brick\Money\ISOCurrencyProvider;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
|
||||||
|
|
||||||
class CurrencyController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get all currencies
|
|
||||||
*
|
|
||||||
* @response array{code: string, name: string, symbol: string}[]
|
|
||||||
*
|
|
||||||
* @operationId getCurrencies
|
|
||||||
*/
|
|
||||||
public function index(): JsonResponse
|
|
||||||
{
|
|
||||||
$currencyService = app(CurrencyService::class);
|
|
||||||
|
|
||||||
$currencies = array_values(array_map(
|
|
||||||
fn (Currency $currency): array => [
|
|
||||||
'code' => $currency->getCurrencyCode(),
|
|
||||||
'name' => $currency->getName(),
|
|
||||||
'symbol' => $currencyService->getCurrencySymbol($currency->getCurrencyCode()),
|
|
||||||
],
|
|
||||||
ISOCurrencyProvider::getInstance()->getAvailableCurrencies()
|
|
||||||
));
|
|
||||||
|
|
||||||
return response()->json($currencies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Api\V1;
|
namespace App\Http\Controllers\Api\V1;
|
||||||
|
|
||||||
use App\Exceptions\Api\InvitationForTheEmailAlreadyExistsApiException;
|
|
||||||
use App\Exceptions\Api\UserIsAlreadyMemberOfOrganizationApiException;
|
use App\Exceptions\Api\UserIsAlreadyMemberOfOrganizationApiException;
|
||||||
use App\Http\Requests\V1\Invitation\InvitationIndexRequest;
|
use App\Http\Requests\V1\Invitation\InvitationIndexRequest;
|
||||||
use App\Http\Requests\V1\Invitation\InvitationStoreRequest;
|
use App\Http\Requests\V1\Invitation\InvitationStoreRequest;
|
||||||
@@ -51,7 +50,6 @@ class InvitationController extends Controller
|
|||||||
*
|
*
|
||||||
* @throws AuthorizationException
|
* @throws AuthorizationException
|
||||||
* @throws UserIsAlreadyMemberOfOrganizationApiException
|
* @throws UserIsAlreadyMemberOfOrganizationApiException
|
||||||
* @throws InvitationForTheEmailAlreadyExistsApiException
|
|
||||||
*
|
*
|
||||||
* @operationId invite
|
* @operationId invite
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,14 +10,12 @@ use App\Exceptions\Api\CanNotRemoveOwnerFromOrganization;
|
|||||||
use App\Exceptions\Api\ChangingRoleOfPlaceholderIsNotAllowed;
|
use App\Exceptions\Api\ChangingRoleOfPlaceholderIsNotAllowed;
|
||||||
use App\Exceptions\Api\ChangingRoleToPlaceholderIsNotAllowed;
|
use App\Exceptions\Api\ChangingRoleToPlaceholderIsNotAllowed;
|
||||||
use App\Exceptions\Api\EntityStillInUseApiException;
|
use App\Exceptions\Api\EntityStillInUseApiException;
|
||||||
use App\Exceptions\Api\InvitationForTheEmailAlreadyExistsApiException;
|
|
||||||
use App\Exceptions\Api\OnlyOwnerCanChangeOwnership;
|
use App\Exceptions\Api\OnlyOwnerCanChangeOwnership;
|
||||||
use App\Exceptions\Api\OnlyPlaceholdersCanBeMergedIntoAnotherMember;
|
use App\Exceptions\Api\OnlyPlaceholdersCanBeMergedIntoAnotherMember;
|
||||||
use App\Exceptions\Api\OrganizationNeedsAtLeastOneOwner;
|
use App\Exceptions\Api\OrganizationNeedsAtLeastOneOwner;
|
||||||
use App\Exceptions\Api\ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException;
|
use App\Exceptions\Api\ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException;
|
||||||
use App\Exceptions\Api\UserIsAlreadyMemberOfOrganizationApiException;
|
use App\Exceptions\Api\UserIsAlreadyMemberOfOrganizationApiException;
|
||||||
use App\Exceptions\Api\UserNotPlaceholderApiException;
|
use App\Exceptions\Api\UserNotPlaceholderApiException;
|
||||||
use App\Http\Requests\V1\Member\MemberDestroyRequest;
|
|
||||||
use App\Http\Requests\V1\Member\MemberIndexRequest;
|
use App\Http\Requests\V1\Member\MemberIndexRequest;
|
||||||
use App\Http\Requests\V1\Member\MemberMergeIntoRequest;
|
use App\Http\Requests\V1\Member\MemberMergeIntoRequest;
|
||||||
use App\Http\Requests\V1\Member\MemberUpdateRequest;
|
use App\Http\Requests\V1\Member\MemberUpdateRequest;
|
||||||
@@ -102,13 +100,11 @@ class MemberController extends Controller
|
|||||||
*
|
*
|
||||||
* @operationId removeMember
|
* @operationId removeMember
|
||||||
*/
|
*/
|
||||||
public function destroy(MemberDestroyRequest $request, Organization $organization, Member $member, MemberService $memberService): JsonResponse
|
public function destroy(Organization $organization, Member $member, MemberService $memberService): JsonResponse
|
||||||
{
|
{
|
||||||
$this->checkPermission($organization, 'members:delete', $member);
|
$this->checkPermission($organization, 'members:delete', $member);
|
||||||
|
|
||||||
$deleteRelated = $request->getDeleteRelated();
|
$memberService->removeMember($member, $organization);
|
||||||
|
|
||||||
$memberService->removeMember($member, $organization, $deleteRelated);
|
|
||||||
|
|
||||||
return response()
|
return response()
|
||||||
->json(null, 204);
|
->json(null, 204);
|
||||||
@@ -140,8 +136,6 @@ class MemberController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge one member into another
|
|
||||||
*
|
|
||||||
* @throws AuthorizationException
|
* @throws AuthorizationException
|
||||||
* @throws OnlyPlaceholdersCanBeMergedIntoAnotherMember
|
* @throws OnlyPlaceholdersCanBeMergedIntoAnotherMember
|
||||||
* @throws \Throwable
|
* @throws \Throwable
|
||||||
@@ -174,7 +168,6 @@ class MemberController extends Controller
|
|||||||
* @throws UserNotPlaceholderApiException
|
* @throws UserNotPlaceholderApiException
|
||||||
* @throws UserIsAlreadyMemberOfOrganizationApiException
|
* @throws UserIsAlreadyMemberOfOrganizationApiException
|
||||||
* @throws ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException
|
* @throws ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException
|
||||||
* @throws InvitationForTheEmailAlreadyExistsApiException
|
|
||||||
*
|
*
|
||||||
* @operationId invitePlaceholder
|
* @operationId invitePlaceholder
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -40,35 +40,15 @@ class OrganizationController extends Controller
|
|||||||
{
|
{
|
||||||
$this->checkPermission($organization, 'organizations:update');
|
$this->checkPermission($organization, 'organizations:update');
|
||||||
|
|
||||||
if ($request->getName() !== null) {
|
$organization->name = $request->input('name');
|
||||||
$organization->name = $request->getName();
|
$oldBillableRate = $organization->billable_rate;
|
||||||
}
|
if ($request->has('employees_can_see_billable_rates')) {
|
||||||
if ($request->getEmployeesCanSeeBillableRates() !== null) {
|
$organization->employees_can_see_billable_rates = $request->validated('employees_can_see_billable_rates');
|
||||||
$organization->employees_can_see_billable_rates = $request->getEmployeesCanSeeBillableRates();
|
|
||||||
}
|
|
||||||
if ($request->getNumberFormat() !== null) {
|
|
||||||
$organization->number_format = $request->getNumberFormat();
|
|
||||||
}
|
|
||||||
if ($request->getCurrencyFormat() !== null) {
|
|
||||||
$organization->currency_format = $request->getCurrencyFormat();
|
|
||||||
}
|
|
||||||
if ($request->getDateFormat() !== null) {
|
|
||||||
$organization->date_format = $request->getDateFormat();
|
|
||||||
}
|
|
||||||
if ($request->getIntervalFormat() !== null) {
|
|
||||||
$organization->interval_format = $request->getIntervalFormat();
|
|
||||||
}
|
|
||||||
if ($request->getTimeFormat() !== null) {
|
|
||||||
$organization->time_format = $request->getTimeFormat();
|
|
||||||
}
|
|
||||||
$hasBillableRate = $request->has('billable_rate');
|
|
||||||
if ($hasBillableRate) {
|
|
||||||
$oldBillableRate = $organization->billable_rate;
|
|
||||||
$organization->billable_rate = $request->getBillableRate();
|
|
||||||
}
|
}
|
||||||
|
$organization->billable_rate = $request->getBillableRate();
|
||||||
$organization->save();
|
$organization->save();
|
||||||
|
|
||||||
if ($hasBillableRate && $oldBillableRate !== $request->getBillableRate()) {
|
if ($oldBillableRate !== $request->getBillableRate()) {
|
||||||
$billableRateService->updateTimeEntriesBillableRateForOrganization($organization);
|
$billableRateService->updateTimeEntriesBillableRateForOrganization($organization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ use App\Models\Organization;
|
|||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use App\Models\TimeEntry;
|
use App\Models\TimeEntry;
|
||||||
use App\Service\LocalizationService;
|
|
||||||
use App\Service\ReportExport\TimeEntriesDetailedCsvExport;
|
use App\Service\ReportExport\TimeEntriesDetailedCsvExport;
|
||||||
use App\Service\ReportExport\TimeEntriesDetailedExport;
|
use App\Service\ReportExport\TimeEntriesDetailedExport;
|
||||||
use App\Service\ReportExport\TimeEntriesReportExport;
|
use App\Service\ReportExport\TimeEntriesReportExport;
|
||||||
@@ -195,7 +194,6 @@ class TimeEntryController extends Controller
|
|||||||
$filename = 'time-entries-export-'.now()->format('Y-m-d_H-i-s').'.'.$format->getFileExtension();
|
$filename = 'time-entries-export-'.now()->format('Y-m-d_H-i-s').'.'.$format->getFileExtension();
|
||||||
$folderPath = 'exports';
|
$folderPath = 'exports';
|
||||||
$path = $folderPath.'/'.$filename;
|
$path = $folderPath.'/'.$filename;
|
||||||
$localizationService = LocalizationService::forOrganization($organization);
|
|
||||||
if ($format === ExportFormat::CSV) {
|
if ($format === ExportFormat::CSV) {
|
||||||
$export = new TimeEntriesDetailedCsvExport(config('filesystems.private'), $folderPath, $filename, $timeEntriesQuery, 1000, $timezone);
|
$export = new TimeEntriesDetailedCsvExport(config('filesystems.private'), $folderPath, $filename, $timeEntriesQuery, 1000, $timezone);
|
||||||
$export->export();
|
$export->export();
|
||||||
@@ -225,8 +223,6 @@ class TimeEntryController extends Controller
|
|||||||
'currency' => $organization->currency,
|
'currency' => $organization->currency,
|
||||||
'start' => $request->getStart()->timezone($timezone),
|
'start' => $request->getStart()->timezone($timezone),
|
||||||
'end' => $request->getEnd()->timezone($timezone),
|
'end' => $request->getEnd()->timezone($timezone),
|
||||||
'localization' => $localizationService,
|
|
||||||
'showBillableRate' => $showBillableRate,
|
|
||||||
]);
|
]);
|
||||||
$footerViewFile = file_get_contents(resource_path('views/reports/time-entry-index/pdf-footer.blade.php'));
|
$footerViewFile = file_get_contents(resource_path('views/reports/time-entry-index/pdf-footer.blade.php'));
|
||||||
if ($footerViewFile === false) {
|
if ($footerViewFile === false) {
|
||||||
@@ -261,7 +257,7 @@ class TimeEntryController extends Controller
|
|||||||
->putFileAs($folderPath, new File($tempFolder->path($filenameTemp)), $filename);
|
->putFileAs($folderPath, new File($tempFolder->path($filenameTemp)), $filename);
|
||||||
} else {
|
} else {
|
||||||
Excel::store(
|
Excel::store(
|
||||||
new TimeEntriesDetailedExport($timeEntriesQuery, $format, $timezone, $localizationService),
|
new TimeEntriesDetailedExport($timeEntriesQuery, $format, $timezone),
|
||||||
$path,
|
$path,
|
||||||
config('filesystems.private'),
|
config('filesystems.private'),
|
||||||
$format->getExportPackageType(),
|
$format->getExportPackageType(),
|
||||||
@@ -398,7 +394,6 @@ class TimeEntryController extends Controller
|
|||||||
);
|
);
|
||||||
$currency = $organization->currency;
|
$currency = $organization->currency;
|
||||||
$timezone = app(TimezoneService::class)->getTimezoneFromUser($this->user());
|
$timezone = app(TimezoneService::class)->getTimezoneFromUser($this->user());
|
||||||
$localizationService = LocalizationService::forOrganization($organization);
|
|
||||||
|
|
||||||
$filename = 'time-entries-report-'.now()->format('Y-m-d_H-i-s').'.'.$format->getFileExtension();
|
$filename = 'time-entries-report-'.now()->format('Y-m-d_H-i-s').'.'.$format->getFileExtension();
|
||||||
$folderPath = 'exports';
|
$folderPath = 'exports';
|
||||||
@@ -424,12 +419,9 @@ class TimeEntryController extends Controller
|
|||||||
'currency' => $currency,
|
'currency' => $currency,
|
||||||
'group' => $group,
|
'group' => $group,
|
||||||
'subGroup' => $subGroup,
|
'subGroup' => $subGroup,
|
||||||
'timezone' => $timezone,
|
|
||||||
'start' => $request->getStart()->timezone($timezone),
|
'start' => $request->getStart()->timezone($timezone),
|
||||||
'end' => $request->getEnd()->timezone($timezone),
|
'end' => $request->getEnd()->timezone($timezone),
|
||||||
'debug' => $debug,
|
'debug' => $debug,
|
||||||
'localization' => $localizationService,
|
|
||||||
'showBillableRate' => $showBillableRate,
|
|
||||||
]);
|
]);
|
||||||
$footerViewFile = file_get_contents(resource_path('views/reports/time-entry-aggregate/pdf-footer.blade.php'));
|
$footerViewFile = file_get_contents(resource_path('views/reports/time-entry-aggregate/pdf-footer.blade.php'));
|
||||||
if ($footerViewFile === false) {
|
if ($footerViewFile === false) {
|
||||||
@@ -458,7 +450,7 @@ class TimeEntryController extends Controller
|
|||||||
->putFileAs($folderPath, new File($tempFolder->path($filenameTemp)), $filename);
|
->putFileAs($folderPath, new File($tempFolder->path($filenameTemp)), $filename);
|
||||||
} else {
|
} else {
|
||||||
Excel::store(
|
Excel::store(
|
||||||
new TimeEntriesReportExport($aggregatedData, $format, $currency, $group, $subGroup, $showBillableRate),
|
new TimeEntriesReportExport($aggregatedData, $format, $currency, $group, $subGroup),
|
||||||
$path,
|
$path,
|
||||||
config('filesystems.private'),
|
config('filesystems.private'),
|
||||||
$format->getExportPackageType(),
|
$format->getExportPackageType(),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace App\Http\Controllers\Api\V1;
|
|||||||
|
|
||||||
use App\Http\Resources\V1\User\UserResource;
|
use App\Http\Resources\V1\User\UserResource;
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
@@ -18,7 +19,7 @@ class UserController extends Controller
|
|||||||
*
|
*
|
||||||
* @throws AuthorizationException
|
* @throws AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function me(): UserResource
|
public function me(): JsonResource
|
||||||
{
|
{
|
||||||
$user = $this->user();
|
$user = $this->user();
|
||||||
|
|
||||||
|
|||||||
@@ -43,10 +43,7 @@ class Controller extends BaseController
|
|||||||
/** @var Member|null $member */
|
/** @var Member|null $member */
|
||||||
$member = Member::query()->whereBelongsTo($organization, 'organization')->whereBelongsTo($user, 'user')->first();
|
$member = Member::query()->whereBelongsTo($organization, 'organization')->whereBelongsTo($user, 'user')->first();
|
||||||
if ($member === null) {
|
if ($member === null) {
|
||||||
Log::error('This function should only be called in authenticated context after checking the user is a member of the organization', [
|
Log::error('This function should only be called in authenticated context after checking the user is a member of the organization');
|
||||||
'user' => $user->getKey(),
|
|
||||||
'organization' => $organization->getKey(),
|
|
||||||
]);
|
|
||||||
throw new AuthorizationException;
|
throw new AuthorizationException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Redirect;
|
use Illuminate\Support\Facades\Redirect;
|
||||||
use Illuminate\Support\Facades\URL;
|
use Illuminate\Support\Facades\URL;
|
||||||
@@ -19,7 +20,8 @@ class EnsureEmailIsVerified
|
|||||||
{
|
{
|
||||||
if (! app()->isLocal()) {
|
if (! app()->isLocal()) {
|
||||||
if ($request->user() === null ||
|
if ($request->user() === null ||
|
||||||
(! $request->user()->hasVerifiedEmail())) {
|
($request->user() instanceof MustVerifyEmail &&
|
||||||
|
! $request->user()->hasVerifiedEmail())) {
|
||||||
return $request->expectsJson()
|
return $request->expectsJson()
|
||||||
? abort(403, 'Your email address is not verified.')
|
? abort(403, 'Your email address is not verified.')
|
||||||
: Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice'));
|
: Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice'));
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ class HandleInertiaRequests extends Middleware
|
|||||||
public function share(Request $request): array
|
public function share(Request $request): array
|
||||||
{
|
{
|
||||||
$hasBilling = Module::has('Billing') && Module::isEnabled('Billing');
|
$hasBilling = Module::has('Billing') && Module::isEnabled('Billing');
|
||||||
$hasInvoicing = Module::has('Invoicing') && Module::isEnabled('Invoicing');
|
|
||||||
|
|
||||||
/** @var BillingContract $billing */
|
/** @var BillingContract $billing */
|
||||||
$billing = app(BillingContract::class);
|
$billing = app(BillingContract::class);
|
||||||
@@ -49,8 +48,7 @@ class HandleInertiaRequests extends Middleware
|
|||||||
|
|
||||||
return array_merge(parent::share($request), [
|
return array_merge(parent::share($request), [
|
||||||
'has_billing_extension' => $hasBilling,
|
'has_billing_extension' => $hasBilling,
|
||||||
'has_invoicing_extension' => $hasInvoicing,
|
'billing' => $billing !== null && $currentOrganization !== null ? [
|
||||||
'billing' => $currentOrganization !== null ? [
|
|
||||||
'has_subscription' => $billing->hasSubscription($currentOrganization),
|
'has_subscription' => $billing->hasSubscription($currentOrganization),
|
||||||
'has_trial' => $billing->hasTrial($currentOrganization),
|
'has_trial' => $billing->hasTrial($currentOrganization),
|
||||||
'trial_until' => $billing->getTrialUntil($currentOrganization)?->toIso8601ZuluString(),
|
'trial_until' => $billing->getTrialUntil($currentOrganization)?->toIso8601ZuluString(),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class ShareInertiaData
|
|||||||
{
|
{
|
||||||
/** @var PermissionStore $permissions */
|
/** @var PermissionStore $permissions */
|
||||||
$permissions = app(PermissionStore::class);
|
$permissions = app(PermissionStore::class);
|
||||||
Inertia::share([
|
Inertia::share(array_filter([
|
||||||
'jetstream' => function () use ($request) {
|
'jetstream' => function () use ($request) {
|
||||||
/** @var User|null $user */
|
/** @var User|null $user */
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
@@ -101,7 +101,7 @@ class ShareInertiaData
|
|||||||
return [$key => $bag->messages()];
|
return [$key => $bag->messages()];
|
||||||
})->all();
|
})->all();
|
||||||
},
|
},
|
||||||
]);
|
]));
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\ApiToken;
|
namespace App\Http\Requests\V1\ApiToken;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class ApiTokenStoreRequest extends BaseFormRequest
|
class ApiTokenStoreRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Http\Requests\V1;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class BaseFormRequest extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @return list<string>
|
|
||||||
*/
|
|
||||||
protected function moneyRules(bool $bigInt = false): array
|
|
||||||
{
|
|
||||||
$rules = [
|
|
||||||
'integer',
|
|
||||||
'min:0',
|
|
||||||
];
|
|
||||||
if ($bigInt) {
|
|
||||||
$rules[] = 'max:9223372036854775807';
|
|
||||||
} else {
|
|
||||||
$rules[] = 'max:2147483647';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rules;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Client;
|
namespace App\Http\Requests\V1\Client;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class ClientIndexRequest extends BaseFormRequest
|
class ClientIndexRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Client;
|
namespace App\Http\Requests\V1\Client;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class ClientStoreRequest extends BaseFormRequest
|
class ClientStoreRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Client;
|
namespace App\Http\Requests\V1\Client;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
* @property Client|null $client Client from model binding
|
* @property Client|null $client Client from model binding
|
||||||
*/
|
*/
|
||||||
class ClientUpdateRequest extends BaseFormRequest
|
class ClientUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Import;
|
namespace App\Http\Requests\V1\Import;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class ImportRequest extends BaseFormRequest
|
class ImportRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Invitation;
|
namespace App\Http\Requests\V1\Invitation;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization
|
* @property Organization $organization
|
||||||
*/
|
*/
|
||||||
class InvitationIndexRequest extends BaseFormRequest
|
class InvitationIndexRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -5,15 +5,18 @@ declare(strict_types=1);
|
|||||||
namespace App\Http\Requests\V1\Invitation;
|
namespace App\Http\Requests\V1\Invitation;
|
||||||
|
|
||||||
use App\Enums\Role;
|
use App\Enums\Role;
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
|
use App\Models\OrganizationInvitation;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization
|
* @property Organization $organization
|
||||||
*/
|
*/
|
||||||
class InvitationStoreRequest extends BaseFormRequest
|
class InvitationStoreRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
@@ -26,6 +29,10 @@ class InvitationStoreRequest extends BaseFormRequest
|
|||||||
'email' => [
|
'email' => [
|
||||||
'required',
|
'required',
|
||||||
'email',
|
'email',
|
||||||
|
UniqueEloquent::make(OrganizationInvitation::class, 'email', function (Builder $builder): Builder {
|
||||||
|
/** @var Builder<OrganizationInvitation> $builder */
|
||||||
|
return $builder->whereBelongsTo($this->organization, 'organization');
|
||||||
|
})->withCustomTranslation('validation.invitation_already_exists'),
|
||||||
],
|
],
|
||||||
'role' => [
|
'role' => [
|
||||||
'required',
|
'required',
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Http\Requests\V1\Member;
|
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property Organization $organization
|
|
||||||
*/
|
|
||||||
class MemberDestroyRequest extends BaseFormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array<string, array<string|ValidationRule>>
|
|
||||||
*/
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'delete_related' => [
|
|
||||||
'string',
|
|
||||||
'in:true,false',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDeleteRelated(): bool
|
|
||||||
{
|
|
||||||
return $this->input('delete_related', 'false') === 'true';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,14 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Member;
|
namespace App\Http\Requests\V1\Member;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization
|
* @property Organization $organization
|
||||||
*/
|
*/
|
||||||
class MemberIndexRequest extends BaseFormRequest
|
class MemberIndexRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Member;
|
namespace App\Http\Requests\V1\Member;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization
|
* @property Organization $organization
|
||||||
*/
|
*/
|
||||||
class MemberMergeIntoRequest extends BaseFormRequest
|
class MemberMergeIntoRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ declare(strict_types=1);
|
|||||||
namespace App\Http\Requests\V1\Member;
|
namespace App\Http\Requests\V1\Member;
|
||||||
|
|
||||||
use App\Enums\Role;
|
use App\Enums\Role;
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization
|
* @property Organization $organization
|
||||||
*/
|
*/
|
||||||
class MemberUpdateRequest extends BaseFormRequest
|
class MemberUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
@@ -27,12 +27,12 @@ class MemberUpdateRequest extends BaseFormRequest
|
|||||||
'string',
|
'string',
|
||||||
Rule::enum(Role::class),
|
Rule::enum(Role::class),
|
||||||
],
|
],
|
||||||
'billable_rate' => array_merge(
|
'billable_rate' => [
|
||||||
[
|
'nullable',
|
||||||
'nullable',
|
'integer',
|
||||||
],
|
'min:0',
|
||||||
$this->moneyRules()
|
'max:2147483647',
|
||||||
),
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,98 +4,44 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Organization;
|
namespace App\Http\Requests\V1\Organization;
|
||||||
|
|
||||||
use App\Enums\CurrencyFormat;
|
|
||||||
use App\Enums\DateFormat;
|
|
||||||
use App\Enums\IntervalFormat;
|
|
||||||
use App\Enums\NumberFormat;
|
|
||||||
use App\Enums\TimeFormat;
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class OrganizationUpdateRequest extends BaseFormRequest
|
class OrganizationUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
*
|
*
|
||||||
* @return array<string, array<string|\Illuminate\Contracts\Validation\Rule>>
|
* @return array<string, array<string|ValidationRule>>
|
||||||
*/
|
*/
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => [
|
'name' => [
|
||||||
|
'required',
|
||||||
'string',
|
'string',
|
||||||
'max:255',
|
'max:255',
|
||||||
],
|
],
|
||||||
'billable_rate' => array_merge(
|
'billable_rate' => [
|
||||||
[
|
'nullable',
|
||||||
'nullable',
|
'integer',
|
||||||
],
|
'min:0',
|
||||||
$this->moneyRules()
|
'max:2147483647',
|
||||||
),
|
],
|
||||||
'employees_can_see_billable_rates' => [
|
'employees_can_see_billable_rates' => [
|
||||||
'boolean',
|
'boolean',
|
||||||
],
|
],
|
||||||
'number_format' => [
|
|
||||||
Rule::enum(NumberFormat::class),
|
|
||||||
],
|
|
||||||
'currency_format' => [
|
|
||||||
Rule::enum(CurrencyFormat::class),
|
|
||||||
],
|
|
||||||
'date_format' => [
|
|
||||||
Rule::enum(DateFormat::class),
|
|
||||||
],
|
|
||||||
'interval_format' => [
|
|
||||||
Rule::enum(IntervalFormat::class),
|
|
||||||
],
|
|
||||||
'time_format' => [
|
|
||||||
Rule::enum(TimeFormat::class),
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName(): ?string
|
|
||||||
{
|
|
||||||
return $this->has('name') ? (string) $this->input('name') : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNumberFormat(): ?NumberFormat
|
|
||||||
{
|
|
||||||
return $this->has('number_format') ? NumberFormat::from($this->input('number_format')) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCurrencyFormat(): ?CurrencyFormat
|
|
||||||
{
|
|
||||||
return $this->has('currency_format') ? CurrencyFormat::from($this->input('currency_format')) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDateFormat(): ?DateFormat
|
|
||||||
{
|
|
||||||
return $this->has('date_format') ? DateFormat::from($this->input('date_format')) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getIntervalFormat(): ?IntervalFormat
|
|
||||||
{
|
|
||||||
return $this->has('interval_format') ? IntervalFormat::from($this->input('interval_format')) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTimeFormat(): ?TimeFormat
|
|
||||||
{
|
|
||||||
return $this->has('time_format') ? TimeFormat::from($this->input('time_format')) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBillableRate(): ?int
|
public function getBillableRate(): ?int
|
||||||
{
|
{
|
||||||
$input = $this->input('billable_rate');
|
$input = $this->input('billable_rate');
|
||||||
|
|
||||||
return $input !== null && $input !== 0 ? (int) $this->input('billable_rate') : null;
|
return $input !== null && $input !== 0 ? (int) $this->input('billable_rate') : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEmployeesCanSeeBillableRates(): ?bool
|
|
||||||
{
|
|
||||||
return $this->has('employees_can_see_billable_rates') ? $this->boolean('employees_can_see_billable_rates') : null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Project;
|
namespace App\Http\Requests\V1\Project;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class ProjectIndexRequest extends BaseFormRequest
|
class ProjectIndexRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,21 +4,20 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Project;
|
namespace App\Http\Requests\V1\Project;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Rules\ColorRule;
|
use App\Rules\ColorRule;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class ProjectStoreRequest extends BaseFormRequest
|
class ProjectStoreRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
@@ -28,7 +27,6 @@ class ProjectStoreRequest extends BaseFormRequest
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
// Name of the project, the name needs to be unique per client and organization
|
|
||||||
'name' => [
|
'name' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'string',
|
||||||
@@ -36,13 +34,7 @@ class ProjectStoreRequest extends BaseFormRequest
|
|||||||
'max:255',
|
'max:255',
|
||||||
UniqueEloquent::make(Project::class, 'name', function (Builder $builder): Builder {
|
UniqueEloquent::make(Project::class, 'name', function (Builder $builder): Builder {
|
||||||
/** @var Builder<Project> $builder */
|
/** @var Builder<Project> $builder */
|
||||||
$clientId = $this->input('client_id');
|
return $builder->whereBelongsTo($this->organization, 'organization');
|
||||||
if (! is_string($clientId) || ! Str::isUuid($clientId)) {
|
|
||||||
$clientId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $builder->whereBelongsTo($this->organization, 'organization')
|
|
||||||
->where('client_id', $clientId);
|
|
||||||
})->withCustomTranslation('validation.project_name_already_exists'),
|
})->withCustomTranslation('validation.project_name_already_exists'),
|
||||||
],
|
],
|
||||||
'color' => [
|
'color' => [
|
||||||
@@ -55,15 +47,14 @@ class ProjectStoreRequest extends BaseFormRequest
|
|||||||
'required',
|
'required',
|
||||||
'boolean',
|
'boolean',
|
||||||
],
|
],
|
||||||
'billable_rate' => array_merge(
|
'billable_rate' => [
|
||||||
[
|
'nullable',
|
||||||
'nullable',
|
'integer',
|
||||||
],
|
'min:0',
|
||||||
$this->moneyRules()
|
'max:2147483647',
|
||||||
),
|
],
|
||||||
// ID of the client
|
// ID of the client
|
||||||
'client_id' => [
|
'client_id' => [
|
||||||
'present',
|
|
||||||
'nullable',
|
'nullable',
|
||||||
ExistsEloquent::make(Client::class, null, function (Builder $builder): Builder {
|
ExistsEloquent::make(Client::class, null, function (Builder $builder): Builder {
|
||||||
/** @var Builder<Client> $builder */
|
/** @var Builder<Client> $builder */
|
||||||
|
|||||||
@@ -4,14 +4,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Project;
|
namespace App\Http\Requests\V1\Project;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Rules\ColorRule;
|
use App\Rules\ColorRule;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@ use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
|||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
* @property Project|null $project Project from model binding
|
* @property Project|null $project Project from model binding
|
||||||
*/
|
*/
|
||||||
class ProjectUpdateRequest extends BaseFormRequest
|
class ProjectUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
@@ -35,13 +34,7 @@ class ProjectUpdateRequest extends BaseFormRequest
|
|||||||
'max:255',
|
'max:255',
|
||||||
UniqueEloquent::make(Project::class, 'name', function (Builder $builder): Builder {
|
UniqueEloquent::make(Project::class, 'name', function (Builder $builder): Builder {
|
||||||
/** @var Builder<Project> $builder */
|
/** @var Builder<Project> $builder */
|
||||||
$clientId = $this->input('client_id');
|
return $builder->whereBelongsTo($this->organization, 'organization');
|
||||||
if (! is_string($clientId) || ! Str::isUuid($clientId)) {
|
|
||||||
$clientId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $builder->whereBelongsTo($this->organization, 'organization')
|
|
||||||
->where('client_id', $clientId);
|
|
||||||
})->ignore($this->project?->getKey())->withCustomTranslation('validation.project_name_already_exists'),
|
})->ignore($this->project?->getKey())->withCustomTranslation('validation.project_name_already_exists'),
|
||||||
],
|
],
|
||||||
'color' => [
|
'color' => [
|
||||||
@@ -61,18 +54,18 @@ class ProjectUpdateRequest extends BaseFormRequest
|
|||||||
'boolean',
|
'boolean',
|
||||||
],
|
],
|
||||||
'client_id' => [
|
'client_id' => [
|
||||||
'present',
|
|
||||||
'nullable',
|
'nullable',
|
||||||
ExistsEloquent::make(Client::class, null, function (Builder $builder): Builder {
|
ExistsEloquent::make(Client::class, null, function (Builder $builder): Builder {
|
||||||
/** @var Builder<Client> $builder */
|
/** @var Builder<Client> $builder */
|
||||||
return $builder->whereBelongsTo($this->organization, 'organization');
|
return $builder->whereBelongsTo($this->organization, 'organization');
|
||||||
})->uuid(),
|
})->uuid(),
|
||||||
],
|
],
|
||||||
'billable_rate' => array_merge([
|
'billable_rate' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
|
'integer',
|
||||||
|
'min:0',
|
||||||
|
'max:2147483647',
|
||||||
],
|
],
|
||||||
$this->moneyRules()
|
|
||||||
),
|
|
||||||
// Estimated time in seconds
|
// Estimated time in seconds
|
||||||
'estimated_time' => [
|
'estimated_time' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\ProjectMember;
|
namespace App\Http\Requests\V1\ProjectMember;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class ProjectMemberStoreRequest extends BaseFormRequest
|
class ProjectMemberStoreRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
@@ -31,12 +31,12 @@ class ProjectMemberStoreRequest extends BaseFormRequest
|
|||||||
return $builder->whereBelongsTo($this->organization, 'organization');
|
return $builder->whereBelongsTo($this->organization, 'organization');
|
||||||
})->uuid(),
|
})->uuid(),
|
||||||
],
|
],
|
||||||
'billable_rate' => array_merge(
|
'billable_rate' => [
|
||||||
[
|
'nullable',
|
||||||
'nullable',
|
'integer',
|
||||||
],
|
'min:0',
|
||||||
$this->moneyRules()
|
'max:2147483647',
|
||||||
),
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\ProjectMember;
|
namespace App\Http\Requests\V1\ProjectMember;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class ProjectMemberUpdateRequest extends BaseFormRequest
|
class ProjectMemberUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
@@ -21,12 +21,12 @@ class ProjectMemberUpdateRequest extends BaseFormRequest
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'billable_rate' => array_merge(
|
'billable_rate' => [
|
||||||
[
|
'nullable',
|
||||||
'nullable',
|
'integer',
|
||||||
],
|
'min:0',
|
||||||
$this->moneyRules()
|
'max:2147483647',
|
||||||
),
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,17 @@ namespace App\Http\Requests\V1\Report;
|
|||||||
use App\Enums\TimeEntryAggregationType;
|
use App\Enums\TimeEntryAggregationType;
|
||||||
use App\Enums\TimeEntryAggregationTypeInterval;
|
use App\Enums\TimeEntryAggregationTypeInterval;
|
||||||
use App\Enums\Weekday;
|
use App\Enums\Weekday;
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\Rule as LegacyValidationRule;
|
use Illuminate\Contracts\Validation\Rule as LegacyValidationRule;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class ReportStoreRequest extends BaseFormRequest
|
class ReportStoreRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
@@ -40,7 +40,7 @@ class ReportStoreRequest extends BaseFormRequest
|
|||||||
'required',
|
'required',
|
||||||
'boolean',
|
'boolean',
|
||||||
],
|
],
|
||||||
// After this date the report will be automatically set to private (is_public=false) (Format: "Y-m-d\TH:i:s\Z", UTC timezone, Example: "2000-02-22T14:58:59Z")
|
// After this date the report will be automatically set to private (is_public=false) (ISO 8601 format, UTC timezone)
|
||||||
'public_until' => [
|
'public_until' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
'date_format:Y-m-d\TH:i:s\Z',
|
'date_format:Y-m-d\TH:i:s\Z',
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Report;
|
namespace App\Http\Requests\V1\Report;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class ReportUpdateRequest extends BaseFormRequest
|
class ReportUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Tag;
|
namespace App\Http\Requests\V1\Tag;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Tag;
|
use App\Models\Tag;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class TagStoreRequest extends BaseFormRequest
|
class TagStoreRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Tag;
|
namespace App\Http\Requests\V1\Tag;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Tag;
|
use App\Models\Tag;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
* @property Tag|null $tag Tag from model binding
|
* @property Tag|null $tag Tag from model binding
|
||||||
*/
|
*/
|
||||||
class TagUpdateRequest extends BaseFormRequest
|
class TagUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,19 +4,19 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Task;
|
namespace App\Http\Requests\V1\Task;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Service\PermissionStore;
|
use App\Service\PermissionStore;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class TaskIndexRequest extends BaseFormRequest
|
class TaskIndexRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,19 +4,19 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Task;
|
namespace App\Http\Requests\V1\Task;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class TaskStoreRequest extends BaseFormRequest
|
class TaskStoreRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\Task;
|
namespace App\Http\Requests\V1\Task;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
* @property Task|null $task Task from model binding
|
* @property Task|null $task Task from model binding
|
||||||
*/
|
*/
|
||||||
class TaskUpdateRequest extends BaseFormRequest
|
class TaskUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ namespace App\Http\Requests\V1\TimeEntry;
|
|||||||
use App\Enums\ExportFormat;
|
use App\Enums\ExportFormat;
|
||||||
use App\Enums\TimeEntryAggregationType;
|
use App\Enums\TimeEntryAggregationType;
|
||||||
use App\Enums\TimeEntryAggregationTypeInterval;
|
use App\Enums\TimeEntryAggregationTypeInterval;
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
@@ -17,6 +16,7 @@ use App\Models\Task;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
@@ -24,7 +24,7 @@ use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
|||||||
/**
|
/**
|
||||||
* @property Organization $organization
|
* @property Organization $organization
|
||||||
*/
|
*/
|
||||||
class TimeEntryAggregateExportRequest extends BaseFormRequest
|
class TimeEntryAggregateExportRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||||||
namespace App\Http\Requests\V1\TimeEntry;
|
namespace App\Http\Requests\V1\TimeEntry;
|
||||||
|
|
||||||
use App\Enums\TimeEntryAggregationType;
|
use App\Enums\TimeEntryAggregationType;
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
@@ -15,6 +14,7 @@ use App\Models\Task;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
@@ -22,7 +22,7 @@ use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
|||||||
/**
|
/**
|
||||||
* @property Organization $organization
|
* @property Organization $organization
|
||||||
*/
|
*/
|
||||||
class TimeEntryAggregateRequest extends BaseFormRequest
|
class TimeEntryAggregateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\TimeEntry;
|
namespace App\Http\Requests\V1\TimeEntry;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class TimeEntryDestroyMultipleRequest extends BaseFormRequest
|
class TimeEntryDestroyMultipleRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\TimeEntry;
|
namespace App\Http\Requests\V1\TimeEntry;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
@@ -13,12 +12,13 @@ use App\Models\Tag;
|
|||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization
|
* @property Organization $organization
|
||||||
*/
|
*/
|
||||||
class TimeEntryIndexRequest extends BaseFormRequest
|
class TimeEntryIndexRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\TimeEntry;
|
namespace App\Http\Requests\V1\TimeEntry;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
@@ -12,12 +11,13 @@ use App\Models\Tag;
|
|||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class TimeEntryStoreRequest extends BaseFormRequest
|
class TimeEntryStoreRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
@@ -59,12 +59,12 @@ class TimeEntryStoreRequest extends BaseFormRequest
|
|||||||
->where('project_id', $this->input('project_id'));
|
->where('project_id', $this->input('project_id'));
|
||||||
})->uuid()->withMessage(__('validation.task_belongs_to_project')),
|
})->uuid()->withMessage(__('validation.task_belongs_to_project')),
|
||||||
],
|
],
|
||||||
// Start of time entry (Format: "Y-m-d\TH:i:s\Z", UTC timezone, Example: "2000-02-22T14:58:59Z")
|
// Start of time entry (ISO 8601 format, UTC timezone)
|
||||||
'start' => [
|
'start' => [
|
||||||
'required',
|
'required',
|
||||||
'date_format:Y-m-d\TH:i:s\Z',
|
'date_format:Y-m-d\TH:i:s\Z',
|
||||||
],
|
],
|
||||||
// End of time entry (Format: "Y-m-d\TH:i:s\Z", UTC timezone, Example: "2000-02-22T14:58:59Z")
|
// End of time entry (ISO 8601 format, UTC timezone)
|
||||||
'end' => [
|
'end' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
'date_format:Y-m-d\TH:i:s\Z',
|
'date_format:Y-m-d\TH:i:s\Z',
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\TimeEntry;
|
namespace App\Http\Requests\V1\TimeEntry;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
@@ -12,12 +11,13 @@ use App\Models\Tag;
|
|||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class TimeEntryUpdateMultipleRequest extends BaseFormRequest
|
class TimeEntryUpdateMultipleRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Requests\V1\TimeEntry;
|
namespace App\Http\Requests\V1\TimeEntry;
|
||||||
|
|
||||||
use App\Http\Requests\V1\BaseFormRequest;
|
|
||||||
use App\Models\Member;
|
use App\Models\Member;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
@@ -12,12 +11,13 @@ use App\Models\Tag;
|
|||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use Illuminate\Contracts\Validation\ValidationRule;
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property Organization $organization Organization from model binding
|
* @property Organization $organization Organization from model binding
|
||||||
*/
|
*/
|
||||||
class TimeEntryUpdateRequest extends BaseFormRequest
|
class TimeEntryUpdateRequest extends FormRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the validation rules that apply to the request.
|
* Get the validation rules that apply to the request.
|
||||||
@@ -59,11 +59,11 @@ class TimeEntryUpdateRequest extends BaseFormRequest
|
|||||||
->where('project_id', $this->input('project_id'));
|
->where('project_id', $this->input('project_id'));
|
||||||
})->uuid()->withMessage(__('validation.task_belongs_to_project')),
|
})->uuid()->withMessage(__('validation.task_belongs_to_project')),
|
||||||
],
|
],
|
||||||
// Start of time entry (Format: "Y-m-d\TH:i:s\Z", UTC timezone, Example: "2000-02-22T14:58:59Z")
|
// Start of time entry (ISO 8601 format, UTC timezone)
|
||||||
'start' => [
|
'start' => [
|
||||||
'date_format:Y-m-d\TH:i:s\Z',
|
'date_format:Y-m-d\TH:i:s\Z',
|
||||||
],
|
],
|
||||||
// End of time entry (Format: "Y-m-d\TH:i:s\Z", UTC timezone, Example: "2000-02-22T14:58:59Z")
|
// End of time entry (ISO 8601 format, UTC timezone)
|
||||||
'end' => [
|
'end' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
'date_format:Y-m-d\TH:i:s\Z',
|
'date_format:Y-m-d\TH:i:s\Z',
|
||||||
|
|||||||
@@ -12,10 +12,6 @@ abstract class BaseResource extends JsonResource
|
|||||||
protected function formatDateTime(?Carbon $carbon): ?string
|
protected function formatDateTime(?Carbon $carbon): ?string
|
||||||
{
|
{
|
||||||
return $carbon?->toIso8601ZuluString();
|
return $carbon?->toIso8601ZuluString();
|
||||||
}
|
|
||||||
|
|
||||||
protected function formatDate(?Carbon $carbon): ?string
|
|
||||||
{
|
|
||||||
return $carbon?->format('Y-m-d');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Resources\V1\Organization;
|
namespace App\Http\Resources\V1\Organization;
|
||||||
|
|
||||||
use App\Enums\CurrencyFormat;
|
|
||||||
use App\Enums\DateFormat;
|
|
||||||
use App\Enums\IntervalFormat;
|
|
||||||
use App\Enums\NumberFormat;
|
|
||||||
use App\Enums\TimeFormat;
|
|
||||||
use App\Http\Resources\V1\BaseResource;
|
use App\Http\Resources\V1\BaseResource;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Service\CurrencyService;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,8 +34,6 @@ class OrganizationResource extends BaseResource
|
|||||||
*/
|
*/
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
$currencyService = app(CurrencyService::class);
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
/** @var string $id ID */
|
/** @var string $id ID */
|
||||||
'id' => $this->resource->id,
|
'id' => $this->resource->id,
|
||||||
@@ -55,18 +47,6 @@ class OrganizationResource extends BaseResource
|
|||||||
'employees_can_see_billable_rates' => $this->resource->employees_can_see_billable_rates,
|
'employees_can_see_billable_rates' => $this->resource->employees_can_see_billable_rates,
|
||||||
/** @var string $currency Currency code (ISO 4217) */
|
/** @var string $currency Currency code (ISO 4217) */
|
||||||
'currency' => $this->resource->currency,
|
'currency' => $this->resource->currency,
|
||||||
/** @var string $currency_symbol Currency symbol */
|
|
||||||
'currency_symbol' => $currencyService->getCurrencySymbol($this->resource->currency),
|
|
||||||
/** @var NumberFormat $number_format Number format */
|
|
||||||
'number_format' => $this->resource->number_format->value,
|
|
||||||
/** @var CurrencyFormat $currency_format Currency format */
|
|
||||||
'currency_format' => $this->resource->currency_format->value,
|
|
||||||
/** @var DateFormat $date_format Date format */
|
|
||||||
'date_format' => $this->resource->date_format->value,
|
|
||||||
/** @var IntervalFormat $interval_format Interval format */
|
|
||||||
'interval_format' => $this->resource->interval_format->value,
|
|
||||||
/** @var TimeFormat $time_format Time format */
|
|
||||||
'time_format' => $this->resource->time_format->value,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,15 @@ use App\Http\Resources\PaginatedResourceCollection;
|
|||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
|
||||||
class ProjectCollection extends ResourceCollection implements PaginatedResourceCollection
|
class ProjectCollection extends ResourceCollection implements PaginatedResourceCollection
|
||||||
{
|
{
|
||||||
private bool $showBillableRates;
|
private bool $showBillableRates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param LengthAwarePaginator<Project> $resource
|
||||||
|
*/
|
||||||
public function __construct($resource, bool $showBillableRates)
|
public function __construct($resource, bool $showBillableRates)
|
||||||
{
|
{
|
||||||
parent::__construct($resource);
|
parent::__construct($resource);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class DetailedReportResource extends BaseResource
|
|||||||
/** @var bool $is_public Whether the report can be accessed via an external link */
|
/** @var bool $is_public Whether the report can be accessed via an external link */
|
||||||
'is_public' => $this->resource->is_public,
|
'is_public' => $this->resource->is_public,
|
||||||
/** @var string|null $public_until Date until the report is public */
|
/** @var string|null $public_until Date until the report is public */
|
||||||
'public_until' => $this->formatDateTime($this->resource->public_until),
|
'public_until' => $this->resource->public_until?->toIso8601ZuluString(),
|
||||||
/** @var string|null $shareable_link Get link to access the report externally, not set if the report is private */
|
/** @var string|null $shareable_link Get link to access the report externally, not set if the report is private */
|
||||||
'shareable_link' => $this->resource->getShareableLink(),
|
'shareable_link' => $this->resource->getShareableLink(),
|
||||||
'properties' => [
|
'properties' => [
|
||||||
@@ -41,9 +41,9 @@ class DetailedReportResource extends BaseResource
|
|||||||
/** @var string $history_group Type of grouping of the historic aggregation (time chart) */
|
/** @var string $history_group Type of grouping of the historic aggregation (time chart) */
|
||||||
'history_group' => $this->resource->properties->historyGroup->value,
|
'history_group' => $this->resource->properties->historyGroup->value,
|
||||||
/** @var string $start Start date of the report */
|
/** @var string $start Start date of the report */
|
||||||
'start' => $this->formatDateTime($this->resource->properties->start),
|
'start' => $this->resource->properties->start->toIso8601ZuluString(),
|
||||||
/** @var string $end End date of the report */
|
/** @var string $end End date of the report */
|
||||||
'end' => $this->formatDateTime($this->resource->properties->end),
|
'end' => $this->resource->properties->end->toIso8601ZuluString(),
|
||||||
/** @var bool|null $active Whether the report is active */
|
/** @var bool|null $active Whether the report is active */
|
||||||
'active' => $this->resource->properties->active,
|
'active' => $this->resource->properties->active,
|
||||||
/** @var array<string>|null $member_ids Filter by multiple member IDs, member IDs are OR combined */
|
/** @var array<string>|null $member_ids Filter by multiple member IDs, member IDs are OR combined */
|
||||||
@@ -60,9 +60,9 @@ class DetailedReportResource extends BaseResource
|
|||||||
'task_ids' => $this->resource->properties->taskIds?->toArray(),
|
'task_ids' => $this->resource->properties->taskIds?->toArray(),
|
||||||
],
|
],
|
||||||
/** @var string $created_at Date when the report was created */
|
/** @var string $created_at Date when the report was created */
|
||||||
'created_at' => $this->formatDateTime($this->resource->created_at),
|
'created_at' => $this->resource->created_at?->toIso8601ZuluString(),
|
||||||
/** @var string $updated_at Date when the report was last updated */
|
/** @var string $updated_at Date when the report was last updated */
|
||||||
'updated_at' => $this->formatDateTime($this->resource->updated_at),
|
'updated_at' => $this->resource->updated_at?->toIso8601ZuluString(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Http\Resources\V1\Report;
|
namespace App\Http\Resources\V1\Report;
|
||||||
|
|
||||||
use App\Enums\CurrencyFormat;
|
|
||||||
use App\Enums\DateFormat;
|
|
||||||
use App\Enums\IntervalFormat;
|
|
||||||
use App\Enums\NumberFormat;
|
|
||||||
use App\Enums\TimeFormat;
|
|
||||||
use App\Http\Resources\V1\BaseResource;
|
use App\Http\Resources\V1\BaseResource;
|
||||||
use App\Models\Report;
|
use App\Models\Report;
|
||||||
use App\Service\CurrencyService;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,29 +64,15 @@ class DetailedWithDataReportResource extends BaseResource
|
|||||||
*/
|
*/
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
$currencyService = app(CurrencyService::class);
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
/** @var string $name Name */
|
/** @var string $name Name */
|
||||||
'name' => $this->resource->name,
|
'name' => $this->resource->name,
|
||||||
/** @var string|null $email Description */
|
/** @var string|null $email Description */
|
||||||
'description' => $this->resource->description,
|
'description' => $this->resource->description,
|
||||||
/** @var string|null $public_until Date until the report is public */
|
/** @var string|null $public_until Date until the report is public */
|
||||||
'public_until' => $this->formatDateTime($this->resource->public_until),
|
'public_until' => $this->resource->public_until?->toIso8601ZuluString(),
|
||||||
/** @var string $currency Currency code (ISO 4217) */
|
/** @var string $currency Currency code (ISO 4217) */
|
||||||
'currency' => $this->resource->organization->currency,
|
'currency' => $this->resource->organization->currency,
|
||||||
/** @var NumberFormat $number_format Number format */
|
|
||||||
'number_format' => $this->resource->organization->number_format->value,
|
|
||||||
/** @var CurrencyFormat $currency_format Currency format */
|
|
||||||
'currency_format' => $this->resource->organization->currency_format->value,
|
|
||||||
/** @var string $currency_symbol Currency symbol */
|
|
||||||
'currency_symbol' => $currencyService->getCurrencySymbol($this->resource->organization->currency),
|
|
||||||
/** @var DateFormat $date_format Date format */
|
|
||||||
'date_format' => $this->resource->organization->date_format->value,
|
|
||||||
/** @var IntervalFormat $interval_format Interval format */
|
|
||||||
'interval_format' => $this->resource->organization->interval_format->value,
|
|
||||||
/** @var TimeFormat $time_format Time format */
|
|
||||||
'time_format' => $this->resource->organization->time_format->value,
|
|
||||||
'properties' => [
|
'properties' => [
|
||||||
/** @var string $group Type of first grouping */
|
/** @var string $group Type of first grouping */
|
||||||
'group' => $this->resource->properties->group->value,
|
'group' => $this->resource->properties->group->value,
|
||||||
@@ -101,9 +81,9 @@ class DetailedWithDataReportResource extends BaseResource
|
|||||||
/** @var string $history_group Type of grouping of the historic aggregation (time chart) */
|
/** @var string $history_group Type of grouping of the historic aggregation (time chart) */
|
||||||
'history_group' => $this->resource->properties->historyGroup->value,
|
'history_group' => $this->resource->properties->historyGroup->value,
|
||||||
/** @var string $start Start date of the report */
|
/** @var string $start Start date of the report */
|
||||||
'start' => $this->formatDateTime($this->resource->properties->start),
|
'start' => $this->resource->properties->start->toIso8601ZuluString(),
|
||||||
/** @var string $end End date of the report */
|
/** @var string $end End date of the report */
|
||||||
'end' => $this->formatDateTime($this->resource->properties->end),
|
'end' => $this->resource->properties->end->toIso8601ZuluString(),
|
||||||
],
|
],
|
||||||
/** @var array{
|
/** @var array{
|
||||||
* grouped_type: string|null,
|
* grouped_type: string|null,
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ class ReportResource extends BaseResource
|
|||||||
/** @var bool $is_public Whether the report can be accessed via an external link */
|
/** @var bool $is_public Whether the report can be accessed via an external link */
|
||||||
'is_public' => $this->resource->is_public,
|
'is_public' => $this->resource->is_public,
|
||||||
/** @var string|null $public_until Date until the report is public */
|
/** @var string|null $public_until Date until the report is public */
|
||||||
'public_until' => $this->formatDateTime($this->resource->public_until),
|
'public_until' => $this->resource->public_until?->toIso8601ZuluString(),
|
||||||
/** @var string|null $shareable_link Get link to access the report externally, not set if the report is private */
|
/** @var string|null $shareable_link Get link to access the report externally, not set if the report is private */
|
||||||
'shareable_link' => $this->resource->getShareableLink(),
|
'shareable_link' => $this->resource->getShareableLink(),
|
||||||
/** @var string $created_at Date when the report was created */
|
/** @var string $created_at Date when the report was created */
|
||||||
'created_at' => $this->formatDateTime($this->resource->created_at),
|
'created_at' => $this->resource->created_at?->toIso8601ZuluString(),
|
||||||
/** @var string $updated_at Date when the report was last updated */
|
/** @var string $updated_at Date when the report was last updated */
|
||||||
'updated_at' => $this->formatDateTime($this->resource->updated_at),
|
'updated_at' => $this->resource->updated_at?->toIso8601ZuluString(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ use OwenIt\Auditing\Models\Audit as PackageAuditModel;
|
|||||||
* @property string $event
|
* @property string $event
|
||||||
* @property string $auditable_type
|
* @property string $auditable_type
|
||||||
* @property string $auditable_id
|
* @property string $auditable_id
|
||||||
* @property array<string, mixed>|null $old_values
|
* @property array|null $old_values
|
||||||
* @property array<string, mixed>|null $new_values
|
* @property array|null $new_values
|
||||||
* @property string|null $url
|
* @property string|null $url
|
||||||
* @property string|null $ip_address
|
* @property string|null $ip_address
|
||||||
* @property string|null $user_agent
|
* @property string|null $user_agent
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class Client extends Model implements AuditableContract
|
|||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, Client>
|
||||||
*/
|
*/
|
||||||
public function organization(): BelongsTo
|
public function organization(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -55,7 +55,7 @@ class Client extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<Project, $this>
|
* @return HasMany<Project>
|
||||||
*/
|
*/
|
||||||
public function projects(): HasMany
|
public function projects(): HasMany
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
|
|||||||
* @property Carbon|null $updated_at
|
* @property Carbon|null $updated_at
|
||||||
* @property-read Organization $organization
|
* @property-read Organization $organization
|
||||||
* @property-read User $user
|
* @property-read User $user
|
||||||
* @property-read Collection<int, ProjectMember> $projectMembers
|
* @property-read Collection<ProjectMember> $projectMembers
|
||||||
* @property-read Collection<int, TimeEntry> $timeEntries
|
* @property-read Collection<TimeEntry> $timeEntries
|
||||||
*
|
*
|
||||||
* @method static MemberFactory factory()
|
* @method static MemberFactory factory()
|
||||||
*/
|
*/
|
||||||
@@ -47,7 +47,7 @@ class Member extends JetstreamMembership implements AuditableContract
|
|||||||
protected $table = 'members';
|
protected $table = 'members';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<User, $this>
|
* @return BelongsTo<User, Member>
|
||||||
*/
|
*/
|
||||||
public function user(): BelongsTo
|
public function user(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -55,7 +55,7 @@ class Member extends JetstreamMembership implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, Member>
|
||||||
*/
|
*/
|
||||||
public function organization(): BelongsTo
|
public function organization(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -63,7 +63,7 @@ class Member extends JetstreamMembership implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<TimeEntry, $this>
|
* @return HasMany<TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function timeEntries(): HasMany
|
public function timeEntries(): HasMany
|
||||||
{
|
{
|
||||||
@@ -71,7 +71,7 @@ class Member extends JetstreamMembership implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<ProjectMember, $this>
|
* @return HasMany<ProjectMember>
|
||||||
*/
|
*/
|
||||||
public function projectMembers(): HasMany
|
public function projectMembers(): HasMany
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,11 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\CurrencyFormat;
|
|
||||||
use App\Enums\DateFormat;
|
|
||||||
use App\Enums\IntervalFormat;
|
|
||||||
use App\Enums\NumberFormat;
|
|
||||||
use App\Enums\TimeFormat;
|
|
||||||
use App\Models\Concerns\CustomAuditable;
|
use App\Models\Concerns\CustomAuditable;
|
||||||
use App\Models\Concerns\HasUuids;
|
use App\Models\Concerns\HasUuids;
|
||||||
use Database\Factories\OrganizationFactory;
|
use Database\Factories\OrganizationFactory;
|
||||||
@@ -18,12 +13,12 @@ use Illuminate\Database\Eloquent\ModelNotFoundException;
|
|||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Laravel\Jetstream\Events\TeamCreated;
|
use Laravel\Jetstream\Events\TeamCreated;
|
||||||
use Laravel\Jetstream\Events\TeamDeleted;
|
use Laravel\Jetstream\Events\TeamDeleted;
|
||||||
use Laravel\Jetstream\Events\TeamUpdated;
|
use Laravel\Jetstream\Events\TeamUpdated;
|
||||||
|
use Laravel\Jetstream\Jetstream;
|
||||||
use Laravel\Jetstream\Team as JetstreamTeam;
|
use Laravel\Jetstream\Team as JetstreamTeam;
|
||||||
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
|
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
|
||||||
|
|
||||||
@@ -42,13 +37,8 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
|
|||||||
* @property Collection<int, User> $realUsers
|
* @property Collection<int, User> $realUsers
|
||||||
* @property-read Collection<int, OrganizationInvitation> $teamInvitations
|
* @property-read Collection<int, OrganizationInvitation> $teamInvitations
|
||||||
* @property Member $membership
|
* @property Member $membership
|
||||||
* @property NumberFormat $number_format
|
|
||||||
* @property CurrencyFormat $currency_format
|
|
||||||
* @property DateFormat $date_format
|
|
||||||
* @property IntervalFormat $interval_format
|
|
||||||
* @property TimeFormat $time_format
|
|
||||||
*
|
*
|
||||||
* @method HasMany<OrganizationInvitation, $this> teamInvitations()
|
* @method HasMany<OrganizationInvitation> teamInvitations()
|
||||||
* @method static OrganizationFactory factory()
|
* @method static OrganizationFactory factory()
|
||||||
*/
|
*/
|
||||||
class Organization extends JetstreamTeam implements AuditableContract
|
class Organization extends JetstreamTeam implements AuditableContract
|
||||||
@@ -70,17 +60,12 @@ class Organization extends JetstreamTeam implements AuditableContract
|
|||||||
'personal_team' => 'boolean',
|
'personal_team' => 'boolean',
|
||||||
'currency' => 'string',
|
'currency' => 'string',
|
||||||
'employees_can_see_billable_rates' => 'boolean',
|
'employees_can_see_billable_rates' => 'boolean',
|
||||||
'number_format' => NumberFormat::class,
|
|
||||||
'currency_format' => CurrencyFormat::class,
|
|
||||||
'date_format' => DateFormat::class,
|
|
||||||
'interval_format' => IntervalFormat::class,
|
|
||||||
'time_format' => TimeFormat::class,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
*
|
*
|
||||||
* @var list<string>
|
* @var array<int, string>
|
||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'name',
|
||||||
@@ -104,6 +89,7 @@ class Organization extends JetstreamTeam implements AuditableContract
|
|||||||
* @var array<string, mixed>
|
* @var array<string, mixed>
|
||||||
*/
|
*/
|
||||||
protected $attributes = [
|
protected $attributes = [
|
||||||
|
'currency' => 'EUR',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,7 +112,7 @@ class Organization extends JetstreamTeam implements AuditableContract
|
|||||||
/**
|
/**
|
||||||
* Get all the users that belong to the team.
|
* Get all the users that belong to the team.
|
||||||
*
|
*
|
||||||
* @return BelongsToMany<User, $this, Pivot, 'membership'>
|
* @return BelongsToMany<User>
|
||||||
*/
|
*/
|
||||||
public function users(): BelongsToMany
|
public function users(): BelongsToMany
|
||||||
{
|
{
|
||||||
@@ -143,7 +129,7 @@ class Organization extends JetstreamTeam implements AuditableContract
|
|||||||
/**
|
/**
|
||||||
* Get the owner of the team.
|
* Get the owner of the team.
|
||||||
*
|
*
|
||||||
* @return BelongsTo<User, $this>
|
* @return BelongsTo<User, Organization>
|
||||||
*/
|
*/
|
||||||
public function owner(): BelongsTo
|
public function owner(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -151,7 +137,7 @@ class Organization extends JetstreamTeam implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<Member, $this>
|
* @return HasMany<Member>
|
||||||
*/
|
*/
|
||||||
public function members(): HasMany
|
public function members(): HasMany
|
||||||
{
|
{
|
||||||
@@ -159,7 +145,7 @@ class Organization extends JetstreamTeam implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsToMany<User, $this, Pivot, 'membership'>
|
* @return BelongsToMany<User>
|
||||||
*/
|
*/
|
||||||
public function realUsers(): BelongsToMany
|
public function realUsers(): BelongsToMany
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class OrganizationInvitation extends JetstreamTeamInvitation implements Auditabl
|
|||||||
/**
|
/**
|
||||||
* Get the organization that the invitation belongs to.
|
* Get the organization that the invitation belongs to.
|
||||||
*
|
*
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, OrganizationInvitation>
|
||||||
*/
|
*/
|
||||||
public function organization(): BelongsTo
|
public function organization(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -63,7 +63,7 @@ class OrganizationInvitation extends JetstreamTeamInvitation implements Auditabl
|
|||||||
/**
|
/**
|
||||||
* Get the organization that the invitation belongs to.
|
* Get the organization that the invitation belongs to.
|
||||||
*
|
*
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, OrganizationInvitation>
|
||||||
*/
|
*/
|
||||||
public function team(): BelongsTo
|
public function team(): BelongsTo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,26 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Models\Passport;
|
namespace App\Models\Passport;
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Laravel\Passport\AuthCode as PassportAuthCode;
|
use Laravel\Passport\AuthCode as PassportAuthCode;
|
||||||
|
|
||||||
/**
|
class AuthCode extends PassportAuthCode {}
|
||||||
* @property string $id
|
|
||||||
* @property string $user_id
|
|
||||||
* @property string $client_id
|
|
||||||
* @property string|null $scopes
|
|
||||||
* @property bool $revoked
|
|
||||||
* @property Carbon $expires_at
|
|
||||||
*/
|
|
||||||
class AuthCode extends PassportAuthCode
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @return BelongsTo<User, $this>
|
|
||||||
*/
|
|
||||||
public function user(): BelongsTo
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class, 'user_id');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,36 +5,22 @@ declare(strict_types=1);
|
|||||||
namespace App\Models\Passport;
|
namespace App\Models\Passport;
|
||||||
|
|
||||||
use Database\Factories\Passport\ClientFactory;
|
use Database\Factories\Passport\ClientFactory;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Laravel\Passport\Client as PassportClient;
|
use Laravel\Passport\Client as PassportClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property string $id
|
* @property string $id
|
||||||
* @property string|null $owner_id
|
* @property string|null $user_id
|
||||||
* @property string|null $owner_type
|
|
||||||
* @property string $name
|
* @property string $name
|
||||||
* @property string|null $secret
|
* @property string|null $secret
|
||||||
* @property string|null $provider
|
* @property string|null $provider
|
||||||
* @property array<string> $grant_types
|
* @property string $redirect
|
||||||
* @property array<string> $redirect_uris
|
* @property bool $personal_access_client
|
||||||
* @property Carbon|null $created_at
|
* @property bool $password_client
|
||||||
* @property Carbon|null $updated_at
|
|
||||||
* @property bool $revoked
|
* @property bool $revoked
|
||||||
*/
|
*/
|
||||||
class Client extends PassportClient
|
class Client extends PassportClient
|
||||||
{
|
{
|
||||||
/** @use HasFactory<ClientFactory> */
|
/** @use HasFactory<ClientFactory> */
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new factory instance for the model.
|
|
||||||
*
|
|
||||||
* @return ClientFactory
|
|
||||||
*/
|
|
||||||
protected static function newFactory(): Factory
|
|
||||||
{
|
|
||||||
return ClientFactory::new();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
9
app/Models/Passport/PersonalAccessClient.php
Normal file
9
app/Models/Passport/PersonalAccessClient.php
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Models\Passport;
|
||||||
|
|
||||||
|
use Laravel\Passport\PersonalAccessClient as PassportPersonalAccessClient;
|
||||||
|
|
||||||
|
class PersonalAccessClient extends PassportPersonalAccessClient {}
|
||||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Models\Passport;
|
namespace App\Models\Passport;
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Database\Factories\Passport\TokenFactory;
|
use Database\Factories\Passport\TokenFactory;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@@ -21,8 +20,6 @@ use Laravel\Passport\Token as PassportToken;
|
|||||||
* @property Carbon|null $created_at
|
* @property Carbon|null $created_at
|
||||||
* @property Carbon|null $updated_at
|
* @property Carbon|null $updated_at
|
||||||
* @property Carbon|null $expires_at
|
* @property Carbon|null $expires_at
|
||||||
* @property-read Client|null $client
|
|
||||||
* @property-read User|null $user
|
|
||||||
*/
|
*/
|
||||||
class Token extends PassportToken
|
class Token extends PassportToken
|
||||||
{
|
{
|
||||||
@@ -32,24 +29,10 @@ class Token extends PassportToken
|
|||||||
/**
|
/**
|
||||||
* Get the client that the token belongs to.
|
* Get the client that the token belongs to.
|
||||||
*
|
*
|
||||||
* @return BelongsTo<Client, $this>
|
* @return BelongsTo<Client, Token>
|
||||||
*/
|
*/
|
||||||
// @phpstan-ignore method.childReturnType
|
|
||||||
public function client(): BelongsTo
|
public function client(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Client::class, 'client_id', 'id');
|
return $this->belongsTo(Client::class, 'client_id', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the user that the token belongs to.
|
|
||||||
*
|
|
||||||
* @deprecated Will be removed in a future Laravel version.
|
|
||||||
*
|
|
||||||
* @return BelongsTo<User, $this>
|
|
||||||
*/
|
|
||||||
// @phpstan-ignore method.childReturnType
|
|
||||||
public function user(): BelongsTo
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class, 'user_id');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ class Project extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, Project>
|
||||||
*/
|
*/
|
||||||
public function organization(): BelongsTo
|
public function organization(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -145,7 +145,7 @@ class Project extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Client, $this>
|
* @return BelongsTo<Client, Project>
|
||||||
*/
|
*/
|
||||||
public function client(): BelongsTo
|
public function client(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -153,7 +153,7 @@ class Project extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<ProjectMember, $this>
|
* @return HasMany<ProjectMember>
|
||||||
*/
|
*/
|
||||||
public function members(): HasMany
|
public function members(): HasMany
|
||||||
{
|
{
|
||||||
@@ -161,7 +161,7 @@ class Project extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<Task, $this>
|
* @return HasMany<Task>
|
||||||
*/
|
*/
|
||||||
public function tasks(): HasMany
|
public function tasks(): HasMany
|
||||||
{
|
{
|
||||||
@@ -169,7 +169,7 @@ class Project extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<TimeEntry, $this>
|
* @return HasMany<TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function timeEntries(): HasMany
|
public function timeEntries(): HasMany
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class ProjectMember extends Model implements AuditableContract
|
|||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Project, $this>
|
* @return BelongsTo<Project, ProjectMember>
|
||||||
*/
|
*/
|
||||||
public function project(): BelongsTo
|
public function project(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -58,7 +58,7 @@ class ProjectMember extends Model implements AuditableContract
|
|||||||
/**
|
/**
|
||||||
* @deprecated Use member relationship instead
|
* @deprecated Use member relationship instead
|
||||||
*
|
*
|
||||||
* @return BelongsTo<User, $this>
|
* @return BelongsTo<User, ProjectMember>
|
||||||
*/
|
*/
|
||||||
public function user(): BelongsTo
|
public function user(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -66,7 +66,7 @@ class ProjectMember extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Member, $this>
|
* @return BelongsTo<Member, ProjectMember>
|
||||||
*/
|
*/
|
||||||
public function member(): BelongsTo
|
public function member(): BelongsTo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class Report extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, Report>
|
||||||
*/
|
*/
|
||||||
public function organization(): BelongsTo
|
public function organization(): BelongsTo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use Staudenmeir\EloquentJsonRelations\Relations\HasManyJson;
|
|||||||
* @property string $organization_id
|
* @property string $organization_id
|
||||||
* @property Carbon|null $created_at
|
* @property Carbon|null $created_at
|
||||||
* @property Carbon|null $updated_at
|
* @property Carbon|null $updated_at
|
||||||
* @property-read Collection<int, TimeEntry> $timeEntries
|
* @property-read Collection<TimeEntry> $timeEntries
|
||||||
* @property-read Organization $organization
|
* @property-read Organization $organization
|
||||||
*
|
*
|
||||||
* @method static TagFactory factory()
|
* @method static TagFactory factory()
|
||||||
@@ -47,7 +47,7 @@ class Tag extends Model implements AuditableContract
|
|||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, Tag>
|
||||||
*/
|
*/
|
||||||
public function organization(): BelongsTo
|
public function organization(): BelongsTo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class Task extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Project, $this>
|
* @return BelongsTo<Project, Task>
|
||||||
*/
|
*/
|
||||||
public function project(): BelongsTo
|
public function project(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -128,7 +128,7 @@ class Task extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, Task>
|
||||||
*/
|
*/
|
||||||
public function organization(): BelongsTo
|
public function organization(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -136,7 +136,7 @@ class Task extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<TimeEntry, $this>
|
* @return HasMany<TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function timeEntries(): HasMany
|
public function timeEntries(): HasMany
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use Staudenmeir\EloquentJsonRelations\Relations\BelongsToJson;
|
|||||||
* @property Carbon|null $end
|
* @property Carbon|null $end
|
||||||
* @property int|null $billable_rate Billable rate per hour in cents
|
* @property int|null $billable_rate Billable rate per hour in cents
|
||||||
* @property bool $billable
|
* @property bool $billable
|
||||||
* @property array<string> $tags
|
* @property array $tags
|
||||||
* @property string $user_id
|
* @property string $user_id
|
||||||
* @property string $member_id
|
* @property string $member_id
|
||||||
* @property bool $is_imported
|
* @property bool $is_imported
|
||||||
@@ -45,7 +45,7 @@ use Staudenmeir\EloquentJsonRelations\Relations\BelongsToJson;
|
|||||||
* @property-read Client|null $client
|
* @property-read Client|null $client
|
||||||
* @property string|null $task_id
|
* @property string|null $task_id
|
||||||
* @property-read Task|null $task
|
* @property-read Task|null $task
|
||||||
* @property-read Collection<int, Tag> $tagsRelation
|
* @property-read Collection<Tag> $tagsRelation
|
||||||
*
|
*
|
||||||
* @method Builder<TimeEntry> hasTag(Tag $tag)
|
* @method Builder<TimeEntry> hasTag(Tag $tag)
|
||||||
* @method static TimeEntryFactory factory()
|
* @method static TimeEntryFactory factory()
|
||||||
@@ -154,7 +154,7 @@ class TimeEntry extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<User, $this>
|
* @return BelongsTo<User, TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function user(): BelongsTo
|
public function user(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -162,7 +162,7 @@ class TimeEntry extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Member, $this>
|
* @return BelongsTo<Member, TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function member(): BelongsTo
|
public function member(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -170,7 +170,7 @@ class TimeEntry extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function organization(): BelongsTo
|
public function organization(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -178,7 +178,7 @@ class TimeEntry extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Project, $this>
|
* @return BelongsTo<Project, TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function project(): BelongsTo
|
public function project(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -186,7 +186,7 @@ class TimeEntry extends Model implements AuditableContract
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Task, $this>
|
* @return BelongsTo<Task, TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function task(): BelongsTo
|
public function task(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -196,7 +196,7 @@ class TimeEntry extends Model implements AuditableContract
|
|||||||
/**
|
/**
|
||||||
* This relation can be reconstructed via the task relation. It is only here for performance reasons.
|
* This relation can be reconstructed via the task relation. It is only here for performance reasons.
|
||||||
*
|
*
|
||||||
* @return BelongsTo<Client, $this>
|
* @return BelongsTo<Client, TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function client(): BelongsTo
|
public function client(): BelongsTo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
@@ -28,7 +27,6 @@ use Laravel\Fortify\TwoFactorAuthenticatable;
|
|||||||
use Laravel\Jetstream\HasProfilePhoto;
|
use Laravel\Jetstream\HasProfilePhoto;
|
||||||
use Laravel\Jetstream\HasTeams;
|
use Laravel\Jetstream\HasTeams;
|
||||||
use Laravel\Passport\AuthCode;
|
use Laravel\Passport\AuthCode;
|
||||||
use Laravel\Passport\Contracts\OAuthenticatable;
|
|
||||||
use Laravel\Passport\HasApiTokens;
|
use Laravel\Passport\HasApiTokens;
|
||||||
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
|
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
|
||||||
|
|
||||||
@@ -54,13 +52,13 @@ use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
|
|||||||
* @property Collection<int, TimeEntry> $timeEntries
|
* @property Collection<int, TimeEntry> $timeEntries
|
||||||
* @property Member $membership
|
* @property Member $membership
|
||||||
*
|
*
|
||||||
* @method HasMany<Organization, $this> ownedTeams()
|
* @method HasMany<Organization> ownedTeams()
|
||||||
* @method static UserFactory factory()
|
* @method static UserFactory factory()
|
||||||
* @method static Builder<User> query()
|
* @method static Builder<User> query()
|
||||||
* @method Builder<User> belongsToOrganization(Organization $organization)
|
* @method Builder<User> belongsToOrganization(Organization $organization)
|
||||||
* @method Builder<User> active()
|
* @method Builder<User> active()
|
||||||
*/
|
*/
|
||||||
class User extends Authenticatable implements AuditableContract, FilamentUser, MustVerifyEmail, OAuthenticatable
|
class User extends Authenticatable implements AuditableContract, FilamentUser, MustVerifyEmail
|
||||||
{
|
{
|
||||||
use CustomAuditable;
|
use CustomAuditable;
|
||||||
use HasApiTokens;
|
use HasApiTokens;
|
||||||
@@ -77,7 +75,7 @@ class User extends Authenticatable implements AuditableContract, FilamentUser, M
|
|||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
*
|
*
|
||||||
* @var list<string>
|
* @var array<int, string>
|
||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'name',
|
||||||
@@ -88,7 +86,7 @@ class User extends Authenticatable implements AuditableContract, FilamentUser, M
|
|||||||
/**
|
/**
|
||||||
* The attributes that should be hidden for serialization.
|
* The attributes that should be hidden for serialization.
|
||||||
*
|
*
|
||||||
* @var list<string>
|
* @var array<int, string>
|
||||||
*/
|
*/
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
'password',
|
'password',
|
||||||
@@ -145,7 +143,7 @@ class User extends Authenticatable implements AuditableContract, FilamentUser, M
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsToMany<Organization, $this, Pivot, 'membership'>
|
* @return BelongsToMany<Organization>
|
||||||
*/
|
*/
|
||||||
public function organizations(): BelongsToMany
|
public function organizations(): BelongsToMany
|
||||||
{
|
{
|
||||||
@@ -160,7 +158,7 @@ class User extends Authenticatable implements AuditableContract, FilamentUser, M
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<TimeEntry, $this>
|
* @return HasMany<TimeEntry>
|
||||||
*/
|
*/
|
||||||
public function timeEntries(): HasMany
|
public function timeEntries(): HasMany
|
||||||
{
|
{
|
||||||
@@ -168,7 +166,7 @@ class User extends Authenticatable implements AuditableContract, FilamentUser, M
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<Organization, $this>
|
* @return BelongsTo<Organization, User>
|
||||||
*/
|
*/
|
||||||
public function currentOrganization(): BelongsTo
|
public function currentOrganization(): BelongsTo
|
||||||
{
|
{
|
||||||
@@ -176,7 +174,7 @@ class User extends Authenticatable implements AuditableContract, FilamentUser, M
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<ProjectMember, $this>
|
* @return HasMany<ProjectMember>
|
||||||
*/
|
*/
|
||||||
public function projectMembers(): HasMany
|
public function projectMembers(): HasMany
|
||||||
{
|
{
|
||||||
@@ -184,7 +182,7 @@ class User extends Authenticatable implements AuditableContract, FilamentUser, M
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<Token, $this>
|
* @return HasMany<Token>
|
||||||
*/
|
*/
|
||||||
public function accessTokens(): HasMany
|
public function accessTokens(): HasMany
|
||||||
{
|
{
|
||||||
@@ -192,13 +190,24 @@ class User extends Authenticatable implements AuditableContract, FilamentUser, M
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<AuthCode, $this>
|
* @return HasMany<AuthCode>
|
||||||
*/
|
*/
|
||||||
public function authCodes(): HasMany
|
public function authCodes(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(AuthCode::class);
|
return $this->hasMany(AuthCode::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the access tokens for the user.
|
||||||
|
*
|
||||||
|
* @return HasMany<Token>
|
||||||
|
*/
|
||||||
|
public function tokens(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Token::class, 'user_id')
|
||||||
|
->orderBy('created_at', 'desc');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Builder<User> $builder
|
* @param Builder<User> $builder
|
||||||
*/
|
*/
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user