mirror of https://github.com/Squidex/squidex.git
Browse Source
# Conflicts: # src/Squidex/Areas/Api/Controllers/Content/ContentsController.cs # src/Squidex/app/features/content/declarations.ts # src/Squidex/app/features/content/module.ts # src/Squidex/app/features/content/pages/content/content-page.component.html # src/Squidex/app/features/content/pages/content/content-page.component.ts # src/Squidex/app/features/content/pages/contents/contents-page.component.ts # src/Squidex/app/features/content/shared/content-item.component.html # src/Squidex/app/shared/services/contents.service.spec.ts # src/Squidex/app/shared/services/contents.service.tspull/285/head
662 changed files with 15276 additions and 10883 deletions
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Core.HandleRules |
|||
{ |
|||
public interface IRuleUrlGenerator |
|||
{ |
|||
string GenerateContentUIUrl(NamedId<Guid> appId, NamedId<Guid> schemaId, Guid contentId); |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Core.Schemas; |
|||
using Squidex.Domain.Apps.Entities.Contents.State; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.States; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents |
|||
{ |
|||
public sealed class ContentVersionLoader : IContentVersionLoader |
|||
{ |
|||
private readonly IStore<Guid> store; |
|||
private readonly FieldRegistry registry; |
|||
|
|||
public ContentVersionLoader(IStore<Guid> store, FieldRegistry registry) |
|||
{ |
|||
Guard.NotNull(store, nameof(store)); |
|||
Guard.NotNull(registry, nameof(registry)); |
|||
|
|||
this.store = store; |
|||
|
|||
this.registry = registry; |
|||
} |
|||
|
|||
public async Task<IContentEntity> LoadAsync(Guid id, long version) |
|||
{ |
|||
var content = new ContentState(); |
|||
|
|||
var persistence = store.WithEventSourcing<ContentGrain, Guid>(id, e => |
|||
{ |
|||
if (content.Version < version) |
|||
{ |
|||
content = content.Apply(e); |
|||
content.Version++; |
|||
} |
|||
}); |
|||
|
|||
await persistence.ReadAsync(); |
|||
|
|||
if (content.Version != version) |
|||
{ |
|||
throw new DomainObjectNotFoundException(id.ToString(), typeof(IContentEntity)); |
|||
} |
|||
|
|||
return content; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Contents |
|||
{ |
|||
public interface IContentVersionLoader |
|||
{ |
|||
Task<IContentEntity> LoadAsync(Guid id, long version); |
|||
} |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Microsoft.AspNetCore.Http; |
|||
|
|||
namespace Squidex.Infrastructure.Caching |
|||
{ |
|||
public sealed class HttpRequestCache : IRequestCache |
|||
{ |
|||
private readonly IHttpContextAccessor httpContextAccessor; |
|||
|
|||
public HttpRequestCache(IHttpContextAccessor httpContextAccessor) |
|||
{ |
|||
Guard.NotNull(httpContextAccessor, nameof(httpContextAccessor)); |
|||
|
|||
this.httpContextAccessor = httpContextAccessor; |
|||
} |
|||
|
|||
public void Add(object key, object value) |
|||
{ |
|||
var cacheKey = GetCacheKey(key); |
|||
|
|||
var items = httpContextAccessor.HttpContext?.Items; |
|||
|
|||
if (items != null) |
|||
{ |
|||
items[cacheKey] = value; |
|||
} |
|||
} |
|||
|
|||
public void Remove(object key) |
|||
{ |
|||
var cacheKey = GetCacheKey(key); |
|||
|
|||
var items = httpContextAccessor.HttpContext?.Items; |
|||
|
|||
if (items != null) |
|||
{ |
|||
items?.Remove(cacheKey); |
|||
} |
|||
} |
|||
|
|||
public bool TryGetValue(object key, out object value) |
|||
{ |
|||
var cacheKey = GetCacheKey(key); |
|||
|
|||
var items = httpContextAccessor.HttpContext?.Items; |
|||
|
|||
if (items != null) |
|||
{ |
|||
return items.TryGetValue(cacheKey, out value); |
|||
} |
|||
|
|||
value = null; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private static string GetCacheKey(object key) |
|||
{ |
|||
return $"CACHE_{key}"; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
namespace Squidex.Infrastructure.Caching |
|||
{ |
|||
public interface IRequestCache |
|||
{ |
|||
void Add(object key, object value); |
|||
|
|||
void Remove(object key); |
|||
|
|||
bool TryGetValue(object key, out object value); |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Squidex.Infrastructure.Caching |
|||
{ |
|||
public static class RequestCacheExtensions |
|||
{ |
|||
public static async Task<T> GetOrCreateAsync<T>(this IRequestCache cache, object key, Func<Task<T>> task) |
|||
{ |
|||
if (cache.TryGetValue(key, out var value) && value is T typedValue) |
|||
{ |
|||
return typedValue; |
|||
} |
|||
|
|||
typedValue = await task(); |
|||
|
|||
cache.Add(key, typedValue); |
|||
|
|||
return typedValue; |
|||
} |
|||
|
|||
public static T GetOrCreate<T>(this IRequestCache cache, object key, Func<T> task) |
|||
{ |
|||
if (cache.TryGetValue(key, out var value) && value is T typedValue) |
|||
{ |
|||
return typedValue; |
|||
} |
|||
|
|||
typedValue = task(); |
|||
|
|||
cache.Add(key, typedValue); |
|||
|
|||
return typedValue; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
namespace Squidex.Infrastructure.Log |
|||
{ |
|||
public interface ILogProfilerSessionProvider |
|||
{ |
|||
ProfilerSession GetSession(); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace Squidex.Infrastructure.Log |
|||
{ |
|||
public sealed class NoopDisposable : IDisposable |
|||
{ |
|||
public static readonly NoopDisposable Instance = new NoopDisposable(); |
|||
|
|||
private NoopDisposable() |
|||
{ |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Diagnostics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace Squidex.Infrastructure.Log |
|||
{ |
|||
public static class Profile |
|||
{ |
|||
private static ILogProfilerSessionProvider sessionProvider; |
|||
|
|||
private sealed class Timer : IDisposable |
|||
{ |
|||
private readonly Stopwatch watch = Stopwatch.StartNew(); |
|||
private readonly ProfilerSession session; |
|||
private readonly string key; |
|||
|
|||
public Timer(ProfilerSession session, string key) |
|||
{ |
|||
this.session = session; |
|||
this.key = key; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
watch.Stop(); |
|||
|
|||
session.Measured(key, watch.ElapsedMilliseconds); |
|||
} |
|||
} |
|||
|
|||
public static void Init(ILogProfilerSessionProvider provider) |
|||
{ |
|||
sessionProvider = provider; |
|||
} |
|||
|
|||
public static IDisposable Method<T>([CallerMemberName] string memberName = null) |
|||
{ |
|||
return Key($"{typeof(T).Name}/{memberName}"); |
|||
} |
|||
|
|||
public static IDisposable Method(string objectName, [CallerMemberName] string memberName = null) |
|||
{ |
|||
return Key($"{objectName}/{memberName}"); |
|||
} |
|||
|
|||
public static IDisposable Key(string key) |
|||
{ |
|||
Guard.NotNull(key, nameof(key)); |
|||
|
|||
var session = sessionProvider?.GetSession(); |
|||
|
|||
if (session == null) |
|||
{ |
|||
return NoopDisposable.Instance; |
|||
} |
|||
|
|||
return new Timer(session, key); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Concurrent; |
|||
|
|||
namespace Squidex.Infrastructure.Log |
|||
{ |
|||
public sealed class ProfilerSession |
|||
{ |
|||
private struct ProfilerItem |
|||
{ |
|||
public long Total; |
|||
public long Count; |
|||
} |
|||
|
|||
private readonly ConcurrentDictionary<string, ProfilerItem> traces = new ConcurrentDictionary<string, ProfilerItem>(); |
|||
|
|||
public void Measured(string name, long elapsed) |
|||
{ |
|||
Guard.NotNullOrEmpty(name, nameof(name)); |
|||
|
|||
traces.AddOrUpdate(name, x => |
|||
{ |
|||
return new ProfilerItem { Total = elapsed, Count = 1 }; |
|||
}, |
|||
(x, result) => |
|||
{ |
|||
result.Total += elapsed; |
|||
result.Count++; |
|||
|
|||
return result; |
|||
}); |
|||
} |
|||
|
|||
public void Write(IObjectWriter writer) |
|||
{ |
|||
Guard.NotNull(writer, nameof(writer)); |
|||
|
|||
if (traces.Count > 0) |
|||
{ |
|||
writer.WriteObject("profiler", p => |
|||
{ |
|||
foreach (var kvp in traces) |
|||
{ |
|||
p.WriteObject(kvp.Key, k => k |
|||
.WriteProperty("elapsedMsTotal", kvp.Value.Total) |
|||
.WriteProperty("elapsedMsAvg", kvp.Value.Total / kvp.Value.Count) |
|||
.WriteProperty("count", kvp.Value.Count)); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Caching.Memory; |
|||
|
|||
namespace Squidex.Infrastructure.UsageTracking |
|||
{ |
|||
public sealed class CachingUsageTracker : CachingProviderBase, IUsageTracker |
|||
{ |
|||
private static readonly TimeSpan CacheTime = TimeSpan.FromMinutes(10); |
|||
private readonly IUsageTracker inner; |
|||
|
|||
public CachingUsageTracker(IUsageTracker inner, IMemoryCache cache) |
|||
: base(cache) |
|||
{ |
|||
Guard.NotNull(inner, nameof(inner)); |
|||
|
|||
this.inner = inner; |
|||
} |
|||
|
|||
public Task<IReadOnlyList<StoredUsage>> QueryAsync(string key, DateTime fromDate, DateTime toDate) |
|||
{ |
|||
return inner.QueryAsync(key, fromDate, toDate); |
|||
} |
|||
|
|||
public Task TrackAsync(string key, double weight, double elapsedMs) |
|||
{ |
|||
return inner.TrackAsync(key, weight, elapsedMs); |
|||
} |
|||
|
|||
public async Task<long> GetMonthlyCallsAsync(string key, DateTime date) |
|||
{ |
|||
Guard.NotNull(key, nameof(key)); |
|||
|
|||
var cacheKey = string.Concat(key, date); |
|||
|
|||
if (Cache.TryGetValue<long>(cacheKey, out var result)) |
|||
{ |
|||
return result; |
|||
} |
|||
|
|||
result = await inner.GetMonthlyCallsAsync(key, date); |
|||
|
|||
Cache.Set(cacheKey, result, CacheTime); |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace Squidex.Areas.Api.Controllers.Apps.Models |
|||
{ |
|||
public sealed class ContributorAssignedDto |
|||
{ |
|||
/// <summary>
|
|||
/// The id of the user that has been assigned as contributor.
|
|||
/// </summary>
|
|||
[Required] |
|||
public string ContributorId { get; set; } |
|||
|
|||
public static ContributorAssignedDto FromId(string id) |
|||
{ |
|||
return new ContributorAssignedDto { ContributorId = id }; |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue