diff --git a/src/Squidex.Domain.Apps.Entities/Assets/Edm/EdmAssetModel.cs b/src/Squidex.Domain.Apps.Entities/Assets/Edm/EdmAssetModel.cs index 33f991d94..32e2f3a53 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/Edm/EdmAssetModel.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/Edm/EdmAssetModel.cs @@ -6,6 +6,7 @@ // ========================================================================== using Microsoft.OData.Edm; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets.Edm { @@ -17,20 +18,20 @@ namespace Squidex.Domain.Apps.Entities.Assets.Edm { var entityType = new EdmEntityType("Squidex", "Asset"); - entityType.AddStructuralProperty(nameof(IAssetEntity.Id), EdmPrimitiveTypeKind.Guid); - entityType.AddStructuralProperty(nameof(IAssetEntity.AppId), EdmPrimitiveTypeKind.Guid); - entityType.AddStructuralProperty(nameof(IAssetEntity.Created), EdmPrimitiveTypeKind.DateTimeOffset); - entityType.AddStructuralProperty(nameof(IAssetEntity.CreatedBy), EdmPrimitiveTypeKind.String); - entityType.AddStructuralProperty(nameof(IAssetEntity.LastModified), EdmPrimitiveTypeKind.DateTimeOffset); - entityType.AddStructuralProperty(nameof(IAssetEntity.LastModifiedBy), EdmPrimitiveTypeKind.String); - entityType.AddStructuralProperty(nameof(IAssetEntity.Version), EdmPrimitiveTypeKind.Int64); - entityType.AddStructuralProperty(nameof(IAssetEntity.FileName), EdmPrimitiveTypeKind.String); - entityType.AddStructuralProperty(nameof(IAssetEntity.FileSize), EdmPrimitiveTypeKind.Int64); - entityType.AddStructuralProperty(nameof(IAssetEntity.FileVersion), EdmPrimitiveTypeKind.Int64); - entityType.AddStructuralProperty(nameof(IAssetEntity.IsImage), EdmPrimitiveTypeKind.Boolean); - entityType.AddStructuralProperty(nameof(IAssetEntity.MimeType), EdmPrimitiveTypeKind.String); - entityType.AddStructuralProperty(nameof(IAssetEntity.PixelHeight), EdmPrimitiveTypeKind.Int32); - entityType.AddStructuralProperty(nameof(IAssetEntity.PixelWidth), EdmPrimitiveTypeKind.Int32); + entityType.AddStructuralProperty(nameof(IAssetEntity.Id).ToCamelCase(), EdmPrimitiveTypeKind.Guid); + entityType.AddStructuralProperty(nameof(IAssetEntity.AppId).ToCamelCase(), EdmPrimitiveTypeKind.Guid); + entityType.AddStructuralProperty(nameof(IAssetEntity.Created).ToCamelCase(), EdmPrimitiveTypeKind.DateTimeOffset); + entityType.AddStructuralProperty(nameof(IAssetEntity.CreatedBy).ToCamelCase(), EdmPrimitiveTypeKind.String); + entityType.AddStructuralProperty(nameof(IAssetEntity.LastModified).ToCamelCase(), EdmPrimitiveTypeKind.DateTimeOffset); + entityType.AddStructuralProperty(nameof(IAssetEntity.LastModifiedBy).ToCamelCase(), EdmPrimitiveTypeKind.String); + entityType.AddStructuralProperty(nameof(IAssetEntity.Version).ToCamelCase(), EdmPrimitiveTypeKind.Int64); + entityType.AddStructuralProperty(nameof(IAssetEntity.FileName).ToCamelCase(), EdmPrimitiveTypeKind.String); + entityType.AddStructuralProperty(nameof(IAssetEntity.FileSize).ToCamelCase(), EdmPrimitiveTypeKind.Int64); + entityType.AddStructuralProperty(nameof(IAssetEntity.FileVersion).ToCamelCase(), EdmPrimitiveTypeKind.Int64); + entityType.AddStructuralProperty(nameof(IAssetEntity.IsImage).ToCamelCase(), EdmPrimitiveTypeKind.Boolean); + entityType.AddStructuralProperty(nameof(IAssetEntity.MimeType).ToCamelCase(), EdmPrimitiveTypeKind.String); + entityType.AddStructuralProperty(nameof(IAssetEntity.PixelHeight).ToCamelCase(), EdmPrimitiveTypeKind.Int32); + entityType.AddStructuralProperty(nameof(IAssetEntity.PixelWidth).ToCamelCase(), EdmPrimitiveTypeKind.Int32); var container = new EdmEntityContainer("Squidex", "Container"); diff --git a/src/Squidex.Infrastructure.MongoDb/MongoDb/OData/PropertyBuilder.cs b/src/Squidex.Infrastructure.MongoDb/MongoDb/OData/PropertyBuilder.cs index a9bfa8d54..ede103c64 100644 --- a/src/Squidex.Infrastructure.MongoDb/MongoDb/OData/PropertyBuilder.cs +++ b/src/Squidex.Infrastructure.MongoDb/MongoDb/OData/PropertyBuilder.cs @@ -17,7 +17,7 @@ namespace Squidex.Infrastructure.MongoDb.OData { private static readonly PropertyCalculator DefaultCalculator = parts => { - return string.Join(".", parts); + return string.Join(".", parts).ToPascalCase(); }; public static StringFieldDefinition BuildFieldDefinition(this QueryNode node, PropertyCalculator propertyCalculator) diff --git a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs index 8938907c3..1c1737086 100644 --- a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs @@ -59,21 +59,44 @@ namespace Squidex.Areas.Api.Controllers.Assets /// Get assets. /// /// The name of the app. + /// The optional asset ids. /// /// 200 => Assets returned. /// 404 => App not found. /// /// - /// Get all assets for the app. Mime types can be comma-separated, e.g. application/json,text/html. + /// Get all assets for the app. /// [MustBeAppReader] [HttpGet] [Route("apps/{app}/assets/")] [ProducesResponseType(typeof(AssetsDto), 200)] [ApiCosts(1)] - public async Task GetAssets(string app) + public async Task GetAssets(string app, [FromQuery] string ids = null) { - var assets = await assetRepository.QueryAsync(App.Id, Request.QueryString.ToString()); + var idsList = new HashSet(); + + if (!string.IsNullOrWhiteSpace(ids)) + { + foreach (var id in ids.Split(',')) + { + if (Guid.TryParse(id, out var guid)) + { + idsList.Add(guid); + } + } + } + + IResultList assets; + + if (idsList.Count > 0) + { + assets = await assetRepository.QueryAsync(App.Id, idsList); + } + else + { + assets = await assetRepository.QueryAsync(App.Id, Request.QueryString.ToString()); + } var response = new AssetsDto { diff --git a/src/Squidex/app/features/content/shared/assets-editor.component.ts b/src/Squidex/app/features/content/shared/assets-editor.component.ts index d51416e5f..bd72451f2 100644 --- a/src/Squidex/app/features/content/shared/assets-editor.component.ts +++ b/src/Squidex/app/features/content/shared/assets-editor.component.ts @@ -68,7 +68,7 @@ export class AssetsEditorComponent implements ControlValueAccessor, OnDestroy, O if (Types.isArrayOfString(value) && value.length > 0) { const assetIds: string[] = value; - this.assetsService.getAssets(this.ctx.appName, 10000, 0, undefined, undefined, value) + this.assetsService.getAssets(this.ctx.appName, 0, 0, undefined, value) .subscribe(dtos => { this.oldAssets = ImmutableArray.of(assetIds.map(id => dtos.items.find(x => x.id === id)).filter(a => !!a).map(a => a!)); }); diff --git a/src/Squidex/app/shared/services/assets.service.spec.ts b/src/Squidex/app/shared/services/assets.service.spec.ts index 00e5b575d..1fb922072 100644 --- a/src/Squidex/app/shared/services/assets.service.spec.ts +++ b/src/Squidex/app/shared/services/assets.service.spec.ts @@ -219,7 +219,7 @@ describe('AssetsService', () => { assetsService.getAssets('my-app', 17, 13, 'my-query').subscribe(); - const req = httpMock.expectOne('http://service/p/api/apps/my-app/assets?$search=my-query&$top=17&$skip=13'); + const req = httpMock.expectOne(`http://service/p/api/apps/my-app/assets?$filter=contains(fileName,'my-query')&$top=17&$skip=13`); expect(req.request.method).toEqual('GET'); expect(req.request.headers.get('If-Match')).toBeNull(); @@ -227,25 +227,12 @@ describe('AssetsService', () => { req.flush({ total: 10, items: [] }); })); - it('should append mime types to find by types', + it('should append ids query to find by ids', inject([AssetsService, HttpTestingController], (assetsService: AssetsService, httpMock: HttpTestingController) => { - assetsService.getAssets('my-app', 17, 13, undefined, ['image/png', 'image/png']).subscribe(); + assetsService.getAssets('my-app', 0, 0, undefined, ['12', '23']).subscribe(); - const req = httpMock.expectOne(`http://service/p/api/apps/my-app/assets?$filter=MimeType eq 'image/png' or MimeType eq 'image/png'&$top=17&$skip=13`); - - expect(req.request.method).toEqual('GET'); - expect(req.request.headers.get('If-Match')).toBeNull(); - - req.flush({ total: 10, items: [] }); - })); - - it('should append mime types to find by ids', - inject([AssetsService, HttpTestingController], (assetsService: AssetsService, httpMock: HttpTestingController) => { - - assetsService.getAssets('my-app', 17, 13, undefined, undefined, ['12', '23']).subscribe(); - - const req = httpMock.expectOne('http://service/p/api/apps/my-app/assets?$filter=Id eq 12 or Id eq 23&$top=17&$skip=13'); + const req = httpMock.expectOne('http://service/p/api/apps/my-app/assets?ids=12,23'); expect(req.request.method).toEqual('GET'); expect(req.request.headers.get('If-Match')).toBeNull(); diff --git a/src/Squidex/app/shared/services/assets.service.ts b/src/Squidex/app/shared/services/assets.service.ts index c272a7c29..0504281ac 100644 --- a/src/Squidex/app/shared/services/assets.service.ts +++ b/src/Squidex/app/shared/services/assets.service.ts @@ -109,30 +109,24 @@ export class AssetsService { ) { } - public getAssets(appName: string, take: number, skip: number, query?: string, mimeTypes?: string[], ids?: string[]): Observable { - const queries: string[] = []; - const filters: string[] = []; + public getAssets(appName: string, take: number, skip: number, query?: string, ids?: string[]): Observable { + let fullQuery = ''; - if (mimeTypes && mimeTypes.length > 0) { - filters.push(mimeTypes.map(mimeType => `MimeType eq '${mimeType}'`).join(' or ')); - } + if (ids) { + fullQuery = `ids=${ids.join(',')}`; + } else { + const queries: string[] = []; - if (ids && ids.length > 0) { - filters.push(ids.map(id => `Id eq ${id}`).join(' or ')); - } + if (query && query.length > 0) { + queries.push(`$filter=contains(fileName,'${encodeURIComponent(query)}')`); + } - if (filters.length > 0) { - queries.push(`$filter=${filters.join(' and ')}`); - } + queries.push(`$top=${take}`); + queries.push(`$skip=${skip}`); - if (query && query.length > 0) { - queries.push(`$search=${encodeURIComponent(query)}`); + fullQuery = queries.join('&'); } - queries.push(`$top=${take}`); - queries.push(`$skip=${skip}`); - - const fullQuery = queries.join('&'); const url = this.apiUrl.buildUrl(`api/apps/${appName}/assets?${fullQuery}`);