Browse Source

Merge branch 'master' of github.com:Squidex/squidex

pull/674/head
Sebastian 5 years ago
parent
commit
23d574b4f5
  1. 49
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/SchemaInfos.cs
  2. 32
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs
  3. 12
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs
  4. 31
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs
  5. 60
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetDto.cs
  6. 47
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/UpsertAssetDto.cs
  7. 4
      backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs
  8. 2
      backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs
  9. 4
      backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs
  10. 10
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs
  11. 10
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs

49
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/SchemaInfos.cs

@ -148,39 +148,38 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents
public string this[IField field]
{
get
{
return this[field.Name.ToCamelCase()];
}
get => GetName(field.Name.ToCamelCase(), false);
}
public string this[string name]
{
get
{
Guard.NotNullOrEmpty(name, nameof(name));
if (!char.IsLetter(name[0]))
{
name = "gql_" + name;
}
else if (name.Equals("Content", StringComparison.OrdinalIgnoreCase))
{
name = $"{name}Entity";
}
get => GetName(name, true);
}
// Avoid duplicate names.
if (!takenNames.TryGetValue(name, out var offset))
{
takenNames[name] = 0;
return name;
}
private string GetName(string name, bool isEntity)
{
Guard.NotNullOrEmpty(name, nameof(name));
takenNames[name] = ++offset;
if (!char.IsLetter(name[0]))
{
name = "gql_" + name;
}
else if (name.Equals("Content", StringComparison.OrdinalIgnoreCase) && isEntity)
{
name = $"{name}Entity";
}
// Add + 1 to all offset for backwars compatibility.
return $"{name}{offset + 1}";
// Avoid duplicate names.
if (!takenNames.TryGetValue(name, out var offset))
{
takenNames[name] = 0;
return name;
}
takenNames[name] = ++offset;
// Add + 1 to all offset for backwars compatibility.
return $"{name}{offset + 1}";
}
}
}

32
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs

