// Copyright Epic Games, Inc. All Rights Reserved. using HordeServer.Api; using HordeServer.Collections; using HordeCommon; using HordeServer.Models; using HordeServer.Services; using HordeServer.Utilities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Server.Kestrel.Core.Features; using MongoDB.Bson; using MongoDB.Bson.Serialization; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; using System.Threading.Tasks; namespace HordeServer.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 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) { this.JobService = JobService; this.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); } } }