File - Migrate avatarUrl > avatarFile on person (data migration + logic) + Attachment data migration (#17752)

- Migration command
    - Check IS_FILES_FIELD_MIGRATED:false
    - Check or create avatarFile field
    - Fetch all people with avatarUrl
           - Move (Copy/move) file in storage
           - Create core.file record
           - Update person record
           
    - bonus : attachment migration  : fullPath > file (same logic)
   
- BE logic
    - Add avatarFile field on person

- FE logic 
   - Adapt logic to upload on/display avatarFile data

The whole imageIdentifier logic will be done later
This commit is contained in:
Etienne
2026-02-11 16:07:05 +01:00
committed by GitHub
parent 5be64bf4be
commit d0c1841f0f
46 changed files with 1704 additions and 737 deletions
@@ -12,11 +12,14 @@ export const buildIdentifierGqlFields = (
| 'imageIdentifierFieldMetadataId'
| 'nameSingular'
>,
isFilesFieldMigrated?: boolean,
): RecordGqlFields => {
const labelIdentifierField =
getLabelIdentifierFieldMetadataItem(objectMetadata);
const imageIdentifierField =
getImageIdentifierFieldMetadataItem(objectMetadata);
const imageIdentifierField = getImageIdentifierFieldMetadataItem(
objectMetadata,
isFilesFieldMigrated,
);
return {
id: true,
@@ -27,6 +27,7 @@ export type GenerateDepthRecordGqlFieldsFromFields = {
>[];
depth: 0 | 1;
shouldOnlyLoadRelationIdentifiers?: boolean;
isFilesFieldMigrated?: boolean;
};
export const generateDepthRecordGqlFieldsFromFields = ({
@@ -34,6 +35,7 @@ export const generateDepthRecordGqlFieldsFromFields = ({
fields,
depth,
shouldOnlyLoadRelationIdentifiers = true,
isFilesFieldMigrated,
}: GenerateDepthRecordGqlFieldsFromFields) => {
const generatedRecordGqlFields: RecordGqlFields = fields.reduce(
(recordGqlFields, fieldMetadata) => {
@@ -83,6 +85,7 @@ export const generateDepthRecordGqlFieldsFromFields = ({
const junctionGqlFields = generateJunctionRelationGqlFields({
fieldMetadataItem: fieldMetadata,
objectMetadataItems,
isFilesFieldMigrated,
});
if (isDefined(junctionGqlFields) && depth === 1) {
@@ -97,7 +100,10 @@ export const generateDepthRecordGqlFieldsFromFields = ({
getLabelIdentifierFieldMetadataItem(targetObjectMetadataItem);
const imageIdentifierFieldMetadataItem =
getImageIdentifierFieldMetadataItem(targetObjectMetadataItem);
getImageIdentifierFieldMetadataItem(
targetObjectMetadataItem,
isFilesFieldMigrated,
);
const relationIdentifierSubGqlFields = {
id: true,
@@ -16,11 +16,13 @@ type JunctionFieldMetadataItem = Pick<
type GenerateJunctionRelationGqlFieldsArgs = {
fieldMetadataItem: JunctionFieldMetadataItem;
objectMetadataItems: JunctionObjectMetadataItem[];
isFilesFieldMigrated?: boolean;
};
const buildRegularTargetFieldGqlFields = (
targetField: JunctionFieldMetadataItem,
objectMetadataItems: JunctionObjectMetadataItem[],
isFilesFieldMigrated?: boolean,
): RecordGqlFields => {
const targetObjectMetadata = objectMetadataItems.find(
(item) => item.id === targetField.relation?.targetObjectMetadata.id,
@@ -31,13 +33,17 @@ const buildRegularTargetFieldGqlFields = (
}
return {
[targetField.name]: buildIdentifierGqlFields(targetObjectMetadata),
[targetField.name]: buildIdentifierGqlFields(
targetObjectMetadata,
isFilesFieldMigrated,
),
};
};
const buildMorphTargetFieldGqlFields = (
targetField: JunctionFieldMetadataItem,
objectMetadataItems: JunctionObjectMetadataItem[],
isFilesFieldMigrated?: boolean,
): RecordGqlFields => {
const morphRelations = targetField.morphRelations;
@@ -63,7 +69,10 @@ const buildMorphTargetFieldGqlFields = (
targetObjectMetadataNamePlural: targetObjectMetadata.namePlural,
});
result[computedFieldName] = buildIdentifierGqlFields(targetObjectMetadata);
result[computedFieldName] = buildIdentifierGqlFields(
targetObjectMetadata,
isFilesFieldMigrated,
);
}
return result;
@@ -72,17 +81,27 @@ const buildMorphTargetFieldGqlFields = (
const buildTargetFieldGqlFields = (
targetField: JunctionFieldMetadataItem,
objectMetadataItems: JunctionObjectMetadataItem[],
isFilesFieldMigrated?: boolean,
): RecordGqlFields => {
if (targetField.type === FieldMetadataType.MORPH_RELATION) {
return buildMorphTargetFieldGqlFields(targetField, objectMetadataItems);
return buildMorphTargetFieldGqlFields(
targetField,
objectMetadataItems,
isFilesFieldMigrated,
);
}
return buildRegularTargetFieldGqlFields(targetField, objectMetadataItems);
return buildRegularTargetFieldGqlFields(
targetField,
objectMetadataItems,
isFilesFieldMigrated,
);
};
// Generates GraphQL fields for a junction relation, including the nested target objects
export const generateJunctionRelationGqlFields = ({
fieldMetadataItem,
objectMetadataItems,
isFilesFieldMigrated,
}: GenerateJunctionRelationGqlFieldsArgs): RecordGqlFields | null => {
const junctionConfig = getJunctionConfig({
settings: fieldMetadataItem.settings,
@@ -100,13 +119,17 @@ export const generateJunctionRelationGqlFields = ({
const junctionTargetFields = targetFields.reduce<RecordGqlFields>(
(acc, targetField) => ({
...acc,
...buildTargetFieldGqlFields(targetField, objectMetadataItems),
...buildTargetFieldGqlFields(
targetField,
objectMetadataItems,
isFilesFieldMigrated,
),
}),
{},
);
return {
...buildIdentifierGqlFields(junctionObjectMetadata),
...buildIdentifierGqlFields(junctionObjectMetadata, isFilesFieldMigrated),
...junctionTargetFields,
};
};