Browse Source

Provide URLs in GraphQL endpoint. Closes #79

pull/85/head
Sebastian Stehle 9 years ago
parent
commit
8f5f69dbb1
  1. 9
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/CachingGraphQLInvoker.cs
  2. 53
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/GraphQLModel.cs
  3. 7
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/IGraphQLContext.cs
  4. 23
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/IGraphQLUrlGenerator.cs
  5. 10
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/QueryContext.cs
  6. 18
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/AssetGraphType.cs
  7. 3
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentDataGraphType.cs
  8. 22
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentGraphType.cs
  9. 5
      src/Squidex/Config/Domain/ReadModule.cs
  10. 50
      src/Squidex/Pipeline/GraphQLUrlGenerator.cs
  11. 2
      src/Squidex/app/framework/angular/image-source.directive.ts
  12. 14
      tests/Squidex.Domain.Apps.Read.Tests/Contents/GraphQLTests.cs
  13. 33
      tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeUrlGenerator.cs

9
src/Squidex.Domain.Apps.Read/Contents/GraphQL/CachingGraphQLInvoker.cs

@ -27,6 +27,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
public sealed class CachingGraphQLInvoker : CachingProviderBase, IGraphQLInvoker, IEventConsumer public sealed class CachingGraphQLInvoker : CachingProviderBase, IGraphQLInvoker, IEventConsumer
{ {
private readonly IContentRepository contentRepository; private readonly IContentRepository contentRepository;
private readonly IGraphQLUrlGenerator urlGenerator;
private readonly IAssetRepository assetRepository; private readonly IAssetRepository assetRepository;
private readonly ISchemaRepository schemaRepository; private readonly ISchemaRepository schemaRepository;
@ -40,16 +41,18 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
get { return "^(schema-)|(apps-)"; } get { return "^(schema-)|(apps-)"; }
} }
public CachingGraphQLInvoker(IMemoryCache cache, ISchemaRepository schemaRepository, IAssetRepository assetRepository, IContentRepository contentRepository) public CachingGraphQLInvoker(IMemoryCache cache, ISchemaRepository schemaRepository, IAssetRepository assetRepository, IContentRepository contentRepository, IGraphQLUrlGenerator urlGenerator)
: base(cache) : base(cache)
{ {
Guard.NotNull(schemaRepository, nameof(schemaRepository)); Guard.NotNull(schemaRepository, nameof(schemaRepository));
Guard.NotNull(assetRepository, nameof(assetRepository)); Guard.NotNull(assetRepository, nameof(assetRepository));
Guard.NotNull(contentRepository, nameof(contentRepository)); Guard.NotNull(contentRepository, nameof(contentRepository));
Guard.NotNull(urlGenerator, nameof(urlGenerator));
this.contentRepository = contentRepository;
this.schemaRepository = schemaRepository; this.schemaRepository = schemaRepository;
this.assetRepository = assetRepository; this.assetRepository = assetRepository;
this.contentRepository = contentRepository; this.urlGenerator = urlGenerator;
} }
public Task ClearAsync() public Task ClearAsync()
@ -73,7 +76,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
Guard.NotNull(query, nameof(query)); Guard.NotNull(query, nameof(query));
var modelContext = await GetModelAsync(app); var modelContext = await GetModelAsync(app);
var queryContext = new QueryContext(app, contentRepository, assetRepository); var queryContext = new QueryContext(app, contentRepository, assetRepository, urlGenerator);
return await modelContext.ExecuteAsync(queryContext, query); return await modelContext.ExecuteAsync(queryContext, query);
} }

53
src/Squidex.Domain.Apps.Read/Contents/GraphQL/GraphQLModel.cs

