Skip to content

Commit

Permalink
Improve assets import to also make update.
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianStehle committed Oct 4, 2021
1 parent 3d99fa6 commit 4df5fd4
Show file tree
Hide file tree
Showing 10 changed files with 1,197 additions and 651 deletions.
26 changes: 13 additions & 13 deletions cli/Squidex.CLI/Squidex.CLI.Tests/FolderTreeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public async Task Should_query_for_path_once_for_each_subtree()
FolderName = "folder2"
};

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder1.Id, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder1.Id, A<AssetFolderScope>._, A<CancellationToken>._))
.Returns(new AssetFoldersDto
{
Items = new List<AssetFolderDto>(),
Expand All @@ -77,7 +77,7 @@ public async Task Should_query_for_path_once_for_each_subtree()
}
});

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder2.Id, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder2.Id, A<AssetFolderScope>._, A<CancellationToken>._))
.Returns(new AssetFoldersDto
{
Items = new List<AssetFolderDto>(),
Expand All @@ -90,7 +90,7 @@ public async Task Should_query_for_path_once_for_each_subtree()
Assert.Equal("folder1", await sut.GetPathAsync(folder1.Id));
Assert.Equal("folder2", await sut.GetPathAsync(folder2.Id));

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<AssetFolderScope>._, A<CancellationToken>._))
.MustHaveHappenedTwiceExactly();
}

Expand All @@ -111,7 +111,7 @@ public async Task Should_not_query_for_path_again_if_child_already_queried()
FolderName = "folder2"
};

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder2.Id, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder2.Id, A<AssetFolderScope>._, A<CancellationToken>._))
.Returns(new AssetFoldersDto
{
Items = new List<AssetFolderDto>(),
Expand All @@ -125,7 +125,7 @@ public async Task Should_not_query_for_path_again_if_child_already_queried()
Assert.Equal("folder1/folder2", await sut.GetPathAsync(folder2.Id));
Assert.Equal("folder1", await sut.GetPathAsync(folder1.Id));

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<AssetFolderScope>._, A<CancellationToken>._))
.MustHaveHappenedOnceExactly();
}

Expand All @@ -146,7 +146,7 @@ public async Task Should_not_query_for_path_again_if_parent_already_queried()
FolderName = "folder2"
};

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder1.Id, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder1.Id, A<AssetFolderScope>._, A<CancellationToken>._))
.Returns(new AssetFoldersDto
{
Items = new List<AssetFolderDto>
Expand All @@ -162,7 +162,7 @@ public async Task Should_not_query_for_path_again_if_parent_already_queried()
Assert.Equal("folder1", await sut.GetPathAsync(folder1.Id));
Assert.Equal("folder1/folder2", await sut.GetPathAsync(folder2.Id));

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<AssetFolderScope>._, A<CancellationToken>._))
.MustHaveHappenedOnceExactly();
}

Expand All @@ -183,7 +183,7 @@ public async Task Should_query_for_id_once_for_each_tree_item()
FolderName = "folder2"
};

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", RootId, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", RootId, A<AssetFolderScope>._, A<CancellationToken>._))
.Returns(new AssetFoldersDto
{
Items = new List<AssetFolderDto>
Expand All @@ -197,7 +197,7 @@ public async Task Should_query_for_id_once_for_each_tree_item()
Assert.Equal(folder1.Id, await sut.GetIdAsync("folder1"));
Assert.Equal(folder2.Id, await sut.GetIdAsync("folder2"));

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<AssetFolderScope>._, A<CancellationToken>._))
.MustHaveHappenedOnceExactly();
}

Expand All @@ -218,7 +218,7 @@ public async Task Should_not_query_for_id_again_if_parent_already_queried()
FolderName = "folder2"
};

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder1.Id, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", folder1.Id, A<AssetFolderScope>._, A<CancellationToken>._))
.Returns(new AssetFoldersDto
{
Items = new List<AssetFolderDto>
Expand All @@ -234,7 +234,7 @@ public async Task Should_not_query_for_id_again_if_parent_already_queried()
Assert.Equal("folder1", await sut.GetPathAsync(folder1.Id));
Assert.Equal("folder1/folder2", await sut.GetPathAsync(folder2.Id));

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<AssetFolderScope>._, A<CancellationToken>._))
.MustHaveHappenedOnceExactly();
}

