Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Issues on selecting users when importing CSV #24253

Merged
merged 15 commits into from
Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 43 additions & 41 deletions app/importer/server/classes/ImportDataConverter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import _ from 'underscore';
import { ObjectId } from 'mongodb';

import { ImportData as ImportDataRaw } from '../../../models/server/raw';
import { IImportUser } from '../../../../definition/IImportUser';
Expand Down Expand Up @@ -120,6 +121,7 @@ export class ImportDataConverter {

protected addObject(type: string, data: Record<string, any>, options: Record<string, any> = {}): void {
ImportData.model.rawCollection().insert({
_id: new ObjectId().toHexString(),
data,
dataType: type,
...options,
Expand Down Expand Up @@ -513,24 +515,24 @@ export class ImportDataConverter {
convertMessages({ beforeImportFn, afterImportFn }: IConversionCallbacks = {}): void {
const rids: Array<string> = [];
const messages = Promise.await(this.getMessagesToImport());
messages.forEach(({ data: m, _id }: IImportMessageRecord) => {
messages.forEach(({ data, _id }: IImportMessageRecord) => {
try {
if (beforeImportFn && !beforeImportFn(m, 'message')) {
if (beforeImportFn && !beforeImportFn(data, 'message')) {
this.skipRecord(_id);
return;
}

if (!m.ts || isNaN(m.ts as unknown as number)) {
if (!data.ts || isNaN(data.ts as unknown as number)) {
throw new Error('importer-message-invalid-timestamp');
}

const creator = this.findImportedUser(m.u._id);
const creator = this.findImportedUser(data.u._id);
if (!creator) {
this._logger.warn(`Imported user not found: ${m.u._id}`);
this._logger.warn(`Imported user not found: ${data.u._id}`);
throw new Error('importer-message-unknown-user');
}

const rid = this.findImportedRoomId(m.rid);
const rid = this.findImportedRoomId(data.rid);
if (!rid) {
throw new Error('importer-message-unknown-room');
}
Expand All @@ -539,41 +541,41 @@ export class ImportDataConverter {
}

// Convert the mentions and channels first because these conversions can also modify the msg in the message object
const mentions = m.mentions && this.convertMessageMentions(m);
const channels = m.channels && this.convertMessageChannels(m);
const mentions = data.mentions && this.convertMessageMentions(data);
const channels = data.channels && this.convertMessageChannels(data);

const msgObj: IMessage = {
rid,
u: {
_id: creator._id,
username: creator.username,
},
msg: m.msg,
ts: m.ts,
t: m.t || undefined,
groupable: m.groupable,
tmid: m.tmid,
tlm: m.tlm,
tcount: m.tcount,
replies: m.replies && this.convertMessageReplies(m.replies),
editedAt: m.editedAt,
editedBy: m.editedBy && (this.findImportedUser(m.editedBy) || undefined),
msg: data.msg,
ts: data.ts,
t: data.t || undefined,
groupable: data.groupable,
tmid: data.tmid,
tlm: data.tlm,
tcount: data.tcount,
replies: data.replies && this.convertMessageReplies(data.replies),
editedAt: data.editedAt,
editedBy: data.editedBy && (this.findImportedUser(data.editedBy) || undefined),
mentions,
channels,
_importFile: m._importFile,
url: m.url,
attachments: m.attachments,
bot: m.bot,
emoji: m.emoji,
alias: m.alias,
_importFile: data._importFile,
url: data.url,
attachments: data.attachments,
bot: data.bot,
emoji: data.emoji,
alias: data.alias,
};

if (m._id) {
msgObj._id = m._id;
if (data._id) {
msgObj._id = data._id;
}

if (m.reactions) {
msgObj.reactions = this.convertMessageReactions(m.reactions);
if (data.reactions) {
msgObj.reactions = this.convertMessageReactions(data.reactions);
}

try {
Expand All @@ -584,7 +586,7 @@ export class ImportDataConverter {
}

if (afterImportFn) {
afterImportFn(m, 'message', true);
afterImportFn(data, 'message', true);
}
} catch (e) {
this.saveError(_id, e);
Expand Down Expand Up @@ -863,38 +865,38 @@ export class ImportDataConverter {

convertChannels(startedByUserId: string, { beforeImportFn, afterImportFn }: IConversionCallbacks = {}): void {
const channels = Promise.await(this.getChannelsToImport());
channels.forEach(({ data: c, _id }: IImportChannelRecord) => {
channels.forEach(({ data, _id }: IImportChannelRecord) => {
try {
if (beforeImportFn && !beforeImportFn(c, 'channel')) {
if (beforeImportFn && !beforeImportFn(data, 'channel')) {
this.skipRecord(_id);
return;
}

if (!c.name && c.t !== 'd') {
if (!data.name && data.t !== 'd') {
throw new Error('importer-channel-missing-name');
}

c.importIds = c.importIds.filter((item) => item);
c.users = _.uniq(c.users);
data.importIds = data.importIds.filter((item) => item);
data.users = _.uniq(data.users);

if (!c.importIds.length) {
if (!data.importIds.length) {
throw new Error('importer-channel-missing-import-id');
}

const existingRoom = this.findExistingRoom(c);
const existingRoom = this.findExistingRoom(data);

if (existingRoom) {
this.updateRoom(existingRoom, c, startedByUserId);
this.updateRoom(existingRoom, data, startedByUserId);
} else {
this.insertRoom(c, startedByUserId);
this.insertRoom(data, startedByUserId);
}

if (c.archived && c._id) {
this.archiveRoomById(c._id);
if (data.archived && data._id) {
this.archiveRoomById(data._id);
}

if (afterImportFn) {
afterImportFn(c, 'channel', !existingRoom);
afterImportFn(data, 'channel', !existingRoom);
}
} catch (e) {
this.saveError(_id, e);
Expand Down
7 changes: 5 additions & 2 deletions client/views/admin/import/PrepareImportPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,17 @@ function PrepareImportPage() {

const statusDebounced = useDebouncedValue(status, 100);

const handleMinimumImportData = () =>
!!((!usersCount && !channelsCount && !messageCount) || (!usersCount && !channelsCount && messageCount !== 0));

return (
<Page>
<Page.Header title={t('Importing_Data')}>
<ButtonGroup>
<Button ghost onClick={handleBackToImportsButtonClick}>
<Icon name='back' /> {t('Back_to_imports')}
</Button>
<Button primary disabled={isImporting} onClick={handleStartButtonClick}>
<Button primary disabled={isImporting || handleMinimumImportData()} onClick={handleStartButtonClick}>
{t('Importer_Prepare_Start_Import')}
</Button>
</ButtonGroup>
Expand All @@ -203,7 +206,7 @@ function PrepareImportPage() {
</Box>
{!isPreparing && (
<Tabs flexShrink={0}>
<Tabs.Item disabled={usersCount === 0} selected={tab === 'users'} onClick={handleTabClick('users')}>
<Tabs.Item selected={tab === 'users'} onClick={handleTabClick('users')}>
{t('Users')} <Badge>{usersCount}</Badge>
</Tabs.Item>
<Tabs.Item selected={tab === 'channels'} onClick={handleTabClick('channels')}>
Expand Down