@ -17,11 +17,13 @@ using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read.Apps; using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Assets;
using Squidex.Domain.Apps.Read.Contents.GraphQL.Types; using Squidex.Domain.Apps.Read.Contents.GraphQL.Types;
using Squidex.Domain.Apps.Read.Schemas; using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using GraphQLSchema = GraphQL.Types.Schema; using GraphQLSchema = GraphQL.Types.Schema;
// ReSharper disable PrivateFieldCanBeConvertedToLocalVariable
// ReSharper disable ConvertClosureToMethodGroup // ReSharper disable ConvertClosureToMethodGroup
// ReSharper disable InvertIf // ReSharper disable InvertIf
// ReSharper disable ParameterHidesMember // ReSharper disable ParameterHidesMember
@ -34,14 +36,19 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
private readonly Dictionary<Guid, ContentGraphType> schemaTypes = new Dictionary<Guid, ContentGraphType>(); private readonly Dictionary<Guid, ContentGraphType> schemaTypes = new Dictionary<Guid, ContentGraphType>();
private readonly Dictionary<Guid, ISchemaEntity> schemas; private readonly Dictionary<Guid, ISchemaEntity> schemas;
private readonly PartitionResolver partitionResolver; private readonly PartitionResolver partitionResolver;
private readonly IGraphType assetType = new AssetGraphType(); private readonly IAppEntity appEntity;
private readonly IGraphType assetType;
private readonly IGraphType assetListType;
private readonly GraphQLSchema graphQLSchema; private readonly GraphQLSchema graphQLSchema;
public GraphQLModel(IAppEntity app, IEnumerable<ISchemaEntity> schemas) public GraphQLModel(IAppEntity appEntity, IEnumerable<ISchemaEntity> schemas)
{ {
partitionResolver = app.PartitionResolver; this.appEntity = appEntity;
partitionResolver = appEntity.PartitionResolver;
IGraphType assetListType = new ListGraphType(new NonNullGraphType(assetType)); assetType = new AssetGraphType(this);
assetListType = new ListGraphType(new NonNullGraphType(assetType));
fieldInfos = new Dictionary<Type, Func<Field, (IGraphType ResolveType, IFieldResolver Resolver)>> fieldInfos = new Dictionary<Type, Func<Field, (IGraphType ResolveType, IFieldResolver Resolver)>>
{ {
@ -94,6 +101,42 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
return (new NoopGraphType(name), new FuncFieldResolver<ContentFieldData, object>(c => c.Source.GetOrDefault(c.FieldName))); return (new NoopGraphType(name), new FuncFieldResolver<ContentFieldData, object>(c => c.Source.GetOrDefault(c.FieldName)));
} }
public IFieldResolver ResolveAssetUrl()
{
var resolver = new FuncFieldResolver<IAssetEntity, object>(c =>
{
var context = (QueryContext)c.UserContext;
return context.UrlGenerator.GenerateAssetUrl(appEntity, c.Source);
});
return resolver;
}
public IFieldResolver ResolveAssetThumbnailUrl()
{
var resolver = new FuncFieldResolver<IAssetEntity, object>(c =>
{
var context = (QueryContext)c.UserContext;
return context.UrlGenerator.GenerateAssetThumbnailUrl(appEntity, c.Source);
});
return resolver;
}
public IFieldResolver ResolveContentUrl(ISchemaEntity schemaEntity)
{
var resolver = new FuncFieldResolver<IContentEntity, object>(c =>
{
var context = (QueryContext)c.UserContext;
return context.UrlGenerator.GenerateContentUrl(appEntity, schemaEntity, c.Source);
});
return resolver;
}
private static ValueTuple<IGraphType, IFieldResolver> ResolveAssets(IGraphType assetListType) private static ValueTuple<IGraphType, IFieldResolver> ResolveAssets(IGraphType assetListType)
{ {
var resolver = new FuncFieldResolver<ContentFieldData, object>(c => var resolver = new FuncFieldResolver<ContentFieldData, object>(c =>
@ -172,7 +215,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
{ {
var schemaEntity = schemas.GetOrDefault(schemaId); var schemaEntity = schemas.GetOrDefault(schemaId);
return schemaEntity != null ? schemaTypes.GetOrAdd(schemaId, k => new ContentGraphType(schemaEntity.Schema, this)) : null; return schemaEntity != null ? schemaTypes.GetOrAdd(schemaId, k => new ContentGraphType(schemaEntity, this)) : null;
} }
} }
} }

7
src/Squidex.Domain.Apps.Read/Contents/GraphQL/IGraphQLContext.cs

@ -11,6 +11,7 @@ using GraphQL.Resolvers;
using GraphQL.Types; using GraphQL.Types;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read.Schemas;
namespace Squidex.Domain.Apps.Read.Contents.GraphQL namespace Squidex.Domain.Apps.Read.Contents.GraphQL
{ {
@ -22,6 +23,12 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
IGraphType GetSchemaType(Guid schemaId); IGraphType GetSchemaType(Guid schemaId);
IFieldResolver ResolveAssetUrl();
IFieldResolver ResolveAssetThumbnailUrl();
IFieldResolver ResolveContentUrl(ISchemaEntity schemaEntity);
(IGraphType ResolveType, IFieldResolver Resolver) GetGraphType(Field field); (IGraphType ResolveType, IFieldResolver Resolver) GetGraphType(Field field);
} }
} }

