mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
458 lines
13 KiB
458 lines
13 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using Squidex.ClientLibrary;
|
|
using TestSuite.Fixtures;
|
|
using TestSuite.Utils;
|
|
|
|
namespace TestSuite;
|
|
|
|
public static class ClientExtensions
|
|
{
|
|
private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30);
|
|
|
|
private static TimeSpan GetTimeout(TimeSpan timeout)
|
|
{
|
|
if (timeout == default)
|
|
{
|
|
return DefaultTimeout;
|
|
}
|
|
|
|
return timeout;
|
|
}
|
|
|
|
public static bool IsPost(this WebhookRequest request)
|
|
{
|
|
return request.Method == "POST";
|
|
}
|
|
|
|
public static bool HasContent(this WebhookRequest request, string content)
|
|
{
|
|
return request.Content.Contains(content, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
public static async Task<bool> PollForDeletionAsync(this IAssetsClient client, string id,
|
|
TimeSpan timeout = default)
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
await client.GetAssetAsync(id, cts.Token);
|
|
}
|
|
catch (SquidexException ex) when (ex.StatusCode == 404)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static async Task<AssetDto?> PollAsync(this IAssetsClient client, Func<AssetDto, bool> predicate,
|
|
TimeSpan timeout = default)
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var results = await client.GetAssetsAsync(null, cts.Token);
|
|
var result = results.Items.FirstOrDefault(predicate);
|
|
|
|
if (result != null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static async Task<ContentsResult<TEntity, TData>> PollAsync<TEntity, TData>(this IContentsClient<TEntity, TData> client, ContentQuery q, Func<TEntity, bool> predicate,
|
|
TimeSpan timeout = default) where TEntity : Content<TData> where TData : class, new()
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var result = await client.GetAsync(q, null, cts.Token);
|
|
|
|
if (result.Items.Any(predicate))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return new ContentsResult<TEntity, TData>();
|
|
}
|
|
|
|
public static async Task<SearchResultDto?> PollAsync(this ISearchClient client, string query, Func<SearchResultDto, bool> predicate,
|
|
TimeSpan timeout = default)
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var results = await client.GetSearchResultsAsync(query, cts.Token);
|
|
var result = results.FirstOrDefault(predicate);
|
|
|
|
if (result != null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static async Task<WebhookRequest?> PollAsync(this WebhookCatcherClient client, string sessionId, Func<WebhookRequest, bool> predicate,
|
|
TimeSpan timeout = default)
|
|
{
|
|
if (timeout == default)
|
|
{
|
|
timeout = TimeSpan.FromMinutes(2);
|
|
}
|
|
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(timeout);
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var results = await client.GetRequestsAsync(sessionId, cts.Token);
|
|
var result = results.FirstOrDefault(predicate);
|
|
|
|
if (result != null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(50, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static async Task<HistoryEventDto?> PollAsync(this IHistoryClient client, string? channel, Func<HistoryEventDto, bool> predicate,
|
|
TimeSpan timeout = default)
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var results = await client.GetAppHistoryAsync(channel, cts.Token);
|
|
var result = results.FirstOrDefault(predicate);
|
|
|
|
if (result != null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static async Task<RuleEventDto?> PollEventAsync(this IRulesClient client, string? ruleId, Func<RuleEventDto, bool> predicate,
|
|
TimeSpan timeout = default)
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var results = await client.GetEventsAsync(ruleId, null, null, cts.Token);
|
|
var result = results.Items.FirstOrDefault(predicate);
|
|
|
|
if (result != null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
[Obsolete("Replaced with jobs.")]
|
|
public static async Task<BackupJobDto?> PollAsync(this IBackupsClient client, Func<BackupJobDto, bool> predicate,
|
|
TimeSpan timeout = default)
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var results = await client.GetBackupsAsync(cts.Token);
|
|
var result = results.Items.FirstOrDefault(predicate);
|
|
|
|
if (result != null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static async Task<JobDto?> PollAsync(this IJobsClient client, Func<JobDto, bool> predicate,
|
|
TimeSpan timeout = default)
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var results = await client.GetJobsAsync(cts.Token);
|
|
var result = results.Items.FirstOrDefault(predicate);
|
|
|
|
if (result != null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static async Task<IDictionary<string, int>> PollTagAsync(this IAssetsClient client, string id,
|
|
TimeSpan timeout = default)
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var result = await client.GetTagsAsync(cts.Token);
|
|
|
|
if (result.TryGetValue(id, out var count) && count > 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return await client.GetTagsAsync();
|
|
}
|
|
|
|
public static async Task<RestoreJobDto?> PollRestoreAsync(this IBackupsClient client, Func<RestoreJobDto, bool> predicate,
|
|
TimeSpan timeout = default)
|
|
{
|
|
try
|
|
{
|
|
using var cts = new CancellationTokenSource(GetTimeout(timeout));
|
|
|
|
while (!cts.IsCancellationRequested)
|
|
{
|
|
var result = await client.GetRestoreJobAsync(cts.Token);
|
|
|
|
if (predicate(result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
await Task.Delay(200, cts.Token);
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static async Task<MemoryStream?> DownloadAsync(this ClientFixture fixture, AssetDto asset, int? version = null)
|
|
{
|
|
var temp = new MemoryStream();
|
|
|
|
using (var httpClient = new HttpClient())
|
|
{
|
|
httpClient.BaseAddress = new Uri(fixture.Url);
|
|
|
|
var url = asset.Links["content"].Href[1..];
|
|
|
|
if (version > 0)
|
|
{
|
|
url += $"?version={version}";
|
|
}
|
|
|
|
using (var response = await httpClient.GetAsync(url))
|
|
{
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
await using (var stream = await response.Content.ReadAsStreamAsync())
|
|
{
|
|
await stream.CopyToAsync(temp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return temp;
|
|
}
|
|
|
|
public static async Task UploadInChunksAsync(this IAssetsClient client, ProgressHandler progress, FileParameter fileParameter, string? id = null)
|
|
{
|
|
var pausingStream = new PauseStream(fileParameter.Data, 0.25);
|
|
var pausingFile = new FileParameter(pausingStream, fileParameter.FileName, fileParameter.ContentType)
|
|
{
|
|
ContentLength = fileParameter.Data.Length,
|
|
};
|
|
|
|
await using (pausingFile.Data)
|
|
{
|
|
using var cts = new CancellationTokenSource(5000);
|
|
|
|
while (progress.Asset == null && progress.Exception == null && !cts.IsCancellationRequested)
|
|
{
|
|
pausingStream.Reset();
|
|
|
|
await client.UploadAssetAsync(pausingFile, progress.AsOptions(id), cts.Token);
|
|
progress.Uploaded();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static async Task<AssetDto> UploadFileAsync(this IAssetsClient client, string path, AssetDto asset, string? fileName = null)
|
|
{
|
|
var fileInfo = new FileInfo(path);
|
|
|
|
await using (var stream = fileInfo.OpenRead())
|
|
{
|
|
var upload = new FileParameter(stream, fileName ?? fileInfo.Name, asset.MimeType);
|
|
|
|
return await client.PutAssetContentAsync(asset.Id, upload);
|
|
}
|
|
}
|
|
|
|
public static async Task<AssetDto> UploadFileAsync(this IAssetsClient client, string path, string fileType, string? fileName = null, string? parentId = null, string? id = null)
|
|
{
|
|
var fileInfo = new FileInfo(path);
|
|
|
|
await using (var stream = fileInfo.OpenRead())
|
|
{
|
|
var upload = new FileParameter(stream, fileName ?? fileInfo.Name, fileType);
|
|
|
|
return await client.PostAssetAsync(parentId, id, true, upload);
|
|
}
|
|
}
|
|
|
|
public static async Task<AssetDto> ReplaceFileAsync(this IAssetsClient client, string id, string path, string fileType, string? fileName = null)
|
|
{
|
|
var fileInfo = new FileInfo(path);
|
|
|
|
await using (var stream = fileInfo.OpenRead())
|
|
{
|
|
var upload = new FileParameter(stream, fileName ?? fileInfo.Name, fileType);
|
|
|
|
return await client.PutAssetContentAsync(id, upload);
|
|
}
|
|
}
|
|
|
|
public static async Task<AssetDto> UploadRandomFileAsync(this IAssetsClient client, int size, string? parentId = null, string? id = null)
|
|
{
|
|
await using (var stream = RandomAsset(size))
|
|
{
|
|
var upload = new FileParameter(stream, RandomName(".txt"), "text/csv");
|
|
|
|
return await client.PostAssetAsync(parentId, id, true, upload);
|
|
}
|
|
}
|
|
|
|
private static MemoryStream RandomAsset(int length)
|
|
{
|
|
var stream = new MemoryStream(length);
|
|
|
|
var random = new Random();
|
|
|
|
for (var i = 0; i < length; i++)
|
|
{
|
|
stream.WriteByte((byte)random.Next());
|
|
}
|
|
|
|
stream.Position = 0;
|
|
|
|
return stream;
|
|
}
|
|
|
|
private static string RandomName(string extension)
|
|
{
|
|
var fileName = $"{Guid.NewGuid()}{extension}";
|
|
|
|
return fileName;
|
|
}
|
|
}
|
|
|