'datetime', ]; } /** * @param Builder $query * @return Builder */ public function scopePending(Builder $query): Builder { return $query->where('status', self::STATUS_PENDING); } /** * The requests a staff member may actually act on. * * MembershipRequestsController guards approve() and deny() with * StaffLibraryScope::allowsGroupMembership, because joining a client * to a group decides what that client -- and any staff member * holding them -- can reach. This is the listing half of the same * rule, and both the queue and the sidebar badge read it, so the * number and the screen behind it cannot drift apart. That is why it * lives here rather than in either caller, the same reasoning * VisibleCommentScope::pendingTotal() gives for owning the comment * badge instead of leaving the middleware to count for itself. * * Narrowed on the client only. Whether the *group* is reachable is * the other half of allowsGroupMembership, and it depends on what is * shared with that group -- not a question to ask row by row in a * listing. So a scoped viewer may still be shown a request they * would be refused on; it will be one of their own clients asking to * join a group out of their reach, rather than a client they were * never meant to hear about. The names are the part that leaks. * * @param Builder $query * @return Builder */ public function scopeApprovableBy(Builder $query, User $viewer): Builder { $clientIds = app(StaffLibraryScope::class)->assignableClientIds($viewer); return $clientIds === null ? $query : $query->whereIn('user_id', $clientIds); } /** * @return BelongsTo */ public function group(): BelongsTo { return $this->belongsTo(Group::class); } /** * @return BelongsTo */ public function user(): BelongsTo { return $this->belongsTo(User::class); } }