mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-06-15 13:32:43 +01:00
Enhanced admin panel
This commit is contained in:
committed by
Constantin Graf
parent
42ad5e004a
commit
0bf8a25d64
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Actions\Fortify;
|
namespace App\Actions\Fortify;
|
||||||
|
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Enums\Weekday;
|
use App\Enums\Weekday;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
@@ -81,7 +82,7 @@ class CreateNewUser implements CreatesNewUsers
|
|||||||
|
|
||||||
$organization->users()->attach(
|
$organization->users()->attach(
|
||||||
$user, [
|
$user, [
|
||||||
'role' => 'owner',
|
'role' => Role::Owner->value,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Actions\Jetstream;
|
namespace App\Actions\Jetstream;
|
||||||
|
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
@@ -42,7 +43,7 @@ class CreateOrganization implements CreatesTeams
|
|||||||
|
|
||||||
$organization->users()->attach(
|
$organization->users()->attach(
|
||||||
$user, [
|
$user, [
|
||||||
'role' => 'owner',
|
'role' => Role::Owner->value,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use App\Filament\Resources\UserResource\Pages;
|
|||||||
use App\Filament\Resources\UserResource\RelationManagers\OrganizationsRelationManager;
|
use App\Filament\Resources\UserResource\RelationManagers\OrganizationsRelationManager;
|
||||||
use App\Filament\Resources\UserResource\RelationManagers\OwnedOrganizationsRelationManager;
|
use App\Filament\Resources\UserResource\RelationManagers\OwnedOrganizationsRelationManager;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Exception;
|
||||||
use Filament\Forms;
|
use Filament\Forms;
|
||||||
use Filament\Forms\Components\TextInput;
|
use Filament\Forms\Components\TextInput;
|
||||||
use Filament\Forms\Form;
|
use Filament\Forms\Form;
|
||||||
@@ -15,6 +16,7 @@ use Filament\Resources\Resource;
|
|||||||
use Filament\Tables;
|
use Filament\Tables;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use STS\FilamentImpersonate\Tables\Actions\Impersonate;
|
||||||
|
|
||||||
class UserResource extends Resource
|
class UserResource extends Resource
|
||||||
{
|
{
|
||||||
@@ -70,6 +72,19 @@ class UserResource extends Resource
|
|||||||
//
|
//
|
||||||
])
|
])
|
||||||
->actions([
|
->actions([
|
||||||
|
Impersonate::make()->before(function (User $record): void {
|
||||||
|
if ($record->currentTeam === null) {
|
||||||
|
$organization = $record->organizations()->where('personal_team', '=', true)->first();
|
||||||
|
if ($organization === null) {
|
||||||
|
$organization = $record->organizations()->first();
|
||||||
|
}
|
||||||
|
if ($organization === null) {
|
||||||
|
throw new Exception('User has no organization');
|
||||||
|
}
|
||||||
|
$record->currentTeam()->associate($organization);
|
||||||
|
$record->save();
|
||||||
|
}
|
||||||
|
}),
|
||||||
Tables\Actions\EditAction::make(),
|
Tables\Actions\EditAction::make(),
|
||||||
])
|
])
|
||||||
->bulkActions([
|
->bulkActions([
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace App\Filament\Resources\UserResource\Pages;
|
|||||||
use App\Filament\Resources\UserResource;
|
use App\Filament\Resources\UserResource;
|
||||||
use Filament\Actions;
|
use Filament\Actions;
|
||||||
use Filament\Resources\Pages\EditRecord;
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
use STS\FilamentImpersonate\Pages\Actions\Impersonate;
|
||||||
|
|
||||||
class EditUser extends EditRecord
|
class EditUser extends EditRecord
|
||||||
{
|
{
|
||||||
@@ -15,6 +16,7 @@ class EditUser extends EditRecord
|
|||||||
protected function getHeaderActions(): array
|
protected function getHeaderActions(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
Impersonate::make()->record($this->getRecord()),
|
||||||
Actions\DeleteAction::make(),
|
Actions\DeleteAction::make(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,6 +126,11 @@ class User extends Authenticatable implements FilamentUser, MustVerifyEmail
|
|||||||
return in_array($this->email, config('auth.super_admins', []), true) && $this->hasVerifiedEmail();
|
return in_array($this->email, config('auth.super_admins', []), true) && $this->hasVerifiedEmail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function canBeImpersonated(): bool
|
||||||
|
{
|
||||||
|
return $this->is_placeholder === false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsToMany<Organization>
|
* @return BelongsToMany<Organization>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -59,10 +59,14 @@ class PermissionStore
|
|||||||
?->membership
|
?->membership
|
||||||
?->role;
|
?->role;
|
||||||
|
|
||||||
|
if ($role === null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
/** @var Role|null $roleObj */
|
/** @var Role|null $roleObj */
|
||||||
$roleObj = Jetstream::findRole($role);
|
$roleObj = Jetstream::findRole($role);
|
||||||
|
|
||||||
return $role !== null ? ($roleObj?->permissions ?? []) : [];
|
return $roleObj?->permissions ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"nwidart/laravel-modules": "dev-feature/fixed_path",
|
"nwidart/laravel-modules": "dev-feature/fixed_path",
|
||||||
"pxlrbt/filament-environment-indicator": "^2.0",
|
"pxlrbt/filament-environment-indicator": "^2.0",
|
||||||
"spatie/temporary-directory": "^2.2",
|
"spatie/temporary-directory": "^2.2",
|
||||||
|
"stechstudio/filament-impersonate": "^3.8",
|
||||||
"tightenco/ziggy": "^2.1.0",
|
"tightenco/ziggy": "^2.1.0",
|
||||||
"tpetry/laravel-postgresql-enhanced": "^0.38.0",
|
"tpetry/laravel-postgresql-enhanced": "^0.38.0",
|
||||||
"wikimedia/composer-merge-plugin": "^2.1.0"
|
"wikimedia/composer-merge-plugin": "^2.1.0"
|
||||||
|
|||||||
155
composer.lock
generated
155
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "ad100a87fbe76efc70708726bc921412",
|
"content-hash": "5779fb7e87efa88e5db2b37e64fe89e3",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "anourvalar/eloquent-serialize",
|
"name": "anourvalar/eloquent-serialize",
|
||||||
@@ -74,28 +74,28 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bacon/bacon-qr-code",
|
"name": "bacon/bacon-qr-code",
|
||||||
"version": "2.0.8",
|
"version": "v3.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Bacon/BaconQrCode.git",
|
"url": "https://github.com/Bacon/BaconQrCode.git",
|
||||||
"reference": "8674e51bb65af933a5ffaf1c308a660387c35c22"
|
"reference": "510de6eca6248d77d31b339d62437cc995e2fb41"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22",
|
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/510de6eca6248d77d31b339d62437cc995e2fb41",
|
||||||
"reference": "8674e51bb65af933a5ffaf1c308a660387c35c22",
|
"reference": "510de6eca6248d77d31b339d62437cc995e2fb41",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"dasprid/enum": "^1.0.3",
|
"dasprid/enum": "^1.0.3",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
"php": "^7.1 || ^8.0"
|
"php": "^8.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phly/keep-a-changelog": "^2.1",
|
"phly/keep-a-changelog": "^2.12",
|
||||||
"phpunit/phpunit": "^7 | ^8 | ^9",
|
"phpunit/phpunit": "^10.5.11 || 11.0.4",
|
||||||
"spatie/phpunit-snapshot-assertions": "^4.2.9",
|
"spatie/phpunit-snapshot-assertions": "^5.1.5",
|
||||||
"squizlabs/php_codesniffer": "^3.4"
|
"squizlabs/php_codesniffer": "^3.9"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-imagick": "to generate QR code images"
|
"ext-imagick": "to generate QR code images"
|
||||||
@@ -122,9 +122,9 @@
|
|||||||
"homepage": "https://github.com/Bacon/BaconQrCode",
|
"homepage": "https://github.com/Bacon/BaconQrCode",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/Bacon/BaconQrCode/issues",
|
"issues": "https://github.com/Bacon/BaconQrCode/issues",
|
||||||
"source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8"
|
"source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.0"
|
||||||
},
|
},
|
||||||
"time": "2022-12-07T17:46:57+00:00"
|
"time": "2024-04-18T11:16:25+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "blade-ui-kit/blade-heroicons",
|
"name": "blade-ui-kit/blade-heroicons",
|
||||||
@@ -3496,6 +3496,73 @@
|
|||||||
},
|
},
|
||||||
"time": "2024-02-28T15:07:15+00:00"
|
"time": "2024-02-28T15:07:15+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "lab404/laravel-impersonate",
|
||||||
|
"version": "1.7.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/404labfr/laravel-impersonate.git",
|
||||||
|
"reference": "82cad73700a8699d63de169bb41abd5ae283e9a8"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/404labfr/laravel-impersonate/zipball/82cad73700a8699d63de169bb41abd5ae283e9a8",
|
||||||
|
"reference": "82cad73700a8699d63de169bb41abd5ae283e9a8",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"laravel/framework": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0",
|
||||||
|
"php": "^7.2 | ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mockery/mockery": "^1.3.3",
|
||||||
|
"orchestra/testbench": "^4.0 | ^5.0 | ^6.0 | ^7.0 | ^8.0 | ^9.0",
|
||||||
|
"phpunit/phpunit": "^7.5 | ^8.0 | ^9.0 | ^10.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"providers": [
|
||||||
|
"Lab404\\Impersonate\\ImpersonateServiceProvider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/helpers.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Lab404\\Impersonate\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Marceau Casals",
|
||||||
|
"email": "marceau@casals.fr"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Laravel Impersonate is a plugin that allows to you to authenticate as your users.",
|
||||||
|
"keywords": [
|
||||||
|
"auth",
|
||||||
|
"impersonate",
|
||||||
|
"impersonation",
|
||||||
|
"laravel",
|
||||||
|
"laravel-package",
|
||||||
|
"laravel-plugin",
|
||||||
|
"package",
|
||||||
|
"plugin",
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/404labfr/laravel-impersonate/issues",
|
||||||
|
"source": "https://github.com/404labfr/laravel-impersonate/tree/1.7.5"
|
||||||
|
},
|
||||||
|
"time": "2024-03-11T14:26:14+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "laminas/laminas-diactoros",
|
"name": "laminas/laminas-diactoros",
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
@@ -3583,20 +3650,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/fortify",
|
"name": "laravel/fortify",
|
||||||
"version": "v1.21.1",
|
"version": "v1.21.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/fortify.git",
|
"url": "https://github.com/laravel/fortify.git",
|
||||||
"reference": "405388fd399264715573e23ed2f368fbce426da3"
|
"reference": "cb122ceec7f8d0231985c1dde8161b3c561bfe90"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/fortify/zipball/405388fd399264715573e23ed2f368fbce426da3",
|
"url": "https://api.github.com/repos/laravel/fortify/zipball/cb122ceec7f8d0231985c1dde8161b3c561bfe90",
|
||||||
"reference": "405388fd399264715573e23ed2f368fbce426da3",
|
"reference": "cb122ceec7f8d0231985c1dde8161b3c561bfe90",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"bacon/bacon-qr-code": "^2.0",
|
"bacon/bacon-qr-code": "^3.0",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"illuminate/support": "^10.0|^11.0",
|
"illuminate/support": "^10.0|^11.0",
|
||||||
"php": "^8.1",
|
"php": "^8.1",
|
||||||
@@ -3644,7 +3711,7 @@
|
|||||||
"issues": "https://github.com/laravel/fortify/issues",
|
"issues": "https://github.com/laravel/fortify/issues",
|
||||||
"source": "https://github.com/laravel/fortify"
|
"source": "https://github.com/laravel/fortify"
|
||||||
},
|
},
|
||||||
"time": "2024-03-19T20:08:25+00:00"
|
"time": "2024-04-25T14:17:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/framework",
|
"name": "laravel/framework",
|
||||||
@@ -8038,6 +8105,48 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-12-25T11:46:58+00:00"
|
"time": "2023-12-25T11:46:58+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "stechstudio/filament-impersonate",
|
||||||
|
"version": "3.8",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/stechstudio/filament-impersonate.git",
|
||||||
|
"reference": "d24a9ffc1ef2f87940d151ca1cb2c2d2e5e524a8"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/stechstudio/filament-impersonate/zipball/d24a9ffc1ef2f87940d151ca1cb2c2d2e5e524a8",
|
||||||
|
"reference": "d24a9ffc1ef2f87940d151ca1cb2c2d2e5e524a8",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"filament/filament": "^3.0",
|
||||||
|
"lab404/laravel-impersonate": "^1.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"providers": [
|
||||||
|
"STS\\FilamentImpersonate\\FilamentImpersonateServiceProvider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"STS\\FilamentImpersonate\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "A Filament package to impersonate your users.",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/stechstudio/filament-impersonate/issues",
|
||||||
|
"source": "https://github.com/stechstudio/filament-impersonate/tree/3.8"
|
||||||
|
},
|
||||||
|
"time": "2024-03-25T03:05:55+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/clock",
|
"name": "symfony/clock",
|
||||||
"version": "v7.0.5",
|
"version": "v7.0.5",
|
||||||
@@ -13908,16 +14017,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "spatie/ignition",
|
"name": "spatie/ignition",
|
||||||
"version": "1.13.2",
|
"version": "1.14.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/spatie/ignition.git",
|
"url": "https://github.com/spatie/ignition.git",
|
||||||
"reference": "952798e239d9969e4e694b124c2cc222798dbb28"
|
"reference": "80385994caed328f6f9c9952926932e65b9b774c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/spatie/ignition/zipball/952798e239d9969e4e694b124c2cc222798dbb28",
|
"url": "https://api.github.com/repos/spatie/ignition/zipball/80385994caed328f6f9c9952926932e65b9b774c",
|
||||||
"reference": "952798e239d9969e4e694b124c2cc222798dbb28",
|
"reference": "80385994caed328f6f9c9952926932e65b9b774c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -13987,7 +14096,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-04-16T08:49:17+00:00"
|
"time": "2024-04-26T08:45:51+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "spatie/laravel-ignition",
|
"name": "spatie/laravel-ignition",
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ return [
|
|||||||
],
|
],
|
||||||
'replacements' => [
|
'replacements' => [
|
||||||
'routes/web' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'CONTROLLER_NAMESPACE'],
|
'routes/web' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'CONTROLLER_NAMESPACE'],
|
||||||
'routes/api' => ['LOWER_NAME', 'STUDLY_NAME'],
|
'routes/api' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'CONTROLLER_NAMESPACE'],
|
||||||
'vite' => ['LOWER_NAME'],
|
'vite' => ['LOWER_NAME', 'STUDLY_NAME'],
|
||||||
'json' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'PROVIDER_NAMESPACE'],
|
'json' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'PROVIDER_NAMESPACE'],
|
||||||
'views/index' => ['LOWER_NAME'],
|
'views/index' => ['LOWER_NAME'],
|
||||||
'views/master' => ['LOWER_NAME', 'STUDLY_NAME'],
|
'views/master' => ['LOWER_NAME', 'STUDLY_NAME'],
|
||||||
@@ -58,6 +58,7 @@ return [
|
|||||||
'AUTHOR_EMAIL',
|
'AUTHOR_EMAIL',
|
||||||
'MODULE_NAMESPACE',
|
'MODULE_NAMESPACE',
|
||||||
'PROVIDER_NAMESPACE',
|
'PROVIDER_NAMESPACE',
|
||||||
|
'APP_FOLDER_NAME',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'gitkeep' => true,
|
'gitkeep' => true,
|
||||||
@@ -93,8 +94,18 @@ return [
|
|||||||
| the migration files?
|
| the migration files?
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'migration' => base_path('database/migrations'),
|
'migration' => base_path('database/migrations'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| The app path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| app folder name
|
||||||
|
| for example can change it to 'src' or 'App'
|
||||||
|
*/
|
||||||
|
'app_folder' => 'app/',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Generator path
|
| Generator path
|
||||||
@@ -103,35 +114,52 @@ return [
|
|||||||
| Setting the generate key to false will not generate that folder
|
| Setting the generate key to false will not generate that folder
|
||||||
*/
|
*/
|
||||||
'generator' => [
|
'generator' => [
|
||||||
|
// app/
|
||||||
|
'channels' => ['path' => 'app/Broadcasting', 'generate' => false],
|
||||||
|
'command' => ['path' => 'app/Console', 'generate' => false],
|
||||||
|
'emails' => ['path' => 'app/Emails', 'generate' => false],
|
||||||
|
'event' => ['path' => 'app/Events', 'generate' => false],
|
||||||
|
'jobs' => ['path' => 'app/Jobs', 'generate' => false],
|
||||||
|
'listener' => ['path' => 'app/Listeners', 'generate' => false],
|
||||||
|
'model' => ['path' => 'app/Models', 'generate' => false],
|
||||||
|
'notifications' => ['path' => 'app/Notifications', 'generate' => false],
|
||||||
|
'observer' => ['path' => 'app/Observers', 'generate' => false],
|
||||||
|
'policies' => ['path' => 'app/Policies', 'generate' => false],
|
||||||
|
'provider' => ['path' => 'app/Providers', 'generate' => true],
|
||||||
|
'route-provider' => ['path' => 'app/Providers', 'generate' => true],
|
||||||
|
'repository' => ['path' => 'app/Repositories', 'generate' => false],
|
||||||
|
'resource' => ['path' => 'app/Transformers', 'generate' => false],
|
||||||
|
'rules' => ['path' => 'app/Rules', 'generate' => false],
|
||||||
|
'component-class' => ['path' => 'app/View/Components', 'generate' => false],
|
||||||
|
'service' => ['path' => 'app/Services', 'generate' => false],
|
||||||
|
|
||||||
|
// app/Http/
|
||||||
|
'controller' => ['path' => 'app/Http/Controllers', 'generate' => true],
|
||||||
|
'filter' => ['path' => 'app/Http/Middleware', 'generate' => false],
|
||||||
|
'request' => ['path' => 'app/Http/Requests', 'generate' => false],
|
||||||
|
|
||||||
|
// config/
|
||||||
'config' => ['path' => 'config', 'generate' => true],
|
'config' => ['path' => 'config', 'generate' => true],
|
||||||
'command' => ['path' => 'App/Console', 'generate' => false],
|
|
||||||
'channels' => ['path' => 'App/Broadcasting', 'generate' => false],
|
// database/
|
||||||
'migration' => ['path' => 'Database/migrations', 'generate' => false],
|
'migration' => ['path' => 'database/migrations', 'generate' => true],
|
||||||
'seeder' => ['path' => 'Database/Seeders', 'generate' => true],
|
'seeder' => ['path' => 'database/seeders', 'namespace' => 'Database\Seeders', 'generate' => true],
|
||||||
'factory' => ['path' => 'Database/Factories', 'generate' => false],
|
'factory' => ['path' => 'database/factories', 'namespace' => 'Database\Factories', 'generate' => true],
|
||||||
'model' => ['path' => 'App/Models', 'generate' => false],
|
|
||||||
'observer' => ['path' => 'App/Observers', 'generate' => false],
|
// lang/
|
||||||
'routes' => ['path' => 'routes', 'generate' => true],
|
|
||||||
'controller' => ['path' => 'App/Http/Controllers', 'generate' => true],
|
|
||||||
'filter' => ['path' => 'App/Http/Middleware', 'generate' => false],
|
|
||||||
'request' => ['path' => 'App/Http/Requests', 'generate' => false],
|
|
||||||
'provider' => ['path' => 'App/Providers', 'generate' => true],
|
|
||||||
'assets' => ['path' => 'resources/assets', 'generate' => false],
|
|
||||||
'lang' => ['path' => 'lang', 'generate' => false],
|
'lang' => ['path' => 'lang', 'generate' => false],
|
||||||
|
|
||||||
|
// resource/
|
||||||
|
'assets' => ['path' => 'resources/assets', 'generate' => true],
|
||||||
'views' => ['path' => 'resources/views', 'generate' => true],
|
'views' => ['path' => 'resources/views', 'generate' => true],
|
||||||
'test' => ['path' => 'tests/Unit', 'generate' => false],
|
|
||||||
'test-feature' => ['path' => 'tests/Feature', 'generate' => false],
|
|
||||||
'repository' => ['path' => 'App/Repositories', 'generate' => false],
|
|
||||||
'event' => ['path' => 'App/Events', 'generate' => false],
|
|
||||||
'listener' => ['path' => 'App/Listeners', 'generate' => false],
|
|
||||||
'policies' => ['path' => 'App/Policies', 'generate' => false],
|
|
||||||
'rules' => ['path' => 'App/Rules', 'generate' => false],
|
|
||||||
'jobs' => ['path' => 'App/Jobs', 'generate' => false],
|
|
||||||
'emails' => ['path' => 'App/Emails', 'generate' => false],
|
|
||||||
'notifications' => ['path' => 'App/Notifications', 'generate' => false],
|
|
||||||
'resource' => ['path' => 'App/resources', 'generate' => false],
|
|
||||||
'component-view' => ['path' => 'resources/views/components', 'generate' => false],
|
'component-view' => ['path' => 'resources/views/components', 'generate' => false],
|
||||||
'component-class' => ['path' => 'App/View/Components', 'generate' => false],
|
|
||||||
|
// routes/
|
||||||
|
'routes' => ['path' => 'routes', 'generate' => true],
|
||||||
|
|
||||||
|
// tests/
|
||||||
|
'test-unit' => ['path' => 'tests/Unit', 'generate' => true],
|
||||||
|
'test-feature' => ['path' => 'tests/Feature', 'generate' => true],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -158,13 +186,13 @@ return [
|
|||||||
| directory. This is useful if you host the package in packagist website.
|
| directory. This is useful if you host the package in packagist website.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'scan' => [
|
'scan' => [
|
||||||
'enabled' => false,
|
'enabled' => false,
|
||||||
'paths' => [
|
'paths' => [
|
||||||
base_path('vendor/*/*'),
|
base_path('vendor/*/*'),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Composer File Template
|
| Composer File Template
|
||||||
@@ -173,12 +201,11 @@ return [
|
|||||||
| Here is the config for the composer.json file, generated by this package
|
| Here is the config for the composer.json file, generated by this package
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'composer' => [
|
'composer' => [
|
||||||
'vendor' => 'nwidart',
|
'vendor' => env('MODULE_VENDOR', 'solidtime-io'),
|
||||||
'author' => [
|
'author' => [
|
||||||
'name' => 'Nicolas Widart',
|
'name' => env('MODULE_AUTHOR_NAME', 'Nicolas Widart'),
|
||||||
'email' => 'n.widart@gmail.com',
|
'email' => env('MODULE_AUTHOR_EMAIL', 'n.widart@gmail.com'),
|
||||||
],
|
],
|
||||||
'composer-output' => false,
|
'composer-output' => false,
|
||||||
],
|
],
|
||||||
@@ -192,11 +219,12 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
'cache' => [
|
'cache' => [
|
||||||
'enabled' => false,
|
'enabled' => env('MODULES_CACHE_ENABLED', false),
|
||||||
'driver' => 'file',
|
'driver' => env('MODULES_CACHE_DRIVER', 'file'),
|
||||||
'key' => 'laravel-modules',
|
'key' => env('MODULES_CACHE_KEY', 'laravel-modules'),
|
||||||
'lifetime' => 60,
|
'lifetime' => env('MODULES_CACHE_LIFETIME', 60),
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Choose what laravel-modules will register as custom namespaces.
|
| Choose what laravel-modules will register as custom namespaces.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Database\Factories;
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Enums\Weekday;
|
use App\Enums\Weekday;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
@@ -100,7 +101,9 @@ class UserFactory extends Factory
|
|||||||
->when(is_callable($callback), $callback)
|
->when(is_callable($callback), $callback)
|
||||||
->create();
|
->create();
|
||||||
|
|
||||||
$organization->users()->attach($user, ['role' => 'owner']);
|
$organization->users()->attach($user, ['role' => Role::Owner->value]);
|
||||||
|
$user->currentTeam()->associate($organization);
|
||||||
|
$user->save();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ class DatabaseSeeder extends Seeder
|
|||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
$this->deleteAll();
|
$this->deleteAll();
|
||||||
$userAcmeOwner = User::factory()->create([
|
$userAcmeOwner = User::factory()->withPersonalOrganization()->create([
|
||||||
'name' => 'Acme Owner',
|
'name' => 'Acme Owner',
|
||||||
'email' => 'owner@acme.test',
|
'email' => 'owner@acme.test',
|
||||||
]);
|
]);
|
||||||
$organizationAcme = Organization::factory()->withOwner($userAcmeOwner)->create([
|
$organizationAcme = Organization::factory()->withOwner($userAcmeOwner)->create([
|
||||||
'name' => 'ACME Corp',
|
'name' => 'ACME Corp',
|
||||||
|
'personal_team' => false,
|
||||||
|
'currency' => 'EUR',
|
||||||
]);
|
]);
|
||||||
$userAcmeManager = User::factory()->withPersonalOrganization()->create([
|
$userAcmeManager = User::factory()->withPersonalOrganization()->create([
|
||||||
'name' => 'Acme Manager',
|
'name' => 'Acme Manager',
|
||||||
@@ -80,29 +82,35 @@ class DatabaseSeeder extends Seeder
|
|||||||
->forUser($userAcmeEmployee)
|
->forUser($userAcmeEmployee)
|
||||||
->forOrganization($organizationAcme)
|
->forOrganization($organizationAcme)
|
||||||
->create();
|
->create();
|
||||||
$client = Client::factory()->create([
|
$client = Client::factory()->forOrganization($organizationAcme)->create([
|
||||||
'name' => 'Big Company',
|
'name' => 'Big Company',
|
||||||
]);
|
]);
|
||||||
$bigCompanyProject = Project::factory()->forClient($client)->create([
|
$bigCompanyProject = Project::factory()->forOrganization($organizationAcme)->forClient($client)->create([
|
||||||
'name' => 'Big Company Project',
|
'name' => 'Big Company Project',
|
||||||
]);
|
]);
|
||||||
Task::factory()->forProject($bigCompanyProject)->create();
|
Task::factory()->forOrganization($organizationAcme)->forProject($bigCompanyProject)->create();
|
||||||
|
|
||||||
$internalProject = Project::factory()->create([
|
$internalProject = Project::factory()->forOrganization($organizationAcme)->create([
|
||||||
'name' => 'Internal Project',
|
'name' => 'Internal Project',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$organization2 = Organization::factory()->create([
|
$organization2Owner = User::factory()->create([
|
||||||
|
'name' => 'Other Owner',
|
||||||
|
'email' => 'owner@rival-company.test',
|
||||||
|
]);
|
||||||
|
$organization2 = Organization::factory()->withOwner($organization2Owner)->create([
|
||||||
'name' => 'Rival Corp',
|
'name' => 'Rival Corp',
|
||||||
|
'personal_team' => true,
|
||||||
|
'currency' => 'USD',
|
||||||
]);
|
]);
|
||||||
$userAcmeManager = User::factory()->withPersonalOrganization()->create([
|
$userAcmeManager = User::factory()->withPersonalOrganization()->create([
|
||||||
'name' => 'Other User',
|
'name' => 'Other User',
|
||||||
'email' => 'test@rival-company.test',
|
'email' => 'test@rival-company.test',
|
||||||
]);
|
]);
|
||||||
$userAcmeManager->organizations()->attach($organization2, [
|
$userAcmeManager->organizations()->attach($organization2, [
|
||||||
'role' => 'admin',
|
'role' => Role::Admin->value,
|
||||||
]);
|
]);
|
||||||
$otherCompanyProject = Project::factory()->forClient($client)->create([
|
$otherCompanyProject = Project::factory()->forOrganization($organization2)->forClient($client)->create([
|
||||||
'name' => 'Scale Company',
|
'name' => 'Scale Company',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Models\Membership;
|
use App\Models\Membership;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
@@ -29,6 +30,6 @@ class CreateTeamTest extends TestCase
|
|||||||
$this->assertCount(2, $user->fresh()->ownedTeams);
|
$this->assertCount(2, $user->fresh()->ownedTeams);
|
||||||
$this->assertEquals('Test Organization', $newOrganization->name);
|
$this->assertEquals('Test Organization', $newOrganization->name);
|
||||||
$member = Membership::query()->whereBelongsTo($user, 'user')->whereBelongsTo($newOrganization, 'organization')->firstOrFail();
|
$member = Membership::query()->whereBelongsTo($user, 'user')->whereBelongsTo($newOrganization, 'organization')->firstOrFail();
|
||||||
$this->assertSame('owner', $member->role);
|
$this->assertSame(Role::Owner->value, $member->role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Models\Membership;
|
use App\Models\Membership;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Providers\RouteServiceProvider;
|
use App\Providers\RouteServiceProvider;
|
||||||
@@ -58,7 +59,7 @@ class RegistrationTest extends TestCase
|
|||||||
$organization = $user->organizations()->firstOrFail();
|
$organization = $user->organizations()->firstOrFail();
|
||||||
$this->assertSame(true, $organization->personal_team);
|
$this->assertSame(true, $organization->personal_team);
|
||||||
$member = Membership::query()->whereBelongsTo($user, 'user')->whereBelongsTo($organization, 'organization')->firstOrFail();
|
$member = Membership::query()->whereBelongsTo($user, 'user')->whereBelongsTo($organization, 'organization')->firstOrFail();
|
||||||
$this->assertSame('owner', $member->role);
|
$this->assertSame(Role::Owner->value, $member->role);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_new_users_can_register_and_frontend_can_send_timezone_for_user(): void
|
public function test_new_users_can_register_and_frontend_can_send_timezone_for_user(): void
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
@@ -64,12 +65,12 @@ class UpdateTeamMemberRoleTest extends TestCase
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
$response = $this->withoutExceptionHandling()->put('/teams/'.$user->currentTeam->id.'/members/'.$otherUser->getKey(), [
|
$response = $this->withoutExceptionHandling()->put('/teams/'.$user->currentTeam->id.'/members/'.$otherUser->getKey(), [
|
||||||
'role' => 'owner',
|
'role' => Role::Owner->value,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
$this->assertTrue($otherUser->fresh()->hasTeamRole(
|
$this->assertTrue($otherUser->fresh()->hasTeamRole(
|
||||||
$user->currentTeam->fresh(), 'owner'
|
$user->currentTeam->fresh(), Role::Owner->value
|
||||||
));
|
));
|
||||||
$this->assertSame($user->currentTeam->fresh()->user_id, $otherUser->getKey());
|
$this->assertSame($user->currentTeam->fresh()->user_id, $otherUser->getKey());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Tests\Unit\Service;
|
namespace Tests\Unit\Service;
|
||||||
|
|
||||||
|
use App\Enums\Role;
|
||||||
use App\Enums\Weekday;
|
use App\Enums\Weekday;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
@@ -267,7 +268,7 @@ class DashboardServiceTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
$organization = Organization::factory()->withOwner($user)->create();
|
$organization = Organization::factory()->withOwner($user)->create();
|
||||||
$organization->users()->attach($user, [
|
$organization->users()->attach($user, [
|
||||||
'role' => 'owner',
|
'role' => Role::Owner->value,
|
||||||
]);
|
]);
|
||||||
$project1 = Project::factory()->forOrganization($organization)->create();
|
$project1 = Project::factory()->forOrganization($organization)->create();
|
||||||
$project2 = Project::factory()->forOrganization($organization)->create();
|
$project2 = Project::factory()->forOrganization($organization)->create();
|
||||||
|
|||||||
Reference in New Issue
Block a user