diff --git a/api/v1/gateway/index.js b/api/v1/gateway/index.js
index b2ea919..ede156f 100644
--- a/api/v1/gateway/index.js
+++ b/api/v1/gateway/index.js
@@ -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,23 +70,37 @@ 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 = {
- username: socket.username,
- creatorId: socket.userId,
- categoryId: categoryId,
- content: content
+ 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,
+ _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)
- socket.join(v);
+ // 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);
+ }
}
});
});
diff --git a/app/app.html b/app/app.html
index fb1fde9..cfbf90f 100755
--- a/app/app.html
+++ b/app/app.html
@@ -109,10 +109,10 @@
{{ button.text }}
-
+
- {{ post.username }}
+ {{ post.author.username }}
diff --git a/app/resources/js/app.js b/app/resources/js/app.js
index fcf2a37..bd41cea 100755
--- a/app/resources/js/app.js
+++ b/app/resources/js/app.js
@@ -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);
- this.resetSnackbarButton();
- this.notification(`${username}: ${content}`);
+ if (messageObject.author.username !== this.loggedInUser.username && messageObject.category._id !== this.selection.category._id) {
+ this.resetSnackbarButton();
+ 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',
- },
- 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');
- }
+ // Navigation
+ navigateToAccountManager() {
+ window.location.href = `${window.location.origin}/auth.html`;
},
- 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;
+
+ // Snackbar
+ 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;
},
- 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');
- }
- }
}
});
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 0615da5..fad6d82 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 6c3b309..8ba4638 100755
--- a/package.json
+++ b/package.json
@@ -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"
}
}