diff --git a/.meteor/packages b/.meteor/packages index ad4d8c5a198..b56ad45f922 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -61,6 +61,7 @@ rocketchat:oembed rocketchat:slashcommands-invite rocketchat:slashcommands-join rocketchat:slashcommands-leave +rocketchat:slashcommands-kick rocketchat:spotify rocketchat:statistics rocketchat:theme diff --git a/.meteor/versions b/.meteor/versions index 1a0b0849829..5ec2cf20d5f 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -150,6 +150,7 @@ rocketchat:message-star@0.0.1 rocketchat:oembed@0.0.1 rocketchat:slashcommands-invite@0.0.1 rocketchat:slashcommands-join@0.0.1 +rocketchat:slashcommands-kick@0.0.1 rocketchat:slashcommands-leave@0.0.1 rocketchat:spotify@0.0.1 rocketchat:statistics@0.0.1 diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 85fb340d789..018e3f6aaef 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -368,6 +368,7 @@ "Remove" : "Remove", "Remove_Admin" : "Remove Admin", "Remove_custom_oauth" : "Remove custom oauth", + "Remove_from_room" : "Remove from room", "Reset_password" : "Reset password", "Restart" : "Restart", "Restart_the_server" : "Restart the server", @@ -494,6 +495,7 @@ "User_not_found_or_incorrect_password" : "User not found or incorrect password", "User_or_channel_name" : "User or channel name", "User_removed_by" : "User __user_removed__ removed by __user_by__.", + "User_removed_from_room" : "The user has been removed from the room", "User_Settings" : "User Settings", "User_updated_successfully" : "User updated successfully", "Username" : "Username", diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee index 905a43410e6..d7043df9ba7 100644 --- a/packages/rocketchat-authorization/server/startup.coffee +++ b/packages/rocketchat-authorization/server/startup.coffee @@ -60,6 +60,9 @@ Meteor.startup -> { _id: 'delete-message', roles : ['admin', 'site-moderator', 'moderator']} + { _id: 'remove-user', + roles : ['admin', 'site-moderator', 'moderator']} + { _id: 'ban-user', roles : ['admin', 'site-moderator', 'moderator']} diff --git a/packages/rocketchat-slashcommands-kick/client.coffee b/packages/rocketchat-slashcommands-kick/client.coffee new file mode 100644 index 00000000000..acc40d33db0 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/client.coffee @@ -0,0 +1,11 @@ +RocketChat.slashCommands.add 'kick', (command, params, item) -> + username = params.trim() + if username is '' + return + username = username.replace('@', '') + + if Session.get('showUserInfo') is username + Session.set('showUserInfo', null) +, + description: TAPi18n.__ 'Remove_someone_from_room' + params: '@username' diff --git a/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json b/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json new file mode 100644 index 00000000000..5f448b30f89 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/i18n/en.i18n.json @@ -0,0 +1,5 @@ +{ + "Username_doesnt_exist" : "The username `#%s` doesn't exist.", + "Username_is_not_in_this_room" : "The user `#%s` is not in this room.", + "Remove_someone_from_room" : "Remove someone from the room" +} diff --git a/packages/rocketchat-slashcommands-kick/package.js b/packages/rocketchat-slashcommands-kick/package.js new file mode 100644 index 00000000000..a5ac2b24a42 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/package.js @@ -0,0 +1,37 @@ +Package.describe({ + name: 'rocketchat:slashcommands-kick', + version: '0.0.1', + summary: 'Command handler for the /kick command', + git: '' +}); + +Package.onUse(function(api) { + + api.versionsFrom('1.0'); + + api.use([ + 'coffeescript', + 'check', + 'rocketchat:lib@0.0.1' + ]); + + api.addFiles('client.coffee', 'client'); + api.addFiles('server.coffee', 'server'); + + // TAPi18n + api.use('templating', 'client'); + var _ = Npm.require('underscore'); + var fs = Npm.require('fs'); + tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-slashcommands-kick/i18n'), function(filename) { + if (fs.statSync('packages/rocketchat-slashcommands-kick/i18n/' + filename).size > 16) { + return 'i18n/' + filename; + } + })); + api.use('tap:i18n@1.6.1', ['client', 'server']); + api.imply('tap:i18n'); + api.addFiles(tapi18nFiles, ['client', 'server']); +}); + +Package.onTest(function(api) { + +}); diff --git a/packages/rocketchat-slashcommands-kick/server.coffee b/packages/rocketchat-slashcommands-kick/server.coffee new file mode 100644 index 00000000000..112313be987 --- /dev/null +++ b/packages/rocketchat-slashcommands-kick/server.coffee @@ -0,0 +1,40 @@ +### +# Kick is a named function that will replace /kick commands +### + +class Kick + constructor: (command, params, item) -> + if command isnt 'kick' or not Match.test params, String + return + + username = params.trim() + if username is '' + return + + username = username.replace('@', '') + + user = Meteor.users.findOne Meteor.userId() + kickedUser = RocketChat.models.Users.findOneByUsername username + room = RocketChat.models.Rooms.findOneById item.rid + + if not kickedUser? + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_doesnt_exist', { postProcess: 'sprintf', sprintf: [ username ] }, user.language); + } + return + + if username not in (room.usernames or []) + RocketChat.Notifications.notifyUser Meteor.userId(), 'message', { + _id: Random.id() + rid: item.rid + ts: new Date + msg: TAPi18n.__('Username_is_not_in_this_room', { postProcess: 'sprintf', sprintf: [ username ] }, user.language); + } + return + + Meteor.call 'removeUserFromRoom', { rid: item.rid, username: username } + +RocketChat.slashCommands.add 'kick', Kick diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee index 341af443b10..00d323ef43c 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.coffee @@ -33,6 +33,9 @@ Template.userInfo.helpers if @utcOffset? return Template.instance().now.get().utcOffset(@utcOffset).format('HH:mm') + canRemoveUser: -> + return RocketChat.authz.hasAllPermission('remove-user', Session.get('openedRoom')) + Template.userInfo.events 'click .pvt-msg': (e) -> Meteor.call 'createDirectMessage', Session.get('showUserInfo'), (error, result) -> @@ -72,6 +75,19 @@ Template.userInfo.events 'click .back': (e) -> Session.set('showUserInfo', null) + 'click .remove-user': (e, t) -> + e.preventDefault() + rid = Session.get('openedRoom') + room = ChatRoom.findOne rid + if RocketChat.authz.hasAllPermission('remove-user', rid) + Meteor.call 'removeUserFromRoom', { rid: rid, username: @user.username }, (err, result) -> + if err + return toastr.error(err.reason or err.message) + toastr.success TAPi18n.__ 'User_removed_from_room' + Session.set('showUserInfo', null) + else + toastr.error(TAPi18n.__ 'Not_allowed') + Template.userInfo.onCreated -> @now = new ReactiveVar moment() diff --git a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html index 844f5126c3e..85fa40e7a79 100644 --- a/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html +++ b/packages/rocketchat-ui-flextab/flex-tab/tabs/userInfo.html @@ -32,7 +32,10 @@ {{#if showAll}} {{#if canDirectMessage user.username}} - + + {{/if}} + {{#if canRemoveUser}} + {{/if}} {{/if}} diff --git a/packages/rocketchat-ui/views/app/room.coffee b/packages/rocketchat-ui/views/app/room.coffee index b7c9ede601c..e382d70faa3 100644 --- a/packages/rocketchat-ui/views/app/room.coffee +++ b/packages/rocketchat-ui/views/app/room.coffee @@ -301,7 +301,7 @@ Template.room.events "click .flex-tab .user-image > a" : (e) -> RocketChat.TabBar.openFlex() - Session.set('showUserInfo', $(e.currentTarget).data('username')) + Session.set('showUserInfo', @username) 'click .user-card-message': (e) -> roomData = Session.get('roomData' + this._arguments[1].rid) diff --git a/server/methods/removeUserFromRoom.coffee b/server/methods/removeUserFromRoom.coffee index d600b6d991c..c77598660c0 100644 --- a/server/methods/removeUserFromRoom.coffee +++ b/server/methods/removeUserFromRoom.coffee @@ -1,25 +1,31 @@ Meteor.methods removeUserFromRoom: (data) -> fromId = Meteor.userId() - # console.log '[methods] removeUserFromRoom -> '.green, 'fromId:', fromId, 'data:', data + console.log '[methods] removeUserFromRoom -> '.green, 'fromId:', fromId, 'data:', data + + check(data, Match.ObjectIncluding({ rid: String, username: String })) + + unless RocketChat.authz.hasPermission(fromId, 'remove-user', data.rid) + throw new Meteor.Error 'not-allowed', 'Not allowed' room = RocketChat.models.Rooms.findOneById data.rid - if room.u?._id isnt Meteor.userId() and room.t is 'c' - throw new Meteor.Error 403, 'Not allowed' + if data.username not in (room?.usernames or []) + throw new Meteor.Error 'not-in-room', 'User is not in this room' removedUser = RocketChat.models.Users.findOneByUsername data.username RocketChat.models.Rooms.removeUsernameById data.rid, data.username - RocketChat.models.Subscriptions.removeByRoomIdAndUserId data.rid, data.username + RocketChat.models.Subscriptions.removeByRoomIdAndUserId data.rid, removedUser._id - switch room.t - when 'c' - RocketChat.authz.removeUsersFromRole(removedUser._id; 'channel-moderator', data.rid) - when 'p' - RocketChat.authz.removeUsersFromRole(removedUser._id; 'group-moderator', data.rid) + if room.t in [ 'c', 'p' ] + RocketChat.authz.removeUsersFromRoles(removedUser._id; 'moderator', data.rid) - RocketChat.models.Messages.createUserRemovedWithRoomIdAndUser data.rid, removedUser + fromUser = RocketChat.models.Users.findOneById fromId + RocketChat.models.Messages.createUserRemovedWithRoomIdAndUser data.rid, removedUser, + u: + _id: fromUser._id + username: fromUser.username return true