replace all mentions of category with channel for better consistency

This commit is contained in:
hippoz 2021-03-26 22:50:21 +02:00
parent e7da5de255
commit 943ed64735
No known key found for this signature in database
GPG key ID: 7C52899193467641
11 changed files with 175 additions and 175 deletions

View file

@ -1,5 +1,5 @@
# Brainlet
Brainlet is a simple chat app. Each category has a text channel associated with it, all messages sent in the text channel are temporary, while in the category itself all posts are permanent.
Brainlet is a simple chat app. Each channel has a text channel associated with it, all messages sent in the text channel are temporary, while in the channel itself all posts are permanent.
# Resources

View file

@ -1,5 +1,5 @@
const User = require("../../models/User");
const Category = require("../../models/Category");
const Channel = require("../../models/Channel");
const Post = require("../../models/Post");
const config = require("../../config");
const { authenticateEndpoint } = require("./../../common/auth/authfunctions");
@ -17,7 +17,7 @@ const createLimiter = rateLimit({
mongoose.connect(config.mongoUrl, {useNewUrlParser: true, useUnifiedTopology: true});
app.post("/category/create", [
app.post("/channel/create", [
createLimiter,
body("title").not().isEmpty().trim().isLength({ min: 3, max: 32 }).escape()
], authenticateEndpoint(async (req, res, user) => {
@ -28,7 +28,7 @@ app.post("/category/create", [
}
const title = req.body.title;
const category = await Category.create({
const channel = await Channel.create({
title: title,
creator: user._id,
posts: []
@ -37,13 +37,13 @@ app.post("/category/create", [
res.status(200).json({
error: false,
message: "SUCCESS_CATEGORY_CREATED",
category: category.getPublicObject()
channel: channel.getPublicObject()
});
}, undefined, config.roleMap.USER));
app.post("/post/create", [
createLimiter,
body("category").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 }),
body("channel").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 }),
body("title").not().isEmpty().trim().isLength({ min: 3, max: 32 }).escape(),
body("body").not().isEmpty().trim().isLength({ min: 3, max: 1000 }).escape(),
], authenticateEndpoint(async (req, res, user) => {
@ -53,7 +53,7 @@ app.post("/post/create", [
return;
}
const category = req.body.category;
const channel = req.body.channel;
const title = req.body.title;
const content = req.body.body;
@ -61,10 +61,10 @@ app.post("/post/create", [
post.title = title;
post.body = content;
post.creator = user._id;
post.category = category;
post.channel = channel;
const r = await Category.updateOne({
_id: category
const r = await Channel.updateOne({
_id: channel
}, {
$push: { posts: post }
});
@ -86,8 +86,8 @@ app.post("/post/create", [
});
}, undefined, config.roleMap.USER));
app.get("/category/:category/info", [
param("category").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 })
app.get("/channel/:channel/info", [
param("channel").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 })
], authenticateEndpoint(async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
@ -95,13 +95,13 @@ app.get("/category/:category/info", [
return;
}
const categoryId = req.params.category;
const category = await Category.findById(categoryId).populate("posts.creator", User.getPulicFields());
const channelId = req.params.channel;
const channel = await Channel.findById(channelId).populate("posts.creator", User.getPulicFields());
// TODO: Implement subscribing to a channel and stuff
const users = await User.find().sort({ _id: -1 }).limit(50).select(User.getPulicFields());
if (!category) {
if (!channel) {
res.status(404).json({
error: true,
message: "ERROR_CATEGORY_NOT_FOUND"
@ -112,7 +112,7 @@ app.get("/category/:category/info", [
res.status(200).json({
error: false,
message: "SUCCESS_CATEGORY_DATA_FETCHED",
category: category.getPublicObject(),
channel: channel.getPublicObject(),
userInfo: {
userListLimit: 50,
users: users
@ -120,19 +120,19 @@ app.get("/category/:category/info", [
});
}, undefined, config.roleMap.USER));
app.get("/category/list", authenticateEndpoint(async (req, res) => {
app.get("/channel/list", authenticateEndpoint(async (req, res) => {
let count = parseInt(req.query.count);
if (!Number.isInteger(count)) {
count = 10;
}
// TODO: This is probably not efficient
const categories = await Category.find().lean().sort({ _id: -1 }).limit(count).select("-posts -__v").populate("creator", User.getPulicFields());
const channels = await Channel.find().lean().sort({ _id: -1 }).limit(count).select("-posts -__v").populate("creator", User.getPulicFields());
res.status(200).json({
error: false,
message: "SUCCESS_CATEGORY_LIST_FETCHED",
categories
channels
});
}, undefined, config.roleMap.USER));

View file

@ -1,7 +1,7 @@
const User = require("../../../models/User");
const secret = require("../../../secret");
const config = require("../../../config");
const Category = require("../../../models/Category");
const Channel = require("../../../models/Channel");
const RateLimiter = require("../../../common/util/ratelimiter");
const jwt = require("jsonwebtoken");
@ -23,15 +23,15 @@ class GatewayServer {
}
}
GatewayServer.prototype._sendSystemMessage = function(socket, message, category) {
GatewayServer.prototype._sendSystemMessage = function(socket, message, channel) {
const messageObject = {
author: {
username: "__SYSTEM",
_id: "5fc69864f15a7c5e504c9a1f"
},
category: {
title: category.title,
_id: category._id
channel: {
title: channel.title,
_id: channel._id
},
content: message,
_id: uuid.v4()
@ -53,7 +53,7 @@ GatewayServer.prototype._processCommand = async function(socket, message) {
switch (command) {
case "INVALID_COMMAND": {
this._sendSystemMessage(socket, "Invalid command.", message.category);
this._sendSystemMessage(socket, "Invalid command.", message.channel);
break;
}
case "admin/fr": {
@ -61,33 +61,33 @@ GatewayServer.prototype._processCommand = async function(socket, message) {
if (socket.user.permissionLevel >= config.roleMap.ADMIN) {
this._gateway.emit("refreshClient", { reason: fullCommand[1] || "REFRESH" });
} else {
this._sendSystemMessage(socket, "how about no", message.category);
this._sendSystemMessage(socket, "how about no", message.channel);
}
} else {
this._sendSystemMessage(socket, "Invalid number of arguments.", message.category);
this._sendSystemMessage(socket, "Invalid number of arguments.", message.channel);
}
break;
}
case "admin/fru": {
if (args === 1) {
if (socket.user.permissionLevel >= config.roleMap.ADMIN) {
const user = await this._findSocketInRoom(message.category._id, fullCommand[1]);
const user = await this._findSocketInRoom(message.channel._id, fullCommand[1]);
if (!user) {
this._sendSystemMessage(socket, "User not found.", message.category);
this._sendSystemMessage(socket, "User not found.", message.channel);
break;
}
this._gateway.in(user.user.sid).emit("refreshClient", { reason: "REFRESH" });
} else {
this._sendSystemMessage(socket, "how about no", message.category);
this._sendSystemMessage(socket, "how about no", message.channel);
}
} else {
this._sendSystemMessage(socket, "Invalid number of arguments.", message.category);
this._sendSystemMessage(socket, "Invalid number of arguments.", message.channel);
}
break;
}
default: {
this._sendSystemMessage(socket, "That command does not exist.", message.category);
this._sendSystemMessage(socket, "That command does not exist.", message.channel);
break;
}
}
@ -170,8 +170,8 @@ GatewayServer.prototype.eventSetup = function() {
console.log(`[*] [gateway] [handshake] Got yoo from ${socket.user.username}, connection is finally completed!`);
socket.isConnected = true;
socket.on("message", async ({ category, content, nickAuthor, destUser }) => {
if (!category || !content || !socket.joinedCategories || !socket.isConnected || !socket.user || !(typeof content === "string") || !(typeof category._id === "string")) return;
socket.on("message", async ({ channel, content, nickAuthor, destUser }) => {
if (!channel || !content || !socket.joinedChannels || !socket.isConnected || !socket.user || !(typeof content === "string") || !(typeof channel._id === "string")) return;
content = content.trim();
if (!content || content === "" || content === " " || content.length >= 2000) return;
if (!this.rateLimiter.consoom(socket.user.token)) { // TODO: maybe user ip instead of token?
@ -179,9 +179,9 @@ GatewayServer.prototype.eventSetup = function() {
return;
}
// TODO: When/if category permissions are added, check if the user has permissions for that category
const categoryTitle = socket.joinedCategories[category._id];
if (!categoryTitle || !(typeof categoryTitle === "string")) return;
// TODO: When/if channel permissions are added, check if the user has permissions for that channel
const channelTitle = socket.joinedChannels[channel._id];
if (!channelTitle || !(typeof channelTitle === "string")) return;
let messageObject = {
author: {
@ -189,9 +189,9 @@ GatewayServer.prototype.eventSetup = function() {
_id: socket.user._id,
color: socket.user.color
},
category: {
title: categoryTitle,
_id: category._id
channel: {
title: channelTitle,
_id: channel._id
},
content: content,
_id: uuid.v4()
@ -214,32 +214,32 @@ GatewayServer.prototype.eventSetup = function() {
}
if (destUser && destUser._id && (typeof destUser._id) === "string") {
const user = await this._findSocketInRoom(messageObject.category._id, destUser._id);
const user = await this._findSocketInRoom(messageObject.channel._id, destUser._id);
if (!user) return;
this._gateway.in(user.user.sid).emit("message", messageObject);
return;
}
this._gateway.in(category._id).emit("message", messageObject);
this._gateway.in(channel._id).emit("message", messageObject);
});
socket.on("subscribe", async (categories) => {
if ( !socket.isConnected || !socket.user || !categories || !Array.isArray(categories) || categories === []) return;
socket.on("subscribe", async (channels) => {
if ( !socket.isConnected || !socket.user || !channels || !Array.isArray(channels) || channels === []) return;
try {
for (const v of categories) {
for (const v of channels) {
if (!v && !(typeof v === "string")) continue;
// 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 = {};
if (socket.joinedCategories[v]) continue;
socket.joinedCategories[v] = category.title;
// TODO: When/if channel permissions are added, check if the user has permissions for that channel
const channel = await Channel.findById(v);
if (channel && channel.title && channel._id) {
if (!socket.joinedChannels) socket.joinedChannels = {};
if (socket.joinedChannels[v]) continue;
socket.joinedChannels[v] = channel.title;
await socket.join(v);
console.log(`[*] [gateway] User ${socket.user.username} subscribed to room ${v} (${category.title}), sending updated user list to all members of that room...`);
console.log(`[*] [gateway] User ${socket.user.username} subscribed to room ${v} (${channel.title}), sending updated user list to all members of that room...`);
const upd = await this._generateClientListUpdateObject(v, category.title);
const upd = await this._generateClientListUpdateObject(v, channel.title);
this._gateway.in(v).emit("clientListUpdate", upd);
}
}
@ -255,10 +255,10 @@ GatewayServer.prototype.eventSetup = function() {
// Socket io automatically adds a user to a room with their own id
if (room === socket.id) return;
const categoryTitle = socket.joinedCategories[room] || "UNKNOWN";
const channelTitle = socket.joinedChannels[room] || "UNKNOWN";
await socket.leave(room);
const upd = await this._generateClientListUpdateObject(room, categoryTitle);
const upd = await this._generateClientListUpdateObject(room, channelTitle);
socket.in(room).emit("clientListUpdate", upd);
});
});
@ -309,11 +309,11 @@ GatewayServer.prototype._findSocketInRoom = async function(room, userid) {
return updatedClientList[0] || undefined;
};
GatewayServer.prototype._generateClientListUpdateObject = async function(room, categoryTitle="UNKNOWN") {
GatewayServer.prototype._generateClientListUpdateObject = async function(room, channelTitle="UNKNOWN") {
const clientList = await this._getSocketsInRoom(room);
return {
category: {
title: categoryTitle,
channel: {
title: channelTitle,
_id: room
},
clientList

View file

@ -3,7 +3,7 @@ const EventEmitter = require("events");
const uuid = require("uuid");
const User = require("../../../models/User");
const Category = require("../../../models/Category");
const Channel = require("../../../models/Channel");
const { parseMessage, opcodeSeparator, getOpcodeByName } = require("./messageparser");
const { checkToken } = require("../../../common/auth/authfunctions");
@ -57,7 +57,7 @@ class GatewayServer extends EventEmitter {
// The user is now successfully authenticated, send the YOO_ACK packet
// TODO: This is probably not efficient
let channels = await Category.find().lean().sort({ _id: -1 }).limit(50).select("-posts -__v").populate("creator", User.getPulicFields(true));
let channels = await Channel.find().lean().sort({ _id: -1 }).limit(50).select("-posts -__v").populate("creator", User.getPulicFields(true));
if (!channels) channels = [];
channels = channels.map(x => ({ ...x, _id: x._id.toString() }));

View file

@ -77,24 +77,24 @@
</md-dialog-content>
</md-dialog>
<md-dialog id="create-category-dialog" :md-active.sync="dialog.show.createCategory">
<md-dialog-title>Create category</md-dialog-title>
<md-dialog id="create-channel-dialog" :md-active.sync="dialog.show.createChannel">
<md-dialog-title>Create channel</md-dialog-title>
<md-dialog-content>
<md-field>
<label>Title</label>
<md-input v-model="dialog.text.createCategory.title"></md-input>
<md-input v-model="dialog.text.createChannel.title"></md-input>
</md-field>
<md-dialog-actions>
<md-button @click="dialog.show.createCategory = false">Close</md-button>
<md-button class="md-primary" @click="createCategory()">Create</md-button>
<md-button @click="dialog.show.createChannel = false">Close</md-button>
<md-button class="md-primary" @click="createChannel()">Create</md-button>
</md-dialog-actions>
</md-dialog-content>
</md-dialog>
<md-dialog id="create-post-dialog" :md-active.sync="dialog.show.createPost">
<md-dialog-title>Create post for <strong>{{ selection.category.title }}</strong></md-dialog-title>
<md-dialog-title>Create post for <strong>{{ selection.channel.title }}</strong></md-dialog-title>
<md-dialog-content>
<md-field>
@ -137,19 +137,19 @@
</md-menu>
</md-toolbar>
<md-toolbar v-show="selection.category.browsing" class="md-dense" md-elevation="5">
<h3 v-if="selection.category.isCategory && !selection.category.isChatContext" class="md-title" style="flex: 1">Browsing category: {{ selection.category.title }}</h3>
<h3 v-if="!selection.category.isCategory && !selection.category.isChatContext" class="md-title" style="flex: 1">Browsing {{ selection.category.title }}</h3>
<h3 v-if="!selection.category.isCategory && selection.category.isChatContext" class="md-title" style="flex: 1">
Browsing {{ selection.category.title }} with
<a v-for="user in userLists[selection.category._id]" class="md-dense cursor" v-on:click="viewProfile(user.user._id)" v-bind:style="{ 'color': user.user.color }">{{ user.user.username }} </a>
<md-toolbar v-show="selection.channel.browsing" class="md-dense" md-elevation="5">
<h3 v-if="selection.channel.isChannel && !selection.channel.isChatContext" class="md-title" style="flex: 1">Browsing channel: {{ selection.channel.title }}</h3>
<h3 v-if="!selection.channel.isChannel && !selection.channel.isChatContext" class="md-title" style="flex: 1">Browsing {{ selection.channel.title }}</h3>
<h3 v-if="!selection.channel.isChannel && selection.channel.isChatContext" class="md-title" style="flex: 1">
Browsing {{ selection.channel.title }} with
<a v-for="user in userLists[selection.channel._id]" class="md-dense cursor" v-on:click="viewProfile(user.user._id)" v-bind:style="{ 'color': user.user.color }">{{ user.user.username }} </a>
</h3>
<md-button @click="browseCategories()" v-if="selection.category.isCategory || selection.category.isChatContext"><md-icon>arrow_back</md-icon></md-button>
<md-button @click="refresh()" v-if="!selection.category.isChatContext"><md-icon>refresh</md-icon></md-button>
<md-button @click="browseChannels()" v-if="selection.channel.isChannel || selection.channel.isChatContext"><md-icon>arrow_back</md-icon></md-button>
<md-button @click="refresh()" v-if="!selection.channel.isChatContext"><md-icon>refresh</md-icon></md-button>
</md-toolbar>
<div id="posts-container" class="posts-container" v-if="selection.category.browsing">
<md-card v-for="post in selection.posts" v-bind:key="post._id" v-if="!selection.category.isChatContext">
<div id="posts-container" class="posts-container" v-if="selection.channel.browsing">
<md-card v-for="post in selection.posts" v-bind:key="post._id" v-if="!selection.channel.isChatContext">
<md-card-header>
<div class="md-title" v-html="post.title"></div>
<span>by <a class="md-dense cursor" v-on:click="viewProfile(post.creator._id)" v-bind:style="{ 'color': post.creator.color}">{{ post.creator.username }}</a></span>
@ -161,7 +161,7 @@
<md-button v-for="button in cardButtons" v-bind:key="button.text" @click="button.click(post)"><md-icon>{{ button.text }}</md-icon></md-button>
</md-card-actions>
</md-card>
<div v-for="post,k in messages[selection.category._id]" v-if="selection.category.isChatContext" :key="post._id + post.author._id">
<div v-for="post,k in messages[selection.channel._id]" v-if="selection.channel.isChatContext" :key="post._id + post.author._id">
<md-card class="message-card">
<md-card-header>
<a v-if="!post.nickAuthor" class="md-dense cursor md-title" v-on:click="viewProfile(post.author._id)" v-bind:style="{ 'color': post.author.color}"><span>{{ post.author.username }}</span></a>
@ -174,26 +174,26 @@
</div>
</div>
<md-speed-dial class="md-fixed md-bottom-right" md-direction="top" md-elevation="5" style="z-index: 4000;" v-show="!selection.category.isChatContext">
<md-speed-dial class="md-fixed md-bottom-right" md-direction="top" md-elevation="5" style="z-index: 4000;" v-show="!selection.channel.isChatContext">
<md-speed-dial-target>
<md-icon class="md-morph-initial">add</md-icon>
<md-icon class="md-morph-final">edit</md-icon>
</md-speed-dial-target>
<md-speed-dial-content>
<md-button v-show="selection.category.isCategory" class="md-icon-button" @click="showCreatePostDialog()">
<md-button v-show="selection.channel.isChannel" class="md-icon-button" @click="showCreatePostDialog()">
<md-icon>add</md-icon>
<md-tooltip md-direction="left">Create a new post</md-tooltip>
</md-button>
<md-button class="md-icon-button" @click="dialog.show.createCategory = true">
<md-button class="md-icon-button" @click="dialog.show.createChannel = true">
<md-icon>category</md-icon>
<md-tooltip md-direction="left">Create a new category</md-tooltip>
<md-tooltip md-direction="left">Create a new channel</md-tooltip>
</md-button>
</md-speed-dial-content>
</md-speed-dial>
<md-field md-inline class="chat-bar" v-show="selection.category.isChatContext">
<md-field md-inline class="chat-bar" v-show="selection.channel.isChatContext">
<label>Write something interesting, go on!</label>
<md-input v-model="message.typed" v-on:keyup.enter="sendCurrentMessage()"></md-input>
</md-field>

View file

@ -10,8 +10,8 @@ const getCreatePostError = (json) => {
case 'body': {
return 'Invalid content. Must be between 3 and 1000 characters';
}
case 'category': {
return 'Invalid category. Something went wrong.';
case 'channel': {
return 'Invalid channel. Something went wrong.';
}
default: {
return 'Invalid value sent to server. Something went wrong.';
@ -20,7 +20,7 @@ const getCreatePostError = (json) => {
}
case 'ERROR_CATEGORY_NOT_FOUND': {
return 'The category you tried to post to no longer exists.';
return 'The channel you tried to post to no longer exists.';
}
case 'ERROR_ACCESS_DENIED': {
@ -33,7 +33,7 @@ const getCreatePostError = (json) => {
}
}
const getCreateCategoryError = (json) => {
const getCreateChannelError = (json) => {
switch (json.message) {
case 'ERROR_REQUEST_INVALID_DATA': {
switch (json.errors[0].param) {
@ -109,22 +109,22 @@ GatewayConnection.prototype.connect = function(token) {
});
};
GatewayConnection.prototype.sendMessage = function(categoryId, content) {
GatewayConnection.prototype.sendMessage = function(channelId, content) {
if (!this.isConnected) return 1;
if (content.length >= 2000) return 1;
this.socket.emit('message', {
category: {
_id: categoryId
channel: {
_id: channelId
},
content
});
};
GatewayConnection.prototype.subscribeToCategoryChat = function(categoryId) {
GatewayConnection.prototype.subscribeToChannelChat = function(channelId) {
if (!this.isConnected) return;
const request = [categoryId];
const request = [channelId];
console.log('[*] [gateway] Subscribing to channel(s)', request);
@ -143,11 +143,11 @@ const app = new Vue({
showApp: false,
menuVisible: false,
selection: {
category: {
channel: {
title: '',
browsing: false,
_id: undefined,
isCategory: false,
isChannel: false,
isChatContext: false
},
posts: []
@ -156,7 +156,7 @@ const app = new Vue({
dialog: {
show: {
createPost: false,
createCategory: false,
createChannel: false,
debug: false
},
text: {
@ -164,7 +164,7 @@ const app = new Vue({
title: '',
body: ''
},
createCategory: {
createChannel: {
title: ''
}
}
@ -201,7 +201,7 @@ const app = new Vue({
this.loggedInUser = json.user;
this.showApp = true;
this.performGatewayConnection();
this.browseCategories();
this.browseChannels();
Notification.requestPermission();
} else {
this.showApp = false;
@ -259,9 +259,9 @@ const app = new Vue({
});
});
},
shouldMergeMessage: function(messageObject, categoryMessageList) {
const lastMessageIndex = categoryMessageList.length-1;
const lastMessage = categoryMessageList[lastMessageIndex];
shouldMergeMessage: function(messageObject, channelMessageList) {
const lastMessageIndex = channelMessageList.length-1;
const lastMessage = channelMessageList[lastMessageIndex];
if (!lastMessage) return;
if (lastMessage.author._id === messageObject.author._id) {
@ -277,32 +277,32 @@ const app = new Vue({
return false;
},
processMessage: async function(messageObject) {
if (!this.messages[messageObject.category._id]) this.$set(this.messages, messageObject.category._id, []);
const categoryMessageList = this.messages[messageObject.category._id];
const lastMessageIndex = categoryMessageList.length-1;
if (!this.messages[messageObject.channel._id]) this.$set(this.messages, messageObject.channel._id, []);
const channelMessageList = this.messages[messageObject.channel._id];
const lastMessageIndex = channelMessageList.length-1;
if (this.shouldMergeMessage(messageObject, categoryMessageList)) {
categoryMessageList[lastMessageIndex].content += `\n${messageObject.content}`;
if (this.shouldMergeMessage(messageObject, channelMessageList)) {
channelMessageList[lastMessageIndex].content += `\n${messageObject.content}`;
} else {
this.messages[messageObject.category._id].push(messageObject);
this.messages[messageObject.channel._id].push(messageObject);
}
if (messageObject.category._id === this.selection.category._id) {
if (messageObject.channel._id === this.selection.channel._id) {
this.$nextTick(() => {
// TODO: When the user presses back, actually undo this scroll cause its annoying to scroll back up in the category list
// TODO: When the user presses back, actually undo this scroll cause its annoying to scroll back up in the channel list
const container = this.$el.querySelector('#posts-container');
container.scrollTop = container.scrollHeight;
});
}
if (messageObject.author.username !== this.loggedInUser.username && messageObject.category._id !== this.selection.category._id) {
this.okNotification(`${messageObject.category.title}/${messageObject.author.username}: ${messageObject.content}`);
if (messageObject.author.username !== this.loggedInUser.username && messageObject.channel._id !== this.selection.channel._id) {
this.okNotification(`${messageObject.channel.title}/${messageObject.author.username}: ${messageObject.content}`);
}
if (messageObject.author.username !== this.loggedInUser.username) {
if (Notification.permission === 'granted') {
try {
new Notification(`${messageObject.category.title}/${messageObject.author.username}`, {
new Notification(`${messageObject.channel.title}/${messageObject.author.username}`, {
body: messageObject.content
});
} catch(e) {
@ -313,20 +313,20 @@ const app = new Vue({
}
},
processUserListUpdate: async function(e) {
const { category, clientList } = e;
if (!this.userLists[category._id]) this.$set(this.userLists, category._id, []);
this.userLists[category._id] = clientList;
const { channel, clientList } = e;
if (!this.userLists[channel._id]) this.$set(this.userLists, channel._id, []);
this.userLists[channel._id] = clientList;
},
openChatForCategory: async function(categoryId) {
this.gateway.subscribeToCategoryChat(categoryId);
openChatForChannel: async function(channelId) {
this.gateway.subscribeToChannelChat(channelId);
this.selection.category.isChatContext = true;
this.selection.category.browsing = true;
this.selection.category.title = 'Chat';
this.selection.category._id = categoryId;
this.selection.channel.isChatContext = true;
this.selection.channel.browsing = true;
this.selection.channel.title = 'Chat';
this.selection.channel._id = channelId;
},
sendCurrentMessage: async function() {
const status = await this.gateway.sendMessage(this.selection.category._id, this.message.typed);
const status = await this.gateway.sendMessage(this.selection.channel._id, this.message.typed);
if (status === 1) {
this.okNotification('Failed to send message!');
return;
@ -343,9 +343,9 @@ const app = new Vue({
console.log('[DEBUG DUMP] [loggedInUser] (this contains sensitive information about the current logged in user, do not leak it to other people lol)', this.loggedInUser);
},
// Category and post browsing
browseCategories: async function() {
const res = await fetch(`${window.location.origin}/api/v1/content/category/list?count=50`, {
// Channel and post browsing
browseChannels: async function() {
const res = await fetch(`${window.location.origin}/api/v1/content/channel/list?count=50`, {
method: 'GET',
headers: {
'Accept': 'application/json',
@ -356,36 +356,36 @@ const app = new Vue({
if (res.ok) {
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.category._id = '__CATEGORY_LIST';
this.selection.channel.title = 'channels';
this.selection.channel.browsing = true;
this.selection.channel.isChannel = false;
this.selection.channel.isChatContext = false;
this.selection.channel._id = '__CATEGORY_LIST';
this.selection.posts = [];
this.cardButtons = [];
this.button('chat', (post) => {
if (post._id) {
this.openChatForCategory(post._id);
this.openChatForChannel(post._id);
}
});
this.button('topic', (post) => {
this.browse(post);
});
for (let i = 0; i < json.categories.length; i++) {
const v = json.categories[i];
for (let i = 0; i < json.channels.length; i++) {
const v = json.channels[i];
this.selection.posts.push({ title: v.title, body: '', _id: v._id, creator: v.creator });
}
} else {
this.okNotification('Failed to fetch category list');
this.okNotification('Failed to fetch channel list');
}
},
browse: async function(category) {
const { _id, title } = category;
browse: async function(channel) {
const { _id, title } = channel;
const res = await fetch(`${window.location.origin}/api/v1/content/category/${_id}/info`, {
const res = await fetch(`${window.location.origin}/api/v1/content/channel/${_id}/info`, {
method: 'GET',
headers: {
'Accept': 'application/json',
@ -396,39 +396,39 @@ const app = new Vue({
if (res.ok) {
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.channel.title = title;
this.selection.channel._id = _id;
this.selection.channel.browsing = true;
this.selection.channel.isChannel = true;
this.selection.channel.isChatContext = false;
this.selection.posts = [];
this.cardButtons = [];
for (let i = 0; i < json.category.posts.length; i++) {
const v = json.category.posts[i];
for (let i = 0; i < json.channel.posts.length; i++) {
const v = json.channel.posts[i];
this.selection.posts.push({ title: v.title, body: v.body, _id: v._id, creator: v.creator });
}
} else {
this.okNotification('Failed to fetch category');
this.okNotification('Failed to fetch channel');
}
},
refresh: function() {
if (this.selection.category.title === 'categories' && this.selection.category.isCategory === false) {
this.browseCategories();
if (this.selection.channel.title === 'channels' && this.selection.channel.isChannel === false) {
this.browseChannels();
} else {
this.browse(this.selection.category);
this.browse(this.selection.channel);
}
},
button: function(text, click) {
this.cardButtons.push({ text, click });
},
stopBrowsing: function() {
this.selection.category = {
this.selection.channel = {
title: '',
browsing: false,
_id: undefined,
isCategory: false,
isChannel: false,
isChatContext: false
};
this.selection.posts = [];
@ -457,20 +457,20 @@ const app = new Vue({
// Content creation
showCreatePostDialog: function() {
if (!this.selection.category.isCategory) {
this.okNotification('You are not in a category');
if (!this.selection.channel.isChannel) {
this.okNotification('You are not in a channel');
return;
}
this.dialog.show.createPost = true;
},
createPost: async function() {
if (!this.selection.category.isCategory) {
this.okNotification('You are not in a category');
if (!this.selection.channel.isChannel) {
this.okNotification('You are not in a channel');
return;
}
const category = this.selection.category;
const channel = this.selection.channel;
const input = this.dialog.text.createPost;
const res = await fetch(`${window.location.origin}/api/v1/content/post/create`, {
@ -481,7 +481,7 @@ const app = new Vue({
},
credentials: 'include',
body: JSON.stringify({
category: category._id,
channel: channel._id,
title: input.title,
body: input.body
})
@ -490,7 +490,7 @@ const app = new Vue({
if (res.ok) {
this.okNotification('Successfully created post');
this.dialog.show.createPost = false;
this.browse(this.selection.category);
this.browse(this.selection.channel);
return;
} else {
if (res.status === 401 || res.status === 403) {
@ -507,10 +507,10 @@ const app = new Vue({
return;
}
},
createCategory: async function() {
const input = this.dialog.text.createCategory;
createChannel: async function() {
const input = this.dialog.text.createChannel;
const res = await fetch(`${window.location.origin}/api/v1/content/category/create`, {
const res = await fetch(`${window.location.origin}/api/v1/content/channel/create`, {
method: 'POST',
headers: {
'Accept': 'application/json',
@ -523,9 +523,9 @@ const app = new Vue({
});
if (res.ok) {
this.okNotification('Successfully created category');
this.dialog.show.createCategory = false;
this.browseCategories();
this.okNotification('Successfully created channel');
this.dialog.show.createChannel = false;
this.browseChannels();
return;
} else {
if (res.status === 401 || res.status === 403) {
@ -538,7 +538,7 @@ const app = new Vue({
}
const json = await res.json();
this.okNotification(getCreateCategoryError(json));
this.okNotification(getCreateChannelError(json));
return;
}
},

View file

@ -2,13 +2,13 @@ const mongoose = require("mongoose");
const Post = require("./Post");
const User = require("./User");
const categorySchema = new mongoose.Schema({
const channelSchema = new mongoose.Schema({
title: String,
creator: {type: mongoose.Schema.Types.ObjectId, ref: "User"},
posts: [Post.schema]
});
categorySchema.method("getPublicObject", function() {
channelSchema.method("getPublicObject", function() {
return {
title: this.title,
creator: this.populate("creator", User.getPulicFields()).creator,
@ -17,6 +17,6 @@ categorySchema.method("getPublicObject", function() {
};
});
const Category = mongoose.model("Category", categorySchema);
const Channel = mongoose.model("Channel", channelSchema);
module.exports = Category;
module.exports = Channel;

View file

@ -4,7 +4,7 @@ const Post = mongoose.model("Post", {
title: String,
body: String,
creator: {type: mongoose.Schema.Types.ObjectId, ref: "User"},
categoryId: {type: mongoose.Schema.Types.ObjectId, ref: "Category"}
channelId: {type: mongoose.Schema.Types.ObjectId, ref: "Channel"}
});
module.exports = Post;

View file

@ -50,7 +50,7 @@ const main = async () => {
discord.login(secret.discord.token);
const category = client.gateway.subscribeToCategoryChat(LISTEN_ON);
const channel = client.gateway.subscribeToChannelChat(LISTEN_ON);
discord.on('message', (e) => {
if (e.webhookID) return;

View file

@ -59,13 +59,13 @@ GatewayConnection.prototype.connect = function(token) {
this.socket.on('clientListUpdate', (e) => this.emit('clientListUpdate', e));
};
GatewayConnection.prototype.sendMessage = function(categoryId, content, { nickAuthor, destUser }) {
GatewayConnection.prototype.sendMessage = function(channelId, content, { nickAuthor, destUser }) {
if (!this.isConnected) return 1;
if (content.length >= 2000) return 1;
this.socket.emit('message', {
category: {
_id: categoryId
channel: {
_id: channelId
},
nickAuthor,
destUser,
@ -73,16 +73,16 @@ GatewayConnection.prototype.sendMessage = function(categoryId, content, { nickAu
});
};
GatewayConnection.prototype.subscribeToCategoryChat = function(categoryId) {
GatewayConnection.prototype.subscribeToChannelChat = function(channelId) {
if (!this.isConnected) return;
const request = [categoryId];
const request = [channelId];
console.log('[*] [gateway] Subscribing to channel(s)', request);
this.socket.emit('subscribe', request);
return categoryId;
return channelId;
};
module.exports = GatewayConnection;

View file

@ -23,7 +23,7 @@ Packets can also have JSON as a payload:
## Instructions
The terms "channel" and "category" are used interchangeably.
The terms "channel" and "channel" are used interchangeably.
## 0:HELLO
*Part of handshake, Server to client*