<?php
|
|
namespace JVBase\rest\routes;
|
|
use JVBase\JVB;
|
use JVBase\rest\RestRouteManager;
|
use JVBase\managers\Cache;
|
use JVBase\utility\Features;
|
use WP_User;
|
use WP_REST_Request;
|
use WP_REST_Response;
|
use Exception;
|
|
if (!defined('ABSPATH')) {
|
exit; // Exit if accessed directly
|
}
|
|
class ApprovalRoutes extends RestRouteManager
|
{
|
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');
|
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 = [];
|
if ($this->hasMemberApproval) {
|
$this->userTypes = array_filter(
|
array_keys($approvals),
|
function ($item) {
|
return $item !== 'term';
|
}
|
);
|
$this->allTypes = $this->userTypes;
|
}
|
if (jvbSiteHasTermApproval()) {
|
$this->termTypes = $approvals['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);
|
}
|
}
|
|
|
/**
|
* @param WP_REST_Request $request
|
*
|
* @return WP_REST_Response
|
*/
|
public function handleApprovalAction(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;
|
|
$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 ($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);
|
}
|
|
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);
|
|
|
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
|
* @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);
|
}
|
|
/**
|
* 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
|
*
|
* @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
|
{
|
global $wpdb;
|
|
$approval_table = $this->getRequestTable($type, $wpdb->prefix);
|
$votes_table = $this->getVoteTable($type, $wpdb->prefix);
|
|
// 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;
|
}
|
|
// 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
|
*
|
* @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 {
|
global $wpdb;
|
$table = $this->getRequestTable('term', $wpdb);
|
|
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
|
));
|
|
if ($existing) {
|
// Decode the requested_by JSON field
|
$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;
|
}
|
|
// Add this user to the requesters
|
$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]
|
);
|
|
if (!$updated) {
|
throw new Exception($wpdb->last_error);
|
}
|
|
$wpdb->query('COMMIT');
|
return (int)$existing->id;
|
}
|
|
$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;
|
}
|
}
|
/**
|
* 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);
|
|
|
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')
|
));
|
}
|
|
// 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';
|
|
// Get appropriate approvals based on type
|
if ($type === 'user' || $type === 'all') {
|
$user_approvals = $this->getUserApprovals($status);
|
} else {
|
$user_approvals = [];
|
}
|
|
if ($type === 'term' || $type === 'all') {
|
$term_approvals = $this->getTermApprovals($status);
|
} else {
|
$term_approvals = [];
|
}
|
|
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"
|
);
|
}
|
}
|