| | |
| | | |
| | | use DateTime; |
| | | use DateTimeZone; |
| | | use JVBase\JVB; |
| | | use JVBase\rest\RateLimiter; |
| | | use JVBase\integrations\services\Cloudflare; |
| | | use JVBase\managers\Errors; |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\managers\OperationQueue; |
| | | use JVBase\managers\Cache; |
| | | use JVBase\managers\NotificationManager; |
| | | use JVBase\utility\Features; |
| | | use JVBase\base\Site; |
| | | use WP_REST_Request; |
| | | use WP_Error; |
| | | use Exception; |
| | |
| | | } |
| | | |
| | | /** |
| | | * @deprecated use Rest.php |
| | | * Handles route registration and high-level coordination |
| | | */ |
| | | abstract class RestRouteManager |
| | |
| | | protected string $route; |
| | | protected string $base; |
| | | protected string $content_type; //the registered post type |
| | | protected string $type; //post, user, term, for MetaManager |
| | | protected string $type; //post, user, term, for Meta |
| | | protected string $action = ''; //optional additional nonce to check |
| | | protected array $callback; //route->callback array |
| | | protected string $operation_type; // from QueueManager.js and OperationQueue.php |
| | |
| | | * @param string $nonceName nonce name to check |
| | | * @param string|null $nonce optional additional nonce to check |
| | | * |
| | | * @return void|WP_Error |
| | | */ |
| | | public function verifyNonce(WP_REST_Request $request, string $nonceName = 'wp_rest', string|null $nonce = null):mixed |
| | | { |
| | | * @return bool|WP_Error |
| | | */ |
| | | public function verifyNonce(WP_REST_Request $request, string $nonceName = 'wp_rest', string|null $nonce = null): bool|WP_Error |
| | | { |
| | | $nonce = (!is_null($nonce)) ? $nonce : $request->get_header('X-WP-Nonce'); |
| | | |
| | | if (!wp_verify_nonce($nonce, $nonceName)) { |
| | |
| | | return false; |
| | | } |
| | | // Verify nonces |
| | | $this->verifyNonce($request, 'wp_rest'); |
| | | $this->verifyNonce($request); |
| | | if ($this->action!=='') { |
| | | $this->verifyNonce($request, $this->action . $user_id, $request->get_header('action_nonce')); |
| | | } |
| | |
| | | |
| | | protected function checkContent(string $content, bool $bool = false):string|bool |
| | | { |
| | | $result = JVB_CONTENT[$content]??JVB_TAXONOMY[$content]??JVB_USER[$content]??''; |
| | | if ($bool) { |
| | | return $result !== ''; |
| | | } |
| | | return $result; |
| | | return (bool)Registrar::getInstance($content); |
| | | } |
| | | |
| | | |
| | |
| | | protected function logError(string $message, array $context = [], string $severity = 'error') |
| | | { |
| | | try { |
| | | JVB()->error()->log( |
| | | Errors::getInstance()->log( |
| | | 'artist_invitations', // component |
| | | $message, |
| | | $context, |
| | |
| | | */ |
| | | protected function checkUser(int $userID): bool |
| | | { |
| | | $cache = Cache::for('checkUser', DAY_IN_SECONDS)->connect('user'); |
| | | $cache = Cache::for('checkUser', 'user',DAY_IN_SECONDS); |
| | | |
| | | return $cache->remember($userID, function() use ($userID) { |
| | | return (bool)get_userdata($userID); |
| | |
| | | */ |
| | | protected function checkShop(int $shopID): bool |
| | | { |
| | | $cache = Cache::for('checkShop',DAY_IN_SECONDS)->connect('taxonomy'); |
| | | $cache = Cache::for('checkShop', 'term',DAY_IN_SECONDS); |
| | | |
| | | return $cache->remember($shopID, function() use ($shopID) { |
| | | return (bool)term_exists($shopID, BASE . 'shop'); |
| | |
| | | } |
| | | |
| | | $taxonomy = jvbCheckBase($taxonomy); |
| | | $cache = Cache::for('checkTerm', DAY_IN_SECONDS)->connect('taxonomy'); |
| | | $cache = Cache::for('checkTerm', 'term', DAY_IN_SECONDS); |
| | | |
| | | return $cache->remember($termID, function() use ($termID, $taxonomy) { |
| | | return (bool)term_exists($termID, $taxonomy); |
| | |
| | | */ |
| | | public function isVerifiedUser(int $user_id): bool |
| | | { |
| | | $cache = Cache::for('verifiedUsers', DAY_IN_SECONDS)->connect('user'); |
| | | $cache = Cache::for('verifiedUsers', 'user',DAY_IN_SECONDS); |
| | | |
| | | return $cache->remember($user_id, function() use ($user_id) { |
| | | return user_can($user_id, 'skip_moderation'); |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * @deprecated |
| | | * @param array $args |
| | | * @param array $data |
| | | * @return array |
| | | */ |
| | | protected function applyTaxonomyFilters(array $args, array $data):array |
| | | { |
| | | // Handle JSON-encoded taxonomy data |
| | |
| | | |
| | | // Keep existing author filtering logic |
| | | $authorQuery = []; |
| | | foreach (jvbAuthorUsers() as $type) { |
| | | foreach (Registrar::withFeature('can_create', 'user') as $type) { |
| | | if (array_key_exists($type, $data)) { |
| | | $artist_ids = array_map( |
| | | 'absint', |
| | |
| | | |
| | | //Handle random |
| | | if (array_key_exists('orderby', $data) && $data['orderby'] === 'random') { |
| | | $current_seed = jvbGetRandomSeed(); |
| | | $current_seed = floor(time() / 1800); |
| | | $args['orderby'] = 'RAND(' . $current_seed . ')'; |
| | | unset($args['order']); |
| | | return $args; |
| | |
| | | $content = jvbNoBase($post_type); |
| | | |
| | | // Get config for this content type |
| | | $config = Features::getConfig($content); |
| | | $config = Registrar::getInstance($content); |
| | | if (!$config) { |
| | | return null; |
| | | } |
| | | |
| | | // Check if this orderby is a custom order |
| | | $customOrders = $config['custom_order'] ?? []; |
| | | $customOrders = $config->custom_order ?? []; |
| | | if (empty($customOrders) || !isset($customOrders[$orderby])) { |
| | | return null; |
| | | } |
| | | |
| | | // Get field definition |
| | | $fields = $config['fields'] ?? []; |
| | | $fields = $config->getFields()??[]; |
| | | if (!isset($fields[$orderby])) { |
| | | return null; |
| | | } |
| | |
| | | protected function isTimeline($args, $data):bool |
| | | { |
| | | $post_types = is_array($args['post_type']) ? $args['post_type'] : [$args['post_type']]; |
| | | foreach ($post_types as $type) { |
| | | if (Features::forContent($type)->has('is_timeline')) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | $areTimeline = array_map(function($type) { return BASE.$type; },Registrar::withFeature('is_timeline', 'post')); |
| | | return !empty(array_intersect($post_types, $areTimeline)); |
| | | } |
| | | |
| | | protected function applyDateFilters(array $args, array $data):array |
| | |
| | | $key = $cache->generateKey($key); |
| | | } |
| | | |
| | | // Prefer tag freshness if available |
| | | $tags = $cache->getTags(); |
| | | |
| | | $lastModified = $tags |
| | | ? $cache->getLastModifiedForTags($tags) |
| | | : $cache::lastModified($group); |
| | | |
| | | $lastModified = $cache::lastModified($group); |
| | | |
| | | if (!$lastModified) { |
| | | return false; |
| | |
| | | |
| | | // Use existing error handler |
| | | try { |
| | | JVB()->error()->log( |
| | | Errors::getInstance()->log( |
| | | 'security_audit', |
| | | $event, |
| | | $context, |
| | | 'info' |
| | | ); |
| | | } catch (\Exception $e) { |
| | | } catch (Exception $e) { |
| | | // Fallback to error_log if handler fails |
| | | error_log("Security Audit: {$event} - " . json_encode($context)); |
| | | } |
| | |
| | | |
| | | protected function verifyTurnstile(string $token): bool |
| | | { |
| | | if (!Features::hasIntegration('cloudflare') || !JVB()->connect('cloudflare')->isSetUp()) { |
| | | if (!Site::hasIntegration('cloudflare') || !Cloudflare::getInstance()->isSetUp()) { |
| | | return true; |
| | | } |
| | | |
| | |
| | | return false; |
| | | } |
| | | |
| | | return JVB()->connect('cloudflare')->verifyTurnstile($token); |
| | | return Cloudflare::getInstance()->verifyTurnstile($token); |
| | | } |
| | | } |