From 3baf3d2545ba6ece6b74a64c0def59bd0774cf54 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Wed, 10 Jun 2026 16:34:12 +0000
Subject: [PATCH] =Laid the groundwork for an improved DashboardManager.php setup. Have to put it aside so I can get the dang Northeh done though.

---
 inc/rest/routes/ApprovalRoutes.php | 1022 +++++++-------------------------------------------------
 1 files changed, 138 insertions(+), 884 deletions(-)

diff --git a/inc/rest/routes/ApprovalRoutes.php b/inc/rest/routes/ApprovalRoutes.php
index 62fc5e4..b35e485 100644
--- a/inc/rest/routes/ApprovalRoutes.php
+++ b/inc/rest/routes/ApprovalRoutes.php
@@ -2,11 +2,13 @@
 
 namespace JVBase\rest\routes;
 
-use JVBase\JVB;
-use JVBase\rest\RestRouteManager;
-use JVBase\managers\Cache;
-use JVBase\utility\Features;
-use WP_User;
+use JVBase\managers\CustomTable;
+use JVBase\registrar\Registrar;
+use JVBase\rest\PermissionHandler;
+use JVBase\rest\Rest;
+use JVBase\rest\Route;
+use JVBase\rest\Response;
+use JVBase\base\Site;
 use WP_REST_Request;
 use WP_REST_Response;
 use Exception;
@@ -15,109 +17,61 @@
     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->hasMemberApproval = Features::forMembership()->has('member_verified');
+        $this->cacheName = 'approvals';
+		$this->hasMemberApproval = Site::membership() && Site::membership()->has('member_verified');
         parent::__construct();
 
         $this->initTypes();
-
-        if ($this->hasMemberApproval) {
-            add_action('user_register', [$this, 'handleNewUserRegistration'], 10, 2);
-        }
-
-        add_action('jvb_cleanup_expired_approvals', [$this, 'cleanupExpiredApprovals']);
     }
 
     protected function initTypes():void
     {
-        $approvals = jvbApprovalTypes();
         $this->userTypes = [];
         $this->termTypes = [];
+		$this->allTypes = [];
         if ($this->hasMemberApproval) {
-            $this->userTypes = array_filter(
-                array_keys($approvals),
-                function ($item) {
-                    return $item !== 'term';
-                }
-            );
+            $this->userTypes = Registrar::withFeature('approve_new', 'user');
             $this->allTypes = $this->userTypes;
         }
-        if (jvbSiteHasTermApproval()) {
-            $this->termTypes = $approvals['term']??[];
+        if (Site::has('term_approval')) {
+            $this->termTypes = Registrar::withFeature('approve_new', 'term');
             $this->allTypes[] = 'term';
         }
     }
 
     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' ]
-            ]
-        ]);
-    }
-
-    /**
-     * @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
-     * @param object $user the new user object
-     *
-     * @return void
-     */
-    public function handleNewUserRegistration(int $user_id, object $user):void
-    {
-		$intersect = array_intersect(
-			array_map(
-				function ($role) {
-					return 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);
-        }
+		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();
     }
 
 
@@ -126,341 +80,50 @@
      *
      * @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', 'dismiss'])) {
+			return false;
+		}
+		$result = JVB()->approvals()->markApproval($request_id, $user_id, $type, $vote, $notes);
+		return $result['success'];
+	}
 
 
-        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");
-            }
-
-            $already_voted = $wpdb->get_row($wpdb->prepare(
-                "SELECT * FROM $votes WHERE request_id = %d AND user_id = %d",
-                $request_id,
-                $user_id
-            ));
-
-            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");
-            }
-
-            $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");
-            }
-
-            $user = get_userdata($user_id);
-            if ($vote === 'approve') {
-                $approvers = json_decode($request->approved_by, true)?:[];
-
-                $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)?:[];
-
-                $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;
-                    }
-                }
-            }
-
-            $wpdb->query('COMMIT');
-
-            return true;
-        } catch (Exception $e) {
-            $wpdb->query('ROLLBACK');
-
-            JVB()->error()
-                ->log(
-                    '[ApprovalRoutes]:handleVote',
-                    "Error creating '.$type.' approval request: " . $e->getMessage(),
-                    [
-                        'user_id'   => $user_id,
-                        'request_id' => $request_id,
-                        'vote'       => $vote
-                    ]
-                );
-            return false;
-        }
-    }
     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;
 
-        $table = $this->getRequestTable($type, $wpdb->prefix);
 
