xenforo.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. import request from "request-promise-native";
  2. import { Dict } from "./util";
  3. enum ReqMethod {
  4. GET = "get",
  5. POST = "post",
  6. DELETE = "delete"
  7. }
  8. export interface RequestError {
  9. code: string;
  10. message: string;
  11. params: { key: string; value: any; }[];
  12. }
  13. export type RequestErrorSet = { errors: RequestError[] };
  14. export class XenforoClient {
  15. constructor(private endpoint: string, private userKey: string) {
  16. }
  17. private async makeRequest<T>(uri :string, method: ReqMethod, data?: any) {
  18. let result = await request(`${this.endpoint}/${uri}`, {
  19. method: method,
  20. headers: {
  21. "XF-Api-Key": this.userKey
  22. },
  23. form: data || undefined,
  24. resolveWithFullResponse: true
  25. }) as Response;
  26. if(result.status != 200){
  27. throw await result.json() as RequestErrorSet;
  28. } else {
  29. return await result.json() as T;
  30. }
  31. }
  32. async getThread(id: string, opts?: GetThreadOptions) {
  33. return await this.makeRequest<GetThreadResponse>(`threads/${id}`, ReqMethod.GET, opts);
  34. }
  35. async deleteThread(id: string, opts?: DeleteThreadOptions) {
  36. return await this.makeRequest<SuccessResponse>(`threads/${id}`, ReqMethod.DELETE, opts);
  37. }
  38. async createThread(forumId: string, title: string, message: string, opts?: CreateThreadOptions) {
  39. return await this.makeRequest<CreateThreadResponse>(`threads/`, ReqMethod.POST, {
  40. node_id: forumId,
  41. title: title,
  42. message: message,
  43. ...opts
  44. });
  45. }
  46. }
  47. //#region Request types
  48. interface DeleteThreadOptions {
  49. hard_delete?: boolean;
  50. reason?: boolean;
  51. starter_alert?: boolean;
  52. starter_alert_reason?: boolean;
  53. }
  54. interface GetThreadOptions {
  55. with_posts?: boolean;
  56. page?: number;
  57. }
  58. interface CreateThreadOptions {
  59. prefix_id?: number;
  60. tags?: string[];
  61. custom_fields?: Dict<string>;
  62. discussion_open?: boolean;
  63. sticky?: boolean;
  64. attachment_key?: boolean;
  65. }
  66. //#endregion
  67. //#region Response types
  68. type GetThreadResponse = {
  69. thread: Thread;
  70. messages: Post[];
  71. pagination: any;
  72. };
  73. type SuccessResponse = {
  74. success: boolean;
  75. }
  76. type CreateThreadResponse = SuccessResponse & { thread: Thread; };
  77. //#endregion
  78. //#region Data types
  79. export interface Forum {
  80. allow_posting: boolean;
  81. allow_poll: boolean;
  82. require_prefix: boolean;
  83. min_tags: number;
  84. }
  85. export interface User {
  86. about?: string;
  87. activity_visible?: boolean;
  88. age?: number;
  89. alert_optout?: any[];
  90. allow_post_profile?: string;
  91. allow_receive_news_feed?: string;
  92. allow_send_personal_conversation?: string;
  93. allow_view_identities: string;
  94. allow_view_profile?: string;
  95. avatar_urls: object;
  96. can_ban: boolean;
  97. can_converse: boolean;
  98. can_edit: boolean;
  99. can_follow: boolean;
  100. can_ignore: boolean;
  101. can_post_profile: boolean;
  102. can_view_profile: boolean;
  103. can_view_profile_posts: boolean;
  104. can_warn: boolean;
  105. content_show_signature?: boolean;
  106. creation_watch_state?: string;
  107. custom_fields?: object;
  108. custom_title?: string;
  109. dob?: object;
  110. email?: string;
  111. email_on_conversation?: boolean;
  112. gravatar?: string;
  113. interaction_watch_state?: boolean;
  114. is_admin?: boolean;
  115. is_banned?: boolean;
  116. is_discouraged?: boolean;
  117. is_followed?: boolean;
  118. is_ignored?: boolean;
  119. is_moderator?: boolean;
  120. is_super_admin?: boolean;
  121. last_activity?: number;
  122. location: string;
  123. push_on_conversation?: boolean;
  124. push_optout?: any[];
  125. receive_admin_email?: boolean;
  126. secondary_group_ids?: any[];
  127. show_dob_date?: boolean;
  128. show_dob_year?: boolean;
  129. signature: string;
  130. timezone?: string;
  131. use_tfa?: any[];
  132. user_group_id?: number;
  133. user_state?: string;
  134. user_title: string;
  135. visible?: boolean;
  136. warning_points?: number;
  137. website?: string;
  138. user_id: number;
  139. username: string;
  140. message_count: number;
  141. register_date: number;
  142. trophy_points: number;
  143. is_staff: boolean;
  144. reaction_score: number;
  145. }
  146. export interface Node {
  147. breadcrumbs: any[];
  148. type_data: object;
  149. node_id: number;
  150. title: string;
  151. node_name: string;
  152. description: string;
  153. node_type_id: string;
  154. parent_node_id: number;
  155. display_order: number;
  156. display_in_list: boolean;
  157. }
  158. export interface Thread {
  159. username: string;
  160. is_watching?: boolean;
  161. visitor_post_count?: number;
  162. custom_fields: object;
  163. tags: any[];
  164. prefix?: string;
  165. can_edit: boolean;
  166. can_edit_tags: boolean;
  167. can_reply: boolean;
  168. can_soft_delete: boolean;
  169. can_hard_delete: boolean;
  170. can_view_attachments: boolean;
  171. Forum?: Node;
  172. thread_id: number;
  173. node_id: number;
  174. title: string;
  175. reply_count: number;
  176. view_count: number;
  177. user_id: number;
  178. post_date: number;
  179. sticky: boolean;
  180. discussion_state: string;
  181. discussion_open: boolean;
  182. discussion_type: string;
  183. first_post_id: number;
  184. last_post_date: number;
  185. last_post_id: number;
  186. last_post_user_id: number;
  187. last_post_username: string;
  188. first_post_reaction_score: number;
  189. prefix_id: number;
  190. }
  191. export interface Attachment {
  192. filename: string;
  193. file_size: number;
  194. height: number;
  195. width: number;
  196. thumbnail_url: string;
  197. video_url: string;
  198. attachment_id: number;
  199. content_type: string;
  200. content_id: number;
  201. attach_date: number;
  202. view_count: number;
  203. }
  204. export interface Post {
  205. username: string;
  206. is_first_post: boolean;
  207. is_last_post: boolean;
  208. can_edit: boolean;
  209. can_soft_delete: boolean;
  210. can_hard_delete: boolean;
  211. can_react: boolean;
  212. can_view_attachments: boolean;
  213. Thread?: Thread;
  214. Attachments?: Attachment[];
  215. is_reacted_to: boolean;
  216. visitor_reaction_id: number;
  217. post_id: number;
  218. thread_id: number;
  219. user_id: number;
  220. post_date: number;
  221. message: string;
  222. message_state: string;
  223. attach_count: number;
  224. warning_message: string;
  225. position: number;
  226. last_edit_date: number;
  227. reaction_score: number;
  228. User: User;
  229. }
  230. //#endregion