Files
UnrealEngine/Engine/Source/Programs/Horde/HordeServer/Dashboard/DashboardPreviewCollection.cs
2025-05-18 13:04:45 +08:00

236 lines
6.7 KiB
C#

// 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
{
/// <summary>
///
/// </summary>
public interface IDashboardPreview
{
/// <summary>
/// The unique ID of the preview item
/// </summary>
public int Id { get; }
/// <summary>
/// When the preview item was created
/// </summary>
public DateTime CreatedAt { get; }
/// <summary>
/// A summary of what the preview item changes
/// </summary>
public string Summary { get; }
/// <summary>
/// The CL the preview was deployed in
/// </summary>
public int? DeployedCL { get; }
/// <summary>
/// Whather the preview is under consideration, if false the preview item didn't pass muster
/// </summary>
public bool Open { get; }
/// <summary>
/// An example of the preview site users can view the changes
/// </summary>
public string? ExampleLink { get; }
/// <summary>
/// Optional Link for discussion the preview item
/// </summary>
public string? DiscussionLink { get; }
/// <summary>
/// Optional Link for discussing the preview item
/// </summary>
public string? TrackingLink { get; }
}
/// <summary>
/// Collection of preview documents
/// </summary>
public interface IDashboardPreviewCollection
{
/// <summary>
/// Add a preview item
/// </summary>
/// <param name="summary"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IDashboardPreview> AddPreviewAsync(string summary, CancellationToken cancellationToken);
/// <summary>
/// Update a dashboard preview item
/// </summary>
/// <param name="previewId"></param>
/// <param name="summary"></param>
/// <param name="deployedCL"></param>
/// <param name="open"></param>
/// <param name="exampleLink"></param>
/// <param name="discussionLink"></param>
/// <param name="trackingLink"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IDashboardPreview?> UpdatePreviewAsync(int previewId, string? summary = null, int? deployedCL = null, bool? open = null, string? exampleLink = null, string? discussionLink = null, string? trackingLink = null, CancellationToken cancellationToken = default);
/// <summary>
/// Finds preview items with the given criterial
/// </summary>
/// <param name="open"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<List<IDashboardPreview>> 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<PreviewDocument> _previews;
readonly ISingletonDocument<PreviewLedger> _ledgerSingleton;
public DashboardPreviewCollection(IMongoService mongoService)
{
_ledgerSingleton = new SingletonDocument<PreviewLedger>(mongoService);
_previews = mongoService.GetCollection<PreviewDocument>("DashboardPreviews");
}
public async Task<IDashboardPreview> 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<IDashboardPreview> 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<IDashboardPreview?> 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<PreviewDocument> updateBuilder = Builders<PreviewDocument>.Update;
List<UpdateDefinition<PreviewDocument>> updates = new List<UpdateDefinition<PreviewDocument>>();
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<List<IDashboardPreview>> FindPreviewsAsync(bool? open = null, CancellationToken cancellationToken = default)
{
FilterDefinition<PreviewDocument> filter = Builders<PreviewDocument>.Filter.Empty;
if (open != null)
{
filter &= Builders<PreviewDocument>.Filter.Eq(x => x.Open, open);
}
List<PreviewDocument> results = await _previews.Find(filter).ToListAsync(cancellationToken);
return results.Select<PreviewDocument, IDashboardPreview>(x => x).ToList();
}
}
}