From 76e2f56eb4dc9f241f315dd5ac14a4864446c892 Mon Sep 17 00:00:00 2001 From: rainbow napkin Date: Tue, 2 Sep 2025 06:48:32 -0400 Subject: [PATCH] Full JSDoc for src/schemas complete. --- src/schemas/channel/channelBanSchema.js | 7 + .../channel/channelPermissionSchema.js | 9 +- src/schemas/channel/channelSchema.js | 137 +++++++++++++++++- src/schemas/channel/chatSchema.js | 3 + 4 files changed, 152 insertions(+), 4 deletions(-) diff --git a/src/schemas/channel/channelBanSchema.js b/src/schemas/channel/channelBanSchema.js index 2eae5e2..a14b2aa 100644 --- a/src/schemas/channel/channelBanSchema.js +++ b/src/schemas/channel/channelBanSchema.js @@ -17,6 +17,9 @@ along with this program. If not, see .*/ //NPM Imports const {mongoose} = require('mongoose'); +/** + * DB Schema for Documents representing a user ban from a single channel + */ const channelBanSchema = new mongoose.Schema({ user: { type: mongoose.SchemaTypes.ObjectID, @@ -41,6 +44,10 @@ const channelBanSchema = new mongoose.Schema({ }); //methods +/** + * Calculates days until ban expiration + * @returns {Number} Days until the given ban expires + */ channelBanSchema.methods.getDaysUntilExpiration = function(){ //Get ban date const expirationDate = new Date(this.banDate); diff --git a/src/schemas/channel/channelPermissionSchema.js b/src/schemas/channel/channelPermissionSchema.js index 824b5e2..bdd709e 100644 --- a/src/schemas/channel/channelPermissionSchema.js +++ b/src/schemas/channel/channelPermissionSchema.js @@ -17,10 +17,17 @@ along with this program. If not, see .*/ //NPM Imports const {mongoose} = require('mongoose'); -//This originally belonged to the permissionSchema, but this avoids circular dependencies. +/** + * Rank Enum, lists all known permission ranks from lowest to highest. + * + * This originally belonged to the permissionSchema, but this avoids circular dependencies. + */ const rankEnum = ["anon", "user", "gold", "bot", "mod", "admin"]; //Since this is intended to be used as a child schema for multiple parent schemas, we won't export it as a model +/** + * DB Schema for Sub-Document representing permission structure for a single channel + */ const channelPermissionSchema = new mongoose.Schema({ manageChannel: { type: mongoose.SchemaTypes.String, diff --git a/src/schemas/channel/channelSchema.js b/src/schemas/channel/channelSchema.js index 75e8593..c3055ca 100644 --- a/src/schemas/channel/channelSchema.js +++ b/src/schemas/channel/channelSchema.js @@ -35,6 +35,9 @@ const chatSchema = require('./chatSchema'); //Utils const { exceptionHandler, errorHandler } = require('../../utils/loggerUtils'); +/** + * DB Schema for Documents containing de-hydrated representations of Canopy Stream/Chat Channels + */ const channelSchema = new mongoose.Schema({ id: { type: mongoose.SchemaTypes.Number, @@ -124,6 +127,9 @@ const channelSchema = new mongoose.Schema({ }); +/** + * Channel pre-save function. Ensures name requirements (for some reason, we should move that to the schema probably), kicks users after rank change, and handles housekeeping after adding tokes/emotes + */ channelSchema.pre('save', async function (next){ if(this.isModified("name")){ if(this.name.match(/^[a-z0-9_\-.]+$/i) == null){ @@ -131,6 +137,7 @@ channelSchema.pre('save', async function (next){ } } + //This entire block is just about finding users after rank-change and making sure they get kicked //Getting the affected user would be a million times easier elsewhere //But this ensures it happens every time channel rank gets changed no matter what if(this.isModified('rankList') && this.rankList != null){ @@ -227,6 +234,11 @@ channelSchema.pre('save', async function (next){ }); //statics +/** + * Registers a new channel to the DB + * @param {Object} channelObj - Channel Object from Browser to register + * @param {Mongoose.Document} ownerObj - DB Docuement representing user + */ channelSchema.statics.register = async function(channelObj, ownerObj){ const {name, description, thumbnail} = channelObj; @@ -258,6 +270,11 @@ channelSchema.statics.register = async function(channelObj, ownerObj){ } } +/** + * Generates Network-Friendly Browser-Digestable list of channels + * @param {Boolean} includeHidden - Whether or not to include hidden channels within the list + * @returns {Array} List of Network-Friendly Browser-Digestable Objects representing channels on the server + */ channelSchema.statics.getChannelList = async function(includeHidden = false){ const chanDB = await this.find({}); var chanGuide = []; @@ -280,9 +297,16 @@ channelSchema.statics.getChannelList = async function(includeHidden = false){ } //Middleware for rank checks -//Man, it would be really nice if express middleware actually supported async functions, you know, as if it where't still 2015 >:( -//Also holy shit, sharing a function between two middleware functions is a nightmare -//I'd rather just have this check chanField for '/c/' to handle channels in URL, fuck me this was obnoxious to write +/** + * Configurable Express Middleware for Per-Channel Endpoint Authorization + * + * Man, it would be really nice if express middleware actually supported async functions, you know, as if it where't still 2015 >:( + * Also holy shit, sharing a function between two middleware functions is a nightmare + * I'd rather just have this check chanField for '/c/' to handle channels in URL, fuck me this was obnoxious to write + * @param {String} - Permission to check against + * @param {String} - Name of channel to authorize against + * @returns {Function} Express middleware function with arguments injected into logic +*/ channelSchema.statics.reqPermCheck = function(perm, chanField = "chanName"){ return (req, res, next)=>{ try{ @@ -327,6 +351,9 @@ channelSchema.statics.reqPermCheck = function(perm, chanField = "chanName"){ } } +/** + * Schedulable Function for Processing and Deleting Expired Channel-level User Bans + */ channelSchema.statics.processExpiredBans = async function(){ const chanDB = await this.find({}); @@ -350,6 +377,11 @@ channelSchema.statics.processExpiredBans = async function(){ } //methods +/** + * Updates settings map for a given channel document + * @param {Map} settingsMap - Map of settings updates to apply against channel document + * @returns {Map} Map of all channel settings + */ channelSchema.methods.updateSettings = async function(settingsMap){ settingsMap.forEach((value, key) => { if(this.settings[key] == null){ @@ -364,6 +396,11 @@ channelSchema.methods.updateSettings = async function(settingsMap){ return this.settings; } +/** + * Crawls through channel rank and runs a callback against the requested user's rank sub-doc + * @param {Mongoose.Document} userDB - User DB Document to run the callback against + * @param {Function} cb - Callback Function to call against the given users rank sub-doc + */ channelSchema.methods.rankCrawl = async function(userDB,cb){ //Crawl through channel rank list //TODO: replace this with rank check function shared with setRank @@ -376,6 +413,12 @@ channelSchema.methods.rankCrawl = async function(userDB,cb){ }); } +/** + * Sets users rank by User Doc + * @param {Mongoose.Document} userDB - DB Document of user's channel rank to change + * @param {String} rank - Channel rank to set user to + * @returns {Array} Channel Rank List + */ channelSchema.methods.setRank = async function(userDB,rank){ //Create variable to store found ranks var foundRankIndex = null; @@ -409,6 +452,10 @@ channelSchema.methods.setRank = async function(userDB,rank){ return this.rankList; } +/** + * Generates Network-Friendly Browser-Digestable channel rank list + * @returns {Array} Network-Friendly Browser-Digestable channel rank list + */ channelSchema.methods.getRankList = async function(){ //Create an empty array to hold the user list const rankList = new Map() @@ -457,6 +504,11 @@ channelSchema.methods.getRankList = async function(){ return rankList; } +/** + * Gets channel rank by user document + * @param {Mongoose.Document} userDB - DB Document of User to pull Channel Rank of + * @returns {String} Channel rank of requested user + */ channelSchema.methods.getChannelRankByUserDoc = async function(userDB = null){ var foundRank = null; @@ -483,11 +535,22 @@ channelSchema.methods.getChannelRankByUserDoc = async function(userDB = null){ } } +/** + * Gets channel rank by username + * @param {String} user - Username of user to pull channel rank of + * @returns {String} Channel rank of requested user + */ channelSchema.methods.getChannelRank = async function(user){ const userDB = await userModel.findOne({user: user.user}); return await this.getChannelRankByUserDoc(userDB); } +/** + * Calculates a permission check against a specific channel permission for a given user by username + * @param {String} user - Username of user to check against + * @param {String} perm - Name of channel Permission to check against + * @returns {Boolean} Whether or not the given user passes the given channel perm check + */ channelSchema.methods.permCheck = async function (user, perm){ //Set userDB to null if we wheren't passed a real user if(user != null){ @@ -499,6 +562,12 @@ channelSchema.methods.permCheck = async function (user, perm){ return await this.permCheckByUserDoc(userDB, perm) } +/** + * Calculates a permission check against a specific channel permission for a given user by DB Document + * @param {Mongoose.Document} userDB - DB Document of user to check against + * @param {String} perm - Name of channel Permission to check against + * @returns {Boolean} Whether or not the given user passes the given channel perm check + */ channelSchema.methods.permCheckByUserDoc = async function(userDB, perm){ //Get site-wide rank as number, default to anon for anonymous users const rank = userDB ? permissionModel.rankToNum(userDB.rank) : permissionModel.rankToNum("anon"); @@ -516,6 +585,11 @@ channelSchema.methods.permCheckByUserDoc = async function(userDB, perm){ return (permCheck || overrideCheck); } +/** + * Generates channel-wide permission map for a given user by user doc + * @param {Mongoose.Document} userDB - DB Document representing a single user account + * @returns {Object} Object containing two maps, one for channel perms, another for site-wide perms + */ channelSchema.methods.getPermMapByUserDoc = async function(userDB){ //Grap site-wide permissions const sitePerms = await permissionModel.getPerms(); @@ -537,6 +611,11 @@ channelSchema.methods.getPermMapByUserDoc = async function(userDB){ }; } +/** + * Checks if a specific user has been issued a channel-specific ban by DB doc + * @param {Mongoose.Document} userDB - DB Document representing a single user account + * @returns {Object} Found ban, if one exists + */ channelSchema.methods.checkBanByUserDoc = async function(userDB){ var foundBan = null; @@ -565,6 +644,10 @@ channelSchema.methods.checkBanByUserDoc = async function(userDB){ return foundBan; } +/** + * Generates Network-Friendly Browser-Digestable list of channel emotes + * @returns {Array} Network-Friendly Browser-Digestable list of channel emotes + */ channelSchema.methods.getEmotes = function(){ //Create an empty array to hold our emote list const emoteList = []; @@ -583,6 +666,10 @@ channelSchema.methods.getEmotes = function(){ return emoteList; } +/** + * Generates Network-Friendly Browser-Digestable list of channel playlists + * @returns {Array} Network-Friendly Browser-Digestable list of channel playlists + */ channelSchema.methods.getPlaylists = function(){ //Create an empty array to hold our emote list const playlists = []; @@ -597,6 +684,10 @@ channelSchema.methods.getPlaylists = function(){ return playlists; } +/** + * Crawls through channel playlists, running a given callback function against each one + * @param {Function} cb - Callback function to run against channel playlists + */ channelSchema.methods.playlistCrawl = function(cb){ for(let listIndex in this.media.playlists){ //Grab the associated playlist @@ -607,6 +698,11 @@ channelSchema.methods.playlistCrawl = function(cb){ } } +/** + * Finds channel playlist by playlist name + * @param {String} name - name of given playlist to find + * @returns {Mongoose.Document} - Sub-Document representing a single playlist + */ channelSchema.methods.getPlaylistByName = function(name){ //Create null value to hold our found playlist let foundPlaylist = null; @@ -626,6 +722,10 @@ channelSchema.methods.getPlaylistByName = function(name){ return foundPlaylist; } +/** + * Deletes channel playlist by playlist name + * @param {String} name - name of given playlist to Delete + */ channelSchema.methods.deletePlaylistByName = async function(name){ //Find the playlist let playlist = this.getPlaylistByName(name); @@ -637,6 +737,10 @@ channelSchema.methods.deletePlaylistByName = async function(name){ await this.save(); } +/** + * Generates Network-Friendly Browser-Digestable list of Channel-Wide user bans + * @returns {Array} Network-Friendly Browser-Digestable list of Channel-Wide user bans + */ channelSchema.methods.getChanBans = async function(){ //Create an empty list to hold our found bans var banList = []; @@ -677,6 +781,12 @@ channelSchema.methods.getChanBans = async function(){ return banList; } +/** + * Issues channel-wide ban to user based on user DB document + * @param {Mongoose.Document} userDB - DB Document representing a single user account to ban + * @param {Number} expirationDays - Days until ban expiration + * @param {Boolean} banAlts - Whether or not to ban alts + */ channelSchema.methods.banByUserDoc = async function(userDB, expirationDays, banAlts){ //Throw a shitfit if the user doesn't exist if(userDB == null){ @@ -714,11 +824,23 @@ channelSchema.methods.banByUserDoc = async function(userDB, expirationDays, banA await this.save(); } +/** + * Syntatic sugar for banning users by username + * @param {String} user - Username of user to ban + * @param {Number} expirationDays - Days until ban expiration + * @param {Boolean} banAlts - Whether or not to ban alts + * @returns {Promise} promise from this.banByUserDoc + */ channelSchema.methods.ban = async function(user, expirationDays, banAlts){ const userDB = await userModel.find({user}); return await this.banByUserDoc(userDB, expirationDays, banAlts); } +/** + * Un-Bans user by DB Document + * @param {Mongoose.Document} userDB - DB Document representing a single user account to un-ban + * @returns {Mongoose.Document} Saved channel document + */ channelSchema.methods.unbanByUserDoc = async function(userDB){ //Throw a shitfit if the user doesn't exist if(userDB == null){ @@ -739,11 +861,20 @@ channelSchema.methods.unbanByUserDoc = async function(userDB){ return await this.save(); } +/** + * Syntatic sugar for un-banning by username + * @param {String} user - Username of user to un-ban + * @returns {Mongoose.Document} Saved channel document + */ channelSchema.methods.unban = async function(user){ const userDB = await userModel.find({user}); return await this.unbanByUserDoc(userDB); } +/** + * Nukes channel upon channel-admin request + * @param {String} confirm - Channel name to confirm deletion of channel + */ channelSchema.methods.nuke = async function(confirm){ if(confirm == "" || confirm == null){ throw loggerUtils.exceptionSmith("Empty Confirmation String!", "validation"); diff --git a/src/schemas/channel/chatSchema.js b/src/schemas/channel/chatSchema.js index e5ac423..537afd0 100644 --- a/src/schemas/channel/chatSchema.js +++ b/src/schemas/channel/chatSchema.js @@ -22,6 +22,9 @@ const linkSchema = new mongoose.Schema({ type: mongoose.SchemaTypes.String }); +/** + * DB Schema for documents representing a single chat message + */ const chatSchema = new mongoose.Schema({ user: { type: mongoose.SchemaTypes.String,