apiKey = config('services.xf_api.key'); $this->superUserId = config('services.xf_api.user'); $this->apiUrl = config('services.xf_api.url'); } /** * @throws ConnectionException */ private function get(string $endpoint, ?int $customUserId = null ): mixed { $response = Http::withHeaders([ 'XF-Api-Key' => $this->apiKey, 'XF-Api-User' => $customUserId ?? $this->superUserId, ])->get("{$this->apiUrl}/{$endpoint}"); if( !$response->ok() ) return null; return $response->json(); } private function post(string $endpoint, ?int $customUserId = null, array $data = [] ): mixed { $response = Http::withHeaders([ 'XF-Api-Key' => $this->apiKey, 'XF-Api-User' => $customUserId ?? $this->superUserId, ])->post("{$this->apiUrl}/{$endpoint}", $data); if( !$response->ok() ) return null; return $response->json(); } private function delete(string $endpoint, ?int $customUserId = null, array $data = [] ): mixed { $response = Http::withHeaders([ 'XF-Api-Key' => $this->apiKey, 'XF-Api-User' => $customUserId ?? $this->superUserId, ])->delete("{$this->apiUrl}/{$endpoint}", $data); if( !$response->ok() ) return null; return $response->json(); } public function getUserAlerts(int $userId): mixed { if( app(XenforoService::class)->getXfUser($userId)?->alerts_unviewed > 0 ) { Cache::forget("xf_alerts_{$userId}"); } return Cache::remember("xf_alerts_{$userId}", 60, function() use($userId) { return $this->get("alerts?page=1&cutoff=7days", $userId); }); } public function markAllNotificationsRead(int $userId): void { Cache::forget("xf_alerts_{$userId}"); $this->post("alerts/marl-all", $userId ); } public function getConversations(int $userId): mixed { return Cache::remember("xf_conversations_{$userId}", 60, function() use($userId) { return $this->get("conversations?page=1&receiver_id={$userId}", $userId); }); } public function createConversation( array $userIdList, string $title, string $message, bool $conversationOpen, bool $openInvite ): bool { $response = $this->post("conversations", data: ['recipient_ids' => $userIdList, 'title' => $title, 'message' => $message, 'open_invite' => $openInvite, 'conversation_open' => $conversationOpen] ); return $response['success'] ?? false; } public function createCommentsThread( Entry|News $entry ): bool { if( !$entry->comments_thread_id || $entry->comments_thread_id <= 0 ){ $data = [ 'node_id' => config('xenforo.comments_node_id'), 'title' => $entry->complete_title, 'message' => $entry->description, 'prefix_id' => config('xenforo.comments_prefixes')[$entry->type] ?? 1, 'custom_fields' => [ 'entry_id' => $entry->id ], 'discussion_open' => true, ]; // TODO: Flag must be removed. $response = $this->post("threads?api_bypass_permissions=true", config('xenforo.bot_user_id'), $data ); if( $response['success'] === true ){ $commentsThreadId = $response['thread']['thread_id']; $entry->update(['comments_thread_id' => $commentsThreadId]); return true; } } return false; } /** * @throws ConnectionException */ public function getThreadPosts(int $threadId, int $page = 1 ): array { $response = $this->get("threads/{$threadId}/posts?page=$page"); if( !isset( $response['posts'] ) || $response['posts'] === [] ) return [ 'posts' => [], 'pagination' => null ]; return $response; } public function updateEntriesCount(int $entryCount, int $userId): bool { $response = $this->post("romhackplaza_entry/update_entry_count", data: ['count' => $entryCount, 'user_id' => $userId] ); return $response['success'] ?? false; } public function featuredRequest( Entry $entry ): bool { $response = $this->post("romhackplaza_entry/featured", data: [ 'entry_id' => $entry->id, 'user_id' => $entry->user_id, 'entry_title' => $entry->complete_title ?? $entry->title, ]); return $response['success'] ?? false; } public function deleteThreadWithEntry(int $threadId): bool { return (bool) $this->delete( "threads/{$threadId}", data: ['reason' => "Deletion with entry." ] ); } public function restoreThreadWithEntry(int $threadId): bool { return (bool) $this->post("threads/{$threadId}/undelete" ); } }