// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HordeServer.Server;
using HordeServer.Utilities;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
namespace HordeServer.Dashboard
{
///
///
///
public interface IDashboardPreview
{
///
/// The unique ID of the preview item
///
public int Id { get; }
///
/// When the preview item was created
///
public DateTime CreatedAt { get; }
///
/// A summary of what the preview item changes
///
public string Summary { get; }
///
/// The CL the preview was deployed in
///
public int? DeployedCL { get; }
///
/// Whather the preview is under consideration, if false the preview item didn't pass muster
///
public bool Open { get; }
///
/// An example of the preview site users can view the changes
///
public string? ExampleLink { get; }
///
/// Optional Link for discussion the preview item
///
public string? DiscussionLink { get; }
///
/// Optional Link for discussing the preview item
///
public string? TrackingLink { get; }
}
///
/// Collection of preview documents
///
public interface IDashboardPreviewCollection
{
///
/// Add a preview item
///
///
///
///
Task AddPreviewAsync(string summary, CancellationToken cancellationToken);
///
/// Update a dashboard preview item
///
///
///
///
///
///
///
///
///
///
Task UpdatePreviewAsync(int previewId, string? summary = null, int? deployedCL = null, bool? open = null, string? exampleLink = null, string? discussionLink = null, string? trackingLink = null, CancellationToken cancellationToken = default);
///
/// Finds preview items with the given criterial
///
///
///
///
Task> FindPreviewsAsync(bool? open = null, CancellationToken cancellationToken = default);
}
internal class DashboardPreviewCollection : IDashboardPreviewCollection
{
[SingletonDocument("dashboard-preview-ledger", "63f8e2154a2e859581b5bb24")]
internal class PreviewLedger : SingletonBase
{
public int NextId { get; set; }
}
internal class PreviewDocument : IDashboardPreview
{
[BsonId]
public int Id { get; set; }
public DateTime CreatedAt { get; set; }
public string Summary { get; set; }
public bool Open { get; set; }
[BsonIgnoreIfNull]
public int? DeployedCL { get; set; }
[BsonIgnoreIfNull]
public string? ExampleLink { get; set; }
[BsonIgnoreIfNull]
public string? DiscussionLink { get; set; }
[BsonIgnoreIfNull]
public string? TrackingLink { get; set; }
[BsonConstructor]
private PreviewDocument()
{
Summary = String.Empty;
}
public PreviewDocument(int id, string summary)
{
Id = id;
Summary = summary;
CreatedAt = DateTime.UtcNow;
Open = true;
}
}
readonly IMongoCollection _previews;
readonly ISingletonDocument _ledgerSingleton;
public DashboardPreviewCollection(IMongoService mongoService)
{
_ledgerSingleton = new SingletonDocument(mongoService);
_previews = mongoService.GetCollection("DashboardPreviews");
}
public async Task AddPreviewAsync(string summary, CancellationToken cancellationToken)
{
PreviewLedger ledger = await _ledgerSingleton.UpdateAsync(x => x.NextId++, cancellationToken);
PreviewDocument newPreview = new PreviewDocument(ledger.NextId, summary);
await _previews.InsertOneAsync(newPreview, (InsertOneOptions?)null, cancellationToken);
return newPreview;
}
public async Task UpdatePreviewAsync(string summary, CancellationToken cancellationToken)
{
PreviewLedger ledger = await _ledgerSingleton.UpdateAsync(x => x.NextId++, cancellationToken);
PreviewDocument newPreview = new PreviewDocument(ledger.NextId, summary);
await _previews.InsertOneAsync(newPreview, (InsertOneOptions?)null, cancellationToken);
return newPreview;
}
public async Task UpdatePreviewAsync(int previewId, string? summary = null, int? deployedCL = null, bool? open = null, string? exampleLink = null, string? discussionLink = null, string? trackingLink = null, CancellationToken cancellationToken = default)
{
UpdateDefinitionBuilder updateBuilder = Builders.Update;
List> updates = new List>();
if (summary != null)
{
updates.Add(updateBuilder.Set(x => x.Summary, summary));
}
if (deployedCL != null)
{
updates.Add(updateBuilder.Set(x => x.DeployedCL, deployedCL));
}
if (open != null)
{
updates.Add(updateBuilder.Set(x => x.Open, open));
}
if (exampleLink != null)
{
updates.Add(updateBuilder.Set(x => x.ExampleLink, exampleLink));
}
if (discussionLink != null)
{
updates.Add(updateBuilder.Set(x => x.DiscussionLink, discussionLink));
}
if (trackingLink != null)
{
updates.Add(updateBuilder.Set(x => x.TrackingLink, trackingLink));
}
if (updates.Count == 0)
{
await _previews.Find(x => x.Id == previewId).FirstOrDefaultAsync(cancellationToken);
}
if (await _previews.FindOneAndUpdateAsync(x => x.Id == previewId, updateBuilder.Combine(updates), null, cancellationToken) == null)
{
return null;
}
return await _previews.Find(x => x.Id == previewId).FirstOrDefaultAsync(cancellationToken);
}
public async Task> FindPreviewsAsync(bool? open = null, CancellationToken cancellationToken = default)
{
FilterDefinition filter = Builders.Filter.Empty;
if (open != null)
{
filter &= Builders.Filter.Eq(x => x.Open, open);
}
List results = await _previews.Find(filter).ToListAsync(cancellationToken);
return results.Select(x => x).ToList();
}
}
}