From afdfd75baec403722c001fb89b9340d64034cd86 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Sat, 2 Mar 2019 17:57:23 -0300 Subject: [PATCH] [FIX] Non-latin room names and other slugifications (#13467) * Show error toast when channel creation fails * Use limax to slugify room names * Use limax on HipChat importer * Use limax on LDAP * Replace yasaricli:slugify with limax * Import limax module default as 'limax' --- .meteor/packages | 1 - .meteor/versions | 1 - package-lock.json | 70 +++++++++++++++++++ package.json | 1 + .../server/importer.js | 4 +- .../server/importer.js | 6 +- packages/rocketchat-ldap/package.js | 1 - packages/rocketchat-ldap/server/sync.js | 4 +- packages/rocketchat-lib/package.js | 1 - .../server/functions/getUsernameSuggestion.js | 4 +- .../client/views/app/createChannel.js | 12 +++- .../rocketchat-utils/lib/getValidRoomName.js | 4 +- 12 files changed, 92 insertions(+), 17 deletions(-) diff --git a/.meteor/packages b/.meteor/packages index 6ceee6a09ac..ddf589282d7 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -187,7 +187,6 @@ rocketchat:push raix:ui-dropped-event steffo:meteor-accounts-saml todda00:friendly-slugs -yasaricli:slugify yasinuslu:blaze-meta rocketchat:e2e diff --git a/.meteor/versions b/.meteor/versions index d833186bf75..ada8b493485 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -294,5 +294,4 @@ underscore@1.0.10 url@1.2.0 webapp@1.7.2 webapp-hashing@1.0.9 -yasaricli:slugify@0.0.7 yasinuslu:blaze-meta@0.3.3 diff --git a/package-lock.json b/package-lock.json index 1b9385bcbb0..a97aca62ca1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3702,6 +3702,11 @@ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, + "bulk-replace": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/bulk-replace/-/bulk-replace-0.0.1.tgz", + "integrity": "sha1-8JVoKolqvUs9ngjeQJzCIuIT+d0=" + }, "bunyan": { "version": "1.8.12", "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", @@ -9104,6 +9109,14 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "hepburn": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/hepburn/-/hepburn-1.1.1.tgz", + "integrity": "sha512-Ok3ZmMJN3ek4WFAL4f5t8k+BmrDRlS5qGjI4um+3cHH0SrYVzJgUTYwIfGvU8s/eWqOEY+gsINwjJSoaBG3A9g==", + "requires": { + "bulk-replace": "0.0.1" + } + }, "highlight.js": { "version": "9.13.1", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz", @@ -10406,6 +10419,11 @@ } } }, + "keypress": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", + "integrity": "sha1-SjGI1CkbZrT2XtuZ+AaqmuKTWSo=" + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -10678,6 +10696,16 @@ "immediate": "~3.0.5" } }, + "limax": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/limax/-/limax-1.7.0.tgz", + "integrity": "sha512-ibcGylOXT5vry2JKfKwLWx2tZudRYWm4SzG9AE/cc5zqwW+3nQy/uPLUvfAUChRdmqxVrK6SNepmO7ZY8RoKfA==", + "requires": { + "hepburn": "^1.1.0", + "pinyin": "^2.8.3", + "speakingurl": "^14.0.1" + } + }, "linkify-it": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz", @@ -12179,6 +12207,23 @@ "semver": "^5.3.0" } }, + "nodejieba": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/nodejieba/-/nodejieba-2.3.0.tgz", + "integrity": "sha512-ZzLsVuNDlrmcBQa/b8G/yegdXje2iFmktYmPksk6qLha1brKEANYqg4XPiBspF1D0y7Npho91KTmvKFcDr0UdA==", + "optional": true, + "requires": { + "nan": "~2.10.0" + }, + "dependencies": { + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "optional": true + } + } + }, "nodemailer": { "version": "4.6.8", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.6.8.tgz", @@ -12938,6 +12983,26 @@ "pinkie": "^2.0.0" } }, + "pinyin": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/pinyin/-/pinyin-2.8.3.tgz", + "integrity": "sha1-MBzLQ1jM/oAlI8S9ZAphK+5NfEs=", + "requires": { + "commander": "~1.1.1", + "nodejieba": "^2.2.1", + "object-assign": "^4.0.1" + }, + "dependencies": { + "commander": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-1.1.1.tgz", + "integrity": "sha1-UNFlGGiuYOzP8KLZ80WVN2vGsEE=", + "requires": { + "keypress": "0.1.x" + } + } + } + }, "pkg-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", @@ -15021,6 +15086,11 @@ "base32.js": "0.0.1" } }, + "speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==" + }, "specificity": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz", diff --git a/package.json b/package.json index 320a7980acb..94d2ad66b8a 100644 --- a/package.json +++ b/package.json @@ -178,6 +178,7 @@ "ldapjs": "^1.0.2", "less": "https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6", "less-plugin-autoprefix": "^2.0.0", + "limax": "^1.7.0", "localforage": "^1.7.3", "lodash.property": "^4.4.2", "lokijs": "^1.5.5", diff --git a/packages/rocketchat-importer-hipchat-enterprise/server/importer.js b/packages/rocketchat-importer-hipchat-enterprise/server/importer.js index d6a8f4b5454..2b561a87e26 100644 --- a/packages/rocketchat-importer-hipchat-enterprise/server/importer.js +++ b/packages/rocketchat-importer-hipchat-enterprise/server/importer.js @@ -1,3 +1,4 @@ +import limax from 'limax'; import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; import { Random } from 'meteor/random'; @@ -13,7 +14,6 @@ import { Messages, Users, Subscriptions, Rooms } from 'meteor/rocketchat:models' import { insertMessage } from 'meteor/rocketchat:lib'; import { Readable } from 'stream'; import path from 'path'; -import s from 'underscore.string'; import fs from 'fs'; import TurndownService from 'turndown'; @@ -968,7 +968,7 @@ export class HipChatEnterpriseImporter extends Base { _importChannel(channelToImport, startedByUserId) { Meteor.runAsUser(startedByUserId, () => { - const existingRoom = Rooms.findOneByName(s.slugify(channelToImport.name)); + const existingRoom = Rooms.findOneByName(limax(channelToImport.name)); // If the room exists or the name of it is 'general', then we don't need to create it again if (existingRoom || channelToImport.name.toUpperCase() === 'GENERAL') { channelToImport.rocketId = channelToImport.name.toUpperCase() === 'GENERAL' ? 'GENERAL' : existingRoom._id; diff --git a/packages/rocketchat-importer-hipchat/server/importer.js b/packages/rocketchat-importer-hipchat/server/importer.js index e22e74366b9..5f4ade2beba 100644 --- a/packages/rocketchat-importer-hipchat/server/importer.js +++ b/packages/rocketchat-importer-hipchat/server/importer.js @@ -1,3 +1,4 @@ +import limax from 'limax'; import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; import { @@ -11,7 +12,6 @@ import { RocketChatFile } from 'meteor/rocketchat:file'; import { Users, Rooms } from 'meteor/rocketchat:models'; import { sendMessage } from 'meteor/rocketchat:lib'; import _ from 'underscore'; -import s from 'underscore.string'; import moment from 'moment'; import 'moment-timezone'; @@ -48,11 +48,11 @@ export class HipChatImporter extends Base { super.updateProgress(ProgressStep.PREPARING_CHANNELS); tempRooms = JSON.parse(entry.getData().toString()).rooms; tempRooms.forEach((room) => { - room.name = s.slugify(room.name); + room.name = limax(room.name); }); } else if (roomName.indexOf('/') > -1) { const item = roomName.split('/'); - roomName = s.slugify(item[0]); + roomName = limax(item[0]); const msgGroupData = item[1].split('.')[0]; if (!tempMessages[roomName]) { tempMessages[roomName] = {}; diff --git a/packages/rocketchat-ldap/package.js b/packages/rocketchat-ldap/package.js index 91ceb561397..e52dfafd803 100644 --- a/packages/rocketchat-ldap/package.js +++ b/packages/rocketchat-ldap/package.js @@ -18,7 +18,6 @@ Package.onUse(function(api) { 'rocketchat:authorization', 'rocketchat:utils', 'rocketchat:callbacks', - 'yasaricli:slugify', 'templating', 'accounts-base', 'accounts-password', diff --git a/packages/rocketchat-ldap/server/sync.js b/packages/rocketchat-ldap/server/sync.js index 190ba994335..e952eeb5093 100644 --- a/packages/rocketchat-ldap/server/sync.js +++ b/packages/rocketchat-ldap/server/sync.js @@ -1,3 +1,4 @@ +import limax from 'limax'; import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; import { RocketChatFile } from 'meteor/rocketchat:file'; @@ -9,7 +10,6 @@ import { _setRealName, _setUsername } from 'meteor/rocketchat:lib'; import { templateVarHandler } from 'meteor/rocketchat:utils'; import { SyncedCron } from 'meteor/littledata:synced-cron'; import { FileUpload } from 'meteor/rocketchat:file-upload'; -import { slugify } from 'meteor/yasaricli:slugify'; import _ from 'underscore'; import LDAP from './ldap'; @@ -19,7 +19,7 @@ export function slug(text) { if (settings.get('UTF8_Names_Slugify') !== true) { return text; } - text = slugify(text, '.'); + text = limax(text, { replacement: '.' }); return text.replace(/[^0-9a-z-_.]/g, ''); } diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index bbe2c99d684..0bf1882e20d 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -28,7 +28,6 @@ Package.onUse(function(api) { 'mizzao:timesync', 'konecty:multiple-instances-status', 'matb33:collection-hooks', - 'yasaricli:slugify', 'service-configuration', 'rocketchat:utils', 'rocketchat:models', diff --git a/packages/rocketchat-lib/server/functions/getUsernameSuggestion.js b/packages/rocketchat-lib/server/functions/getUsernameSuggestion.js index 4674d8f074d..05501a28044 100644 --- a/packages/rocketchat-lib/server/functions/getUsernameSuggestion.js +++ b/packages/rocketchat-lib/server/functions/getUsernameSuggestion.js @@ -1,10 +1,10 @@ +import limax from 'limax'; import { Meteor } from 'meteor/meteor'; -import { slugify } from 'meteor/yasaricli:slugify'; import { Users } from 'meteor/rocketchat:models'; import { settings } from 'meteor/rocketchat:settings'; function slug(text) { - return slugify(text, '.').replace(/[^0-9a-z-_.]/g, ''); + return limax(text, { replacement: '.' }).replace(/[^0-9a-z-_.]/g, ''); } function usernameIsAvaliable(username) { diff --git a/packages/rocketchat-ui/client/views/app/createChannel.js b/packages/rocketchat-ui/client/views/app/createChannel.js index 6b84080ce5f..f979c8d5007 100644 --- a/packages/rocketchat-ui/client/views/app/createChannel.js +++ b/packages/rocketchat-ui/client/views/app/createChannel.js @@ -9,6 +9,7 @@ import { settings } from 'meteor/rocketchat:settings'; import { callbacks } from 'meteor/rocketchat:callbacks'; import { t, roomTypes } from 'meteor/rocketchat:utils'; import { hasAllPermission } from 'meteor/rocketchat:authorization'; +import toastr from 'toastr'; import _ from 'underscore'; const acEvents = { @@ -241,11 +242,18 @@ Template.createChannel.events({ Meteor.call(isPrivate ? 'createPrivateGroup' : 'createChannel', name, instance.selectedUsers.get().map((user) => user.username), readOnly, {}, extraData, function(err, result) { if (err) { if (err.error === 'error-invalid-name') { - return instance.invalid.set(true); + instance.invalid.set(true); + return; } if (err.error === 'error-duplicate-channel-name') { - return instance.inUse.set(true); + instance.inUse.set(true); + return; + } + if (err.error === 'error-invalid-room-name') { + toastr.error(t('error-invalid-room-name', { room_name: name })); + return; } + toastr.error(err.message); return; } diff --git a/packages/rocketchat-utils/lib/getValidRoomName.js b/packages/rocketchat-utils/lib/getValidRoomName.js index 92306dc0098..de891909247 100644 --- a/packages/rocketchat-utils/lib/getValidRoomName.js +++ b/packages/rocketchat-utils/lib/getValidRoomName.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; +import limax from 'limax'; import { settings } from 'meteor/rocketchat:settings'; import { Rooms } from 'meteor/rocketchat:models'; -import s from 'underscore.string'; export const getValidRoomName = (displayName, rid = '') => { let slugifiedName = displayName; @@ -15,7 +15,7 @@ export const getValidRoomName = (displayName, rid = '') => { throw new Meteor.Error('error-duplicate-channel-name', `A channel with name '${ displayName }' exists`, { function: 'RocketChat.getValidRoomName', channel_name: displayName }); } } - slugifiedName = s.slugify(displayName); + slugifiedName = limax(displayName); } let nameValidation;