import request from "request-promise-native"; import { Response } from "request"; import { Dict } from "./util"; enum ReqMethod { GET = "get", POST = "post", DELETE = "delete" } export interface RequestError { code: string; message: string; params: { key: string; value: any; }[]; } export type RequestErrorSet = { errors: RequestError[] }; export class XenforoClient { constructor(private endpoint: string, private userKey: string) { } private async makeRequest(uri: string, method: ReqMethod, data?: any) { let result = await request(`${this.endpoint}/${uri}`, { method: method, headers: { "XF-Api-Key": this.userKey }, form: data || undefined, resolveWithFullResponse: true }) as Response; if (result.statusCode != 200) { throw await JSON.parse(result.body) as RequestErrorSet; } else { return await JSON.parse(result.body) as T; } } async getThread(id: number, opts?: GetThreadOptions) { return await this.makeRequest(`threads/${id}`, ReqMethod.GET, opts); } async deleteThread(id: number, opts?: DeleteThreadOptions) { return await this.makeRequest(`threads/${id}`, ReqMethod.DELETE, opts); } async createThread(forumId: number, title: string, message: string, opts?: CreateThreadOptions) { return await this.makeRequest(`threads/`, ReqMethod.POST, { node_id: forumId, title: title, message: message, ...opts }); } async getPost(id: number) { let post = await this.makeRequest<{post: Post}>(`posts/${id}`, ReqMethod.GET); return post.post; } async getForumThreads(id: number) { return await this.makeRequest(`forums/${id}/threads`, ReqMethod.GET); } } //#region Request types interface DeleteThreadOptions { hard_delete?: boolean; reason?: boolean; starter_alert?: boolean; starter_alert_reason?: boolean; } interface GetThreadOptions { with_posts?: boolean; page?: number; } interface CreateThreadOptions { prefix_id?: number; tags?: string[]; custom_fields?: Dict; discussion_open?: boolean; sticky?: boolean; attachment_key?: boolean; } //#endregion //#region Response types type GetThreadResponse = { thread: Thread; messages: Post[]; pagination: any; }; type SuccessResponse = { success: boolean; } type CreateThreadResponse = SuccessResponse & { thread: Thread; }; type GetForumThreadsResponse = { threads: Thread[]; pagination: object; sticky: Thread[]; }; //#endregion //#region Data types export interface Forum { allow_posting: boolean; allow_poll: boolean; require_prefix: boolean; min_tags: number; } export interface User { about?: string; activity_visible?: boolean; age?: number; alert_optout?: any[]; allow_post_profile?: string; allow_receive_news_feed?: string; allow_send_personal_conversation?: string; allow_view_identities: string; allow_view_profile?: string; avatar_urls: object; can_ban: boolean; can_converse: boolean; can_edit: boolean; can_follow: boolean; can_ignore: boolean; can_post_profile: boolean; can_view_profile: boolean; can_view_profile_posts: boolean; can_warn: boolean; content_show_signature?: boolean; creation_watch_state?: string; custom_fields?: object; custom_title?: string; dob?: object; email?: string; email_on_conversation?: boolean; gravatar?: string; interaction_watch_state?: boolean; is_admin?: boolean; is_banned?: boolean; is_discouraged?: boolean; is_followed?: boolean; is_ignored?: boolean; is_moderator?: boolean; is_super_admin?: boolean; last_activity?: number; location: string; push_on_conversation?: boolean; push_optout?: any[]; receive_admin_email?: boolean; secondary_group_ids?: any[]; show_dob_date?: boolean; show_dob_year?: boolean; signature: string; timezone?: string; use_tfa?: any[]; user_group_id?: number; user_state?: string; user_title: string; visible?: boolean; warning_points?: number; website?: string; user_id: number; username: string; message_count: number; register_date: number; trophy_points: number; is_staff: boolean; reaction_score: number; } export interface Node { breadcrumbs: any[]; type_data: object; node_id: number; title: string; node_name: string; description: string; node_type_id: string; parent_node_id: number; display_order: number; display_in_list: boolean; } export interface Thread { username: string; is_watching?: boolean; visitor_post_count?: number; custom_fields: object; tags: any[]; prefix?: string; can_edit: boolean; can_edit_tags: boolean; can_reply: boolean; can_soft_delete: boolean; can_hard_delete: boolean; can_view_attachments: boolean; Forum?: Node; thread_id: number; node_id: number; title: string; reply_count: number; view_count: number; user_id: number; post_date: number; sticky: boolean; discussion_state: string; discussion_open: boolean; discussion_type: string; first_post_id: number; last_post_date: number; last_post_id: number; last_post_user_id: number; last_post_username: string; first_post_reaction_score: number; prefix_id: number; } export interface Attachment { filename: string; file_size: number; height: number; width: number; thumbnail_url: string; video_url: string; attachment_id: number; content_type: string; content_id: number; attach_date: number; view_count: number; } export interface Post { username: string; is_first_post: boolean; is_last_post: boolean; can_edit: boolean; can_soft_delete: boolean; can_hard_delete: boolean; can_react: boolean; can_view_attachments: boolean; Thread?: Thread; Attachments?: Attachment[]; is_reacted_to: boolean; visitor_reaction_id: number; post_id: number; thread_id: number; user_id: number; post_date: number; message: string; message_state: string; attach_count: number; warning_message: string; position: number; last_edit_date: number; reaction_score: number; User: User; } //#endregion