cubash-archive/controllers/conversation.js

244 lines
5.5 KiB
JavaScript

let Type = require('../lib/validation/type');
let validationError = require('../lib/errors/validationError');
let {
User,
Conversation,
Message,
UserConversation,
Sequelize
} = require('../models');
let sequelizeInstance = require('../models').sequelize;
exports.create = async function (userIds, name) {
//Remove duplicates
let userIdsSet = new Set(
userIds.filter(id => typeof id === 'number')
);
let userPromises = [];
let users;
userIdsSet.forEach(id => {
userPromises.push(User.findByPk(id));
});
users = (await Promise.all(userPromises)).filter(user => user !== null);
if(users.length > 1) {
let notNullUserIds = users.map(u => u.id).sort().join(',');
let existingConversation = await Conversation.findOne({
where: {
groupUsers: notNullUserIds
}
});
if(existingConversation) {
throw validationError({
message: 'Channel conversation already exists, you cannot make a duplicate.',
value: userIds
});
} else {
let conversation = await Conversation.create({ name, groupUsers: notNullUserIds });
await conversation.addUsers(users);
return conversation.toJSON();
}
} else {
throw validationError({
message: 'At least two users required for a conversation',
value: userIds
});
}
};
/*
userId of current user
page to search on (offset)
searchString of usernames given by user
*/
exports.getFromUser = async function (userId, page, searchString) {
console.log(userId)
let usernames = (searchString || '').split(/\s+/);
let replacementsObj = {
offset: (page || 0) * 10,
usernamesLen: usernames.length,
usernames: usernames.join('|'),
userId
};
let orClause = '';
if(usernames[0]) {
orClause = 'OR users.username RLIKE :usernames'
replacementsObj.usernamesLen++;
}
let sql = `
SELECT
conversations.*,
messages.content as 'Messages.content',
messages.createdAt as 'Messages.createdAt',
users.username as 'User.username',
users.id as 'User.id',
userconversations.lastRead as 'lastRead'
FROM
(
SELECT ConversationId
FROM userconversations
INNER JOIN users
ON userconversations.UserId = users.id
WHERE users.id = :userId ${orClause}
GROUP BY userconversations.ConversationId
HAVING count(*) = :usernamesLen
) q
JOIN conversations
ON conversations.id = q.ConversationId
JOIN messages
ON conversations.id = messages.ConversationId AND messages.id in
(
SELECT MAX(id)
FROM messages
WHERE messages.ConversationId = conversations.id
)
JOIN users
ON users.id = messages.UserId
JOIN userconversations
ON userconversations.UserId = users.id AND userconversations.ConversationId = conversations.id
ORDER BY messages.id DESC
LIMIT 10
OFFSET :offset
`;
let conversations = await sequelizeInstance.query(sql, {
replacements: replacementsObj,
type: sequelizeInstance.QueryTypes.SELECT,
model: Conversation
});
let mappedPropertiesPromises = conversations.map(async conversation => {
let json = await conversation.setName(userId);
json.Messages = [{
content: json['Messages.content'],
createdAt: json['Messages.createdAt'],
User: {
id: json['User.id'],
username: json['User.username']
}
}];
delete json['Messages.content'];
delete json['Messages.createdAt'];
delete json['User.id'];
delete json['User.username'];
return json;
});
let mappedProperties = await Promise.all(mappedPropertiesPromises);
return {
Conversations: mappedProperties,
continuePagination: mappedProperties.length === 10
};
};
exports.get = async function (userId, conversationId, page) {
let messageCount = await Message.count({
where: {
ConversationId: conversationId
}
});
let offset = messageCount - (page || 1) * 10;
let limit = 10;
if(offset < 0) {
limit = 10 + offset;
offset = 0;
}
let conversation = await Conversation.findByPk(conversationId, {
include: [
{
model: User,
where: { id: userId },
attributes: { exclude: ['hash'] }
},
{
model: Message,
include: [
{
model: User,
attributes: { exclude: ['hash'] }
}
],
limit,
offset,
order: [['id', 'ASC']]
}
]
});
if(!conversation) {
throw validationError({
message: 'Either the conversation doesn\'t exist or you\'re not part of the conversation'
});
} else {
let json = await conversation.setName(userId);
json.continuePagination = !!offset;
return json;
}
};
exports.getUserIds = async function (conversationId) {
let conversation = await Conversation.findByPk(conversationId, {
include: [{ model: User }]
});
if(!conversation) {
throw validationError({
message: 'The conversation doesn\'t exist'
});
} else {
return conversation.Users.map(user => user.id);
}
};
exports.updateLastRead = async function (conversationId, userId) {
let res = await UserConversation.update({
lastRead: new Date()
}, {
where: { ConversationId: conversationId, UserId: userId }
});
//Affected rows should always be 1
if(res[0] !== 1) {
throw validationError({
message: 'Either the conversationId or UserId is invalid'
});
} else {
return true;
}
};
exports.updateName = async function (conversationId, userId, name) {
let conversation = await Conversation.findByPk(conversationId, {
include: [{ model: User }]
});
if(
!conversation ||
conversation.Users.find(u => u.id === userId) === undefined
) {
throw validationError({
message: 'Either the conversationId or userId is invalid'
});
}
let res = await Conversation.update({ name }, {
where: { id: conversationId }
});
return true;
};