23
src/Squidex.Domain.Apps.Read/Contents/GraphQL/IGraphQLUrlGenerator.cs

@ -0,0 +1,23 @@
// ==========================================================================
// IGraphQLUrlGenerator.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Assets;
using Squidex.Domain.Apps.Read.Schemas;
namespace Squidex.Domain.Apps.Read.Contents.GraphQL
{
public interface IGraphQLUrlGenerator
{
string GenerateAssetUrl(IAppEntity appEntity, IAssetEntity assetEntity);
string GenerateAssetThumbnailUrl(IAppEntity appEntity, IAssetEntity assetEntity);
string GenerateContentUrl(IAppEntity appEntity, ISchemaEntity schemaEntity, IContentEntity contentEntity);
}
}

10
src/Squidex.Domain.Apps.Read/Contents/GraphQL/QueryContext.cs

@ -28,16 +28,24 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
private readonly ConcurrentDictionary<Guid, IAssetEntity> cachedAssets = new ConcurrentDictionary<Guid, IAssetEntity>(); private readonly ConcurrentDictionary<Guid, IAssetEntity> cachedAssets = new ConcurrentDictionary<Guid, IAssetEntity>();
private readonly IContentRepository contentRepository; private readonly IContentRepository contentRepository;
private readonly IAssetRepository assetRepository; private readonly IAssetRepository assetRepository;
private readonly IGraphQLUrlGenerator urlGenerator;
private readonly IAppEntity app; private readonly IAppEntity app;
public QueryContext(IAppEntity app, IContentRepository contentRepository, IAssetRepository assetRepository) public IGraphQLUrlGenerator UrlGenerator
{
get { return urlGenerator; }
}
public QueryContext(IAppEntity app, IContentRepository contentRepository, IAssetRepository assetRepository, IGraphQLUrlGenerator urlGenerator)
{ {
Guard.NotNull(contentRepository, nameof(contentRepository)); Guard.NotNull(contentRepository, nameof(contentRepository));
Guard.NotNull(assetRepository, nameof(assetRepository)); Guard.NotNull(assetRepository, nameof(assetRepository));
Guard.NotNull(urlGenerator, nameof(urlGenerator));
Guard.NotNull(app, nameof(app)); Guard.NotNull(app, nameof(app));
this.contentRepository = contentRepository; this.contentRepository = contentRepository;
this.assetRepository = assetRepository; this.assetRepository = assetRepository;
this.urlGenerator = urlGenerator;
this.app = app; this.app = app;
} }

18
src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/AssetGraphType.cs

