JSDoc for rc/schemas/tokebot & src/schemas/user complete.

This commit is contained in:
rainbow napkin 2025-09-01 04:53:04 -04:00
parent 7b8c44158f
commit 1d5c1037ab
5 changed files with 242 additions and 7 deletions

View file

@ -21,6 +21,9 @@ const {mongoose} = require('mongoose');
const defaultTokes = require("../../../defaultTokes.json"); const defaultTokes = require("../../../defaultTokes.json");
const server = require('../../server'); const server = require('../../server');
/**
* Mongoose Schema representing a toke command
*/
const tokeCommandSchema = new mongoose.Schema({ const tokeCommandSchema = new mongoose.Schema({
command:{ command:{
type: mongoose.SchemaTypes.String, type: mongoose.SchemaTypes.String,
@ -28,8 +31,10 @@ const tokeCommandSchema = new mongoose.Schema({
} }
}); });
/**
* Pre-Save middleware, ensures tokebot receives all new toke commands
*/
tokeCommandSchema.pre('save', async function (next){ tokeCommandSchema.pre('save', async function (next){
//if the command was changed //if the command was changed
if(this.isModified("command")){ if(this.isModified("command")){
//Get server tokebot object //Get server tokebot object
@ -44,6 +49,9 @@ tokeCommandSchema.pre('save', async function (next){
next(); next();
}); });
/**
* Pre-Delete middleware, ensures tokebot removes all old toke commands
*/
tokeCommandSchema.pre('deleteOne', {document: true}, async function (next){ tokeCommandSchema.pre('deleteOne', {document: true}, async function (next){
//Get server tokebot object (isn't this a fun dot crawler? Why hasn't anyone asked me to stop writing software yet?) //Get server tokebot object (isn't this a fun dot crawler? Why hasn't anyone asked me to stop writing software yet?)
const tokebot = server.channelManager.chatHandler.commandPreprocessor.tokebot; const tokebot = server.channelManager.chatHandler.commandPreprocessor.tokebot;
@ -55,6 +63,10 @@ tokeCommandSchema.pre('deleteOne', {document: true}, async function (next){
next(); next();
}); });
/**
* Pulls command strings from DB and reports back
* @returns {Array} Array of toke commands pulled from the DB
*/
tokeCommandSchema.statics.getCommandStrings = async function(){ tokeCommandSchema.statics.getCommandStrings = async function(){
//Get all toke commands in the DB //Get all toke commands in the DB
const tokeDB = await this.find({}); const tokeDB = await this.find({});
@ -71,6 +83,9 @@ tokeCommandSchema.statics.getCommandStrings = async function(){
return tokeArray; return tokeArray;
} }
/**
* Loads default tokes into the DB from flat file upon launch
*/
tokeCommandSchema.statics.loadDefaults = async function(){ tokeCommandSchema.statics.loadDefaults = async function(){
//Make sure registerToke function is happy //Make sure registerToke function is happy
const _this = this; const _this = this;

View file

@ -30,8 +30,14 @@ const {mongoose} = require('mongoose');
const hashUtil = require('../../utils/hashUtils'); const hashUtil = require('../../utils/hashUtils');
const mailUtils = require('../../utils/mailUtils'); const mailUtils = require('../../utils/mailUtils');
/**
* Email change token retention time
*/
const daysToExpire = 7; const daysToExpire = 7;
/**
* DB Schema for Document representing a single email change request
*/
const emailChangeSchema = new mongoose.Schema({ const emailChangeSchema = new mongoose.Schema({
user: { user: {
type: mongoose.SchemaTypes.ObjectID, type: mongoose.SchemaTypes.ObjectID,
@ -60,7 +66,9 @@ const emailChangeSchema = new mongoose.Schema({
}); });
//Presave function /**
* Pre-Save function, ensures IP's are hashed and previous requests are deleted upon request creation
*/
emailChangeSchema.pre('save', async function (next){ emailChangeSchema.pre('save', async function (next){
//If we're saving an ip //If we're saving an ip
if(this.isModified('ipHash')){ if(this.isModified('ipHash')){
@ -76,7 +84,9 @@ emailChangeSchema.pre('save', async function (next){
next(); next();
}); });
//statics /**
* Schedulable function for processing expired email change requests
*/
emailChangeSchema.statics.processExpiredRequests = async function(){ emailChangeSchema.statics.processExpiredRequests = async function(){
//Pull all requests from the DB //Pull all requests from the DB
//Tested finding request by date, but mongoose kept throwing casting errors. //Tested finding request by date, but mongoose kept throwing casting errors.
@ -96,7 +106,9 @@ emailChangeSchema.statics.processExpiredRequests = async function(){
} }
} }
//methods /**
* Consumes email change token, changing email address on a given user
*/
emailChangeSchema.methods.consume = async function(){ emailChangeSchema.methods.consume = async function(){
//Populate the user reference //Populate the user reference
await this.populate('user'); await this.populate('user');
@ -137,6 +149,10 @@ emailChangeSchema.methods.consume = async function(){
} }
/**
* Generates email change URL from a given token
* @returns {String} Email change URL generated from token
*/
emailChangeSchema.methods.getChangeURL = function(){ emailChangeSchema.methods.getChangeURL = function(){
//Check for default port based on protocol //Check for default port based on protocol
if((config.protocol == 'http' && config.port == 80) || (config.protocol == 'https' && config.port == 443 || config.proxied)){ if((config.protocol == 'http' && config.port == 80) || (config.protocol == 'https' && config.port == 443 || config.proxied)){
@ -148,6 +164,10 @@ emailChangeSchema.methods.getChangeURL = function(){
} }
} }
/**
* Calculates days until token expiration
* @returns {Number} Days until token expiration
*/
emailChangeSchema.methods.getDaysUntilExpiration = function(){ emailChangeSchema.methods.getDaysUntilExpiration = function(){
//Get request date //Get request date
const expirationDate = new Date(this.date); const expirationDate = new Date(this.date);

View file

@ -30,8 +30,14 @@ const {mongoose} = require('mongoose');
const hashUtil = require('../../utils/hashUtils.js'); const hashUtil = require('../../utils/hashUtils.js');
const loggerUtils = require('../../utils/loggerUtils.js') const loggerUtils = require('../../utils/loggerUtils.js')
/**
* Password reset token retention time
*/
const daysToExpire = 7; const daysToExpire = 7;
/**
* DB Schema for documents containing a single expiring password reset token
*/
const passwordResetSchema = new mongoose.Schema({ const passwordResetSchema = new mongoose.Schema({
user: { user: {
type: mongoose.SchemaTypes.ObjectID, type: mongoose.SchemaTypes.ObjectID,
@ -56,7 +62,9 @@ const passwordResetSchema = new mongoose.Schema({
}); });
//Presave function /**
* Pre-save function, ensures IP's are hashed before saving
*/
passwordResetSchema.pre('save', async function (next){ passwordResetSchema.pre('save', async function (next){
//If we're saving an ip //If we're saving an ip
if(this.isModified('ipHash')){ if(this.isModified('ipHash')){
@ -67,7 +75,9 @@ passwordResetSchema.pre('save', async function (next){
next(); next();
}); });
//statics /**
* Schedulable function for processing expired reset requests
*/
passwordResetSchema.statics.processExpiredRequests = async function(){ passwordResetSchema.statics.processExpiredRequests = async function(){
//Pull all requests from the DB //Pull all requests from the DB
//Tested finding request by date, but mongoose kept throwing casting errors. //Tested finding request by date, but mongoose kept throwing casting errors.
@ -88,6 +98,11 @@ passwordResetSchema.statics.processExpiredRequests = async function(){
} }
//methods //methods
/**
* Resets password and consumes token
* @param {String} pass - New password to set
* @param {String} confirmPass - Confirmation String to ensure new pass is correct
*/
passwordResetSchema.methods.consume = async function(pass, confirmPass){ passwordResetSchema.methods.consume = async function(pass, confirmPass){
//Check confirmation pass //Check confirmation pass
if(pass != confirmPass){ if(pass != confirmPass){
@ -110,6 +125,10 @@ passwordResetSchema.methods.consume = async function(pass, confirmPass){
await this.deleteOne(); await this.deleteOne();
} }
/**
* Generates password reset URL off of the token object
* @returns {String} Reset URL
*/
passwordResetSchema.methods.getResetURL = function(){ passwordResetSchema.methods.getResetURL = function(){
//Check for default port based on protocol //Check for default port based on protocol
if((config.protocol == 'http' && config.port == 80) || (config.protocol == 'https' && config.port == 443) || config.proxied){ if((config.protocol == 'http' && config.port == 80) || (config.protocol == 'https' && config.port == 443) || config.proxied){
@ -121,6 +140,10 @@ passwordResetSchema.methods.getResetURL = function(){
} }
} }
/**
* Returns number of days until token expiration
* @returns {Number} Number of days until token expiration
*/
passwordResetSchema.methods.getDaysUntilExpiration = function(){ passwordResetSchema.methods.getDaysUntilExpiration = function(){
//Get request date //Get request date
const expirationDate = new Date(this.date); const expirationDate = new Date(this.date);

View file

@ -22,6 +22,9 @@ const hashUtil = require('../../utils/hashUtils.js');
const {userModel} = require('./userSchema.js'); const {userModel} = require('./userSchema.js');
const loggerUtils = require('../../utils/loggerUtils.js'); const loggerUtils = require('../../utils/loggerUtils.js');
/**
* DB Schema for Documents representing a single user's ban
*/
const userBanSchema = new mongoose.Schema({ const userBanSchema = new mongoose.Schema({
user: { user: {
type: mongoose.SchemaTypes.ObjectID, type: mongoose.SchemaTypes.ObjectID,
@ -64,6 +67,11 @@ const userBanSchema = new mongoose.Schema({
} }
}); });
/**
* Checks ban by IP
* @param {String} ip - IP Address check for bans
* @returns {Mongoose.Document} Found ban Document if one exists.
*/
userBanSchema.statics.checkBanByIP = async function(ip){ userBanSchema.statics.checkBanByIP = async function(ip){
//Get hash of ip //Get hash of ip
const ipHash = hashUtil.hashIP(ip); const ipHash = hashUtil.hashIP(ip);
@ -127,6 +135,11 @@ userBanSchema.statics.checkBanByIP = async function(ip){
return foundBan; return foundBan;
} }
/**
* Checks for bans by user DB doc
* @param {Mongoose.Document} userDB - User Doc to check
* @returns {Mongoose.Document} Found ban document for given user doc
*/
userBanSchema.statics.checkBanByUserDoc = async function(userDB){ userBanSchema.statics.checkBanByUserDoc = async function(userDB){
const banDB = await this.find({}); const banDB = await this.find({});
var foundBan = null; var foundBan = null;
@ -156,11 +169,21 @@ userBanSchema.statics.checkBanByUserDoc = async function(userDB){
return foundBan; return foundBan;
} }
/**
* Checks for ban by username
* @param {String} user - User to check for bans
* @returns {Mongoose.Document} Found User Ban DB Document
*/
userBanSchema.statics.checkBan = async function(user){ userBanSchema.statics.checkBan = async function(user){
const userDB = await userModel.findOne({user: user.user}); const userDB = await userModel.findOne({user: user.user});
return this.checkBanByUserDoc(userDB); return this.checkBanByUserDoc(userDB);
} }
/**
* Looks through processed bans by user
* @param {String} user - user to check against for bans
* @returns {Mongoose.Document} Spent User Ban Document
*/
userBanSchema.statics.checkProcessedBans = async function(user){ userBanSchema.statics.checkProcessedBans = async function(user){
//Pull banlist and create empty variable to hold any found ban //Pull banlist and create empty variable to hold any found ban
const banDB = await this.find({}); const banDB = await this.find({});
@ -182,6 +205,14 @@ userBanSchema.statics.checkProcessedBans = async function(user){
return foundBan; return foundBan;
} }
/**
* Bans a given user by their user Document
* @param {Mongoose.Document} userDB - DB Doc of the user to ban
* @param {Boolean} permanent - Whether or not it's permanant
* @param {Number} expirationDays - Days to expire
* @param {Boolean} ipBan - Whether or not we're banning by IP
* @returns {Mongoose.Document} A freshly created User Ban DB Document :)
*/
userBanSchema.statics.banByUserDoc = async function(userDB, permanent, expirationDays, ipBan = false){ userBanSchema.statics.banByUserDoc = async function(userDB, permanent, expirationDays, ipBan = false){
//Prevent missing users //Prevent missing users
if(userDB == null){ if(userDB == null){
@ -258,11 +289,24 @@ userBanSchema.statics.banByUserDoc = async function(userDB, permanent, expiratio
} }
} }
/**
* Bans user by username
* @param {String} user - Username of user to ban
* @param {Boolean} permanent - Whether or not it's permanant
* @param {Number} expirationDays - Days to expire
* @param {Boolean} ipBan - Whether or not we're banning by IP
* @returns {Mongoose.Document} A freshly created User Ban DB Document :)
*/
userBanSchema.statics.ban = async function(user, permanent, expirationDays, ipBan){ userBanSchema.statics.ban = async function(user, permanent, expirationDays, ipBan){
const userDB = await userModel.findOne({user: user.user}); const userDB = await userModel.findOne({user: user.user});
return this.banByUserDoc(userDB, permanent, expirationDays, ipBan); return this.banByUserDoc(userDB, permanent, expirationDays, ipBan);
} }
/**
* Unbans users by user doc
* @param {Mongoose.Document} userDB - User DB Document to unban
* @returns {Mongoose.Document} Old, deleted ban document
*/
userBanSchema.statics.unbanByUserDoc = async function(userDB){ userBanSchema.statics.unbanByUserDoc = async function(userDB){
//Prevent missing users //Prevent missing users
@ -281,6 +325,12 @@ userBanSchema.statics.unbanByUserDoc = async function(userDB){
return oldBan; return oldBan;
} }
/**
* Unban deleted user
* Can't bring back accounts, but will re-allow re-use of old usernames, and new accounts/connections from banned IP's
* @param {String} user - Username of deleted account to unban
* @returns {Mongoose.Document} Old, deleted ban document
*/
userBanSchema.statics.unbanDeleted = async function(user){ userBanSchema.statics.unbanDeleted = async function(user){
const banDB = await this.checkProcessedBans(user); const banDB = await this.checkProcessedBans(user);
@ -292,6 +342,11 @@ userBanSchema.statics.unbanDeleted = async function(user){
return oldBan; return oldBan;
} }
/**
* Unbans user by username
* @param {String} user - Username of user to unban
* @returns Old, deleted ban document
*/
userBanSchema.statics.unban = async function(user){ userBanSchema.statics.unban = async function(user){
//Find user in DB //Find user in DB
const userDB = await userModel.findOne({user: user.user}); const userDB = await userModel.findOne({user: user.user});
@ -306,6 +361,10 @@ userBanSchema.statics.unban = async function(user){
} }
} }
/**
* Generates Network-Friendly Browser-Digestable list of bans for the admin panel
* @returns {Object} Network-Friendly Browser-Digestable list of bans for the admin panel
*/
userBanSchema.statics.getBans = async function(){ userBanSchema.statics.getBans = async function(){
//Get the ban, populating users and alts //Get the ban, populating users and alts
const banDB = await this.find({}).populate('user').populate('alts'); const banDB = await this.find({}).populate('user').populate('alts');
@ -352,6 +411,9 @@ userBanSchema.statics.getBans = async function(){
return bans; return bans;
} }
/**
* Scheduable function for processing expired user bans
*/
userBanSchema.statics.processExpiredBans = async function(){ userBanSchema.statics.processExpiredBans = async function(){
//Channel ban expirations may vary so there's no way to search for expired bans //Channel ban expirations may vary so there's no way to search for expired bans
const banDB = await this.find({}); const banDB = await this.find({});
@ -402,6 +464,10 @@ userBanSchema.statics.processExpiredBans = async function(){
} }
//methods //methods
/**
* Calculates days until ban expiration
* @returns {Number} Days until ban expiration
*/
userBanSchema.methods.getDaysUntilExpiration = function(){ userBanSchema.methods.getDaysUntilExpiration = function(){
//Get ban date //Get ban date
const expirationDate = new Date(this.banDate); const expirationDate = new Date(this.banDate);

View file

@ -33,6 +33,9 @@ const mailUtil = require('../../utils/mailUtils');
const loggerUtils = require('../../utils/loggerUtils') const loggerUtils = require('../../utils/loggerUtils')
/**
* Mongoose Schema for a document representing a single canopy user
*/
const userSchema = new mongoose.Schema({ const userSchema = new mongoose.Schema({
id: { id: {
type: mongoose.SchemaTypes.Number, type: mongoose.SchemaTypes.Number,
@ -147,6 +150,9 @@ const userSchema = new mongoose.Schema({
}); });
//This is one of those places where you really DON'T want to use an arrow function over an anonymous one! //This is one of those places where you really DON'T want to use an arrow function over an anonymous one!
/**
* Pre-Save function for user document, handles password hashing, flair updates, emote refreshes, and kills sessions upon rank change
*/
userSchema.pre('save', async function (next){ userSchema.pre('save', async function (next){
//If the password was changed //If the password was changed
@ -190,7 +196,9 @@ userSchema.pre('save', async function (next){
next(); next();
}); });
//post-delete function (document not query) /**
* Pre-Delete function for user accounts, drops connections and rips it self out from alt accounts
*/
userSchema.post('deleteOne', {document: true}, async function (){ userSchema.post('deleteOne', {document: true}, async function (){
//Kill any active sessions //Kill any active sessions
await this.killAllSessions("If you're seeing this, your account has been deleted. So long, and thanks for all the fish! <3"); await this.killAllSessions("If you're seeing this, your account has been deleted. So long, and thanks for all the fish! <3");
@ -212,6 +220,11 @@ userSchema.post('deleteOne', {document: true}, async function (){
}); });
//statics //statics
/**
* Registers a new user account with given information
* @param {Object} userObj - Object representing user to register, generated by the client
* @param {String} ip - IP Address of connection registering the account
*/
userSchema.statics.register = async function(userObj, ip){ userSchema.statics.register = async function(userObj, ip){
//Pull values from user object //Pull values from user object
const {user, pass, passConfirm, email} = userObj; const {user, pass, passConfirm, email} = userObj;
@ -246,6 +259,13 @@ userSchema.statics.register = async function(userObj, ip){
} }
} }
/**
* Authenticates a username and password pair
* @param {String} user - Username of account to login as
* @param {String} pass - Password to authenticat account
* @param {String} failLine - Line to paste into custom error upon login failure
* @returns {Mongoose.Document} - User DB Document upon success
*/
userSchema.statics.authenticate = async function(user, pass, failLine = "Bad Username or Password."){ userSchema.statics.authenticate = async function(user, pass, failLine = "Bad Username or Password."){
//check for missing pass //check for missing pass
if(!user || !pass){ if(!user || !pass){
@ -274,6 +294,12 @@ userSchema.statics.authenticate = async function(user, pass, failLine = "Bad Use
} }
} }
/**
* Gets profile by username
* @param {String} user - name of user to find
* @param {Boolean} includeEmail - Whether or not to include email in the final result
* @returns {Object} A network-friendly browser-digestable Object representing a single user profile
*/
userSchema.statics.findProfile = async function(user, includeEmail = false){ userSchema.statics.findProfile = async function(user, includeEmail = false){
//Catch null users //Catch null users
if(user == null || user.user == null){ if(user == null || user.user == null){
@ -309,6 +335,10 @@ userSchema.statics.findProfile = async function(user, includeEmail = false){
} }
/**
* Tattoos a single toke callout to all the users within it
* @param {Map} tokemap - Map containing list of users and the toke command they used to join the toke
*/
userSchema.statics.tattooToke = function(tokemap){ userSchema.statics.tattooToke = function(tokemap){
//For each toke, asynchronously: //For each toke, asynchronously:
tokemap.forEach(async (toke, user) => { tokemap.forEach(async (toke, user) => {
@ -345,6 +375,11 @@ userSchema.statics.tattooToke = function(tokemap){
}); });
} }
/**
* Acquires a list of the entire userbase
* @param {Boolean} fullList - Determines whether or not we're listing rank and email
* @returns {Array} Array of objects containing user metadata
*/
userSchema.statics.getUserList = async function(fullList = false){ userSchema.statics.getUserList = async function(fullList = false){
var userList = []; var userList = [];
//Get all of our users //Get all of our users
@ -379,6 +414,9 @@ userSchema.statics.getUserList = async function(fullList = false){
return userList; return userList;
} }
/**
* Process and Deletes Aged IP Records
*/
userSchema.statics.processAgedIPRecords = async function(){ userSchema.statics.processAgedIPRecords = async function(){
//Pull full userlist //Pull full userlist
const users = await this.find({}); const users = await this.find({});
@ -408,10 +446,19 @@ userSchema.statics.processAgedIPRecords = async function(){
//methods //methods
/**
* Checks password against a user document
* @param {String} pass - Password to authenticate
* @returns {Boolean} True if authenticated
*/
userSchema.methods.checkPass = function(pass){ userSchema.methods.checkPass = function(pass){
return hashUtil.comparePassword(pass, this.pass) return hashUtil.comparePassword(pass, this.pass)
} }
/**
* Lists authenticated sessions for a given user document
* @returns {Promise} Promise containing an array of active user sessions for a given user
*/
userSchema.methods.getAuthenticatedSessions = async function(){ userSchema.methods.getAuthenticatedSessions = async function(){
var returnArr = []; var returnArr = [];
@ -442,6 +489,11 @@ userSchema.methods.getAuthenticatedSessions = async function(){
} }
/**
* Generates a network-friendly browser-digestable profile object for a sepcific user document
* @param {Boolean} includeEmail - Whether or not to include the email address in the complete profile object
* @returns {Object} Network-Friendly Browser-Digestable object containing profile metadata
*/
userSchema.methods.getProfile = function(includeEmail = false){ userSchema.methods.getProfile = function(includeEmail = false){
//Create profile hashtable //Create profile hashtable
const profile = { const profile = {
@ -465,6 +517,10 @@ userSchema.methods.getProfile = function(includeEmail = false){
return profile; return profile;
} }
/**
* Gets list of profiles of alt accounts related to the given user document
* @returns {Array} List of alternate profiles
*/
userSchema.methods.getAltProfiles = async function(){ userSchema.methods.getAltProfiles = async function(){
//Create an empty list to hold alt profiles //Create an empty list to hold alt profiles
const profileList = []; const profileList = [];
@ -482,6 +538,11 @@ userSchema.methods.getAltProfiles = async function(){
return profileList; return profileList;
} }
/**
* Sets flair for current user documetn
* @param {String} flair - flair to set
* @returns {Mongoose.Document} returns found flair document from DB
*/
userSchema.methods.setFlair = async function(flair){ userSchema.methods.setFlair = async function(flair){
//Find flair by name //Find flair by name
const flairDB = await flairModel.findOne({name: flair}); const flairDB = await flairModel.findOne({name: flair});
@ -493,6 +554,10 @@ userSchema.methods.setFlair = async function(flair){
return flairDB; return flairDB;
} }
/**
* Gets number of tokes for a given user document
* @returns {Number} Number of tokes recorded for the given user document
*/
userSchema.methods.getTokeCount = function(){ userSchema.methods.getTokeCount = function(){
//Set tokeCount to 0 //Set tokeCount to 0
var tokeCount = 0; var tokeCount = 0;
@ -507,6 +572,10 @@ userSchema.methods.getTokeCount = function(){
return tokeCount; return tokeCount;
} }
/**
* Gets number of emotes for a given user document
* @returns {Array} Array of objects representing emotes for the given user document
*/
userSchema.methods.getEmotes = function(){ userSchema.methods.getEmotes = function(){
//Create an empty array to hold our emote list //Create an empty array to hold our emote list
const emoteList = []; const emoteList = [];
@ -525,6 +594,10 @@ userSchema.methods.getEmotes = function(){
return emoteList; return emoteList;
} }
/**
* Deletes an emote from the user Document
* @param {String} name - Name of emote to delete
*/
userSchema.methods.deleteEmote = async function(name){ userSchema.methods.deleteEmote = async function(name){
//Get index by emote name //Get index by emote name
const emoteIndex = this.emotes.findIndex(checkName); const emoteIndex = this.emotes.findIndex(checkName);
@ -541,6 +614,10 @@ userSchema.methods.deleteEmote = async function(name){
} }
} }
/**
* Gets list of user playlists
* @returns {Array} Array of objects represnting a playlist containing media objects
*/
userSchema.methods.getPlaylists = function(){ userSchema.methods.getPlaylists = function(){
//Create an empty array to hold our emote list //Create an empty array to hold our emote list
const playlists = []; const playlists = [];
@ -555,6 +632,10 @@ userSchema.methods.getPlaylists = function(){
return playlists; return playlists;
} }
/**
* Iterates through user playlists and calls a given callback function against them
* @param {Function} cb - Callback function to call against user playlists
*/
userSchema.methods.playlistCrawl = function(cb){ userSchema.methods.playlistCrawl = function(cb){
for(let listIndex in this.playlists){ for(let listIndex in this.playlists){
//Grab the associated playlist //Grab the associated playlist
@ -565,6 +646,11 @@ userSchema.methods.playlistCrawl = function(cb){
} }
} }
/**
* Returns playlist by name
* @param {String} name - Playlist to get by name
* @returns {Object} Object representing the requested playlist
*/
userSchema.methods.getPlaylistByName = function(name){ userSchema.methods.getPlaylistByName = function(name){
//Create null value to hold our found playlist //Create null value to hold our found playlist
let foundPlaylist = null; let foundPlaylist = null;
@ -584,6 +670,10 @@ userSchema.methods.getPlaylistByName = function(name){
return foundPlaylist; return foundPlaylist;
} }
/**
* Deletes a playlist from the user document by name
* @param {String} name - Name of playlist to delete
*/
userSchema.methods.deletePlaylistByName = async function(name){ userSchema.methods.deletePlaylistByName = async function(name){
//Find the playlist //Find the playlist
const playlist = this.getPlaylistByName(name); const playlist = this.getPlaylistByName(name);
@ -595,6 +685,10 @@ userSchema.methods.deletePlaylistByName = async function(name){
await this.save(); await this.save();
} }
/**
* Salts, Hashes and Tattoo's IP address to user document in a privacy respecting manner
* @param {String} ip - Plaintext IP Address to Salt, Hash and Tattoo
*/
userSchema.methods.tattooIPRecord = async function(ip){ userSchema.methods.tattooIPRecord = async function(ip){
//Hash the users ip //Hash the users ip
const ipHash = hashUtil.hashIP(ip); const ipHash = hashUtil.hashIP(ip);
@ -666,6 +760,10 @@ userSchema.methods.tattooIPRecord = async function(ip){
} }
//note: if you gotta call this from a request authenticated by it's user, make sure to kill that session first! //note: if you gotta call this from a request authenticated by it's user, make sure to kill that session first!
/**
* Kills all sessions for a given user
* @param {String} reason - Reason to kill user sessions
*/
userSchema.methods.killAllSessions = async function(reason = "A full log-out from all devices was requested for your account."){ userSchema.methods.killAllSessions = async function(reason = "A full log-out from all devices was requested for your account."){
//get authenticated sessions //get authenticated sessions
var sessions = await this.getAuthenticatedSessions(); var sessions = await this.getAuthenticatedSessions();
@ -679,6 +777,10 @@ userSchema.methods.killAllSessions = async function(reason = "A full log-out fro
server.channelManager.kickConnections(this.user, reason); server.channelManager.kickConnections(this.user, reason);
} }
/**
* Changes password for a given user document
* @param {Object} passChange - passChange object handed down from Browser
*/
userSchema.methods.changePassword = async function(passChange){ userSchema.methods.changePassword = async function(passChange){
if(this.checkPass(passChange.oldPass)){ if(this.checkPass(passChange.oldPass)){
if(passChange.newPass == passChange.confirmPass){ if(passChange.newPass == passChange.confirmPass){
@ -701,6 +803,11 @@ userSchema.methods.changePassword = async function(passChange){
} }
/**
* Checks another user document against this one to see if they're alts
* @param {Mongoose.Document} userDB - User document to check for alts against
* @returns {Boolean} True if alt
*/
userSchema.methods.altCheck = async function(userDB){ userSchema.methods.altCheck = async function(userDB){
//Found alt flag //Found alt flag
let foundAlt = false; let foundAlt = false;
@ -716,6 +823,10 @@ userSchema.methods.altCheck = async function(userDB){
return foundAlt; return foundAlt;
} }
/**
* Nukes user account from the face of the planet upon said user's request
* @param {String} pass - Password to authenticate against before deleting
*/
userSchema.methods.nuke = async function(pass){ userSchema.methods.nuke = async function(pass){
//Check we have a confirmation password //Check we have a confirmation password
if(pass == "" || pass == null){ if(pass == "" || pass == null){