Expand All @@ -255,7 +255,7 @@ public async Task Should_query_for_id_once_and_create_new_folder()
FolderName = "folder2"
};

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", RootId, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", RootId, A<AssetFolderScope>._, A<CancellationToken>._))
.Returns(new AssetFoldersDto
{
Items = new List<AssetFolderDto>
Expand All @@ -273,7 +273,7 @@ public async Task Should_query_for_id_once_and_create_new_folder()
Assert.Equal(folder1.Id, await sut.GetIdAsync("folder1"));
Assert.Equal(folder2.Id, await sut.GetIdAsync("folder2"));

A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<CancellationToken>._))
A.CallTo(() => assets.GetAssetFoldersAsync("my-app", A<string>._, A<AssetFolderScope>._, A<CancellationToken>._))
.MustHaveHappenedOnceExactly();
}
}
Expand Down
48 changes: 45 additions & 3 deletions cli/Squidex.CLI/Squidex.CLI/Commands/App_Assets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================

using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CommandDotNet;
using FluentValidation;
using FluentValidation.Attributes;
using Squidex.CLI.Commands.Implementation;
using Squidex.CLI.Commands.Implementation.Sync.Assets;
using Squidex.CLI.Configuration;
using Squidex.ClientLibrary.Management;

namespace Squidex.CLI.Commands
{
Expand Down Expand Up @@ -47,7 +50,7 @@ public async Task List(ImportArguments arguments)
var relativeFolder = Path.GetRelativePath(folder.FullName, file.Directory.FullName);
var relativePath = Path.GetRelativePath(folder.FullName, file.FullName);

var targetFolder = arguments.TargetFolder;
var targetFolder = arguments.TargetFolder ?? ".";

if (!string.IsNullOrWhiteSpace(relativePath) && relativePath != ".")
{
Expand All @@ -56,10 +59,49 @@ public async Task List(ImportArguments arguments)

var parentId = await folderTree.GetIdAsync(targetFolder);

await log.DoSafeLineAsync($"Uploading {relativePath}", async () =>
var existings = await assets.GetAssetsAsync(session.App, new AssetQuery
{
await assets.PostAssetAsync(session.App, parentId, duplicate: arguments.Duplicate, file: file);
ParentId = parentId,
Filter = $"fileName eq '{file.Name}'",
Top = 2
});

try
{
if (existings.Items.Count > 0)
{
var existing = existings.Items.First();

log.WriteLine($"Updating: {relativePath}");

await assets.PutAssetContentAsync(session.App, existing.Id, file: file);

log.StepSuccess();
}
else
{
log.WriteLine($"Uploading: {relativePath}");

var result = await assets.PostAssetAsync(session.App, parentId, duplicate: arguments.Duplicate, file: file);

if (result._meta.IsDuplicate == "true")
{
log.StepSkipped("duplicate.");
}
else
{
log.StepSuccess();
}
}
}
catch (Exception ex)
{
LogExtensions.HandleException(ex, error => log.WriteLine("Error: {0}", error));
}
finally
{
log.WriteLine();
}
}

log.WriteLine("> Import completed");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,6 @@ public static async Task DoSafeAsync(this ILogger log, string process, Func<Task
}
}

public static async Task DoSafeLineAsync(this ILogger log, string process, Func<Task> action)
{
await LockObject.WaitAsync();
try
{
log.WriteLine("Start: {0}", process);

await action();

log.WriteLine("Done : {0}", process);
}
catch (Exception ex)
{
HandleException(ex, error => log.WriteLine("Error: {0}; {1}", process, error));
}
finally
{
log.WriteLine();

LockObject.Release();
}
}

public static void ProcessSkipped(this ILogger log, string process, string reason)
{
LockObject.Wait();
Expand Down Expand Up @@ -133,7 +110,7 @@ public static void ProcessFailed(this ILogger log, string process, Exception exc
}
}

private static void HandleException(Exception ex, Action<string> error)
public static void HandleException(Exception ex, Action<string> error)
{
switch (ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace Squidex.CLI.Commands.Implementation.Sync.App
{
public sealed class AppRoleModel
{
[Required]
public string[] Permissions { get; set; }
public List<string> Permissions { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ await log.DoSafeAsync("Exporting Roles", async () =>
{
model.Roles[role.Name] = new AppRoleModel
{
Permissions = role.Permissions.ToArray()
Permissions = role.Permissions
};
}
});
Expand Down Expand Up @@ -299,7 +299,7 @@ public async Task GenerateSchemaAsync(ISyncService sync)
{
["custom"] = new AppRoleModel
{
Permissions = new[]
Permissions = new List<string>
{
"schemas.*"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public sealed class AssetModel

public string Slug { get; set; }

public ICollection<string> Tags { get; set; }
public List<string> Tags { get; set; }

public IDictionary<string, object> Metadata { get; set; }
public Dictionary<string, object> Metadata { get; set; }

public bool IsProtected { get; set; }
}
Expand Down
2 changes: 1 addition & 1 deletion cli/Squidex.CLI/Squidex.CLI/Squidex.CLI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<TargetFramework>net5.0</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<ToolCommandName>sq</ToolCommandName>
<Version>7.14</Version>
<Version>7.15</Version>
</PropertyGroup>
<ItemGroup>
<None Remove="Commands\Implementation\OpenLibrary\Structure\schemas\author.json" />
Expand Down
6 changes: 6 additions & 0 deletions csharp/Squidex.ClientLibrary/CodeGeneration/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public static void Main()
generatorSettings.CSharpGeneratorSettings.Namespace = "Squidex.ClientLibrary.Management";
generatorSettings.CSharpGeneratorSettings.RequiredPropertiesMustBeDefined = false;
generatorSettings.CSharpGeneratorSettings.ExcludedTypeNames = new[] { "JsonInheritanceConverter" };
generatorSettings.CSharpGeneratorSettings.ArrayType = "System.Collections.Generic.List";
generatorSettings.CSharpGeneratorSettings.ArrayInstanceType = "System.Collections.Generic.List";
generatorSettings.CSharpGeneratorSettings.ArrayBaseType = "System.Collections.Generic.List";
generatorSettings.CSharpGeneratorSettings.DictionaryBaseType = "System.Collections.Generic.Dictionary";
generatorSettings.CSharpGeneratorSettings.DictionaryInstanceType = "System.Collections.Generic.Dictionary";
generatorSettings.CSharpGeneratorSettings.DictionaryType = "System.Collections.Generic.Dictionary";
generatorSettings.GenerateOptionalParameters = true;
generatorSettings.GenerateClientInterfaces = true;
generatorSettings.ExceptionClass = "SquidexManagementException";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,19 @@ public partial interface IAssetsClient
/// <exception cref="SquidexManagementException">A server side error occurred.</exception>
Task<AssetDto> PostAssetAsync(string app, string parentId = null, string id = null, bool? duplicate = null, FileInfo file = null, CancellationToken cancellationToken = default);

/// <summary>
/// Replace asset content.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="id">The id of the asset.</param>
/// <param name="file">The file to upload.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <returns>
/// Asset updated.
/// </returns>
/// <exception cref="SquidexManagementException">A server side error occurred.</exception>
Task<AssetDto> PutAssetContentAsync(string app, string id, FileInfo file, CancellationToken cancellationToken = default);

/// <summary>Get assets.</summary>
/// <param name="app">The name of the app.</param>
/// <param name="query">The optional asset query.</param>
Expand Down Expand Up @@ -201,6 +214,14 @@ public Task<AssetDto> PostAssetAsync(string app, string parentId = null, string
return PostAssetAsync(app, parentId, id, duplicate, new FileParameter(file.OpenRead(), file.Name, MimeTypesMap.GetMimeType(file.Name)), cancellationToken);
}

/// <inheritdoc />
public Task<AssetDto> PutAssetContentAsync(string app, string id, FileInfo file, CancellationToken cancellationToken = default)
{
Guard.NotNull(file, nameof(file));

return PutAssetContentAsync(app, id, new FileParameter(file.OpenRead(), file.Name, MimeTypesMap.GetMimeType(file.Name)), cancellationToken);
}

/// <inheritdoc />
public Task<AssetsDto> GetAssetsAsync(string app, AssetQuery query = null, CancellationToken cancellationToken = default)
{
Expand Down
Loading

0 comments on commit 4df5fd4

Please sign in to comment.