| | |
| | | <?php |
| | | namespace JVBase\rest\routes; |
| | | |
| | | use JVBase\base\Site; |
| | | use JVBase\Instance; |
| | | use JVBase\managers\Approvals; |
| | | use JVBase\managers\Cache; |
| | | use JVBase\managers\CustomTable; |
| | | use JVBase\managers\NotificationManager; |
| | | use JVBase\registrar\Registrar; |
| | | use JVBase\rest\Rest; |
| | | use JVBase\rest\Route; |
| | |
| | | $this->cacheName = 'notifications'; |
| | | $this->cacheTtl = HOUR_IN_SECONDS; |
| | | parent::__construct(); |
| | | $this->cache = Cache::for($this->cacheName, 'user', $this->cacheTtl); |
| | | |
| | | $this->notifications = CustomTable::for('notifications'); |
| | | $this->metrics = CustomTable::for('notification_metrics'); |
| | | |
| | | // Build complete type map |
| | | $allTypes = []; |
| | |
| | | if (!$user_id) { |
| | | return $this->unauthorized(); |
| | | } |
| | | $type = sanitize_text_field($request->get_param('type') ?? ''); |
| | | $status = sanitize_text_field($request->get_param('status') ?? ''); |
| | | $limit = absint($request->get_param('limit')); |
| | | $offset = absint($request->get_param('offset')); |
| | | $args = $this->buildParams($request); |
| | | |
| | | $cacheKey = compact('user_id', 'type', 'status', 'limit', 'offset'); |
| | | |
| | | $result = $this->cache->remember($cacheKey, function() use ($user_id, $type, $status, $limit, $offset) { |
| | | // Build where conditions |
| | | $where = ['owner_id' => $user_id]; |
| | | if ($type) $where['type'] = $type; |
| | | if ($status) $where['status'] = $status; |
| | | |
| | | $items = $this->notifications |
| | | ->where($where) |
| | | ->orderBy('created_at', 'DESC') |
| | | ->limit($limit, $offset) |
| | | ->getResults(); |
| | | |
| | | $total = $this->notifications->where($where)->countResults(); |
| | | |
| | | // Format notifications |
| | | $formatted = array_map([$this, 'formatNotification'], $items); |
| | | |
| | | return [ |
| | | 'items' => $formatted, |
| | | 'total' => $total, |
| | | 'has_more' => ($offset + $limit) < $total |
| | | ]; |
| | | }); |
| | | |
| | | return $this->success($result); |
| | | return $this->success($this->manager->getUserNotifications($user_id, $args)); |
| | | } |
| | | |
| | | /** |
| | |
| | | if (!$user_id) { |
| | | return $this->unauthorized(); |
| | | } |
| | | $type = sanitize_text_field($request->get_param('type') ?? ''); |
| | | |
| | | $cacheKey = compact('user_id', 'type'); |
| | | |
| | | $count = $this->cache->remember($cacheKey, function() use ($user_id, $type) { |
| | | $where = ['owner_id' => $user_id, 'status' => 'unread']; |
| | | if ($type) $where['type'] = $type; |
| | | |
| | | return $this->notifications->where($where)->countResults(); |
| | | }); |
| | | $args = $this->buildParams($request); |
| | | $args['status'] = 'unread'; |
| | | $count = $this->manager->countUserNotifications($user_id, $args); |
| | | |
| | | return $this->success(['count' => $count]); |
| | | } |
| | |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * Get regular notifications from the notifications table |
| | | */ |
| | | protected function getRegularNotifications(int $user_id, array $params): array |
| | | { |
| | | $cacheKey = compact('user_id', 'params'); |
| | | |
| | | return $this->cache->remember($cacheKey, function() use ($user_id, $params) { |
| | | $status = $params['status']; |
| | | $type = $params['type']; |
| | | $limit = $params['limit']; |
| | | $offset = $params['page']; |
| | | |
| | | // Build base query |
| | | $where = ['owner_id' => $user_id]; |
| | | |
| | | // Handle status filter |
| | | if ($status === 'read') { |
| | | // For multiple statuses, use raw query |
| | | $notifications = $this->getNotificationsWithMultipleStatuses( |
| | | $user_id, |
| | | ['read', 'actioned'], |
| | | $type, |
| | | $limit, |
| | | $offset |
| | | ); |
| | | } else { |
| | | // Single status - use fluent builder |
| | | if ($status !== 'all') { |
| | | $where['status'] = $status; |
| | | } |
| | | |
| | | // Handle type filter |
| | | if ($type !== 'all' && isset($this->typeMap[$type])) { |
| | | $types = $this->typeMap[$type]; |
| | | if (!empty($types)) { |
| | | // Multiple types - use raw query |
| | | return $this->getNotificationsByTypes( |
| | | $user_id, |
| | | $types, |
| | | $status, |
| | | $limit, |
| | | $offset |
| | | ); |
| | | } |
| | | } |
| | | |
| | | // Simple query - use fluent builder |
| | | $notifications = $this->notifications |
| | | ->where($where) |
| | | ->orderBy('created_at', 'DESC') |
| | | ->limit($limit, $offset) |
| | | ->getResults(); |
| | | } |
| | | |
| | | // Format notifications |
| | | return array_map([$this, 'formatNotification'], $notifications); |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * Get notifications with multiple status values |
| | | */ |
| | | protected function getNotificationsWithMultipleStatuses( |
| | | int $user_id, |
| | | array $statuses, |
| | | string $type, |
| | | int $limit, |
| | | int $offset |
| | | ): array { |
| | | $placeholders = implode(',', array_fill(0, count($statuses), '%s')); |
| | | $params = array_merge([$user_id], $statuses); |
| | | |
| | | $typeCondition = ''; |
| | | if ($type !== 'all' && isset($this->typeMap[$type])) { |
| | | $types = $this->typeMap[$type]; |
| | | if (!empty($types)) { |
| | | $typePlaceholders = implode(',', array_fill(0, count($types), '%s')); |
| | | $typeCondition = "AND type IN ({$typePlaceholders})"; |
| | | $params = array_merge($params, $types); |
| | | } |
| | | } |
| | | |
| | | $params[] = $limit; |
| | | $params[] = $offset; |
| | | |
| | | return $this->notifications->queryResults( |
| | | "SELECT * FROM {table} |
| | | WHERE owner_id = %d |
| | | AND status IN ({$placeholders}) |
| | | {$typeCondition} |
| | | ORDER BY created_at DESC |
| | | LIMIT %d OFFSET %d", |
| | | $params |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * Get notifications by multiple types |
| | | */ |
| | | protected function getNotificationsByTypes( |
| | | int $user_id, |
| | | array $types, |
| | | string $status, |
| | | int $limit, |
| | | int $offset |
| | | ): array { |
| | | $placeholders = implode(',', array_fill(0, count($types), '%s')); |
| | | $params = array_merge([$user_id], $types, [$limit, $offset]); |
| | | |
| | | $statusCondition = ''; |
| | | if ($status !== 'all') { |
| | | $statusCondition = "AND status = %s"; |
| | | array_splice($params, -2, 0, [$status]); |
| | | } |
| | | |
| | | return $this->notifications->queryResults( |
| | | "SELECT * FROM {table} |
| | | WHERE owner_id = %d |
| | | AND type IN ({$placeholders}) |
| | | {$statusCondition} |
| | | ORDER BY created_at DESC |
| | | LIMIT %d OFFSET %d", |
| | | $params |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * Get approval notifications from the approval_requests table |
| | | */ |
| | | protected function getApprovalNotifications(int $user_id, string $status): array |
| | | { |
| | | $cacheKey = compact('user_id', 'status'); |
| | | |
| | | return $this->cache->remember($cacheKey, function() use ($user_id, $status) { |
| | | if (!$this->isVerifiedUser($user_id)) { |
| | | return []; |
| | | } |
| | | |
| | | global $wpdb; |
| | | $formatted = []; |
| | | |
| | | // Build status condition |
| | | $statusCondition = "1=1"; |
| | | if ($status === 'unread') { |
| | | $statusCondition = "a.status = 'pending'"; |
| | | } elseif ($status === 'read') { |
| | | $statusCondition = "a.status IN ('approved', 'rejected')"; |
| | | } elseif ($status !== 'all') { |
| | | $statusCondition = $wpdb->prepare("a.status = %s", $status); |
| | | } |
| | | |
| | | $approvals = Registrar::withFeature('approve_new'); |
| | | foreach ($approvals as $type => $config) { |
| | | $table = $wpdb->prefix . BASE . 'approval_' . $type . 'requests'; |
| | | $votes = $wpdb->prefix . BASE . 'approval_' . $type . 'votes'; |
| | | |
| | | $approvalRequests = $wpdb->get_results( |
| | | $wpdb->prepare( |
| | | "SELECT a.*, |
| | | COALESCE(v.vote, 'none') as user_vote |
| | | FROM {$table} a |
| | | LEFT JOIN {$votes} v ON a.id = v.request_id AND v.user_id = %d |
| | | WHERE a.user_id != %d |
| | | AND {$statusCondition} |
| | | ORDER BY a.created_at DESC", |
| | | $user_id, |
| | | $user_id |
| | | ) |
| | | ); |
| | | |
| | | // Filter out requests created by current user |
| | | foreach ($approvalRequests as $approval) { |
| | | $requested_by = json_decode($approval->requested_by, true); |
| | | |
| | | if (is_array($requested_by) && in_array($user_id, $requested_by)) { |
| | | continue; |
| | | } |
| | | |
| | | $formatted[] = $this->formatApprovalNotification($approval); |
| | | } |
| | | } |
| | | |
| | | return $formatted; |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * Get content notifications for a user |
| | |
| | | { |
| | | $params = $request->get_params(); |
| | | |
| | | return [ |
| | | 'status' => in_array($params['status'] ?? '', ['all', 'unread', 'expired']) |
| | | $args = [ |
| | | 'status' => in_array($params['status']??'unread', ['all', 'unread', 'expired']) |
| | | ? $params['status'] |
| | | : 'unread', |
| | | 'user_id' => get_current_user_id(), |
| | | 'page' => absint($params['page'] ?? 1), |
| | | 'type' => in_array($params['type'] ?? '', array_keys($this->manager->notification_types ?? [])) |
| | | 'type' => in_array($params['type'] ?? 'all', array_keys($this->manager->notification_types ?? [])) |
| | | ? $params['type'] |
| | | : 'all', |
| | | 'orderby' => $this->checkArray($params['orderby'], ['target_type', 'priority', 'created_at','read_at','actioned_at','action_taken','status'])??'created_at', |
| | | 'order' => strtoupper($this->checkArray($params['order']??'DESC', ['desc','asc'])??'DESC'), |
| | | 'page' => max(1, absint($params['page']??1)), |
| | | 'per_page' => absint($params['per_page']??20), |
| | | ]; |
| | | |
| | | foreach ($params as $param => $value) { |
| | | $result = match ($param) { |
| | | 'target_id' => absint($value), |
| | | 'target_type' => sanitize_text_field(strtolower($value)), |
| | | 'from_user' => $this->checkUser(absint($value)), |
| | | 'priority' => $this->checkArray($value, ['low','medium', 'high']), |
| | | 'action_taken' => $value === 1 ? 1 : 0, |
| | | default => false |
| | | }; |
| | | if ($result) { |
| | | $args[$param] = $result; |
| | | } |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |