diff --git a/package-lock.json b/package-lock.json index 72f0fa2..3f3c3b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "faker": "^5.5.3", "jest": "^29.7.0", "jest-fetch-mock": "^3.0.3", + "jsdoc": "^4.0.3", "jsonwebtoken": "^9.0.2", "moment-timezone": "^0.5.45", "mongodb": "^6.5.0", @@ -39,7 +40,8 @@ "@babel/node": "^7.23.9", "@babel/preset-env": "^7.24.3", "@faker-js/faker": "^8.4.1", - "@types/faker": "^6.6.9" + "@types/faker": "^6.6.9", + "jsdocs": "^0.0.1" } }, "node_modules/@ampproject/remapping": { @@ -2444,6 +2446,17 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jsdoc/salty": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.8.tgz", + "integrity": "sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==", + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, "node_modules/@mongodb-js/saslprep": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.5.tgz", @@ -2567,6 +2580,25 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==" + }, "node_modules/@types/node": { "version": "20.12.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.5.tgz", @@ -3046,6 +3078,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, "node_modules/body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -3228,6 +3265,17 @@ } ] }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -3837,6 +3885,17 @@ "node": ">= 0.6" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -6729,11 +6788,64 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, "node_modules/jsbn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, + "node_modules/jsdoc": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.3.tgz", + "integrity": "sha512-Nu7Sf35kXJ1MWDZIMAuATRQTg1iIPdzh7tqJ6jjvaU/GfDf+qi5UV8zJR3Mo+/pYFvm8mzay4+6O5EWigaQBQw==", + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^14.1.1", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdoc/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jsdocs": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsdocs/-/jsdocs-0.0.1.tgz", + "integrity": "sha512-XWCzq0PqgHUTgeHohvZdy0O5L69IOqPFt58w7jAmAEUMYU4cZtaCcN3iWUfwjq+fVFIkhCMMGSWFxd1vy1Hm3g==", + "dev": true, + "bin": { + "jsdocs": "bin/jsdocs" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -6848,6 +6960,14 @@ "node": ">=0.10.0" } }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -6869,6 +6989,14 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -6880,6 +7008,11 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -6972,6 +7105,52 @@ "tmpl": "1.0.5" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -7064,6 +7243,17 @@ "node": "*" } }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -8076,6 +8266,14 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -8253,6 +8451,14 @@ "node": ">=0.10.0" } }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dependencies": { + "lodash": "^4.17.21" + } + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -9094,6 +9300,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + }, "node_modules/uid-safe": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", @@ -9130,6 +9341,11 @@ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -9438,6 +9654,11 @@ } } }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index f92b013..dcd74e4 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "faker": "^5.5.3", "jest": "^29.7.0", "jest-fetch-mock": "^3.0.3", + "jsdoc": "^4.0.3", "jsonwebtoken": "^9.0.2", "moment-timezone": "^0.5.45", "mongodb": "^6.5.0", @@ -45,6 +46,7 @@ "@babel/node": "^7.23.9", "@babel/preset-env": "^7.24.3", "@faker-js/faker": "^8.4.1", - "@types/faker": "^6.6.9" + "@types/faker": "^6.6.9", + "jsdocs": "^0.0.1" } } diff --git a/src/services/communityQueueService.js b/src/services/communityQueueService.js index 261cc34..20e9067 100644 --- a/src/services/communityQueueService.js +++ b/src/services/communityQueueService.js @@ -1,3 +1,7 @@ +/** + * @module community/queue/service + */ + import { Post } from '../db/models/Post.js'; import { Comment } from '../db/models/Comment.js'; import { Community } from '../db/models/Community.js'; @@ -10,18 +14,13 @@ import { Community } from '../db/models/Community.js'; * @param {string} item_id - The UUID of the item to be objected. * @param {string} item_type - The type of the item. Can be either 'post' or 'comment'. * @param {string} objection_type - The type of the objection. Can be either 'reported', 'spammed', or 'removed'. - * @param {string} objected_by - The UUID of the user who is objecting the item. This is a reference to a User object. + * @param {string} objected_by - The user who is objecting the item. This user must be a moderator of the community. * @param {string} objection_type_value - The reason for the objection. Must be a valid reason based on the objection type. * @param {string} community_name - The name of the community where the item is posted. * * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a message indicating the success. If an error occurs, the object contains an 'err' property with the status code and error message. * * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. - * - * @example - * objectItem('123e4567-e89b-12d3-a456-426614174000', 'post', 'reported', '123e4567-e89b-12d3-a456-426614174000', 'Harassment', 'community1') - * .then(result => console.log(result)) - * .catch(err => console.error(err)); */ const objectItem = async (item_id, item_type, objection_type, objected_by, objection_type_value, community_name) => { @@ -107,6 +106,19 @@ const objectItem = async (item_id, item_type, objection_type, objected_by, objec } }; +/** + * Edits an item (post or comment) by updating its content in the database. + * + * @param {string} item_id - The UUID of the item to be edited. + * @param {string} item_type - The type of the item. Can be either 'post' or 'comment'. + * @param {string} new_content - The new content for the item. Must be a string. + * @param {Object} editing_user - The user who is editing the item. This user must be the author of the item. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a message indicating the success. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const editItem = async (item_id, item_type, new_content, editing_user) => { try { // Determine the model based on the item_type @@ -157,6 +169,20 @@ const editItem = async (item_id, item_type, new_content, editing_user) => { }; //////////////////////////////////////////////////////////////////////////// Handlers //////////////////////////////////////////////////////////////////////////// + +/** + * Handles an objection on an item (post or comment) by either approving or removing it. + * + * @param {string} item_id - The UUID of the item to handle the objection on. + * @param {string} item_type - The type of the item. Can be either 'post' or 'comment'. + * @param {string} objection_type - The type of the objection. Can be either 'reported', 'spammed', or 'removed'. + * @param {string} action - The action to take on the objection. Can be either 'approve' or 'remove'. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a message indicating the success. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const handleObjection = async (item_id, item_type, objection_type, action) => { try { // Determine the model based on the item_type @@ -220,6 +246,18 @@ const handleObjection = async (item_id, item_type, objection_type, action) => { } }; +/** + * Handles an edit on an item (post or comment) by either approving or removing it. + * + * @param {string} item_id - The UUID of the item to handle the edit on. + * @param {string} item_type - The type of the item. Can be either 'post' or 'comment'. + * @param {string} action - The action to take on the edit. Can be either 'approve' or 'remove'. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a message indicating the success. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const handleEdit = async (item_id, item_type, action) => { // Determine the model based on the item_type const Model = item_type === 'post' ? Post : Comment; @@ -267,6 +305,19 @@ const handleEdit = async (item_id, item_type, action) => { return { message: `Edit ${action}d successfully` }; }; +/** + * Handles an unmoderated item (post or comment) by either approving or removing it. + * + * @param {string} itemId - The UUID of the item to handle. + * @param {string} itemType - The type of the item. Can be either 'post' or 'comment'. + * @param {string} userId - The UUID of the user performing the action. + * @param {string} action - The action to take on the item. Can be either 'approve' or 'remove'. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a message indicating the success. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const handleUnmoderatedItem = async (itemId, itemType, userId, action) => { try { // Determine the model based on the item_type @@ -315,6 +366,22 @@ const handleUnmoderatedItem = async (itemId, itemType, userId, action) => { //////////////////////////////////////////////////////////////////////////// Pages //////////////////////////////////////////////////////////////////////////// +/** + * Fetches items (posts or comments) from a specified queue of a community. + * + * @param {string} time_filter - The order in which to return the items. Can be either 'newest first' or 'oldest first'. + * @param {string} posts_or_comments - The type of items to return. Can be either 'posts', 'comments', or 'posts and comments'. + * @param {string} queue_type - The type of queue from which to fetch the items. Can be either 'reported', 'removed', 'unmoderated' or 'edited'. + * @param {string} community_name - The name of the community from which to fetch the items. + * @param {Object} authenticated_user - The user who is fetching the items. This user must be a moderator of the community. + * @param {number} page - The page number to return in the pagination. + * @param {number} limit - The number of items to return per page. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains an 'items' property with the fetched items. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const getItemsFromQueue = async (time_filter, posts_or_comments, queue_type, community_name, authenticated_user, page, limit) => { try { // Validate the time_filter parameter. It should be either 'newest first' or 'oldest first'. diff --git a/src/services/communityScheduledPostsService.js b/src/services/communityScheduledPostsService.js index 6d0dce1..9e3f033 100644 --- a/src/services/communityScheduledPostsService.js +++ b/src/services/communityScheduledPostsService.js @@ -1,3 +1,7 @@ +/** + * @module community/scheduled-posts/service + */ + // TODO: Scheduled posts appear in the unmoderated queue. import { Post } from "../db/models/Post.js"; import { scheduledPost } from "../db/models/scheduledPosts.js"; @@ -13,6 +17,17 @@ import { getCommunityGeneralSettings } from "./communitySettingsService.js"; import schedule from "node-schedule"; +/** + * Saves a post for future scheduling. + * + * @param {Object} scheduling_details - The details for when the post should be scheduled. + * @param {Object} postInput - The input for the post. This object should contain the necessary attributes for a post. + * @param {Object} user - The user who is creating the post. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a 'saved_post_id' property with the id of the saved post. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ const savePostForScheduling = async (scheduling_details, postInput, user) => { // Check that the input to create the new post is valid. @@ -96,6 +111,16 @@ const savePostForScheduling = async (scheduling_details, postInput, user) => { return { saved_post_id: savedPost._id }; } +/** + * Posts a scheduled post immediately and removes it from the scheduled posts if it is not recurring. + * + * @param {string} post_id - The id of the scheduled post to post. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a 'successMessage' property with a success message. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const postScheduledPost = async (post_id) => { // Find the scheduled post with the given post id. @@ -137,6 +162,14 @@ const postScheduledPost = async (post_id) => { return { successMessage: `Post with title ${post.title} posted successfully on ${post.created_at}!` }; } +/** + * Retrieves all scheduled posts for a given community and separates them into recurring and non-recurring posts. + * + * @param {string} community_name - The name of the community for which to retrieve the scheduled posts. + * + * @returns {Promise} - A promise that resolves to an object. The object contains two properties: 'recurring_posts' and 'non_recurring_posts'. Each property is an array of posts. + */ + const getScheduledPosts = async (community_name) => { // Find all the scheduled posts in the database excluding the 'moderator_details' field. @@ -150,6 +183,17 @@ const getScheduledPosts = async (community_name) => { return { recurring_posts, non_recurring_posts }; } +/** + * Edits the description of a scheduled post. + * + * @param {string} post_id - The id of the scheduled post to edit. + * @param {string} new_description - The new description for the scheduled post. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains an 'edited_post' property with the edited post. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const editScheduledPost = async (post_id, new_description) => { try { // Get the post with the given id. @@ -179,6 +223,16 @@ const editScheduledPost = async (post_id, new_description) => { } } +/** + * Submits a scheduled post immediately and removes it from the scheduled posts if it is not recurring. + * + * @param {string} post_id - The id of the scheduled post to submit. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a 'message' property with a success message. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + // submitScheduledPost can only be called with an id of a post from those in the scheduledPosts table and that are non recurring. // it should delete the post from the scheduledPosts table and post it to the posts table. // it should also cancel the scheduling of the post using job.cancel() @@ -226,6 +280,16 @@ const submitScheduledPost = async (post_id) => { return { message: `Post with title ${post.title} posted successfully on ${post.created_at}!` }; } +/** + * Cancels a scheduled post and removes it from the scheduled posts. + * + * @param {string} post_id - The id of the scheduled post to cancel. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a 'message' property with a success message. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const cancelScheduledPost = async (post_id) => { // Find the scheduled post with the given post id. const scheduled_post = await scheduledPost.findById(post_id); diff --git a/src/services/communitySettingsService.js b/src/services/communitySettingsService.js index c9bd659..945aeee 100644 --- a/src/services/communitySettingsService.js +++ b/src/services/communitySettingsService.js @@ -1,3 +1,7 @@ +/** + * @module community/settings/service + */ + // Mod Tools --> Settings --> General Settings // Mod Tools --> Settings --> Posts and Comments // Mod Tools --> Moderation --> Content Controls @@ -20,6 +24,17 @@ import { CommunityPostsAndComments } from "../db/models/communityPostsAndComment //////////////////////////////////////////////////////////////////////// Get Settings ////////////////////////////////////////////////////////////// + +/** + * Fetches the general settings of a specified community. + * + * @param {string} community_name - The name of the community from which to fetch the general settings. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a 'general_settings' property with the fetched general settings. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const getCommunityGeneralSettings = async (community_name) => { // This could be due to a bug in the front-end code that incorrectly formats the community_name. if (typeof community_name !== 'string') { @@ -51,6 +66,16 @@ const getCommunityGeneralSettings = async (community_name) => { } }; +/** + * Fetches the content controls of a specified community. + * + * @param {string} community_name - The name of the community from which to fetch the content controls. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a 'content_controls' property with the fetched content controls. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const getCommunityContentControls = async (community_name) => { if (typeof community_name !== 'string') { return { err: { status: 400, message: 'Invalid arguments' } }; @@ -75,6 +100,16 @@ const getCommunityContentControls = async (community_name) => { } }; +/** + * Fetches the posts and comments of a specified community. + * + * @param {string} community_name - The name of the community from which to fetch the posts and comments. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains a 'posts_and_comments' property with the fetched posts and comments. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const getCommunityPostsAndComments = async (community_name) => { if (typeof community_name !== 'string') { return { err: { status: 400, message: 'Invalid arguments' } }; @@ -104,6 +139,17 @@ const getCommunityPostsAndComments = async (community_name) => { // These functions can be optimised by populating the settings attribute (exactly like in the get functions above) then accessing the settings attribute directly of the returned community from the query. // TODO: Update these functions after finishing the Community Appearance feature. +/** + * Changes the general settings of a specified community. + * + * @param {string} community_name - The name of the community for which to change the general settings. + * @param {Object} general_settings - The new general settings for the community. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains an 'updated_general_settings' property with the updated general settings. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const changeCommunityGeneralSettings = async ( community_name, general_settings @@ -141,6 +187,17 @@ const changeCommunityGeneralSettings = async ( } }; +/** + * Changes the content controls of a specified community. + * + * @param {string} community_name - The name of the community for which to change the content controls. + * @param {Object} content_controls - The new content controls for the community. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains an 'updated_content_controls' property with the updated content controls. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const changeCommunityContentControls = async ( community_name, content_controls @@ -172,6 +229,17 @@ const changeCommunityContentControls = async ( } }; +/** + * Changes the posts and comments of a specified community. + * + * @param {string} community_name - The name of the community for which to change the posts and comments. + * @param {Object} posts_and_comments - The new posts and comments for the community. This object can have 'posts' and 'comments' properties. + * + * @returns {Promise} - A promise that resolves to an object. If the function is successful, the object contains an 'updated_posts_and_comments' property with the updated posts and comments. If an error occurs, the object contains an 'err' property with the status code and error message. + * + * @throws {Object} - If an error occurs, an object is thrown with an 'err' property containing the status code and error message. + */ + const changeCommunityPostsAndComments = async ( community_name, posts_and_comments