mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 06:07:21 +01:00
Improvements to shadow muting (#15543)
* fix test wording * make shadow mute work for dms * shadow mute chat messages * shadow mute invites * oops * refactor mute handling into middleware * correctly throw error * fix * test(chat): expect errors when muted Also fixes the Linux version in the mongo commands. Again. wtf --------- Co-authored-by: Kalista Payne <kalista@habitica.com>
This commit is contained in:
@@ -105,8 +105,8 @@
|
|||||||
"start": "node --watch ./website/server/index.js",
|
"start": "node --watch ./website/server/index.js",
|
||||||
"start:simple": "node ./website/server/index.js",
|
"start:simple": "node ./website/server/index.js",
|
||||||
"debug": "node --watch --inspect ./website/server/index.js",
|
"debug": "node --watch --inspect ./website/server/index.js",
|
||||||
"mongo:dev": "run-rs -v 7.0.23 -l ubuntu2204 --keep --dbpath mongodb-data --number 1 --quiet",
|
"mongo:dev": "run-rs -v 7.0.23 -l ubuntu2214 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||||
"mongo:test": "run-rs -v 7.0.23 -l ubuntu2204 --keep --dbpath mongodb-data-testing --number 1 --quiet",
|
"mongo:test": "run-rs -v 7.0.23 -l ubuntu2214 --keep --dbpath mongodb-data-testing --number 1 --quiet",
|
||||||
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
|
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
|
||||||
"apidoc": "gulp apidoc",
|
"apidoc": "gulp apidoc",
|
||||||
"heroku-postbuild": ".heroku/report_deploy.sh"
|
"heroku-postbuild": ".heroku/report_deploy.sh"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
|
SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
|
||||||
} from '../../../../../website/server/models/group';
|
} from '../../../../../website/server/models/group';
|
||||||
import { MAX_MESSAGE_LENGTH } from '../../../../../website/common/script/constants';
|
import { MAX_MESSAGE_LENGTH, CHAT_FLAG_FROM_SHADOW_MUTE } from '../../../../../website/common/script/constants';
|
||||||
import * as email from '../../../../../website/server/libs/email';
|
import * as email from '../../../../../website/server/libs/email';
|
||||||
|
|
||||||
describe('POST /chat', () => {
|
describe('POST /chat', () => {
|
||||||
@@ -80,17 +80,20 @@ describe('POST /chat', () => {
|
|||||||
member.updateOne({ 'flags.chatRevoked': false });
|
member.updateOne({ 'flags.chatRevoked': false });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not error when chat privileges are revoked when sending a message to a private guild', async () => {
|
it('errors when chat privileges are revoked when sending a message to a private guild', async () => {
|
||||||
await member.updateOne({
|
await member.updateOne({
|
||||||
'flags.chatRevoked': true,
|
'flags.chatRevoked': true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
await expect(member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage }))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
expect(message.message.id).to.exist;
|
code: 401,
|
||||||
|
error: 'NotAuthorized',
|
||||||
|
message: t('chatPrivilegesRevoked'),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not error when chat privileges are revoked when sending a message to a party', async () => {
|
it('errors when chat privileges are revoked when sending a message to a party', async () => {
|
||||||
const { group, members } = await createAndPopulateGroup({
|
const { group, members } = await createAndPopulateGroup({
|
||||||
groupDetails: {
|
groupDetails: {
|
||||||
name: 'Party',
|
name: 'Party',
|
||||||
@@ -106,9 +109,12 @@ describe('POST /chat', () => {
|
|||||||
'auth.timestamps.created': new Date('2022-01-01'),
|
'auth.timestamps.created': new Date('2022-01-01'),
|
||||||
});
|
});
|
||||||
|
|
||||||
const message = await privatePartyMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage });
|
await expect(privatePartyMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage }))
|
||||||
|
.to.eventually.be.rejected.and.eql({
|
||||||
expect(message.message.id).to.exist;
|
code: 401,
|
||||||
|
error: 'NotAuthorized',
|
||||||
|
message: t('chatPrivilegesRevoked'),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -123,7 +129,7 @@ describe('POST /chat', () => {
|
|||||||
member.updateOne({ 'flags.chatShadowMuted': false });
|
member.updateOne({ 'flags.chatShadowMuted': false });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a chat with zero flagCount when sending a message to a private guild', async () => {
|
it('creates a chat with flagCount set when sending a message to a private guild', async () => {
|
||||||
await member.updateOne({
|
await member.updateOne({
|
||||||
'flags.chatShadowMuted': true,
|
'flags.chatShadowMuted': true,
|
||||||
});
|
});
|
||||||
@@ -131,10 +137,10 @@ describe('POST /chat', () => {
|
|||||||
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
const message = await member.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
||||||
|
|
||||||
expect(message.message.id).to.exist;
|
expect(message.message.id).to.exist;
|
||||||
expect(message.message.flagCount).to.eql(0);
|
expect(message.message.flagCount).to.eql(CHAT_FLAG_FROM_SHADOW_MUTE);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a chat with zero flagCount when sending a message to a party', async () => {
|
it('creates a chat with flagCount set when sending a message to a party', async () => {
|
||||||
const { group, members } = await createAndPopulateGroup({
|
const { group, members } = await createAndPopulateGroup({
|
||||||
groupDetails: {
|
groupDetails: {
|
||||||
name: 'Party',
|
name: 'Party',
|
||||||
@@ -153,7 +159,7 @@ describe('POST /chat', () => {
|
|||||||
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage });
|
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage });
|
||||||
|
|
||||||
expect(message.message.id).to.exist;
|
expect(message.message.id).to.exist;
|
||||||
expect(message.message.flagCount).to.eql(0);
|
expect(message.message.flagCount).to.eql(CHAT_FLAG_FROM_SHADOW_MUTE);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,24 @@ describe('Post /groups/:groupId/invite', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fakes sending an invite if user is shadow muted', async () => {
|
||||||
|
const inviterMuted = await inviter.updateOne({ 'flags.chatShadowMuted': true });
|
||||||
|
const userToInvite = await generateUser();
|
||||||
|
|
||||||
|
const response = await inviterMuted.post(`/groups/${group._id}/invite`, {
|
||||||
|
usernames: [userToInvite.auth.local.lowerCaseUsername],
|
||||||
|
});
|
||||||
|
expect(response).to.be.an('Array');
|
||||||
|
expect(response[0]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
|
||||||
|
expect(response[0]._id).to.be.a('String');
|
||||||
|
expect(response[0].id).to.eql(group._id);
|
||||||
|
expect(response[0].name).to.eql(groupName);
|
||||||
|
expect(response[0].inviter).to.eql(inviter._id);
|
||||||
|
|
||||||
|
await expect(userToInvite.get('/user'))
|
||||||
|
.to.eventually.not.have.nested.property('invitations.parties[0].id', group._id);
|
||||||
|
});
|
||||||
|
|
||||||
it('invites a user to a group by username', async () => {
|
it('invites a user to a group by username', async () => {
|
||||||
const userToInvite = await generateUser();
|
const userToInvite = await generateUser();
|
||||||
|
|
||||||
@@ -209,6 +227,24 @@ describe('Post /groups/:groupId/invite', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fakes sending an invite if user is shadow muted', async () => {
|
||||||
|
const inviterMuted = await inviter.updateOne({ 'flags.chatShadowMuted': true });
|
||||||
|
const userToInvite = await generateUser();
|
||||||
|
|
||||||
|
const response = await inviterMuted.post(`/groups/${group._id}/invite`, {
|
||||||
|
uuids: [userToInvite._id],
|
||||||
|
});
|
||||||
|
expect(response).to.be.an('Array');
|
||||||
|
expect(response[0]).to.have.all.keys(['_id', 'id', 'name', 'inviter']);
|
||||||
|
expect(response[0]._id).to.be.a('String');
|
||||||
|
expect(response[0].id).to.eql(group._id);
|
||||||
|
expect(response[0].name).to.eql(groupName);
|
||||||
|
expect(response[0].inviter).to.eql(inviter._id);
|
||||||
|
|
||||||
|
await expect(userToInvite.get('/user'))
|
||||||
|
.to.eventually.not.have.nested.property('invitations.parties[0].id', group._id);
|
||||||
|
});
|
||||||
|
|
||||||
it('invites a user to a group by uuid', async () => {
|
it('invites a user to a group by uuid', async () => {
|
||||||
const userToInvite = await generateUser();
|
const userToInvite = await generateUser();
|
||||||
|
|
||||||
@@ -281,6 +317,19 @@ describe('Post /groups/:groupId/invite', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fakes sending invite when inviter is shadow muted', async () => {
|
||||||
|
const inviterMuted = await inviter.updateOne({ 'flags.chatShadowMuted': true });
|
||||||
|
const res = await inviterMuted.post(`/groups/${group._id}/invite`, {
|
||||||
|
emails: [testInvite],
|
||||||
|
inviter: 'inviter name',
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedUser = await inviterMuted.sync();
|
||||||
|
|
||||||
|
expect(res).to.exist;
|
||||||
|
expect(updatedUser.invitesSent).to.eql(1);
|
||||||
|
});
|
||||||
|
|
||||||
it('returns an error when invite is missing an email', async () => {
|
it('returns an error when invite is missing an email', async () => {
|
||||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||||
emails: [{ name: 'test' }],
|
emails: [{ name: 'test' }],
|
||||||
@@ -405,6 +454,19 @@ describe('Post /groups/:groupId/invite', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fakes sending an invite if user is shadow muted', async () => {
|
||||||
|
const inviterMuted = await inviter.updateOne({ 'flags.chatShadowMuted': true });
|
||||||
|
const newUser = await generateUser();
|
||||||
|
const invite = await inviterMuted.post(`/groups/${group._id}/invite`, {
|
||||||
|
uuids: [newUser._id],
|
||||||
|
emails: [{ name: 'test', email: 'test@habitica.com' }],
|
||||||
|
});
|
||||||
|
const invitedUser = await newUser.get('/user');
|
||||||
|
|
||||||
|
expect(invitedUser.invitations.parties[0]).to.not.exist;
|
||||||
|
expect(invite).to.exist;
|
||||||
|
});
|
||||||
|
|
||||||
it('invites users to a group by uuid and email', async () => {
|
it('invites users to a group by uuid and email', async () => {
|
||||||
const newUser = await generateUser();
|
const newUser = await generateUser();
|
||||||
const invite = await inviter.post(`/groups/${group._id}/invite`, {
|
const invite = await inviter.post(`/groups/${group._id}/invite`, {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ describe('POST /members/send-private-message', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns error when to user has blocked the sender', async () => {
|
it('returns error when recipient has blocked the sender', async () => {
|
||||||
const receiver = await generateUser({ 'inbox.blocks': [userToSendMessage._id] });
|
const receiver = await generateUser({ 'inbox.blocks': [userToSendMessage._id] });
|
||||||
|
|
||||||
await expect(userToSendMessage.post('/members/send-private-message', {
|
await expect(userToSendMessage.post('/members/send-private-message', {
|
||||||
@@ -56,7 +56,7 @@ describe('POST /members/send-private-message', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns error when sender has blocked to user', async () => {
|
it('returns error when sender has blocked recipient', async () => {
|
||||||
const receiver = await generateUser();
|
const receiver = await generateUser();
|
||||||
const sender = await generateUser({ 'inbox.blocks': [receiver._id] });
|
const sender = await generateUser({ 'inbox.blocks': [receiver._id] });
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ describe('POST /members/send-private-message', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns error when to user has opted out of messaging', async () => {
|
it('returns error when recipient has opted out of messaging', async () => {
|
||||||
const receiver = await generateUser({ 'inbox.optOut': true });
|
const receiver = await generateUser({ 'inbox.optOut': true });
|
||||||
|
|
||||||
await expect(userToSendMessage.post('/members/send-private-message', {
|
await expect(userToSendMessage.post('/members/send-private-message', {
|
||||||
@@ -174,7 +174,7 @@ describe('POST /members/send-private-message', () => {
|
|||||||
expect(notification.data.excerpt).to.equal(messageExcerpt);
|
expect(notification.data.excerpt).to.equal(messageExcerpt);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows admin to send when sender has blocked the admin', async () => {
|
it('allows admin to send when recipient has blocked the admin', async () => {
|
||||||
userToSendMessage = await generateUser({
|
userToSendMessage = await generateUser({
|
||||||
'permissions.moderator': true,
|
'permissions.moderator': true,
|
||||||
});
|
});
|
||||||
@@ -202,7 +202,7 @@ describe('POST /members/send-private-message', () => {
|
|||||||
expect(sendersMessageInSendersInbox).to.exist;
|
expect(sendersMessageInSendersInbox).to.exist;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows admin to send when to user has opted out of messaging', async () => {
|
it('allows admin to send when recipient has opted out of messaging', async () => {
|
||||||
userToSendMessage = await generateUser({
|
userToSendMessage = await generateUser({
|
||||||
'permissions.moderator': true,
|
'permissions.moderator': true,
|
||||||
});
|
});
|
||||||
@@ -229,4 +229,58 @@ describe('POST /members/send-private-message', () => {
|
|||||||
expect(sendersMessageInReceiversInbox).to.exist;
|
expect(sendersMessageInReceiversInbox).to.exist;
|
||||||
expect(sendersMessageInSendersInbox).to.exist;
|
expect(sendersMessageInSendersInbox).to.exist;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('sender is shadow muted', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
userToSendMessage = await generateUser({
|
||||||
|
'flags.chatShadowMuted': true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not save the message in the receiver inbox', async () => {
|
||||||
|
const receiver = await generateUser();
|
||||||
|
|
||||||
|
const response = await userToSendMessage.post('/members/send-private-message', {
|
||||||
|
message: messageToSend,
|
||||||
|
toUserId: receiver._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.message.uuid).to.equal(receiver._id);
|
||||||
|
|
||||||
|
const updatedReceiver = await receiver.get('/user');
|
||||||
|
const updatedSender = await userToSendMessage.get('/user');
|
||||||
|
|
||||||
|
const sendersMessageInReceiversInbox = _.find(
|
||||||
|
updatedReceiver.inbox.messages,
|
||||||
|
message => message.uuid === userToSendMessage._id && message.text === messageToSend,
|
||||||
|
);
|
||||||
|
|
||||||
|
const sendersMessageInSendersInbox = _.find(
|
||||||
|
updatedSender.inbox.messages,
|
||||||
|
message => message.uuid === receiver._id && message.text === messageToSend,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(sendersMessageInReceiversInbox).to.not.exist;
|
||||||
|
expect(sendersMessageInSendersInbox).to.exist;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not save the message message twice if recipient is sender', async () => {
|
||||||
|
const response = await userToSendMessage.post('/members/send-private-message', {
|
||||||
|
message: messageToSend,
|
||||||
|
toUserId: userToSendMessage._id,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.message.uuid).to.equal(userToSendMessage._id);
|
||||||
|
|
||||||
|
const updatedSender = await userToSendMessage.get('/user');
|
||||||
|
|
||||||
|
const sendersMessageInSendersInbox = _.find(
|
||||||
|
updatedSender.inbox.messages,
|
||||||
|
message => message.uuid === userToSendMessage._id && message.text === messageToSend,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(sendersMessageInSendersInbox).to.exist;
|
||||||
|
expect(Object.keys(updatedSender.inbox.messages).length).to.equal(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import pick from 'lodash/pick';
|
import pick from 'lodash/pick';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import { authWithHeaders } from '../../middlewares/auth';
|
import { authWithHeaders, chatPrivilegesRequired } from '../../middlewares/auth';
|
||||||
import { model as Group } from '../../models/group';
|
import { model as Group } from '../../models/group';
|
||||||
import { model as User } from '../../models/user';
|
import { model as User } from '../../models/user';
|
||||||
import {
|
import {
|
||||||
@@ -118,7 +118,7 @@ function getBannedWordsFromText (message) {
|
|||||||
api.postChat = {
|
api.postChat = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/groups/:groupId/chat',
|
url: '/groups/:groupId/chat',
|
||||||
middlewares: [authWithHeaders()],
|
middlewares: [authWithHeaders(), chatPrivilegesRequired()],
|
||||||
async handler (req, res) {
|
async handler (req, res) {
|
||||||
const { user } = res.locals;
|
const { user } = res.locals;
|
||||||
const { groupId } = req.params;
|
const { groupId } = req.params;
|
||||||
@@ -161,10 +161,6 @@ api.postChat = {
|
|||||||
throw new BadRequest(res.t('bannedSlurUsed'));
|
throw new BadRequest(res.t('bannedSlurUsed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group.privacy === 'public' && user.flags.chatRevoked) {
|
|
||||||
throw new NotAuthorized(res.t('chatPrivilegesRevoked'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent banned words being posted, except in private guilds/parties
|
// prevent banned words being posted, except in private guilds/parties
|
||||||
// and in certain public guilds with specific topics
|
// and in certain public guilds with specific topics
|
||||||
if (group.privacy === 'public' && !group.bannedWordsAllowed) {
|
if (group.privacy === 'public' && !group.bannedWordsAllowed) {
|
||||||
@@ -204,7 +200,7 @@ api.postChat = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let flagCount = 0;
|
let flagCount = 0;
|
||||||
if (group.privacy === 'public' && user.flags.chatShadowMuted) {
|
if (user.flags.chatShadowMuted) {
|
||||||
flagCount = common.constants.CHAT_FLAG_FROM_SHADOW_MUTE;
|
flagCount = common.constants.CHAT_FLAG_FROM_SHADOW_MUTE;
|
||||||
|
|
||||||
// Email the mods
|
// Email the mods
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import pick from 'lodash/pick';
|
|||||||
import uniqBy from 'lodash/uniqBy';
|
import uniqBy from 'lodash/uniqBy';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { authWithHeaders } from '../../middlewares/auth';
|
import { authWithHeaders, chatPrivilegesRequired } from '../../middlewares/auth';
|
||||||
import {
|
import {
|
||||||
model as Group,
|
model as Group,
|
||||||
basicFields as basicGroupFields,
|
basicFields as basicGroupFields,
|
||||||
@@ -97,8 +97,6 @@ const api = {};
|
|||||||
* @apiError (401) {NotAuthorized} messageInsufficientGems User does not have enough gems (4)
|
* @apiError (401) {NotAuthorized} messageInsufficientGems User does not have enough gems (4)
|
||||||
* @apiError (401) {NotAuthorized} partyMustbePrivate Party must have privacy set to private
|
* @apiError (401) {NotAuthorized} partyMustbePrivate Party must have privacy set to private
|
||||||
* @apiError (401) {NotAuthorized} messageGroupAlreadyInParty
|
* @apiError (401) {NotAuthorized} messageGroupAlreadyInParty
|
||||||
* @apiError (401) {NotAuthorized} chatPrivilegesRevoked You cannot do this because your chat
|
|
||||||
privileges have been removed...
|
|
||||||
*
|
*
|
||||||
* @apiSuccess (201) {Object} data The created group (See <a href="https://github.com/HabitRPG/habitica/blob/develop/website/server/models/group.js" target="_blank">/website/server/models/group.js</a>)
|
* @apiSuccess (201) {Object} data The created group (See <a href="https://github.com/HabitRPG/habitica/blob/develop/website/server/models/group.js" target="_blank">/website/server/models/group.js</a>)
|
||||||
*
|
*
|
||||||
@@ -1099,12 +1097,10 @@ api.removeGroupMember = {
|
|||||||
api.inviteToGroup = {
|
api.inviteToGroup = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/groups/:groupId/invite',
|
url: '/groups/:groupId/invite',
|
||||||
middlewares: [authWithHeaders()],
|
middlewares: [authWithHeaders(), chatPrivilegesRequired()],
|
||||||
async handler (req, res) {
|
async handler (req, res) {
|
||||||
const { user } = res.locals;
|
const { user } = res.locals;
|
||||||
|
|
||||||
if (user.flags.chatRevoked) throw new NotAuthorized(res.t('chatPrivilegesRevoked'));
|
|
||||||
|
|
||||||
req.checkParams('groupId', apiError('groupIdRequired')).notEmpty();
|
req.checkParams('groupId', apiError('groupIdRequired')).notEmpty();
|
||||||
|
|
||||||
if (user.invitesSent >= MAX_EMAIL_INVITES_BY_USER) throw new NotAuthorized(res.t('inviteLimitReached', { techAssistanceEmail: TECH_ASSISTANCE_EMAIL }));
|
if (user.invitesSent >= MAX_EMAIL_INVITES_BY_USER) throw new NotAuthorized(res.t('inviteLimitReached', { techAssistanceEmail: TECH_ASSISTANCE_EMAIL }));
|
||||||
@@ -1131,25 +1127,41 @@ api.inviteToGroup = {
|
|||||||
|
|
||||||
const results = [];
|
const results = [];
|
||||||
|
|
||||||
if (uuids) {
|
if (!user.flags.chatShadowMuted) {
|
||||||
const uuidInvites = uuids.map(uuid => inviteByUUID(uuid, group, user, req, res));
|
if (uuids) {
|
||||||
const uuidResults = await Promise.all(uuidInvites);
|
const uuidInvites = uuids.map(uuid => inviteByUUID(uuid, group, user, req, res));
|
||||||
results.push(...uuidResults);
|
const uuidResults = await Promise.all(uuidInvites);
|
||||||
}
|
results.push(...uuidResults);
|
||||||
|
}
|
||||||
|
|
||||||
if (emails) {
|
if (emails) {
|
||||||
const emailInvites = emails.map(invite => inviteByEmail(invite, group, user, req, res));
|
const emailInvites = emails.map(invite => inviteByEmail(invite, group, user, req, res));
|
||||||
user.invitesSent += emails.length;
|
user.invitesSent += emails.length;
|
||||||
await user.save();
|
await user.save();
|
||||||
const emailResults = await Promise.all(emailInvites);
|
const emailResults = await Promise.all(emailInvites);
|
||||||
results.push(...emailResults);
|
results.push(...emailResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usernames) {
|
if (usernames) {
|
||||||
const usernameInvites = usernames
|
const usernameInvites = usernames
|
||||||
.map(username => inviteByUserName(username, group, user, req, res));
|
.map(username => inviteByUserName(username, group, user, req, res));
|
||||||
const usernameResults = await Promise.all(usernameInvites);
|
const usernameResults = await Promise.all(usernameInvites);
|
||||||
results.push(...usernameResults);
|
results.push(...usernameResults);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const fakeCount = (uuids ? uuids.length : 0)
|
||||||
|
+ (emails ? emails.length : 0)
|
||||||
|
+ (usernames ? usernames.length : 0);
|
||||||
|
results.push(...new Array(fakeCount).fill({
|
||||||
|
id: group._id,
|
||||||
|
_id: group._id,
|
||||||
|
name: group.name,
|
||||||
|
inviter: user._id,
|
||||||
|
}));
|
||||||
|
if (emails) {
|
||||||
|
user.invitesSent += emails.length;
|
||||||
|
await user.save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.respond(200, results);
|
res.respond(200, results);
|
||||||
|
|||||||
@@ -3,30 +3,36 @@ import { getUserInfo, sendTxn as sendTxnEmail } from '../email'; // eslint-disab
|
|||||||
import { sendNotification as sendPushNotification } from '../pushNotifications';
|
import { sendNotification as sendPushNotification } from '../pushNotifications';
|
||||||
|
|
||||||
export async function sentMessage (sender, receiver, message, translate) {
|
export async function sentMessage (sender, receiver, message, translate) {
|
||||||
const messageSent = await sender.sendMessage(receiver, { receiverMsg: message });
|
const fakeSending = sender.flags.chatShadowMuted;
|
||||||
|
const messageSent = await sender.sendMessage(receiver, {
|
||||||
|
receiverMsg: message,
|
||||||
|
fakeSending,
|
||||||
|
});
|
||||||
const senderName = getUserInfo(sender, ['name']).name;
|
const senderName = getUserInfo(sender, ['name']).name;
|
||||||
|
|
||||||
if (receiver.preferences.emailNotifications.newPM !== false) {
|
if (!fakeSending) {
|
||||||
sendTxnEmail(receiver, 'new-pm', [
|
if (receiver.preferences.emailNotifications.newPM !== false) {
|
||||||
{ name: 'SENDER', content: senderName },
|
sendTxnEmail(receiver, 'new-pm', [
|
||||||
]);
|
{ name: 'SENDER', content: senderName },
|
||||||
}
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
if (receiver.preferences.pushNotifications.newPM !== false && messageSent.unformattedText) {
|
if (receiver.preferences.pushNotifications.newPM !== false && messageSent.unformattedText) {
|
||||||
await sendPushNotification(
|
await sendPushNotification(
|
||||||
receiver,
|
receiver,
|
||||||
{
|
{
|
||||||
title: translate(
|
title: translate(
|
||||||
'newPMNotificationTitle',
|
'newPMNotificationTitle',
|
||||||
{ name: getUserInfo(sender, ['name']).name },
|
{ name: getUserInfo(sender, ['name']).name },
|
||||||
receiver.preferences.language,
|
receiver.preferences.language,
|
||||||
),
|
),
|
||||||
message: messageSent.unformattedText,
|
message: messageSent.unformattedText,
|
||||||
identifier: 'newPM',
|
identifier: 'newPM',
|
||||||
category: 'newPM',
|
category: 'newPM',
|
||||||
payload: { replyTo: sender._id, senderName, message: messageSent.unformattedText },
|
payload: { replyTo: sender._id, senderName, message: messageSent.unformattedText },
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return messageSent;
|
return messageSent;
|
||||||
|
|||||||
@@ -145,3 +145,15 @@ export function authWithSession (req, res, next) {
|
|||||||
})
|
})
|
||||||
.catch(next);
|
.catch(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function chatPrivilegesRequired () {
|
||||||
|
return function chatPrivilegesRequiredHandler (req, res, next) {
|
||||||
|
const { user } = res.locals;
|
||||||
|
|
||||||
|
if (user.flags.chatRevoked) {
|
||||||
|
throw new NotAuthorized(res.t('chatPrivilegesRevoked'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ schema.methods.getObjectionsToInteraction = function getObjectionsToInteraction
|
|||||||
schema.methods.sendMessage = async function sendMessage (userToReceiveMessage, options) {
|
schema.methods.sendMessage = async function sendMessage (userToReceiveMessage, options) {
|
||||||
const sender = this;
|
const sender = this;
|
||||||
const senderMsg = options.senderMsg || options.receiverMsg;
|
const senderMsg = options.senderMsg || options.receiverMsg;
|
||||||
|
const { fakeSending } = options;
|
||||||
// whether to save users after sending the message, defaults to true
|
// whether to save users after sending the message, defaults to true
|
||||||
const saveUsers = options.save !== false;
|
const saveUsers = options.save !== false;
|
||||||
|
|
||||||
@@ -165,7 +166,7 @@ schema.methods.sendMessage = async function sendMessage (userToReceiveMessage, o
|
|||||||
// Do not add the message twice when sending it to yourself
|
// Do not add the message twice when sending it to yourself
|
||||||
let newSenderMessage;
|
let newSenderMessage;
|
||||||
|
|
||||||
if (!sendingToYourself) {
|
if (!sendingToYourself || fakeSending) {
|
||||||
newSenderMessage = new Inbox({
|
newSenderMessage = new Inbox({
|
||||||
sent: true,
|
sent: true,
|
||||||
ownerId: sender._id,
|
ownerId: sender._id,
|
||||||
@@ -175,12 +176,13 @@ schema.methods.sendMessage = async function sendMessage (userToReceiveMessage, o
|
|||||||
setUserStyles(newSenderMessage, sender);
|
setUserStyles(newSenderMessage, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
const promises = [newReceiverMessage.save()];
|
const promises = [];
|
||||||
if (!sendingToYourself) promises.push(newSenderMessage.save());
|
if (!fakeSending) promises.push(newReceiverMessage.save());
|
||||||
|
if (!sendingToYourself || fakeSending) promises.push(newSenderMessage.save());
|
||||||
|
|
||||||
if (saveUsers) {
|
if (saveUsers) {
|
||||||
promises.push(sender.save());
|
promises.push(sender.save());
|
||||||
if (!sendingToYourself) promises.push(userToReceiveMessage.save());
|
if (!sendingToYourself && !fakeSending) promises.push(userToReceiveMessage.save());
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|||||||
Reference in New Issue
Block a user