cacheName = 'approvals'; $this->hasMemberApproval = Site::membership() && Site::membership()->has('member_verified'); parent::__construct(); $this->initTypes(); } protected function initTypes():void { $this->userTypes = []; $this->termTypes = []; $this->allTypes = []; if ($this->hasMemberApproval) { $this->userTypes = Registrar::getFeatured('approve_new', 'user'); $this->allTypes = $this->userTypes; } if (Site::has('term_approval')) { $this->termTypes = Registrar::getFeatured('approve_new', 'term'); $this->allTypes[] = 'term'; } } public function registerRoutes():void { Route::for('approvals') ->get([$this, 'getApprovals']) ->args([ 'user' => 'integer|required', 'type' => 'string', 'status' => 'string|enum:pending,approved,rejected,expired', ]) ->auth(PermissionHandler::combine(['user', 'verified'])) ->rateLimit(30) ->post([$this, 'handleAction']) ->args([ 'user' => 'integer|required', 'request_id' => 'integer|required', 'action' => 'string|required|enum:approve,reject', 'type' => 'string|required', 'notes' => 'string', ]) ->auth(PermissionHandler::combine(['user', 'verified'])) ->rateLimit(3) ->register(); } /** * @param WP_REST_Request $request * * @return WP_REST_Response */ public function handleAction(WP_REST_Request $request):WP_REST_Response { $data = $request->get_params(); $request_id = absint($data['request_id']); $user_id = absint($data['user']); $action = sanitize_text_field($data['action']); $type = sanitize_text_field($data['type']); $notes = sanitize_text_field($data['notes'] ?? ''); if (!in_array($type, $this->allTypes)) { return Response::validationError(['message' => 'Invalid type']); } $result = $this->handleVote($type, $action, $request_id, $user_id, $notes); return $result ? Response::success(['message' => 'Vote recorded successfully']) : Response::error('Failed to record vote'); } /** * Artist and Term Approvals */ protected function handleVote(string $type, string $vote, int $request_id, int $user_id, string $notes = ''): bool { if (!in_array($vote, ['approve', 'reject', 'dismiss'])) { return false; } $result = JVB()->approvals()->markApproval($request_id, $user_id, $type, $vote, $notes); return $result['success']; } protected function rebuildExpiryDate() { return date('Y-m-d H:i:s', strtotime("+{$this->expiryDays} days", time())); } /************* * Artist Approvals ************/ /** * Record an approval vote for an artist * * @param int $user_id User casting the approval vote * @param int $request_id The approval request ID * @param string $vote 'approve' or 'reject' * @param string $notes Optional notes for the vote * * @return bool Success status */ public function voteForArtist(int $user_id, int $request_id, string $vote, string $notes = ''):bool { return $this->handleVote(jvbUserRole($user_id), $vote, $request_id, $user_id, $notes); } /** * Get verification details for a request * * @param int $requestID the request ID * @param string $type Type * * @return array|false Verification details or false if not verified */ public function getVerificationDetails(int $requestID, string $type): array|false { $request = JVB()->approvals()->getRequest($requestID, $type); if (!$request) { return false; } $votes = JVB()->approvals()->getVotes($requestID, $type); // Join with user data for display names foreach ($votes as &$vote) { $user = get_userdata($vote['user_id']); $vote['approver_name'] = $user ? jvbGetUsername($vote['user_id']) : 'Someone'; } return [ 'request' => $request, 'votes' => $votes, 'verification_date' => $request['updated_at'], ]; } /** * Create a new term approval request * * @param int $user_id User requesting approval * @param string $taxonomy Taxonomy * @param string $name New Term Name * @param int $parent Parent Term ID * @param int $required_approvals Number of approvals required * * @return int|false Request ID or false on failure */ public function createTermApprovalRequest( int $user_id, string $taxonomy, string $name, int $parent = 0, int $required_approvals = 3 ): int|false { $result = JVB()->approvals()->createApproval( $user_id, $taxonomy, $name, $parent ); return $result['success']; } protected function getTableName(string $type, string $suffix): string { return match ($type) { 'term' => "approval_term_{$suffix}", default => "approval_{$type}_{$suffix}", }; } public function getApprovals(WP_REST_Request $request): WP_REST_Response { $user_id = absint($request->get_param('user')); $type = sanitize_text_field($request->get_param('type') ?? 'all'); $status = sanitize_text_field($request->get_param('status') ?? 'pending'); if (!$this->checkUser($user_id)) { return $this->unauthorized(); } $cacheKey = compact('user_id', 'type', 'status'); $result = $this->cache->remember($cacheKey, function() use ($type, $status) { $data = []; if ($type === 'user' || $type === 'all') { $data['user_approvals'] = $this->getUserApprovals($status); } if ($type === 'term' || $type === 'all') { $data['term_approvals'] = $this->getTermApprovals($status); } return $data; }); return $this->success($result); } private function getUserApprovals(string $status = 'pending'): array { $table = CustomTable::for($this->getTableName('artist', 'requests')); $query = $table; if ($status !== 'all') { $query = $query->where(['status' => $status]); } return $query->orderBy('created_at', 'DESC')->getResults(ARRAY_A); } private function getTermApprovals(string $status = 'pending'): array { $table = CustomTable::for($this->getTableName('term', 'requests')); if ($status === 'all') { return $table->orderBy('created_at', 'DESC')->getResults(ARRAY_A); } return $table ->where(['status' => $status]) ->orderBy('created_at', 'DESC') ->getResults(ARRAY_A); } }