// Copyright Epic Games, Inc. All Rights Reserved. using System.Collections.Generic; using System.Threading.Tasks; using Horde.Build.Acls; using Horde.Build.Streams; using Horde.Build.Utilities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Horde.Build.Projects { using ProjectId = StringId; /// /// Controller for the /api/v1/projects endpoint /// [ApiController] [Authorize] [Route("[controller]")] public class ProjectsController : HordeControllerBase { /// /// Singleton instance of the project service /// private readonly ProjectService _projectService; /// /// Singleton instance of the stream service /// private readonly StreamService _streamService; /// /// Constructor /// /// The project service /// The stream service public ProjectsController(ProjectService projectService, StreamService streamService) { _projectService = projectService; _streamService = streamService; } /// /// Query all the projects /// /// Whether to include streams in the response /// Whether to include categories in the response /// Filter for the properties to return /// Information about all the projects [HttpGet] [Route("/api/v1/projects")] [ProducesResponseType(typeof(List), 200)] public async Task>> GetProjectsAsync([FromQuery(Name = "Streams")] bool includeStreams = false, [FromQuery(Name = "Categories")] bool includeCategories = false, [FromQuery] PropertyFilter? filter = null) { List projects = await _projectService.GetProjectsAsync(); ProjectPermissionsCache permissionsCache = new ProjectPermissionsCache(); List? streams = null; if (includeStreams || includeCategories) { streams = await _streamService.GetStreamsAsync(); } List responses = new List(); foreach (IProject project in projects) { if (await _projectService.AuthorizeAsync(project, AclAction.ViewProject, User, permissionsCache)) { bool bIncludeAcl = await _projectService.AuthorizeAsync(project, AclAction.ViewPermissions, User, permissionsCache); responses.Add(project.ToResponse(includeStreams, includeCategories, streams, bIncludeAcl).ApplyFilter(filter)); } } return responses; } /// /// Retrieve information about a specific project /// /// Id of the project to get information about /// Filter for the properties to return /// Information about the requested project [HttpGet] [Route("/api/v1/projects/{projectId}")] [ProducesResponseType(typeof(List), 200)] public async Task> GetProjectAsync(ProjectId projectId, [FromQuery] PropertyFilter? filter = null) { IProject? project = await _projectService.GetProjectAsync(projectId); if (project == null) { return NotFound(projectId); } ProjectPermissionsCache cache = new ProjectPermissionsCache(); if (!await _projectService.AuthorizeAsync(project, AclAction.ViewProject, User, cache)) { return Forbid(AclAction.ViewProject, projectId); } bool bIncludeStreams = PropertyFilter.Includes(filter, nameof(GetProjectResponse.Streams)); bool bIncludeCategories = PropertyFilter.Includes(filter, nameof(GetProjectResponse.Categories)); List? visibleStreams = null; if (bIncludeStreams || bIncludeCategories) { visibleStreams = new List(); List streams = await _streamService.GetStreamsAsync(project.Id); foreach (IStream stream in streams) { if (await _streamService.AuthorizeAsync(stream, AclAction.ViewStream, User, cache)) { visibleStreams.Add(stream); } } } bool bIncludeAcl = await _projectService.AuthorizeAsync(project, AclAction.ViewPermissions, User, cache); return project.ToResponse(bIncludeStreams, bIncludeCategories, visibleStreams, bIncludeAcl).ApplyFilter(filter); } /// /// Retrieve information about a specific project /// /// Id of the project to get information about /// Information about the requested project [HttpGet] [Route("/api/v1/projects/{projectId}/logo")] public async Task> GetProjectLogoAsync(ProjectId projectId) { IProject? project = await _projectService.GetProjectAsync(projectId); if (project == null) { return NotFound(projectId); } if (!await _projectService.AuthorizeAsync(project, AclAction.ViewProject, User, null)) { return Forbid(AclAction.ViewProject, projectId); } IProjectLogo? projectLogo = await _projectService.Collection.GetLogoAsync(projectId); if (projectLogo == null) { return NotFound(); } return new FileContentResult(projectLogo.Data, projectLogo.MimeType); } } }