Files command - fixes (#18016)
- Fixed "property entity not found" error when updating/creating a new field and querying the same object repository just after - Downgraded log type for unnecessary migration
This commit is contained in:
+1
-1
@@ -444,7 +444,7 @@ export class MigrateActivityRichTextAttachmentFileIdsCommand extends ActiveOrSus
|
||||
|
||||
return fileId;
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
this.logger.warn(
|
||||
`Failed to create attachment from URL ${url}: ${error.message}`,
|
||||
);
|
||||
|
||||
|
||||
+97
-90
@@ -25,6 +25,7 @@ import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata
|
||||
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity';
|
||||
|
||||
@@ -195,102 +196,108 @@ export class MigrateAttachmentFilesCommand extends ActiveOrSuspendedWorkspacesMi
|
||||
return;
|
||||
}
|
||||
|
||||
const attachmentRepository =
|
||||
await this.twentyORMGlobalManager.getRepository<AttachmentWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'attachment',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
const systemAuthContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
await this.twentyORMGlobalManager.executeInWorkspaceContext(async () => {
|
||||
const attachmentRepository =
|
||||
await this.twentyORMGlobalManager.getRepository<AttachmentWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'attachment',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const attachments = await attachmentRepository.find({
|
||||
where: {
|
||||
fullPath: Not(IsNull()),
|
||||
file: Or(IsNull(), Equal([])),
|
||||
},
|
||||
select: ['id', 'name', 'fullPath'],
|
||||
});
|
||||
|
||||
if (attachments.length === 0) {
|
||||
this.logger.log(
|
||||
`No attachments to migrate for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Found ${attachments.length} attachment(s) to migrate in workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const attachments = await attachmentRepository.find({
|
||||
where: {
|
||||
fullPath: Not(IsNull()),
|
||||
file: Or(IsNull(), Equal([])),
|
||||
},
|
||||
select: ['id', 'name', 'fullPath'],
|
||||
});
|
||||
const fileRepository = this.coreDataSource.getRepository(FileEntity);
|
||||
|
||||
if (attachments.length === 0) {
|
||||
this.logger.log(`No attachments to migrate for workspace ${workspaceId}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Found ${attachments.length} attachment(s) to migrate in workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const fileRepository = this.coreDataSource.getRepository(FileEntity);
|
||||
|
||||
for (const attachment of attachments) {
|
||||
if (!isNonEmptyString(attachment.fullPath)) {
|
||||
this.logger.warn(
|
||||
`Skipping attachment ${attachment.id} - invalid fullPath`,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const { type: fileExtension, filename } =
|
||||
extractFolderPathFilenameAndTypeOrThrow(attachment.fullPath);
|
||||
|
||||
const fileId = v4();
|
||||
const newFilename = `${fileId}${isNonEmptyString(fileExtension) ? `.${fileExtension}` : ''}`;
|
||||
const newResourcePath = `${FileFolder.FilesField}/${attachmentFileflatFieldMetadata.universalIdentifier}/${newFilename}`;
|
||||
|
||||
if (!isDryRun) {
|
||||
await this.fileStorageService.copyLegacy({
|
||||
from: {
|
||||
folderPath: `workspace-${workspaceId}`,
|
||||
filename: attachment.fullPath,
|
||||
},
|
||||
to: {
|
||||
folderPath: `${workspaceId}/${twentyStandardFlatApplication.universalIdentifier}`,
|
||||
filename: newResourcePath,
|
||||
},
|
||||
});
|
||||
|
||||
const fileEntity = fileRepository.create({
|
||||
id: fileId,
|
||||
path: newResourcePath,
|
||||
workspaceId,
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
size: -1,
|
||||
settings: {
|
||||
isTemporaryFile: true,
|
||||
toDelete: false,
|
||||
},
|
||||
});
|
||||
|
||||
await fileRepository.save(fileEntity);
|
||||
|
||||
await attachmentRepository.update(
|
||||
{ id: attachment.id },
|
||||
{
|
||||
file: [
|
||||
{
|
||||
fileId: fileEntity.id,
|
||||
label: attachment.name || filename,
|
||||
},
|
||||
],
|
||||
},
|
||||
for (const attachment of attachments) {
|
||||
if (!isNonEmptyString(attachment.fullPath)) {
|
||||
this.logger.warn(
|
||||
`Skipping attachment ${attachment.id} - invalid fullPath`,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Migrated attachment ${attachment.id} (${attachment.name})`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to migrate attachment ${attachment.id} in workspace ${workspaceId}: ${error.message}`,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
try {
|
||||
const { type: fileExtension, filename } =
|
||||
extractFolderPathFilenameAndTypeOrThrow(attachment.fullPath);
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Completed attachment files migration for workspace ${workspaceId}`,
|
||||
);
|
||||
const fileId = v4();
|
||||
const newFilename = `${fileId}${isNonEmptyString(fileExtension) ? `.${fileExtension}` : ''}`;
|
||||
const newResourcePath = `${FileFolder.FilesField}/${attachmentFileflatFieldMetadata.universalIdentifier}/${newFilename}`;
|
||||
|
||||
if (!isDryRun) {
|
||||
await this.fileStorageService.copyLegacy({
|
||||
from: {
|
||||
folderPath: `workspace-${workspaceId}`,
|
||||
filename: attachment.fullPath,
|
||||
},
|
||||
to: {
|
||||
folderPath: `${workspaceId}/${twentyStandardFlatApplication.universalIdentifier}`,
|
||||
filename: newResourcePath,
|
||||
},
|
||||
});
|
||||
|
||||
const fileEntity = fileRepository.create({
|
||||
id: fileId,
|
||||
path: newResourcePath,
|
||||
workspaceId,
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
size: -1,
|
||||
settings: {
|
||||
isTemporaryFile: true,
|
||||
toDelete: false,
|
||||
},
|
||||
});
|
||||
|
||||
await fileRepository.save(fileEntity);
|
||||
|
||||
await attachmentRepository.update(
|
||||
{ id: attachment.id },
|
||||
{
|
||||
file: [
|
||||
{
|
||||
fileId: fileEntity.id,
|
||||
label: attachment.name || filename,
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Migrated attachment ${attachment.id} (${attachment.name})`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to migrate attachment ${attachment.id} in workspace ${workspaceId}: ${error.message}`,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Completed attachment files migration for workspace ${workspaceId}`,
|
||||
);
|
||||
}, systemAuthContext);
|
||||
}
|
||||
}
|
||||
|
||||
+89
-85
@@ -26,6 +26,7 @@ import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata
|
||||
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
|
||||
@@ -205,97 +206,100 @@ export class MigratePersonAvatarFilesCommand extends ActiveOrSuspendedWorkspaces
|
||||
return;
|
||||
}
|
||||
|
||||
const personRepository =
|
||||
await this.twentyORMGlobalManager.getRepository<PersonWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'person',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
const systemAuthContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
const personsWithAvatars = await personRepository.find({
|
||||
where: {
|
||||
avatarUrl: ILike(`%${FileFolder.PersonPicture}%`),
|
||||
avatarFile: Or(IsNull(), Equal([])),
|
||||
},
|
||||
select: ['id', 'avatarUrl'],
|
||||
});
|
||||
|
||||
if (personsWithAvatars.length === 0) {
|
||||
this.logger.log(
|
||||
`No persons with avatarUrl found in workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Found ${personsWithAvatars.length} person(s) with avatarUrl containing 'people' folder in workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const fileRepository = this.coreDataSource.getRepository(FileEntity);
|
||||
|
||||
for (const person of personsWithAvatars) {
|
||||
assertIsDefinedOrThrow(person.avatarUrl);
|
||||
|
||||
try {
|
||||
const { type: fileExtension } = extractFolderPathFilenameAndTypeOrThrow(
|
||||
person.avatarUrl,
|
||||
await this.twentyORMGlobalManager.executeInWorkspaceContext(async () => {
|
||||
const personRepository =
|
||||
await this.twentyORMGlobalManager.getRepository<PersonWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'person',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const fileId = v4();
|
||||
const newFileName = `${fileId}${isNonEmptyString(fileExtension) ? `.${fileExtension}` : ''}`;
|
||||
const newResourcePath = `${FileFolder.FilesField}/${avatarFileFieldMetadata.universalIdentifier}/${newFileName}`;
|
||||
const personsWithAvatars = await personRepository.find({
|
||||
where: {
|
||||
avatarUrl: ILike(`%${FileFolder.PersonPicture}%`),
|
||||
avatarFile: Or(IsNull(), Equal([])),
|
||||
},
|
||||
select: ['id', 'avatarUrl'],
|
||||
});
|
||||
|
||||
if (!isDryRun) {
|
||||
await this.fileStorageService.copyLegacy({
|
||||
from: {
|
||||
folderPath: `workspace-${workspaceId}`,
|
||||
filename: person.avatarUrl,
|
||||
},
|
||||
to: {
|
||||
folderPath: `${workspaceId}/${twentyStandardFlatApplication.universalIdentifier}`,
|
||||
filename: newResourcePath,
|
||||
},
|
||||
});
|
||||
|
||||
const fileEntity = fileRepository.create({
|
||||
id: fileId,
|
||||
path: newResourcePath,
|
||||
workspaceId,
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
size: -1,
|
||||
settings: {
|
||||
isTemporaryFile: true,
|
||||
toDelete: false,
|
||||
},
|
||||
});
|
||||
|
||||
await fileRepository.save(fileEntity);
|
||||
|
||||
await personRepository.update(
|
||||
{ id: person.id },
|
||||
{
|
||||
avatarFile: [
|
||||
{
|
||||
fileId: fileEntity.id,
|
||||
label: newFileName,
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(`Migrated avatar for person ${person.id}`);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to migrate avatar for person ${person.id} in workspace ${workspaceId}: ${error.message}`,
|
||||
if (personsWithAvatars.length === 0) {
|
||||
this.logger.log(
|
||||
`No persons with avatarUrl found in workspace ${workspaceId}`,
|
||||
);
|
||||
throw error;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Completed person avatar files migration for workspace ${workspaceId}`,
|
||||
);
|
||||
this.logger.log(
|
||||
`Found ${personsWithAvatars.length} person(s) with avatarUrl containing 'people' folder in workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const fileRepository = this.coreDataSource.getRepository(FileEntity);
|
||||
|
||||
for (const person of personsWithAvatars) {
|
||||
assertIsDefinedOrThrow(person.avatarUrl);
|
||||
|
||||
try {
|
||||
const { type: fileExtension } =
|
||||
extractFolderPathFilenameAndTypeOrThrow(person.avatarUrl);
|
||||
|
||||
const fileId = v4();
|
||||
const newFileName = `${fileId}${isNonEmptyString(fileExtension) ? `.${fileExtension}` : ''}`;
|
||||
const newResourcePath = `${FileFolder.FilesField}/${avatarFileFieldMetadata.universalIdentifier}/${newFileName}`;
|
||||
|
||||
if (!isDryRun) {
|
||||
await this.fileStorageService.copyLegacy({
|
||||
from: {
|
||||
folderPath: `workspace-${workspaceId}`,
|
||||
filename: person.avatarUrl,
|
||||
},
|
||||
to: {
|
||||
folderPath: `${workspaceId}/${twentyStandardFlatApplication.universalIdentifier}`,
|
||||
filename: newResourcePath,
|
||||
},
|
||||
});
|
||||
|
||||
const fileEntity = fileRepository.create({
|
||||
id: fileId,
|
||||
path: newResourcePath,
|
||||
workspaceId,
|
||||
applicationId: twentyStandardFlatApplication.id,
|
||||
size: -1,
|
||||
settings: {
|
||||
isTemporaryFile: true,
|
||||
toDelete: false,
|
||||
},
|
||||
});
|
||||
|
||||
await fileRepository.save(fileEntity);
|
||||
|
||||
await personRepository.update(
|
||||
{ id: person.id },
|
||||
{
|
||||
avatarFile: [
|
||||
{
|
||||
fileId: fileEntity.id,
|
||||
label: newFileName,
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(`Migrated avatar for person ${person.id}`);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to migrate avatar for person ${person.id} in workspace ${workspaceId}: ${error.message}`,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Completed person avatar files migration for workspace ${workspaceId}`,
|
||||
);
|
||||
}, systemAuthContext);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -71,8 +71,8 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta
|
||||
BackfillMessageChannelThrottleRetryAfterCommand,
|
||||
BackfillStandardViewsAndFieldMetadataCommand,
|
||||
MigrateWorkspacePicturesCommand,
|
||||
BackfillFileSizeAndMimeTypeCommand,
|
||||
MigrateWorkflowSendEmailAttachmentsCommand,
|
||||
BackfillFileSizeAndMimeTypeCommand,
|
||||
],
|
||||
})
|
||||
export class V1_18_UpgradeVersionCommandModule {}
|
||||
|
||||
Reference in New Issue
Block a user