replace all mentions of category with channel for better consistency
This commit is contained in:
parent
e7da5de255
commit
943ed64735
11 changed files with 175 additions and 175 deletions
|
@ -1,5 +1,5 @@
|
||||||
# Brainlet
|
# 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
|
# Resources
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const User = require("../../models/User");
|
const User = require("../../models/User");
|
||||||
const Category = require("../../models/Category");
|
const Channel = require("../../models/Channel");
|
||||||
const Post = require("../../models/Post");
|
const Post = require("../../models/Post");
|
||||||
const config = require("../../config");
|
const config = require("../../config");
|
||||||
const { authenticateEndpoint } = require("./../../common/auth/authfunctions");
|
const { authenticateEndpoint } = require("./../../common/auth/authfunctions");
|
||||||
|
@ -17,7 +17,7 @@ const createLimiter = rateLimit({
|
||||||
|
|
||||||
mongoose.connect(config.mongoUrl, {useNewUrlParser: true, useUnifiedTopology: true});
|
mongoose.connect(config.mongoUrl, {useNewUrlParser: true, useUnifiedTopology: true});
|
||||||
|
|
||||||
app.post("/category/create", [
|
app.post("/channel/create", [
|
||||||
createLimiter,
|
createLimiter,
|
||||||
body("title").not().isEmpty().trim().isLength({ min: 3, max: 32 }).escape()
|
body("title").not().isEmpty().trim().isLength({ min: 3, max: 32 }).escape()
|
||||||
], authenticateEndpoint(async (req, res, user) => {
|
], authenticateEndpoint(async (req, res, user) => {
|
||||||
|
@ -28,7 +28,7 @@ app.post("/category/create", [
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = req.body.title;
|
const title = req.body.title;
|
||||||
const category = await Category.create({
|
const channel = await Channel.create({
|
||||||
title: title,
|
title: title,
|
||||||
creator: user._id,
|
creator: user._id,
|
||||||
posts: []
|
posts: []
|
||||||
|
@ -37,13 +37,13 @@ app.post("/category/create", [
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
error: false,
|
error: false,
|
||||||
message: "SUCCESS_CATEGORY_CREATED",
|
message: "SUCCESS_CATEGORY_CREATED",
|
||||||
category: category.getPublicObject()
|
channel: channel.getPublicObject()
|
||||||
});
|
});
|
||||||
}, undefined, config.roleMap.USER));
|
}, undefined, config.roleMap.USER));
|
||||||
|
|
||||||
app.post("/post/create", [
|
app.post("/post/create", [
|
||||||
createLimiter,
|
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("title").not().isEmpty().trim().isLength({ min: 3, max: 32 }).escape(),
|
||||||
body("body").not().isEmpty().trim().isLength({ min: 3, max: 1000 }).escape(),
|
body("body").not().isEmpty().trim().isLength({ min: 3, max: 1000 }).escape(),
|
||||||
], authenticateEndpoint(async (req, res, user) => {
|
], authenticateEndpoint(async (req, res, user) => {
|
||||||
|
@ -53,7 +53,7 @@ app.post("/post/create", [
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const category = req.body.category;
|
const channel = req.body.channel;
|
||||||
const title = req.body.title;
|
const title = req.body.title;
|
||||||
const content = req.body.body;
|
const content = req.body.body;
|
||||||
|
|
||||||
|
@ -61,10 +61,10 @@ app.post("/post/create", [
|
||||||
post.title = title;
|
post.title = title;
|
||||||
post.body = content;
|
post.body = content;
|
||||||
post.creator = user._id;
|
post.creator = user._id;
|
||||||
post.category = category;
|
post.channel = channel;
|
||||||
|
|
||||||
const r = await Category.updateOne({
|
const r = await Channel.updateOne({
|
||||||
_id: category
|
_id: channel
|
||||||
}, {
|
}, {
|
||||||
$push: { posts: post }
|
$push: { posts: post }
|
||||||
});
|
});
|
||||||
|
@ -86,8 +86,8 @@ app.post("/post/create", [
|
||||||
});
|
});
|
||||||
}, undefined, config.roleMap.USER));
|
}, undefined, config.roleMap.USER));
|
||||||
|
|
||||||
app.get("/category/:category/info", [
|
app.get("/channel/:channel/info", [
|
||||||
param("category").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 })
|
param("channel").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 })
|
||||||
], authenticateEndpoint(async (req, res) => {
|
], authenticateEndpoint(async (req, res) => {
|
||||||
const errors = validationResult(req);
|
const errors = validationResult(req);
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
|
@ -95,13 +95,13 @@ app.get("/category/:category/info", [
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const categoryId = req.params.category;
|
const channelId = req.params.channel;
|
||||||
const category = await Category.findById(categoryId).populate("posts.creator", User.getPulicFields());
|
const channel = await Channel.findById(channelId).populate("posts.creator", User.getPulicFields());
|
||||||
|
|
||||||
// TODO: Implement subscribing to a channel and stuff
|
// TODO: Implement subscribing to a channel and stuff
|
||||||
const users = await User.find().sort({ _id: -1 }).limit(50).select(User.getPulicFields());
|
const users = await User.find().sort({ _id: -1 }).limit(50).select(User.getPulicFields());
|
||||||
|
|
||||||
if (!category) {
|
if (!channel) {
|
||||||
res.status(404).json({
|
res.status(404).json({
|
||||||
error: true,
|
error: true,
|
||||||
message: "ERROR_CATEGORY_NOT_FOUND"
|
message: "ERROR_CATEGORY_NOT_FOUND"
|
||||||
|
@ -112,7 +112,7 @@ app.get("/category/:category/info", [
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
error: false,
|
error: false,
|
||||||
message: "SUCCESS_CATEGORY_DATA_FETCHED",
|
message: "SUCCESS_CATEGORY_DATA_FETCHED",
|
||||||
category: category.getPublicObject(),
|
channel: channel.getPublicObject(),
|
||||||
userInfo: {
|
userInfo: {
|
||||||
userListLimit: 50,
|
userListLimit: 50,
|
||||||
users: users
|
users: users
|
||||||
|
@ -120,19 +120,19 @@ app.get("/category/:category/info", [
|
||||||
});
|
});
|
||||||
}, undefined, config.roleMap.USER));
|
}, 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);
|
let count = parseInt(req.query.count);
|
||||||
if (!Number.isInteger(count)) {
|
if (!Number.isInteger(count)) {
|
||||||
count = 10;
|
count = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This is probably not efficient
|
// 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({
|
res.status(200).json({
|
||||||
error: false,
|
error: false,
|
||||||
message: "SUCCESS_CATEGORY_LIST_FETCHED",
|
message: "SUCCESS_CATEGORY_LIST_FETCHED",
|
||||||
categories
|
channels
|
||||||
});
|
});
|
||||||
}, undefined, config.roleMap.USER));
|
}, undefined, config.roleMap.USER));
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const User = require("../../../models/User");
|
const User = require("../../../models/User");
|
||||||
const secret = require("../../../secret");
|
const secret = require("../../../secret");
|
||||||
const config = require("../../../config");
|
const config = require("../../../config");
|
||||||
const Category = require("../../../models/Category");
|
const Channel = require("../../../models/Channel");
|
||||||
const RateLimiter = require("../../../common/util/ratelimiter");
|
const RateLimiter = require("../../../common/util/ratelimiter");
|
||||||
|
|
||||||
const jwt = require("jsonwebtoken");
|
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 = {
|
const messageObject = {
|
||||||
author: {
|
author: {
|
||||||
username: "__SYSTEM",
|
username: "__SYSTEM",
|
||||||
_id: "5fc69864f15a7c5e504c9a1f"
|
_id: "5fc69864f15a7c5e504c9a1f"
|
||||||
},
|
},
|
||||||
category: {
|
channel: {
|
||||||
title: category.title,
|
title: channel.title,
|
||||||
_id: category._id
|
_id: channel._id
|
||||||
},
|
},
|
||||||
content: message,
|
content: message,
|
||||||
_id: uuid.v4()
|
_id: uuid.v4()
|
||||||
|
@ -53,7 +53,7 @@ GatewayServer.prototype._processCommand = async function(socket, message) {
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "INVALID_COMMAND": {
|
case "INVALID_COMMAND": {
|
||||||
this._sendSystemMessage(socket, "Invalid command.", message.category);
|
this._sendSystemMessage(socket, "Invalid command.", message.channel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "admin/fr": {
|
case "admin/fr": {
|
||||||
|
@ -61,33 +61,33 @@ GatewayServer.prototype._processCommand = async function(socket, message) {
|
||||||
if (socket.user.permissionLevel >= config.roleMap.ADMIN) {
|
if (socket.user.permissionLevel >= config.roleMap.ADMIN) {
|
||||||
this._gateway.emit("refreshClient", { reason: fullCommand[1] || "REFRESH" });
|
this._gateway.emit("refreshClient", { reason: fullCommand[1] || "REFRESH" });
|
||||||
} else {
|
} else {
|
||||||
this._sendSystemMessage(socket, "how about no", message.category);
|
this._sendSystemMessage(socket, "how about no", message.channel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._sendSystemMessage(socket, "Invalid number of arguments.", message.category);
|
this._sendSystemMessage(socket, "Invalid number of arguments.", message.channel);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "admin/fru": {
|
case "admin/fru": {
|
||||||
if (args === 1) {
|
if (args === 1) {
|
||||||
if (socket.user.permissionLevel >= config.roleMap.ADMIN) {
|
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) {
|
if (!user) {
|
||||||
this._sendSystemMessage(socket, "User not found.", message.category);
|
this._sendSystemMessage(socket, "User not found.", message.channel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._gateway.in(user.user.sid).emit("refreshClient", { reason: "REFRESH" });
|
this._gateway.in(user.user.sid).emit("refreshClient", { reason: "REFRESH" });
|
||||||
} else {
|
} else {
|
||||||
this._sendSystemMessage(socket, "how about no", message.category);
|
this._sendSystemMessage(socket, "how about no", message.channel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._sendSystemMessage(socket, "Invalid number of arguments.", message.category);
|
this._sendSystemMessage(socket, "Invalid number of arguments.", message.channel);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
this._sendSystemMessage(socket, "That command does not exist.", message.category);
|
this._sendSystemMessage(socket, "That command does not exist.", message.channel);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,8 +170,8 @@ GatewayServer.prototype.eventSetup = function() {
|
||||||
console.log(`[*] [gateway] [handshake] Got yoo from ${socket.user.username}, connection is finally completed!`);
|
console.log(`[*] [gateway] [handshake] Got yoo from ${socket.user.username}, connection is finally completed!`);
|
||||||
socket.isConnected = true;
|
socket.isConnected = true;
|
||||||
|
|
||||||
socket.on("message", async ({ category, content, nickAuthor, destUser }) => {
|
socket.on("message", async ({ channel, content, nickAuthor, destUser }) => {
|
||||||
if (!category || !content || !socket.joinedCategories || !socket.isConnected || !socket.user || !(typeof content === "string") || !(typeof category._id === "string")) return;
|
if (!channel || !content || !socket.joinedChannels || !socket.isConnected || !socket.user || !(typeof content === "string") || !(typeof channel._id === "string")) return;
|
||||||
content = content.trim();
|
content = content.trim();
|
||||||
if (!content || content === "" || content === " " || content.length >= 2000) return;
|
if (!content || content === "" || content === " " || content.length >= 2000) return;
|
||||||
if (!this.rateLimiter.consoom(socket.user.token)) { // TODO: maybe user ip instead of token?
|
if (!this.rateLimiter.consoom(socket.user.token)) { // TODO: maybe user ip instead of token?
|
||||||
|
@ -179,9 +179,9 @@ GatewayServer.prototype.eventSetup = function() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: When/if category permissions are added, check if the user has permissions for that category
|
// TODO: When/if channel permissions are added, check if the user has permissions for that channel
|
||||||
const categoryTitle = socket.joinedCategories[category._id];
|
const channelTitle = socket.joinedChannels[channel._id];
|
||||||
if (!categoryTitle || !(typeof categoryTitle === "string")) return;
|
if (!channelTitle || !(typeof channelTitle === "string")) return;
|
||||||
|
|
||||||
let messageObject = {
|
let messageObject = {
|
||||||
author: {
|
author: {
|
||||||
|
@ -189,9 +189,9 @@ GatewayServer.prototype.eventSetup = function() {
|
||||||
_id: socket.user._id,
|
_id: socket.user._id,
|
||||||
color: socket.user.color
|
color: socket.user.color
|
||||||
},
|
},
|
||||||
category: {
|
channel: {
|
||||||
title: categoryTitle,
|
title: channelTitle,
|
||||||
_id: category._id
|
_id: channel._id
|
||||||
},
|
},
|
||||||
content: content,
|
content: content,
|
||||||
_id: uuid.v4()
|
_id: uuid.v4()
|
||||||
|
@ -214,32 +214,32 @@ GatewayServer.prototype.eventSetup = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destUser && destUser._id && (typeof destUser._id) === "string") {
|
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;
|
if (!user) return;
|
||||||
|
|
||||||
this._gateway.in(user.user.sid).emit("message", messageObject);
|
this._gateway.in(user.user.sid).emit("message", messageObject);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._gateway.in(category._id).emit("message", messageObject);
|
this._gateway.in(channel._id).emit("message", messageObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("subscribe", async (categories) => {
|
socket.on("subscribe", async (channels) => {
|
||||||
if ( !socket.isConnected || !socket.user || !categories || !Array.isArray(categories) || categories === []) return;
|
if ( !socket.isConnected || !socket.user || !channels || !Array.isArray(channels) || channels === []) return;
|
||||||
try {
|
try {
|
||||||
for (const v of categories) {
|
for (const v of channels) {
|
||||||
if (!v && !(typeof v === "string")) continue;
|
if (!v && !(typeof v === "string")) continue;
|
||||||
// TODO: When/if category permissions are added, check if the user has permissions for that category
|
// TODO: When/if channel permissions are added, check if the user has permissions for that channel
|
||||||
const category = await Category.findById(v);
|
const channel = await Channel.findById(v);
|
||||||
if (category && category.title && category._id) {
|
if (channel && channel.title && channel._id) {
|
||||||
if (!socket.joinedCategories) socket.joinedCategories = {};
|
if (!socket.joinedChannels) socket.joinedChannels = {};
|
||||||
if (socket.joinedCategories[v]) continue;
|
if (socket.joinedChannels[v]) continue;
|
||||||
socket.joinedCategories[v] = category.title;
|
socket.joinedChannels[v] = channel.title;
|
||||||
await socket.join(v);
|
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);
|
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
|
// Socket io automatically adds a user to a room with their own id
|
||||||
if (room === socket.id) return;
|
if (room === socket.id) return;
|
||||||
|
|
||||||
const categoryTitle = socket.joinedCategories[room] || "UNKNOWN";
|
const channelTitle = socket.joinedChannels[room] || "UNKNOWN";
|
||||||
await socket.leave(room);
|
await socket.leave(room);
|
||||||
|
|
||||||
const upd = await this._generateClientListUpdateObject(room, categoryTitle);
|
const upd = await this._generateClientListUpdateObject(room, channelTitle);
|
||||||
socket.in(room).emit("clientListUpdate", upd);
|
socket.in(room).emit("clientListUpdate", upd);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -309,11 +309,11 @@ GatewayServer.prototype._findSocketInRoom = async function(room, userid) {
|
||||||
return updatedClientList[0] || undefined;
|
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);
|
const clientList = await this._getSocketsInRoom(room);
|
||||||
return {
|
return {
|
||||||
category: {
|
channel: {
|
||||||
title: categoryTitle,
|
title: channelTitle,
|
||||||
_id: room
|
_id: room
|
||||||
},
|
},
|
||||||
clientList
|
clientList
|
||||||
|
|
|
@ -3,7 +3,7 @@ const EventEmitter = require("events");
|
||||||
const uuid = require("uuid");
|
const uuid = require("uuid");
|
||||||
|
|
||||||
const User = require("../../../models/User");
|
const User = require("../../../models/User");
|
||||||
const Category = require("../../../models/Category");
|
const Channel = require("../../../models/Channel");
|
||||||
const { parseMessage, opcodeSeparator, getOpcodeByName } = require("./messageparser");
|
const { parseMessage, opcodeSeparator, getOpcodeByName } = require("./messageparser");
|
||||||
const { checkToken } = require("../../../common/auth/authfunctions");
|
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
|
// The user is now successfully authenticated, send the YOO_ACK packet
|
||||||
// TODO: This is probably not efficient
|
// 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 = [];
|
if (!channels) channels = [];
|
||||||
channels = channels.map(x => ({ ...x, _id: x._id.toString() }));
|
channels = channels.map(x => ({ ...x, _id: x._id.toString() }));
|
||||||
|
|
||||||
|
|
|
@ -77,24 +77,24 @@
|
||||||
</md-dialog-content>
|
</md-dialog-content>
|
||||||
</md-dialog>
|
</md-dialog>
|
||||||
|
|
||||||
<md-dialog id="create-category-dialog" :md-active.sync="dialog.show.createCategory">
|
<md-dialog id="create-channel-dialog" :md-active.sync="dialog.show.createChannel">
|
||||||
<md-dialog-title>Create category</md-dialog-title>
|
<md-dialog-title>Create channel</md-dialog-title>
|
||||||
|
|
||||||
<md-dialog-content>
|
<md-dialog-content>
|
||||||
<md-field>
|
<md-field>
|
||||||
<label>Title</label>
|
<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-field>
|
||||||
|
|
||||||
<md-dialog-actions>
|
<md-dialog-actions>
|
||||||
<md-button @click="dialog.show.createCategory = false">Close</md-button>
|
<md-button @click="dialog.show.createChannel = false">Close</md-button>
|
||||||
<md-button class="md-primary" @click="createCategory()">Create</md-button>
|
<md-button class="md-primary" @click="createChannel()">Create</md-button>
|
||||||
</md-dialog-actions>
|
</md-dialog-actions>
|
||||||
</md-dialog-content>
|
</md-dialog-content>
|
||||||
</md-dialog>
|
</md-dialog>
|
||||||
|
|
||||||
<md-dialog id="create-post-dialog" :md-active.sync="dialog.show.createPost">
|
<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-dialog-content>
|
||||||
<md-field>
|
<md-field>
|
||||||
|
@ -137,19 +137,19 @@
|
||||||
</md-menu>
|
</md-menu>
|
||||||
</md-toolbar>
|
</md-toolbar>
|
||||||
|
|
||||||
<md-toolbar v-show="selection.category.browsing" class="md-dense" md-elevation="5">
|
<md-toolbar v-show="selection.channel.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.channel.isChannel && !selection.channel.isChatContext" class="md-title" style="flex: 1">Browsing channel: {{ selection.channel.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.channel.isChannel && !selection.channel.isChatContext" class="md-title" style="flex: 1">Browsing {{ selection.channel.title }}</h3>
|
||||||
<h3 v-if="!selection.category.isCategory && selection.category.isChatContext" class="md-title" style="flex: 1">
|
<h3 v-if="!selection.channel.isChannel && selection.channel.isChatContext" class="md-title" style="flex: 1">
|
||||||
Browsing {{ selection.category.title }} with
|
Browsing {{ selection.channel.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>
|
<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>
|
</h3>
|
||||||
<md-button @click="browseCategories()" v-if="selection.category.isCategory || selection.category.isChatContext"><md-icon>arrow_back</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.category.isChatContext"><md-icon>refresh</md-icon></md-button>
|
<md-button @click="refresh()" v-if="!selection.channel.isChatContext"><md-icon>refresh</md-icon></md-button>
|
||||||
</md-toolbar>
|
</md-toolbar>
|
||||||
|
|
||||||
<div id="posts-container" class="posts-container" v-if="selection.category.browsing">
|
<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.category.isChatContext">
|
<md-card v-for="post in selection.posts" v-bind:key="post._id" v-if="!selection.channel.isChatContext">
|
||||||
<md-card-header>
|
<md-card-header>
|
||||||
<div class="md-title" v-html="post.title"></div>
|
<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>
|
<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-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-actions>
|
||||||
</md-card>
|
</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 class="message-card">
|
||||||
<md-card-header>
|
<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>
|
<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>
|
||||||
</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-speed-dial-target>
|
||||||
<md-icon class="md-morph-initial">add</md-icon>
|
<md-icon class="md-morph-initial">add</md-icon>
|
||||||
<md-icon class="md-morph-final">edit</md-icon>
|
<md-icon class="md-morph-final">edit</md-icon>
|
||||||
</md-speed-dial-target>
|
</md-speed-dial-target>
|
||||||
|
|
||||||
<md-speed-dial-content>
|
<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-icon>add</md-icon>
|
||||||
<md-tooltip md-direction="left">Create a new post</md-tooltip>
|
<md-tooltip md-direction="left">Create a new post</md-tooltip>
|
||||||
</md-button>
|
</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-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-button>
|
||||||
</md-speed-dial-content>
|
</md-speed-dial-content>
|
||||||
</md-speed-dial>
|
</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>
|
<label>Write something interesting, go on!</label>
|
||||||
<md-input v-model="message.typed" v-on:keyup.enter="sendCurrentMessage()"></md-input>
|
<md-input v-model="message.typed" v-on:keyup.enter="sendCurrentMessage()"></md-input>
|
||||||
</md-field>
|
</md-field>
|
||||||
|
|
|
@ -10,8 +10,8 @@ const getCreatePostError = (json) => {
|
||||||
case 'body': {
|
case 'body': {
|
||||||
return 'Invalid content. Must be between 3 and 1000 characters';
|
return 'Invalid content. Must be between 3 and 1000 characters';
|
||||||
}
|
}
|
||||||
case 'category': {
|
case 'channel': {
|
||||||
return 'Invalid category. Something went wrong.';
|
return 'Invalid channel. Something went wrong.';
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
return 'Invalid value sent to server. Something went wrong.';
|
return 'Invalid value sent to server. Something went wrong.';
|
||||||
|
@ -20,7 +20,7 @@ const getCreatePostError = (json) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'ERROR_CATEGORY_NOT_FOUND': {
|
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': {
|
case 'ERROR_ACCESS_DENIED': {
|
||||||
|
@ -33,7 +33,7 @@ const getCreatePostError = (json) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCreateCategoryError = (json) => {
|
const getCreateChannelError = (json) => {
|
||||||
switch (json.message) {
|
switch (json.message) {
|
||||||
case 'ERROR_REQUEST_INVALID_DATA': {
|
case 'ERROR_REQUEST_INVALID_DATA': {
|
||||||
switch (json.errors[0].param) {
|
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 (!this.isConnected) return 1;
|
||||||
if (content.length >= 2000) return 1;
|
if (content.length >= 2000) return 1;
|
||||||
|
|
||||||
this.socket.emit('message', {
|
this.socket.emit('message', {
|
||||||
category: {
|
channel: {
|
||||||
_id: categoryId
|
_id: channelId
|
||||||
},
|
},
|
||||||
content
|
content
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
GatewayConnection.prototype.subscribeToCategoryChat = function(categoryId) {
|
GatewayConnection.prototype.subscribeToChannelChat = function(channelId) {
|
||||||
if (!this.isConnected) return;
|
if (!this.isConnected) return;
|
||||||
|
|
||||||
const request = [categoryId];
|
const request = [channelId];
|
||||||
|
|
||||||
console.log('[*] [gateway] Subscribing to channel(s)', request);
|
console.log('[*] [gateway] Subscribing to channel(s)', request);
|
||||||
|
|
||||||
|
@ -143,11 +143,11 @@ const app = new Vue({
|
||||||
showApp: false,
|
showApp: false,
|
||||||
menuVisible: false,
|
menuVisible: false,
|
||||||
selection: {
|
selection: {
|
||||||
category: {
|
channel: {
|
||||||
title: '',
|
title: '',
|
||||||
browsing: false,
|
browsing: false,
|
||||||
_id: undefined,
|
_id: undefined,
|
||||||
isCategory: false,
|
isChannel: false,
|
||||||
isChatContext: false
|
isChatContext: false
|
||||||
},
|
},
|
||||||
posts: []
|
posts: []
|
||||||
|
@ -156,7 +156,7 @@ const app = new Vue({
|
||||||
dialog: {
|
dialog: {
|
||||||
show: {
|
show: {
|
||||||
createPost: false,
|
createPost: false,
|
||||||
createCategory: false,
|
createChannel: false,
|
||||||
debug: false
|
debug: false
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
|
@ -164,7 +164,7 @@ const app = new Vue({
|
||||||
title: '',
|
title: '',
|
||||||
body: ''
|
body: ''
|
||||||
},
|
},
|
||||||
createCategory: {
|
createChannel: {
|
||||||
title: ''
|
title: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ const app = new Vue({
|
||||||
this.loggedInUser = json.user;
|
this.loggedInUser = json.user;
|
||||||
this.showApp = true;
|
this.showApp = true;
|
||||||
this.performGatewayConnection();
|
this.performGatewayConnection();
|
||||||
this.browseCategories();
|
this.browseChannels();
|
||||||
Notification.requestPermission();
|
Notification.requestPermission();
|
||||||
} else {
|
} else {
|
||||||
this.showApp = false;
|
this.showApp = false;
|
||||||
|
@ -259,9 +259,9 @@ const app = new Vue({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
shouldMergeMessage: function(messageObject, categoryMessageList) {
|
shouldMergeMessage: function(messageObject, channelMessageList) {
|
||||||
const lastMessageIndex = categoryMessageList.length-1;
|
const lastMessageIndex = channelMessageList.length-1;
|
||||||
const lastMessage = categoryMessageList[lastMessageIndex];
|
const lastMessage = channelMessageList[lastMessageIndex];
|
||||||
|
|
||||||
if (!lastMessage) return;
|
if (!lastMessage) return;
|
||||||
if (lastMessage.author._id === messageObject.author._id) {
|
if (lastMessage.author._id === messageObject.author._id) {
|
||||||
|
@ -277,32 +277,32 @@ const app = new Vue({
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
processMessage: async function(messageObject) {
|
processMessage: async function(messageObject) {
|
||||||
if (!this.messages[messageObject.category._id]) this.$set(this.messages, messageObject.category._id, []);
|
if (!this.messages[messageObject.channel._id]) this.$set(this.messages, messageObject.channel._id, []);
|
||||||
const categoryMessageList = this.messages[messageObject.category._id];
|
const channelMessageList = this.messages[messageObject.channel._id];
|
||||||
const lastMessageIndex = categoryMessageList.length-1;
|
const lastMessageIndex = channelMessageList.length-1;
|
||||||
|
|
||||||
if (this.shouldMergeMessage(messageObject, categoryMessageList)) {
|
if (this.shouldMergeMessage(messageObject, channelMessageList)) {
|
||||||
categoryMessageList[lastMessageIndex].content += `\n${messageObject.content}`;
|
channelMessageList[lastMessageIndex].content += `\n${messageObject.content}`;
|
||||||
} else {
|
} 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(() => {
|
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');
|
const container = this.$el.querySelector('#posts-container');
|
||||||
container.scrollTop = container.scrollHeight;
|
container.scrollTop = container.scrollHeight;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageObject.author.username !== this.loggedInUser.username && messageObject.category._id !== this.selection.category._id) {
|
if (messageObject.author.username !== this.loggedInUser.username && messageObject.channel._id !== this.selection.channel._id) {
|
||||||
this.okNotification(`${messageObject.category.title}/${messageObject.author.username}: ${messageObject.content}`);
|
this.okNotification(`${messageObject.channel.title}/${messageObject.author.username}: ${messageObject.content}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageObject.author.username !== this.loggedInUser.username) {
|
if (messageObject.author.username !== this.loggedInUser.username) {
|
||||||
if (Notification.permission === 'granted') {
|
if (Notification.permission === 'granted') {
|
||||||
try {
|
try {
|
||||||
new Notification(`${messageObject.category.title}/${messageObject.author.username}`, {
|
new Notification(`${messageObject.channel.title}/${messageObject.author.username}`, {
|
||||||
body: messageObject.content
|
body: messageObject.content
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
@ -313,20 +313,20 @@ const app = new Vue({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
processUserListUpdate: async function(e) {
|
processUserListUpdate: async function(e) {
|
||||||
const { category, clientList } = e;
|
const { channel, clientList } = e;
|
||||||
if (!this.userLists[category._id]) this.$set(this.userLists, category._id, []);
|
if (!this.userLists[channel._id]) this.$set(this.userLists, channel._id, []);
|
||||||
this.userLists[category._id] = clientList;
|
this.userLists[channel._id] = clientList;
|
||||||
},
|
},
|
||||||
openChatForCategory: async function(categoryId) {
|
openChatForChannel: async function(channelId) {
|
||||||
this.gateway.subscribeToCategoryChat(categoryId);
|
this.gateway.subscribeToChannelChat(channelId);
|
||||||
|
|
||||||
this.selection.category.isChatContext = true;
|
this.selection.channel.isChatContext = true;
|
||||||
this.selection.category.browsing = true;
|
this.selection.channel.browsing = true;
|
||||||
this.selection.category.title = 'Chat';
|
this.selection.channel.title = 'Chat';
|
||||||
this.selection.category._id = categoryId;
|
this.selection.channel._id = channelId;
|
||||||
},
|
},
|
||||||
sendCurrentMessage: async function() {
|
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) {
|
if (status === 1) {
|
||||||
this.okNotification('Failed to send message!');
|
this.okNotification('Failed to send message!');
|
||||||
return;
|
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);
|
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
|
// Channel and post browsing
|
||||||
browseCategories: async function() {
|
browseChannels: async function() {
|
||||||
const res = await fetch(`${window.location.origin}/api/v1/content/category/list?count=50`, {
|
const res = await fetch(`${window.location.origin}/api/v1/content/channel/list?count=50`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
@ -356,36 +356,36 @@ const app = new Vue({
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
|
|
||||||
this.selection.category.title = 'categories';
|
this.selection.channel.title = 'channels';
|
||||||
this.selection.category.browsing = true;
|
this.selection.channel.browsing = true;
|
||||||
this.selection.category.isCategory = false;
|
this.selection.channel.isChannel = false;
|
||||||
this.selection.category.isChatContext = false;
|
this.selection.channel.isChatContext = false;
|
||||||
this.selection.category._id = '__CATEGORY_LIST';
|
this.selection.channel._id = '__CATEGORY_LIST';
|
||||||
this.selection.posts = [];
|
this.selection.posts = [];
|
||||||
|
|
||||||
this.cardButtons = [];
|
this.cardButtons = [];
|
||||||
|
|
||||||
this.button('chat', (post) => {
|
this.button('chat', (post) => {
|
||||||
if (post._id) {
|
if (post._id) {
|
||||||
this.openChatForCategory(post._id);
|
this.openChatForChannel(post._id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.button('topic', (post) => {
|
this.button('topic', (post) => {
|
||||||
this.browse(post);
|
this.browse(post);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < json.categories.length; i++) {
|
for (let i = 0; i < json.channels.length; i++) {
|
||||||
const v = json.categories[i];
|
const v = json.channels[i];
|
||||||
this.selection.posts.push({ title: v.title, body: '', _id: v._id, creator: v.creator });
|
this.selection.posts.push({ title: v.title, body: '', _id: v._id, creator: v.creator });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.okNotification('Failed to fetch category list');
|
this.okNotification('Failed to fetch channel list');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
browse: async function(category) {
|
browse: async function(channel) {
|
||||||
const { _id, title } = category;
|
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',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
@ -396,39 +396,39 @@ const app = new Vue({
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
|
|
||||||
this.selection.category.title = title;
|
this.selection.channel.title = title;
|
||||||
this.selection.category._id = _id;
|
this.selection.channel._id = _id;
|
||||||
this.selection.category.browsing = true;
|
this.selection.channel.browsing = true;
|
||||||
this.selection.category.isCategory = true;
|
this.selection.channel.isChannel = true;
|
||||||
this.selection.category.isChatContext = false;
|
this.selection.channel.isChatContext = false;
|
||||||
this.selection.posts = [];
|
this.selection.posts = [];
|
||||||
|
|
||||||
this.cardButtons = [];
|
this.cardButtons = [];
|
||||||
|
|
||||||
for (let i = 0; i < json.category.posts.length; i++) {
|
for (let i = 0; i < json.channel.posts.length; i++) {
|
||||||
const v = json.category.posts[i];
|
const v = json.channel.posts[i];
|
||||||
this.selection.posts.push({ title: v.title, body: v.body, _id: v._id, creator: v.creator });
|
this.selection.posts.push({ title: v.title, body: v.body, _id: v._id, creator: v.creator });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.okNotification('Failed to fetch category');
|
this.okNotification('Failed to fetch channel');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
if (this.selection.category.title === 'categories' && this.selection.category.isCategory === false) {
|
if (this.selection.channel.title === 'channels' && this.selection.channel.isChannel === false) {
|
||||||
this.browseCategories();
|
this.browseChannels();
|
||||||
} else {
|
} else {
|
||||||
this.browse(this.selection.category);
|
this.browse(this.selection.channel);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
button: function(text, click) {
|
button: function(text, click) {
|
||||||
this.cardButtons.push({ text, click });
|
this.cardButtons.push({ text, click });
|
||||||
},
|
},
|
||||||
stopBrowsing: function() {
|
stopBrowsing: function() {
|
||||||
this.selection.category = {
|
this.selection.channel = {
|
||||||
title: '',
|
title: '',
|
||||||
browsing: false,
|
browsing: false,
|
||||||
_id: undefined,
|
_id: undefined,
|
||||||
isCategory: false,
|
isChannel: false,
|
||||||
isChatContext: false
|
isChatContext: false
|
||||||
};
|
};
|
||||||
this.selection.posts = [];
|
this.selection.posts = [];
|
||||||
|
@ -457,20 +457,20 @@ const app = new Vue({
|
||||||
|
|
||||||
// Content creation
|
// Content creation
|
||||||
showCreatePostDialog: function() {
|
showCreatePostDialog: function() {
|
||||||
if (!this.selection.category.isCategory) {
|
if (!this.selection.channel.isChannel) {
|
||||||
this.okNotification('You are not in a category');
|
this.okNotification('You are not in a channel');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dialog.show.createPost = true;
|
this.dialog.show.createPost = true;
|
||||||
},
|
},
|
||||||
createPost: async function() {
|
createPost: async function() {
|
||||||
if (!this.selection.category.isCategory) {
|
if (!this.selection.channel.isChannel) {
|
||||||
this.okNotification('You are not in a category');
|
this.okNotification('You are not in a channel');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const category = this.selection.category;
|
const channel = this.selection.channel;
|
||||||
const input = this.dialog.text.createPost;
|
const input = this.dialog.text.createPost;
|
||||||
|
|
||||||
const res = await fetch(`${window.location.origin}/api/v1/content/post/create`, {
|
const res = await fetch(`${window.location.origin}/api/v1/content/post/create`, {
|
||||||
|
@ -481,7 +481,7 @@ const app = new Vue({
|
||||||
},
|
},
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
category: category._id,
|
channel: channel._id,
|
||||||
title: input.title,
|
title: input.title,
|
||||||
body: input.body
|
body: input.body
|
||||||
})
|
})
|
||||||
|
@ -490,7 +490,7 @@ const app = new Vue({
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
this.okNotification('Successfully created post');
|
this.okNotification('Successfully created post');
|
||||||
this.dialog.show.createPost = false;
|
this.dialog.show.createPost = false;
|
||||||
this.browse(this.selection.category);
|
this.browse(this.selection.channel);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (res.status === 401 || res.status === 403) {
|
if (res.status === 401 || res.status === 403) {
|
||||||
|
@ -507,10 +507,10 @@ const app = new Vue({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createCategory: async function() {
|
createChannel: async function() {
|
||||||
const input = this.dialog.text.createCategory;
|
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',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
@ -523,9 +523,9 @@ const app = new Vue({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
this.okNotification('Successfully created category');
|
this.okNotification('Successfully created channel');
|
||||||
this.dialog.show.createCategory = false;
|
this.dialog.show.createChannel = false;
|
||||||
this.browseCategories();
|
this.browseChannels();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (res.status === 401 || res.status === 403) {
|
if (res.status === 401 || res.status === 403) {
|
||||||
|
@ -538,7 +538,7 @@ const app = new Vue({
|
||||||
}
|
}
|
||||||
|
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
this.okNotification(getCreateCategoryError(json));
|
this.okNotification(getCreateChannelError(json));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,13 +2,13 @@ const mongoose = require("mongoose");
|
||||||
const Post = require("./Post");
|
const Post = require("./Post");
|
||||||
const User = require("./User");
|
const User = require("./User");
|
||||||
|
|
||||||
const categorySchema = new mongoose.Schema({
|
const channelSchema = new mongoose.Schema({
|
||||||
title: String,
|
title: String,
|
||||||
creator: {type: mongoose.Schema.Types.ObjectId, ref: "User"},
|
creator: {type: mongoose.Schema.Types.ObjectId, ref: "User"},
|
||||||
posts: [Post.schema]
|
posts: [Post.schema]
|
||||||
});
|
});
|
||||||
|
|
||||||
categorySchema.method("getPublicObject", function() {
|
channelSchema.method("getPublicObject", function() {
|
||||||
return {
|
return {
|
||||||
title: this.title,
|
title: this.title,
|
||||||
creator: this.populate("creator", User.getPulicFields()).creator,
|
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;
|
|
@ -4,7 +4,7 @@ const Post = mongoose.model("Post", {
|
||||||
title: String,
|
title: String,
|
||||||
body: String,
|
body: String,
|
||||||
creator: {type: mongoose.Schema.Types.ObjectId, ref: "User"},
|
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;
|
module.exports = Post;
|
|
@ -50,7 +50,7 @@ const main = async () => {
|
||||||
|
|
||||||
discord.login(secret.discord.token);
|
discord.login(secret.discord.token);
|
||||||
|
|
||||||
const category = client.gateway.subscribeToCategoryChat(LISTEN_ON);
|
const channel = client.gateway.subscribeToChannelChat(LISTEN_ON);
|
||||||
|
|
||||||
discord.on('message', (e) => {
|
discord.on('message', (e) => {
|
||||||
if (e.webhookID) return;
|
if (e.webhookID) return;
|
||||||
|
|
|
@ -59,13 +59,13 @@ GatewayConnection.prototype.connect = function(token) {
|
||||||
this.socket.on('clientListUpdate', (e) => this.emit('clientListUpdate', e));
|
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 (!this.isConnected) return 1;
|
||||||
if (content.length >= 2000) return 1;
|
if (content.length >= 2000) return 1;
|
||||||
|
|
||||||
this.socket.emit('message', {
|
this.socket.emit('message', {
|
||||||
category: {
|
channel: {
|
||||||
_id: categoryId
|
_id: channelId
|
||||||
},
|
},
|
||||||
nickAuthor,
|
nickAuthor,
|
||||||
destUser,
|
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;
|
if (!this.isConnected) return;
|
||||||
|
|
||||||
const request = [categoryId];
|
const request = [channelId];
|
||||||
|
|
||||||
console.log('[*] [gateway] Subscribing to channel(s)', request);
|
console.log('[*] [gateway] Subscribing to channel(s)', request);
|
||||||
|
|
||||||
this.socket.emit('subscribe', request);
|
this.socket.emit('subscribe', request);
|
||||||
|
|
||||||
return categoryId;
|
return channelId;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = GatewayConnection;
|
module.exports = GatewayConnection;
|
|
@ -23,7 +23,7 @@ Packets can also have JSON as a payload:
|
||||||
|
|
||||||
## Instructions
|
## Instructions
|
||||||
|
|
||||||
The terms "channel" and "category" are used interchangeably.
|
The terms "channel" and "channel" are used interchangeably.
|
||||||
|
|
||||||
## 0:HELLO
|
## 0:HELLO
|
||||||
*Part of handshake, Server to client*
|
*Part of handshake, Server to client*
|
||||||
|
|
Reference in a new issue