organization_id !== $organization->id) { throw new AuthorizationException('Member does not belong to organization'); } } /** * List all members of an organization * * @return MemberCollection * * @throws AuthorizationException * * @operationId getMembers */ public function index(Organization $organization, MemberIndexRequest $request): MemberCollection { $this->checkPermission($organization, 'members:view'); $members = Member::query() ->whereBelongsTo($organization, 'organization') ->with(['user']) ->paginate(config('app.pagination_per_page_default')); return MemberCollection::make($members); } /** * Update a member of the organization * * @throws AuthorizationException * @throws OrganizationNeedsAtLeastOneOwner * @throws OnlyOwnerCanChangeOwnership * @throws ChangingRoleToPlaceholderIsNotAllowed * @throws ChangingRoleOfPlaceholderIsNotAllowed * * @operationId updateMember */ public function update(Organization $organization, Member $member, MemberUpdateRequest $request, BillableRateService $billableRateService, MemberService $memberService): JsonResource { $this->checkPermission($organization, 'members:update', $member); if ($request->has('billable_rate') && $member->billable_rate !== $request->getBillableRate()) { $member->billable_rate = $request->getBillableRate(); $billableRateService->updateTimeEntriesBillableRateForMember($member); } if ($request->has('role') && $member->role !== $request->getRole()->value) { $newRole = $request->getRole(); $allowOwnerChange = $this->hasPermission($organization, 'members:change-ownership'); $memberService->changeRole($member, $organization, $newRole, $allowOwnerChange); } $member->save(); return new MemberResource($member); } /** * Remove a member of the organization. * * @throws AuthorizationException|EntityStillInUseApiException|CanNotRemoveOwnerFromOrganization * * @operationId removeMember */ public function destroy(Organization $organization, Member $member, MemberService $memberService): JsonResponse { $this->checkPermission($organization, 'members:delete', $member); $memberService->removeMember($member, $organization); return response() ->json(null, 204); } /** * Make a member a placeholder member * * @throws AuthorizationException|CanNotRemoveOwnerFromOrganization|ChangingRoleOfPlaceholderIsNotAllowed * * @operationId makePlaceholder */ public function makePlaceholder(Organization $organization, Member $member, MemberService $memberService): JsonResponse { $this->checkPermission($organization, 'members:make-placeholder', $member); if ($member->role === Role::Owner->value) { throw new CanNotRemoveOwnerFromOrganization; } if ($member->role === Role::Placeholder->value) { throw new ChangingRoleOfPlaceholderIsNotAllowed; } $memberService->makeMemberToPlaceholder($member); MemberMadeToPlaceholder::dispatch($member, $organization); return response()->json(null, 204); } /** * @throws AuthorizationException * @throws OnlyPlaceholdersCanBeMergedIntoAnotherMember * @throws \Throwable * * @operationId mergeMember */ public function mergeInto(Organization $organization, Member $member, MemberMergeIntoRequest $request, MemberService $memberService): JsonResponse { $this->checkPermission($organization, 'members:merge-into', $member); $user = $member->user; if ($member->role !== Role::Placeholder->value || ! $user->is_placeholder) { throw new OnlyPlaceholdersCanBeMergedIntoAnotherMember; } $memberTo = Member::findOrFail($request->getMemberId()); DB::transaction(function () use ($organization, $member, $user, $memberTo, $memberService): void { $memberService->assignOrganizationEntitiesToDifferentMember($organization, $member, $memberTo); $member->delete(); $user->delete(); }); return response()->json(null, 204); } /** * Invite a placeholder member to become a real member of the organization * * @throws AuthorizationException * @throws UserNotPlaceholderApiException * @throws UserIsAlreadyMemberOfOrganizationApiException * @throws ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException * * @operationId invitePlaceholder */ public function invitePlaceholder(Organization $organization, Member $member, InvitationService $invitationService): JsonResponse { $this->checkPermission($organization, 'members:invite-placeholder', $member); $user = $member->user; if (! $user->is_placeholder) { throw new UserNotPlaceholderApiException; } if (Str::endsWith($user->email, '@solidtime-import.test')) { throw new ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException; } $invitationService->inviteUser($organization, $user->email, Role::Employee); return response()->json(null, 204); } }