@ -61,7 +61,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// <param name="app">The name of the app.</param>
/// <param name="idOrSlug">The id or slug of the asset.</param>
/// <param name="more">Optional suffix that can be used to seo-optimize the link to the image Has not effect.</param>
/// <param name="queries">The query string parameters.</param>
/// <param name="request">The request parameters.</param>
/// <returns>
/// 200 => Asset found and content or (resized) image returned.
/// 404 => Asset or app not found.
@ -72,7 +72,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[ApiPermission]
[ApiCosts(0.5)]
[AllowAnonymous]
public async Task<IActionResult> GetAssetContentBySlug(string app, string idOrSlug, [FromQuery] AssetContentQueryDto queries, string? more = null)
public async Task<IActionResult> GetAssetContentBySlug(string app, string idOrSlug, AssetContentQueryDto request, string? more = null)
{
var requestContext = Context.Clone(b => b.WithoutAssetEnrichment());
@ -83,14 +83,14 @@ namespace Squidex.Areas.Api.Controllers.Assets
asset = await assetQuery.FindBySlugAsync(requestContext, idOrSlug);
}
return await DeliverAssetAsync(requestContext, asset, queries);
return await DeliverAssetAsync(requestContext, asset, request);
}
/// <summary>
/// Get the asset content.
/// </summary>
/// <param name="id">The id of the asset.</param>
/// <param name="queries">The query string parameters.</param>
/// <param name="request">The request parameters.</param>
/// <returns>
/// 200 => Asset found and content or (resized) image returned.
/// 404 => Asset or app not found.
@ -102,18 +102,18 @@ namespace Squidex.Areas.Api.Controllers.Assets
[ApiCosts(0.5)]
[AllowAnonymous]
[Obsolete("Use overload with app name")]
public async Task<IActionResult> GetAssetContent(DomainId id, [FromQuery] AssetContentQueryDto queries)
public async Task<IActionResult> GetAssetContent(DomainId id, AssetContentQueryDto request)
{
var requestContext = Context.Clone(b => b.WithoutAssetEnrichment());
var asset = await assetQuery.FindGlobalAsync(requestContext, id);
return await DeliverAssetAsync(requestContext, asset, queries);
return await DeliverAssetAsync(requestContext, asset, request);
}
private async Task<IActionResult> DeliverAssetAsync(Context context, IAssetEntity? asset, AssetContentQueryDto queries)
private async Task<IActionResult> DeliverAssetAsync(Context context, IAssetEntity? asset, AssetContentQueryDto request)
{
queries ??= new AssetContentQueryDto();
request ??= new AssetContentQueryDto();
if (asset == null)
{
@ -127,16 +127,16 @@ namespace Squidex.Areas.Api.Controllers.Assets
return StatusCode(403);
}
if (asset != null && queries.Version > EtagVersion.Any && asset.Version != queries.Version)
if (asset != null && request.Version > EtagVersion.Any && asset.Version != request.Version)
{
if (context.App != null)
{
asset = await assetQuery.FindAsync(context, asset.Id, queries.Version);
asset = await assetQuery.FindAsync(context, asset.Id, request.Version);
}
else
{
// Fallback for old endpoint. Does not set the surrogate key.
asset = await assetLoader.GetAsync(asset.AppId.Id, asset.Id, queries.Version);
asset = await assetLoader.GetAsync(asset.AppId.Id, asset.Id, request.Version);
}
}
@ -145,15 +145,15 @@ namespace Squidex.Areas.Api.Controllers.Assets
return NotFound();
}
var resizeOptions = queries.ToResizeOptions(asset);
var resizeOptions = request.ToResizeOptions(asset);
FileCallback callback;
Response.Headers[HeaderNames.ETag] = asset.FileVersion.ToString();
if (queries.CacheDuration > 0)
if (request.CacheDuration > 0)
{
Response.Headers[HeaderNames.CacheControl] = $"public,max-age={queries.CacheDuration}";
Response.Headers[HeaderNames.CacheControl] = $"public,max-age={request.CacheDuration}";
}
var contentLength = (long?)null;
@ -164,7 +164,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
{
var resizedAsset = $"{asset.AppId.Id}_{asset.Id}_{asset.FileVersion}_{resizeOptions}";
if (queries.ForceResize)
if (request.ForceResize)
{
await ResizeAsync(asset, bodyStream, resizedAsset, resizeOptions, true, ct);
}
@ -198,7 +198,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
FileDownloadName = asset.FileName,
FileSize = contentLength,
LastModified = asset.LastModified.ToDateTimeOffset(),
SendInline = queries.Download != 1
SendInline = request.Download != 1
};
}

12
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs

@ -68,7 +68,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
}
/// <summary>
/// Upload a new asset.
/// Create an asset folder.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="request">The asset folder object that needs to be added to the App.</param>
@ -79,7 +79,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// </returns>
[HttpPost]
[Route("apps/{app}/assets/folders", Order = -1)]
[ProducesResponseType(typeof(AssetDto), 201)]
[ProducesResponseType(typeof(AssetFolderDto), 201)]
[AssetRequestSizeLimit]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpdate)]
[ApiCosts(1)]
@ -93,7 +93,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
}
/// <summary>
/// Updates the asset folder.
/// Update an asset folder.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="id">The id of the asset folder.</param>
@ -105,7 +105,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// </returns>
[HttpPut]
[Route("apps/{app}/assets/folders/{id}/", Order = -1)]
[ProducesResponseType(typeof(AssetDto), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(AssetFolderDto), StatusCodes.Status200OK)]
[AssetRequestSizeLimit]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpdate)]
[ApiCosts(1)]
@ -119,7 +119,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
}
/// <summary>
/// Moves the asset folder.
/// Move an asset folder.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="id">The id of the asset folder.</param>
@ -131,7 +131,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// </returns>
[HttpPut]
[Route("apps/{app}/assets/folders/{id}/parent", Order = -1)]
[ProducesResponseType(typeof(AssetDto), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(AssetFolderDto), StatusCodes.Status200OK)]
[AssetRequestSizeLimit]
[ApiPermissionOrAnonymous(Permissions.AppAssetsUpdate)]
[ApiCosts(1)]

