Skip to content

Commit 39ec65f

Browse files
authored
Merge pull request #434 from assistify/#418-requestless-threading
Update the Rocket.Chat core PR from assistify-branch
2 parents 0a8858d + d96df06 commit 39ec65f

File tree

17 files changed

+238
-45
lines changed

17 files changed

+238
-45
lines changed

.meteor/packages

+1
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,5 @@ tap:i18n
198198
underscore
199199

200200
assistify:threading
201+
assistify:migrations
201202
overture8:wordcloud2

.meteor/versions

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ accounts-password@1.5.1
88
accounts-twitter@1.4.1
99
aldeed:simple-schema@1.5.4
1010
allow-deny@1.1.0
11+
assistify:migrations@0.0.1
1112
assistify:threading@0.1.0
1213
autoupdate@1.4.0
1314
babel-compiler@7.0.9

packages/assistify-migrations/README.md

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Write your package code here!
2+
3+
// Variables exported by this module can be imported by other packages and
4+
// applications. See migrations-tests.js for an example of importing.
5+
export const name = 'migrations';
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Package.describe({
2+
name: 'assistify:migrations',
3+
version: '0.0.1',
4+
summary: 'Assistify migrations',
5+
git: 'http://github.com/assistify/Rocket.Chat',
6+
documentation: ''
7+
});
8+
9+
Package.onUse(function(api) {
10+
api.versionsFrom('1.6.1.1');
11+
api.use('ecmascript');
12+
api.mainModule('migrations.js');
13+
api.addFiles('server/startup/migrations.js', 'server');
14+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
Up to now, there's no "DB version" stored for assistify.
3+
Until we've got expensive of contradicting migrations, we'll just use this file to write functions running
4+
on startup which migrate data - ignoring the actual version
5+
*/
6+
7+
Meteor.startup(() => {
8+
const topics = RocketChat.models.Rooms.findByType('e').fetch();
9+
let counterRequests = 0;
10+
// Update room type and parent room id for request
11+
12+
const mapRoomParentRoom = new Map();
13+
RocketChat.models.Rooms.findByType('r').forEach((request) => {
14+
const update = {};
15+
update.$set = {};
16+
let parentTopic = null;
17+
18+
if (request.expertise) {
19+
parentTopic = topics.find(topic => {
20+
return request.expertise === topic.name;
21+
});
22+
if (!parentTopic) {
23+
console.log('couldn\'t find topic', request.expertise, '- ignoring');
24+
} else {
25+
update.$set.parentRoomId = parentTopic._id;
26+
mapRoomParentRoom.set(request._id, parentTopic._id); // buffer the mapping for the subscriptions update lateron
27+
}
28+
}
29+
update.$set.oldType = request.t;
30+
update.$set.t = 'p';
31+
// update requests
32+
RocketChat.models.Rooms.update({_id: request._id}, update);
33+
counterRequests++;
34+
});
35+
console.log('Migrated', counterRequests, 'requests to private groups');
36+
37+
//Update room type and parent room id for expertises
38+
RocketChat.models.Rooms.update({
39+
t: 'e'
40+
}, {
41+
$set: {
42+
oldType: 'e', // move the room type as old room type
43+
t: 'c' // set new room type to public channel
44+
}
45+
}, {
46+
multi: true
47+
});
48+
49+
//update subscriptions for requests
50+
RocketChat.models.Subscriptions.update({
51+
t: 'r'
52+
}, {
53+
$set: {
54+
oldType: 'r',
55+
t: 'p'
56+
}
57+
}, {
58+
multi: true
59+
});
60+
61+
// provide parent Room links in the subscriptions as well
62+
mapRoomParentRoom.forEach((value, key)=>{
63+
RocketChat.models.Subscriptions.update({
64+
rid: key
65+
}, {
66+
$set: {
67+
parentRoomId: value
68+
}
69+
}, {
70+
multi: true
71+
});
72+
});
73+
74+
//update subscriptions for expertises
75+
RocketChat.models.Subscriptions.update({
76+
t: 'e'
77+
}, {
78+
$set: {
79+
oldType: 'e',
80+
t: 'c'
81+
}
82+
}, {
83+
multi: true
84+
});
85+
86+
});

packages/assistify-threading/client/createThreadMessageAction.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ Meteor.startup(function() {
1717
// remove the hidden message from the UI - the message list is not reactive
1818
Tracker.nonreactive(function() {
1919
ChatMessage.remove({
20-
_id: message._id,
21-
'u._id': Meteor.userId()
20+
_id: message._id
2221
});
2322
});
2423

Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template name="ChannelNotFound">
22
<div>
33
{{#if showMoreTopics}}
4-
<a id="more-topics" href='#'>{{_ "Topic_Search"}}</a>
4+
<a>{{_ "Enter_a_room_name"}}</a>
55
{{else}}
66
<a>{{_ "Nothing_found"}}.</a>
77
{{/if}}
88
</div>
9-
</template>
9+
</template>

packages/assistify-threading/client/views/creationDialog/CreateThread.js

+1
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ Template.CreateThread.onRendered(function() {
274274
const parentChannelElement = this.find('#parentChannel-search');
275275
const questionElement = this.find('#first_question');
276276

277+
questionElement.focus();
277278
instance.ac.element = parentChannelElement;
278279
instance.ac.$element = $(instance.ac.element);
279280
instance.ac.$element.on('autocompleteselect', function(e, { item }) {

packages/assistify-threading/config.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ function getParentChannels() {
44
return result.channels.map((channel) => {
55
if (channel.name !== null) {
66
return {
7-
key: channel.name,
7+
key: channel.name, // has to be "key" in order to be able to select it in the settings as dropdown
88
i18nLabel: channel.name
99
};
1010
}
@@ -15,8 +15,16 @@ Meteor.startup(() => {
1515
RocketChat.settings.addGroup('Threading');
1616

1717
// the channel for which threads are created if none is explicitly chosen
18-
const potentialParentChannels = getParentChannels();
19-
const defaultChannel = potentialParentChannels[0] ? potentialParentChannels[0].key : '';
18+
let defaultChannel = '';
19+
20+
const generalChannel = RocketChat.models.Rooms.findOneById('GENERAL');
21+
22+
if (generalChannel) {
23+
defaultChannel = generalChannel.name;
24+
} else {
25+
const potentialParentChannels = getParentChannels();
26+
defaultChannel = potentialParentChannels[0] ? potentialParentChannels[0].key : '';
27+
}
2028
RocketChat.settings.add('Thread_default_parent_Channel', defaultChannel, {
2129
group: 'Threading',
2230
i18nLabel: 'Thread_default_parent_Channel',

packages/assistify-threading/lib/messageTypes/threadMessage.js

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Meteor.startup(function() {
77
message: 'thread-created',
88
data(message) {
99
return {
10+
channelLink: `<a class="mention-link" data-channel= ${ message.channels[0]._id } title="">${ TAPi18n.__('thread') }</a>`,
1011
message: `<a class="mention-link" data-channel= ${ message.channels[0]._id } title="">&quot;${ message.channels[0].initialMessage.text }&quot;</a>`,
1112
username: `<a class="mention-link" data-username= ${ message.mentions[0].name } title="">@${ message.mentions[0].name }</a>`
1213
};

packages/assistify-threading/lib/threadRoomType.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class ThreadRoomType extends RoomTypeConfig {
44
constructor() {
55
super({
66
identifier: 'thread',
7-
order: 5,
7+
order: 25,
88
label: 'Threads'
99
});
1010

packages/assistify-threading/server/methods/createThread.js

+57-31
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { FlowRouter } from 'meteor/kadira:flow-router';
44
import { Meteor } from 'meteor/meteor';
55

66
/*
7-
* When a message is eligible to be answered as a independent question then it can be threaded into a new channel.
7+
* When a repostedMessage is eligible to be answered as a independent question then it can be threaded into a new channel.
88
* When threading, the question is re-posted into a new room. To leave origin traces between the messages we update
9-
* the original message with system message to allow user to navigate to the message created in the new Room and vice verse.
9+
* the original repostedMessage with system repostedMessage to allow user to navigate to the repostedMessage created in the new Room and vice verse.
1010
*/
1111
export class ThreadBuilder {
1212
constructor(parentRoomId, openingQuestion) {
@@ -37,46 +37,72 @@ export class ThreadBuilder {
3737
return RocketChat.models.Rooms.findOne(roomId);
3838
}
3939

40-
_postMessage(room, user, message, attachments, channels, mentions) {
40+
_postMessage(room, user, repostedMessage, attachments, channels, mentions) {
4141
attachments = attachments || [];
4242

4343
//sendMessage expects the attachments timestamp to be a string, => serialize it
4444
attachments.forEach(attachment =>
4545
attachment.ts = attachment.ts ? attachment.ts.toISOString() : ''
4646
);
47-
const newMessage = { _id: Random.id(), rid: room.rid, msg: message, attachments, channels, mentions };
47+
const newMessage = { _id: Random.id(), rid: room.rid, msg: repostedMessage, attachments, channels, mentions };
4848
return RocketChat.sendMessage(user, newMessage, room);
4949
}
5050

5151
_getMessageUrl(msgId) {
52-
return FlowRouter.path('message', { id: msgId });
52+
const siteUrl = RocketChat.settings.get('Site_Url');
53+
return `${ siteUrl }${ siteUrl.endsWith('/') ? '' : '/' }?msg=${ msgId }`;
5354
}
5455

55-
_linkMessages(roomCreated, parentRoom, message) {
56+
_linkMessages(roomCreated, parentRoom, repostedMessage) {
5657
const rocketCatUser = RocketChat.models.Users.findOneByUsername('rocket.cat');
5758
if (rocketCatUser && Meteor.userId()) {
58-
/* Add link in parent Room
59-
*/
60-
RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser('create-thread', parentRoom._id, this._getMessageUrl(message._id), rocketCatUser,
61-
{
62-
mentions: [{
63-
_id: Meteor.user()._id, // Thread Initiator
64-
name: Meteor.user().username // Use @Name field for navigation
65-
}],
66-
channels: [{
67-
_id: roomCreated._id, // Parent Room ID
68-
name: roomCreated.name,
69-
initialMessage: {
70-
_id: message._id,
71-
text: message.msg
72-
}
73-
}]
74-
});
59+
/* Add link in parent Room */
60+
61+
const linkMessage = Object.assign({}, this._openingQuestion); // shallow copy of the original message
62+
delete linkMessage._id;
63+
64+
const repostingUser = Meteor.user();
65+
linkMessage.u = {
66+
_id: repostingUser._id,
67+
username: repostingUser.username,
68+
name: repostingUser.name
69+
};
70+
71+
linkMessage.mentions = [{
72+
_id: repostingUser._id, // Thread Initiator
73+
name: repostingUser.username // Use @Name field for navigation
74+
}].concat(this._openingQuestion.mentions||[]);
75+
76+
linkMessage.channels = [{
77+
_id: roomCreated._id, // Parent Room ID
78+
name: roomCreated.name,
79+
initialMessage: {
80+
_id: repostedMessage._id,
81+
text: repostedMessage.msg
82+
}
83+
}];
84+
85+
const messageQuoteAttachment = { // @see pinMessage.js
86+
message_link: FlowRouter.path('message', { id: repostedMessage._id }),
87+
text: this._openingQuestion.msg,
88+
ts: this._openingQuestion.ts
89+
};
90+
91+
if (repostingUser._id !== this._openingQuestion.u._id) {
92+
messageQuoteAttachment.author_name = this._openingQuestion.u.username;
93+
messageQuoteAttachment.author_icon = getAvatarUrlFromUsername(this._openingQuestion.u.username);
94+
}
95+
96+
linkMessage.attachments = [messageQuoteAttachment].concat(this._openingQuestion.attachments||[]);
97+
98+
linkMessage.urls = [{url: this._getMessageUrl(repostedMessage._id)}];
99+
100+
return RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser('create-thread', parentRoom._id, this._getMessageUrl(repostedMessage._id), rocketCatUser, linkMessage, {ts: this._openingQuestion.ts});
75101
}
76102
}
77103

78104
_getMembers() {
79-
const checkRoles = ['owner', 'moderator'];
105+
const checkRoles = ['owner', 'moderator', 'leader'];
80106
const members = [];
81107
const users = RocketChat.models.Subscriptions.findByRoomIdWhenUsernameExists(this._parentRoomId, {
82108
fields: {
@@ -111,7 +137,7 @@ export class ThreadBuilder {
111137

112138
create() {
113139
const parentRoom = ThreadBuilder.getRoom(this._parentRoomId);
114-
// Generate RoomName for xthe new room to be created.
140+
// Generate RoomName for the new room to be created.
115141
this.name = `${ parentRoom.name || parentRoom.usernames.join('-') }-${ ThreadBuilder.getNextId() }`;
116142
const threadRoomType = parentRoom.t === 'd' ? 'p' : parentRoom.t;
117143
const threadRoom = RocketChat.createRoom(threadRoomType, this.name, Meteor.user() && Meteor.user().username, this._getMembers(), false,
@@ -125,14 +151,14 @@ export class ThreadBuilder {
125151
const room = RocketChat.models.Rooms.findOneById(threadRoom.rid);
126152
if (room && parentRoom) {
127153
// Post message
128-
const message = this._postMessage(
154+
const repostedMessage = this._postMessage(
129155
room,
130156
this._openingQuestion.u,
131157
this._openingQuestion.msg,
132158
this._openingQuestion.attachments ? this._openingQuestion.attachments.filter(attachment => attachment.type && attachment.type === 'file') : []
133159
);
134160
// Link messages
135-
this._linkMessages(room, parentRoom, message);
161+
this._linkMessages(room, parentRoom, repostedMessage);
136162
}
137163

138164
return threadRoom;
@@ -148,11 +174,11 @@ Meteor.methods({
148174

149175
return new ThreadBuilder(parentRoomId, openingQuestion).create();
150176
},
151-
createThreadFromMessage(message) {
152-
const thread = Meteor.call('createThread', message.rid, message);
177+
createThreadFromMessage(openingQuestion) {
178+
const thread = Meteor.call('createThread', openingQuestion.rid, openingQuestion);
153179
if (thread) {
154-
//remove the original message from the display
155-
RocketChat.models.Messages.setHiddenById(message._id);
180+
//remove the original repostedMessage from the display
181+
RocketChat.models.Messages.setHiddenById(openingQuestion._id);
156182
return thread;
157183
}
158184
}

packages/rocketchat-i18n/i18n/de.i18n.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -1831,7 +1831,7 @@
18311831
"New_role": "Neue Rolle",
18321832
"New_Room_Notification": "Neuer-Raum-Benachrichtigung",
18331833
"New_thread": "Neuer Thread",
1834-
"New_thread_first_message": "Üblicherweise beginn ein Thread mit einer Frage, bspw. \"Wie lade ich ein Bild hoch?\"",
1834+
"New_thread_first_message": "Üblicherweise beginnt ein Thread mit einer Frage, bspw. \"Wie lade ich ein Bild hoch?\"",
18351835
"New_Trigger": "Neuer Trigger",
18361836
"New_version_available_(s)": "Neue Version verfügbar (%s)",
18371837
"New_videocall_request": "Neuer Video-Anruf",
@@ -2506,10 +2506,10 @@
25062506
"This_room_has_been_unarchived_by__username_": "Dieser Raum wurde von __username__ aus dem Archiv geholt",
25072507
"Threading_title": "Einen neuen Thread anlegen",
25082508
"Thread_start": "Thread starten",
2509-
"thread-created" : "__username__ hat einen neuen Thread angelegt: __message__.",
2510-
"Threading_description": "Hilf dabei, die Übersicht zu behalten! Indem Du einen Thread anlegst, wird ein Unterkanal mit passenden Mitgliedern erstellt.",
2509+
"thread-created" : "Ich habe einen neuen __channelLink__ angelegt",
2510+
"Threading_description": "Erstelle einen Thread, um wichtigen Dingen mehr Raum zu geben. Dort kannst Du mit allen verfügbaren Mitgliedern schreiben, ohne andere zu stören. So sorgst Du für etwas mehr Ordnung in Eurem Chat.",
25112511
"Thread_from_context_menu": "Threads im Kontext-Menü",
2512-
"Threading_context_menu_button": "Eigener Button",
2512+
"Threading_context_menu_button": "Separater Button",
25132513
"Threading_context_menu_none": "Unsichtbar",
25142514
"Thread_creation_on_home": "Threads von der Home-Seite aus anlegen",
25152515
"Thread_default_parent_Channel": "Standard-Kanal für neue Threads",
@@ -2518,6 +2518,7 @@
25182518
"Thread_target_channel_description": "Wähle einen Kanal oder eine Gruppe aus, die zu Deinem Anliegen passt",
25192519
"Thread_target_channel_prefix": "Du erstellst einen Thread in",
25202520
"Thread_target_channel_suffix": "- wähle einen anderen übergeordneten Kanal aus",
2521+
"thread": "Thread",
25212522
"Threads": "Threads",
25222523
"Threads_in_sidebar": "Threads in Seitenleiste",
25232524
"Threads_in_sidebar_description": "Threads in Seitenleiste gruppieren",

packages/rocketchat-i18n/i18n/en.i18n.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2507,7 +2507,7 @@
25072507
"This_room_has_been_unarchived_by__username_": "This room has been unarchived by __username__",
25082508
"Threading_title": "Create a new thread",
25092509
"Thread_start": "Start a thread",
2510-
"thread-created" : "__username__ has started a new thread: __message__.",
2510+
"thread-created" : "I started a new __channelLink__",
25112511
"Thread_from_context_menu": "Threads in context-menu",
25122512
"Threading_context_menu_button": "Dedicated button",
25132513
"Threading_context_menu_none": "Invisible",
@@ -2519,6 +2519,7 @@
25192519
"Thread_target_channel_description": "Select a channel which is related to what you want to ask",
25202520
"Thread_target_channel_prefix": "You are creating a thread in",
25212521
"Thread_target_channel_suffix": "- select a different parent channel",
2522+
"thread": "thread",
25222523
"Threads": "Threads",
25232524
"Threads_in_sidebar": "Threads in channel list",
25242525
"Threads_in_sidebar_description": "Group threads in sidebar",

0 commit comments

Comments
 (0)