@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
{ {
public sealed class AssetGraphType : ObjectGraphType<IAssetEntity> public sealed class AssetGraphType : ObjectGraphType<IAssetEntity>
{ {
public AssetGraphType() public AssetGraphType(IGraphQLContext context)
{ {
Name = "AssetDto"; Name = "AssetDto";
@ -75,6 +75,22 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = "The mime type." Description = "The mime type."
}); });
AddField(new FieldType
{
Name = "url",
Resolver = context.ResolveAssetUrl(),
ResolvedType = new NonNullGraphType(new StringGraphType()),
Description = "The url to the asset."
});
AddField(new FieldType
{
Name = "thumbnailUrl",
Resolver = context.ResolveAssetThumbnailUrl(),
ResolvedType = new StringGraphType(),
Description = "The thumbnail url to the asset."
});
AddField(new FieldType AddField(new FieldType
{ {
Name = "fileName", Name = "fileName",

3
src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentDataGraphType.cs

@ -52,8 +52,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
fieldGraphType.Description = $"The structure of the {fieldName} of a {schemaName} content type."; fieldGraphType.Description = $"The structure of the {fieldName} of a {schemaName} content type.";
var fieldResolver = var fieldResolver = new FuncFieldResolver<NamedContentData, ContentFieldData>(c => c.Source.GetOrDefault(field.Name));
new FuncFieldResolver<NamedContentData, ContentFieldData>(c => c.Source.GetOrDefault(field.Name));
AddField(new FieldType AddField(new FieldType
{ {

22
src/Squidex.Domain.Apps.Read/Contents/GraphQL/Types/ContentGraphType.cs

@ -9,27 +9,27 @@
using System; using System;
using GraphQL.Resolvers; using GraphQL.Resolvers;
using GraphQL.Types; using GraphQL.Types;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Schema = Squidex.Domain.Apps.Core.Schemas.Schema;
namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
{ {
public sealed class ContentGraphType : ObjectGraphType<IContentEntity> public sealed class ContentGraphType : ObjectGraphType<IContentEntity>
{ {
private readonly Schema schema; private readonly ISchemaEntity schemaEntity;
private readonly IGraphQLContext context; private readonly IGraphQLContext context;
public ContentGraphType(Schema schema, IGraphQLContext context) public ContentGraphType(ISchemaEntity schemaEntity, IGraphQLContext context)
{ {
this.schema = schema;
this.context = context; this.context = context;
this.schemaEntity = schemaEntity;
Name = $"{schema.Name.ToPascalCase()}Dto"; Name = $"{schemaEntity.Name.ToPascalCase()}Dto";
} }
public void Initialize() public void Initialize()
{ {
var schemaName = schema.Properties.Label.WithFallback(schema.Name); var schemaName = schemaEntity.Schema.Properties.Label.WithFallback(schemaEntity.Name);
AddField(new FieldType AddField(new FieldType
{ {
@ -79,11 +79,19 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL.Types
Description = $"The user that has updated the {schemaName} content last." Description = $"The user that has updated the {schemaName} content last."
}); });
AddField(new FieldType
{
Name = "url",
Resolver = context.ResolveContentUrl(schemaEntity),
ResolvedType = new NonNullGraphType(new StringGraphType()),
Description = $"The url to the the {schemaName} content."
});
AddField(new FieldType AddField(new FieldType
{ {
Name = "data", Name = "data",
Resolver = Resolver(x => x.Data), Resolver = Resolver(x => x.Data),
ResolvedType = new NonNullGraphType(new ContentDataGraphType(schema, context)), ResolvedType = new NonNullGraphType(new ContentDataGraphType(schemaEntity.Schema, context)),
Description = $"The data of the {schemaName} content." Description = $"The data of the {schemaName} content."
}); });

5
src/Squidex/Config/Domain/ReadModule.cs

@ -23,6 +23,7 @@ using Squidex.Domain.Apps.Read.Schemas.Services;
using Squidex.Domain.Apps.Read.Schemas.Services.Implementations; using Squidex.Domain.Apps.Read.Schemas.Services.Implementations;
using Squidex.Domain.Users; using Squidex.Domain.Users;
using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.CQRS.Events;
using Squidex.Pipeline;
// ReSharper disable UnusedAutoPropertyAccessor.Local // ReSharper disable UnusedAutoPropertyAccessor.Local
@ -64,6 +65,10 @@ namespace Squidex.Config.Domain
.AsSelf() .AsSelf()
.SingleInstance(); .SingleInstance();
builder.RegisterType<GraphQLUrlGenerator>()
.As<IGraphQLUrlGenerator>()
.SingleInstance();
builder.RegisterType<AssetUserPictureStore>() builder.RegisterType<AssetUserPictureStore>()
.As<IUserPictureStore>() .As<IUserPictureStore>()
.SingleInstance(); .SingleInstance();

50
src/Squidex/Pipeline/GraphQLUrlGenerator.cs

@ -0,0 +1,50 @@
// ==========================================================================
// GraphQLUrlGenerator.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Microsoft.Extensions.Options;
using Squidex.Config;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Assets;
using Squidex.Domain.Apps.Read.Contents;
using Squidex.Domain.Apps.Read.Contents.GraphQL;
using Squidex.Domain.Apps.Read.Schemas;
// ReSharper disable ConvertIfStatementToReturnStatement
namespace Squidex.Pipeline
{
public sealed class GraphQLUrlGenerator : IGraphQLUrlGenerator
{
private readonly MyUrlsOptions urlsOptions;
public GraphQLUrlGenerator(IOptions<MyUrlsOptions> urlsOptions)
{
this.urlsOptions = urlsOptions.Value;
}
public string GenerateAssetThumbnailUrl(IAppEntity appEntity, IAssetEntity assetEntity)
{
if (!assetEntity.IsImage)
{
return null;
}
return urlsOptions.BuildUrl($"api/assets/{assetEntity.Id}?version={assetEntity.Version}&width=100&mode=Max");
}
public string GenerateAssetUrl(IAppEntity appEntity, IAssetEntity assetEntity)
{
return urlsOptions.BuildUrl($"api/assets/{assetEntity.Id}?version={assetEntity.Version}");
}
public string GenerateContentUrl(IAppEntity appEntity, ISchemaEntity schemaEntity, IContentEntity contentEntity)
{
return urlsOptions.BuildUrl($"api/content/{appEntity.Name}/{schemaEntity.Name}/{contentEntity.Id}");
}
}
}

2
src/Squidex/app/framework/angular/image-source.directive.ts

@ -92,7 +92,7 @@ export class ImageSourceDirective implements OnChanges, OnInit, AfterViewInit {
let source = `${this.imageSource}&width=${w}&height=${h}&mode=Crop`; let source = `${this.imageSource}&width=${w}&height=${h}&mode=Crop`;
if (this.query !== null) { if (this.query !== null) {
source += `q=${this.query}`; source += `&q=${this.query}`;
} }
this.renderer.setElementAttribute(this.element.nativeElement, 'src', source); this.renderer.setElementAttribute(this.element.nativeElement, 'src', source);

14
tests/Squidex.Domain.Apps.Read.Tests/Contents/GraphQLTests.cs

@ -82,7 +82,7 @@ namespace Squidex.Domain.Apps.Read.Contents
schemaRepository.Setup(x => x.QueryAllAsync(appId)).Returns(Task.FromResult<IReadOnlyList<ISchemaEntity>>(schemas)); schemaRepository.Setup(x => x.QueryAllAsync(appId)).Returns(Task.FromResult<IReadOnlyList<ISchemaEntity>>(schemas));
sut = new CachingGraphQLInvoker(cache, schemaRepository.Object, assetRepository.Object, contentRepository.Object); sut = new CachingGraphQLInvoker(cache, schemaRepository.Object, assetRepository.Object, contentRepository.Object, new FakeUrlGenerator());
} }
[Fact] [Fact]
@ -97,6 +97,8 @@ namespace Squidex.Domain.Apps.Read.Contents
createdBy createdBy
lastModified lastModified
lastModifiedBy lastModifiedBy
url
thumbnailUrl
mimeType mimeType
fileName fileName
fileSize fileSize
@ -131,6 +133,8 @@ namespace Squidex.Domain.Apps.Read.Contents
createdBy = "subject:user1", createdBy = "subject:user1",
lastModified = assetEntity.LastModified.ToDateTimeUtc(), lastModified = assetEntity.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2", lastModifiedBy = "subject:user2",
url = $"assets/{assetEntity.Id}",
thumbnailUrl = $"assets/{assetEntity.Id}?width=100",
mimeType = "image/png", mimeType = "image/png",
fileName = "MyFile.png", fileName = "MyFile.png",
fileSize = 1024, fileSize = 1024,
@ -163,6 +167,8 @@ namespace Squidex.Domain.Apps.Read.Contents
createdBy createdBy
lastModified lastModified
lastModifiedBy lastModifiedBy
url
thumbnailUrl
mimeType mimeType
fileName fileName
fileSize fileSize
@ -191,6 +197,8 @@ namespace Squidex.Domain.Apps.Read.Contents
createdBy = "subject:user1", createdBy = "subject:user1",
lastModified = assetEntity.LastModified.ToDateTimeUtc(), lastModified = assetEntity.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2", lastModifiedBy = "subject:user2",
url = $"assets/{assetEntity.Id}",
thumbnailUrl = $"assets/{assetEntity.Id}?width=100",
mimeType = "image/png", mimeType = "image/png",
fileName = "MyFile.png", fileName = "MyFile.png",
fileSize = 1024, fileSize = 1024,
@ -219,6 +227,7 @@ namespace Squidex.Domain.Apps.Read.Contents
createdBy createdBy
lastModified lastModified
lastModifiedBy lastModifiedBy
url
data { data {
myString { myString {
iv iv
@ -266,6 +275,7 @@ namespace Squidex.Domain.Apps.Read.Contents
createdBy = "subject:user1", createdBy = "subject:user1",
lastModified = contentEntity.LastModified.ToDateTimeUtc(), lastModified = contentEntity.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2", lastModifiedBy = "subject:user2",
url = $"contents/my-schema/{contentEntity.Id}",
data = new data = new
{ {
myString = new myString = new
@ -325,6 +335,7 @@ namespace Squidex.Domain.Apps.Read.Contents
createdBy createdBy
lastModified lastModified
lastModifiedBy lastModifiedBy
url
data {{ data {{
myString {{ myString {{
iv iv
@ -366,6 +377,7 @@ namespace Squidex.Domain.Apps.Read.Contents
createdBy = "subject:user1", createdBy = "subject:user1",
lastModified = contentEntity.LastModified.ToDateTimeUtc(), lastModified = contentEntity.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2", lastModifiedBy = "subject:user2",
url = $"contents/my-schema/{contentEntity.Id}",
data = new data = new
{ {
myString = new myString = new

33
tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeUrlGenerator.cs

@ -0,0 +1,33 @@
// ==========================================================================
// FakeUrlGenerator.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Assets;
using Squidex.Domain.Apps.Read.Contents.GraphQL;
using Squidex.Domain.Apps.Read.Schemas;
namespace Squidex.Domain.Apps.Read.Contents.TestData
{
public sealed class FakeUrlGenerator : IGraphQLUrlGenerator
{
public string GenerateAssetUrl(IAppEntity appEntity, IAssetEntity assetEntity)
{
return $"assets/{assetEntity.Id}";
}
public string GenerateAssetThumbnailUrl(IAppEntity appEntity, IAssetEntity assetEntity)
{
return $"assets/{assetEntity.Id}?width=100";
}
public string GenerateContentUrl(IAppEntity appEntity, ISchemaEntity schemaEntity, IContentEntity contentEntity)
{
return $"contents/{schemaEntity.Name}/{contentEntity.Id}";
}
}
}
Loading…
Cancel
Save