SockDrawer/SockBot

View on GitHub
providers/nodebb/category.js

Summary

Maintainability
B
4 hrs
Test Coverage
'use strict';
/**
* NodeBB provider module Category class
* @module sockbot.providers.nodebb.Category
* @author Accalia
* @license MIT
*/
const utils = require('../../lib/utils');
 
/**
* Create a Category class and bind it to a forum instance
*
* @param {Provider} forum A forum instance to bind to constructed Category class
* @returns {Category} A Category class bound to the provided `forum` instance
*/
Function `bindCategory` has 114 lines of code (exceeds 25 allowed). Consider refactoring.
exports.bindCategory = function bindCategory(forum) {
/**
* Topic Processor
*
* @typedef {TopicProcesspr}
* @function
*
* @param {Topic} topic Topic to process
* @param {User} user Topic Opening User
* @param {Category} category The category `topic` belongs to
* @returns {Promise} Resolves on completion
*/
 
/**
* Create a function to process topic data using a Topic Processor
*
* @private
*
* @param {TopicProcessor} eachTopic Function to process topics
* @returns {function} Internal topic processing function
*/
function onEachTopic(eachTopic) {
return (data) => forum.Topic.parseExtended(data)
.then((parsed) => eachTopic(parsed.topic, parsed.user, parsed.category));
}
 
/**
* Category Class
*
* Represents a forum category.
*
* @public
*
*/
class Category {
/**
* Construct a category object from a provided payload.
*
* This constructor is intended for private use only, if you need top construct a category from payload data use
* `Category.parse()` instead.
*
* @public
* @class
*
* @param {*} payload Payload to construct the Category object out of
*/
constructor(payload) {
payload = utils.parseJSON(payload);
const values = {
id: payload.cid,
name: payload.name,
description: payload.description,
url: payload.slug,
parentId: payload.parentCid,
topicCount: payload.topic_count,
postCount: payload.post_count,
recentPosts: payload.numRecentReplies
};
utils.mapSet(this, values);
}
 
/**
* Category Id
*
* @public
*
* @type {number}
*/
get id() {
return utils.mapGet(this, 'id');
}
 
/**
* Category Name
*
* @public
*
* @type {string}
*/
get name() {
return utils.mapGet(this, 'name');
}
 
/**
* Category description
*
* @public
*
* @type {string}
*/
get description() {
return utils.mapGet(this, 'description');
}
 
/**
* Parent Category Id
*
* @public
*
* @type {number}
*/
get parentId() {
return utils.mapGet(this, 'parentId');
}
 
/**
* Number of topics in this category
*
* @public
*
* @type {number}
*/
get topicCount() {
return utils.mapGet(this, 'topicCount');
}
 
/**
* Number of posts in this category
*
* @public
*
* @type {number}
*/
get postCount() {
return utils.mapGet(this, 'postCount');
}
 
/**
* Number of "recent" posts in this category
*
* @public
*
* @type {number}
*/
get recentPosts() {
return utils.mapGet(this, 'recentPosts');
}
 
/**
* The web URL of the category
*
* @public
*
* @returns {Promise<string>} Resolves to the web URL *
*/
url() {
return Promise.resolve(`${forum.url}/category/${utils.mapGet(this, 'url')}`);
}
 
/**
* Get all Topics in the category
*
* @public
*
* @param {TopicProcessor} eachTopic A function to process each topic
* @returns {Promise} Resolves when all topics have been processed
*/
getAllTopics(eachTopic) {
return new Promise((resolve, reject) => {
let idx = 0;
const each = onEachTopic(eachTopic);
const iterate = () => forum._emit('categories.loadMore', {
cid: this.id,
after: idx,
direction: 1
}).then((results) => {
if (!results.topics || !results.topics.length) {
return resolve(this);
}
idx = results.nextStart;
return utils.iterate(results.topics, each)
.then(iterate).catch(reject);
}).catch(reject);
iterate();
});
}
 
/**
* Get all recently active Topics in the category
*
* @public
*
* @param {TopicProcessor} eachTopic A function to process each topic
* @returns {Promise} Resolves when all topics have been processed
*/
getRecentTopics(eachTopic) {
const payload = {
cid: this.id,
after: 0,
direction: 1
};
const each = onEachTopic(eachTopic);
return forum._emit('categories.loadMore', payload)
.then((results) => utils.iterate(results.topics, each))
.then(() => this);
}
 
/**
* Apply an action to this category
*
* @private
*
* @param {string} action The action to perform
* @returns {Promise<Category>} Resolves to delf on completion
*/
_categoryAction(action) {
const payload = {
cid: this.id
};
return forum._emit(action, payload)
.then(() => this);
}
/**
* Add a topic to this category
*
* @public
*
* @param {string} title The title of the topic
* @param {string} body The body of the first post of the topic
*
* @returns {Promise<Topic>} Resolves to the newly created topic
*/
addTopic(title, body) {
const payload = {
cid: this.id,
title: title,
content: body,
tags: [],
thumb: ''
};
return forum._emitWithRetry(10000, 'topics.post', payload)
.then((results) => forum.Topic.parse(results));
}
 
/**
* Watch this category for new activity
*
* @public
*
* @returns {Promise<Category>} Resolves to self on completion
*/
watch() {
return this._categoryAction('categories.watch');
}
 
/**
* Stop watching this category for new activity
*
* @public
*
* @returns {Promise<Category>} Resolves to self on completion
*/
unwatch() {
return this._categoryAction('categories.ignore');
}
 
/**
* Prevent this category from generating any notifications
*
* This is not currently supported by NodeBB and is a noop
*
* @public
*
* @returns {Promise<Category>} Resolves to self on completion
*/
mute() {
return Promise.resolve(this);
}
 
/**
* Allow this category to generate notifications
*
* This is not currently supported by NodeBB and is a noop
*
* @public
*
* @returns {Promise<Category>} Resolves to self on completion
*/
unmute() {
return Promise.resolve(this);
}
 
/**
* retrieve a category by Id
*
* @public
*
* @param {number} categoryId Id of the category to retrieve
* @returns {Promise<Category>} Resolves to retrieved category
*/
static get(categoryId) {
return forum.fetchObject('categories.getCategory', categoryId, Category.parse);
}
 
 
/**
* Parse a category from payload data
*
* @public
*
* @param {*} payload Data to parse as category
* @returns {Category} Parsed category
*
*/
static parse(payload) {
if (!payload) {
throw new Error('E_CATEGORY_NOT_FOUND');
}
return new Category(payload);
}
}
return Category;
};