diff --git a/src/app/channel/activeChannel.js b/src/app/channel/activeChannel.js index 18d059e..a465b06 100644 --- a/src/app/channel/activeChannel.js +++ b/src/app/channel/activeChannel.js @@ -106,7 +106,8 @@ class activeChannel{ "Greetings, %UNAME%.", "Sup, %UNAME%.", "I AM THE GOD OF HELLFIRE, AND I BRING YOU: %UNAME%!", - "A wild %UNAME% has appeared!" + "A wild %UNAME% has appeared!", + "OH MY FUCKING GOD HOLY SHIT IT'S %UNAME%!!!", ], leave: [ "%UNAME% left.", @@ -134,7 +135,6 @@ class activeChannel{ "That'll do, %UNAME%." ] } - } @@ -150,6 +150,8 @@ class activeChannel{ var userObj = this.userList.get(userDB.user); //get channel rank for current user const chanRank = await chanDB.getChannelRankByUserDoc(userDB); + //Keep track of whether or not user has connected to this channel on another tab/device yet + let first = false; //If user is already connected if(userObj){ @@ -161,6 +163,8 @@ class activeChannel{ await userDB.populate('flair'); //Set user object userObj = new connectedUser(userDB, chanRank, this, socket); + //Throw first flag + first = true; } //Set user entry in userlist @@ -175,7 +179,7 @@ class activeChannel{ this.webRTCHandler.defineListeners(socket); //Hand off the connection initiation to it's user object - const activeUser = await userObj.handleConnection(userDB, chanDB, socket) + const activeUser = await userObj.handleConnection(userDB, chanDB, socket, first) //Send out the userlist this.broadcastUserList(socket.chan); @@ -267,7 +271,7 @@ class activeChannel{ const activeList = leaving ? this.userAnnouncements.leave : this.userAnnouncements.join; //Randomly yoink the applicable message const msg = activeList[Math.floor(Math.random() * activeList.length)]; - + //Replace %UNAME% placeholder with users name and broadcast the welcome wagon this.server.chatHandler.relayChat(user, "", 0, msg.replace("%UNAME%", user), "serverwhisper", this.name, []); } } diff --git a/src/app/channel/connectedUser.js b/src/app/channel/connectedUser.js index b70e63a..d0b09ae 100644 --- a/src/app/channel/connectedUser.js +++ b/src/app/channel/connectedUser.js @@ -96,11 +96,12 @@ class connectedUser{ * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access * @param {Socket} socket - Requesting Socket + * @param {Boolean} first - thrown true if this is the socket for this user on this channel * @returns {activeUser} active user object generated by the new connection */ - async handleConnection(userDB, chanDB, socket){ + async handleConnection(userDB, chanDB, socket, first){ //send metadata to client - this.sendClientMetadata(); + this.sendClientMetadata(undefined, undefined, first); //Send out emotes this.sendSiteEmotes(); @@ -122,7 +123,6 @@ class connectedUser{ await userDB.tattooIPRecord(socket.handshake.address); } - //Return active user object for use by activeChannel and channelManager objects return this; } @@ -179,8 +179,9 @@ class connectedUser{ * Sends glut of required initial metadata to the client upon a new connection * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access + * @param {Boolean} welcome - Whether or not to throw welcome wagon, ensures we dont welcome before the metadata is sent */ - async sendClientMetadata(userDB, chanDB){ + async sendClientMetadata(userDB, chanDB, welcome){ //Get flairList from DB and setup flairList array const flairListDB = await flairModel.find({}); var flairList = []; @@ -238,8 +239,11 @@ class connectedUser{ //Send off the metadata to our user's clients this.emit("clientMetadata", {user: userObj, flairList, queueLock, chatBuffer, streamType: chanDB.settings.streamType}); - //Broadcast the welcome wagon - this.channel.welcomeWagon(userDB.user); + //If we where told to welcome the user + if(welcome){ + //Broadcast the welcome wagon + this.channel.welcomeWagon(userDB.user); + } } /** diff --git a/src/app/channel/media/queue.js b/src/app/channel/media/queue.js index f74b0f0..b6871f2 100644 --- a/src/app/channel/media/queue.js +++ b/src/app/channel/media/queue.js @@ -518,30 +518,7 @@ class queue{ */ async getArchive(socket, data){ try{ - //If we get an invalid start date - if(typeof data.startDate != "number" || data.startDate < 0){ - //Bitch, moan, an' complain! - loggerUtils.socketErrorHandler(socket, "Invalid Start Date!", "validation"); - //Yeetus-Deletus bitch - return; - } - //If we get an invalid start date - if(typeof data.endDate != "number" || data.endDate < 0){ - //Bitch, moan, an' complain! - loggerUtils.socketErrorHandler(socket, "Invalid End Date!", "validation"); - //Yeetus-Deletus bitch - return; - } - - //If our startDate isn't before our endDate - if(data.startDate >= data.endDate){ - //Bitch, moan, an' complain! - loggerUtils.socketErrorHandler(socket, "Invalid Date Range!", "validation"); - //Yeetus-Deletus bitch - return; - } - //Get the current channel from the database const chanDB = await channelModel.findOne({name: socket.chan}); @@ -551,12 +528,86 @@ class queue{ return; } - //Create new date objects to represent range of data requested - const startDate = new Date(data.startDate); - const endDate = new Date(data.endDate); + let startDate = undefined; + let endDate = undefined; + let title = undefined; + let url = undefined - //Grab archives from given range, and send them back to the requesting socket - socket.emit("archive", {archive: await this.prepArchive(startDate, endDate)}); + //If we where supplied with a start date + if(data.startDate != null){ + //If we get an invalid start date + if((typeof data.startDate != "number" || data.startDate < 0)){ + //Bitch, moan, an' complain! + loggerUtils.socketErrorHandler(socket, "Invalid Start Date!", "validation"); + //Yeetus-Deletus bitch + return; + } + + + //Store validated start date as new date object + startDate = new Date(data.startDate); + } + + if(data.endDate != null){ + //If we get an invalid start date + if((typeof data.endDate != "number" || data.endDate < 0)){ + //Bitch, moan, an' complain! + loggerUtils.socketErrorHandler(socket, "Invalid End Date!", "validation"); + //Yeetus-Deletus bitch + return; + } + + //If our startDate isn't before our endDate + if(data.startDate != null && data.startDate >= data.endDate){ + //Bitch, moan, an' complain! + loggerUtils.socketErrorHandler(socket, "Invalid Date Range!", "validation"); + //Yeetus-Deletus bitch + return; + } + + //Store validated endDate as new date object + endDate = new Date(data.endDate); + } + + + //If we have a valid title + if(data.title != null && data.title != ''){ + //If the title is too long + if(!validator.isLength(data.title, {max:30})){ + //Bitch, moan, complain... + loggerUtils.socketErrorHandler(socket, "Title too long!", "validation"); + //and ignore it! + return; + } + + //Sanatize, trim, and keep the title + title = validator.escape(validator.trim(data.title)); + } + + //If we were given a URL + if(data.url != null && data.url != ''){ + //Set URL + url = data.url; + + //If we were given a bad URL + if(!validator.isURL(url,{require_valid_protocol: true})){ + //Attempt to fix the situation by encoding it + url = encodeURI(url); + + //If it's still bad + if(!validator.isURL(url,{require_valid_protocol: true})){ + //Bitch, moan, complain... + loggerUtils.socketErrorHandler(socket, "Bad URL!", "validation"); + //and ignore it! + return; + } + } + } + + + + //Grab archives from given range, and send them back to the requesting socket, providing result as search result if search was requested + socket.emit(data.search ? "archiveSearch" : "archive", {archive: await this.prepArchive(startDate, endDate, title, url)}); }catch(err){ return loggerUtils.socketExceptionHandler(socket, err); } @@ -1903,12 +1954,20 @@ class queue{ } } - async prepArchive(startDate, endDate = new Date()){ + /** + * Preps archive for network transmission to clients + * @param {Date} startDate - Start date to pass to archive query + * @param {Date} endDate - end date to pass to archive query + * @param {String} title - title to search through archive for + * @param {String} url - URL to pass to archive query + * @returns Array of archived media objects prepped for network transmission. + */ + async prepArchive(startDate, endDate = new Date(), title, url){ //Define array to hold prepped archive objects const preppedArchive = []; //Get archive since yesterday - const archive = await this.queryArchive(startDate, endDate); + const archive = await this.queryArchive(startDate, endDate, url); //Iterate through the channel archive backwards to save time for(let mediaIndex = archive.length - 1; mediaIndex >= 0; mediaIndex--){ @@ -1921,8 +1980,11 @@ class queue{ media.earlyEnd = null; } - //Add it to the temporary preppd archive array as if it where part of the actual schedule map - preppedArchive.unshift([media.startTime, media]); + //If requested title is unspecified or was found in the in the media's title + if((title == null || title == '') || media.title.includes(title)){ + //Add it to the temporary preppd archive array as if it where part of the actual schedule map + preppedArchive.unshift([media.startTime, media]); + } } return preppedArchive; @@ -2062,21 +2124,28 @@ class queue{ * Get Channel Archive * @param {Date} startDate - Start of range to grab from * @param {Date} endDate - End of range to grab from + * @param {String} url - URL to search for */ - async queryArchive(startDate, endDate = new Date()){ + async queryArchive(startDate, endDate = new Date(), url){ + //Define object to contain our DB query + const dbQuery = { + channel: this.channel._id + }; + //If we provided a start date if(startDate != null){ - //Return archived media after start date - return await archivedMediaModel.find({ - channel:this.channel._id, - //Prevent mongoose from attempting to sanatize and invalidate our query object, plus I think we can trust an epoch that came from server-side :) - startTime: mongoose.trusted({$gt: startDate.getTime(), $lt: endDate.getTime()}) - }); - //Otherwise - }else{ - //return all archived media - return await archivedMediaModel.find({channel:this.channel._id}); + //Specify start/end datetime, this one needs to be unsantized for it to werk, I figure its taking in numbers returned by a server-side function, this is fine + dbQuery.startTime = mongoose.trusted({$gt: startDate.getTime(), $lt: endDate.getTime()}); } + + //Do I really need to re-type this shit for the url? + if(url != null && url != ''){ + //Search for exact URL matches + dbQuery.url = {$eq: url}; + } + + //return archived media based on resulting query + return await archivedMediaModel.find(dbQuery); } } diff --git a/src/views/partial/panels/queue.ejs b/src/views/partial/panels/queue.ejs index 4c07713..753501f 100644 --- a/src/views/partial/panels/queue.ejs +++ b/src/views/partial/panels/queue.ejs @@ -50,6 +50,14 @@ along with this program. If not, see . %> +