UNPKG

growstocks-wrapper

Version:

A fully fledged GrowStocks OAuth & Pay API wrapper for NodeJS.

242 lines (212 loc) 7.59 kB
const RequestManager = require("../rest/RequestManager"); const Request = require("../rest/Request"); const Endpoints = require("../rest/Endpoints"); const GrowStocksUser = require("./GrowStocksUser"); const FormData = require("form-data"); const Transaction = require("./Transaction"); const { EventEmitter } = require("events"); /** * Represents a growstocks client. * @constructor * @param {string} options - Client options in JSON format. */ class GrowStocksClient extends EventEmitter { constructor (options) { super(); if (!options) throw new Error("You must include credentials as options."); /** * The name of growstocks developer organisation. * @type {string} */ this.organisation = options.organisation || null; /** * GrowStocks organisation url. * @type {string} */ this.url = options.url || null; /** * GrowStocks client code. * @type {string} */ this.clientCode = options.clientCode || null; /** * GrowStocks secret token. * @type {string} */ Object.defineProperty(this, "secret", { value: options.secret }); /** * This growstocks client's request manager. * @type {RequestManager} */ this.manager = new RequestManager(); /** * This growstocks client's redirect url. * @type {string} */ this.redirectURL = options.redirectURL || null; /** * Array of scopes the organisation will ask for when logging in the user. * @type {array[string]} */ this.scopes = options.scopes.map(scope => scope.toLowerCase()) || null; /** * payRedirectURL - the url that users will be redirected to after transaction is authorized. * @type {string} */ this.payRedirectURL = options.payRedirectURL || null; /** * The developer's account balance. * @type {number} */ this.balance = null; if ([ this.organisation, this.url, this.clientCode, this.secret, this.redirectURL, this.scopes ].some(property => property === null)) throw new TypeError("You must provide valid options keys (organisation, url, clientCode, secret, redirectURL, scopes) within the GrowStocksClient constructor."); for (const scope of this.scopes) { if (!["email", "profile", "balance"].includes(scope)) throw new TypeError(`Invalid scope ${scope} provided. Valid scopes are email, profile, balance.`); else continue; } if (this.scopes.includes("balance") && this.scopes.length < 2) throw new TypeError("The balance scope must be used with either profile or email scopes."); } /** * Use a authorization token to get data on a user. * @param {string} authToken * @returns {GrowStocksUser} A GrowStocks user. */ async exchangeAuthToken (authToken) { const body = new FormData(); body.append("secret", this.secret); body.append("token", authToken); const exhangeRequest = new Request("post", `${Endpoints.auth.base}${Endpoints.auth.user}`, { body: body }); const userData = await this.manager.push(exhangeRequest); if (userData.success) { return new GrowStocksUser(userData, authToken, this); } else { const errorObj = { error: true, location: `${Endpoints.auth.base}${Endpoints.auth.user}`, method: "post", reason: userData.reason, params: { token: authToken } }; this.emit("error", errorObj); return errorObj; } } /** * Returns a url encoded string to which you can redirect user for the authorization flow. * @returns {string} A valid url. */ get authURL () { return `${Endpoints.OAuth.base}${Endpoints.OAuth.authorize(this.clientCode, this.scopes, this.redirectURL)}`; } /** * Gets data on a transaction using it's id. * @param {string} transactionid - The id of the transaction. * @returns {Transaction} A new transaction. */ async getTransaction (transactionid) { const reqBody = new FormData(); reqBody.append("secret", this.secret); reqBody.append("transaction", transactionid); const req = new Request("post", `${Endpoints.pay.base}${Endpoints.pay.getTransaction}`, { body: reqBody }); const reqRes = await this.manager.push(req); if (reqRes.success) { return new Transaction(reqRes, this); } else { const errorObj = { error: true, location: `${Endpoints.pay.base}${Endpoints.pay.getTransaction}`, method: "post", reason: reqRes.reason, params: { transactionid } }; this.emit("error", errorObj); return errorObj; } } /** * Pay an user a certain amount of world locks. * @param {number} uid The growstocks user id of the user you want to send world locks to. * @param {number} amount The amount of world locks you want to send. * @param {string} note The note you want to include. (Optional; max 50 chars) * @returns {Transaction} A transaction with all the details. */ async pay (uid, amount, note = "") { if (isNaN(uid) && isNaN(parseInt(uid))) throw new Error("The user id format you want to pay is invalid."); if (!this.scopes.includes("balance")) throw new Error("To use the pay function, make sure you include balance scope."); if (!amount || isNaN(amount)) throw new TypeError("You must provide avalid number as amount to pay."); if (note.length > 50) { note = note.split("").slice(0, 46).join(" ") + "..."; this.client.emit("warn", `WARNING: Note for paying user with id ${this.id} (${this.name}) is larger than 50 characters (limit enforced by the api) so it's been trimed down to 50 characters.`); } const body = new FormData(); body.append("secret", this.secret); body.append("party", uid); body.append("amount", amount); body.append("notes", note); const request = new Request("post", `${Endpoints.pay.base}${Endpoints.pay.send}`, { body: body }); const response = await this.manager.push(request); if (response.success) { this.balance = response.balance; return await this.getTransaction(response.transaction); } else { const errorObj = { error: true, location: `${Endpoints.pay.base}${Endpoints.pay.send}`, method: "post", reason: response.reason, params: { uid, amount, note } }; this.emit("error", errorObj); return errorObj; } } /** * Sets the balance property of itself to the output of the API and returns it. */ async getBalance () { const body = new FormData(); body.append("secret", this.secret); const request = new Request("post", `${Endpoints.pay.base}${Endpoints.pay.balance}`, { body: body }); const response = await this.manager.push(request); if (response.success) { this.balance = response.balance; return this.balance; } else { const errorObj = { error: true, location: `${Endpoints.pay.base}${Endpoints.pay.balance}`, method: "post", reason: response.reason, params: {} }; this.emit("error", errorObj); return errorObj; } } } module.exports = GrowStocksClient;