Merge branch 'hotfix/21.56.9' into master
[gitter.git] / public / js / views / chat / commands.js
blob3668d905a09bd8bc47c073ed4a77d9d172579f6e
1 'use strict';
3 var _ = require('lodash');
4 var context = require('gitter-web-client-context');
5 var appEvents = require('../../utils/appevents');
6 var apiClient = require('../../components/api-client');
7 var unreadItemsClient = require('../../components/unread-items-client');
9 function updateNotifications(mode) {
10   apiClient.userRoom.put('/settings/notifications', { mode: mode }).then(function() {
11     appEvents.triggerParent('user_notification', {
12       title: 'Notifications',
13       text: 'Notification settings have been updated for this room'
14     });
15   });
18 const mentionRegexp = `@([\\w\\-.:\\[\\]]+)`;
20 var commandsList = [
21   {
22     command: 'ban @username',
23     description: 'Ban somebody from the room.',
24     criteria: function() {
25       var isOrgRoom = false;
26       if (context.troupe().get('githubType') == 'ORG') isOrgRoom = true;
27       return !context.inOneToOneTroupeContext() && context.isTroupeAdmin() && !isOrgRoom;
28     },
29     completion: 'ban @',
30     regexp: /^\/ban/,
31     action: function(text) {
32       const userMatch = text.match(new RegExp(`\\/ban ${mentionRegexp}(\\s+(removemsgs))?\\s*$`));
33       if (!userMatch) return;
34       var user = userMatch[1];
35       var removeMessages = !!userMatch[3];
37       apiClient.room
38         .post('/bans', { username: user, removeMessages: removeMessages })
39         .catch(function(e) {
40           var errorMessage;
41           switch (e.status) {
42             case 403:
43               errorMessage = 'You do not have permission to ban people.';
44               break;
46             case 400:
47               errorMessage = e.friendlyMessage || 'Ban failed';
48               break;
50             case 404:
51               errorMessage = 'That person does not exist (on Gitter that is)';
52               break;
53             default:
54               errorMessage = 'Ban failed';
55           }
57           appEvents.triggerParent('user_notification', {
58             title: 'Could not ban user',
59             text: errorMessage,
60             className: 'notification-error'
61           });
62         });
63     }
64   },
65   {
66     command: 'channel',
67     description: 'Create a channel',
68     completion: 'channel ',
69     regexp: /^\/channel/,
70     action: function(text) {
71       var channelMatch = text.match(/^\s*\/channel(?:\s+([\w-]+))?/);
72       var channel = channelMatch[1];
74       if (channel) {
75         appEvents.trigger('route', 'createroom/' + channel);
76       } else {
77         appEvents.trigger('route', 'createroom');
78       }
79     }
80   },
81   {
82     command: 'fav',
83     description: 'Toggle the room as a favourite',
84     completion: 'fav ',
85     regexp: /^\/fav\s*$/,
86     action: function() {
87       var isFavourite = !context.troupe().get('favourite');
89       apiClient.userRoom.put('', { favourite: isFavourite });
90     }
91   },
92   {
93     command: 'goto',
94     description: 'Goto the room (foo/bar)',
95     completion: 'goto ',
96     regexp: /^\/goto/,
97     action: function(text) {
98       const gotoMatch = text.match(/^\s*\/goto(?:\s+((?:[^/]+\/?){2,3}))?/);
99       if (!gotoMatch) return;
100       const roomUri = gotoMatch[1];
102       appEvents.trigger('navigation', `/${roomUri}`, 'chat', roomUri);
103     }
104   },
105   {
106     command: 'join',
107     description: 'Goto the room (foo/bar)',
108     completion: 'join ',
109     regexp: /^\/join/,
110     action: function(text) {
111       const joinMatch = text.match(/^\s*\/join(?:\s+((?:[^/]+\/?){2,3}))?/);
112       if (!joinMatch) return;
113       const roomUri = joinMatch[1];
115       appEvents.trigger('navigation', `/${roomUri}`, 'chat', roomUri);
116     }
117   },
118   {
119     command: 'leave',
120     description: 'Leave the room',
121     completion: 'leave ',
122     regexp: /^\/(leave|part)\s*$/,
123     criteria: function() {
124       return !context.inOneToOneTroupeContext();
125     },
126     action: function() {
127       context.troupe().set('aboutToLeave', true);
128       apiClient.room.delete('/users/' + context.getUserId(), {}).then(function() {
129         appEvents.trigger('navigation', '/home', 'home', '');
130         context.troupe().set('roomMember', false);
131       });
132     }
133   },
134   {
135     command: 'me',
136     description: "Let people know what's happening",
137     completion: 'me ',
138     regexp: /^\/me/
139   },
140   {
141     command: 'query @username',
142     description: 'Have a private conversation with @username',
143     completion: 'query @',
144     regexp: /^\/query/,
145     action: function(text) {
146       const userMatch = text.match(new RegExp(`\\/query ${mentionRegexp}\\s*$`));
147       if (!userMatch) return;
148       var user = userMatch[1];
150       var url = '/' + user;
151       var type = user === context.user().get('username') ? 'home' : 'chat';
152       var title = user;
154       appEvents.trigger('navigation', url, type, title);
155     }
156   },
157   {
158     command: 'remove @username',
159     description: 'Remove somebody from the room',
160     criteria: function() {
161       return !context.inOneToOneTroupeContext() && context.isTroupeAdmin();
162     },
163     completion: 'remove @',
164     regexp: /^\/remove/,
165     action: function(text) {
166       const userMatch = text.match(new RegExp(`\\/remove ${mentionRegexp}\\s*$`));
167       if (!userMatch) return;
168       var user = userMatch[1];
169       appEvents.trigger('command.room.remove', user);
170     }
171   },
172   {
173     command: 'subst',
174     regexp: /^s\/([^\/]+)\/([^\/]*)\/i?(g?)\s*$/,
175     action: function(text) {
176       var re = this.regexp.exec(text);
177       var search = re[1];
178       var replace = re[2];
179       var global = !!re[3];
180       appEvents.trigger(
181         'chatCollectionView:substLastChat',
182         context.getUserId(),
183         search,
184         replace,
185         global
186       );
187     }
188   },
189   {
190     command: 'topic foo',
191     description: 'Set room topic to foo',
192     criteria: function() {
193       return !context.inOneToOneTroupeContext() && context.isTroupeAdmin();
194     },
195     completion: 'topic ',
196     regexp: /^\/topic/,
197     action: function(text) {
198       var topicMatch = text.match(/^\/topic (.+)/);
199       if (topicMatch) {
200         var topic = topicMatch[1];
202         context.troupe().set('topic', topic);
204         apiClient.room.put('', { topic: topic });
205       }
206     }
207   },
208   {
209     command: 'unban @username',
210     description: 'Unban somebody from the room',
211     criteria: function() {
212       var isOrgRoom = false;
213       if (context.troupe().get('githubType') == 'ORG') isOrgRoom = true;
214       return !context.inOneToOneTroupeContext() && context.isTroupeAdmin() && !isOrgRoom;
215     },
216     completion: 'unban @',
217     regexp: /^\/unban/,
218     action: function(text) {
219       const userMatch = text.match(new RegExp(`\\/unban ${mentionRegexp}\\s*$`));
220       if (!userMatch) return;
221       var user = userMatch[1];
223       apiClient.room.delete('/bans/' + user, {}).catch(function(e) {
224         var errorMessage;
225         switch (e.status) {
226           case 403:
227             errorMessage = 'You do not have permission to unban people.';
228             break;
230           case 400:
231             errorMessage = e.friendlyMessage || 'Unban failed';
232             break;
234           case 404:
235             errorMessage = 'That person is not on the banned list.';
236             break;
237           default:
238             errorMessage = 'Unban failed';
239         }
241         appEvents.triggerParent('user_notification', {
242           title: 'Could not unban user',
243           text: errorMessage,
244           className: 'notification-error'
245         });
246       });
247     }
248   },
249   {
250     command: 'notify-all',
251     description: 'Get notified on all messages',
252     completion: 'notify-all',
253     regexp: /^\/notify-all\s*$/,
254     action: function() {
255       updateNotifications('all');
256     }
257   },
258   {
259     command: 'notify-announcements',
260     description: 'Get notified on mentions and group messages',
261     completion: 'notify-announcements',
262     regexp: /^\/notify-announcements\s*$/,
263     action: function() {
264       updateNotifications('announcement');
265     }
266   },
267   {
268     command: 'notify-mute',
269     description: 'Mute all notifications, except direct mentions',
270     completion: 'notify-mute',
271     regexp: /^\/notify-mute\s*$/,
272     action: function() {
273       updateNotifications('mute');
274     }
275   },
277   {
278     command: 'mark-all-read',
279     description: 'Mark all chat items as read',
280     completion: 'mark-all-read',
281     regexp: /^\/mark-all-read\s*$/,
282     action: function() {
283       unreadItemsClient.markAllRead();
284     }
285   },
287   // Hidden Commands
288   {
289     command: 'update-default-mode',
290     description: 'Update default mode for rooms',
291     completion: 'update-default-mode',
292     regexp: /^\/update-default-mode\b/,
293     hidden: true,
294     // regexp: /^\/mark-all-read\s*$/,
295     action: function(text) {
296       var topicMatch = text.match(/^\/update-default-mode\s+(all|annoucement|mute)(\s+override)?/);
297       if (!topicMatch) return;
299       var override = !!topicMatch[2];
301       apiClient.user.put('/settings/defaultRoomMode', { mode: topicMatch[1], override: override });
302     }
303   }
306 module.exports = {
307   size: commandsList.length,
309   getSuggestions: function(term) {
310     return commandsList.filter(function(cmd) {
311       var elligible = !cmd.hidden && (!cmd.criteria || cmd.criteria()) && cmd.completion;
312       return elligible && cmd.command.indexOf(term) === 0;
313     });
314   },
316   findMatch: function(text) {
317     return _.find(commandsList, function(cmd) {
318       return text.match(cmd.regexp);
319     });
320   }