mirror of https://github.com/Squidex/squidex.git
38 changed files with 579 additions and 569 deletions
@ -1,40 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using MongoDB.Bson; |
|||
using MongoDB.Bson.Serialization.Attributes; |
|||
using Squidex.Domain.Apps.Entities.Assets; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets |
|||
{ |
|||
public sealed class MongoAssetStatsEntity : IAssetStatsEntity |
|||
{ |
|||
[BsonId] |
|||
[BsonElement] |
|||
[BsonRepresentation(BsonType.String)] |
|||
public string Id { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
[BsonRepresentation(BsonType.String)] |
|||
public Guid AssetId { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
[BsonDateTimeOptions(DateOnly = true)] |
|||
public DateTime Date { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public long TotalSize { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public long TotalCount { get; set; } |
|||
} |
|||
} |
|||
@ -1,101 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using Squidex.Domain.Apps.Entities.Assets; |
|||
using Squidex.Domain.Apps.Entities.Assets.Repositories; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
using Squidex.Infrastructure.MongoDb; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets |
|||
{ |
|||
public partial class MongoAssetStatsRepository : MongoRepositoryBase<MongoAssetStatsEntity>, IAssetStatsRepository, IEventConsumer |
|||
{ |
|||
public MongoAssetStatsRepository(IMongoDatabase database) |
|||
: base(database) |
|||
{ |
|||
} |
|||
|
|||
protected override string CollectionName() |
|||
{ |
|||
return "Projections_AssetStats"; |
|||
} |
|||
|
|||
protected override Task SetupCollectionAsync(IMongoCollection<MongoAssetStatsEntity> collection, CancellationToken ct = default(CancellationToken)) |
|||
{ |
|||
return collection.Indexes.CreateManyAsync( |
|||
new[] |
|||
{ |
|||
new CreateIndexModel<MongoAssetStatsEntity>(Index.Ascending(x => x.AssetId).Ascending(x => x.Date)), |
|||
new CreateIndexModel<MongoAssetStatsEntity>(Index.Ascending(x => x.AssetId).Descending(x => x.Date)) |
|||
}, ct); |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<IAssetStatsEntity>> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate) |
|||
{ |
|||
var originalSizesEntities = |
|||
await Collection.Find(x => x.AssetId == appId && x.Date >= fromDate && x.Date <= toDate).SortBy(x => x.Date) |
|||
.ToListAsync(); |
|||
|
|||
var enrichedSizes = new List<MongoAssetStatsEntity>(); |
|||
|
|||
var sizesDictionary = originalSizesEntities.ToDictionary(x => x.Date); |
|||
|
|||
var previousSize = long.MinValue; |
|||
var previousCount = long.MinValue; |
|||
|
|||
for (var date = fromDate; date <= toDate; date = date.AddDays(1)) |
|||
{ |
|||
var size = sizesDictionary.GetOrDefault(date); |
|||
|
|||
if (size != null) |
|||
{ |
|||
previousSize = size.TotalSize; |
|||
previousCount = size.TotalCount; |
|||
} |
|||
else |
|||
{ |
|||
if (previousSize < 0) |
|||
{ |
|||
var firstBeforeRangeEntity = |
|||
await Collection.Find(x => x.AssetId == appId && x.Date < fromDate).SortByDescending(x => x.Date) |
|||
.FirstOrDefaultAsync(); |
|||
|
|||
previousSize = firstBeforeRangeEntity?.TotalSize ?? 0L; |
|||
previousCount = firstBeforeRangeEntity?.TotalCount ?? 0L; |
|||
} |
|||
|
|||
size = new MongoAssetStatsEntity |
|||
{ |
|||
Date = date, |
|||
TotalSize = previousSize, |
|||
TotalCount = previousCount |
|||
}; |
|||
} |
|||
|
|||
enrichedSizes.Add(size); |
|||
} |
|||
|
|||
return enrichedSizes; |
|||
} |
|||
|
|||
public async Task<long> GetTotalSizeAsync(Guid appId) |
|||
{ |
|||
var totalSizeEntity = |
|||
await Collection.Find(x => x.AssetId == appId).SortByDescending(x => x.Date) |
|||
.FirstOrDefaultAsync(); |
|||
|
|||
return totalSizeEntity?.TotalSize ?? 0; |
|||
} |
|||
} |
|||
} |
|||
@ -1,72 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using MongoDB.Bson; |
|||
using MongoDB.Bson.Serialization.Attributes; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.MongoDb; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.History |
|||
{ |
|||
public sealed class MongoHistoryEventEntity : MongoEntity, |
|||
IEntity, |
|||
IUpdateableEntity, |
|||
IUpdateableEntityWithVersion, |
|||
IUpdateableEntityWithCreatedBy |
|||
{ |
|||
[BsonElement] |
|||
[BsonRequired] |
|||
[BsonRepresentation(BsonType.String)] |
|||
public Guid AppId { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public long Version { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public string Channel { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public string Message { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public RefToken Actor { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement] |
|||
public Dictionary<string, string> Parameters { get; set; } |
|||
|
|||
RefToken IUpdateableEntityWithCreatedBy.CreatedBy |
|||
{ |
|||
get |
|||
{ |
|||
return Actor; |
|||
} |
|||
set |
|||
{ |
|||
Actor = value; |
|||
} |
|||
} |
|||
|
|||
public MongoHistoryEventEntity() |
|||
{ |
|||
Parameters = new Dictionary<string, string>(); |
|||
} |
|||
|
|||
public MongoHistoryEventEntity AddParameter(string key, string value) |
|||
{ |
|||
Parameters.Add(key, value); |
|||
|
|||
return this; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Domain.Apps.Entities.Assets.Repositories; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.UsageTracking; |
|||
|
|||
#pragma warning disable CS0649
|
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Assets |
|||
{ |
|||
public partial class DefaultAssetStatsRepository : IAssetStatsRepository |
|||
{ |
|||
private const string Category = "Default"; |
|||
private const string CounterTotalCount = "TotalAssets"; |
|||
private const string CounterTotalSize = "TotalSize"; |
|||
private static readonly DateTime SummaryDate; |
|||
private readonly IUsageRepository usageStore; |
|||
|
|||
public DefaultAssetStatsRepository(IUsageRepository usageStore) |
|||
{ |
|||
Guard.NotNull(usageStore, nameof(usageStore)); |
|||
|
|||
this.usageStore = usageStore; |
|||
} |
|||
|
|||
public async Task<long> GetTotalSizeAsync(Guid appId) |
|||
{ |
|||
var entries = await usageStore.QueryAsync(appId.ToString(), SummaryDate, SummaryDate); |
|||
|
|||
return (long)entries.Select(x => x.Counters.Get(CounterTotalSize)).FirstOrDefault(); |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<AssetStats>> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate) |
|||
{ |
|||
var enriched = new List<AssetStats>(); |
|||
|
|||
var usagesFlat = await usageStore.QueryAsync(appId.ToString(), fromDate, toDate); |
|||
|
|||
for (var date = fromDate; date <= toDate; date = date.AddDays(1)) |
|||
{ |
|||
var stored = usagesFlat.FirstOrDefault(x => x.Date == date && x.Category == Category); |
|||
|
|||
var totalCount = 0L; |
|||
var totalSize = 0L; |
|||
|
|||
if (stored != null) |
|||
{ |
|||
totalCount = (long)stored.Counters.Get(CounterTotalCount); |
|||
totalSize = (long)stored.Counters.Get(CounterTotalSize); |
|||
} |
|||
|
|||
enriched.Add(new AssetStats(date, totalCount, totalSize)); |
|||
} |
|||
|
|||
return enriched; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using NodaTime; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.History |
|||
{ |
|||
public sealed class HistoryEvent |
|||
{ |
|||
public Guid Id { get; set; } = Guid.NewGuid(); |
|||
|
|||
public Guid AppId { get; set; } |
|||
|
|||
public RefToken Actor { get; set; } |
|||
|
|||
public Instant Created { get; set; } |
|||
|
|||
public long Version { get; set; } |
|||
|
|||
public string Channel { get; set; } |
|||
|
|||
public string Message { get; set; } |
|||
|
|||
public Dictionary<string, string> Parameters { get; set; } = new Dictionary<string, string>(); |
|||
|
|||
public HistoryEvent() |
|||
{ |
|||
} |
|||
|
|||
public HistoryEvent(string channel, string message) |
|||
{ |
|||
Guard.NotNullOrEmpty(channel, nameof(channel)); |
|||
Guard.NotNullOrEmpty(message, nameof(message)); |
|||
|
|||
Channel = channel; |
|||
|
|||
Message = message; |
|||
} |
|||
|
|||
public HistoryEvent AddParameter(string key, object value) |
|||
{ |
|||
Parameters[key] = value.ToString(); |
|||
|
|||
return this; |
|||
} |
|||
} |
|||
} |
|||
@ -1,43 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.History |
|||
{ |
|||
public sealed class HistoryEventToStore |
|||
{ |
|||
private readonly Dictionary<string, string> parameters = new Dictionary<string, string>(); |
|||
|
|||
public string Channel { get; } |
|||
|
|||
public string Message { get; } |
|||
|
|||
public IReadOnlyDictionary<string, string> Parameters |
|||
{ |
|||
get { return parameters; } |
|||
} |
|||
|
|||
public HistoryEventToStore(string channel, string message) |
|||
{ |
|||
Guard.NotNullOrEmpty(channel, nameof(channel)); |
|||
Guard.NotNullOrEmpty(message, nameof(message)); |
|||
|
|||
Channel = channel; |
|||
|
|||
Message = message; |
|||
} |
|||
|
|||
public HistoryEventToStore AddParameter(string key, object value) |
|||
{ |
|||
parameters[key] = value.ToString(); |
|||
|
|||
return this; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using NodaTime; |
|||
using Squidex.Domain.Apps.Entities.History.Repositories; |
|||
using Squidex.Domain.Apps.Events; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.EventSourcing; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.History |
|||
{ |
|||
public sealed class HistoryService : IHistoryService, IEventConsumer |
|||
{ |
|||
private readonly Dictionary<string, string> texts = new Dictionary<string, string>(); |
|||
private readonly List<IHistoryEventsCreator> creators; |
|||
private readonly IHistoryEventRepository repository; |
|||
private readonly IClock clock; |
|||
|
|||
public string Name |
|||
{ |
|||
get { return GetType().Name; } |
|||
} |
|||
|
|||
public string EventsFilter |
|||
{ |
|||
get { return ".*"; } |
|||
} |
|||
|
|||
public HistoryService(IHistoryEventRepository repository, IEnumerable<IHistoryEventsCreator> creators, IClock clock) |
|||
{ |
|||
Guard.NotNull(repository, nameof(repository)); |
|||
Guard.NotNull(clock, nameof(clock)); |
|||
Guard.NotNull(creators, nameof(creators)); |
|||
|
|||
this.clock = clock; |
|||
this.creators = creators.ToList(); |
|||
|
|||
foreach (var creator in this.creators) |
|||
{ |
|||
foreach (var text in creator.Texts) |
|||
{ |
|||
texts[text.Key] = text.Value; |
|||
} |
|||
} |
|||
|
|||
this.repository = repository; |
|||
} |
|||
|
|||
public async Task On(Envelope<IEvent> @event) |
|||
{ |
|||
foreach (var creator in creators) |
|||
{ |
|||
var historyEvent = await creator.CreateEventAsync(@event); |
|||
|
|||
if (historyEvent != null) |
|||
{ |
|||
var appEvent = (AppEvent)@event.Payload; |
|||
|
|||
historyEvent.Actor = appEvent.Actor; |
|||
historyEvent.AppId = appEvent.AppId.Id; |
|||
historyEvent.Created = clock.GetCurrentInstant(); |
|||
historyEvent.Version = @event.Headers.EventStreamNumber(); |
|||
|
|||
await repository.InsertAsync(historyEvent); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public Task ClearAsync() |
|||
{ |
|||
return repository.ClearAsync(); |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<ParsedHistoryEvent>> QueryByChannelAsync(Guid appId, string channelPrefix, int count) |
|||
{ |
|||
var items = await repository.QueryByChannelAsync(appId, channelPrefix, count); |
|||
|
|||
return items.Select(x => new ParsedHistoryEvent(x, texts)).ToList(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,23 +1,18 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using Squidex.Infrastructure; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.History |
|||
{ |
|||
public interface IHistoryEventEntity : IEntity |
|||
public interface IHistoryService |
|||
{ |
|||
Guid EventId { get; } |
|||
|
|||
RefToken Actor { get; } |
|||
|
|||
string Message { get; } |
|||
|
|||
long Version { get; } |
|||
Task<IReadOnlyList<ParsedHistoryEvent>> QueryByChannelAsync(Guid appId, string channelPrefix, int count); |
|||
} |
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using Squidex.Infrastructure.MongoDb; |
|||
|
|||
namespace Squidex.Infrastructure.UsageTracking |
|||
{ |
|||
public sealed class MongoUsageRepository : MongoRepositoryBase<MongoUsage>, IUsageRepository |
|||
{ |
|||
private static readonly BulkWriteOptions Unordered = new BulkWriteOptions { IsOrdered = false }; |
|||
|
|||
public MongoUsageRepository(IMongoDatabase database) |
|||
: base(database) |
|||
{ |
|||
} |
|||
|
|||
protected override string CollectionName() |
|||
{ |
|||
return "UsagesV2"; |
|||
} |
|||
|
|||
protected override Task SetupCollectionAsync(IMongoCollection<MongoUsage> collection, CancellationToken ct = default(CancellationToken)) |
|||
{ |
|||
return collection.Indexes.CreateOneAsync( |
|||
new CreateIndexModel<MongoUsage>(Index.Ascending(x => x.Key).Ascending(x => x.Category).Ascending(x => x.Date)), cancellationToken: ct); |
|||
} |
|||
|
|||
public async Task TrackUsagesAsync(params UsageUpdate[] updates) |
|||
{ |
|||
if (updates.Length == 1) |
|||
{ |
|||
var value = updates[0]; |
|||
|
|||
if (value.Counters.Count > 0) |
|||
{ |
|||
var (filter, update) = CreateOperation(value); |
|||
|
|||
await Collection.UpdateOneAsync(filter, update, Upsert); |
|||
} |
|||
} |
|||
else if (updates.Length > 0) |
|||
{ |
|||
var writes = new List<WriteModel<MongoUsage>>(); |
|||
|
|||
foreach (var value in updates) |
|||
{ |
|||
if (value.Counters.Count > 0) |
|||
{ |
|||
var (filter, update) = CreateOperation(value); |
|||
|
|||
writes.Add(new UpdateOneModel<MongoUsage>(filter, update) { IsUpsert = true }); |
|||
} |
|||
} |
|||
|
|||
await Collection.BulkWriteAsync(writes, Unordered); |
|||
} |
|||
} |
|||
|
|||
private static (FilterDefinition<MongoUsage>, UpdateDefinition<MongoUsage>) CreateOperation(UsageUpdate usageUpdate) |
|||
{ |
|||
var id = $"{usageUpdate.Key}_{usageUpdate.Date:yyyy-MM-dd}_{usageUpdate.Category}"; |
|||
|
|||
var update = Update |
|||
.SetOnInsert(x => x.Id, id) |
|||
.SetOnInsert(x => x.Key, usageUpdate.Key) |
|||
.SetOnInsert(x => x.Date, usageUpdate.Date) |
|||
.SetOnInsert(x => x.Category, usageUpdate.Category); |
|||
|
|||
foreach (var counter in usageUpdate.Counters) |
|||
{ |
|||
update = update.Inc($"Counters.{counter.Key}", counter.Value); |
|||
} |
|||
|
|||
var filter = Filter.Eq(x => x.Id, id); |
|||
|
|||
return (filter, update); |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<StoredUsage>> QueryAsync(string key, DateTime fromDate, DateTime toDate) |
|||
{ |
|||
var entities = await Collection.Find(x => x.Key == key && x.Date >= fromDate && x.Date <= toDate).ToListAsync(); |
|||
|
|||
return entities.Select(x => new StoredUsage(x.Category, x.Date, x.Counters)).ToList(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,58 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using Squidex.Infrastructure.MongoDb; |
|||
|
|||
namespace Squidex.Infrastructure.UsageTracking |
|||
{ |
|||
public sealed class MongoUsageStore : MongoRepositoryBase<MongoUsage>, IUsageStore |
|||
{ |
|||
public MongoUsageStore(IMongoDatabase database) |
|||
: base(database) |
|||
{ |
|||
} |
|||
|
|||
protected override string CollectionName() |
|||
{ |
|||
return "Usages"; |
|||
} |
|||
|
|||
protected override Task SetupCollectionAsync(IMongoCollection<MongoUsage> collection, CancellationToken ct = default(CancellationToken)) |
|||
{ |
|||
return collection.Indexes.CreateOneAsync( |
|||
new CreateIndexModel<MongoUsage>(Index.Ascending(x => x.Key).Ascending(x => x.Category).Ascending(x => x.Date)), cancellationToken: ct); |
|||
} |
|||
|
|||
public Task TrackUsagesAsync(DateTime date, string key, string category, double count, double elapsedMs) |
|||
{ |
|||
var id = $"{key}_{date:yyyy-MM-dd}_{category}"; |
|||
|
|||
return Collection.UpdateOneAsync(x => x.Id == id && x.Category == category, |
|||
Update |
|||
.Inc(x => x.TotalCount, count) |
|||
.Inc(x => x.TotalElapsedMs, elapsedMs) |
|||
.SetOnInsert(x => x.Id, id) |
|||
.SetOnInsert(x => x.Key, key) |
|||
.SetOnInsert(x => x.Date, date) |
|||
.SetOnInsert(x => x.Category, category), |
|||
Upsert); |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<StoredUsage>> QueryAsync(string key, DateTime fromDate, DateTime toDate) |
|||
{ |
|||
var entities = await Collection.Find(x => x.Key == key && x.Date >= fromDate && x.Date <= toDate).ToListAsync(); |
|||
|
|||
return entities.Select(x => new StoredUsage(x.Category, x.Date, (long)x.TotalCount, (long)x.TotalElapsedMs)).ToList(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
|
|||
namespace Squidex.Infrastructure.UsageTracking |
|||
{ |
|||
public sealed class Counters : Dictionary<string, double> |
|||
{ |
|||
public double Get(string name) |
|||
{ |
|||
if (name == null) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
TryGetValue(name, out var value); |
|||
|
|||
return value; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace Squidex.Infrastructure.UsageTracking |
|||
{ |
|||
public struct UsageUpdate |
|||
{ |
|||
public DateTime Date; |
|||
|
|||
public string Key; |
|||
|
|||
public string Category; |
|||
|
|||
public Counters Counters; |
|||
|
|||
public UsageUpdate(DateTime date, string key, string category, Counters counters) |
|||
{ |
|||
Key = key; |
|||
Category = category; |
|||
Counters = counters; |
|||
Date = date; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue