mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-08 00:02:15 +01:00
Renamed jetstream team to organization
This commit is contained in:
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Fortify;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
@@ -46,9 +46,9 @@ class CreateNewUser implements CreatesNewUsers
|
||||
*/
|
||||
protected function createTeam(User $user): void
|
||||
{
|
||||
$user->ownedTeams()->save(Team::forceCreate([
|
||||
$user->ownedTeams()->save(Organization::forceCreate([
|
||||
'user_id' => $user->id,
|
||||
'name' => explode(' ', $user->name, 2)[0]."'s Team",
|
||||
'name' => explode(' ', $user->name, 2)[0]."'s Organization",
|
||||
'personal_team' => true,
|
||||
]));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
@@ -15,32 +15,32 @@ use Laravel\Jetstream\Events\TeamMemberAdded;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
use Laravel\Jetstream\Rules\Role;
|
||||
|
||||
class AddTeamMember implements AddsTeamMembers
|
||||
class AddOrganizationMember implements AddsTeamMembers
|
||||
{
|
||||
/**
|
||||
* Add a new team member to the given team.
|
||||
*/
|
||||
public function add(User $user, Team $team, string $email, ?string $role = null): void
|
||||
public function add(User $user, Organization $organization, string $email, ?string $role = null): void
|
||||
{
|
||||
Gate::forUser($user)->authorize('addTeamMember', $team);
|
||||
Gate::forUser($user)->authorize('addTeamMember', $organization);
|
||||
|
||||
$this->validate($team, $email, $role);
|
||||
$this->validate($organization, $email, $role);
|
||||
|
||||
$newTeamMember = Jetstream::findUserByEmailOrFail($email);
|
||||
|
||||
AddingTeamMember::dispatch($team, $newTeamMember);
|
||||
AddingTeamMember::dispatch($organization, $newTeamMember);
|
||||
|
||||
$team->users()->attach(
|
||||
$organization->users()->attach(
|
||||
$newTeamMember, ['role' => $role]
|
||||
);
|
||||
|
||||
TeamMemberAdded::dispatch($team, $newTeamMember);
|
||||
TeamMemberAdded::dispatch($organization, $newTeamMember);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the add member operation.
|
||||
*/
|
||||
protected function validate(Team $team, string $email, ?string $role): void
|
||||
protected function validate(Organization $organization, string $email, ?string $role): void
|
||||
{
|
||||
Validator::make([
|
||||
'email' => $email,
|
||||
@@ -48,7 +48,7 @@ class AddTeamMember implements AddsTeamMembers
|
||||
], $this->rules(), [
|
||||
'email.exists' => __('We were unable to find a registered user with this email address.'),
|
||||
])->after(
|
||||
$this->ensureUserIsNotAlreadyOnTeam($team, $email)
|
||||
$this->ensureUserIsNotAlreadyOnTeam($organization, $email)
|
||||
)->validateWithBag('addTeamMember');
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ class AddTeamMember implements AddsTeamMembers
|
||||
/**
|
||||
* Ensure that the user is not already on the team.
|
||||
*/
|
||||
protected function ensureUserIsNotAlreadyOnTeam(Team $team, string $email): Closure
|
||||
protected function ensureUserIsNotAlreadyOnTeam(Organization $team, string $email): Closure
|
||||
{
|
||||
return function ($validator) use ($team, $email) {
|
||||
$validator->errors()->addIf(
|
||||
@@ -4,22 +4,27 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Laravel\Jetstream\Contracts\CreatesTeams;
|
||||
use Laravel\Jetstream\Events\AddingTeam;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
|
||||
class CreateTeam implements CreatesTeams
|
||||
class CreateOrganization implements CreatesTeams
|
||||
{
|
||||
/**
|
||||
* Validate and create a new team for the given user.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
*
|
||||
* @throws AuthorizationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function create(User $user, array $input): Team
|
||||
public function create(User $user, array $input): Organization
|
||||
{
|
||||
Gate::forUser($user)->authorize('create', Jetstream::newTeamModel());
|
||||
|
||||
@@ -29,11 +34,14 @@ class CreateTeam implements CreatesTeams
|
||||
|
||||
AddingTeam::dispatch($user);
|
||||
|
||||
$user->switchTeam($team = $user->ownedTeams()->create([
|
||||
/** @var Organization $organization */
|
||||
$organization = $user->ownedTeams()->create([
|
||||
'name' => $input['name'],
|
||||
'personal_team' => false,
|
||||
]));
|
||||
]);
|
||||
|
||||
return $team;
|
||||
$user->switchTeam($organization);
|
||||
|
||||
return $organization;
|
||||
}
|
||||
}
|
||||
@@ -4,15 +4,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use Laravel\Jetstream\Contracts\DeletesTeams;
|
||||
|
||||
class DeleteTeam implements DeletesTeams
|
||||
class DeleteOrganization implements DeletesTeams
|
||||
{
|
||||
/**
|
||||
* Delete the given team.
|
||||
*/
|
||||
public function delete(Team $team): void
|
||||
public function delete(Organization $team): void
|
||||
{
|
||||
$team->purge();
|
||||
}
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Jetstream\Contracts\DeletesTeams;
|
||||
@@ -47,7 +47,7 @@ class DeleteUser implements DeletesUsers
|
||||
{
|
||||
$user->teams()->detach();
|
||||
|
||||
$user->ownedTeams->each(function (Team $team) {
|
||||
$user->ownedTeams->each(function (Organization $team) {
|
||||
$this->deletesTeams->delete($team);
|
||||
});
|
||||
}
|
||||
|
||||
94
app/Actions/Jetstream/InviteOrganizationMember.php
Normal file
94
app/Actions/Jetstream/InviteOrganizationMember.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Organization;
|
||||
use App\Models\OrganizationInvitation;
|
||||
use App\Models\User;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
|
||||
use Laravel\Jetstream\Contracts\InvitesTeamMembers;
|
||||
use Laravel\Jetstream\Events\InvitingTeamMember;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
use Laravel\Jetstream\Mail\TeamInvitation;
|
||||
use Laravel\Jetstream\Rules\Role;
|
||||
|
||||
class InviteOrganizationMember implements InvitesTeamMembers
|
||||
{
|
||||
/**
|
||||
* Invite a new team member to the given team.
|
||||
*/
|
||||
public function invite(User $user, Organization $organization, string $email, ?string $role = null): void
|
||||
{
|
||||
Gate::forUser($user)->authorize('addTeamMember', $organization);
|
||||
|
||||
$this->validate($organization, $email, $role);
|
||||
|
||||
InvitingTeamMember::dispatch($organization, $email, $role);
|
||||
|
||||
$invitation = $organization->teamInvitations()->create([
|
||||
'email' => $email,
|
||||
'role' => $role,
|
||||
]);
|
||||
|
||||
Mail::to($email)->send(new TeamInvitation($invitation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the invite member operation.
|
||||
*/
|
||||
protected function validate(Organization $organization, string $email, ?string $role): void
|
||||
{
|
||||
Validator::make([
|
||||
'email' => $email,
|
||||
'role' => $role,
|
||||
], $this->rules($organization), [
|
||||
'email.unique' => __('This user has already been invited to the team.'),
|
||||
])->after(
|
||||
$this->ensureUserIsNotAlreadyOnTeam($organization, $email)
|
||||
)->validateWithBag('addTeamMember');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for inviting a team member.
|
||||
*
|
||||
* @return array<string, ValidationRule|array|string>
|
||||
*/
|
||||
protected function rules(Organization $organization): array
|
||||
{
|
||||
return array_filter([
|
||||
'email' => [
|
||||
'required',
|
||||
'email',
|
||||
new UniqueEloquent(OrganizationInvitation::class, 'email', function (Builder $builder) use ($organization) {
|
||||
/** @var Builder<OrganizationInvitation> $builder */
|
||||
return $builder->whereBelongsTo($organization, 'organization');
|
||||
}),
|
||||
],
|
||||
'role' => Jetstream::hasRoles()
|
||||
? ['required', 'string', new Role]
|
||||
: null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the user is not already on the team.
|
||||
*/
|
||||
protected function ensureUserIsNotAlreadyOnTeam(Organization $organization, string $email): Closure
|
||||
{
|
||||
return function ($validator) use ($organization, $email) {
|
||||
$validator->errors()->addIf(
|
||||
$organization->hasUserWithEmail($email),
|
||||
'email',
|
||||
__('This user already belongs to the team.')
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Closure;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Laravel\Jetstream\Contracts\InvitesTeamMembers;
|
||||
use Laravel\Jetstream\Events\InvitingTeamMember;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
use Laravel\Jetstream\Mail\TeamInvitation;
|
||||
use Laravel\Jetstream\Rules\Role;
|
||||
|
||||
class InviteTeamMember implements InvitesTeamMembers
|
||||
{
|
||||
/**
|
||||
* Invite a new team member to the given team.
|
||||
*/
|
||||
public function invite(User $user, Team $team, string $email, ?string $role = null): void
|
||||
{
|
||||
Gate::forUser($user)->authorize('addTeamMember', $team);
|
||||
|
||||
$this->validate($team, $email, $role);
|
||||
|
||||
InvitingTeamMember::dispatch($team, $email, $role);
|
||||
|
||||
$invitation = $team->teamInvitations()->create([
|
||||
'email' => $email,
|
||||
'role' => $role,
|
||||
]);
|
||||
|
||||
Mail::to($email)->send(new TeamInvitation($invitation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the invite member operation.
|
||||
*/
|
||||
protected function validate(Team $team, string $email, ?string $role): void
|
||||
{
|
||||
Validator::make([
|
||||
'email' => $email,
|
||||
'role' => $role,
|
||||
], $this->rules($team), [
|
||||
'email.unique' => __('This user has already been invited to the team.'),
|
||||
])->after(
|
||||
$this->ensureUserIsNotAlreadyOnTeam($team, $email)
|
||||
)->validateWithBag('addTeamMember');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules for inviting a team member.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
|
||||
*/
|
||||
protected function rules(Team $team): array
|
||||
{
|
||||
return array_filter([
|
||||
'email' => [
|
||||
'required', 'email',
|
||||
Rule::unique('team_invitations')->where(function (Builder $query) use ($team) {
|
||||
$query->where('team_id', $team->id);
|
||||
}),
|
||||
],
|
||||
'role' => Jetstream::hasRoles()
|
||||
? ['required', 'string', new Role]
|
||||
: null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the user is not already on the team.
|
||||
*/
|
||||
protected function ensureUserIsNotAlreadyOnTeam(Team $team, string $email): Closure
|
||||
{
|
||||
return function ($validator) use ($team, $email) {
|
||||
$validator->errors()->addIf(
|
||||
$team->hasUserWithEmail($email),
|
||||
'email',
|
||||
__('This user already belongs to the team.')
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
@@ -12,28 +12,28 @@ use Illuminate\Validation\ValidationException;
|
||||
use Laravel\Jetstream\Contracts\RemovesTeamMembers;
|
||||
use Laravel\Jetstream\Events\TeamMemberRemoved;
|
||||
|
||||
class RemoveTeamMember implements RemovesTeamMembers
|
||||
class RemoveOrganizationMember implements RemovesTeamMembers
|
||||
{
|
||||
/**
|
||||
* Remove the team member from the given team.
|
||||
*/
|
||||
public function remove(User $user, Team $team, User $teamMember): void
|
||||
public function remove(User $user, Organization $organization, User $teamMember): void
|
||||
{
|
||||
$this->authorize($user, $team, $teamMember);
|
||||
$this->authorize($user, $organization, $teamMember);
|
||||
|
||||
$this->ensureUserDoesNotOwnTeam($teamMember, $team);
|
||||
$this->ensureUserDoesNotOwnTeam($teamMember, $organization);
|
||||
|
||||
$team->removeUser($teamMember);
|
||||
$organization->removeUser($teamMember);
|
||||
|
||||
TeamMemberRemoved::dispatch($team, $teamMember);
|
||||
TeamMemberRemoved::dispatch($organization, $teamMember);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize that the user can remove the team member.
|
||||
*/
|
||||
protected function authorize(User $user, Team $team, User $teamMember): void
|
||||
protected function authorize(User $user, Organization $organization, User $teamMember): void
|
||||
{
|
||||
if (! Gate::forUser($user)->check('removeTeamMember', $team) &&
|
||||
if (! Gate::forUser($user)->check('removeTeamMember', $organization) &&
|
||||
$user->id !== $teamMember->id) {
|
||||
throw new AuthorizationException;
|
||||
}
|
||||
@@ -42,9 +42,9 @@ class RemoveTeamMember implements RemovesTeamMembers
|
||||
/**
|
||||
* Ensure that the currently authenticated user does not own the team.
|
||||
*/
|
||||
protected function ensureUserDoesNotOwnTeam(User $teamMember, Team $team): void
|
||||
protected function ensureUserDoesNotOwnTeam(User $teamMember, Organization $organization): void
|
||||
{
|
||||
if ($teamMember->id === $team->owner->id) {
|
||||
if ($teamMember->id === $organization->owner->id) {
|
||||
throw ValidationException::withMessages([
|
||||
'team' => [__('You may not leave a team that you created.')],
|
||||
])->errorBag('removeTeamMember');
|
||||
@@ -4,28 +4,33 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Actions\Jetstream;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Laravel\Jetstream\Contracts\UpdatesTeamNames;
|
||||
|
||||
class UpdateTeamName implements UpdatesTeamNames
|
||||
class UpdateOrganization implements UpdatesTeamNames
|
||||
{
|
||||
/**
|
||||
* Validate and update the given team's name.
|
||||
*
|
||||
* @param array<string, string> $input
|
||||
*
|
||||
* @throws AuthorizationException
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function update(User $user, Team $team, array $input): void
|
||||
public function update(User $user, Organization $organization, array $input): void
|
||||
{
|
||||
Gate::forUser($user)->authorize('update', $team);
|
||||
Gate::forUser($user)->authorize('update', $organization);
|
||||
|
||||
Validator::make($input, [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
])->validateWithBag('updateTeamName');
|
||||
|
||||
$team->forceFill([
|
||||
$organization->forceFill([
|
||||
'name' => $input['name'],
|
||||
])->save();
|
||||
}
|
||||
@@ -14,7 +14,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
* @property string $id
|
||||
* @property string $name
|
||||
* @property string $organization_id
|
||||
* @property-read Team $organization
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
* @property-read Organization $organization
|
||||
*
|
||||
* @method static ClientFactory factory()
|
||||
*/
|
||||
@@ -33,10 +35,10 @@ class Client extends Model
|
||||
];
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Team, Client>
|
||||
* @return BelongsTo<Organization, Client>
|
||||
*/
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Team::class, 'organization_id');
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,14 +7,24 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Laravel\Jetstream\Membership as JetstreamMembership;
|
||||
|
||||
/**
|
||||
* @property string $id
|
||||
* @property string $role
|
||||
* @property string $organization_id
|
||||
* @property string $user_id
|
||||
* @property string $created_at
|
||||
* @property string $updated_at
|
||||
* @property-read Organization $organization
|
||||
* @property-read User $user
|
||||
*/
|
||||
class Membership extends JetstreamMembership
|
||||
{
|
||||
use HasUuids;
|
||||
|
||||
/**
|
||||
* Indicates if the IDs are auto-incrementing.
|
||||
* The table associated with the pivot model.
|
||||
*
|
||||
* @var bool
|
||||
* @var string
|
||||
*/
|
||||
public $incrementing = true;
|
||||
protected $table = 'organization_user';
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\TeamFactory;
|
||||
use Database\Factories\OrganizationFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
@@ -17,10 +17,10 @@ use Laravel\Jetstream\Team as JetstreamTeam;
|
||||
* @property string $id
|
||||
* @property User $owner
|
||||
*
|
||||
* @method HasMany<TeamInvitation> teamInvitations()
|
||||
* @method static TeamFactory factory()
|
||||
* @method HasMany<OrganizationInvitation> teamInvitations()
|
||||
* @method static OrganizationFactory factory()
|
||||
*/
|
||||
class Team extends JetstreamTeam
|
||||
class Organization extends JetstreamTeam
|
||||
{
|
||||
use HasFactory;
|
||||
use HasUuids;
|
||||
52
app/Models/OrganizationInvitation.php
Normal file
52
app/Models/OrganizationInvitation.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
use Laravel\Jetstream\TeamInvitation as JetstreamTeamInvitation;
|
||||
|
||||
/**
|
||||
* @property string $id
|
||||
* @property string $email
|
||||
*/
|
||||
class OrganizationInvitation extends JetstreamTeamInvitation
|
||||
{
|
||||
use HasUuids;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'organization_invitations';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'email',
|
||||
'role',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the organization that the invitation belongs to.
|
||||
*/
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Jetstream::teamModel(), 'organization_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the organization that the invitation belongs to.
|
||||
*/
|
||||
public function team(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Jetstream::teamModel(), 'organization_id');
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
* @property string $name
|
||||
* @property string $organization_id
|
||||
* @property string $client_id
|
||||
* @property-read Team $organization
|
||||
* @property-read Organization $organization
|
||||
* @property-read Client|null $client
|
||||
* @property-read Collection<Task> $tasks
|
||||
*
|
||||
@@ -38,11 +38,11 @@ class Project extends Model
|
||||
];
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Team, Project>
|
||||
* @return BelongsTo<Organization, Project>
|
||||
*/
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Team::class, 'organization_id');
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
* @property string $id
|
||||
* @property string $name
|
||||
* @property string $organization_id
|
||||
* @property-read Team $organization
|
||||
* @property-read Organization $organization
|
||||
*
|
||||
* @method static TagFactory factory()
|
||||
*/
|
||||
@@ -33,10 +33,10 @@ class Tag extends Model
|
||||
];
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Team, Tag>
|
||||
* @return BelongsTo<Organization, Tag>
|
||||
*/
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Team::class, 'organization_id');
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
* @property string $project_id
|
||||
* @property string $organization_id
|
||||
* @property-read Project $project
|
||||
* @property-read Team $organization
|
||||
* @property-read Organization $organization
|
||||
*
|
||||
* @method static TaskFactory factory()
|
||||
*/
|
||||
@@ -43,10 +43,10 @@ class Task extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Team, Task>
|
||||
* @return BelongsTo<Organization, Task>
|
||||
*/
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Team::class, 'organization_id');
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
use Laravel\Jetstream\TeamInvitation as JetstreamTeamInvitation;
|
||||
|
||||
class TeamInvitation extends JetstreamTeamInvitation
|
||||
{
|
||||
use HasUuids;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'email',
|
||||
'role',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the team that the invitation belongs to.
|
||||
*/
|
||||
public function team(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Jetstream::teamModel());
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ use Illuminate\Support\Carbon;
|
||||
* @property bool $billable
|
||||
* @property array $tags
|
||||
* @property-read User $user
|
||||
* @property-read Team $organization
|
||||
* @property-read Organization $organization
|
||||
* @property-read Project|null $project
|
||||
* @property-read Task|null $task
|
||||
*
|
||||
@@ -52,11 +52,11 @@ class TimeEntry extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Team, TimeEntry>
|
||||
* @return BelongsTo<Organization, TimeEntry>
|
||||
*/
|
||||
public function organization(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Team::class, 'organization_id');
|
||||
return $this->belongsTo(Organization::class, 'organization_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ use Database\Factories\UserFactory;
|
||||
use Filament\Panel;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
@@ -20,7 +21,7 @@ use Laravel\Passport\HasApiTokens;
|
||||
* @property string $id
|
||||
* @property string $name
|
||||
*
|
||||
* @method HasMany<Team> ownedTeams()
|
||||
* @method HasMany<Organization> ownedTeams()
|
||||
* @method static UserFactory factory()
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
@@ -79,4 +80,17 @@ class User extends Authenticatable
|
||||
// TODO: Implement canAccessPanel() method.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsToMany<Organization>
|
||||
*/
|
||||
public function organizations(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Organization::class, Membership::class)
|
||||
->withPivot([
|
||||
'role',
|
||||
])
|
||||
->withTimestamps()
|
||||
->as('membership');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class TeamPolicy
|
||||
class OrganizationPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
@@ -23,9 +23,9 @@ class TeamPolicy
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, Team $team): bool
|
||||
public function view(User $user, Organization $organization): bool
|
||||
{
|
||||
return $user->belongsToTeam($team);
|
||||
return $user->belongsToTeam($organization);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,40 +39,40 @@ class TeamPolicy
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, Team $team): bool
|
||||
public function update(User $user, Organization $organization): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
return $user->ownsTeam($organization);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can add team members.
|
||||
*/
|
||||
public function addTeamMember(User $user, Team $team): bool
|
||||
public function addTeamMember(User $user, Organization $organization): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
return $user->ownsTeam($organization);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update team member permissions.
|
||||
*/
|
||||
public function updateTeamMember(User $user, Team $team): bool
|
||||
public function updateTeamMember(User $user, Organization $organization): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
return $user->ownsTeam($organization);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can remove team members.
|
||||
*/
|
||||
public function removeTeamMember(User $user, Team $team): bool
|
||||
public function removeTeamMember(User $user, Organization $organization): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
return $user->ownsTeam($organization);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, Team $team): bool
|
||||
public function delete(User $user, Organization $organization): bool
|
||||
{
|
||||
return $user->ownsTeam($team);
|
||||
return $user->ownsTeam($organization);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@ declare(strict_types=1);
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Membership;
|
||||
use App\Models\Team;
|
||||
use App\Models\TeamInvitation;
|
||||
use App\Models\Organization;
|
||||
use App\Models\OrganizationInvitation;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
@@ -31,8 +31,8 @@ class AppServiceProvider extends ServiceProvider
|
||||
Model::preventSilentlyDiscardingAttributes(! $this->app->isProduction());
|
||||
Relation::enforceMorphMap([
|
||||
'membership' => Membership::class,
|
||||
'team' => Team::class,
|
||||
'team_invitation' => TeamInvitation::class,
|
||||
'team' => Organization::class,
|
||||
'team_invitation' => OrganizationInvitation::class,
|
||||
'user' => User::class,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
// use Illuminate\Support\Facades\Gate;
|
||||
use App\Models\Organization;
|
||||
use App\Policies\OrganizationPolicy;
|
||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
use Laravel\Passport\Passport;
|
||||
@@ -17,7 +18,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||
* @var array<class-string, class-string>
|
||||
*/
|
||||
protected $policies = [
|
||||
//
|
||||
Organization::class => OrganizationPolicy::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,13 +4,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Actions\Jetstream\AddTeamMember;
|
||||
use App\Actions\Jetstream\CreateTeam;
|
||||
use App\Actions\Jetstream\DeleteTeam;
|
||||
use App\Actions\Jetstream\AddOrganizationMember;
|
||||
use App\Actions\Jetstream\CreateOrganization;
|
||||
use App\Actions\Jetstream\DeleteOrganization;
|
||||
use App\Actions\Jetstream\DeleteUser;
|
||||
use App\Actions\Jetstream\InviteTeamMember;
|
||||
use App\Actions\Jetstream\RemoveTeamMember;
|
||||
use App\Actions\Jetstream\UpdateTeamName;
|
||||
use App\Actions\Jetstream\InviteOrganizationMember;
|
||||
use App\Actions\Jetstream\RemoveOrganizationMember;
|
||||
use App\Actions\Jetstream\UpdateOrganization;
|
||||
use App\Models\Organization;
|
||||
use App\Models\OrganizationInvitation;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Jetstream\Jetstream;
|
||||
|
||||
@@ -31,13 +33,15 @@ class JetstreamServiceProvider extends ServiceProvider
|
||||
{
|
||||
$this->configurePermissions();
|
||||
|
||||
Jetstream::createTeamsUsing(CreateTeam::class);
|
||||
Jetstream::updateTeamNamesUsing(UpdateTeamName::class);
|
||||
Jetstream::addTeamMembersUsing(AddTeamMember::class);
|
||||
Jetstream::inviteTeamMembersUsing(InviteTeamMember::class);
|
||||
Jetstream::removeTeamMembersUsing(RemoveTeamMember::class);
|
||||
Jetstream::deleteTeamsUsing(DeleteTeam::class);
|
||||
Jetstream::createTeamsUsing(CreateOrganization::class);
|
||||
Jetstream::updateTeamNamesUsing(UpdateOrganization::class);
|
||||
Jetstream::addTeamMembersUsing(AddOrganizationMember::class);
|
||||
Jetstream::inviteTeamMembersUsing(InviteOrganizationMember::class);
|
||||
Jetstream::removeTeamMembersUsing(RemoveOrganizationMember::class);
|
||||
Jetstream::deleteTeamsUsing(DeleteOrganization::class);
|
||||
Jetstream::deleteUsersUsing(DeleteUser::class);
|
||||
Jetstream::useTeamModel(Organization::class);
|
||||
Jetstream::useTeamInvitationModel(OrganizationInvitation::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"filament/filament": "^3.2",
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"inertiajs/inertia-laravel": "^0.6.8",
|
||||
"korridor/laravel-model-validation-rules": "^3.0",
|
||||
"laravel/framework": "^10.10",
|
||||
"laravel/jetstream": "^4.2",
|
||||
"laravel/passport": "*",
|
||||
|
||||
66
composer.lock
generated
66
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "34dbd2208afb93ce559614a5c014397e",
|
||||
"content-hash": "68ea9179372fd4db583f50784a1ca6f7",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anourvalar/eloquent-serialize",
|
||||
@@ -2509,6 +2509,70 @@
|
||||
},
|
||||
"time": "2023-12-07T10:44:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "korridor/laravel-model-validation-rules",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/korridor/laravel-model-validation-rules.git",
|
||||
"reference": "23537e5bd296a042bbe0c3a1c6d556c89dfbad42"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/korridor/laravel-model-validation-rules/zipball/23537e5bd296a042bbe0c3a1c6d556c89dfbad42",
|
||||
"reference": "23537e5bd296a042bbe0c3a1c6d556c89dfbad42",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/database": "^10",
|
||||
"illuminate/support": "^10",
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.6",
|
||||
"orchestra/testbench": "^8.0",
|
||||
"phpunit/phpunit": "^10",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Korridor\\LaravelModelValidationRules\\ModelValidationServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Korridor\\LaravelModelValidationRules\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "korridor",
|
||||
"email": "26689068+korridor@users.noreply.github.com"
|
||||
}
|
||||
],
|
||||
"description": "A laravel validation rule that uses eloquent to validate if a model exists",
|
||||
"homepage": "https://github.com/korridor/laravel-model-validation-rules",
|
||||
"keywords": [
|
||||
"eloquent",
|
||||
"exist",
|
||||
"laravel",
|
||||
"model",
|
||||
"rule",
|
||||
"validation"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/korridor/laravel-model-validation-rules/issues",
|
||||
"source": "https://github.com/korridor/laravel-model-validation-rules/tree/3.0.0"
|
||||
},
|
||||
"time": "2023-02-16T11:15:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/fortify",
|
||||
"version": "v1.20.0",
|
||||
|
||||
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
@@ -22,11 +22,11 @@ class ClientFactory extends Factory
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->company(),
|
||||
'organization_id' => Team::factory(),
|
||||
'organization_id' => Organization::factory(),
|
||||
];
|
||||
}
|
||||
|
||||
public function forOrganization(Team $organization): self
|
||||
public function forOrganization(Organization $organization): self
|
||||
{
|
||||
return $this->state(function (array $attributes) use ($organization) {
|
||||
return [
|
||||
|
||||
@@ -4,13 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Team>
|
||||
* @extends Factory<Organization>
|
||||
*/
|
||||
class TeamFactory extends Factory
|
||||
class OrganizationFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
@@ -5,8 +5,8 @@ declare(strict_types=1);
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Organization;
|
||||
use App\Models\Project;
|
||||
use App\Models\Team;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
@@ -24,12 +24,12 @@ class ProjectFactory extends Factory
|
||||
return [
|
||||
'name' => $this->faker->company(),
|
||||
'color' => $this->faker->hexColor(),
|
||||
'organization_id' => Team::factory(),
|
||||
'organization_id' => Organization::factory(),
|
||||
'client_id' => null,
|
||||
];
|
||||
}
|
||||
|
||||
public function forOrganization(Team $organization): self
|
||||
public function forOrganization(Organization $organization): self
|
||||
{
|
||||
return $this->state(function (array $attributes) use ($organization) {
|
||||
return [
|
||||
|
||||
@@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Organization;
|
||||
use App\Models\Tag;
|
||||
use App\Models\Team;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
@@ -22,11 +22,11 @@ class TagFactory extends Factory
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->name,
|
||||
'organization_id' => Team::factory(),
|
||||
'organization_id' => Organization::factory(),
|
||||
];
|
||||
}
|
||||
|
||||
public function forOrganization(Team $organization): self
|
||||
public function forOrganization(Organization $organization): self
|
||||
{
|
||||
return $this->state(function (array $attributes) use ($organization) {
|
||||
return [
|
||||
|
||||
@@ -4,9 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Organization;
|
||||
use App\Models\Project;
|
||||
use App\Models\Task;
|
||||
use App\Models\Team;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ class TaskFactory extends Factory
|
||||
return [
|
||||
'name' => $this->faker->word(),
|
||||
'project_id' => Project::factory(),
|
||||
'organization_id' => Team::factory(),
|
||||
'organization_id' => Organization::factory(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class TaskFactory extends Factory
|
||||
});
|
||||
}
|
||||
|
||||
public function forOrganization(Team $organization): self
|
||||
public function forOrganization(Organization $organization): self
|
||||
{
|
||||
return $this->state(function (array $attributes) use ($organization) {
|
||||
return [
|
||||
|
||||
@@ -4,9 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Organization;
|
||||
use App\Models\Project;
|
||||
use App\Models\Task;
|
||||
use App\Models\Team;
|
||||
use App\Models\TimeEntry;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
@@ -32,7 +32,7 @@ class TimeEntryFactory extends Factory
|
||||
'billable' => $this->faker->boolean(),
|
||||
'tags' => [],
|
||||
'user_id' => User::factory(),
|
||||
'organization_id' => Team::factory(),
|
||||
'organization_id' => Organization::factory(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class TimeEntryFactory extends Factory
|
||||
});
|
||||
}
|
||||
|
||||
public function forOrganization(Team $organization): self
|
||||
public function forOrganization(Organization $organization): self
|
||||
{
|
||||
return $this->state(function (array $attributes) use ($organization) {
|
||||
return [
|
||||
|
||||
@@ -4,14 +4,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Jetstream\Features;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
* @extends Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
@@ -50,16 +49,12 @@ class UserFactory extends Factory
|
||||
/**
|
||||
* Indicate that the user should have a personal team.
|
||||
*/
|
||||
public function withPersonalTeam(?callable $callback = null): static
|
||||
public function withPersonalOrganization(?callable $callback = null): static
|
||||
{
|
||||
if (! Features::hasTeamFeatures()) {
|
||||
return $this->state([]);
|
||||
}
|
||||
|
||||
return $this->has(
|
||||
Team::factory()
|
||||
Organization::factory()
|
||||
->state(fn (array $attributes, User $user) => [
|
||||
'name' => $user->name.'\'s Team',
|
||||
'name' => $user->name.'\'s Organization',
|
||||
'user_id' => $user->id,
|
||||
'personal_team' => true,
|
||||
])
|
||||
|
||||
@@ -13,7 +13,7 @@ return new class extends Migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('teams', function (Blueprint $table) {
|
||||
Schema::create('organizations', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->foreignUuid('user_id')->index();
|
||||
$table->string('name');
|
||||
@@ -13,14 +13,14 @@ return new class extends Migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('team_user', function (Blueprint $table) {
|
||||
Schema::create('organization_user', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->foreignUuid('team_id');
|
||||
$table->foreignUuid('organization_id');
|
||||
$table->foreignUuid('user_id');
|
||||
$table->string('role')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['team_id', 'user_id']);
|
||||
$table->unique(['organization_id', 'user_id']);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,16 +13,16 @@ return new class extends Migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('team_invitations', function (Blueprint $table) {
|
||||
Schema::create('organization_invitations', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->foreignUuid('team_id')
|
||||
$table->foreignUuid('organization_id')
|
||||
->constrained()
|
||||
->cascadeOnDelete();
|
||||
$table->string('email');
|
||||
$table->string('role')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['team_id', 'email']);
|
||||
$table->unique(['organization_id', 'email']);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ return new class extends Migration
|
||||
$table->uuid('organization_id');
|
||||
$table->foreign('organization_id')
|
||||
->references('id')
|
||||
->on('teams')
|
||||
->on('organizations')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->timestamps();
|
||||
|
||||
@@ -26,7 +26,7 @@ return new class extends Migration
|
||||
$table->uuid('organization_id');
|
||||
$table->foreign('organization_id')
|
||||
->references('id')
|
||||
->on('teams')
|
||||
->on('organizations')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->timestamps();
|
||||
|
||||
@@ -25,7 +25,7 @@ return new class extends Migration
|
||||
$table->uuid('organization_id');
|
||||
$table->foreign('organization_id')
|
||||
->references('id')
|
||||
->on('teams')
|
||||
->on('organizations')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->timestamps();
|
||||
|
||||
@@ -19,7 +19,7 @@ return new class extends Migration
|
||||
$table->uuid('organization_id');
|
||||
$table->foreign('organization_id')
|
||||
->references('id')
|
||||
->on('teams')
|
||||
->on('organizations')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->timestamps();
|
||||
|
||||
@@ -28,7 +28,7 @@ return new class extends Migration
|
||||
$table->uuid('organization_id');
|
||||
$table->foreign('organization_id')
|
||||
->references('id')
|
||||
->on('teams')
|
||||
->on('organizations')
|
||||
->cascadeOnUpdate()
|
||||
->restrictOnDelete();
|
||||
$table->uuid('project_id')->nullable();
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace Database\Seeders;
|
||||
|
||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use App\Models\Client;
|
||||
use App\Models\Organization;
|
||||
use App\Models\Project;
|
||||
use App\Models\Task;
|
||||
use App\Models\Team;
|
||||
use App\Models\TimeEntry;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
@@ -22,14 +22,23 @@ class DatabaseSeeder extends Seeder
|
||||
public function run(): void
|
||||
{
|
||||
$this->deleteAll();
|
||||
$organization = Team::factory()->create([
|
||||
$organization = Organization::factory()->create([
|
||||
'name' => 'ACME Corp',
|
||||
]);
|
||||
$user1 = User::factory()->withPersonalTeam()->create([
|
||||
$user1 = User::factory()->withPersonalOrganization()->create([
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
]);
|
||||
$user1->teams()->attach($organization);
|
||||
$userAcmeAdmin = User::factory()->create([
|
||||
'name' => 'ACME Admin',
|
||||
'email' => 'admin@acme.test',
|
||||
]);
|
||||
$user1->organizations()->attach($organization, [
|
||||
'role' => 'editor',
|
||||
]);
|
||||
$userAcmeAdmin->organizations()->attach($organization, [
|
||||
'role' => 'admin',
|
||||
]);
|
||||
$client = Client::factory()->create([
|
||||
'name' => 'Big Company',
|
||||
]);
|
||||
@@ -50,6 +59,6 @@ class DatabaseSeeder extends Seeder
|
||||
DB::table((new Project())->getTable())->delete();
|
||||
DB::table((new Client())->getTable())->delete();
|
||||
DB::table((new User())->getTable())->delete();
|
||||
DB::table((new Team())->getTable())->delete();
|
||||
DB::table((new Organization())->getTable())->delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,12 +72,12 @@ const logout = () => {
|
||||
|
||||
<template #content>
|
||||
<div class="w-60">
|
||||
<!-- Team Management -->
|
||||
<!-- Organization Management -->
|
||||
<div class="block px-4 py-2 text-xs text-gray-400">
|
||||
Manage Team
|
||||
</div>
|
||||
|
||||
<!-- Team Settings -->
|
||||
<!-- Organization Settings -->
|
||||
<DropdownLink :href="route('teams.show', $page.props.auth.user.current_team)">
|
||||
Team Settings
|
||||
</DropdownLink>
|
||||
@@ -86,7 +86,7 @@ const logout = () => {
|
||||
Create New Team
|
||||
</DropdownLink>
|
||||
|
||||
<!-- Team Switcher -->
|
||||
<!-- Organization Switcher -->
|
||||
<template v-if="$page.props.auth.user.all_teams.length > 1">
|
||||
<div class="border-t border-gray-200 dark:border-gray-600" />
|
||||
|
||||
@@ -229,7 +229,7 @@ const logout = () => {
|
||||
</ResponsiveNavLink>
|
||||
</form>
|
||||
|
||||
<!-- Team Management -->
|
||||
<!-- Organization Management -->
|
||||
<template v-if="$page.props.jetstream.hasTeamFeatures">
|
||||
<div class="border-t border-gray-200 dark:border-gray-600" />
|
||||
|
||||
@@ -237,7 +237,7 @@ const logout = () => {
|
||||
Manage Team
|
||||
</div>
|
||||
|
||||
<!-- Team Settings -->
|
||||
<!-- Organization Settings -->
|
||||
<ResponsiveNavLink :href="route('teams.show', $page.props.auth.user.current_team)" :active="route().current('teams.show')">
|
||||
Team Settings
|
||||
</ResponsiveNavLink>
|
||||
@@ -246,7 +246,7 @@ const logout = () => {
|
||||
Create New Team
|
||||
</ResponsiveNavLink>
|
||||
|
||||
<!-- Team Switcher -->
|
||||
<!-- Organization Switcher -->
|
||||
<template v-if="$page.props.auth.user.all_teams.length > 1">
|
||||
<div class="border-t border-gray-200 dark:border-gray-600" />
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ const deleteTeam = () => {
|
||||
</DangerButton>
|
||||
</div>
|
||||
|
||||
<!-- Delete Team Confirmation Modal -->
|
||||
<!-- Delete Organization Confirmation Modal -->
|
||||
<ConfirmationModal :show="confirmingTeamDeletion" @close="confirmingTeamDeletion = false">
|
||||
<template #title>
|
||||
Delete Team
|
||||
|
||||
@@ -97,7 +97,7 @@ const displayableRole = (role) => {
|
||||
<div v-if="userPermissions.canAddTeamMembers">
|
||||
<SectionBorder />
|
||||
|
||||
<!-- Add Team Member -->
|
||||
<!-- Add Organization Member -->
|
||||
<FormSection @submitted="addTeamMember">
|
||||
<template #title>
|
||||
Add Team Member
|
||||
@@ -177,7 +177,7 @@ const displayableRole = (role) => {
|
||||
<div v-if="team.team_invitations.length > 0 && userPermissions.canAddTeamMembers">
|
||||
<SectionBorder />
|
||||
|
||||
<!-- Team Member Invitations -->
|
||||
<!-- Organization Member Invitations -->
|
||||
<ActionSection class="mt-10 sm:mt-0">
|
||||
<template #title>
|
||||
Pending Team Invitations
|
||||
@@ -187,7 +187,7 @@ const displayableRole = (role) => {
|
||||
These people have been invited to your team and have been sent an invitation email. They may join the team by accepting the email invitation.
|
||||
</template>
|
||||
|
||||
<!-- Pending Team Member Invitation List -->
|
||||
<!-- Pending Organization Member Invitation List -->
|
||||
<template #content>
|
||||
<div class="space-y-6">
|
||||
<div v-for="invitation in team.team_invitations" :key="invitation.id" class="flex items-center justify-between">
|
||||
@@ -196,7 +196,7 @@ const displayableRole = (role) => {
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<!-- Cancel Team Invitation -->
|
||||
<!-- Cancel Organization Invitation -->
|
||||
<button
|
||||
v-if="userPermissions.canRemoveTeamMembers"
|
||||
class="cursor-pointer ms-6 text-sm text-red-500 focus:outline-none"
|
||||
@@ -214,7 +214,7 @@ const displayableRole = (role) => {
|
||||
<div v-if="team.users.length > 0">
|
||||
<SectionBorder />
|
||||
|
||||
<!-- Manage Team Members -->
|
||||
<!-- Manage Organization Members -->
|
||||
<ActionSection class="mt-10 sm:mt-0">
|
||||
<template #title>
|
||||
Team Members
|
||||
@@ -224,7 +224,7 @@ const displayableRole = (role) => {
|
||||
All of the people that are part of this team.
|
||||
</template>
|
||||
|
||||
<!-- Team Member List -->
|
||||
<!-- Organization Member List -->
|
||||
<template #content>
|
||||
<div class="space-y-6">
|
||||
<div v-for="user in team.users" :key="user.id" class="flex items-center justify-between">
|
||||
@@ -236,7 +236,7 @@ const displayableRole = (role) => {
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<!-- Manage Team Member Role -->
|
||||
<!-- Manage Organization Member Role -->
|
||||
<button
|
||||
v-if="userPermissions.canUpdateTeamMembers && availableRoles.length"
|
||||
class="ms-2 text-sm text-gray-400 underline"
|
||||
@@ -249,7 +249,7 @@ const displayableRole = (role) => {
|
||||
{{ displayableRole(user.membership.role) }}
|
||||
</div>
|
||||
|
||||
<!-- Leave Team -->
|
||||
<!-- Leave Organization -->
|
||||
<button
|
||||
v-if="$page.props.auth.user.id === user.id"
|
||||
class="cursor-pointer ms-6 text-sm text-red-500"
|
||||
@@ -258,7 +258,7 @@ const displayableRole = (role) => {
|
||||
Leave
|
||||
</button>
|
||||
|
||||
<!-- Remove Team Member -->
|
||||
<!-- Remove Organization Member -->
|
||||
<button
|
||||
v-else-if="userPermissions.canRemoveTeamMembers"
|
||||
class="cursor-pointer ms-6 text-sm text-red-500"
|
||||
@@ -328,7 +328,7 @@ const displayableRole = (role) => {
|
||||
</template>
|
||||
</DialogModal>
|
||||
|
||||
<!-- Leave Team Confirmation Modal -->
|
||||
<!-- Leave Organization Confirmation Modal -->
|
||||
<ConfirmationModal :show="confirmingLeavingTeam" @close="confirmingLeavingTeam = false">
|
||||
<template #title>
|
||||
Leave Team
|
||||
@@ -354,7 +354,7 @@ const displayableRole = (role) => {
|
||||
</template>
|
||||
</ConfirmationModal>
|
||||
|
||||
<!-- Remove Team Member Confirmation Modal -->
|
||||
<!-- Remove Organization Member Confirmation Modal -->
|
||||
<ConfirmationModal :show="teamMemberBeingRemoved" @close="teamMemberBeingRemoved = null">
|
||||
<template #title>
|
||||
Remove Team Member
|
||||
|
||||
@@ -35,7 +35,7 @@ const updateTeamName = () => {
|
||||
</template>
|
||||
|
||||
<template #form>
|
||||
<!-- Team Owner Information -->
|
||||
<!-- Organization Owner Information -->
|
||||
<div class="col-span-6">
|
||||
<InputLabel value="Team Owner" />
|
||||
|
||||
@@ -51,7 +51,7 @@ const updateTeamName = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Team Name -->
|
||||
<!-- Organization Name -->
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<InputLabel for="name" value="Team Name" />
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@component('mail::message')
|
||||
{{ __('You have been invited to join the :team team!', ['team' => $invitation->team->name]) }}
|
||||
{{ __('You have been invited to join the :team team!', ['team' => $invitation->organization->name]) }}
|
||||
|
||||
@if (Laravel\Fortify\Features::enabled(Laravel\Fortify\Features::registration()))
|
||||
{{ __('If you do not have an account, you may create one by clicking the button below. After creating an account, you may click the invitation acceptance button in this email to accept the team invitation:') }}
|
||||
|
||||
@@ -20,7 +20,7 @@ class ApiTokenPermissionsTest extends TestCase
|
||||
$this->markTestSkipped('API support is not enabled.');
|
||||
}
|
||||
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$token = $user->tokens()->create([
|
||||
'name' => 'Test Token',
|
||||
|
||||
@@ -19,7 +19,7 @@ class CreateApiTokenTest extends TestCase
|
||||
$this->markTestSkipped('API support is not enabled.');
|
||||
}
|
||||
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$response = $this->post('/user/api-tokens', [
|
||||
'name' => 'Test Token',
|
||||
|
||||
@@ -14,13 +14,13 @@ class CreateTeamTest extends TestCase
|
||||
|
||||
public function test_teams_can_be_created(): void
|
||||
{
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$response = $this->post('/teams', [
|
||||
'name' => 'Test Team',
|
||||
'name' => 'Test Organization',
|
||||
]);
|
||||
|
||||
$this->assertCount(2, $user->fresh()->ownedTeams);
|
||||
$this->assertEquals('Test Team', $user->fresh()->ownedTeams()->latest('id')->first()->name);
|
||||
$this->assertEquals('Test Organization', $user->fresh()->ownedTeams()->latest('id')->first()->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class DeleteApiTokenTest extends TestCase
|
||||
$this->markTestSkipped('API support is not enabled.');
|
||||
}
|
||||
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$token = $user->tokens()->create([
|
||||
'name' => 'Test Token',
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
@@ -15,9 +15,9 @@ class DeleteTeamTest extends TestCase
|
||||
|
||||
public function test_teams_can_be_deleted(): void
|
||||
{
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$user->ownedTeams()->save($team = Team::factory()->make([
|
||||
$user->ownedTeams()->save($team = Organization::factory()->make([
|
||||
'personal_team' => false,
|
||||
]));
|
||||
|
||||
@@ -33,7 +33,7 @@ class DeleteTeamTest extends TestCase
|
||||
|
||||
public function test_personal_teams_cant_be_deleted(): void
|
||||
{
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$response = $this->delete('/teams/'.$user->currentTeam->id);
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class EmailVerificationTest extends TestCase
|
||||
$this->markTestSkipped('Email verification not enabled.');
|
||||
}
|
||||
|
||||
$user = User::factory()->withPersonalTeam()->unverified()->create();
|
||||
$user = User::factory()->withPersonalOrganization()->unverified()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get('/email/verify');
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace Tests\Feature;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Laravel\Jetstream\Features;
|
||||
use Laravel\Jetstream\Mail\TeamInvitation;
|
||||
use Tests\TestCase;
|
||||
|
||||
@@ -17,41 +16,37 @@ class InviteTeamMemberTest extends TestCase
|
||||
|
||||
public function test_team_members_can_be_invited_to_team(): void
|
||||
{
|
||||
if (! Features::sendsTeamInvitations()) {
|
||||
$this->markTestSkipped('Team invitations not enabled.');
|
||||
}
|
||||
|
||||
// Arrange
|
||||
Mail::fake();
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
|
||||
// Act
|
||||
$response = $this->post('/teams/'.$user->currentTeam->id.'/members', [
|
||||
'email' => 'test@example.com',
|
||||
'role' => 'admin',
|
||||
]);
|
||||
|
||||
// Assert
|
||||
Mail::assertSent(TeamInvitation::class);
|
||||
|
||||
$this->assertCount(1, $user->currentTeam->fresh()->teamInvitations);
|
||||
}
|
||||
|
||||
public function test_team_member_invitations_can_be_cancelled(): void
|
||||
{
|
||||
if (! Features::sendsTeamInvitations()) {
|
||||
$this->markTestSkipped('Team invitations not enabled.');
|
||||
}
|
||||
|
||||
// Arrange
|
||||
Mail::fake();
|
||||
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$invitation = $user->currentTeam->teamInvitations()->create([
|
||||
'email' => 'test@example.com',
|
||||
'role' => 'admin',
|
||||
]);
|
||||
|
||||
// Act
|
||||
$response = $this->delete('/team-invitations/'.$invitation->id);
|
||||
|
||||
// Assert
|
||||
$this->assertCount(0, $user->currentTeam->fresh()->teamInvitations);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class LeaveTeamTest extends TestCase
|
||||
|
||||
public function test_users_can_leave_teams(): void
|
||||
{
|
||||
$user = User::factory()->withPersonalTeam()->create();
|
||||
$user = User::factory()->withPersonalOrganization()->create();
|
||||
|
||||
$user->currentTeam->users()->attach(
|
||||
$otherUser = User::factory()->create(), ['role' => 'admin']
|
||||
@@ -29,7 +29,7 @@ class LeaveTeamTest extends TestCase
|
||||
|
||||
public function test_team_owners_cant_leave_their_own_team(): void
|
||||
{
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$response = $this->delete('/teams/'.$user->currentTeam->id.'/members/'.$user->id);
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ class PasswordConfirmationTest extends TestCase
|
||||
|
||||
public function test_confirm_password_screen_can_be_rendered(): void
|
||||
{
|
||||
$user = User::factory()->withPersonalTeam()->create();
|
||||
$user = User::factory()->withPersonalOrganization()->create();
|
||||
|
||||
$response = $this->actingAs($user)->get('/user/confirm-password');
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ class RemoveTeamMemberTest extends TestCase
|
||||
|
||||
public function test_team_members_can_be_removed_from_teams(): void
|
||||
{
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$user->currentTeam->users()->attach(
|
||||
$otherUser = User::factory()->create(), ['role' => 'admin']
|
||||
@@ -27,7 +27,7 @@ class RemoveTeamMemberTest extends TestCase
|
||||
|
||||
public function test_only_team_owner_can_remove_team_members(): void
|
||||
{
|
||||
$user = User::factory()->withPersonalTeam()->create();
|
||||
$user = User::factory()->withPersonalOrganization()->create();
|
||||
|
||||
$user->currentTeam->users()->attach(
|
||||
$otherUser = User::factory()->create(), ['role' => 'admin']
|
||||
|
||||
@@ -14,7 +14,7 @@ class UpdateTeamMemberRoleTest extends TestCase
|
||||
|
||||
public function test_team_member_roles_can_be_updated(): void
|
||||
{
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$user->currentTeam->users()->attach(
|
||||
$otherUser = User::factory()->create(), ['role' => 'admin']
|
||||
@@ -31,7 +31,7 @@ class UpdateTeamMemberRoleTest extends TestCase
|
||||
|
||||
public function test_only_team_owner_can_update_team_member_roles(): void
|
||||
{
|
||||
$user = User::factory()->withPersonalTeam()->create();
|
||||
$user = User::factory()->withPersonalOrganization()->create();
|
||||
|
||||
$user->currentTeam->users()->attach(
|
||||
$otherUser = User::factory()->create(), ['role' => 'admin']
|
||||
|
||||
@@ -14,13 +14,13 @@ class UpdateTeamNameTest extends TestCase
|
||||
|
||||
public function test_team_names_can_be_updated(): void
|
||||
{
|
||||
$this->actingAs($user = User::factory()->withPersonalTeam()->create());
|
||||
$this->actingAs($user = User::factory()->withPersonalOrganization()->create());
|
||||
|
||||
$response = $this->put('/teams/'.$user->currentTeam->id, [
|
||||
'name' => 'Test Team',
|
||||
'name' => 'Test Organization',
|
||||
]);
|
||||
|
||||
$this->assertCount(1, $user->fresh()->ownedTeams);
|
||||
$this->assertEquals('Test Team', $user->currentTeam->fresh()->name);
|
||||
$this->assertEquals('Test Organization', $user->currentTeam->fresh()->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ declare(strict_types=1);
|
||||
namespace Tests\Unit\Model;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Team;
|
||||
use App\Models\Organization;
|
||||
|
||||
class ClientModelTest extends ModelTestAbstract
|
||||
{
|
||||
public function test_it_belongs_to_a_organization(): void
|
||||
{
|
||||
// Arrange
|
||||
$organization = Team::factory()->create();
|
||||
$organization = Organization::factory()->create();
|
||||
$client = Client::factory()->forOrganization($organization)->create();
|
||||
|
||||
// Act
|
||||
|
||||
@@ -5,16 +5,16 @@ declare(strict_types=1);
|
||||
namespace Tests\Unit\Model;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Organization;
|
||||
use App\Models\Project;
|
||||
use App\Models\Task;
|
||||
use App\Models\Team;
|
||||
|
||||
class ProjectModelTest extends ModelTestAbstract
|
||||
{
|
||||
public function test_it_belongs_to_a_organization(): void
|
||||
{
|
||||
// Arrange
|
||||
$organization = Team::factory()->create();
|
||||
$organization = Organization::factory()->create();
|
||||
$project = Project::factory()->forOrganization($organization)->create();
|
||||
|
||||
// Act
|
||||
|
||||
@@ -4,15 +4,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Model;
|
||||
|
||||
use App\Models\Organization;
|
||||
use App\Models\Tag;
|
||||
use App\Models\Team;
|
||||
|
||||
class TagModelTest extends ModelTestAbstract
|
||||
{
|
||||
public function test_it_belongs_to_a_organization(): void
|
||||
{
|
||||
// Arrange
|
||||
$organization = Team::factory()->create();
|
||||
$organization = Organization::factory()->create();
|
||||
$task = Tag::factory()->forOrganization($organization)->create();
|
||||
|
||||
// Act
|
||||
|
||||
@@ -4,16 +4,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Model;
|
||||
|
||||
use App\Models\Organization;
|
||||
use App\Models\Project;
|
||||
use App\Models\Task;
|
||||
use App\Models\Team;
|
||||
|
||||
class TaskModelTest extends ModelTestAbstract
|
||||
{
|
||||
public function test_it_belongs_to_a_organization(): void
|
||||
{
|
||||
// Arrange
|
||||
$organization = Team::factory()->create();
|
||||
$organization = Organization::factory()->create();
|
||||
$task = Task::factory()->forOrganization($organization)->create();
|
||||
|
||||
// Act
|
||||
|
||||
@@ -4,9 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit\Model;
|
||||
|
||||
use App\Models\Organization;
|
||||
use App\Models\Project;
|
||||
use App\Models\Task;
|
||||
use App\Models\Team;
|
||||
use App\Models\TimeEntry;
|
||||
use App\Models\User;
|
||||
|
||||
@@ -30,7 +30,7 @@ class TimeEntryModelTest extends ModelTestAbstract
|
||||
public function test_it_belongs_to_a_organization(): void
|
||||
{
|
||||
// Arrange
|
||||
$organization = Team::factory()->create();
|
||||
$organization = Organization::factory()->create();
|
||||
$timeEntry = TimeEntry::factory()->forOrganization($organization)->create();
|
||||
|
||||
// Act
|
||||
|
||||
Reference in New Issue
Block a user