parent
e6ba3d84bc
commit
1c2e35bd93
@ -1,119 +0,0 @@ |
||||
RocketChat.Notifications = new class |
||||
constructor: -> |
||||
self = @ |
||||
|
||||
@debug = false |
||||
|
||||
@streamAll = new Meteor.Streamer 'notify-all' |
||||
@streamLogged = new Meteor.Streamer 'notify-logged' |
||||
@streamRoom = new Meteor.Streamer 'notify-room' |
||||
@streamRoomUsers = new Meteor.Streamer 'notify-room-users' |
||||
@streamUser = new Meteor.Streamer 'notify-user' |
||||
|
||||
|
||||
@streamAll.allowWrite('none') |
||||
@streamLogged.allowWrite('none') |
||||
@streamRoom.allowWrite('none') |
||||
@streamRoomUsers.allowWrite (eventName, args...) -> |
||||
[roomId, e] = eventName.split('/') |
||||
|
||||
user = Meteor.users.findOne @userId, {fields: {username: 1}} |
||||
if RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(roomId, @userId)? |
||||
subscriptions = RocketChat.models.Subscriptions.findByRoomIdAndNotUserId(roomId, @userId).fetch() |
||||
for subscription in subscriptions |
||||
RocketChat.Notifications.notifyUser(subscription.u._id, e, args...) |
||||
|
||||
return false |
||||
|
||||
@streamUser.allowWrite('logged') |
||||
|
||||
@streamAll.allowRead('all') |
||||
|
||||
@streamLogged.allowRead('logged') |
||||
|
||||
@streamRoom.allowRead (eventName) -> |
||||
if not @userId? then return false |
||||
|
||||
roomId = eventName.split('/')[0] |
||||
|
||||
user = Meteor.users.findOne @userId, {fields: {username: 1}} |
||||
room = RocketChat.models.Rooms.findOneById(roomId) |
||||
if room.t is 'l' and room.v._id is user._id |
||||
return true |
||||
|
||||
return room.usernames.indexOf(user.username) > -1 |
||||
|
||||
@streamRoomUsers.allowRead('none'); |
||||
|
||||
@streamUser.allowRead (eventName) -> |
||||
userId = eventName.split('/')[0] |
||||
return @userId? and @userId is userId |
||||
|
||||
|
||||
notifyAll: (eventName, args...) -> |
||||
console.log 'notifyAll', arguments if @debug is true |
||||
|
||||
args.unshift eventName |
||||
@streamAll.emit.apply @streamAll, args |
||||
|
||||
notifyLogged: (eventName, args...) -> |
||||
console.log 'notifyLogged', arguments if @debug is true |
||||
|
||||
args.unshift eventName |
||||
@streamLogged.emit.apply @streamLogged, args |
||||
|
||||
notifyRoom: (room, eventName, args...) -> |
||||
console.log 'notifyRoom', arguments if @debug is true |
||||
|
||||
args.unshift "#{room}/#{eventName}" |
||||
@streamRoom.emit.apply @streamRoom, args |
||||
|
||||
notifyUser: (userId, eventName, args...) -> |
||||
console.log 'notifyUser', arguments if @debug is true |
||||
|
||||
args.unshift "#{userId}/#{eventName}" |
||||
@streamUser.emit.apply @streamUser, args |
||||
|
||||
|
||||
notifyAllInThisInstance: (eventName, args...) -> |
||||
console.log 'notifyAll', arguments if @debug is true |
||||
|
||||
args.unshift eventName |
||||
@streamAll.emitWithoutBroadcast.apply @streamAll, args |
||||
|
||||
notifyLoggedInThisInstance: (eventName, args...) -> |
||||
console.log 'notifyLogged', arguments if @debug is true |
||||
|
||||
args.unshift eventName |
||||
@streamLogged.emitWithoutBroadcast.apply @streamLogged, args |
||||
|
||||
notifyRoomInThisInstance: (room, eventName, args...) -> |
||||
console.log 'notifyRoomAndBroadcast', arguments if @debug is true |
||||
|
||||
args.unshift "#{room}/#{eventName}" |
||||
@streamRoom.emitWithoutBroadcast.apply @streamRoom, args |
||||
|
||||
notifyUserInThisInstance: (userId, eventName, args...) -> |
||||
console.log 'notifyUserAndBroadcast', arguments if @debug is true |
||||
|
||||
args.unshift "#{userId}/#{eventName}" |
||||
@streamUser.emitWithoutBroadcast.apply @streamUser, args |
||||
|
||||
|
||||
## Permissions for client |
||||
|
||||
# Enable emit for event typing for rooms and add username to event data |
||||
func = (eventName, username) -> |
||||
[room, e] = eventName.split('/') |
||||
|
||||
if e is 'webrtc' |
||||
return true |
||||
|
||||
if e is 'typing' |
||||
user = Meteor.users.findOne(@userId, {fields: {username: 1}}) |
||||
if user?.username is username |
||||
return true |
||||
|
||||
return false |
||||
|
||||
RocketChat.Notifications.streamRoom.allowWrite func |
@ -0,0 +1,132 @@ |
||||
RocketChat.Notifications = new class { |
||||
constructor() { |
||||
this.debug = false; |
||||
this.streamAll = new Meteor.Streamer('notify-all'); |
||||
this.streamLogged = new Meteor.Streamer('notify-logged'); |
||||
this.streamRoom = new Meteor.Streamer('notify-room'); |
||||
this.streamRoomUsers = new Meteor.Streamer('notify-room-users'); |
||||
this.streamUser = new Meteor.Streamer('notify-user'); |
||||
this.streamAll.allowWrite('none'); |
||||
this.streamLogged.allowWrite('none'); |
||||
this.streamRoom.allowWrite('none'); |
||||
this.streamRoomUsers.allowWrite(function(eventName, ...args) { |
||||
const [roomId, e] = eventName.split('/'); |
||||
// const user = Meteor.users.findOne(this.userId, {
|
||||
// fields: {
|
||||
// username: 1
|
||||
// }
|
||||
// });
|
||||
if (RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(roomId, this.userId) != null) { |
||||
const subscriptions = RocketChat.models.Subscriptions.findByRoomIdAndNotUserId(roomId, this.userId).fetch(); |
||||
subscriptions.forEach(subscription => RocketChat.Notifications.notifyUser(subscription.u._id, e, ...args)); |
||||
} |
||||
return false; |
||||
}); |
||||
this.streamUser.allowWrite('logged'); |
||||
this.streamAll.allowRead('all'); |
||||
this.streamLogged.allowRead('logged'); |
||||
this.streamRoom.allowRead(function(eventName) { |
||||
if (this.userId == null) { |
||||
return false; |
||||
} |
||||
const [roomId] = eventName.split('/'); |
||||
const user = Meteor.users.findOne(this.userId, { |
||||
fields: { |
||||
username: 1 |
||||
} |
||||
}); |
||||
const room = RocketChat.models.Rooms.findOneById(roomId); |
||||
if (room.t === 'l' && room.v._id === user._id) { |
||||
return true; |
||||
} |
||||
return room.usernames.indexOf(user.username) > -1; |
||||
}); |
||||
this.streamRoomUsers.allowRead('none'); |
||||
this.streamUser.allowRead(function(eventName) { |
||||
const [userId] = eventName.split('/'); |
||||
return (this.userId != null) && this.userId === userId; |
||||
}); |
||||
} |
||||
|
||||
notifyAll(eventName, ...args) { |
||||
if (this.debug === true) { |
||||
console.log('notifyAll', arguments); |
||||
} |
||||
args.unshift(eventName); |
||||
return this.streamAll.emit.apply(this.streamAll, args); |
||||
} |
||||
|
||||
notifyLogged(eventName, ...args) { |
||||
if (this.debug === true) { |
||||
console.log('notifyLogged', arguments); |
||||
} |
||||
args.unshift(eventName); |
||||
return this.streamLogged.emit.apply(this.streamLogged, args); |
||||
} |
||||
|
||||
notifyRoom(room, eventName, ...args) { |
||||
if (this.debug === true) { |
||||
console.log('notifyRoom', arguments); |
||||
} |
||||
args.unshift(`${ room }/${ eventName }`); |
||||
return this.streamRoom.emit.apply(this.streamRoom, args); |
||||
} |
||||
|
||||
notifyUser(userId, eventName, ...args) { |
||||
if (this.debug === true) { |
||||
console.log('notifyUser', arguments); |
||||
} |
||||
args.unshift(`${ userId }/${ eventName }`); |
||||
return this.streamUser.emit.apply(this.streamUser, args); |
||||
} |
||||
|
||||
notifyAllInThisInstance(eventName, ...args) { |
||||
if (this.debug === true) { |
||||
console.log('notifyAll', arguments); |
||||
} |
||||
args.unshift(eventName); |
||||
return this.streamAll.emitWithoutBroadcast.apply(this.streamAll, args); |
||||
} |
||||
|
||||
notifyLoggedInThisInstance(eventName, ...args) { |
||||
if (this.debug === true) { |
||||
console.log('notifyLogged', arguments); |
||||
} |
||||
args.unshift(eventName); |
||||
return this.streamLogged.emitWithoutBroadcast.apply(this.streamLogged, args); |
||||
} |
||||
|
||||
notifyRoomInThisInstance(room, eventName, ...args) { |
||||
if (this.debug === true) { |
||||
console.log('notifyRoomAndBroadcast', arguments); |
||||
} |
||||
args.unshift(`${ room }/${ eventName }`); |
||||
return this.streamRoom.emitWithoutBroadcast.apply(this.streamRoom, args); |
||||
} |
||||
|
||||
notifyUserInThisInstance(userId, eventName, ...args) { |
||||
if (this.debug === true) { |
||||
console.log('notifyUserAndBroadcast', arguments); |
||||
} |
||||
args.unshift(`${ userId }/${ eventName }`); |
||||
return this.streamUser.emitWithoutBroadcast.apply(this.streamUser, args); |
||||
} |
||||
}; |
||||
|
||||
RocketChat.Notifications.streamRoom.allowWrite(function(eventName, username) { |
||||
const [, e] = eventName.split('/'); |
||||
if (e === 'webrtc') { |
||||
return true; |
||||
} |
||||
if (e === 'typing') { |
||||
const user = Meteor.users.findOne(this.userId, { |
||||
fields: { |
||||
username: 1 |
||||
} |
||||
}); |
||||
if (user != null && user.username === username) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
}); |
@ -0,0 +1,20 @@ |
||||
RocketChat.checkUsernameAvailability = function(username) { |
||||
return RocketChat.settings.get('Accounts_BlockedUsernameList', function(key, value) { |
||||
const usernameBlackList = _.map(value.split(','), function(username) { |
||||
return username.trim(); |
||||
}); |
||||
if (usernameBlackList.length !== 0) { |
||||
if (usernameBlackList.every(restrictedUsername => { |
||||
const regex = new RegExp(`^${ s.escapeRegExp(restrictedUsername) }$`, 'i'); |
||||
return !regex.test(s.trim(s.escapeRegExp(username))); |
||||
})) { |
||||
return !Meteor.users.findOne({ |
||||
username: { |
||||
$regex: new RegExp(`^${ s.trim(s.escapeRegExp(username)) }$`, 'i') |
||||
} |
||||
}); |
||||
} |
||||
return false; |
||||
} |
||||
}); |
||||
}; |
@ -1,50 +0,0 @@ |
||||
RocketChat.sendMessage = (user, message, room, upsert = false) -> |
||||
if not user or not message or not room._id |
||||
return false |
||||
|
||||
unless message.ts? |
||||
message.ts = new Date() |
||||
|
||||
message.u = _.pick user, ['_id','username'] |
||||
|
||||
if not Match.test(message.msg, String) |
||||
message.msg = '' |
||||
|
||||
message.rid = room._id |
||||
|
||||
if not room.usernames? || room.usernames.length is 0 |
||||
updated_room = RocketChat.models.Rooms.findOneById(room._id) |
||||
if updated_room? |
||||
room = updated_room |
||||
else |
||||
room.usernames = [] |
||||
|
||||
if message.parseUrls isnt false |
||||
if urls = message.msg.match /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]*)?\??([-\+=&!:;%@\/\.\,\w]+)?(?:#([^\s\)]+))?)?/g |
||||
message.urls = urls.map (url) -> url: url |
||||
|
||||
message = RocketChat.callbacks.run 'beforeSaveMessage', message |
||||
|
||||
# Avoid saving sandstormSessionId to the database |
||||
sandstormSessionId = null |
||||
if message.sandstormSessionId |
||||
sandstormSessionId = message.sandstormSessionId |
||||
delete message.sandstormSessionId |
||||
|
||||
if message._id? and upsert |
||||
_id = message._id |
||||
delete message._id |
||||
RocketChat.models.Messages.upsert {_id: _id, 'u._id': message.u._id}, message |
||||
message._id = _id |
||||
else |
||||
message._id = RocketChat.models.Messages.insert message |
||||
|
||||
### |
||||
Defer other updates as their return is not interesting to the user |
||||
### |
||||
Meteor.defer -> |
||||
# Execute all callbacks |
||||
message.sandstormSessionId = sandstormSessionId |
||||
RocketChat.callbacks.run 'afterSaveMessage', message, room |
||||
|
||||
return message |
@ -0,0 +1,59 @@ |
||||
RocketChat.sendMessage = function(user, message, room, upsert = false) { |
||||
if (!user || !message || !room._id) { |
||||
return false; |
||||
} |
||||
if (message.ts == null) { |
||||
message.ts = new Date(); |
||||
} |
||||
message.u = _.pick(user, ['_id', 'username', 'name']); |
||||
if (!Match.test(message.msg, String)) { |
||||
message.msg = ''; |
||||
} |
||||
message.rid = room._id; |
||||
if (room.usernames || room.usernames.length === 0) { |
||||
const updated_room = RocketChat.models.Rooms.findOneById(room._id); |
||||
if (updated_room != null) { |
||||
room = updated_room; |
||||
} else { |
||||
room.usernames = []; |
||||
} |
||||
} |
||||
if (message.parseUrls !== false) { |
||||
const urls = message.msg.match(/([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]*)?\??([-\+=&!:;%@\/\.\,\w]+)?(?:#([^\s\)]+))?)?/g); |
||||
if (urls) { |
||||
message.urls = urls.map(function(url) { |
||||
return { |
||||
url |
||||
}; |
||||
}); |
||||
} |
||||
} |
||||
message = RocketChat.callbacks.run('beforeSaveMessage', message); |
||||
// Avoid saving sandstormSessionId to the database
|
||||
let sandstormSessionId = null; |
||||
if (message.sandstormSessionId) { |
||||
sandstormSessionId = message.sandstormSessionId; |
||||
delete message.sandstormSessionId; |
||||
} |
||||
if (message._id && upsert) { |
||||
const _id = message._id; |
||||
delete message._id; |
||||
RocketChat.models.Messages.upsert({ |
||||
_id, |
||||
'u._id': message.u._id |
||||
}, message); |
||||
message._id = _id; |
||||
} else { |
||||
message._id = RocketChat.models.Messages.insert(message); |
||||
} |
||||
|
||||
/* |
||||
Defer other updates as their return is not interesting to the user |
||||
*/ |
||||
Meteor.defer(() => { |
||||
// Execute all callbacks
|
||||
message.sandstormSessionId = sandstormSessionId; |
||||
return RocketChat.callbacks.run('afterSaveMessage', message, room); |
||||
}); |
||||
return message; |
||||
}; |
@ -1,77 +0,0 @@ |
||||
RocketChat._setUsername = (userId, username) -> |
||||
username = s.trim username |
||||
if not userId or not username |
||||
return false |
||||
|
||||
try |
||||
nameValidation = new RegExp '^' + RocketChat.settings.get('UTF8_Names_Validation') + '$' |
||||
catch |
||||
nameValidation = new RegExp '^[0-9a-zA-Z-_.]+$' |
||||
|
||||
if not nameValidation.test username |
||||
return false |
||||
|
||||
user = RocketChat.models.Users.findOneById userId |
||||
|
||||
# User already has desired username, return |
||||
if user.username is username |
||||
return user |
||||
|
||||
previousUsername = user.username |
||||
|
||||
# Check username availability or if the user already owns a different casing of the name |
||||
if ( !previousUsername or !(username.toLowerCase() == previousUsername.toLowerCase())) |
||||
unless RocketChat.checkUsernameAvailability username |
||||
return false |
||||
|
||||
# If first time setting username, send Enrollment Email |
||||
try |
||||
if not previousUsername and user.emails?.length > 0 and RocketChat.settings.get 'Accounts_Enrollment_Email' |
||||
Accounts.sendEnrollmentEmail(user._id) |
||||
catch error |
||||
|
||||
user.username = username |
||||
|
||||
# If first time setting username, check if should set default avatar |
||||
if not previousUsername and RocketChat.settings.get('Accounts_SetDefaultAvatar') is true |
||||
avatarSuggestions = getAvatarSuggestionForUser user |
||||
for service, avatarData of avatarSuggestions |
||||
if service isnt 'gravatar' |
||||
RocketChat.setUserAvatar(user, avatarData.blob, avatarData.contentType, service) |
||||
gravatar = null |
||||
break |
||||
else |
||||
gravatar = avatarData |
||||
if gravatar? |
||||
RocketChat.setUserAvatar(user, gravatar.blob, gravatar.contentType, 'gravatar') |
||||
|
||||
# Username is available; if coming from old username, update all references |
||||
if previousUsername |
||||
RocketChat.models.Messages.updateAllUsernamesByUserId user._id, username |
||||
RocketChat.models.Messages.updateUsernameOfEditByUserId user._id, username |
||||
|
||||
RocketChat.models.Messages.findByMention(previousUsername).forEach (msg) -> |
||||
updatedMsg = msg.msg.replace(new RegExp("@#{previousUsername}", "ig"), "@#{username}") |
||||
RocketChat.models.Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername msg._id, previousUsername, username, updatedMsg |
||||
|
||||
RocketChat.models.Rooms.replaceUsername previousUsername, username |
||||
RocketChat.models.Rooms.replaceMutedUsername previousUsername, username |
||||
RocketChat.models.Rooms.replaceUsernameOfUserByUserId user._id, username |
||||
|
||||
RocketChat.models.Subscriptions.setUserUsernameByUserId user._id, username |
||||
RocketChat.models.Subscriptions.setNameForDirectRoomsWithOldName previousUsername, username |
||||
|
||||
rs = RocketChatFileAvatarInstance.getFileWithReadStream(encodeURIComponent("#{previousUsername}.jpg")) |
||||
if rs? |
||||
RocketChatFileAvatarInstance.deleteFile encodeURIComponent("#{username}.jpg") |
||||
ws = RocketChatFileAvatarInstance.createWriteStream encodeURIComponent("#{username}.jpg"), rs.contentType |
||||
ws.on 'end', Meteor.bindEnvironment -> |
||||
RocketChatFileAvatarInstance.deleteFile encodeURIComponent("#{previousUsername}.jpg") |
||||
rs.readStream.pipe(ws) |
||||
|
||||
# Set new username |
||||
RocketChat.models.Users.setUsername user._id, username |
||||
return user |
||||
|
||||
RocketChat.setUsername = RocketChat.RateLimiter.limitFunction RocketChat._setUsername, 1, 60000, |
||||
0: () -> return not Meteor.userId() or not RocketChat.authz.hasPermission(Meteor.userId(), 'edit-other-user-info') # Administrators have permission to change others usernames, so don't limit those |
@ -0,0 +1,85 @@ |
||||
|
||||
RocketChat._setUsername = function(userId, u) { |
||||
const username = s.trim(u); |
||||
if (!userId || !username) { |
||||
return false; |
||||
} |
||||
let nameValidation; |
||||
try { |
||||
nameValidation = new RegExp(`^${ RocketChat.settings.get('UTF8_Names_Validation') }$`); |
||||
} catch (error) { |
||||
nameValidation = new RegExp('^[0-9a-zA-Z-_.]+$'); |
||||
} |
||||
if (!nameValidation.test(username)) { |
||||
return false; |
||||
} |
||||
const user = RocketChat.models.Users.findOneById(userId); |
||||
// User already has desired username, return
|
||||
if (user.username === username) { |
||||
return user; |
||||
} |
||||
const previousUsername = user.username; |
||||
// Check username availability or if the user already owns a different casing of the name
|
||||
if (!previousUsername || !(username.toLowerCase() === previousUsername.toLowerCase())) { |
||||
if (!RocketChat.checkUsernameAvailability(username)) { |
||||
return false; |
||||
} |
||||
} |
||||
//If first time setting username, send Enrollment Email
|
||||
try { |
||||
if (!previousUsername && user.emails && user.emails.length > 0 && RocketChat.settings.get('Accounts_Enrollment_Email')) { |
||||
Accounts.sendEnrollmentEmail(user._id); |
||||
} |
||||
} catch (e) { |
||||
console.error(e); |
||||
} |
||||
/* globals getAvatarSuggestionForUser */ |
||||
user.username = username; |
||||
if (!previousUsername && RocketChat.settings.get('Accounts_SetDefaultAvatar') === true) { |
||||
const avatarSuggestions = getAvatarSuggestionForUser(user); |
||||
let gravatar; |
||||
Object.keys(avatarSuggestions).some(service => { |
||||
const avatarData = avatarSuggestions[service]; |
||||
if (service !== 'gravatar') { |
||||
RocketChat.setUserAvatar(user, avatarData.blob, avatarData.contentType, service); |
||||
gravatar = null; |
||||
return true; |
||||
} else { |
||||
gravatar = avatarData; |
||||
} |
||||
}); |
||||
if (gravatar != null) { |
||||
RocketChat.setUserAvatar(user, gravatar.blob, gravatar.contentType, 'gravatar'); |
||||
} |
||||
} |
||||
// Username is available; if coming from old username, update all references
|
||||
if (previousUsername) { |
||||
RocketChat.models.Messages.updateAllUsernamesByUserId(user._id, username); |
||||
RocketChat.models.Messages.updateUsernameOfEditByUserId(user._id, username); |
||||
RocketChat.models.Messages.findByMention(previousUsername).forEach(function(msg) { |
||||
const updatedMsg = msg.msg.replace(new RegExp(`@${ previousUsername }`, 'ig'), `@${ username }`); |
||||
return RocketChat.models.Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername(msg._id, previousUsername, username, updatedMsg); |
||||
}); |
||||
RocketChat.models.Rooms.replaceUsername(previousUsername, username); |
||||
RocketChat.models.Rooms.replaceMutedUsername(previousUsername, username); |
||||
RocketChat.models.Rooms.replaceUsernameOfUserByUserId(user._id, username); |
||||
RocketChat.models.Subscriptions.setUserUsernameByUserId(user._id, username); |
||||
RocketChat.models.Subscriptions.setNameForDirectRoomsWithOldName(previousUsername, username); |
||||
const rs = RocketChatFileAvatarInstance.getFileWithReadStream(encodeURIComponent(`${ previousUsername }.jpg`)); |
||||
if (rs != null) { |
||||
RocketChatFileAvatarInstance.deleteFile(encodeURIComponent(`${ username }.jpg`)); |
||||
const ws = RocketChatFileAvatarInstance.createWriteStream(encodeURIComponent(`${ username }.jpg`), rs.contentType); |
||||
ws.on('end', Meteor.bindEnvironment(() => RocketChatFileAvatarInstance.deleteFile(encodeURIComponent(`${ previousUsername }.jpg`)))); |
||||
rs.readStream.pipe(ws); |
||||
} |
||||
} |
||||
// Set new username*
|
||||
RocketChat.models.Users.setUsername(user._id, username); |
||||
return user; |
||||
}; |
||||
|
||||
RocketChat.setUsername = RocketChat.RateLimiter.limitFunction(RocketChat._setUsername, 1, 60000, { |
||||
[0](userId) { |
||||
return !userId || !RocketChat.authz.hasPermission(userId, 'edit-other-user-info'); |
||||
} |
||||
}); |
@ -1,248 +0,0 @@ |
||||
blockedSettings = {} |
||||
process.env.SETTINGS_BLOCKED?.split(',').forEach (settingId) -> |
||||
blockedSettings[settingId] = 1 |
||||
|
||||
hiddenSettings = {} |
||||
process.env.SETTINGS_HIDDEN?.split(',').forEach (settingId) -> |
||||
hiddenSettings[settingId] = 1 |
||||
|
||||
RocketChat.settings._sorter = {} |
||||
|
||||
### |
||||
# Add a setting |
||||
# @param {String} _id |
||||
# @param {Mixed} value |
||||
# @param {Object} setting |
||||
### |
||||
RocketChat.settings.add = (_id, value, options = {}) -> |
||||
# console.log '[functions] RocketChat.settings.add -> '.green, 'arguments:', arguments |
||||
|
||||
if not _id or |
||||
not value? and not process?.env?['OVERWRITE_SETTING_' + _id]? |
||||
return false |
||||
|
||||
RocketChat.settings._sorter[options.group] ?= 0 |
||||
|
||||
options.packageValue = value |
||||
options.valueSource = 'packageValue' |
||||
options.hidden = false |
||||
options.blocked = options.blocked || false |
||||
options.sorter ?= RocketChat.settings._sorter[options.group]++ |
||||
|
||||
if options.enableQuery? |
||||
options.enableQuery = JSON.stringify options.enableQuery |
||||
|
||||
if options.i18nDefaultQuery? |
||||
options.i18nDefaultQuery = JSON.stringify options.i18nDefaultQuery |
||||
|
||||
if process?.env?[_id]? |
||||
value = process.env[_id] |
||||
if value.toLowerCase() is "true" |
||||
value = true |
||||
else if value.toLowerCase() is "false" |
||||
value = false |
||||
options.processEnvValue = value |
||||
options.valueSource = 'processEnvValue' |
||||
|
||||
else if Meteor.settings?[_id]? |
||||
value = Meteor.settings[_id] |
||||
options.meteorSettingsValue = value |
||||
options.valueSource = 'meteorSettingsValue' |
||||
|
||||
if not options.i18nLabel? |
||||
options.i18nLabel = _id |
||||
|
||||
# Default description i18n key will be the setting name + "_Description" (eg: LDAP_Enable -> LDAP_Enable_Description) |
||||
if not options.i18nDescription? |
||||
options.i18nDescription = "#{_id}_Description" |
||||
|
||||
if blockedSettings[_id]? |
||||
options.blocked = true |
||||
|
||||
if hiddenSettings[_id]? |
||||
options.hidden = true |
||||
|
||||
if process?.env?['OVERWRITE_SETTING_' + _id]? |
||||
value = process.env['OVERWRITE_SETTING_' + _id] |
||||
if value.toLowerCase() is "true" |
||||
value = true |
||||
else if value.toLowerCase() is "false" |
||||
value = false |
||||
options.value = value |
||||
options.processEnvValue = value |
||||
options.valueSource = 'processEnvValue' |
||||
|
||||
updateOperations = |
||||
$set: options |
||||
$setOnInsert: |
||||
createdAt: new Date |
||||
|
||||
if options.editor? |
||||
updateOperations.$setOnInsert.editor = options.editor |
||||
delete options.editor |
||||
|
||||
if not options.value? |
||||
if options.force is true |
||||
updateOperations.$set.value = options.packageValue |
||||
else |
||||
updateOperations.$setOnInsert.value = value |
||||
|
||||
query = _.extend { _id: _id }, updateOperations.$set |
||||
|
||||
if not options.section? |
||||
updateOperations.$unset = { section: 1 } |
||||
query.section = { $exists: false } |
||||
|
||||
existantSetting = RocketChat.models.Settings.db.findOne(query) |
||||
|
||||
if existantSetting? |
||||
if not existantSetting.editor? and updateOperations.$setOnInsert.editor? |
||||
updateOperations.$set.editor = updateOperations.$setOnInsert.editor |
||||
delete updateOperations.$setOnInsert.editor |
||||
else |
||||
updateOperations.$set.ts = new Date |
||||
|
||||
return RocketChat.models.Settings.upsert { _id: _id }, updateOperations |
||||
|
||||
|
||||
|
||||
### |
||||
# Add a setting group |
||||
# @param {String} _id |
||||
### |
||||
RocketChat.settings.addGroup = (_id, options = {}, cb) -> |
||||
# console.log '[functions] RocketChat.settings.addGroup -> '.green, 'arguments:', arguments |
||||
|
||||
if not _id |
||||
return false |
||||
|
||||
if _.isFunction(options) |
||||
cb = options |
||||
options = {} |
||||
|
||||
if not options.i18nLabel? |
||||
options.i18nLabel = _id |
||||
|
||||
if not options.i18nDescription? |
||||
options.i18nDescription = "#{_id}_Description" |
||||
|
||||
options.ts = new Date |
||||
options.blocked = false |
||||
options.hidden = false |
||||
|
||||
if blockedSettings[_id]? |
||||
options.blocked = true |
||||
|
||||
if hiddenSettings[_id]? |
||||
options.hidden = true |
||||
|
||||
RocketChat.models.Settings.upsert { _id: _id }, |
||||
$set: options |
||||
$setOnInsert: |
||||
type: 'group' |
||||
createdAt: new Date |
||||
|
||||
if cb? |
||||
cb.call |
||||
add: (id, value, options = {}) -> |
||||
options.group = _id |
||||
RocketChat.settings.add id, value, options |
||||
|
||||
section: (section, cb) -> |
||||
cb.call |
||||
add: (id, value, options = {}) -> |
||||
options.group = _id |
||||
options.section = section |
||||
RocketChat.settings.add id, value, options |
||||
|
||||
return |
||||
|
||||
|
||||
### |
||||
# Remove a setting by id |
||||
# @param {String} _id |
||||
### |
||||
RocketChat.settings.removeById = (_id) -> |
||||
# console.log '[functions] RocketChat.settings.add -> '.green, 'arguments:', arguments |
||||
|
||||
if not _id |
||||
return false |
||||
|
||||
return RocketChat.models.Settings.removeById _id |
||||
|
||||
|
||||
### |
||||
# Update a setting by id |
||||
# @param {String} _id |
||||
### |
||||
RocketChat.settings.updateById = (_id, value, editor) -> |
||||
# console.log '[functions] RocketChat.settings.updateById -> '.green, 'arguments:', arguments |
||||
|
||||
if not _id or not value? |
||||
return false |
||||
|
||||
if editor? |
||||
return RocketChat.models.Settings.updateValueAndEditorById _id, value, editor |
||||
|
||||
return RocketChat.models.Settings.updateValueById _id, value |
||||
|
||||
|
||||
### |
||||
# Update options of a setting by id |
||||
# @param {String} _id |
||||
### |
||||
RocketChat.settings.updateOptionsById = (_id, options) -> |
||||
# console.log '[functions] RocketChat.settings.updateOptionsById -> '.green, 'arguments:', arguments |
||||
|
||||
if not _id or not options? |
||||
return false |
||||
|
||||
return RocketChat.models.Settings.updateOptionsById _id, options |
||||
|
||||
|
||||
### |
||||
# Update a setting by id |
||||
# @param {String} _id |
||||
### |
||||
RocketChat.settings.clearById = (_id) -> |
||||
# console.log '[functions] RocketChat.settings.clearById -> '.green, 'arguments:', arguments |
||||
|
||||
if not _id? |
||||
return false |
||||
|
||||
return RocketChat.models.Settings.updateValueById _id, undefined |
||||
|
||||
|
||||
### |
||||
# Update a setting by id |
||||
### |
||||
RocketChat.settings.init = -> |
||||
RocketChat.settings.initialLoad = true |
||||
RocketChat.models.Settings.find().observe |
||||
added: (record) -> |
||||
Meteor.settings[record._id] = record.value |
||||
if record.env is true |
||||
process.env[record._id] = record.value |
||||
RocketChat.settings.load record._id, record.value, RocketChat.settings.initialLoad |
||||
changed: (record) -> |
||||
Meteor.settings[record._id] = record.value |
||||
if record.env is true |
||||
process.env[record._id] = record.value |
||||
RocketChat.settings.load record._id, record.value, RocketChat.settings.initialLoad |
||||
removed: (record) -> |
||||
delete Meteor.settings[record._id] |
||||
if record.env is true |
||||
delete process.env[record._id] |
||||
RocketChat.settings.load record._id, undefined, RocketChat.settings.initialLoad |
||||
RocketChat.settings.initialLoad = false |
||||
|
||||
for fn in RocketChat.settings.afterInitialLoad |
||||
fn(Meteor.settings) |
||||
|
||||
|
||||
RocketChat.settings.afterInitialLoad = [] |
||||
|
||||
RocketChat.settings.onAfterInitialLoad = (fn) -> |
||||
RocketChat.settings.afterInitialLoad.push(fn) |
||||
if RocketChat.settings.initialLoad is false |
||||
fn(Meteor.settings) |
@ -0,0 +1,283 @@ |
||||
const blockedSettings = {}; |
||||
|
||||
if (process.env.SETTINGS_BLOCKED) { |
||||
process.env.SETTINGS_BLOCKED.split(',').forEach((settingId) => blockedSettings[settingId] = 1); |
||||
} |
||||
|
||||
const hiddenSettings = {}; |
||||
if (process.env.SETTINGS_HIDDEN) { |
||||
process.env.SETTINGS_HIDDEN.split(',').forEach((settingId) => hiddenSettings[settingId] = 1); |
||||
} |
||||
|
||||
RocketChat.settings._sorter = {}; |
||||
|
||||
|
||||
/* |
||||
* Add a setting |
||||
* @param {String} _id |
||||
* @param {Mixed} value |
||||
* @param {Object} setting |
||||
*/ |
||||
|
||||
RocketChat.settings.add = function(_id, value, options = {}) { |
||||
if (options == null) { |
||||
options = {}; |
||||
} |
||||
if (!_id || value == null) { |
||||
return false; |
||||
} |
||||
if (RocketChat.settings._sorter[options.group] == null) { |
||||
RocketChat.settings._sorter[options.group] = 0; |
||||
} |
||||
options.packageValue = value; |
||||
options.valueSource = 'packageValue'; |
||||
options.hidden = false; |
||||
options.blocked = options.blocked || false; |
||||
if (options.sorter == null) { |
||||
options.sorter = RocketChat.settings._sorter[options.group]++; |
||||
} |
||||
if (options.enableQuery != null) { |
||||
options.enableQuery = JSON.stringify(options.enableQuery); |
||||
} |
||||
if (options.i18nDefaultQuery != null) { |
||||
options.i18nDefaultQuery = JSON.stringify(options.i18nDefaultQuery); |
||||
} |
||||
if (typeof process !== 'undefined' && process.env && process.env._id) { |
||||
let value = process.env[_id]; |
||||
if (value.toLowerCase() === 'true') { |
||||
value = true; |
||||
} else if (value.toLowerCase() === 'false') { |
||||
value = false; |
||||
} |
||||
options.processEnvValue = value; |
||||
options.valueSource = 'processEnvValue'; |
||||
} else if (Meteor.settings && Meteor.settings) { |
||||
const value = Meteor.settings[_id]; |
||||
options.meteorSettingsValue = value; |
||||
options.valueSource = 'meteorSettingsValue'; |
||||
} |
||||
if (options.i18nLabel == null) { |
||||
options.i18nLabel = _id; |
||||
} |
||||
if (options.i18nDescription == null) { |
||||
options.i18nDescription = `${ _id }_Description`; |
||||
} |
||||
if (blockedSettings[_id] != null) { |
||||
options.blocked = true; |
||||
} |
||||
if (hiddenSettings[_id] != null) { |
||||
options.hidden = true; |
||||
} |
||||
if (typeof process !== 'undefined' && process.env && process.env[`OVERWRITE_SETTING_${ _id }`]) { |
||||
let value = process.env[`OVERWRITE_SETTING_${ _id }`]; |
||||
if (value.toLowerCase() === 'true') { |
||||
value = true; |
||||
} else if (value.toLowerCase() === 'false') { |
||||
value = false; |
||||
} |
||||
options.value = value; |
||||
options.processEnvValue = value; |
||||
options.valueSource = 'processEnvValue'; |
||||
} |
||||
const updateOperations = { |
||||
$set: options, |
||||
$setOnInsert: { |
||||
createdAt: new Date |
||||
} |
||||
}; |
||||
if (options.editor != null) { |
||||
updateOperations.$setOnInsert.editor = options.editor; |
||||
delete options.editor; |
||||
} |
||||
if (options.value == null) { |
||||
if (options.force === true) { |
||||
updateOperations.$set.value = options.packageValue; |
||||
} else { |
||||
updateOperations.$setOnInsert.value = value; |
||||
} |
||||
} |
||||
const query = _.extend({ |
||||
_id |
||||
}, updateOperations.$set); |
||||
if (options.section == null) { |
||||
updateOperations.$unset = { |
||||
section: 1 |
||||
}; |
||||
query.section = { |
||||
$exists: false |
||||
}; |
||||
} |
||||
const existantSetting = RocketChat.models.Settings.db.findOne(query); |
||||
if (existantSetting != null) { |
||||
if (existantSetting.editor == null && updateOperations.$setOnInsert.editor != null) { |
||||
updateOperations.$set.editor = updateOperations.$setOnInsert.editor; |
||||
delete updateOperations.$setOnInsert.editor; |
||||
} |
||||
} else { |
||||
updateOperations.$set.ts = new Date; |
||||
} |
||||
return RocketChat.models.Settings.upsert({ |
||||
_id |
||||
}, updateOperations); |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Add a setting group |
||||
* @param {String} _id |
||||
*/ |
||||
|
||||
RocketChat.settings.addGroup = function(_id, options = {}, cb) { |
||||
if (!_id) { |
||||
return false; |
||||
} |
||||
if (_.isFunction(options)) { |
||||
cb = options; |
||||
options = {}; |
||||
} |
||||
if (options.i18nLabel == null) { |
||||
options.i18nLabel = _id; |
||||
} |
||||
if (options.i18nDescription == null) { |
||||
options.i18nDescription = `${ _id }_Description`; |
||||
} |
||||
options.ts = new Date; |
||||
options.blocked = false; |
||||
options.hidden = false; |
||||
if (blockedSettings[_id] != null) { |
||||
options.blocked = true; |
||||
} |
||||
if (hiddenSettings[_id] != null) { |
||||
options.hidden = true; |
||||
} |
||||
RocketChat.models.Settings.upsert({ |
||||
_id |
||||
}, { |
||||
$set: options, |
||||
$setOnInsert: { |
||||
type: 'group', |
||||
createdAt: new Date |
||||
} |
||||
}); |
||||
if (cb != null) { |
||||
cb.call({ |
||||
add(id, value, options) { |
||||
if (options == null) { |
||||
options = {}; |
||||
} |
||||
options.group = _id; |
||||
return RocketChat.settings.add(id, value, options); |
||||
}, |
||||
section(section, cb) { |
||||
return cb.call({ |
||||
add(id, value, options) { |
||||
if (options == null) { |
||||
options = {}; |
||||
} |
||||
options.group = _id; |
||||
options.section = section; |
||||
return RocketChat.settings.add(id, value, options); |
||||
} |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Remove a setting by id |
||||
* @param {String} _id |
||||
*/ |
||||
|
||||
RocketChat.settings.removeById = function(_id) { |
||||
if (!_id) { |
||||
return false; |
||||
} |
||||
return RocketChat.models.Settings.removeById(_id); |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Update a setting by id |
||||
* @param {String} _id |
||||
*/ |
||||
|
||||
RocketChat.settings.updateById = function(_id, value, editor) { |
||||
if (!_id || value == null) { |
||||
return false; |
||||
} |
||||
if (editor != null) { |
||||
return RocketChat.models.Settings.updateValueAndEditorById(_id, value, editor); |
||||
} |
||||
return RocketChat.models.Settings.updateValueById(_id, value); |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Update options of a setting by id |
||||
* @param {String} _id |
||||
*/ |
||||
|
||||
RocketChat.settings.updateOptionsById = function(_id, options) { |
||||
if (!_id || options == null) { |
||||
return false; |
||||
} |
||||
return RocketChat.models.Settings.updateOptionsById(_id, options); |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Update a setting by id |
||||
* @param {String} _id |
||||
*/ |
||||
|
||||
RocketChat.settings.clearById = function(_id) { |
||||
if (_id == null) { |
||||
return false; |
||||
} |
||||
return RocketChat.models.Settings.updateValueById(_id, undefined); |
||||
}; |
||||
|
||||
|
||||
/* |
||||
* Update a setting by id |
||||
*/ |
||||
|
||||
RocketChat.settings.init = function() { |
||||
RocketChat.settings.initialLoad = true; |
||||
RocketChat.models.Settings.find().observe({ |
||||
added(record) { |
||||
Meteor.settings[record._id] = record.value; |
||||
if (record.env === true) { |
||||
process.env[record._id] = record.value; |
||||
} |
||||
return RocketChat.settings.load(record._id, record.value, RocketChat.settings.initialLoad); |
||||
}, |
||||
changed(record) { |
||||
Meteor.settings[record._id] = record.value; |
||||
if (record.env === true) { |
||||
process.env[record._id] = record.value; |
||||
} |
||||
return RocketChat.settings.load(record._id, record.value, RocketChat.settings.initialLoad); |
||||
}, |
||||
removed(record) { |
||||
delete Meteor.settings[record._id]; |
||||
if (record.env === true) { |
||||
delete process.env[record._id]; |
||||
} |
||||
return RocketChat.settings.load(record._id, undefined, RocketChat.settings.initialLoad); |
||||
} |
||||
}); |
||||
RocketChat.settings.initialLoad = false; |
||||
RocketChat.settings.afterInitialLoad.forEach(fn => fn(Meteor.settings)); |
||||
}; |
||||
|
||||
RocketChat.settings.afterInitialLoad = []; |
||||
|
||||
RocketChat.settings.onAfterInitialLoad = function(fn) { |
||||
RocketChat.settings.afterInitialLoad.push(fn); |
||||
if (RocketChat.settings.initialLoad === false) { |
||||
return fn(Meteor.settings); |
||||
} |
||||
}; |
@ -1,64 +0,0 @@ |
||||
import moment from 'moment' |
||||
|
||||
Meteor.methods |
||||
sendMessage: (message) -> |
||||
|
||||
check message, Object |
||||
|
||||
if not Meteor.userId() |
||||
throw new Meteor.Error('error-invalid-user', "Invalid user", { method: 'sendMessage' }) |
||||
|
||||
if message.ts |
||||
tsDiff = Math.abs(moment(message.ts).diff()) |
||||
if tsDiff > 60000 |
||||
throw new Meteor.Error('error-message-ts-out-of-sync', 'Message timestamp is out of sync', { method: 'sendMessage', message_ts: message.ts, server_ts: new Date().getTime() }) |
||||
else if tsDiff > 10000 |
||||
message.ts = new Date() |
||||
else |
||||
message.ts = new Date() |
||||
|
||||
if message.msg?.length > RocketChat.settings.get('Message_MaxAllowedSize') |
||||
throw new Meteor.Error('error-message-size-exceeded', 'Message size exceeds Message_MaxAllowedSize', { method: 'sendMessage' }) |
||||
|
||||
user = RocketChat.models.Users.findOneById Meteor.userId(), fields: username: 1, name: 1 |
||||
|
||||
room = Meteor.call 'canAccessRoom', message.rid, user._id |
||||
|
||||
if not room |
||||
return false |
||||
|
||||
subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(message.rid, Meteor.userId()); |
||||
if subscription and (subscription.blocked or subscription.blocker) |
||||
RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { |
||||
_id: Random.id() |
||||
rid: room._id |
||||
ts: new Date |
||||
msg: TAPi18n.__('room_is_blocked', {}, user.language) |
||||
} |
||||
return false |
||||
|
||||
if user.username in (room.muted or []) |
||||
RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { |
||||
_id: Random.id() |
||||
rid: room._id |
||||
ts: new Date |
||||
msg: TAPi18n.__('You_have_been_muted', {}, user.language) |
||||
} |
||||
return false |
||||
|
||||
message.alias = user.name if not message.alias? and RocketChat.settings.get 'Message_SetNameToAliasEnabled' |
||||
if Meteor.settings.public.sandstorm |
||||
message.sandstormSessionId = this.connection.sandstormSessionId() |
||||
|
||||
RocketChat.metrics.messagesSent.inc() # This line needs to be moved to it's proper place. See the comments on: https://github.com/RocketChat/Rocket.Chat/pull/5736 |
||||
RocketChat.sendMessage user, message, room |
||||
|
||||
# Limit a user, who does not have the "bot" role, to sending 5 msgs/second |
||||
DDPRateLimiter.addRule |
||||
type: 'method' |
||||
name: 'sendMessage' |
||||
userId: (userId) -> |
||||
user = RocketChat.models.Users.findOneById(userId) |
||||
return true if not user?.roles |
||||
return 'bot' not in user.roles |
||||
, 5, 1000 |
@ -0,0 +1,81 @@ |
||||
import moment from 'moment'; |
||||
|
||||
Meteor.methods({ |
||||
sendMessage(message) { |
||||
check(message, Object); |
||||
if (!Meteor.userId()) { |
||||
throw new Meteor.Error('error-invalid-user', 'Invalid user', { |
||||
method: 'sendMessage' |
||||
}); |
||||
} |
||||
if (message.ts) { |
||||
const tsDiff = Math.abs(moment(message.ts).diff()); |
||||
if (tsDiff > 60000) { |
||||
throw new Meteor.Error('error-message-ts-out-of-sync', 'Message timestamp is out of sync', { |
||||
method: 'sendMessage', |
||||
message_ts: message.ts, |
||||
server_ts: new Date().getTime() |
||||
}); |
||||
} else if (tsDiff > 10000) { |
||||
message.ts = new Date(); |
||||
} |
||||
} else { |
||||
message.ts = new Date(); |
||||
} |
||||
if (message.msg && message.msg.length > RocketChat.settings.get('Message_MaxAllowedSize')) { |
||||
throw new Meteor.Error('error-message-size-exceeded', 'Message size exceeds Message_MaxAllowedSize', { |
||||
method: 'sendMessage' |
||||
}); |
||||
} |
||||
const user = RocketChat.models.Users.findOneById(Meteor.userId(), { |
||||
fields: { |
||||
username: 1, |
||||
name: 1 |
||||
} |
||||
}); |
||||
const room = Meteor.call('canAccessRoom', message.rid, user._id); |
||||
if (!room) { |
||||
return false; |
||||
} |
||||
const subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId(message.rid, Meteor.userId()); |
||||
if (subscription && subscription.blocked || subscription.blocker) { |
||||
RocketChat.Notifications.notifyUser(Meteor.userId(), 'message', { |
||||
_id: Random.id(), |
||||
rid: room._id, |
||||
ts: new Date, |
||||
msg: TAPi18n.__('room_is_blocked', {}, user.language) |
||||
}); |
||||
return false; |
||||
} |
||||
|
||||
if ((room.muted||[]).includes(user.username)) { |
||||
RocketChat.Notifications.notifyUser(Meteor.userId(), 'message', { |
||||
_id: Random.id(), |
||||
rid: room._id, |
||||
ts: new Date, |
||||
msg: TAPi18n.__('You_have_been_muted', {}, user.language) |
||||
}); |
||||
return false; |
||||
} |
||||
if (message.alias == null && RocketChat.settings.get('Message_SetNameToAliasEnabled')) { |
||||
message.alias = user.name; |
||||
} |
||||
if (Meteor.settings['public'].sandstorm) { |
||||
message.sandstormSessionId = this.connection.sandstormSessionId(); |
||||
} |
||||
RocketChat.metrics.messagesSent.inc(); // TODO This line needs to be moved to it's proper place. See the comments on: https://github.com/RocketChat/Rocket.Chat/pull/5736
|
||||
return RocketChat.sendMessage(user, message, room); |
||||
} |
||||
}); |
||||
// Limit a user, who does not have the "bot" role, to sending 5 msgs/second
|
||||
DDPRateLimiter.addRule({ |
||||
type: 'method', |
||||
name: 'sendMessage', |
||||
userId(userId) { |
||||
const user = RocketChat.models.Users.findOneById(userId); |
||||
if (user == null || !user.roles) { |
||||
return true; |
||||
} |
||||
return user.roles.includes('bot'); |
||||
} |
||||
}, 5, 1000); |
@ -0,0 +1,580 @@ |
||||
RocketChat.models.Messages = new class extends RocketChat.models._Base { |
||||
constructor() { |
||||
super('message'); |
||||
|
||||
this.tryEnsureIndex({ 'rid': 1, 'ts': 1 }); |
||||
this.tryEnsureIndex({ 'ts': 1 }); |
||||
this.tryEnsureIndex({ 'u._id': 1 }); |
||||
this.tryEnsureIndex({ 'editedAt': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'editedBy._id': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'rid': 1, 't': 1, 'u._id': 1 }); |
||||
this.tryEnsureIndex({ 'expireAt': 1 }, { expireAfterSeconds: 0 }); |
||||
this.tryEnsureIndex({ 'msg': 'text' }); |
||||
this.tryEnsureIndex({ 'file._id': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'mentions.username': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'pinned': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'snippeted': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'location': '2dsphere' }); |
||||
this.tryEnsureIndex({ 'slackBotId': 1, 'slackTs': 1 }, { sparse: 1 }); |
||||
} |
||||
|
||||
// FIND
|
||||
findByMention(username, options) { |
||||
const query = {'mentions.username': username}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByMentionAndRoomId(username, rid, options) { |
||||
const query = { |
||||
_hidden: { $ne: true }, |
||||
'mentions.username': username, |
||||
rid |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByRoomId(roomId, options) { |
||||
const query = { |
||||
_hidden: { |
||||
$ne: true |
||||
}, |
||||
|
||||
rid: roomId |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByRoomIdNotContainingTypes(roomId, types, options) { |
||||
const query = { |
||||
_hidden: { |
||||
$ne: true |
||||
}, |
||||
|
||||
rid: roomId |
||||
}; |
||||
|
||||
if (Match.test(types, [String]) && (types.length > 0)) { |
||||
query.t = |
||||
{$nin: types}; |
||||
} |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findInvisibleByRoomId(roomId, options) { |
||||
const query = { |
||||
_hidden: true, |
||||
rid: roomId |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByRoomIdAfterTimestamp(roomId, timestamp, options) { |
||||
const query = { |
||||
_hidden: { |
||||
$ne: true |
||||
}, |
||||
rid: roomId, |
||||
ts: { |
||||
$gt: timestamp |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByRoomIdBeforeTimestamp(roomId, timestamp, options) { |
||||
const query = { |
||||
_hidden: { |
||||
$ne: true |
||||
}, |
||||
rid: roomId, |
||||
ts: { |
||||
$lt: timestamp |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByRoomIdBeforeTimestampInclusive(roomId, timestamp, options) { |
||||
const query = { |
||||
_hidden: { |
||||
$ne: true |
||||
}, |
||||
rid: roomId, |
||||
ts: { |
||||
$lte: timestamp |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByRoomIdBetweenTimestamps(roomId, afterTimestamp, beforeTimestamp, options) { |
||||
const query = { |
||||
_hidden: { |
||||
$ne: true |
||||
}, |
||||
rid: roomId, |
||||
ts: { |
||||
$gt: afterTimestamp, |
||||
$lt: beforeTimestamp |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByRoomIdBetweenTimestampsInclusive(roomId, afterTimestamp, beforeTimestamp, options) { |
||||
const query = { |
||||
_hidden: { |
||||
$ne: true |
||||
}, |
||||
rid: roomId, |
||||
ts: { |
||||
$gte: afterTimestamp, |
||||
$lte: beforeTimestamp |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByRoomIdBeforeTimestampNotContainingTypes(roomId, timestamp, types, options) { |
||||
const query = { |
||||
_hidden: { |
||||
$ne: true |
||||
}, |
||||
rid: roomId, |
||||
ts: { |
||||
$lt: timestamp |
||||
} |
||||
}; |
||||
|
||||
if (Match.test(types, [String]) && (types.length > 0)) { |
||||
query.t = |
||||
{$nin: types}; |
||||
} |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleByRoomIdBetweenTimestampsNotContainingTypes(roomId, afterTimestamp, beforeTimestamp, types, options) { |
||||
const query = { |
||||
_hidden: { |
||||
$ne: true |
||||
}, |
||||
rid: roomId, |
||||
ts: { |
||||
$gt: afterTimestamp, |
||||
$lt: beforeTimestamp |
||||
} |
||||
}; |
||||
|
||||
if (Match.test(types, [String]) && (types.length > 0)) { |
||||
query.t = |
||||
{$nin: types}; |
||||
} |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findVisibleCreatedOrEditedAfterTimestamp(timestamp, options) { |
||||
const query = { |
||||
_hidden: { $ne: true }, |
||||
$or: [{ |
||||
ts: { |
||||
$gt: timestamp |
||||
} |
||||
}, |
||||
{ |
||||
'editedAt': { |
||||
$gt: timestamp |
||||
} |
||||
} |
||||
] |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findStarredByUserAtRoom(userId, roomId, options) { |
||||
const query = { |
||||
_hidden: { $ne: true }, |
||||
'starred._id': userId, |
||||
rid: roomId |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findPinnedByRoom(roomId, options) { |
||||
const query = { |
||||
t: { $ne: 'rm' }, |
||||
_hidden: { $ne: true }, |
||||
pinned: true, |
||||
rid: roomId |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findSnippetedByRoom(roomId, options) { |
||||
const query = { |
||||
_hidden: { $ne: true }, |
||||
snippeted: true, |
||||
rid: roomId |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
getLastTimestamp(options) { |
||||
if (options == null) { options = {}; } |
||||
const query = { ts: { $exists: 1 } }; |
||||
options.sort = { ts: -1 }; |
||||
options.limit = 1; |
||||
const [message] = this.find(query, options).fetch(); |
||||
return message && message.ts; |
||||
} |
||||
|
||||
findByRoomIdAndMessageIds(rid, messageIds, options) { |
||||
const query = { |
||||
rid, |
||||
_id: { |
||||
$in: messageIds |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findOneBySlackBotIdAndSlackTs(slackBotId, slackTs) { |
||||
const query = { |
||||
slackBotId, |
||||
slackTs |
||||
}; |
||||
|
||||
return this.findOne(query); |
||||
} |
||||
|
||||
findOneBySlackTs(slackTs) { |
||||
const query = {slackTs}; |
||||
|
||||
return this.findOne(query); |
||||
} |
||||
|
||||
cloneAndSaveAsHistoryById(_id) { |
||||
const me = RocketChat.models.Users.findOneById(Meteor.userId()); |
||||
const record = this.findOneById(_id); |
||||
record._hidden = true; |
||||
record.parent = record._id; |
||||
record.editedAt = new Date; |
||||
record.editedBy = { |
||||
_id: Meteor.userId(), |
||||
username: me.username |
||||
}; |
||||
delete record._id; |
||||
return this.insert(record); |
||||
} |
||||
|
||||
// UPDATE
|
||||
setHiddenById(_id, hidden) { |
||||
if (hidden == null) { hidden = true; } |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
_hidden: hidden |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setAsDeletedByIdAndUser(_id, user) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
msg: '', |
||||
t: 'rm', |
||||
urls: [], |
||||
mentions: [], |
||||
attachments: [], |
||||
reactions: [], |
||||
editedAt: new Date(), |
||||
editedBy: { |
||||
_id: user._id, |
||||
username: user.username |
||||
} |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setPinnedByIdAndUserId(_id, pinnedBy, pinned, pinnedAt) { |
||||
if (pinned == null) { pinned = true; } |
||||
if (pinnedAt == null) { pinnedAt = 0; } |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
pinned, |
||||
pinnedAt: pinnedAt || new Date, |
||||
pinnedBy |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setSnippetedByIdAndUserId(message, snippetName, snippetedBy, snippeted, snippetedAt) { |
||||
if (snippeted == null) { snippeted = true; } |
||||
if (snippetedAt == null) { snippetedAt = 0; } |
||||
const query = {_id: message._id}; |
||||
|
||||
const msg = `\`\`\`${ message.msg }\`\`\``; |
||||
|
||||
const update = { |
||||
$set: { |
||||
msg, |
||||
snippeted, |
||||
snippetedAt: snippetedAt || new Date, |
||||
snippetedBy, |
||||
snippetName |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setUrlsById(_id, urls) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
urls |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
updateAllUsernamesByUserId(userId, username) { |
||||
const query = {'u._id': userId}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
'u.username': username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
updateUsernameOfEditByUserId(userId, username) { |
||||
const query = {'editedBy._id': userId}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
'editedBy.username': username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
updateUsernameAndMessageOfMentionByIdAndOldUsername(_id, oldUsername, newUsername, newMessage) { |
||||
const query = { |
||||
_id, |
||||
'mentions.username': oldUsername |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
'mentions.$.username': newUsername, |
||||
'msg': newMessage |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
updateUserStarById(_id, userId, starred) { |
||||
let update; |
||||
const query = {_id}; |
||||
|
||||
if (starred) { |
||||
update = { |
||||
$addToSet: { |
||||
starred: { _id: userId } |
||||
} |
||||
}; |
||||
} else { |
||||
update = { |
||||
$pull: { |
||||
starred: { _id: Meteor.userId() } |
||||
} |
||||
}; |
||||
} |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
upgradeEtsToEditAt() { |
||||
const query = {ets: { $exists: 1 }}; |
||||
|
||||
const update = { |
||||
$rename: { |
||||
'ets': 'editedAt' |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
setMessageAttachments(_id, attachments) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
attachments |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setSlackBotIdAndSlackTs(_id, slackBotId, slackTs) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
slackBotId, |
||||
slackTs |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
|
||||
// INSERT
|
||||
createWithTypeRoomIdMessageAndUser(type, roomId, message, user, extraData) { |
||||
const room = RocketChat.models.Rooms.findOneById(roomId, { fields: { sysMes: 1 }}); |
||||
if ((room != null ? room.sysMes : undefined) === false) { |
||||
return; |
||||
} |
||||
const record = { |
||||
t: type, |
||||
rid: roomId, |
||||
ts: new Date, |
||||
msg: message, |
||||
u: { |
||||
_id: user._id, |
||||
username: user.username |
||||
}, |
||||
groupable: false |
||||
}; |
||||
|
||||
_.extend(record, extraData); |
||||
|
||||
record._id = this.insertOrUpsert(record); |
||||
RocketChat.models.Rooms.incMsgCountById(room._id, 1); |
||||
return record; |
||||
} |
||||
|
||||
createUserJoinWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('uj', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createUserLeaveWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('ul', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createUserRemovedWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('ru', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createUserAddedWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('au', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createCommandWithRoomIdAndUser(command, roomId, user, extraData) { |
||||
return this.createWithTypeRoomIdMessageAndUser('command', roomId, command, user, extraData); |
||||
} |
||||
|
||||
createUserMutedWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('user-muted', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createUserUnmutedWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('user-unmuted', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createNewModeratorWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('new-moderator', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createModeratorRemovedWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('moderator-removed', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createNewOwnerWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('new-owner', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createOwnerRemovedWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('owner-removed', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createSubscriptionRoleAddedWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('subscription-role-added', roomId, message, user, extraData); |
||||
} |
||||
|
||||
createSubscriptionRoleRemovedWithRoomIdAndUser(roomId, user, extraData) { |
||||
const message = user.username; |
||||
return this.createWithTypeRoomIdMessageAndUser('subscription-role-removed', roomId, message, user, extraData); |
||||
} |
||||
|
||||
// REMOVE
|
||||
removeById(_id) { |
||||
const query = {_id}; |
||||
|
||||
return this.remove(query); |
||||
} |
||||
|
||||
removeByRoomId(roomId) { |
||||
const query = {rid: roomId}; |
||||
|
||||
return this.remove(query); |
||||
} |
||||
|
||||
removeByUserId(userId) { |
||||
const query = {'u._id': userId}; |
||||
|
||||
return this.remove(query); |
||||
} |
||||
|
||||
getMessageByFileId(fileID) { |
||||
return this.findOne({ 'file._id': fileID }); |
||||
} |
||||
}; |
@ -0,0 +1,760 @@ |
||||
class ModelRooms extends RocketChat.models._Base { |
||||
constructor() { |
||||
super(...arguments); |
||||
|
||||
this.tryEnsureIndex({ 'name': 1 }, { unique: 1, sparse: 1 }); |
||||
this.tryEnsureIndex({ 'default': 1 }); |
||||
this.tryEnsureIndex({ 'usernames': 1 }); |
||||
this.tryEnsureIndex({ 't': 1 }); |
||||
this.tryEnsureIndex({ 'u._id': 1 }); |
||||
|
||||
this.cache.ignoreUpdatedFields.push('msgs', 'lm'); |
||||
this.cache.ensureIndex(['t', 'name'], 'unique'); |
||||
this.cache.options = {fields: {usernames: 0}}; |
||||
} |
||||
|
||||
findOneByIdOrName(_idOrName, options) { |
||||
const query = { |
||||
$or: [{ |
||||
_id: _idOrName |
||||
}, { |
||||
name: _idOrName |
||||
}] |
||||
}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
findOneByImportId(_id, options) { |
||||
const query = {importIds: _id}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
findOneByName(name, options) { |
||||
const query = {name}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
findOneByNameAndType(name, type, options) { |
||||
const query = { |
||||
name, |
||||
t: type |
||||
}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
findOneByIdContainingUsername(_id, username, options) { |
||||
const query = { |
||||
_id, |
||||
usernames: username |
||||
}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
findOneByNameAndTypeNotContainingUsername(name, type, username, options) { |
||||
const query = { |
||||
name, |
||||
t: type, |
||||
usernames: { |
||||
$ne: username |
||||
} |
||||
}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
|
||||
// FIND
|
||||
|
||||
findById(roomId, options) { |
||||
return this.find({ _id: roomId }, options); |
||||
} |
||||
|
||||
findByIds(roomIds, options) { |
||||
return this.find({ _id: {$in: [].concat(roomIds)} }, options); |
||||
} |
||||
|
||||
findByType(type, options) { |
||||
const query = {t: type}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByTypes(types, options) { |
||||
const query = { |
||||
t: { |
||||
$in: types |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByUserId(userId, options) { |
||||
const query = {'u._id': userId}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findBySubscriptionUserId(userId, options) { |
||||
let data; |
||||
if (this.useCache) { |
||||
data = RocketChat.models.Subscriptions.findByUserId(userId).fetch(); |
||||
data = data.map(function(item) { |
||||
if (item._room) { |
||||
return item._room; |
||||
} |
||||
console.log('Empty Room for Subscription', item); |
||||
return {}; |
||||
}); |
||||
return this.arrayToCursor(this.processQueryOptionsOnResult(data, options)); |
||||
} |
||||
|
||||
data = RocketChat.models.Subscriptions.findByUserId(userId, {fields: {rid: 1}}).fetch(); |
||||
data = data.map(item => item.rid); |
||||
|
||||
const query = { |
||||
_id: { |
||||
$in: data |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findBySubscriptionUserIdUpdatedAfter(userId, _updatedAt, options) { |
||||
if (this.useCache) { |
||||
let data = RocketChat.models.Subscriptions.findByUserId(userId).fetch(); |
||||
data = data.map(function(item) { |
||||
if (item._room) { |
||||
return item._room; |
||||
} |
||||
console.log('Empty Room for Subscription', item); |
||||
return {}; |
||||
}); |
||||
data = data.filter(item => item._updatedAt > _updatedAt); |
||||
return this.arrayToCursor(this.processQueryOptionsOnResult(data, options)); |
||||
} |
||||
|
||||
let ids = RocketChat.models.Subscriptions.findByUserId(userId, {fields: {rid: 1}}).fetch(); |
||||
ids = ids.map(item => item.rid); |
||||
|
||||
const query = { |
||||
_id: { |
||||
$in: ids |
||||
}, |
||||
_updatedAt: { |
||||
$gt: _updatedAt |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByNameContaining(name, options) { |
||||
const nameRegex = new RegExp(s.trim(s.escapeRegExp(name)), 'i'); |
||||
|
||||
const query = { |
||||
$or: [ |
||||
{name: nameRegex}, |
||||
{ |
||||
t: 'd', |
||||
usernames: nameRegex |
||||
} |
||||
] |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByNameContainingTypesWithUsername(name, types, options) { |
||||
const nameRegex = new RegExp(s.trim(s.escapeRegExp(name)), 'i'); |
||||
|
||||
const $or = []; |
||||
for (const type of Array.from(types)) { |
||||
const obj = {name: nameRegex, t: type.type}; |
||||
if (type.username != null) { |
||||
obj.usernames = type.username; |
||||
} |
||||
if (type.ids != null) { |
||||
obj._id = {$in: type.ids}; |
||||
} |
||||
$or.push(obj); |
||||
} |
||||
|
||||
const query = {$or}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findContainingTypesWithUsername(types, options) { |
||||
|
||||
const $or = []; |
||||
for (const type of Array.from(types)) { |
||||
const obj = {t: type.type}; |
||||
if (type.username != null) { |
||||
obj.usernames = type.username; |
||||
} |
||||
if (type.ids != null) { |
||||
obj._id = {$in: type.ids}; |
||||
} |
||||
$or.push(obj); |
||||
} |
||||
|
||||
const query = {$or}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByNameContainingAndTypes(name, types, options) { |
||||
const nameRegex = new RegExp(s.trim(s.escapeRegExp(name)), 'i'); |
||||
|
||||
const query = { |
||||
t: { |
||||
$in: types |
||||
}, |
||||
$or: [ |
||||
{name: nameRegex}, |
||||
{ |
||||
t: 'd', |
||||
usernames: nameRegex |
||||
} |
||||
] |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByNameAndTypeNotContainingUsername(name, type, username, options) { |
||||
const query = { |
||||
t: type, |
||||
name, |
||||
usernames: { |
||||
$ne: username |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByNameStartingAndTypes(name, types, options) { |
||||
const nameRegex = new RegExp(`^${ s.trim(s.escapeRegExp(name)) }`, 'i'); |
||||
|
||||
const query = { |
||||
t: { |
||||
$in: types |
||||
}, |
||||
$or: [ |
||||
{name: nameRegex}, |
||||
{ |
||||
t: 'd', |
||||
usernames: nameRegex |
||||
} |
||||
] |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByDefaultAndTypes(defaultValue, types, options) { |
||||
const query = { |
||||
default: defaultValue, |
||||
t: { |
||||
$in: types |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByTypeContainingUsername(type, username, options) { |
||||
const query = { |
||||
t: type, |
||||
usernames: username |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByTypeContainingUsernames(type, username, options) { |
||||
const query = { |
||||
t: type, |
||||
usernames: { $all: [].concat(username) } |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByTypesAndNotUserIdContainingUsername(types, userId, username, options) { |
||||
const query = { |
||||
t: { |
||||
$in: types |
||||
}, |
||||
uid: { |
||||
$ne: userId |
||||
}, |
||||
usernames: username |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByContainingUsername(username, options) { |
||||
const query = {usernames: username}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByTypeAndName(type, name, options) { |
||||
if (this.useCache) { |
||||
return this.cache.findByIndex('t,name', [type, name], options); |
||||
} |
||||
|
||||
const query = { |
||||
name, |
||||
t: type |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByTypeAndNameContainingUsername(type, name, username, options) { |
||||
const query = { |
||||
name, |
||||
t: type, |
||||
usernames: username |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByTypeAndArchivationState(type, archivationstate, options) { |
||||
const query = {t: type}; |
||||
|
||||
if (archivationstate) { |
||||
query.archived = true; |
||||
} else { |
||||
query.archived = { $ne: true }; |
||||
} |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
// UPDATE
|
||||
addImportIds(_id, importIds) { |
||||
importIds = [].concat(importIds); |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$addToSet: { |
||||
importIds: { |
||||
$each: importIds |
||||
} |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
archiveById(_id) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
archived: true |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
unarchiveById(_id) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
archived: false |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
addUsernameById(_id, username, muted) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$addToSet: { |
||||
usernames: username |
||||
} |
||||
}; |
||||
|
||||
if (muted) { |
||||
update.$addToSet.muted = username; |
||||
} |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
addUsernamesById(_id, usernames) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$addToSet: { |
||||
usernames: { |
||||
$each: usernames |
||||
} |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
addUsernameByName(name, username) { |
||||
const query = {name}; |
||||
|
||||
const update = { |
||||
$addToSet: { |
||||
usernames: username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
removeUsernameById(_id, username) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$pull: { |
||||
usernames: username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
removeUsernamesById(_id, usernames) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$pull: { |
||||
usernames: { |
||||
$in: usernames |
||||
} |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
removeUsernameFromAll(username) { |
||||
const query = {usernames: username}; |
||||
|
||||
const update = { |
||||
$pull: { |
||||
usernames: username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
removeUsernameByName(name, username) { |
||||
const query = {name}; |
||||
|
||||
const update = { |
||||
$pull: { |
||||
usernames: username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setNameById(_id, name) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
name |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
incMsgCountById(_id, inc) { |
||||
if (inc == null) { inc = 1; } |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$inc: { |
||||
msgs: inc |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
incMsgCountAndSetLastMessageTimestampById(_id, inc, lastMessageTimestamp) { |
||||
if (inc == null) { inc = 1; } |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
lm: lastMessageTimestamp |
||||
}, |
||||
$inc: { |
||||
msgs: inc |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
replaceUsername(previousUsername, username) { |
||||
const query = {usernames: previousUsername}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
'usernames.$': username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
replaceMutedUsername(previousUsername, username) { |
||||
const query = {muted: previousUsername}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
'muted.$': username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
replaceUsernameOfUserByUserId(userId, username) { |
||||
const query = {'u._id': userId}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
'u.username': username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
setJoinCodeById(_id, joinCode) { |
||||
let update; |
||||
const query = {_id}; |
||||
|
||||
if ((joinCode != null ? joinCode.trim() : undefined) !== '') { |
||||
update = { |
||||
$set: { |
||||
joinCodeRequired: true, |
||||
joinCode |
||||
} |
||||
}; |
||||
} else { |
||||
update = { |
||||
$set: { |
||||
joinCodeRequired: false |
||||
}, |
||||
$unset: { |
||||
joinCode: 1 |
||||
} |
||||
}; |
||||
} |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setUserById(_id, user) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
u: { |
||||
_id: user._id, |
||||
username: user.username |
||||
} |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setTypeById(_id, type) { |
||||
const query = {_id}; |
||||
const update = { |
||||
$set: { |
||||
t: type |
||||
} |
||||
}; |
||||
if (type === 'p') { |
||||
update.$unset = {default: ''}; |
||||
} |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setTopicById(_id, topic) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
topic |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setAnnouncementById(_id, announcement) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
announcement |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
muteUsernameByRoomId(_id, username) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$addToSet: { |
||||
muted: username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
unmuteUsernameByRoomId(_id, username) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$pull: { |
||||
muted: username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
saveDefaultById(_id, defaultValue) { |
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
default: defaultValue === 'true' |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setTopicAndTagsById(_id, topic, tags) { |
||||
const setData = {}; |
||||
const unsetData = {}; |
||||
|
||||
if (topic != null) { |
||||
if (!_.isEmpty(s.trim(topic))) { |
||||
setData.topic = s.trim(topic); |
||||
} else { |
||||
unsetData.topic = 1; |
||||
} |
||||
} |
||||
|
||||
if (tags != null) { |
||||
if (!_.isEmpty(s.trim(tags))) { |
||||
setData.tags = s.trim(tags).split(',').map(tag => s.trim(tag)); |
||||
} else { |
||||
unsetData.tags = 1; |
||||
} |
||||
} |
||||
|
||||
const update = {}; |
||||
|
||||
if (!_.isEmpty(setData)) { |
||||
update.$set = setData; |
||||
} |
||||
|
||||
if (!_.isEmpty(unsetData)) { |
||||
update.$unset = unsetData; |
||||
} |
||||
|
||||
if (_.isEmpty(update)) { |
||||
return; |
||||
} |
||||
|
||||
return this.update({ _id }, update); |
||||
} |
||||
|
||||
// INSERT
|
||||
createWithTypeNameUserAndUsernames(type, name, user, usernames, extraData) { |
||||
const room = { |
||||
name, |
||||
t: type, |
||||
usernames, |
||||
msgs: 0, |
||||
u: { |
||||
_id: user._id, |
||||
username: user.username |
||||
} |
||||
}; |
||||
|
||||
_.extend(room, extraData); |
||||
|
||||
room._id = this.insert(room); |
||||
return room; |
||||
} |
||||
|
||||
createWithIdTypeAndName(_id, type, name, extraData) { |
||||
const room = { |
||||
_id, |
||||
ts: new Date(), |
||||
t: type, |
||||
name, |
||||
usernames: [], |
||||
msgs: 0 |
||||
}; |
||||
|
||||
_.extend(room, extraData); |
||||
|
||||
this.insert(room); |
||||
return room; |
||||
} |
||||
|
||||
|
||||
// REMOVE
|
||||
removeById(_id) { |
||||
const query = {_id}; |
||||
|
||||
return this.remove(query); |
||||
} |
||||
|
||||
removeByTypeContainingUsername(type, username) { |
||||
const query = { |
||||
t: type, |
||||
usernames: username |
||||
}; |
||||
|
||||
return this.remove(query); |
||||
} |
||||
} |
||||
|
||||
RocketChat.models.Rooms = new ModelRooms('room', true); |
@ -0,0 +1,178 @@ |
||||
class ModelSettings extends RocketChat.models._Base { |
||||
constructor() { |
||||
super(...arguments); |
||||
|
||||
this.tryEnsureIndex({ 'blocked': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'hidden': 1 }, { sparse: 1 }); |
||||
} |
||||
|
||||
// FIND
|
||||
findById(_id) { |
||||
const query = {_id}; |
||||
|
||||
return this.find(query); |
||||
} |
||||
|
||||
findOneNotHiddenById(_id) { |
||||
const query = { |
||||
_id, |
||||
hidden: { $ne: true } |
||||
}; |
||||
|
||||
return this.findOne(query); |
||||
} |
||||
|
||||
findByIds(_id = []) { |
||||
_id = [].concat(_id); |
||||
|
||||
const query = { |
||||
_id: { |
||||
$in: _id |
||||
} |
||||
}; |
||||
|
||||
return this.find(query); |
||||
} |
||||
|
||||
findByRole(role, options) { |
||||
const query = {role}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findPublic(options) { |
||||
const query = {public: true}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findNotHiddenPublic(ids = []) { |
||||
const filter = { |
||||
hidden: { $ne: true }, |
||||
public: true |
||||
}; |
||||
|
||||
if (ids.length > 0) { |
||||
filter._id = |
||||
{$in: ids}; |
||||
} |
||||
|
||||
return this.find(filter, { fields: {_id: 1, value: 1} }); |
||||
} |
||||
|
||||
findNotHiddenPublicUpdatedAfter(updatedAt) { |
||||
const filter = { |
||||
hidden: { $ne: true }, |
||||
public: true, |
||||
_updatedAt: { |
||||
$gt: updatedAt |
||||
} |
||||
}; |
||||
|
||||
return this.find(filter, { fields: {_id: 1, value: 1} }); |
||||
} |
||||
|
||||
findNotHiddenPrivate() { |
||||
return this.find({ |
||||
hidden: { $ne: true }, |
||||
public: { $ne: true } |
||||
}); |
||||
} |
||||
|
||||
findNotHidden(options) { |
||||
return this.find({ hidden: { $ne: true } }, options); |
||||
} |
||||
|
||||
findNotHiddenUpdatedAfter(updatedAt) { |
||||
return this.find({ |
||||
hidden: { $ne: true }, |
||||
_updatedAt: { |
||||
$gt: updatedAt |
||||
} |
||||
}); |
||||
} |
||||
|
||||
// UPDATE
|
||||
updateValueById(_id, value) { |
||||
const query = { |
||||
blocked: { $ne: true }, |
||||
value: { $ne: value }, |
||||
_id |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
value |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
updateValueAndEditorById(_id, value, editor) { |
||||
const query = { |
||||
blocked: { $ne: true }, |
||||
value: { $ne: value }, |
||||
_id |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
value, |
||||
editor |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
updateValueNotHiddenById(_id, value) { |
||||
const query = { |
||||
_id, |
||||
hidden: { $ne: true }, |
||||
blocked: { $ne: true } |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
value |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
updateOptionsById(_id, options) { |
||||
const query = { |
||||
blocked: { $ne: true }, |
||||
_id |
||||
}; |
||||
|
||||
const update = {$set: options}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
// INSERT
|
||||
createWithIdAndValue(_id, value) { |
||||
const record = { |
||||
_id, |
||||
value, |
||||
_createdAt: new Date |
||||
}; |
||||
|
||||
return this.insert(record); |
||||
} |
||||
|
||||
// REMOVE
|
||||
removeById(_id) { |
||||
const query = { |
||||
blocked: { $ne: true }, |
||||
_id |
||||
}; |
||||
|
||||
return this.remove(query); |
||||
} |
||||
} |
||||
|
||||
RocketChat.models.Settings = new ModelSettings('settings', true); |
@ -0,0 +1,570 @@ |
||||
class ModelSubscriptions extends RocketChat.models._Base { |
||||
constructor() { |
||||
super(...arguments); |
||||
|
||||
this.tryEnsureIndex({ 'rid': 1, 'u._id': 1 }, { unique: 1 }); |
||||
this.tryEnsureIndex({ 'rid': 1, 'alert': 1, 'u._id': 1 }); |
||||
this.tryEnsureIndex({ 'rid': 1, 'roles': 1 }); |
||||
this.tryEnsureIndex({ 'u._id': 1, 'name': 1, 't': 1 }); |
||||
this.tryEnsureIndex({ 'u._id': 1, 'name': 1, 't': 1, 'code': 1 }, { unique: 1 }); |
||||
this.tryEnsureIndex({ 'open': 1 }); |
||||
this.tryEnsureIndex({ 'alert': 1 }); |
||||
this.tryEnsureIndex({ 'unread': 1 }); |
||||
this.tryEnsureIndex({ 'ts': 1 }); |
||||
this.tryEnsureIndex({ 'ls': 1 }); |
||||
this.tryEnsureIndex({ 'audioNotification': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'desktopNotifications': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'mobilePushNotifications': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'emailNotifications': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'autoTranslate': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'autoTranslateLanguage': 1 }, { sparse: 1 }); |
||||
|
||||
this.cache.ensureIndex('rid', 'array'); |
||||
this.cache.ensureIndex('u._id', 'array'); |
||||
this.cache.ensureIndex('name', 'array'); |
||||
this.cache.ensureIndex(['rid', 'u._id'], 'unique'); |
||||
this.cache.ensureIndex(['name', 'u._id'], 'unique'); |
||||
} |
||||
|
||||
|
||||
// FIND ONE
|
||||
findOneByRoomIdAndUserId(roomId, userId) { |
||||
if (this.useCache) { |
||||
return this.cache.findByIndex('rid,u._id', [roomId, userId]).fetch(); |
||||
} |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
return this.findOne(query); |
||||
} |
||||
|
||||
findOneByRoomNameAndUserId(roomName, userId) { |
||||
if (this.useCache) { |
||||
return this.cache.findByIndex('name,u._id', [roomName, userId]).fetch(); |
||||
} |
||||
const query = { |
||||
name: roomName, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
return this.findOne(query); |
||||
} |
||||
|
||||
// FIND
|
||||
findByUserId(userId, options) { |
||||
if (this.useCache) { |
||||
return this.cache.findByIndex('u._id', userId, options); |
||||
} |
||||
|
||||
const query = |
||||
{'u._id': userId}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByUserIdUpdatedAfter(userId, updatedAt, options) { |
||||
const query = { |
||||
'u._id': userId, |
||||
_updatedAt: { |
||||
$gt: updatedAt |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
// FIND
|
||||
findByRoomIdAndRoles(roomId, roles, options) { |
||||
roles = [].concat(roles); |
||||
const query = { |
||||
'rid': roomId, |
||||
'roles': { $in: roles } |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByType(types, options) { |
||||
const query = { |
||||
t: { |
||||
$in: types |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByTypeAndUserId(type, userId, options) { |
||||
const query = { |
||||
t: type, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByTypeNameAndUserId(type, name, userId, options) { |
||||
const query = { |
||||
t: type, |
||||
name, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByRoomId(roomId, options) { |
||||
if (this.useCache) { |
||||
return this.cache.findByIndex('rid', roomId, options); |
||||
} |
||||
|
||||
const query = |
||||
{rid: roomId}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByRoomIdAndNotUserId(roomId, userId, options) { |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': { |
||||
$ne: userId |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
getLastSeen(options) { |
||||
if (options == null) { options = {}; } |
||||
const query = { ls: { $exists: 1 } }; |
||||
options.sort = { ls: -1 }; |
||||
options.limit = 1; |
||||
const [subscription] = this.find(query, options).fetch(); |
||||
return subscription && subscription.ls; |
||||
} |
||||
|
||||
findByRoomIdAndUserIds(roomId, userIds) { |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': { |
||||
$in: userIds |
||||
} |
||||
}; |
||||
|
||||
return this.find(query); |
||||
} |
||||
|
||||
// UPDATE
|
||||
archiveByRoomId(roomId) { |
||||
const query = |
||||
{rid: roomId}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
alert: false, |
||||
open: false, |
||||
archived: true |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
unarchiveByRoomId(roomId) { |
||||
const query = |
||||
{rid: roomId}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
alert: false, |
||||
open: true, |
||||
archived: false |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
hideByRoomIdAndUserId(roomId, userId) { |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
alert: false, |
||||
open: false |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
openByRoomIdAndUserId(roomId, userId) { |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
open: true |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setAsReadByRoomIdAndUserId(roomId, userId) { |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
open: true, |
||||
alert: false, |
||||
unread: 0, |
||||
ls: new Date |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setAsUnreadByRoomIdAndUserId(roomId, userId, firstMessageUnreadTimestamp) { |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
open: true, |
||||
alert: true, |
||||
ls: firstMessageUnreadTimestamp |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setFavoriteByRoomIdAndUserId(roomId, userId, favorite) { |
||||
if (favorite == null) { favorite = true; } |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
f: favorite |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
updateNameAndAlertByRoomId(roomId, name) { |
||||
const query = |
||||
{rid: roomId}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
name, |
||||
alert: true |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
updateNameByRoomId(roomId, name) { |
||||
const query = |
||||
{rid: roomId}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
name |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
setUserUsernameByUserId(userId, username) { |
||||
const query = |
||||
{'u._id': userId}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
'u.username': username |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
setNameForDirectRoomsWithOldName(oldName, name) { |
||||
const query = { |
||||
name: oldName, |
||||
t: 'd' |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
name |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
incUnreadOfDirectForRoomIdExcludingUserId(roomId, userId, inc) { |
||||
if (inc == null) { inc = 1; } |
||||
const query = { |
||||
rid: roomId, |
||||
t: 'd', |
||||
'u._id': { |
||||
$ne: userId |
||||
} |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
alert: true, |
||||
open: true |
||||
}, |
||||
$inc: { |
||||
unread: inc |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
incUnreadForRoomIdExcludingUserId(roomId, userId, inc) { |
||||
if (inc == null) { inc = 1; } |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': { |
||||
$ne: userId |
||||
} |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
alert: true, |
||||
open: true |
||||
}, |
||||
$inc: { |
||||
unread: inc |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
incUnreadForRoomIdAndUserIds(roomId, userIds, inc) { |
||||
if (inc == null) { inc = 1; } |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': { |
||||
$in: userIds |
||||
} |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
alert: true, |
||||
open: true |
||||
}, |
||||
$inc: { |
||||
unread: inc |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
setAlertForRoomIdExcludingUserId(roomId, userId) { |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': { |
||||
$ne: userId |
||||
}, |
||||
$or: [ |
||||
{ alert: { $ne: true } }, |
||||
{ open: { $ne: true } } |
||||
] |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
alert: true, |
||||
open: true |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
setBlockedByRoomId(rid, blocked, blocker) { |
||||
const query = { |
||||
rid, |
||||
'u._id': blocked |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
blocked: true |
||||
} |
||||
}; |
||||
|
||||
const query2 = { |
||||
rid, |
||||
'u._id': blocker |
||||
}; |
||||
|
||||
const update2 = { |
||||
$set: { |
||||
blocker: true |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update) && this.update(query2, update2); |
||||
} |
||||
|
||||
unsetBlockedByRoomId(rid, blocked, blocker) { |
||||
const query = { |
||||
rid, |
||||
'u._id': blocked |
||||
}; |
||||
|
||||
const update = { |
||||
$unset: { |
||||
blocked: 1 |
||||
} |
||||
}; |
||||
|
||||
const query2 = { |
||||
rid, |
||||
'u._id': blocker |
||||
}; |
||||
|
||||
const update2 = { |
||||
$unset: { |
||||
blocker: 1 |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update) && this.update(query2, update2); |
||||
} |
||||
|
||||
updateTypeByRoomId(roomId, type) { |
||||
const query = |
||||
{rid: roomId}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
t: type |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
addRoleById(_id, role) { |
||||
const query = |
||||
{_id}; |
||||
|
||||
const update = { |
||||
$addToSet: { |
||||
roles: role |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
removeRoleById(_id, role) { |
||||
const query = |
||||
{_id}; |
||||
|
||||
const update = { |
||||
$pull: { |
||||
roles: role |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setArchivedByUsername(username, archived) { |
||||
const query = { |
||||
t: 'd', |
||||
name: username |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
archived |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update, { multi: true }); |
||||
} |
||||
|
||||
// INSERT
|
||||
createWithRoomAndUser(room, user, extraData) { |
||||
const subscription = { |
||||
open: false, |
||||
alert: false, |
||||
unread: 0, |
||||
ts: room.ts, |
||||
rid: room._id, |
||||
name: room.name, |
||||
t: room.t, |
||||
u: { |
||||
_id: user._id, |
||||
username: user.username |
||||
} |
||||
}; |
||||
|
||||
_.extend(subscription, extraData); |
||||
|
||||
return this.insert(subscription); |
||||
} |
||||
|
||||
|
||||
// REMOVE
|
||||
removeByUserId(userId) { |
||||
const query = |
||||
{'u._id': userId}; |
||||
|
||||
return this.remove(query); |
||||
} |
||||
|
||||
removeByRoomId(roomId) { |
||||
const query = |
||||
{rid: roomId}; |
||||
|
||||
return this.remove(query); |
||||
} |
||||
|
||||
removeByRoomIdAndUserId(roomId, userId) { |
||||
const query = { |
||||
rid: roomId, |
||||
'u._id': userId |
||||
}; |
||||
|
||||
return this.remove(query); |
||||
} |
||||
} |
||||
|
||||
RocketChat.models.Subscriptions = new ModelSubscriptions('subscription', true); |
@ -0,0 +1,91 @@ |
||||
RocketChat.models.Uploads = new class extends RocketChat.models._Base { |
||||
constructor() { |
||||
super('uploads'); |
||||
|
||||
this.tryEnsureIndex({ 'rid': 1 }); |
||||
this.tryEnsureIndex({ 'uploadedAt': 1 }); |
||||
} |
||||
|
||||
findNotHiddenFilesOfRoom(roomId, limit) { |
||||
const fileQuery = { |
||||
rid: roomId, |
||||
complete: true, |
||||
uploading: false, |
||||
_hidden: { |
||||
$ne: true |
||||
} |
||||
}; |
||||
|
||||
const fileOptions = { |
||||
limit, |
||||
sort: { |
||||
uploadedAt: -1 |
||||
}, |
||||
fields: { |
||||
_id: 1, |
||||
userId: 1, |
||||
rid: 1, |
||||
name: 1, |
||||
description: 1, |
||||
type: 1, |
||||
url: 1, |
||||
uploadedAt: 1 |
||||
} |
||||
}; |
||||
|
||||
return this.find(fileQuery, fileOptions); |
||||
} |
||||
|
||||
insertFileInit(roomId, userId, store, file, extra) { |
||||
const fileData = { |
||||
rid: roomId, |
||||
userId, |
||||
store, |
||||
complete: false, |
||||
uploading: true, |
||||
progress: 0, |
||||
extension: s.strRightBack(file.name, '.'), |
||||
uploadedAt: new Date() |
||||
}; |
||||
|
||||
_.extend(fileData, file, extra); |
||||
|
||||
if ((this.model.direct != null ? this.model.direct.insert : undefined) != null) { |
||||
file = this.model.direct.insert(fileData); |
||||
} else { |
||||
file = this.insert(fileData); |
||||
} |
||||
|
||||
return file; |
||||
} |
||||
|
||||
updateFileComplete(fileId, userId, file) { |
||||
let result; |
||||
if (!fileId) { |
||||
return; |
||||
} |
||||
|
||||
const filter = { |
||||
_id: fileId, |
||||
userId |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
complete: true, |
||||
uploading: false, |
||||
progress: 1 |
||||
} |
||||
}; |
||||
|
||||
update.$set = _.extend(file, update.$set); |
||||
|
||||
if ((this.model.direct != null ? this.model.direct.insert : undefined) != null) { |
||||
result = this.model.direct.update(filter, update); |
||||
} else { |
||||
result = this.update(filter, update); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
}; |
@ -0,0 +1,538 @@ |
||||
class ModelUsers extends RocketChat.models._Base { |
||||
constructor() { |
||||
super(...arguments); |
||||
|
||||
this.tryEnsureIndex({ 'roles': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'name': 1 }); |
||||
this.tryEnsureIndex({ 'lastLogin': 1 }); |
||||
this.tryEnsureIndex({ 'status': 1 }); |
||||
this.tryEnsureIndex({ 'active': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'statusConnection': 1 }, { sparse: 1 }); |
||||
this.tryEnsureIndex({ 'type': 1 }); |
||||
|
||||
this.cache.ensureIndex('username', 'unique'); |
||||
} |
||||
|
||||
findOneByImportId(_id, options) { |
||||
return this.findOne({ importIds: _id }, options); |
||||
} |
||||
|
||||
findOneByUsername(username, options) { |
||||
const query = {username}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
findOneByEmailAddress(emailAddress, options) { |
||||
const query = {'emails.address': new RegExp(`^${ s.escapeRegExp(emailAddress) }$`, 'i')}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
findOneAdmin(admin, options) { |
||||
const query = {admin}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
findOneByIdAndLoginToken(_id, token, options) { |
||||
const query = { |
||||
_id, |
||||
'services.resume.loginTokens.hashedToken' : Accounts._hashLoginToken(token) |
||||
}; |
||||
|
||||
return this.findOne(query, options); |
||||
} |
||||
|
||||
|
||||
// FIND
|
||||
findById(userId) { |
||||
const query = {_id: userId}; |
||||
|
||||
return this.find(query); |
||||
} |
||||
|
||||
findUsersNotOffline(options) { |
||||
const query = { |
||||
username: { |
||||
$exists: 1 |
||||
}, |
||||
status: { |
||||
$in: ['online', 'away', 'busy'] |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
|
||||
findByUsername(username, options) { |
||||
const query = {username}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findUsersByUsernamesWithHighlights(usernames, options) { |
||||
if (this.useCache) { |
||||
const result = { |
||||
fetch() { |
||||
return RocketChat.models.Users.getDynamicView('highlights').data().filter(record => usernames.indexOf(record.username) > -1); |
||||
}, |
||||
count() { |
||||
return result.fetch().length; |
||||
}, |
||||
forEach(fn) { |
||||
return result.fetch().forEach(fn); |
||||
} |
||||
}; |
||||
return result; |
||||
} |
||||
|
||||
const query = { |
||||
username: { $in: usernames }, |
||||
'settings.preferences.highlights.0': { |
||||
$exists: true |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findActiveByUsernameOrNameRegexWithExceptions(searchTerm, exceptions, options) { |
||||
if (exceptions == null) { exceptions = []; } |
||||
if (options == null) { options = {}; } |
||||
if (!_.isArray(exceptions)) { |
||||
exceptions = [ exceptions ]; |
||||
} |
||||
|
||||
const termRegex = new RegExp(s.escapeRegExp(searchTerm), 'i'); |
||||
const query = { |
||||
$or: [{ |
||||
username: termRegex |
||||
}, { |
||||
name: termRegex |
||||
}], |
||||
active: true, |
||||
type: { |
||||
$in: ['user', 'bot'] |
||||
}, |
||||
$and: [{ |
||||
username: { |
||||
$exists: true |
||||
} |
||||
}, { |
||||
username: { |
||||
$nin: exceptions |
||||
} |
||||
}] |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByActiveUsersExcept(searchTerm, exceptions, options) { |
||||
if (exceptions == null) { exceptions = []; } |
||||
if (options == null) { options = {}; } |
||||
if (!_.isArray(exceptions)) { |
||||
exceptions = [ exceptions ]; |
||||
} |
||||
|
||||
const termRegex = new RegExp(s.escapeRegExp(searchTerm), 'i'); |
||||
const query = { |
||||
$and: [ |
||||
{ |
||||
active: true, |
||||
$or: [ |
||||
{ |
||||
username: termRegex |
||||
}, |
||||
{ |
||||
name: termRegex |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
username: { $exists: true, $nin: exceptions } |
||||
} |
||||
] |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findUsersByNameOrUsername(nameOrUsername, options) { |
||||
const query = { |
||||
username: { |
||||
$exists: 1 |
||||
}, |
||||
|
||||
$or: [ |
||||
{name: nameOrUsername}, |
||||
{username: nameOrUsername} |
||||
], |
||||
|
||||
type: { |
||||
$in: ['user'] |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findByUsernameNameOrEmailAddress(usernameNameOrEmailAddress, options) { |
||||
const query = { |
||||
$or: [ |
||||
{name: usernameNameOrEmailAddress}, |
||||
{username: usernameNameOrEmailAddress}, |
||||
{'emails.address': usernameNameOrEmailAddress} |
||||
], |
||||
type: { |
||||
$in: ['user', 'bot'] |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findLDAPUsers(options) { |
||||
const query = {ldap: true}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
findCrowdUsers(options) { |
||||
const query = {crowd: true}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
getLastLogin(options) { |
||||
if (options == null) { options = {}; } |
||||
const query = { lastLogin: { $exists: 1 } }; |
||||
options.sort = { lastLogin: -1 }; |
||||
options.limit = 1; |
||||
const [user] = this.find(query, options).fetch(); |
||||
return user && user.lastLogin; |
||||
} |
||||
|
||||
findUsersByUsernames(usernames, options) { |
||||
const query = { |
||||
username: { |
||||
$in: usernames |
||||
} |
||||
}; |
||||
|
||||
return this.find(query, options); |
||||
} |
||||
|
||||
// UPDATE
|
||||
addImportIds(_id, importIds) { |
||||
importIds = [].concat(importIds); |
||||
|
||||
const query = {_id}; |
||||
|
||||
const update = { |
||||
$addToSet: { |
||||
importIds: { |
||||
$each: importIds |
||||
} |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
updateLastLoginById(_id) { |
||||
const update = { |
||||
$set: { |
||||
lastLogin: new Date |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setServiceId(_id, serviceName, serviceId) { |
||||
const update = |
||||
{$set: {}}; |
||||
|
||||
const serviceIdKey = `services.${ serviceName }.id`; |
||||
update.$set[serviceIdKey] = serviceId; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setUsername(_id, username) { |
||||
const update = |
||||
{$set: {username}}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setEmail(_id, email) { |
||||
const update = { |
||||
$set: { |
||||
emails: [{ |
||||
address: email, |
||||
verified: false |
||||
} |
||||
] |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setEmailVerified(_id, email) { |
||||
const query = { |
||||
_id, |
||||
emails: { |
||||
$elemMatch: { |
||||
address: email, |
||||
verified: false |
||||
} |
||||
} |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
'emails.$.verified': true |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
setName(_id, name) { |
||||
const update = { |
||||
$set: { |
||||
name |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setCustomFields(_id, fields) { |
||||
const values = {}; |
||||
Object.keys(fields).reduce(key => { |
||||
const value = fields[key]; |
||||
values[`customFields.${ key }`] = value; |
||||
}); |
||||
|
||||
const update = {$set: values}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setAvatarOrigin(_id, origin) { |
||||
const update = { |
||||
$set: { |
||||
avatarOrigin: origin |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
unsetAvatarOrigin(_id) { |
||||
const update = { |
||||
$unset: { |
||||
avatarOrigin: 1 |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setUserActive(_id, active) { |
||||
if (active == null) { active = true; } |
||||
const update = { |
||||
$set: { |
||||
active |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setAllUsersActive(active) { |
||||
const update = { |
||||
$set: { |
||||
active |
||||
} |
||||
}; |
||||
|
||||
return this.update({}, update, { multi: true }); |
||||
} |
||||
|
||||
unsetLoginTokens(_id) { |
||||
const update = { |
||||
$set: { |
||||
'services.resume.loginTokens' : [] |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
unsetRequirePasswordChange(_id) { |
||||
const update = { |
||||
$unset: { |
||||
'requirePasswordChange' : true, |
||||
'requirePasswordChangeReason' : true |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
resetPasswordAndSetRequirePasswordChange(_id, requirePasswordChange, requirePasswordChangeReason) { |
||||
const update = { |
||||
$unset: { |
||||
'services.password': 1 |
||||
}, |
||||
$set: { |
||||
requirePasswordChange, |
||||
requirePasswordChangeReason |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setLanguage(_id, language) { |
||||
const update = { |
||||
$set: { |
||||
language |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setProfile(_id, profile) { |
||||
const update = { |
||||
$set: { |
||||
'settings.profile': profile |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setPreferences(_id, preferences) { |
||||
const update = { |
||||
$set: { |
||||
'settings.preferences': preferences |
||||
} |
||||
}; |
||||
|
||||
return this.update(_id, update); |
||||
} |
||||
|
||||
setUtcOffset(_id, utcOffset) { |
||||
const query = { |
||||
_id, |
||||
utcOffset: { |
||||
$ne: utcOffset |
||||
} |
||||
}; |
||||
|
||||
const update = { |
||||
$set: { |
||||
utcOffset |
||||
} |
||||
}; |
||||
|
||||
return this.update(query, update); |
||||
} |
||||
|
||||
saveUserById(_id, data) { |
||||
const setData = {}; |
||||
const unsetData = {}; |
||||
|
||||
if (data.name != null) { |
||||
if (!_.isEmpty(s.trim(data.name))) { |
||||
setData.name = s.trim(data.name); |
||||
} else { |
||||
unsetData.name = 1; |
||||
} |
||||
} |
||||
|
||||
if (data.email != null) { |
||||
if (!_.isEmpty(s.trim(data.email))) { |
||||
setData.emails = [{address: s.trim(data.email)}]; |
||||
} else { |
||||
unsetData.emails = 1; |
||||
} |
||||
} |
||||
|
||||
if (data.phone != null) { |
||||
if (!_.isEmpty(s.trim(data.phone))) { |
||||
setData.phone = [{phoneNumber: s.trim(data.phone)}]; |
||||
} else { |
||||
unsetData.phone = 1; |
||||
} |
||||
} |
||||
|
||||
const update = {}; |
||||
|
||||
if (!_.isEmpty(setData)) { |
||||
update.$set = setData; |
||||
} |
||||
|
||||
if (!_.isEmpty(unsetData)) { |
||||
update.$unset = unsetData; |
||||
} |
||||
|
||||
if (_.isEmpty(update)) { |
||||
return true; |
||||
} |
||||
|
||||
return this.update({ _id }, update); |
||||
} |
||||
|
||||
// INSERT
|
||||
create(data) { |
||||
const user = { |
||||
createdAt: new Date, |
||||
avatarOrigin: 'none' |
||||
}; |
||||
|
||||
_.extend(user, data); |
||||
|
||||
return this.insert(user); |
||||
} |
||||
|
||||
|
||||
// REMOVE
|
||||
removeById(_id) { |
||||
return this.remove(_id); |
||||
} |
||||
|
||||
/* |
||||
Find users to send a message by email if: |
||||
- he is not online |
||||
- has a verified email |
||||
- has not disabled email notifications |
||||
- `active` is equal to true (false means they were deactivated and can't login) |
||||
*/ |
||||
getUsersToSendOfflineEmail(usersIds) { |
||||
const query = { |
||||
_id: { |
||||
$in: usersIds |
||||
}, |
||||
active: true, |
||||
status: 'offline', |
||||
statusConnection: { |
||||
$ne: 'online' |
||||
}, |
||||
'emails.verified': true |
||||
}; |
||||
|
||||
return this.find(query, { fields: { name: 1, username: 1, emails: 1, 'settings.preferences.emailNotificationMode': 1 } }); |
||||
} |
||||
} |
||||
|
||||
RocketChat.models.Users = new ModelUsers(Meteor.users, true); |
Loading…
Reference in new issue