UNPKG

discourse-js

Version:

A client-side javascript wrapper for the discourse API.

799 lines (746 loc) 30.5 kB
import { camelizeKeys } from 'humps'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var _extendStatics = function extendStatics(d, b) { _extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; } || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return _extendStatics(d, b); }; function __extends(d, b) { _extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var _assign = function __assign() { _assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return _assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function sent() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } var createBody = function (params) { var form = new FormData(); Object.keys(params).forEach(function (paramKey) { var paramValue = params[paramKey]; if (paramValue instanceof Array) { paramValue.forEach(function (param) { form.append(paramKey + "[]", param); }); } else if (typeof paramValue === 'number') { form.append(paramKey, paramValue.toString()); } else { form.append(paramKey, paramValue); } }); return form; }; var buildQueryString = function (uri, params) { var queryString = Object.keys(params) .map(function (key) { var value = params[key]; if (Array.isArray(value)) { return value.map(function (sub) { return key + "[]=" + sub; }).join('&'); } return key + "=" + params[key]; }) .join('&'); var separator = !!queryString ? (uri.indexOf('?') !== -1 ? '&' : '?') : ''; return "" + uri + separator + queryString; }; var ApiError = /** @class */ (function (_super) { __extends(ApiError, _super); function ApiError(status, statusText, error, errorArray) { if (errorArray === void 0) { errorArray = []; } var _this = _super.call(this) || this; var errorMessage = error || errorArray.join(', '); _this.name = 'ApiError'; _this.status = status; _this.statusText = statusText; _this.message = status + " - " + (statusText || errorMessage); _this.error = errorMessage; return _this; } return ApiError; }(Error)); function Categories(discourse) { var _this = this; this.getCategory = function (_a) { if (_a === void 0) { _a = { latest: false, }; } return __awaiter(_this, void 0, void 0, function () { var cat_id = _a.cat_id, latest = _a.latest, inputs = __rest(_a, ["cat_id", "latest"]); return __generator(this, function (_b) { if (!cat_id) { throw new Error('No id defined. You must pass an `cat_id` to the getCategory function.'); } return [2 /*return*/, discourse.get({ path: buildQueryString("c/" + cat_id + (latest ? '/l/latest' : '') + ".json", inputs), })]; }); }); }; this.getSubcategory = function (_a) { if (_a === void 0) { _a = { latest: false, }; } return __awaiter(_this, void 0, void 0, function () { var cat_id = _a.cat_id, subcat_id = _a.subcat_id, latest = _a.latest, inputs = __rest(_a, ["cat_id", "subcat_id", "latest"]); return __generator(this, function (_b) { if (!cat_id || !subcat_id) { throw new Error('No id defined. You must pass an id to the getSubcategory function.'); } return [2 /*return*/, discourse.get({ path: buildQueryString("c/" + cat_id + "/" + subcat_id + (latest ? '/l/latest' : '') + ".json", inputs), })]; }); }); }; } function Groups(discourse) { var _this = this; this.getMembers = function (_a) { var group_name = _a.group_name; return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_b) { return [2 /*return*/, discourse.get({ path: "groups/" + group_name + "/members.json", })]; }); }); }; } function Messages(discourse) { var _this = this; this.get = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, discourse.get({ path: "topics/private-messages/" + discourse._API_USERNAME + ".json", })]; }); }); }; this.getGroupMessages = function (_a) { var group_name = _a.group_name; return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_b) { return [2 /*return*/, discourse.get({ path: "topics/private-messages-group/" + discourse._API_USERNAME + "/" + group_name + ".json", headers: { Accept: 'application/json', }, })]; }); }); }; this.getSentMessages = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, discourse.get({ path: "topics/private-messages-sent/" + discourse._API_USERNAME + ".json", })]; }); }); }; this.getAllMessages = function () { return __awaiter(_this, void 0, void 0, function () { var getMessages, getSentMessages; return __generator(this, function (_a) { getMessages = this.get(); getSentMessages = this.getSentMessages(); return [2 /*return*/, Promise.all([getMessages, getSentMessages])]; }); }); }; this.send = function (inputs) { if (inputs === void 0) { inputs = {}; } return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, discourse.post({ path: 'posts', body: inputs, })]; }); }); }; } function Notifications(discourse) { var _this = this; this.get = function (inputs) { if (inputs === void 0) { inputs = {}; } return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, discourse.get({ method: 'GET', path: buildQueryString('notifications.json', inputs), })]; }); }); }; this.markRead = function (_a) { var id = _a.id; return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_b) { return [2 /*return*/, discourse.put(_assign({ path: 'notifications/mark-read' }, (id ? { body: { id: id, }, } : {})))]; }); }); }; } var PostActions; (function (PostActions) { PostActions[PostActions["Bookmark"] = 1] = "Bookmark"; PostActions[PostActions["Like"] = 2] = "Like"; PostActions[PostActions["OffTopic"] = 3] = "OffTopic"; PostActions[PostActions["Inappropriate"] = 4] = "Inappropriate"; PostActions[PostActions["_"] = 5] = "_"; PostActions[PostActions["NotifyUser"] = 6] = "NotifyUser"; PostActions[PostActions["NotifyModerators"] = 7] = "NotifyModerators"; PostActions[PostActions["Spam"] = 8] = "Spam"; })(PostActions || (PostActions = {})); function Posts(discourse) { var _this = this; this.create = function (inputs) { if (inputs === void 0) { inputs = {}; } return __awaiter(_this, void 0, void 0, function () { var _a, url, width, height, shortUrl, body_1; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!inputs.imageUri) return [3 /*break*/, 2]; return [4 /*yield*/, discourse.uploads.create({ 'files[]': { uri: inputs.imageUri, name: 'photo.jpeg', type: 'image/jpeg', }, type: 'composer', synchronous: true, })]; case 1: _a = _b.sent(), url = _a.url, width = _a.width, height = _a.height, shortUrl = _a.shortUrl; if (url) { body_1 = {}; // Remove the imageUri from the inputs as it's not used in the next request. delete inputs.imageUri; Object.keys(inputs).forEach(function (key) { return (body_1[key] = inputs[key]); }); // Prepend the raw message with the image. body_1.raw = "![" + width + "x" + height + "](" + shortUrl + ")\n" + body_1.raw; return [2 /*return*/, discourse.post({ path: 'posts', body: body_1, })]; } return [3 /*break*/, 3]; case 2: return [2 /*return*/, discourse.post({ path: 'posts', body: inputs, })]; case 3: return [2 /*return*/]; } }); }); }; this.reply = function (_a) { var topic_id = _a.topic_id, raw = _a.raw, reply_to_post_number = _a.reply_to_post_number; return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_b) { if (!topic_id) { throw new Error('No topic_id defined. You must pass a topic to reply function.'); } return [2 /*return*/, discourse.post({ path: 'posts', body: { topic_id: topic_id, raw: raw, reply_to_post_number: reply_to_post_number, archetype: 'regular', nested_post: true, }, })]; }); }); }; /** * post_action_type_id values * 1: bookmark * 2: like * 3: flag - off topic * 4: flag - inappropriate * 8: flag - spam * 6: flag - notify user * 7: flag - notify moderators */ this.postAction = function (_a) { var _b = _a.method, method = _b === void 0 ? 'post' : _b, body = _a.body, _c = _a.id, id = _c === void 0 ? null : _c; return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_d) { return [2 /*return*/, discourse[method]({ path: id ? "post_actions/" + id : 'post_actions', body: body, })]; }); }); }; this.like = function (_a) { var id = _a.id; return _this.postAction({ body: { id: id, post_action_type_id: PostActions.Like } }); }; this.unlike = function (_a) { var id = _a.id; return _this.postAction({ method: 'delete', body: { post_action_type_id: PostActions.Like }, id: id, }); }; this.flag = function (_a) { var id = _a.id, post_action_type_id = _a.post_action_type_id, message = _a.message, flag_topic = _a.flag_topic; return _this.postAction({ body: { id: id, post_action_type_id: post_action_type_id, message: message, flag_topic: flag_topic } }); }; } function Preferences(discourse) { var _this = this; this.pickAvatar = function (_a) { var _b = _a === void 0 ? {} : _a, username = _b.username, upload_id = _b.upload_id; return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_c) { return [2 /*return*/, discourse.put({ path: "u/" + username + "/preferences/avatar/pick", body: { upload_id: upload_id, type: 'uploaded', }, })]; }); }); }; } function Topics(discourse) { var _this = this; this.getTopic = function (_a) { if (_a === void 0) { _a = {}; } return __awaiter(_this, void 0, void 0, function () { var id = _a.id, reverse = _a.reverse, inputs = __rest(_a, ["id", "reverse"]); return __generator(this, function (_b) { return [2 /*return*/, discourse.get({ path: buildQueryString("t/" + id + (reverse ? '/last' : '') + ".json", inputs), })]; }); }); }; this.getTopicPosts = function (_a) { if (_a === void 0) { _a = {}; } return __awaiter(_this, void 0, void 0, function () { var params; var id = _a.id, posts = _a.posts, inputs = __rest(_a, ["id", "posts"]); return __generator(this, function (_b) { params = _assign({ post_ids: posts }, inputs); return [2 /*return*/, discourse.get({ path: buildQueryString("t/" + id + "/posts.json", params), })]; }); }); }; this.getTopicsByUsername = function (_a) { return __awaiter(_this, void 0, void 0, function () { var username = _a.username, inputs = __rest(_a, ["username"]); return __generator(this, function (_b) { return [2 /*return*/, discourse.get({ path: buildQueryString("topics/created-by/" + username + ".json", inputs), })]; }); }); }; this.getTopicsByTag = function (_a) { if (_a === void 0) { _a = {}; } return __awaiter(_this, void 0, void 0, function () { var tag = _a.tag, inputs = __rest(_a, ["tag"]); return __generator(this, function (_b) { return [2 /*return*/, discourse.get({ path: buildQueryString("tags/" + tag + ".json", inputs), })]; }); }); }; this.getTopicsByCategoryAndTag = function (_a) { if (_a === void 0) { _a = {}; } return __awaiter(_this, void 0, void 0, function () { var tag = _a.tag, category = _a.category, subcategory = _a.subcategory, inputs = __rest(_a, ["tag", "category", "subcategory"]); return __generator(this, function (_b) { return [2 /*return*/, discourse.get({ path: buildQueryString("tags/c/" + category + "/" + (subcategory ? subcategory + "/" : '') + tag + ".json", inputs), })]; }); }); }; this.deleteTopic = function (_a) { if (_a === void 0) { _a = {}; } return __awaiter(_this, void 0, void 0, function () { var id = _a.id, inputs = __rest(_a, ["id"]); return __generator(this, function (_b) { return [2 /*return*/, discourse.delete({ path: buildQueryString("t/" + id, inputs), })]; }); }); }; this.createTopic = function (inputs) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, discourse.posts.create(inputs)]; }); }); }; } function Uploads(discourse) { var _this = this; this.create = function (body) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, discourse.post({ path: 'uploads.json', body: body, })]; }); }); }; } function Users(discourse) { var _this = this; this.getUser = function (_a) { var username = (_a === void 0 ? {} : _a).username; return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_b) { return [2 /*return*/, discourse .get({ path: "users/" + username + ".json", }) .then(function (response) { return response; }) .catch(function (error) { return error; })]; }); }); }; this.getUserSummary = function (_a) { var username = (_a === void 0 ? {} : _a).username; return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_b) { return [2 /*return*/, discourse .get({ path: "u/" + username + "/summary.json", }) .then(function (response) { return response; }) .catch(function (error) { return error; })]; }); }); }; } var NotificationType; (function (NotificationType) { NotificationType[NotificationType["mentioned"] = 1] = "mentioned"; NotificationType[NotificationType["replied"] = 2] = "replied"; NotificationType[NotificationType["quoted"] = 3] = "quoted"; NotificationType[NotificationType["edited"] = 4] = "edited"; NotificationType[NotificationType["liked"] = 5] = "liked"; NotificationType[NotificationType["privateMessage"] = 6] = "privateMessage"; NotificationType[NotificationType["invitedToPrivateMessage"] = 7] = "invitedToPrivateMessage"; NotificationType[NotificationType["inviteeAccepted"] = 8] = "inviteeAccepted"; NotificationType[NotificationType["posted"] = 9] = "posted"; NotificationType[NotificationType["movedPost"] = 10] = "movedPost"; NotificationType[NotificationType["linked"] = 11] = "linked"; NotificationType[NotificationType["grantedBadge"] = 12] = "grantedBadge"; NotificationType[NotificationType["invitedToTopic"] = 13] = "invitedToTopic"; NotificationType[NotificationType["custom"] = 14] = "custom"; NotificationType[NotificationType["groupMentioned"] = 15] = "groupMentioned"; NotificationType[NotificationType["groupMessageSummary"] = 16] = "groupMessageSummary"; NotificationType[NotificationType["watchingFirstPost"] = 17] = "watchingFirstPost"; NotificationType[NotificationType["topicReminder"] = 18] = "topicReminder"; NotificationType[NotificationType["likedConsolidated"] = 19] = "likedConsolidated"; NotificationType[NotificationType["postApproved"] = 20] = "postApproved"; NotificationType[NotificationType["codeReviewCommitApproved"] = 21] = "codeReviewCommitApproved"; NotificationType[NotificationType["membershipRequestAccepted"] = 22] = "membershipRequestAccepted"; NotificationType[NotificationType["membershipRequestConsolidated"] = 23] = "membershipRequestConsolidated"; NotificationType[NotificationType["bookmarkReminder"] = 24] = "bookmarkReminder"; NotificationType[NotificationType["reaction"] = 25] = "reaction"; NotificationType[NotificationType["votesReleased"] = 26] = "votesReleased"; NotificationType[NotificationType["eventReminder"] = 27] = "eventReminder"; NotificationType[NotificationType["eventInvitation"] = 28] = "eventInvitation"; })(NotificationType || (NotificationType = {})); var VERSION = require('../package.json').version; var resources = { Categories: Categories, Groups: Groups, Messages: Messages, Notifications: Notifications, Posts: Posts, Preferences: Preferences, Topics: Topics, Uploads: Uploads, Users: Users, }; var Discourse = /** @class */ (function () { function Discourse(userApiKey, baseUrl, apiKey) { var _this = this; if (apiKey === void 0) { apiKey = null; } this.config = function (_a) { var _b = _a === void 0 ? { apiUsername: null, apiKey: null, } : _a, userApiKey = _b.userApiKey, baseUrl = _b.baseUrl, apiUsername = _b.apiUsername, apiKey = _b.apiKey; _this._USER_API_KEY = userApiKey; _this._BASE_URL = baseUrl; // Admin User API _this._API_KEY = apiKey; _this._API_USERNAME = apiUsername; // If we are using the Admin API then we'll need to include // the API key and username in each request either as part // of our URL params or as part of our POST body _this.isUsingAdminAPI = _this._API_KEY && _this._API_USERNAME; }; this.createBody = function (body) { return _this.isUsingAdminAPI ? createBody(_assign(_assign({}, body), { api_key: _this._API_KEY, api_username: _this._API_USERNAME })) : createBody(body); }; this.get = function (_a) { var _b = _a === void 0 ? {} : _a, path = _b.path, headers = _b.headers; return _this.request({ method: 'GET', headers: headers, path: _this.isUsingAdminAPI ? buildQueryString(path, { api_key: _this._API_KEY, api_username: _this._API_USERNAME, }) : path, }); }; this.post = function (_a) { var path = _a.path, headers = _a.headers, body = _a.body; return _this.request({ method: 'POST', headers: headers, path: path, body: _this.createBody(body), }); }; this.request = function (options) { var body = options.body, method = options.method, path = options.path, headers = options.headers; var fetchOptions = { method: method, headers: _assign(_assign({}, _this.requestHeaders()), headers), body: body, mimeType: 'multipart/form-data', }; return fetch(_this._BASE_URL + "/" + path, fetchOptions) .then(function (response) { var contentType = response.headers.get('content-type'); if (response.ok) { if (contentType && contentType.indexOf('application/json') !== -1) { return response.json().then(camelizeKeys); } else { /** * If our response is OK but is not json * just resolve with response.text(). * This happens when we DELETE a topic * because nothing is returned from the request. */ return response.text(); } } else { var status_1 = response.status, statusText_1 = response.statusText; if (contentType && contentType.indexOf('application/json') !== -1) { return response.json().then(function (json) { throw new ApiError(status_1, statusText_1, '', json.errors); }); } else { return response.text().then(function (text) { throw new ApiError(status_1, statusText_1, text); }); } } }) .catch(function (error) { if (error instanceof ApiError) throw error; throw new Error(error); }); }; this._BASE_URL = baseUrl; this._USER_API_KEY = userApiKey; // Admin User API this._API_KEY = apiKey; var resource; for (resource in resources) { this[resource.toLowerCase()] = new resources[resource](this); } } Discourse.prototype.requestHeaders = function () { return _assign({ 'User-Agent': "DiscourseJS " + VERSION }, (this._USER_API_KEY ? { 'User-Api-Key': this._USER_API_KEY } : {})); }; Discourse.prototype.put = function (_a) { var path = _a.path, headers = _a.headers, body = _a.body; return this.request({ method: 'PUT', headers: headers, path: path, body: this.createBody(body), }); }; Discourse.prototype.delete = function (_a) { var path = _a.path, headers = _a.headers, body = _a.body; return this.request({ method: 'DELETE', headers: headers, path: path, body: this.createBody(body), }); }; return Discourse; }()); export default Discourse; export { ApiError, NotificationType, PostActions, buildQueryString, createBody }; //# sourceMappingURL=index.esm.js.map