31
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs

@ -172,10 +172,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// Upload a new asset.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="parentId">The optional parent folder id.</param>
/// <param name="file">The file to upload.</param>
/// <param name="id">The optional custom asset id.</param>
/// <param name="duplicate">True to duplicate the asset, event if the file has been uploaded.</param>
/// <param name="request">The request parameters.</param>
/// <returns>
/// 201 => Asset created.
/// 400 => Asset request not valid.
@ -191,16 +188,9 @@ namespace Squidex.Areas.Api.Controllers.Assets
[AssetRequestSizeLimit]
[ApiPermissionOrAnonymous(Permissions.AppAssetsCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostAsset(string app, [FromQuery] DomainId parentId, IFormFile file, [FromQuery] DomainId? id = null, [FromQuery] bool duplicate = false)
public async Task<IActionResult> PostAsset(string app, CreateAssetDto request)
{
var assetFile = await CheckAssetFileAsync(file);
var command = new CreateAsset { File = assetFile, ParentId = parentId, Duplicate = duplicate };
if (id != null && id.Value != default && !string.IsNullOrWhiteSpace(id.Value.ToString()))
{
command.AssetId = id.Value;
}
var command = request.ToCommand(await CheckAssetFileAsync(request.File));
var response = await InvokeCommandAsync(command);
@ -238,9 +228,8 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// Upsert an asset.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="parentId">The optional parent folder id.</param>
/// <param name="file">The file to upload.</param>
/// <param name="id">The optional custom asset id.</param>
/// <param name="request">The request parameters.</param>
/// <returns>
/// 200 => Asset created or updated.
/// 400 => Asset request not valid.
@ -256,11 +245,9 @@ namespace Squidex.Areas.Api.Controllers.Assets
[AssetRequestSizeLimit]
[ApiPermissionOrAnonymous(Permissions.AppAssetsCreate)]
[ApiCosts(1)]
public async Task<IActionResult> PostUpsertAsset(string app, DomainId id, [FromQuery] DomainId? parentId, IFormFile file)
public async Task<IActionResult> PostUpsertAsset(string app, DomainId id, UpsertAssetDto request)
{
var assetFile = await CheckAssetFileAsync(file);
var command = new UpsertAsset { File = assetFile, ParentId = parentId, AssetId = id };
var command = request.ToCommand(id, await CheckAssetFileAsync(request.File));
var response = await InvokeCommandAsync(command);
@ -289,9 +276,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
[ApiCosts(1)]
public async Task<IActionResult> PutAssetContent(string app, DomainId id, IFormFile file)
{
var assetFile = await CheckAssetFileAsync(file);
var command = new UpdateAsset { File = assetFile, AssetId = id };
var command = new UpdateAsset { File = await CheckAssetFileAsync(file), AssetId = id };
var response = await InvokeCommandAsync(command);
@ -299,7 +284,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
}
/// <summary>
/// Updates the asset.
/// Update an asset.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="id">The id of the asset.</param>

60
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetDto.cs

@ -0,0 +1,60 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Squidex.Assets;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Areas.Api.Controllers.Assets.Models
{
public sealed class CreateAssetDto
{
/// <summary>
/// The file to upload.
/// </summary>
public IFormFile File { get; set; }
/// <summary>
/// The optional parent folder id.
/// </summary>
[FromQuery]
public DomainId ParentId { get; set; }
/// <summary>
/// The optional path to the parent folder.
/// </summary>
[FromQuery]
public string? ParentPath { get; set; }
/// <summary>
/// The optional custom asset id.
/// </summary>
[FromQuery]
public DomainId? Id { get; set; }
/// <summary>
/// True to duplicate the asset, event if the file has been uploaded.
/// </summary>
[FromQuery]
public bool Duplicate { get; set; }
public CreateAsset ToCommand(AssetFile file)
{
var command = SimpleMapper.Map(this, new CreateAsset { File = file });
if (Id != null && Id.Value != default && !string.IsNullOrWhiteSpace(Id.Value.ToString()))
{
command.AssetId = Id.Value;
}
return command;
}
}
}

47
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/UpsertAssetDto.cs

@ -0,0 +1,47 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Squidex.Assets;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Areas.Api.Controllers.Assets.Models
{
public sealed class UpsertAssetDto
{
/// <summary>
/// The file to upload.
/// </summary>
public IFormFile File { get; set; }
/// <summary>
/// The optional parent folder id.
/// </summary>
[FromQuery]
public DomainId ParentId { get; set; }
/// <summary>
/// The optional path to the parent folder.
/// </summary>
[FromQuery]
public string? ParentPath { get; set; }
/// <summary>
/// True to duplicate the asset, event if the file has been uploaded.
/// </summary>
[FromQuery]
public bool Duplicate { get; set; }
public UpsertAsset ToCommand(DomainId id, AssetFile file)
{
return SimpleMapper.Map(this, new UpsertAsset { File = file, AssetId = id });
}
}
}

4
backend/src/Squidex/Areas/Api/Controllers/Comments/CommentsController.cs

@ -93,7 +93,7 @@ namespace Squidex.Areas.Api.Controllers.Comments
}
/// <summary>
/// Updates the comment.
/// Update a comment.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="commentsId">The id of the comments.</param>
@ -118,7 +118,7 @@ namespace Squidex.Areas.Api.Controllers.Comments
}
/// <summary>
/// Deletes the comment.
/// Delete a comment.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="commentsId">The id of the comments.</param>

2
backend/src/Squidex/Areas/Api/Controllers/Comments/Notifications/UserNotificationsController.cs

@ -67,7 +67,7 @@ namespace Squidex.Areas.Api.Controllers.Comments.Notifications
}
/// <summary>
/// Deletes the notification.
/// Delete a notification.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="commentId">The id of the comment.</param>

4
backend/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs

@ -107,7 +107,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
}
/// <summary>
/// Reorders the fields.
/// Reorder all fields.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="name">The name of the schema.</param>
@ -132,7 +132,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas
}
/// <summary>
/// Reorders the nested fields.
/// Reorder all nested fields.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="name">The name of the schema.</param>

