From 2127b1bdd73ecd2423e443992da4b442f5a3c1a3 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Wed, 04 Feb 2026 21:19:25 +0000
Subject: [PATCH] =Major overhaul of MetaManager.php -> Meta.php and RestRouteManager.php -> Rest.php. Seems to work for JakeVan
---
inc/rest/routes/ApprovalRoutes.php | 1191 ++++++++++++++++++++++++-----------------------------------
1 files changed, 481 insertions(+), 710 deletions(-)
diff --git a/inc/rest/routes/ApprovalRoutes.php b/inc/rest/routes/ApprovalRoutes.php
index 62fc5e4..e01ffd5 100644
--- a/inc/rest/routes/ApprovalRoutes.php
+++ b/inc/rest/routes/ApprovalRoutes.php
@@ -2,11 +2,12 @@
namespace JVBase\rest\routes;
-use JVBase\JVB;
-use JVBase\rest\RestRouteManager;
-use JVBase\managers\Cache;
+use JVBase\managers\CustomTable;
+use JVBase\rest\PermissionHandler;
+use JVBase\rest\Rest;
+use JVBase\rest\Route;
+use JVBase\rest\Response;
use JVBase\utility\Features;
-use WP_User;
use WP_REST_Request;
use WP_REST_Response;
use Exception;
@@ -15,20 +16,18 @@
exit; // Exit if accessed directly
}
-class ApprovalRoutes extends RestRouteManager
+class ApprovalRoutes extends Rest
{
protected array $userTypes;
protected array $termTypes;
protected array $allTypes;
- protected array $requestTables;
- protected array $voteTables;
protected int $expiryDays = 7;
protected bool $hasMemberApproval = false;
public function __construct()
{
- $this->cache_name = 'approvals';
+ $this->cacheName = 'approvals';
$this->hasMemberApproval = Features::forMembership()->has('member_verified');
parent::__construct();
@@ -63,37 +62,28 @@
public function registerRoutes():void
{
- register_rest_route($this->namespace, '/approvals', [
- [
- 'methods' => 'GET',
- 'callback' => [ $this, 'getApprovals' ],
- 'permission_callback' => [ $this, 'checkPermission' ]
- ],
- [
- 'methods' => 'POST',
- 'callback' => [ $this, 'handleApprovalAction' ],
- 'permission_callback' => [ $this, 'checkPermission' ]
- ]
- ]);
+ 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);
}
/**
- * @param WP_REST_Request $request The REST request
- *
- * @return bool
- */
- public function checkPermission(WP_REST_Request $request):bool
- {
- $userID = get_current_user_id();
- if (!user_can($userID, 'skip_moderation')) {
- return false;
- }
-
- return parent::checkPermission($request);
- }
-
-
- /**
* Handler for user registration
*
* @param int $user_id New user ID
@@ -101,24 +91,18 @@
*
* @return void
*/
- public function handleNewUserRegistration(int $user_id, object $user):void
- {
+ public function handleNewUserRegistration(int $user_id, object $user): void
+ {
$intersect = array_intersect(
- array_map(
- function ($role) {
- return BASE.$role;
- },
- $this->userTypes
- ),
+ array_map(fn($role) => BASE.$role, $this->userTypes),
(array) $user->roles
);
- if (!empty($intersect)) {
- // Mark as unverified initially
- $user->add_cap('skip_moderation', false);
- // Create approval request
- $this->createArtistApprovalRequest($user_id);
- }
- }
+
+ if (!empty($intersect)) {
+ $user->add_cap('skip_moderation', false);
+ $this->createArtistApprovalRequest($user_id);
+ }
+ }
/**
@@ -126,216 +110,170 @@
*
* @return WP_REST_Response
*/
- public function handleApprovalAction(WP_REST_Request $request):WP_REST_Response
+ public function handleAction(WP_REST_Request $request):WP_REST_Response
{
- $data = $request->get_params();
- $request_id = $data['request_id'] ?? 0;
- $user_id = (array_key_exists('user', $data) &&
- is_numeric($data['user'])) ?
- (int) $data['user'] : get_current_user_id();
- $action = (array_key_exists('action', $data) && in_array($data['action'], [
- 'approve',
- 'reject'
- ])) ? $data['action'] : false;
+ $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'] ?? '');
- $type = (array_key_exists('type', $data) &&
- in_array($data['type'], $this->allTypes)) ?
- $data['type'] :
- false;
- $notes = (array_key_exists('notes', $data)) ? sanitize_text_field($data['notes']) : '';
+ if (!in_array($type, $this->allTypes)) {
+ return Response::validationError(['message' => 'Invalid type']);
+ }
- if ($action && $request_id !== 0 && $type) {
- $result = $this->handleVote($type, $action, $request_id, $user_id, $notes);
- return new WP_REST_Response([
- 'success' => $result,
- 'message' => $result ? 'Vote recorded successfully' : 'Failed to record vote'
- ], $result ? 200 : 500);
- }
- return new WP_REST_Response([
- 'success' => false,
- 'message' => 'Invalid action or request ID'
- ], 400);
+ $result = $this->handleVote($type, $action, $request_id, $user_id, $notes);
+
+ return $result
+ ? Response::success(['message' => 'Vote recorded successfully'])
+ : Response::error('Failed to record vote');
}
- protected function getRequestTable(string $type, string $prefix):string
- {
- return match ($type) {
- 'term' => $prefix . BASE . 'approval_term_requests',
- default => $prefix . BASE . 'approval_' . $type . '_requests',
- };
- }
- protected function getVoteTable(string $type, string $prefix):string
- {
- return match ($type) {
- 'term' => $prefix . BASE . 'approval_term_votes',
- default => $prefix . BASE . 'approval_' . $type . '_votes',
- };
- }
/**
* 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'])) {
- return false;
- }
- global $wpdb;
- $table = $this->getRequestTable($type, $wpdb->prefix);
- $votes = $this->getVoteTable($type, $wpdb->prefix);
+ protected function handleVote(string $type, string $vote, int $request_id, int $user_id, string $notes = ''): bool
+ {
+ if (!in_array($vote, ['approve', 'reject'])) {
+ return false;
+ }
+ $requestTable = $this->getTableName($type, 'requests');
+ $voteTable = $this->getTableName($type, 'votes');
- try {
- $request = $wpdb->get_row($wpdb->prepare(
- "SELECT * FROM $table WHERE id = %d",
- $request_id
- ));
- if (!$request || $request->status !== 'pending') {
- throw new Exception("Invalid approval request");
- }
+ $requests = CustomTable::for($requestTable);
+ $votes = CustomTable::for($voteTable);
- $already_voted = $wpdb->get_row($wpdb->prepare(
- "SELECT * FROM $votes WHERE request_id = %d AND user_id = %d",
- $request_id,
- $user_id
- ));
+ try {
+ return $requests->transaction(function($requests) use ($votes, $request_id, $user_id, $vote, $notes, $type) {
+ // Get the approval request
+ $request = $requests->where(['id' => $request_id])->first();
- if ($already_voted && $already_voted->vote !== $vote) {
- $wpdb->update(
- $votes,
- [
- 'vote' => $vote,
- ],
- [
- 'id' => $already_voted->id
- ]
- );
- return true;
- } elseif ($already_voted) {
- throw new Exception("User has already voted on this request");
- }
+ if (!$request || $request->status !== 'pending') {
+ throw new Exception("Invalid approval request");
+ }
- $result = $wpdb->insert(
- $votes,
- [
- 'request_id' => $request_id,
- 'user_id' => $user_id,
- 'vote' => $vote,
- 'notes' => $notes,
- 'created_at' => current_time('mysql')
- ]
- );
- if (!$result) {
- throw new Exception("Failed to record vote");
- }
+ // Check if user already voted
+ $existingVote = $votes->where([
+ 'request_id' => $request_id,
+ 'user_id' => $user_id
+ ])->first();
- $user = get_userdata($user_id);
- if ($vote === 'approve') {
- $approvers = json_decode($request->approved_by, true)?:[];
+ if ($existingVote) {
+ if ($existingVote->vote !== $vote) {
+ // Update vote
+ $votes->where(['id' => $existingVote->id])
+ ->updateResults(['vote' => $vote]);
+ return true;
+ }
+ throw new Exception("User has already voted on this request");
+ }
- $approvers[$user_id] = [
- 'name' => $user->display_name,
- 'voted' => current_time('mysql')
- ];
- $wpdb->update(
- $table,
- [
- 'current_approvals' => $request->current_approvals + 1,
- 'updated_at' => current_time('mysql'),
- 'approved_by' => $approvers,
- 'expires_at' => $this->rebuildExpiryDate()
- ],
- [
- 'id' => $request_id
- ]
- );
- if ($request->current_approvals + 1 >= $request->required_approvals) {
- switch ($type) {
- case 'user':
- case 'artist':
- $this->completeVerification($request_id);
- break;
- case 'term':
- $this->makeTermLive($request);
- break;
- }
- }
- } elseif ($vote === 'reject') {
- $rejecters = json_decode($request->rejected_by, true)?:[];
+ // Insert new vote
+ $votes->create([
+ 'request_id' => $request_id,
+ 'user_id' => $user_id,
+ 'vote' => $vote,
+ 'notes' => $notes,
+ ]);
- $rejecters[$user_id] = [
- 'name' => $user->display_name,
- 'voted' => current_time('mysql')
- ];
- $wpdb->update(
- $table,
- [
- 'current_rejections' => $request->current_rejections + 1,
- 'rejected_by' => $rejecters,
- 'updated_at' => current_time('mysql'),
- 'expires_at' => $this->rebuildExpiryDate()
- ],
- [
- 'id' => $request_id
- ]
- );
- if ($request->current_rejections + 1 >= $request->required_approvals) {
- switch ($type) {
- case 'user':
- case 'artist':
- $this->denyVerification($request_id);
- break;
- case 'term':
- $this->makeTermUnalive($request);
- break;
- }
- }
- }
+ // Update request based on vote type
+ $user = get_userdata($user_id);
- $wpdb->query('COMMIT');
+ if ($vote === 'approve') {
+ $this->handleApproval($requests, $request, $request_id, $user, $type);
+ } else {
+ $this->handleRejection($requests, $request, $request_id, $user, $type);
+ }
- return true;
- } catch (Exception $e) {
- $wpdb->query('ROLLBACK');
+ return true;
+ });
+ } catch (Exception $e) {
+ $this->logError('handleVote', [
+ 'error' => $e->getMessage(),
+ 'user_id' => $user_id,
+ 'request_id' => $request_id,
+ 'vote' => $vote
+ ]);
+ return false;
+ }
+ }
- JVB()->error()
- ->log(
- '[ApprovalRoutes]:handleVote',
- "Error creating '.$type.' approval request: " . $e->getMessage(),
- [
- 'user_id' => $user_id,
- 'request_id' => $request_id,
- 'vote' => $vote
- ]
- );
- return false;
- }
- }
+ /**
+ * Handle approval vote logic
+ */
+ protected function handleApproval(CustomTable $table, object $request, int $request_id, $user, string $type): void
+ {
+ $approvers = json_decode($request->approved_by, true) ?: [];
+ $approvers[$user->ID] = [
+ 'name' => $user->display_name,
+ 'voted' => current_time('mysql')
+ ];
+
+ $table->where(['id' => $request_id])->updateResults([
+ 'current_approvals' => $request->current_approvals + 1,
+ 'approved_by' => json_encode($approvers),
+ 'expires_at' => $this->rebuildExpiryDate()
+ ]);
+
+ // Check if threshold met
+ if ($request->current_approvals + 1 >= $request->required_approvals) {
+ match ($type) {
+ 'term' => $this->makeTermLive($request),
+ default => $this->completeVerification($request_id, $type),
+ };
+ }
+ }
+
+ /**
+ * Handle rejection vote logic
+ */
+ protected function handleRejection(CustomTable $table, object $request, int $request_id, $user, string $type): void
+ {
+ $rejecters = json_decode($request->rejected_by, true) ?: [];
+ $rejecters[$user->ID] = [
+ 'name' => $user->display_name,
+ 'voted' => current_time('mysql')
+ ];
+
+ $table->where(['id' => $request_id])->updateResults([
+ 'current_rejections' => $request->current_rejections + 1,
+ 'rejected_by' => json_encode($rejecters),
+ 'expires_at' => $this->rebuildExpiryDate()
+ ]);
+
+ // Check if threshold met
+ if ($request->current_rejections + 1 >= $request->required_approvals) {
+ match ($type) {
+ 'term' => $this->makeTermUnalive($request),
+ default => $this->denyVerification($request_id, $type),
+ };
+ }
+ }
protected function rebuildExpiryDate()
{
return date('Y-m-d H:i:s', strtotime("+{$this->expiryDays} days", time()));
}
+
/**
* @param string $type user/artist or term
* @param array $request
*
* @return bool|int
*/
- protected function createApprovalRequest(string $type, array $request):bool|int
- {
- global $wpdb;
+ protected function createApprovalRequest(string $type, array $request): int
+ {
+ $tableName = $this->getTableName($type, 'requests');
- $table = $this->getRequestTable($type, $wpdb->prefix);
+ $id = CustomTable::for($tableName)->create($request);
- $result = $wpdb->insert(
- $table,
- $request
- );
+ if (!$id) {
+ throw new Exception('Failed to create approval request');
+ }
- if (!$result) {
- throw new Exception($wpdb->last_error);
- }
- return $wpdb->insert_id;
- }
+ return $id;
+ }
/*************
* Artist Approvals
@@ -347,60 +285,45 @@
*
* @return int|false Request ID or false on failure
*/
- public function createArtistApprovalRequest(int $user_id):int|false
- {
- global $wpdb;
- $wpdb->query('START TRANSACTION');
+ /**
+ * Create artist approval request - REFACTORED
+ */
+ public function createArtistApprovalRequest(int $user_id): int|false
+ {
+ $userRole = jvbUserRole($user_id);
+ $tableName = $this->getTableName($userRole, 'requests');
+ $table = CustomTable::for($tableName);
- try {
- //Check for existing first
- $table = $this->getRequestTable(jvbUserRole($user_id), $wpdb->prefix);
+ try {
+ return $table->transaction(function($table) use ($user_id) {
+ // Check for existing request
+ $existing = $table->where(['user_id' => $user_id])->first();
- // Verify this is not a duplicate request
- $existing = $wpdb->get_var($wpdb->prepare(
- "SELECT id FROM $table
- WHERE user_id = %d",
- $user_id
- ));
+ if ($existing) {
+ return $existing->id;
+ }
- if ($existing) {
- return $existing;
- }
+ $user_data = get_userdata($user_id);
- $user_data = get_userdata($user_id);
- $request = [
- 'user_id' => $user_id,
- 'status' => 'pending',
- 'expires_at' => date('Y-m-d H:i:s', strtotime('+30 days')),
- 'created_at' => current_time('mysql'),
- 'updated_at' => current_time('mysql'),
- 'name' => $user_data->display_name,
- 'email' => $user_data->user_email,
- ];
-
- $result = $this->createApprovalRequest('user', $request);
-
- if (!$result) {
- throw new Exception($wpdb->last_error);
- }
-
- $wpdb->query('COMMIT');
-
- return $result;
- } catch (Exception $e) {
- $wpdb->query('ROLLBACK');
- JVB()->error()
- ->log(
- '[ApprovalRoutes]:createArtistApprovalRequest',
- "Error creating artist approval request: " . $e->getMessage(),
- [
- 'user_id' => $user_id,
- ]
- );
-
- return false;
- }
- }
+ return $table->create([
+ 'user_id' => $user_id,
+ 'status' => 'pending',
+ 'expires_at' => date('Y-m-d H:i:s', strtotime('+30 days')),
+ 'current_approvals' => 0,
+ 'current_rejections' => 0,
+ 'required_approvals' => 3, // From config
+ 'approved_by' => json_encode([]),
+ 'rejected_by' => json_encode([]),
+ ]);
+ });
+ } catch (Exception $e) {
+ $this->logError('createArtistApprovalRequest', [
+ 'error' => $e->getMessage(),
+ 'user_id' => $user_id
+ ]);
+ return false;
+ }
+ }
/**
* Mark an artist as verified
@@ -475,154 +398,57 @@
return $this->handleVote(jvbUserRole($user_id), $vote, $request_id, $user_id, $notes);
}
- /**
- * Mark an artist as verified after receiving required approvals
- *
- * @param int $request_id The approval request ID
- *
- * @return bool Success status
- */
- public function completeVerification(int $request_id):bool
- {
- global $wpdb;
- $approval_table = $wpdb->prefix . $this->userRequests;
+ /**
+ * Complete verification - REFACTORED
+ */
+ protected function completeVerification(int $request_id, string $type = 'artist'): void
+ {
+ $tableName = $this->getTableName($type, 'requests');
+ $table = CustomTable::for($tableName);
- // Get the request details
- $request = $wpdb->get_row($wpdb->prepare(
- "SELECT * FROM $approval_table WHERE id = %d",
- $request_id
- ));
+ $table->where(['id' => $request_id])->updateResults([
+ 'status' => 'approved',
+ 'approved_at' => current_time('mysql')
+ ]);
- if (!$request || $request->status !== 'pending') {
- return false;
- }
+ $request = $table->where(['id' => $request_id])->first();
- // Check if enough approvals have been collected
- if ($request->current_approvals < $request->required_approvals) {
- return false;
- }
+ if ($request && $request->user_id) {
+ $user = new \WP_User($request->user_id);
+ $user->add_cap('skip_moderation', true);
- // Start a transaction
- $wpdb->query('START TRANSACTION');
+ JVB()->notification()->addNotification(
+ $request->user_id,
+ 'approval_granted',
+ ['message' => 'Your account has been verified!']
+ );
+ }
- try {
- // Get the user ID from the request
- $user_id = $request->user_id;
+ $this->cache->flush();
+ }
- $this->verifyArtist($user_id, $request->current_approvals);
+ protected function denyVerification(int $request_id, string $type = 'artist'): void
+ {
+ $tableName = $this->getTableName($type, 'requests');
+ $table = CustomTable::for($tableName);
- // Update the request status
- $updated = $wpdb->update(
- $approval_table,
- [
- 'status' => 'approved',
- 'updated_at' => current_time('mysql')
- ],
- [ 'id' => $request_id ]
- );
+ $table->where(['id' => $request_id])->updateResults([
+ 'status' => 'rejected',
+ 'rejected_at' => current_time('mysql')
+ ]);
- if ($updated === false) {
- throw new Exception("Failed to update approval request status");
- }
+ $request = $table->where(['id' => $request_id])->first();
- // Notify the user they've been verified
- JVB()->notification()->addNotification(
- $user_id,
- 'artist_approved',
- [
- 'request_id' => $request_id,
- 'approval_date' => current_time('mysql')
- ]
- );
+ if ($request && $request->user_id) {
+ JVB()->notification()->addNotification(
+ $request->user_id,
+ 'approval_denied',
+ ['message' => 'Your verification request was not approved.']
+ );
+ }
- $wpdb->query('COMMIT');
-
- return true;
- } catch (Exception $e) {
- $wpdb->query('ROLLBACK');
- JVB()->error()
- ->log(
- '[ApprovalRoutes]:completeVerification',
- "Error verifying user: " . $e->getMessage(),
- [
- 'user_id' => $user_id,
- ]
- );
-
- return false;
- }
- }
-
- public function denyVerification(int $request_id):bool
- {
- global $wpdb;
- $approval_table = $wpdb->prefix . $this->userRequests;
-
- // Get the request details
- $request = $wpdb->get_row($wpdb->prepare(
- "SELECT * FROM $approval_table WHERE id = %d",
- $request_id
- ));
-
- if (!$request || $request->status !== 'pending') {
- return false;
- }
-
- // Check if enough approvals have been collected
- if ($request->current_rejections < $request->required_approvals) {
- return false;
- }
-
- // Start a transaction
- $wpdb->query('START TRANSACTION');
-
- try {
- // Get the user ID from the request
- $user_id = $request->user_id;
-
- $this->unverifyArtist($user_id, $request->rejected_by);
-
- // Update the request status
- $updated = $wpdb->update(
- $approval_table,
- [
- 'status' => 'rejected',
- 'updated_at' => current_time('mysql')
- ],
- [ 'id' => $request_id ]
- );
-
- if ($updated === false) {
- throw new Exception("Failed to update approval request status");
- }
-
- // Notify the user they've been verified
- JVB()->notification()->addNotification(
- $user_id,
- 'artist_rejected',
- [
- 'request_id' => $request_id,
- 'approval_date' => current_time('mysql')
- ]
- );
-
- $wpdb->query('COMMIT');
-
- return true;
- } catch (Exception $e) {
- $wpdb->query('ROLLBACK');
- JVB()->error()
- ->log(
- '[ApprovalRoutes]:denyVerification',
- "Error removing artist verification status: " . $e->getMessage(),
- [
- 'user_id' => $user_id
- ]
- );
-
- return false;
- }
- }
+ $this->cache->flush();
+ }
/**
* Get verification details for a request
@@ -632,40 +458,35 @@
*
* @return array|false Verification details or false if not verified
*/
- public function getVerificationDetails(int $requestID, string $type):array|false
- {
- global $wpdb;
+ public function getVerificationDetails(int $requestID, string $type): array|false
+ {
+ $requestTable = CustomTable::for($this->getTableName($type, 'requests'));
+ $voteTable = CustomTable::for($this->getTableName($type, 'votes'));
- $approval_table = $this->getRequestTable($type, $wpdb->prefix);
- $votes_table = $this->getVoteTable($type, $wpdb->prefix);
+ $request = $requestTable->where(['id' => $requestID])->first(ARRAY_A);
- // Get the approval request
- $request = $wpdb->get_row($wpdb->prepare(
- "SELECT * FROM $approval_table
- WHERE id = %d
- ORDER BY updated_at DESC",
- $requestID
- ), ARRAY_A);
+ if (!$request) {
+ return false;
+ }
- if (!$request) {
- return false;
- }
+ // Get the votes for this request
+ $votes = $voteTable
+ ->where(['request_id' => $request['id']])
+ ->orderBy('created_at', 'ASC')
+ ->getResults(ARRAY_A);
- // Get the votes for this request
- $votes = $wpdb->get_results($wpdb->prepare(
- "SELECT v.*, u.display_name as approver_name
- FROM $votes_table v
- WHERE v.request_id = %d
- ORDER BY v.created_at",
- $request['id']
- ), ARRAY_A);
+ // Join with user data for display names
+ foreach ($votes as &$vote) {
+ $user = get_userdata($vote['user_id']);
+ $vote['approver_name'] = $user ? $user->display_name : 'Unknown';
+ }
- return [
- 'request' => $request,
- 'votes' => $votes,
- 'verification_date' => $request['updated_at'],
- ];
- }
+ return [
+ 'request' => $request,
+ 'votes' => $votes,
+ 'verification_date' => $request['updated_at'],
+ ];
+ }
/*************
* Term Approvals
@@ -682,80 +503,69 @@
*
* @return boolean Success or failure
*/
- protected function makeTermLive(object $request):bool
- {
- global $wpdb;
+ protected function makeTermLive(object $request): bool
+ {
+ try {
+ $taxonomy = $request->taxonomy;
+ $term_name = $request->name;
+ $parent = $request->parent;
- try {
- // Get term data from request
- $taxonomy = $request->taxonomy;
- $term_name = $request->name;
- $parent = $request->parent;
+ $result = wp_insert_term($term_name, $taxonomy, [
+ 'parent' => $parent
+ ]);
- $result = wp_insert_term($term_name, $taxonomy, [
- 'parent' => $parent
- ]);
+ if (is_wp_error($result)) {
+ throw new Exception($result->get_error_message());
+ }
- if (is_wp_error($result)) {
- throw new Exception($result->get_error_message());
- }
- $term_id = $result['term_id'];
+ $term_id = $result['term_id'];
- $table = $this->getRequestTable('term', $wpdb);
- // Update request status
- $wpdb->update(
- $table,
- [
- 'status' => 'approved',
- 'updated_at' => current_time('mysql'),
- 'created_term' => $term_id
- ],
- [ 'id' => $request->id ]
- );
+ // Update request status
+ CustomTable::for($this->getTableName('term', 'requests'))
+ ->where(['id' => $request->id])
+ ->updateResults([
+ 'status' => 'approved',
+ 'created_term' => $term_id
+ ]);
- $userIDs = [];
- $approvedBy = [];
- $approvors = json_decode($request->approved_by, true) ?: [];
- $requesters = json_decode($request->requested_by, true) ?: [];
- $rejectors = json_decode($request->rejected_by, true) ?: [];
- foreach (array_merge($requesters, $approvors, $rejectors) as $user_id => $info) {
- $userIDs[] = $user_id;
- }
- foreach ($approvors as $user_id => $info) {
- $approvedBy[] = $info['name'];
- }
+ $userIDs = [];
+ $approvedBy = [];
+ $approvers = json_decode($request->approved_by, true) ?: [];
+ $requesters = json_decode($request->requested_by, true) ?: [];
+ $rejectors = json_decode($request->rejected_by, true) ?: [];
- $approvedBy = jvbCommaList($approvedBy);
+ foreach (array_merge($requesters, $approvers, $rejectors) as $user_id => $info) {
+ $userIDs[] = $user_id;
+ }
+ foreach ($approvers as $user_id => $info) {
+ $approvedBy[] = $info['name'];
+ }
- // Notify the requester
- JVB()->notification()->addNotification(
- $userIDs,
- 'term_approved',
- [
- 'term_id' => $term_id,
- 'term_name' => $term_name,
- 'taxonomy' => $taxonomy,
- 'approved_by' => $approvedBy
- ]
- );
+ $approvedBy = jvbCommaList($approvedBy);
- return true;
- } catch (Exception $e) {
- JVB()->error()
- ->log(
- '[ApprovalRoutes]:makeTermLive',
- "Error making term live: " . $e->getMessage(),
- [
- 'request_id' => $request->id,
- 'requester' => $request->requested_by,
- 'term_name' => $term_name,
- 'taxonomy' => $taxonomy
- ]
- );
+ JVB()->notification()->addNotification(
+ $userIDs,
+ 'term_approved',
+ [
+ 'term_id' => $term_id,
+ 'term_name' => $term_name,
+ 'taxonomy' => $taxonomy,
+ 'approved_by' => $approvedBy
+ ]
+ );
- return false;
- }
- }
+ return true;
+ } catch (Exception $e) {
+ $this->logError('makeTermLive', [
+ 'error' => $e->getMessage(),
+ 'request_id' => $request->id,
+ 'term_name' => $term_name ?? '',
+ 'taxonomy' => $taxonomy ?? ''
+ ]);
+
+ return false;
+ }
+ }
/**
* Reject a proposed term
*
@@ -763,64 +573,54 @@
*
* @return boolean Success or failure
*/
- protected function makeTermUnalive(object $request):bool
- {
- global $wpdb;
+ protected function makeTermUnalive(object $request): bool
+ {
+ try {
+ // Update request status
+ CustomTable::for($this->getTableName('term', 'requests'))
+ ->where(['id' => $request->id])
+ ->updateResults([
+ 'status' => 'rejected'
+ ]);
- try {
- // Update request status
- $wpdb->update(
- $this->getRequestTable('term', $wpdb),
- [
- 'status' => 'rejected',
- 'updated_at' => current_time('mysql'),
- ],
- [ 'id' => $request->id ]
- );
+ $userIDs = [];
+ $rejectedBy = [];
- $userIDs = [];
- $rejectedBy = [];
+ $approvers = json_decode($request->approved_by, true) ?: [];
+ $requesters = json_decode($request->requested_by, true) ?: [];
+ $rejectors = json_decode($request->rejected_by, true) ?: [];
- $approvors = json_decode($request->approved_by, true) ?: [];
- $requesters = json_decode($request->requested_by, true) ?: [];
- $rejectors = json_decode($request->rejected_by, true) ?: [];
- foreach (array_merge($requesters, $approvors, $rejectors) as $user_id => $info) {
- $userIDs[] = $user_id;
- }
- foreach ($rejectors as $user_id => $info) {
- $rejectedBy[] = $info['name'];
- }
+ foreach (array_merge($requesters, $approvers, $rejectors) as $user_id => $info) {
+ $userIDs[] = $user_id;
+ }
+ foreach ($rejectors as $user_id => $info) {
+ $rejectedBy[] = $info['name'];
+ }
- $rejectedBy = jvbCommaList($rejectedBy);
+ $rejectedBy = jvbCommaList($rejectedBy);
- // Notify the requester
- JVB()->notification()->addNotification(
- $userIDs,
- 'term_rejected',
- [
- 'term_name' => $request->name,
- 'taxonomy' => $request->taxonomy,
- 'rejected_by' => $rejectedBy
- ]
- );
+ JVB()->notification()->addNotification(
+ $userIDs,
+ 'term_rejected',
+ [
+ 'term_name' => $request->name,
+ 'taxonomy' => $request->taxonomy,
+ 'rejected_by' => $rejectedBy
+ ]
+ );
- return true;
- } catch (Exception $e) {
- JVB()->error()
- ->log(
- '[ApprovalRoutes]:makeTermUnalive',
- "Error rejecting term: " . $e->getMessage(),
- [
- 'request_id' => $request->id,
- 'requester' => $request->requested_by,
- 'term_name' => $request->name,
- 'taxonomy' => $request->taxonomy
- ]
- );
+ return true;
+ } catch (Exception $e) {
+ $this->logError('makeTermUnalive', [
+ 'error' => $e->getMessage(),
+ 'request_id' => $request->id,
+ 'term_name' => $request->name ?? '',
+ 'taxonomy' => $request->taxonomy ?? ''
+ ]);
- return false;
- }
- }
+ return false;
+ }
+ }
/**
* Create a new term approval request
@@ -833,179 +633,150 @@
*
* @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 {
- global $wpdb;
- $table = $this->getRequestTable('term', $wpdb);
+ public function createTermApprovalRequest(
+ int $user_id,
+ string $taxonomy,
+ string $name,
+ int $parent = 0,
+ int $required_approvals = 3
+ ): int|false {
+ $table = CustomTable::for($this->getTableName('term', 'requests'));
- try {
- $wpdb->query('START TRANSACTION');
- // Step 1: Check if user already has a pending request for this term
- $existing = $wpdb->get_row($wpdb->prepare(
- "SELECT id, requested_by FROM $table
- WHERE name = %s
- AND taxonomy = %s
- AND parent = %d
- AND status = 'pending'",
- $name,
- $taxonomy,
- $parent
- ));
+ try {
+ return $table->transaction(function($table) use ($user_id, $taxonomy, $name, $parent, $required_approvals) {
+ // Check for existing request
+ $existing = $table->where([
+ 'name' => $name,
+ 'taxonomy' => $taxonomy,
+ 'parent' => $parent,
+ 'status' => 'pending'
+ ])->first();
- if ($existing) {
- // Decode the requested_by JSON field
- $requestedBy = json_decode($existing->requested_by, true) ?: [];
+ if ($existing) {
+ $requestedBy = json_decode($existing->requested_by, true) ?: [];
- // Check if this user has already requested this term
- if (isset($requestedBy[$user_id])) {
- $wpdb->query('COMMIT');
- return (int)$existing->id;
- }
+ if (isset($requestedBy[$user_id])) {
+ return (int)$existing->id;
+ }
- // Add this user to the requesters
- $requestedBy[$user_id] = get_userdata($user_id)->display_name;
+ $requestedBy[$user_id] = get_userdata($user_id)->display_name;
- // Update the request with the new requester
- $updated = $wpdb->update(
- $table,
- ['requested_by' => json_encode($requestedBy)],
- ['id' => $existing->id]
- );
+ $table->where(['id' => $existing->id])->updateResults([
+ 'requested_by' => json_encode($requestedBy)
+ ]);
- if (!$updated) {
- throw new Exception($wpdb->last_error);
- }
+ return (int)$existing->id;
+ }
- $wpdb->query('COMMIT');
- return (int)$existing->id;
- }
+ // Create new request
+ return $this->createApprovalRequest('term', [
+ 'taxonomy' => $taxonomy,
+ 'name' => $name,
+ 'parent' => $parent ?: null,
+ 'status' => 'pending',
+ 'required_approvals' => $required_approvals,
+ 'current_approvals' => 0,
+ 'current_rejections' => 0,
+ 'requested_by' => json_encode([$user_id => get_userdata($user_id)->display_name]),
+ 'expires_at' => date('Y-m-d H:i:s', strtotime('+30 days')),
+ ]);
+ });
+ } catch (Exception $e) {
+ $this->logError('createTermApprovalRequest', [
+ 'error' => $e->getMessage(),
+ 'user_id' => $user_id,
+ 'taxonomy' => $taxonomy,
+ 'name' => $name
+ ]);
- $request = [
- 'taxonomy' => $taxonomy,
- 'name' => $name,
- 'parent' => $parent ?: null,
- 'status' => 'pending',
- 'required_approvals' => $required_approvals,
- 'current_approvals' => 0,
- 'current_rejections' => 0,
- 'requested_by' => json_encode([$user_id => get_userdata($user_id)->display_name]),
- 'expires_at' => date('Y-m-d H:i:s', strtotime('+30 days')),
- 'created_at' => current_time('mysql'),
- 'updated_at' => current_time('mysql')
- ];
- $result = $this->createApprovalRequest('term', $request);
-
- if (!$result) {
- throw new Exception($wpdb->last_error);
- }
-
- $request_id = $wpdb->insert_id;
- $wpdb->query('COMMIT');
- return $request_id;
- } catch (Exception $e) {
- $wpdb->query('ROLLBACK');
- JVB()->error()
- ->log(
- '[ApprovalRoutes]:createTermApprovalRequest',
- "Error creating term approval request: " . $e->getMessage(),
- [
- 'user_id' => $user_id,
- 'taxonomy' => $taxonomy,
- 'name' => $name
- ]
- );
-
- return false;
- }
- }
+ return false;
+ }
+ }
/**
* Clean up expired approval requests and notify admin
*
* @return void
*/
- public function cleanupExpiredApprovals(): void
- {
- global $wpdb;
- $tables = array_map(function ($table) use ($wpdb){
- return $wpdb->prefix . BASE . 'approval_'.$table.'_requests';
- }, $this->allTypes);
+ public function cleanupExpiredApprovals(): void
+ {
+ $now = current_time('mysql');
+ foreach ($this->allTypes as $type) {
+ $tableName = $this->getTableName($type, 'requests');
- foreach ($tables as $table) {
- $wpdb->query($wpdb->prepare(
- "UPDATE $table SET status = 'expired', updated_at = %s
- WHERE status = 'pending' AND expires_at < %s",
- current_time('mysql'),
- current_time('mysql')
- ));
- }
+ CustomTable::for($tableName)->query(
+ "UPDATE {table}
+ SET status = 'expired'
+ WHERE status = 'pending'
+ AND expires_at < %s",
+ [$now]
+ );
+ }
- // Clear caches
$this->cache->flush();
- }
+ }
- public function getApprovals(WP_REST_Request $request)
- {
- $user_id = get_current_user_id();
- $params = $request->get_params();
- $type = $params['type'] ?? 'all';
- $status = $params['status'] ?? 'pending';
+ protected function getTableName(string $type, string $suffix): string
+ {
+ return match ($type) {
+ 'term' => "approval_term_{$suffix}",
+ default => "approval_{$type}_{$suffix}",
+ };
+ }
- // Get appropriate approvals based on type
- if ($type === 'user' || $type === 'all') {
- $user_approvals = $this->getUserApprovals($status);
- } else {
- $user_approvals = [];
- }
+ 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 ($type === 'term' || $type === 'all') {
- $term_approvals = $this->getTermApprovals($status);
- } else {
- $term_approvals = [];
- }
+ if (!$this->checkUser($user_id)) {
+ return $this->unauthorized();
+ }
- return new WP_REST_Response([
- 'user_approvals' => $user_approvals,
- 'term_approvals' => $term_approvals
- ]);
- }
+ $cacheKey = compact('user_id', 'type', 'status');
- private function getUserApprovals(string $status = 'pending'): array
- {
- global $wpdb;
- $table = $wpdb->prefix . $this->userRequests;
+ $result = $this->cache->remember($cacheKey, function() use ($type, $status) {
+ $data = [];
- // Build the status condition
- $status_condition = ($status === 'all') ?
- "status IN ('pending', 'approved', 'rejected', 'expired')" :
- $wpdb->prepare("status = %s", $status);
+ if ($type === 'user' || $type === 'all') {
+ $data['user_approvals'] = $this->getUserApprovals($status);
+ }
- return $wpdb->get_results(
- "SELECT * FROM $table
- WHERE $status_condition
- ORDER BY created_at DESC"
- );
- }
+ if ($type === 'term' || $type === 'all') {
+ $data['term_approvals'] = $this->getTermApprovals($status);
+ }
- private function getTermApprovals(string $status = 'pending'): array
- {
- global $wpdb;
- $table = $wpdb->prefix . $this->termRequests;
+ return $data;
+ });
- // Build the status condition
- $status_condition = ($status === 'all') ?
- "status IN ('pending', 'approved', 'rejected', 'expired')" :
- $wpdb->prepare("status = %s", $status);
+ return $this->success($result);
+ }
- return $wpdb->get_results(
- "SELECT * FROM $table
- WHERE $status_condition
- ORDER BY created_at DESC"
- );
- }
+ 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);
+ }
}
--
Gitblit v1.10.0