// Copyright Epic Games, Inc. All Rights Reserved. using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using Horde.Build.Acls; using Horde.Build.Streams; using Horde.Build.Utilities; using MongoDB.Driver; namespace Horde.Build.Projects { using ProjectId = StringId; /// /// Represents a project /// public interface IProject { /// /// Identifier for the project. /// ProjectId Id { get; } /// /// Name of the project /// string Name { get; } /// /// Revision of the config file used to configure this project /// string? ConfigRevision { get; } /// /// Order to display on the dashboard /// public int Order { get; } /// /// Configuration settings for the stream /// ProjectConfig Config { get; } /// /// The ACL for this object /// Acl? Acl { get; } } /// /// Interface for a document containing a project logo /// public interface IProjectLogo { /// /// The project id /// public ProjectId Id { get; } /// /// Path to the logo /// public string Path { get; } /// /// Revision of the file /// public string Revision { get; } /// /// Mime type for the image /// public string MimeType { get; } /// /// Image data /// public byte[] Data { get; } } /// /// Extension methods for projects /// public static class ProjectExtensions { /// /// Converts this object to a public response /// /// The project instance /// Whether to include streams in the response /// Whether to include categories in the response /// The list of streams /// Whether to include the ACL in the response /// Response instance public static GetProjectResponse ToResponse(this IProject project, bool includeStreams, bool includeCategories, List? streams, bool includeAcl) { List? streamResponses = null; if(includeStreams) { streamResponses = streams!.ConvertAll(x => new GetProjectStreamResponse(x.Id.ToString(), x.Name)); } List? categoryResponses = null; if (includeCategories) { categoryResponses = project.Config.Categories.ConvertAll(x => new GetProjectCategoryResponse(x)); if (streams != null) { foreach (IStream stream in streams) { GetProjectCategoryResponse? categoryResponse = categoryResponses.FirstOrDefault(x => MatchCategory(stream.Name, x)); if(categoryResponse == null) { int row = (categoryResponses.Count > 0) ? categoryResponses.Max(x => x.Row) : 0; if (categoryResponses.Count(x => x.Row == row) >= 3) { row++; } ProjectCategoryConfig otherCategory = new ProjectCategoryConfig(); otherCategory.Name = "Other"; otherCategory.Row = row; otherCategory.IncludePatterns.Add(".*"); categoryResponse = new GetProjectCategoryResponse(otherCategory); categoryResponses.Add(categoryResponse); } categoryResponse.Streams!.Add(stream.Id.ToString()); } } } GetAclResponse? aclResponse = (includeAcl && project.Acl != null) ? new GetAclResponse(project.Acl) : null; return new GetProjectResponse(project.Id.ToString(), project.Name, project.Order, streamResponses, categoryResponses, aclResponse); } /// /// Tests if a category response matches a given stream name /// /// The stream name /// The category response /// True if the category matches static bool MatchCategory(string name, GetProjectCategoryResponse category) { if (category.IncludePatterns.Any(x => Regex.IsMatch(name, x))) { if (!category.ExcludePatterns.Any(x => Regex.IsMatch(name, x))) { return true; } } return false; } } /// /// Projection of a project definition to just include permissions info /// public interface IProjectPermissions { /// /// ACL for the project /// public Acl? Acl { get; } } }