10
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs

@ -65,6 +65,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var schemaDef =
new Schema(schemaId.Name)
.Publish()
.AddNumber(16, "2_numbers", Partitioning.Invariant,
new NumberFieldProperties())
.AddNumber(17, "2-numbers", Partitioning.Invariant,
new NumberFieldProperties())
.AddNumber(18, "content", Partitioning.Invariant,
new NumberFieldProperties())
.AddJson(1, "my-json", Partitioning.Invariant,
new JsonFieldProperties())
.AddString(2, "my-string", Partitioning.Language,
@ -97,10 +103,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
.AddBoolean(121, "nested-boolean")
.AddNumber(122, "nested-number")
.AddNumber(123, "nested_number"))
.AddNumber(16, "2_numbers", Partitioning.Invariant,
new NumberFieldProperties())
.AddNumber(17, "2-numbers", Partitioning.Invariant,
new NumberFieldProperties())
.SetScripts(new SchemaScripts { Query = "<query-script>" });
schema = Mocks.Schema(appId, schemaId, schemaDef);

10
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs

@ -32,6 +32,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
gql_2Numbers2 {
iv
}
content {
iv
}
myString {
de
}
@ -92,6 +95,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
.AddField("2-numbers",
new ContentFieldData()
.AddInvariant(23))
.AddField("content",
new ContentFieldData()
.AddInvariant(24))
.AddField("my-number",
new ContentFieldData()
.AddInvariant(1.0))
@ -208,6 +214,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{
iv = 23.0
},
["content"] = new
{
iv = 24.0
},
["myString"] = new
{
de = "value"

Loading…
Cancel
Save