#11370 & #11402 ### Changes made: 1. Updated search.service.ts to properly handle workspace member avatar and Person Avatar URLs with authentication tokens 2. Integrated FileService for token generation 3. Added FileModule to SearchModule for dependency injection ### Implementation details: - Used getImageUrlWithToken to append authentication tokens to avatar URLs specifically for workspace members --------- Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
This commit is contained in:
@ -27,7 +27,7 @@ export class FileService {
|
||||
});
|
||||
}
|
||||
|
||||
async encodeFileToken(payloadToEncode: Record<string, any>) {
|
||||
encodeFileToken(payloadToEncode: Record<string, any>) {
|
||||
const fileTokenExpiresIn = this.twentyConfigService.get(
|
||||
'FILE_TOKEN_EXPIRES_IN',
|
||||
);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { mockObjectMetadataItemsWithFieldMaps } from 'src/engine/core-modules/search/__mocks__/mockObjectMetadataItemsWithFieldMaps';
|
||||
import { SearchService } from 'src/engine/core-modules/search/services/search.service';
|
||||
|
||||
@ -8,7 +9,7 @@ describe('SearchService', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [SearchService],
|
||||
providers: [SearchService, { provide: FileService, useValue: {} }],
|
||||
}).compile();
|
||||
|
||||
service = module.get<SearchService>(SearchService);
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { FileModule } from 'src/engine/core-modules/file/file.module';
|
||||
import { SearchResolver } from 'src/engine/core-modules/search/search.resolver';
|
||||
import { SearchService } from 'src/engine/core-modules/search/services/search.service';
|
||||
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceCacheStorageModule, FeatureFlagModule],
|
||||
imports: [WorkspaceCacheStorageModule, FeatureFlagModule, FileModule],
|
||||
providers: [SearchResolver, SearchService],
|
||||
})
|
||||
export class SearchModule {}
|
||||
|
||||
@ -118,6 +118,7 @@ export class SearchResolver {
|
||||
return this.searchService.computeSearchObjectResults(
|
||||
allRecordsWithObjectMetadataItems,
|
||||
limit,
|
||||
workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { Brackets, ObjectLiteral } from 'typeorm';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { getLogoUrlFromDomainName } from 'twenty-shared/utils';
|
||||
import { Brackets, ObjectLiteral } from 'typeorm';
|
||||
|
||||
import { ObjectRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||
import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||
|
||||
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { RESULTS_LIMIT_BY_OBJECT_WITHOUT_SEARCH_TERMS } from 'src/engine/core-modules/search/constants/results-limit-by-object-without-search-terms';
|
||||
import { STANDARD_OBJECTS_BY_PRIORITY_RANK } from 'src/engine/core-modules/search/constants/standard-objects-by-priority-rank';
|
||||
import { ObjectRecordFilterInput } from 'src/engine/core-modules/search/dtos/object-record-filter-input';
|
||||
@ -24,6 +25,8 @@ import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.
|
||||
|
||||
@Injectable()
|
||||
export class SearchService {
|
||||
constructor(private readonly fileService: FileService) {}
|
||||
|
||||
filterObjectMetadataItems({
|
||||
objectMetadataItemWithFieldMaps,
|
||||
includedObjectNameSingulars,
|
||||
@ -194,9 +197,18 @@ export class SearchService {
|
||||
].name;
|
||||
}
|
||||
|
||||
private getImageUrlWithToken(avatarUrl: string, workspaceId: string): string {
|
||||
const avatarUrlToken = this.fileService.encodeFileToken({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return `${avatarUrl}?token=${avatarUrlToken}`;
|
||||
}
|
||||
|
||||
getImageIdentifierValue(
|
||||
record: ObjectRecord,
|
||||
objectMetadataItem: ObjectMetadataItemWithFieldMaps,
|
||||
workspaceId: string,
|
||||
): string {
|
||||
const imageIdentifierField =
|
||||
this.getImageIdentifierColumn(objectMetadataItem);
|
||||
@ -205,12 +217,15 @@ export class SearchService {
|
||||
return getLogoUrlFromDomainName(record.domainNamePrimaryLinkUrl) || '';
|
||||
}
|
||||
|
||||
return imageIdentifierField ? record[imageIdentifierField] : '';
|
||||
return imageIdentifierField
|
||||
? this.getImageUrlWithToken(record[imageIdentifierField], workspaceId)
|
||||
: '';
|
||||
}
|
||||
|
||||
computeSearchObjectResults(
|
||||
recordsWithObjectMetadataItems: RecordsWithObjectMetadataItem[],
|
||||
limit: number,
|
||||
workspaceId: string,
|
||||
) {
|
||||
const searchRecords = recordsWithObjectMetadataItems.flatMap(
|
||||
({ objectMetadataItem, records }) => {
|
||||
@ -219,7 +234,11 @@ export class SearchService {
|
||||
recordId: record.id,
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
label: this.getLabelIdentifierValue(record, objectMetadataItem),
|
||||
imageUrl: this.getImageIdentifierValue(record, objectMetadataItem),
|
||||
imageUrl: this.getImageIdentifierValue(
|
||||
record,
|
||||
objectMetadataItem,
|
||||
workspaceId,
|
||||
),
|
||||
tsRankCD: record.tsRankCD,
|
||||
tsRank: record.tsRank,
|
||||
};
|
||||
|
||||
@ -80,6 +80,7 @@ export const SEARCH_FIELDS_FOR_WORKSPACE_MEMBER: FieldTypeAndNameMetadata[] = [
|
||||
description: msg`A workspace member`,
|
||||
icon: STANDARD_OBJECT_ICONS.workspaceMember,
|
||||
labelIdentifierStandardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.name,
|
||||
imageIdentifierStandardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.avatarUrl,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNotAuditLogged()
|
||||
|
||||
Reference in New Issue
Block a user