// Copyright Epic Games, Inc. All Rights Reserved. using HordeServer.Models; using HordeServer.Services; using HordeServer.Utilities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using MongoDB.Bson; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; using TimeZoneConverter; namespace HordeServer.Controllers { /// /// Controller for the /api/v1/status endpoint /// [ApiController] [Authorize] [Route("[controller]")] public class NoticesController : ControllerBase { /// /// Timezone to use for display notices /// TimeZoneInfo TimeZone; /// /// The globals singleton /// ISingletonDocument Globals; /// /// Constructor /// /// The server settings /// The globals singleton public NoticesController(IOptions Settings, ISingletonDocument Globals) { string? ScheduleTimeZone = Settings.Value.ScheduleTimeZone; this.TimeZone = (ScheduleTimeZone == null) ? TimeZoneInfo.Local : TZConvert.GetTimeZoneInfo(ScheduleTimeZone); this.Globals = Globals; } /// /// Update a status message /// /// /// [HttpPost("/api/v1/notices")] public async Task AddNoticeAsync(Notice Status) { Status.Id = ObjectId.GenerateNewId().ToString(); await Globals.UpdateAsync(x => x.Notices.Add(Status)); return Ok(); } /// /// Remove a manually added status message /// /// [HttpDelete("/api/v1/notices/{Id}")] public async Task DeleteNoticeAsync(string Id) { await Globals.UpdateAsync(x => x.Notices.RemoveAll(x => x.Id == Id)); return Ok(); } /// /// Gets the current status messages /// /// The status messages [HttpGet("/api/v1/notices")] public async Task> GetNoticesAsync() { Globals Value = await Globals.GetAsync(); List Messages = new List(Value.Notices); if(Value.ScheduledDowntime.Count > 0) { DateTimeOffset Now = DateTimeOffset.Now; (DateTimeOffset StartTime, DateTimeOffset FinishTime) = Value.ScheduledDowntime[0].GetNext(Now); for (int Idx = 1; Idx < Value.ScheduledDowntime.Count; Idx++) { (DateTimeOffset NextStartTime, DateTimeOffset NextFinishTime) = Value.ScheduledDowntime[Idx].GetNext(Now); if (NextFinishTime < StartTime) { StartTime = NextStartTime; } if (NextStartTime < FinishTime && NextFinishTime > FinishTime) { FinishTime = NextFinishTime; } } if (StartTime < Now) { string FinishTimeString = String.Format(CultureInfo.CurrentCulture, "{0:t}", TimeZoneInfo.ConvertTime(FinishTime, TimeZone)); Messages.Add(new Notice { StartTime = StartTime.UtcDateTime, FinishTime = FinishTime.UtcDateTime, Message = $"Horde is currently in scheduled downtime. Jobs will resume execution at {FinishTimeString} {TimeZone.Id}." }); } else if(StartTime < Now + TimeSpan.FromHours(12.0)) { string StartTimeString = String.Format(CultureInfo.CurrentCulture, "{0:t}", StartTime); string FinishTimeString = String.Format(CultureInfo.CurrentCulture, "{0:t}", FinishTime); Messages.Add(new Notice { StartTime = StartTime.UtcDateTime, FinishTime = FinishTime.UtcDateTime, Message = $"Downtime is scheduled from {StartTimeString} to {FinishTimeString} {TimeZone.Id}. No jobs will run during this time." }); } } return Messages; } } }