diff --git a/src/app/channel/chatHandler.js b/src/app/channel/chatHandler.js index a8235c1..e326e02 100644 --- a/src/app/channel/chatHandler.js +++ b/src/app/channel/chatHandler.js @@ -83,4 +83,9 @@ module.exports = class{ const user = this.server.getSocketInfo(socket); this.server.io.in(socket.chan).emit("chatMessage", {user: user.user, flair: user.flair, highLevel: user.highLevel, msg, type}); } + + relayChannelAnnouncement(socket, msg){ + //This codebase is always at a 10 + this.server.io.in(socket.chan).emit("chatMessage", {user: "Channel", flair: "", highLevel: 10, msg, type: "announcement"}); + } } \ No newline at end of file diff --git a/src/app/channel/commandPreprocessor.js b/src/app/channel/commandPreprocessor.js index e5bf620..ddb1721 100644 --- a/src/app/channel/commandPreprocessor.js +++ b/src/app/channel/commandPreprocessor.js @@ -16,13 +16,17 @@ along with this program. If not, see .*/ //NPM Imports const validator = require('validator');//No express here, so regular validator it is! + +//Local Imports +const channelModel = require('../../schemas/channel/channelSchema'); + module.exports = class commandPreprocessor{ constructor(server){ this.server = server; this.commandProcessor = new commandProcessor(server, this); } - preprocess(socket, data){ + async preprocess(socket, data){ //Set socket, data, and sendFlag this.socket = socket; this.sendFlag = true; @@ -36,7 +40,7 @@ module.exports = class commandPreprocessor{ //split the command this.splitCommand(); //Process the command - this.processServerCommand(); + await this.processServerCommand(); //Send it as chat (assuming the flag isn't false) this.sendChat(); } @@ -60,15 +64,15 @@ module.exports = class commandPreprocessor{ this.argumentArray = this.command.match(/\b\w+\b/g);//Match by words surrounded by borders } - processServerCommand(){ - //If the first word is '!' - if(this.commandArray[0] == '!'){ + async processServerCommand(){ + //If the raw message starts with '!' (skip commands that start with whitespace so people can send example commands in chat) + if(this.rawData.msg[0] == '!'){ //if it isn't just an exclimation point, and we have a real command - if(this.argumentArray != null && this.commandProcessor[this.argumentArray[0]] != null){ + if(this.argumentArray != null && this.commandProcessor[this.argumentArray[0].toLowerCase()] != null){ //disable chat this.sendFlag = false; //Process the command - this.commandProcessor[this.argumentArray[0]](); + await this.commandProcessor[this.argumentArray[0].toLowerCase()](); } } } @@ -89,12 +93,23 @@ class commandProcessor{ } whisper(){ - //Ensure we don't double dip - this.sendFlag = false; - //splice out our whisper this.preprocessor.commandArray.splice(0,2); //send it this.server.chatHandler.relayChat(this.preprocessor.socket, this.preprocessor.commandArray.join(''), 'whisper'); + + return; + } + + async announce(){ + const chanDB = await channelModel.findOne({name: this.preprocessor.socket.chan}); + + //Check if the user has permission, and publicly shame them if they don't (lmao) + if(!(this.preprocessor.sendFlag = !(await chanDB.permCheck(this.preprocessor.socket.user, 'announce')))){ + //splice out our whisper + this.preprocessor.commandArray.splice(0,2); + //send it + this.server.chatHandler.relayChannelAnnouncement(this.preprocessor.socket, this.preprocessor.commandArray.join('')); + } } } \ No newline at end of file diff --git a/src/schemas/channel/channelPermissionSchema.js b/src/schemas/channel/channelPermissionSchema.js index e65fd1b..5c83209 100644 --- a/src/schemas/channel/channelPermissionSchema.js +++ b/src/schemas/channel/channelPermissionSchema.js @@ -58,6 +58,12 @@ const channelPermissionSchema = new mongoose.Schema({ default: "admin", required: true }, + announce: { + type: mongoose.SchemaTypes.String, + enum: rankEnum, + default: "admin", + required: true + }, deleteChannel: { type: mongoose.SchemaTypes.String, enum: rankEnum, diff --git a/src/validators/permissionsValidator.js b/src/validators/permissionsValidator.js index c2d609d..d07eec8 100644 --- a/src/validators/permissionsValidator.js +++ b/src/validators/permissionsValidator.js @@ -111,6 +111,12 @@ module.exports.channelPermissionValidator = { options: module.exports.isRank }, }, + 'channelPermissionsMap.announce': { + optional: true, + custom: { + options: module.exports.isRank + }, + }, 'channelPermissionsMap.deleteChannel': { optional: true, custom: { diff --git a/src/views/channel.ejs b/src/views/channel.ejs index cac60d7..bdb9d1b 100644 --- a/src/views/channel.ejs +++ b/src/views/channel.ejs @@ -122,7 +122,7 @@ along with this program. If not, see .--> <%- include('partial/scripts', {user}); %> - + diff --git a/www/css/channel.css b/www/css/channel.css index c44d7ce..4fe7266 100644 --- a/www/css/channel.css +++ b/www/css/channel.css @@ -147,6 +147,7 @@ p.panel-head-element{ .chat-entry{ display: flex; + align-content: center; } .chat-entry-username{ @@ -156,6 +157,7 @@ p.panel-head-element{ .chat-entry-body{ margin: 0.2em; + align-content: center; } .user-list-high-level{ @@ -194,6 +196,16 @@ span.user-entry{ font-size: 0.7em; } +.announcement{ + font-size: 1.5em; + flex-direction: column; + text-align: center; +} + +.announcement-title{ + margin: 0; +} + #media-panel-aspect-lock-icon{ display: none; } diff --git a/www/css/theme/movie-night.css b/www/css/theme/movie-night.css index 600f90d..c72147b 100644 --- a/www/css/theme/movie-night.css +++ b/www/css/theme/movie-night.css @@ -293,6 +293,11 @@ select.panel-head-element{ border-bottom: solid 1px var(--accent0); } +.announcement-title{ + background-color: var(--danger0-alt0); + color: var(--accent1); +} + /* popup */ .popup-backer{ diff --git a/www/js/channel/chat.js b/www/js/channel/chat.js index 11418e4..69da64a 100644 --- a/www/js/channel/chat.js +++ b/www/js/channel/chat.js @@ -27,7 +27,7 @@ class chatBox{ //Preprocessor objects this.commandPreprocessor = new commandPreprocessor(client); - this.chatPreprocessor = new chatPreprocessor(); + this.chatPostprocessor = new chatPostprocessor(); //Element Nodes this.chatPanel = document.querySelector("#chat-panel-div"); @@ -112,7 +112,7 @@ class chatBox{ chatEntry.appendChild(chatBody); - this.chatBuffer.appendChild(this.chatPreprocessor.preprocess(chatEntry, data)); + this.chatBuffer.appendChild(this.chatPostprocessor.preprocess(chatEntry, data)); //Set size to aspect on launch this.resizeAspect(); diff --git a/www/js/channel/chatPreprocessor.js b/www/js/channel/chatPostprocessor.js similarity index 77% rename from www/js/channel/chatPreprocessor.js rename to www/js/channel/chatPostprocessor.js index fff1321..e905f59 100644 --- a/www/js/channel/chatPreprocessor.js +++ b/www/js/channel/chatPostprocessor.js @@ -1,4 +1,4 @@ -class chatPreprocessor{ +class chatPostprocessor{ constructor(){ } @@ -14,7 +14,7 @@ class chatPreprocessor{ //Inject whitespace into un-processed words this.addWhitespace(); - //Sush chat if it's a whisper + //Handle non-standard chat types this.handleChatType(); //Inject the pre-processed chat into the chatEntry node @@ -81,6 +81,18 @@ class chatPreprocessor{ handleChatType(){ if(this.rawData.type == "whisper"){ this.chatBody.classList.add('whisper'); + }else if(this.rawData.type == "announcement"){ + //Squash the high-level + this.chatEntry.querySelector('.high-level').remove(); + + //Get the username and make it into an announcement title (little hacky but this *IS* postprocessing) + const userNode = this.chatEntry.querySelector('.chat-entry-username'); + userNode.innerHTML = `${userNode.innerHTML.slice(0,-2)} Announcement`; + //Add/remove relevant classes + userNode.classList.remove('chat-entry-username'); + userNode.classList.add('announcement-title'); + this.chatBody.classList.add('announcement-body'); + this.chatEntry.classList.add('announcement'); } } } \ No newline at end of file diff --git a/www/js/channel/commandPreprocessor.js b/www/js/channel/commandPreprocessor.js index ed9ee07..8aded78 100644 --- a/www/js/channel/commandPreprocessor.js +++ b/www/js/channel/commandPreprocessor.js @@ -26,12 +26,12 @@ class commandPreprocessor{ //If this is a local command if(this.commandArray[0] == '/'){ //If the command exists - if(this.argumentArray != null && this.commandProcessor[this.argumentArray[0]] != null){ + if(this.argumentArray != null && this.commandProcessor[this.argumentArray[0].toLowerCase()] != null){ //Don't send it to the server this.sendFlag = false; //Call the command with the argument array - this.commandProcessor[this.argumentArray[0]](this.argumentArray, this.commandArray); + this.commandProcessor[this.argumentArray[0].toLowerCase()](this.argumentArray, this.commandArray); } } }