// Copyright Epic Games, Inc. All Rights Reserved. using System.Collections.Generic; using System.Threading.Tasks; using Horde.Build.Acls; using Horde.Build.Api; using Horde.Build.Collections; using Horde.Build.Models; using Horde.Build.Services; using Horde.Build.Utilities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using MongoDB.Bson; namespace Horde.Build.Controllers { using JobId = ObjectId; using StreamId = StringId; /// /// Controller for the /api/v1/testdata endpoint /// [ApiController] [Authorize] [Route("[controller]")] public class TestDataController : ControllerBase { /// /// Collection of job documents /// private readonly JobService _jobService; /// /// Collection of test data documents /// private readonly ITestDataCollection _testDataCollection; /// /// Constructor /// /// The job service singleton /// Collection of test data documents public TestDataController(JobService jobService, ITestDataCollection testDataCollection) { _jobService = jobService; _testDataCollection = testDataCollection; } /// /// Creates a new TestData document /// /// The stream document [HttpPost] [Route("/api/v1/testdata")] public async Task> CreateAsync(CreateTestDataRequest request) { IJob? job = await _jobService.GetJobAsync(new JobId(request.JobId)); if (job == null) { return NotFound(); } if (!await _jobService.AuthorizeAsync(job, AclAction.UpdateJob, User, null)) { return Forbid(); } IJobStep? jobStep; if (!job.TryGetStep(request.StepId.ToSubResourceId(), out jobStep)) { return NotFound(); } ITestData testData = await _testDataCollection.AddAsync(job, jobStep, request.Key, new BsonDocument(request.Data)); return new CreateTestDataResponse(testData.Id.ToString()); } /// /// Searches for test data that matches a set of criteria /// /// The stream id /// The minimum changelist number to return (inclusive) /// The maximum changelist number to return (inclusive) /// The job id /// The unique step id /// Key identifying the result to return /// Offset within the results to return /// Number of results to return /// Filter for properties to return /// The stream document [HttpGet] [Route("/api/v1/testdata")] [ProducesResponseType(typeof(List), 200)] public async Task>> FindTestDataAsync([FromQuery] string? streamId = null, [FromQuery] int? minChange = null, [FromQuery] int? maxChange = null, string? jobId = null, string? jobStepId = null, string? key = null, int index = 0, int count = 10, PropertyFilter? filter = null) { StreamId? streamIdValue = null; if(streamId != null) { streamIdValue = new StreamId(streamId); } JobPermissionsCache cache = new JobPermissionsCache(); List results = new List(); List documents = await _testDataCollection.FindAsync(streamIdValue, minChange, maxChange, jobId?.ToObjectId(), jobStepId?.ToSubResourceId(), key, index, count); foreach (ITestData document in documents) { if (await _jobService.AuthorizeAsync(document.JobId, AclAction.ViewJob, User, cache)) { results.Add(PropertyFilter.Apply(new GetTestDataResponse(document), filter)); } } return results; } /// /// Retrieve information about a specific issue /// /// Id of the document to get information about /// Filter for the properties to return /// List of matching agents [HttpGet] [Route("/api/v1/testdata/{testDataId}")] [ProducesResponseType(typeof(GetTestDataResponse), 200)] public async Task> GetTestDataAsync(string testDataId, [FromQuery] PropertyFilter? filter = null) { ITestData? testData = await _testDataCollection.GetAsync(testDataId.ToObjectId()); if (testData == null) { return NotFound(); } if (!await _jobService.AuthorizeAsync(testData.JobId, AclAction.ViewJob, User, null)) { return Forbid(); } return PropertyFilter.Apply(new GetTestDataResponse(testData), filter); } } }