-        $result = $wpdb->insert(
-            $table,
-            $request
-        );
-
-        if (!$result) {
-            throw new Exception($wpdb->last_error);
-        }
-        return $wpdb->insert_id;
-    }
 
     /*************
      * Artist Approvals
      ************/
     /**
-     * Create artist approval request
-     *
-     * @param int $user_id User ID to be approved
-     *
-     * @return int|false Request ID or false on failure
-     */
-    public function createArtistApprovalRequest(int $user_id):int|false
-    {
-        global $wpdb;
-        $wpdb->query('START TRANSACTION');
-
-        try {
-            //Check for existing first
-            $table = $this->getRequestTable(jvbUserRole($user_id), $wpdb->prefix);
-
-            // 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;
-            }
-
-            $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;
-        }
-    }
-
-    /**
-     * Mark an artist as verified
-     *
-     * @param int $user_id The user to verify
-     * @param int $verified_by ID of user who verified them (optional)
-     *
-     * @return bool Success status
-     */
-    public function verifyArtist(int $user_id, int $verified_by = 0):bool
-    {
-        $user = get_userdata($user_id);
-
-        // Check if user has the artist role
-        if (!array_intersect(array_map(function ($role) { return BASE.$role; }, $this->userTypes), $user->roles)) {
-            return false;
-        }
-
-        // Add the capability
-        $user->add_cap('skip_moderation', true);
-
-        // Store verification metadata
-        update_user_meta($user_id, BASE . 'verification_date', current_time('mysql'));
-        if ($verified_by) {
-            update_user_meta($user_id, BASE . 'verified_by', $verified_by);
-        }
-
-        return true;
-    }
-
-    /**
-     * Mark an artist as verified
-     *
-     * @param int $user_id The user to verify
-     * @param int $verified_by ID of user who verified them (optional)
-     *
-     * @return bool Success status
-     */
-    public function unverifyArtist(int $user_id, int $verified_by = 0):bool
-    {
-        $user = get_userdata($user_id);
-
-        // Check if user has the artist role
-        if (!array_intersect(array_map(function ($role) { return BASE.$role; }, $this->userTypes), $user->roles)) {
-            return false;
-        }
-
-        // Add the capability
-        $user->add_cap('skip_moderation', false);
-
-        // Store verification metadata
-        update_user_meta($user_id, BASE . 'unverification_date', current_time('mysql'));
-        if ($verified_by) {
-            update_user_meta($user_id, BASE . 'unverified_by', $verified_by);
-        }
-
-        return true;
-    }
-
-    /**
      * Record an approval vote for an artist
      *
      * @param int $user_id User casting the approval vote
@@ -475,154 +138,6 @@
         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;
-
-        // 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_approvals < $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->verifyArtist($user_id, $request->current_approvals);
-
-            // Update the request status
-            $updated = $wpdb->update(
-                $approval_table,
-                [
-                    'status'     => 'approved',
-                    '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_approved',
-                [
-                    'request_id'     => $request_id,
-                    'approval_date'  => current_time('mysql')
-                ]
-            );
-
-            $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;
-        }
-    }
 
     /**
      * Get verification details for a request
@@ -632,195 +147,28 @@
      *
      * @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
+	{
+		$request = JVB()->approvals()->getRequest($requestID, $type);
+		if (!$request) {
+			return false;
+		}
+		$votes = JVB()->approvals()->getVotes($requestID, $type);
 
-        $approval_table = $this->getRequestTable($type, $wpdb->prefix);
-        $votes_table = $this->getVoteTable($type, $wpdb->prefix);
+		// 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';
+		}
 
-        // 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);
+		return [
+			'request' => $request,
+			'votes' => $votes,
+			'verification_date' => $request['updated_at'],
+		];
+	}
 
-        if (!$request) {
-            return false;
-        }
 
-        // 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);
-
-        return [
-            'request'           => $request,
-            'votes'             => $votes,
-            'verification_date' => $request['updated_at'],
-        ];
-    }
-
-    /*************
-     * Term Approvals
-     ************/
-    public function voteForTerm(int $user_id, int $request_id, string $vote, string $notes = ''):bool
-    {
-        return $this->handleVote('term', $vote, $user_id, $request_id, $notes);
-    }
-
-    /**
-     * Publish an approved term
-     *
-     * @param object $request Approval request object
-     *
-     * @return boolean Success or failure
-     */
-    protected function makeTermLive(object $request):bool
-    {
-        global $wpdb;
-
-        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
-            ]);
-
-            if (is_wp_error($result)) {
-                throw new Exception($result->get_error_message());
-            }
-            $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 ]
-            );
-
-            $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'];
-            }
-
-            $approvedBy = jvbCommaList($approvedBy);
-
-            // Notify the requester
-            JVB()->notification()->addNotification(
-                $userIDs,
-                'term_approved',
-                [
-                    'term_id'     => $term_id,
-                    'term_name'   => $term_name,
-                    'taxonomy'    => $taxonomy,
-                    'approved_by' => $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
-                    ]
-                );
-
-            return false;
-        }
-    }
-    /**
-     * Reject a proposed term
-     *
-     * @param object $request request object
-     *
-     * @return boolean Success or failure
-     */
-    protected function makeTermUnalive(object $request):bool
-    {
-        global $wpdb;
-
-        try {
-            // Update request status
-            $wpdb->update(
-                $this->getRequestTable('term', $wpdb),
-                [
-                    'status'     => 'rejected',
-                    'updated_at' => current_time('mysql'),
-                ],
-                [ 'id' => $request->id ]
-            );
-
-            $userIDs = [];
-            $rejectedBy = [];
-
-            $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'];
-            }
-
-            $rejectedBy = jvbCommaList($rejectedBy);
-
-            // Notify the requester
-            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 false;
-        }
-    }
 
     /**
      * Create a new term approval request
@@ -833,179 +181,85 @@
      *
      * @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 {
 
-        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
-            ));
+		$result = JVB()->approvals()->createApproval(
+			$user_id,
+			$taxonomy,
+			$name,
+			$parent
+		);
+		return $result['success'];
+	}
 
-            if ($existing) {
-                // Decode the requested_by JSON field
-                $requestedBy = json_decode($existing->requested_by, true) ?: [];
+	protected function getTableName(string $type, string $suffix): string
+	{
+		return match ($type) {
+			'term' => "approval_term_{$suffix}",
+			default => "approval_{$type}_{$suffix}",
+		};
+	}
 
-                // Check if this user has already requested this term
-                if (isset($requestedBy[$user_id])) {
-                    $wpdb->query('COMMIT');
-                    return (int)$existing->id;
-                }
+	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');
 
-                // Add this user to the requesters
-                $requestedBy[$user_id] = get_userdata($user_id)->display_name;
+		if (!$this->checkUser($user_id)) {
+			return $this->unauthorized();
+		}
 
-                // Update the request with the new requester
-                $updated = $wpdb->update(
-                    $table,
-                    ['requested_by' => json_encode($requestedBy)],
-                    ['id' => $existing->id]
-                );
+		$cacheKey = compact('user_id', 'type', 'status');
 
-                if (!$updated) {
-                    throw new Exception($wpdb->last_error);
-                }
+		$result = $this->cache->remember($cacheKey, function() use ($type, $status) {
+			$data = [];
 
-                $wpdb->query('COMMIT');
-                return (int)$existing->id;
-            }
+			if ($type === 'user' || $type === 'all') {
+				$data['user_approvals'] = $this->getUserApprovals($status);
+			}
 
-            $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 ($type === 'term' || $type === 'all') {
+				$data['term_approvals'] = $this->getTermApprovals($status);
+			}
 
-            if (!$result) {
-                throw new Exception($wpdb->last_error);
-            }
+			return $data;
+		});
 
-            $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 $this->success($result);
+	}
 
-            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);
+	private function getUserApprovals(string $status = 'pending'): array
+	{
 
+		$table = CustomTable::for($this->getTableName('artist', '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')
-            ));
-        }
+		$query = $table;
 
-        // Clear caches
-		$this->cache->flush();
-    }
+		if ($status !== 'all') {
+			$query = $query->where(['status' => $status]);
+		}
 
-    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';
+		return $query->orderBy('created_at', 'DESC')->getResults(ARRAY_A);
+	}
 
-        // Get appropriate approvals based on type
-        if ($type === 'user' || $type === 'all') {
-            $user_approvals = $this->getUserApprovals($status);
-        } else {
-            $user_approvals = [];
-        }
+	private function getTermApprovals(string $status = 'pending'): array
+	{
+		$table = CustomTable::for($this->getTableName('term', 'requests'));
 
-        if ($type === 'term' || $type === 'all') {
-            $term_approvals = $this->getTermApprovals($status);
-        } else {
-            $term_approvals = [];
-        }
+		if ($status === 'all') {
+			return $table->orderBy('created_at', 'DESC')->getResults(ARRAY_A);
+		}
 
-        return new WP_REST_Response([
-            'user_approvals' => $user_approvals,
-            'term_approvals' => $term_approvals
-        ]);
-    }
-
-    private function getUserApprovals(string $status = 'pending'): array
-    {
-        global $wpdb;
-        $table = $wpdb->prefix . $this->userRequests;
-
-        // Build the status condition
-        $status_condition = ($status === 'all') ?
-            "status IN ('pending', 'approved', 'rejected', 'expired')" :
-            $wpdb->prepare("status = %s", $status);
-
-        return $wpdb->get_results(
-            "SELECT * FROM $table
-        WHERE $status_condition
-        ORDER BY created_at DESC"
-        );
-    }
-
-    private function getTermApprovals(string $status = 'pending'): array
-    {
-        global $wpdb;
-        $table = $wpdb->prefix . $this->termRequests;
-
-        // Build the status condition
-        $status_condition = ($status === 'all') ?
-            "status IN ('pending', 'approved', 'rejected', 'expired')" :
-            $wpdb->prepare("status = %s", $status);
-
-        return $wpdb->get_results(
-            "SELECT * FROM $table
-        WHERE $status_condition
-        ORDER BY created_at DESC"
-        );
-    }
+		return $table
+			->where(['status' => $status])
+			->orderBy('created_at', 'DESC')
+			->getResults(ARRAY_A);
+	}
 }

--
Gitblit v1.10.0