forked from hippoz/brainlet
improve message object structure, rearrange methods in app.js just for the code to look better and make sure the message list updates when a new message is sent
This commit is contained in:
parent
89acdf6a3c
commit
667a843370
5 changed files with 172 additions and 135 deletions
|
@ -1,9 +1,11 @@
|
|||
const User = require('../../../models/User');
|
||||
const secret = require('../../../secret');
|
||||
const config = require('../../../config');
|
||||
const Category = require('../../../models/Category');
|
||||
|
||||
const jwt = require('jsonwebtoken');
|
||||
const siolib = require('socket.io')
|
||||
const siolib = require('socket.io');
|
||||
const uuid = require('uuid');
|
||||
|
||||
class GatewayServer {
|
||||
constructor(httpServer) {
|
||||
|
@ -68,24 +70,38 @@ GatewayServer.prototype.eventSetup = function() {
|
|||
console.log(`[*] [gateway] [handshake] Got yoo from ${socket.username}, connection is finally completed!`);
|
||||
socket.isConnected = true;
|
||||
|
||||
socket.on('message', ({ categoryId, content }) => {
|
||||
// TODO: URGENT: Check if the category exists and if the user has access to it (access coming soon)
|
||||
const msgConfig = {
|
||||
socket.on('message', ({ category, content }) => {
|
||||
// TODO: When/if category permissions are added, check if the user has permissions for that category
|
||||
const categoryTitle = socket.joinedCategories[category._id];
|
||||
if (!categoryTitle) return;
|
||||
|
||||
const messageObject = {
|
||||
author: {
|
||||
username: socket.username,
|
||||
creatorId: socket.userId,
|
||||
categoryId: categoryId,
|
||||
content: content
|
||||
_id: socket.userId
|
||||
},
|
||||
category: {
|
||||
title: categoryTitle,
|
||||
_id: category._id
|
||||
},
|
||||
content: content,
|
||||
_id: uuid.v4()
|
||||
};
|
||||
|
||||
socket.to(categoryId).emit('message', msgConfig);
|
||||
socket.emit('message', msgConfig);
|
||||
socket.to(category._id).emit('message', messageObject);
|
||||
socket.emit('message', messageObject);
|
||||
});
|
||||
|
||||
socket.on('subscribe', async (categories) => {
|
||||
for (let v of categories) {
|
||||
// TODO: URGENT: Check if the category exists and if the user has access to it (access coming soon)
|
||||
// TODO: When/if category permissions are added, check if the user has permissions for that category
|
||||
const category = await Category.findById(v);
|
||||
if (category && category.title && category._id) {
|
||||
if (!socket.joinedCategories) socket.joinedCategories = {};
|
||||
socket.joinedCategories[v] = category.title;
|
||||
socket.join(v);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -109,10 +109,10 @@
|
|||
<md-button v-for="button in cardButtons" v-bind:key="button.text" @click="button.click(post)">{{ button.text }}</md-button>
|
||||
</md-card-actions>
|
||||
</md-card>
|
||||
<div v-for="post,k in messages[selection.category._id]" v-if="selection.category.isChatContext" :key="post.content + post.creatorId + k">
|
||||
<div v-for="post,k in messages[selection.category._id]" v-if="selection.category.isChatContext" :key="post._id + post.author._id">
|
||||
<md-card>
|
||||
<md-card-header>
|
||||
<a class="md-dense cursor md-title" v-on:click="viewProfile(post.creatorId)"><span>{{ post.username }}</span></a>
|
||||
<a class="md-dense cursor md-title" v-on:click="viewProfile(post.author._id)"><span>{{ post.author.username }}</span></a>
|
||||
</md-card-header>
|
||||
|
||||
<md-card-content v-html="post.content"></md-card-content>
|
||||
|
|
|
@ -100,7 +100,12 @@ GatewayConnection.prototype.connect = function(token) {
|
|||
GatewayConnection.prototype.sendMessage = function(categoryId, content) {
|
||||
if (!this.isConnected) return;
|
||||
|
||||
this.socket.emit('message', { categoryId, content });
|
||||
this.socket.emit('message', {
|
||||
category: {
|
||||
_id: categoryId
|
||||
},
|
||||
content
|
||||
});
|
||||
};
|
||||
|
||||
GatewayConnection.prototype.subscribeToCategoryChat = function(categoryId) {
|
||||
|
@ -193,29 +198,7 @@ const app = new Vue({
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
navigateToAccountManager() {
|
||||
window.location.href = `${window.location.origin}/auth.html`;
|
||||
},
|
||||
snackbarButtonAction: function() {
|
||||
this.showSnackbarNotification = false;
|
||||
},
|
||||
snackbarButtonClick: function() {
|
||||
this.snackbarButtonAction();
|
||||
},
|
||||
snackbarEditButton: function(buttonText="Ok", action) {
|
||||
this.snackbarButtonText = buttonText;
|
||||
this.snackbarButtonAction = action;
|
||||
},
|
||||
resetSnackbarButton: function() {
|
||||
this.snackbarButtonText = 'Ok';
|
||||
this.snackbarButtonAction = () => {
|
||||
this.showSnackbarNotification = false;
|
||||
};
|
||||
},
|
||||
notification: function(text) {
|
||||
this.snackbarNotification = text;
|
||||
this.showSnackbarNotification = true;
|
||||
},
|
||||
// Gateway and chat
|
||||
performGatewayConnection: function() {
|
||||
// TODO: again, the thing im doing with the token is not very secure, since its being sent by the current user info endpoint and is also being send through query parameters
|
||||
this.gateway.onDisconnect = (e) => {
|
||||
|
@ -223,21 +206,99 @@ const app = new Vue({
|
|||
this.notification('ERROR: You have been disconnected from the gateway. Realtime features such as chat will not work and unexpected errors may occur.');
|
||||
};
|
||||
this.gateway.onConnect = () => {
|
||||
this.gateway.socket.on('message', ({ username, categoryId, content, creatorId }) => {
|
||||
this.showMessageNotification(categoryId, username, creatorId, content);
|
||||
})
|
||||
this.gateway.socket.on('message', this.processMessage);
|
||||
};
|
||||
this.gateway.connect(this.loggedInUser.token);
|
||||
},
|
||||
showMessageNotification: async function(categoryId, username, creatorId, content) {
|
||||
if (!this.messages[categoryId]) this.messages[categoryId] = []
|
||||
this.messages[categoryId].push({ username, content, creatorId });
|
||||
processMessage: async function(messageObject) {
|
||||
if (!this.messages[messageObject.category._id]) this.$set(this.messages, messageObject.category._id, []);
|
||||
this.messages[messageObject.category._id].push(messageObject);
|
||||
|
||||
if (messageObject.author.username !== this.loggedInUser.username && messageObject.category._id !== this.selection.category._id) {
|
||||
this.resetSnackbarButton();
|
||||
this.notification(`${username}: ${content}`);
|
||||
this.notification(`${messageObject.author.username}: ${messageObject.content}`);
|
||||
}
|
||||
},
|
||||
button: function(text, click) {
|
||||
this.cardButtons.push({ text, click });
|
||||
openChatForCategory: async function(categoryId) {
|
||||
this.gateway.subscribeToCategoryChat(categoryId);
|
||||
|
||||
this.selection.category.isChatContext = true;
|
||||
this.selection.category.browsing = true;
|
||||
this.selection.category.title = 'Chat';
|
||||
this.selection.category._id = categoryId;
|
||||
},
|
||||
|
||||
// Category and post browsing
|
||||
browseCategories: async function() {
|
||||
const res = await fetch(`${window.location.origin}/api/v1/content/category/list?count=50`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
const json = await res.json();
|
||||
|
||||
this.selection.category.title = 'categories';
|
||||
this.selection.category.browsing = true;
|
||||
this.selection.category.isCategory = false;
|
||||
this.selection.category.isChatContext = false;
|
||||
this.selection.posts = [];
|
||||
|
||||
this.cardButtons = [];
|
||||
|
||||
this.button('Chat', (post) => {
|
||||
if (post._id) {
|
||||
this.openChatForCategory(post._id);
|
||||
this.gateway.sendMessage(post._id, 'yoooo');
|
||||
}
|
||||
});
|
||||
this.button('View', (post) => {
|
||||
this.browse(post);
|
||||
});
|
||||
|
||||
for (let i = 0; i < json.categories.length; i++) {
|
||||
const v = json.categories[i];
|
||||
this.selection.posts.push({ title: v.title, body: '', _id: v._id, creator: v.creator });
|
||||
}
|
||||
} else {
|
||||
this.resetSnackbarButton();
|
||||
this.notification('Failed to fetch category list');
|
||||
}
|
||||
},
|
||||
browse: async function(category) {
|
||||
const { _id, title } = category;
|
||||
|
||||
const res = await fetch(`${window.location.origin}/api/v1/content/category/${_id}/info`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
const json = await res.json();
|
||||
|
||||
this.selection.category.title = title;
|
||||
this.selection.category._id = _id;
|
||||
this.selection.category.browsing = true;
|
||||
this.selection.category.isCategory = true;
|
||||
this.selection.category.isChatContext = false;
|
||||
this.selection.posts = [];
|
||||
|
||||
this.cardButtons = [];
|
||||
|
||||
for (let i = 0; i < json.category.posts.length; i++) {
|
||||
const v = json.category.posts[i];
|
||||
this.selection.posts.push({ title: v.title, body: v.body, _id: v._id, creator: v.creator });
|
||||
}
|
||||
} else {
|
||||
this.resetSnackbarButton();
|
||||
this.notification('Failed to fetch category');
|
||||
}
|
||||
},
|
||||
refresh: function() {
|
||||
if (this.selection.category.title === 'categories' && this.selection.category.isCategory === false) {
|
||||
|
@ -246,6 +307,20 @@ const app = new Vue({
|
|||
this.browse(this.selection.category);
|
||||
}
|
||||
},
|
||||
button: function(text, click) {
|
||||
this.cardButtons.push({ text, click });
|
||||
},
|
||||
stopBrowsing: function() {
|
||||
this.selection.category = {
|
||||
title: '',
|
||||
browsing: false,
|
||||
_id: undefined,
|
||||
isCategory: false,
|
||||
isChatContext: false
|
||||
};
|
||||
this.selection.posts = [];
|
||||
this.cardButtons = [];
|
||||
},
|
||||
viewProfile: async function(id) {
|
||||
// TODO: this just returns the username for now
|
||||
const res = await fetch(`${window.location.origin}/api/v1/users/user/${id}/info`, {
|
||||
|
@ -267,16 +342,8 @@ const app = new Vue({
|
|||
this.notification('Failed to fetch user data');
|
||||
}
|
||||
},
|
||||
stopBrowsing: function() {
|
||||
this.selection.category = {
|
||||
title: '',
|
||||
browsing: false,
|
||||
_id: undefined,
|
||||
isCategory: false
|
||||
};
|
||||
this.selection.posts = [];
|
||||
this.cardButtons = [];
|
||||
},
|
||||
|
||||
// Content creation
|
||||
showCreatePostDialog: function() {
|
||||
if (!this.selection.category.isCategory) {
|
||||
this.resetSnackbarButton();
|
||||
|
@ -373,84 +440,32 @@ const app = new Vue({
|
|||
return;
|
||||
}
|
||||
},
|
||||
browse: async function(category) {
|
||||
const { _id, title } = category;
|
||||
|
||||
const res = await fetch(`${window.location.origin}/api/v1/content/category/${_id}/info`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
// Navigation
|
||||
navigateToAccountManager() {
|
||||
window.location.href = `${window.location.origin}/auth.html`;
|
||||
},
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
const json = await res.json();
|
||||
|
||||
this.selection.category.title = title;
|
||||
this.selection.category._id = _id;
|
||||
this.selection.category.browsing = true;
|
||||
this.selection.category.isCategory = true;
|
||||
this.selection.category.isChatContext = false;
|
||||
this.selection.posts = [];
|
||||
|
||||
this.cardButtons = [];
|
||||
|
||||
for (let i = 0; i < json.category.posts.length; i++) {
|
||||
const v = json.category.posts[i];
|
||||
this.selection.posts.push({ title: v.title, body: v.body, _id: v._id, creator: v.creator });
|
||||
}
|
||||
} else {
|
||||
this.resetSnackbarButton();
|
||||
this.notification('Failed to fetch category');
|
||||
}
|
||||
// Snackbar
|
||||
snackbarButtonAction: function() {
|
||||
this.showSnackbarNotification = false;
|
||||
},
|
||||
openChatForCategory: async function(categoryId) {
|
||||
this.gateway.subscribeToCategoryChat(categoryId);
|
||||
|
||||
this.selection.category.isChatContext = true;
|
||||
this.selection.category.browsing = true;
|
||||
this.selection.category.title = 'Chat';
|
||||
this.selection.category._id = categoryId;
|
||||
snackbarButtonClick: function() {
|
||||
this.snackbarButtonAction();
|
||||
},
|
||||
browseCategories: async function() {
|
||||
const res = await fetch(`${window.location.origin}/api/v1/content/category/list?count=50`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
snackbarEditButton: function(buttonText="Ok", action) {
|
||||
this.snackbarButtonText = buttonText;
|
||||
this.snackbarButtonAction = action;
|
||||
},
|
||||
resetSnackbarButton: function() {
|
||||
this.snackbarButtonText = 'Ok';
|
||||
this.snackbarButtonAction = () => {
|
||||
this.showSnackbarNotification = false;
|
||||
};
|
||||
},
|
||||
notification: function(text) {
|
||||
this.snackbarNotification = text;
|
||||
this.showSnackbarNotification = true;
|
||||
},
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
const json = await res.json();
|
||||
|
||||
this.selection.category.title = 'categories';
|
||||
this.selection.category.browsing = true;
|
||||
this.selection.category.isCategory = false;
|
||||
this.selection.category.isChatContext = false;
|
||||
this.selection.posts = [];
|
||||
|
||||
this.cardButtons = [];
|
||||
|
||||
this.button('Chat', (post) => {
|
||||
if (post._id) {
|
||||
this.openChatForCategory(post._id);
|
||||
this.gateway.sendMessage(post._id, 'yoooo');
|
||||
}
|
||||
});
|
||||
this.button('View', (post) => {
|
||||
this.browse(post);
|
||||
});
|
||||
|
||||
for (let i = 0; i < json.categories.length; i++) {
|
||||
const v = json.categories[i];
|
||||
this.selection.posts.push({ title: v.title, body: '', _id: v._id, creator: v.creator });
|
||||
}
|
||||
} else {
|
||||
this.resetSnackbarButton();
|
||||
this.notification('Failed to fetch category list');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
5
package-lock.json
generated
5
package-lock.json
generated
|
@ -1202,6 +1202,11 @@
|
|||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
|
||||
"integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg=="
|
||||
},
|
||||
"validator": {
|
||||
"version": "13.1.1",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.1.1.tgz",
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"express-validator": "^6.6.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"mongoose": "^5.10.0",
|
||||
"socket.io": "^3.0.1"
|
||||
"socket.io": "^3.0.1",
|
||||
"uuid": "^8.3.1"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue