diff --git a/defaultFlair.json b/defaultFlair.json
index 6f6e608..65c2801 100644
--- a/defaultFlair.json
+++ b/defaultFlair.json
@@ -1,10 +1,17 @@
[
{
- "name": "glitter",
+ "name": "gold",
+ "displayName": "Gold",
"rank": "gold"
},
{
- "name": "negativeGlitter",
- "ranke": "gold"
+ "name": "black-gold",
+ "displayName": "Black Gold",
+ "rank": "gold"
+ },
+ {
+ "name": "lightning",
+ "displayName": "Lightning",
+ "rank": "gold"
}
-]
\ No newline at end of file
+]
diff --git a/src/app/channel/activeChannel.js b/src/app/channel/activeChannel.js
index 949e438..7c78111 100644
--- a/src/app/channel/activeChannel.js
+++ b/src/app/channel/activeChannel.js
@@ -14,6 +14,10 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .*/
+//local imports
+const flairModel = require('../../schemas/flairSchema');
+const permissionModel = require('../../schemas/permissionSchema');
+
module.exports = class{
constructor(server, name){
this.server = server;
@@ -21,7 +25,7 @@ module.exports = class{
this.userList = new Map();
}
- handleConnection(userDB, socket){
+ async handleConnection(userDB, socket){
//get current user object from the userlist
var userObj = this.userList.get(userDB.user);
@@ -45,6 +49,9 @@ module.exports = class{
//if everything looks good, admit the connection to the channel
socket.join(socket.chan);
+ //Make sure the client receives important client-info before userlist
+ await this.sendClientMetadata(userDB, socket);
+
//Send out the userlist
this.broadcastUserList(socket.chan);
}
@@ -71,13 +78,59 @@ module.exports = class{
this.broadcastUserList(socket.chan);
}
+ async sendClientMetadata(userObj, socket){
+ const flairListDB = await flairModel.find({});
+ var flairList = [];
+
+ const user = {
+ id: userObj.id,
+ user: userObj.user,
+ rank: userObj.rank,
+ flair: userObj.flair
+ }
+
+ flairListDB.forEach((flair)=>{
+ if(permissionModel.rankToNum(flair.rank) <= permissionModel.rankToNum(userObj.rank)){
+ flairList.push({
+ name: flair.name,
+ displayName: flair.displayName
+ });
+ }
+ });
+
+ socket.emit("clientMetadata", {user, flairList});
+ }
+
broadcastUserList(){
var userList = [];
this.userList.forEach((userObj, user) => {
- userList.push(user);
+ userList.push({
+ user: user,
+ flair: userObj.flair
+ });
});
- this.server.io.in(this.name).emit("user-list", userList);
+ this.server.io.in(this.name).emit("userList", userList);
+ }
+
+ updateFlair(user, flair){
+ const userObj = this.userList.get(user);
+
+ userObj.flair = flair;
+
+ this.userList.set(user, userObj);
+
+ //Quick hack to make this compatible with sendClientMetadata. make sure we do this AFTER setting the object in the userList map...
+ userObj.name = user;
+
+ //Crawl through user's sockets (lol)
+ userObj.sockets.forEach((sockid) => {
+ //Send metadata to each one
+ const socket = this.server.io.sockets.sockets.get(sockid);
+ this.sendClientMetadata(userObj, socket);
+ });
+
+ this.broadcastUserList();
}
}
\ No newline at end of file
diff --git a/src/app/channel/channelManager.js b/src/app/channel/channelManager.js
index 7b0006e..0fb2797 100644
--- a/src/app/channel/channelManager.js
+++ b/src/app/channel/channelManager.js
@@ -116,4 +116,19 @@ module.exports = class{
const channel = this.activeChannels.get(socket.chan);
return channel.userList.get(socket.user.user);
}
+
+ getConnectedChannels(socket){
+ var chanList = [];
+
+ this.activeChannels.forEach((channel) => {
+ const foundUser = channel.userList.get(socket.user.user);
+
+ //If we found a user and this channel hasn't been added to the list
+ if(foundUser){
+ chanList.push(channel);
+ }
+ });
+
+ return chanList;
+ }
}
\ No newline at end of file
diff --git a/src/app/channel/chatHandler.js b/src/app/channel/chatHandler.js
index 48f6ffd..cc266d3 100644
--- a/src/app/channel/chatHandler.js
+++ b/src/app/channel/chatHandler.js
@@ -20,7 +20,6 @@ const validator = require('validator');//No express here, so regular validator i
//local imports
const loggerUtils = require('../../utils/loggerUtils');
const userModel = require('../../schemas/userSchema');
-const channelManager = require('./channelManager');
module.exports = class{
constructor(server){
@@ -54,13 +53,20 @@ module.exports = class{
}
async setFlair(socket, data){
- const userDB = await userModel.findOne({user: socket.user.user});
+ var userDB = await userModel.findOne({user: socket.user.user});
+ const chanList = this.server.getConnectedChannels(socket)
if(userDB){
try{
//We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries
userDB.flair = data.flair;
- await userDB.save();
+ userDB = await userDB.save();
+
+ chanList.forEach((channel) => {
+ channel.updateFlair(userDB.user, userDB.flair);
+ });
+
+
}catch(err){
return loggerUtils.socketExceptionHandler(socket, err);
}
diff --git a/src/schemas/flairSchema.js b/src/schemas/flairSchema.js
index ec43073..f8981ed 100644
--- a/src/schemas/flairSchema.js
+++ b/src/schemas/flairSchema.js
@@ -26,6 +26,10 @@ const flairSchema = new mongoose.Schema({
type: mongoose.SchemaTypes.String,
required: true
},
+ displayName:{
+ type: mongoose.SchemaTypes.String,
+ required: true
+ },
rank: {
type: mongoose.SchemaTypes.String,
enum: permissionModel.rankEnum,
diff --git a/src/schemas/userSchema.js b/src/schemas/userSchema.js
index 4dc56f6..ebd5b7e 100644
--- a/src/schemas/userSchema.js
+++ b/src/schemas/userSchema.js
@@ -105,6 +105,10 @@ userSchema.pre('save', async function (next){
//Throw a shit fit. Do not pass go. Do not collect $200.
throw new Error("Invalid flair!");
}
+
+ if(permissionModel.rankToNum(this.rank) < permissionModel.rankToNum(foundFlair.rank)){
+ throw new Error(`User '${this.user}' does not have a high enough rank for flair '${foundFlair.displayName}'!`);
+ }
}
}
diff --git a/src/views/partial/styles.ejs b/src/views/partial/styles.ejs
index afd5a9c..86461ab 100644
--- a/src/views/partial/styles.ejs
+++ b/src/views/partial/styles.ejs
@@ -15,4 +15,5 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .-->
+
\ No newline at end of file
diff --git a/www/css/channel.css b/www/css/channel.css
index d9bb45a..35c0eab 100644
--- a/www/css/channel.css
+++ b/www/css/channel.css
@@ -202,6 +202,7 @@ input#chat-panel-prompt{
.user-entry{
margin: 0.2em;
font-size: 1em;
+ width: fit-content;
}
#media-panel-aspect-lock-icon{
diff --git a/www/css/flair.css b/www/css/flair.css
new file mode 100644
index 0000000..be1dcdd
--- /dev/null
+++ b/www/css/flair.css
@@ -0,0 +1,16 @@
+.flair-gold, .flair-black-gold, .flair-lightning{
+ background-image: url('/img/flair/gold.gif');
+ border-radius: 0.3em;
+ box-shadow: 0.1em 0.1em 3px #fff4b6 inset, -0.1em 0.1em 3px #fff4b6 inset, 0.1em -0.1em 3px #fff4b6 inset, -0.1em -0.1em 3px #fff4b6 inset;
+ color: rgb(121, 106, 23);
+ text-shadow: 1px 1px 1px #fff4b6, -1px 1px 1px #fff4b6, 1px -1px 1px #fff4b6, -1px -1px 1px #fff4b6;
+ padding: 0.1em 0.4em;
+}
+
+.flair-black-gold{
+ filter: invert(1) grayscale(0.9);
+}
+
+.flair-lightning{
+ filter: invert(1) grayscale(0.5);
+}
\ No newline at end of file
diff --git a/www/img/flair/gold.gif b/www/img/flair/gold.gif
new file mode 100644
index 0000000..28eaa51
Binary files /dev/null and b/www/img/flair/gold.gif differ
diff --git a/www/js/channel/channel.js b/www/js/channel/channel.js
index 5622942..9169c2e 100644
--- a/www/js/channel/channel.js
+++ b/www/js/channel/channel.js
@@ -43,9 +43,19 @@ class channel{
document.title = `${this.channelName} - Connected`
});
- this.socket.on("error", (data) => {
- console.log(data);
- });
+ this.socket.on("clientMetadata", this.handleClientInfo.bind(this));
+
+ this.socket.on("error", console.log);
+ }
+
+ handleClientInfo(data){
+ this.user = {
+ id: data.user.id,
+ name: data.user.name,
+ rank: data.user.rank
+ }
+
+ this.chatBox.handleClientInfo(data);
}
}
diff --git a/www/js/channel/chat.js b/www/js/channel/chat.js
index 19cdda2..fc2ee66 100644
--- a/www/js/channel/chat.js
+++ b/www/js/channel/chat.js
@@ -27,7 +27,8 @@ class chatBox{
//Element Nodes
this.chatPanel = document.querySelector("#chat-panel-div");
- this.highLevel = document.querySelector("#chat-panel-high-level-select");
+ this.highSelect = document.querySelector("#chat-panel-high-level-select");
+ this.flairSelect = document.querySelector("#chat-panel-flair-select");
this.chatBuffer = document.querySelector("#chat-panel-buffer-div");
this.chatPrompt = document.querySelector("#chat-panel-prompt");
this.settingsIcon = document.querySelector("#chat-panel-settings-icon");
@@ -57,6 +58,7 @@ class chatBox{
this.aspectLockIcon.addEventListener("click", this.lockAspect.bind(this));
this.showChatIcon.addEventListener("click", ()=>{this.toggleUI()});
this.hideChatIcon.addEventListener("click", ()=>{this.toggleUI()});
+ this.flairSelect.addEventListener("change", this.setFlair.bind(this));
//Clickdragger/Resize
this.clickDragger.handle.addEventListener("mousedown", this.unlockAspect.bind(this));
@@ -69,6 +71,92 @@ class chatBox{
});
}
+ displayChat(chat){
+ //Create chat-entry span
+ var chatEntry = document.createElement('span');
+ chatEntry.classList.add("chat-panel-buffer","chat-entry",`chat-entry-${chat.user}`);
+
+ //Create high-level label
+ var highLevel = document.createElement('p');
+ highLevel.classList.add("chat-panel-buffer","chat-entry-high-level");
+ highLevel.innerHTML = `${chat.high}`;
+ chatEntry.appendChild(highLevel);
+
+ //Create username label
+ var userLabel = document.createElement('p');
+ userLabel.classList.add("chat-panel-buffer","chat-entry-username");
+
+ if(chat.flair != ""){
+ var flair = `flair-${chat.flair}`;
+ }else{
+ var flair = this.client.userList.colorMap.get(chat.user);
+ }
+
+ //Create color span
+ var colorSpan = document.createElement('span');
+ colorSpan.classList.add("chat-entry-flair-span", flair);
+ colorSpan.innerHTML = `${chat.user}`;
+ userLabel.innerHTML = `${colorSpan.outerHTML}: `;
+
+ chatEntry.appendChild(userLabel);
+
+ //Create chat body
+ var chatBody = document.createElement('p');
+ chatBody.classList.add("chat-panel-buffer","chat-entry-body");
+ chatBody.innerHTML = chat.msg;
+ chatEntry.appendChild(chatBody);
+
+ this.chatBuffer.appendChild(chatEntry);
+ }
+
+ async send(event){
+ if((!event || !event.key || event.key == "Enter") && this.chatPrompt.value){
+ this.client.socket.emit("chatMessage",{msg: this.chatPrompt.value, high: this.highSelect.value});
+ this.chatPrompt.value = "";
+ }
+ }
+
+ handleClientInfo(data){
+ this.updateFlairSelect(data.flairList, data.user.flair);
+ }
+
+ setFlair(event){
+ const flair = event.target.value;
+
+ this.client.socket.emit("setFlair", {flair});
+ }
+
+
+
+ updateFlairSelect(flairList, flair){
+ //clear current flair select
+ this.flairSelect.innerHTML = "";
+
+ //Inject flair object for standard flair like the hack we are
+ flairList.push({
+ name: "",
+ displayName: "Classic"
+ });
+
+ //For each flair in flairlist
+ flairList.forEach((flair) => {
+ //Create an option
+ var flairOption = document.createElement('option');
+ //Set the name and innerHTML
+ flairOption.value = flair.name;
+ flairOption.innerHTML = flair.displayName;
+
+ //Append it to the select
+ this.flairSelect.appendChild(flairOption);
+ });
+
+ //Set the selected flair in the UI
+ this.flairSelect.value = flair;
+ //Re-style the UI, do this in two seperate steps in-case we're running for the first time and have nothing to replace.
+ this.flairSelect.className = this.flairSelect.className.replace(/flair-\S*/, "");
+ this.flairSelect.classList.add(`flair-${flair}`);
+ }
+
lockAspect(event){
//prevent the user from breaking shit :P
if(this.chatPanel.style.display != "none"){
@@ -112,44 +200,4 @@ class chatBox{
this.client.player.hideVideoIcon.style.display = "none";
}
}
-
- displayChat(chat){
- //Create chat-entry span
- var chatEntry = document.createElement('span');
- chatEntry.classList.add("chat-panel-buffer","chat-entry",`chat-entry-${chat.user}`);
-
- //Create high-level label
- var highLevel = document.createElement('p');
- highLevel.classList.add("chat-panel-buffer","chat-entry-high-level");
- highLevel.innerHTML = `${chat.high}`;
- chatEntry.appendChild(highLevel);
-
- //Create username label
- var userLabel = document.createElement('p');
- userLabel.classList.add("chat-panel-buffer","chat-entry-username");
-
- //Create color span
- var colorSpan = document.createElement('span');
- colorSpan.classList.add(this.client.userList.colorMap.get(chat.user));
- colorSpan.innerHTML = `${chat.user}`;
- userLabel.innerHTML = `${colorSpan.outerHTML}: `;
-
- chatEntry.appendChild(userLabel);
-
- //Create chat body
- var chatBody = document.createElement('p');
- chatBody.classList.add("chat-panel-buffer","chat-entry-body");
- chatBody.innerHTML = chat.msg;
- chatEntry.appendChild(chatBody);
-
- this.chatBuffer.appendChild(chatEntry);
- }
-
- async send(event){
- if((!event || !event.key || event.key == "Enter") && this.chatPrompt.value){
- this.client.socket.emit("chatMessage",{msg: this.chatPrompt.value, high: this.highLevel.value});
- this.chatPrompt.value = "";
- }
- }
-
}
\ No newline at end of file
diff --git a/www/js/channel/userlist.js b/www/js/channel/userlist.js
index 5730047..9bce9f7 100644
--- a/www/js/channel/userlist.js
+++ b/www/js/channel/userlist.js
@@ -53,7 +53,7 @@ class userList{
}
defineListeners(){
- this.client.socket.on('user-list', (data) => {
+ this.client.socket.on('userList', (data) => {
this.updateList(data);
});
}
@@ -72,12 +72,12 @@ class userList{
var color = this.userColors[Math.floor(Math.random()*this.userColors.length)]
//if this user was in the previous colormap
- if(this.colorMap.get(user) != null){
+ if(this.colorMap.get(user.user) != null){
//Override with previous color
- color = this.colorMap.get(user);
+ color = this.colorMap.get(user.user);
}
- newMap.set(user, color);
+ newMap.set(user.user, color);
this.renderUser(user, color);
});
@@ -87,8 +87,14 @@ class userList{
renderUser(user, color){
var userEntry = document.createElement('p');
- userEntry.innerText = user;
- userEntry.id = `user-entry-${user}`;
+ userEntry.innerText = user.user;
+ userEntry.id = `user-entry-${user.user}`;
+
+ //Override color with flair
+ if(user.flair != ""){
+ color = `flair-${user.flair}`;
+ }
+
userEntry.classList.add("chat-panel-users","user-entry",color);
this.userList.appendChild(userEntry);