// Copyright Epic Games, Inc. All Rights Reserved.
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using EpicGames.Horde.Jobs;
using EpicGames.Horde.Jobs.Bisect;
using EpicGames.Horde.Users;
using HordeServer.Accounts;
using HordeServer.Acls;
using HordeServer.Plugins;
using HordeServer.Server;
using HordeServer.Server.Notices;
using HordeServer.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace HordeServer.Users
{
///
/// Controller for the /api/v1/user endpoint
///
[ApiController]
[Authorize]
[Route("[controller]")]
public class UserController : ControllerBase
{
readonly IUserCollection _userCollection;
readonly IAvatarService? _avatarService;
readonly IEnumerable _responseFilters;
readonly IOptionsSnapshot _globalConfig;
readonly IOptionsMonitor _settings;
///
/// Constructor
///
public UserController(IUserCollection userCollection, IAvatarService? avatarService, IEnumerable responseFilters, IOptionsSnapshot globalConfig, IOptionsMonitor settings)
{
_userCollection = userCollection;
_avatarService = avatarService;
_responseFilters = responseFilters;
_globalConfig = globalConfig;
_settings = settings;
}
///
/// Gets information about the logged in user
///
/// Http result code
[HttpGet]
[Route("/api/v1/user")]
[ProducesResponseType(typeof(GetUserResponse), 200)]
public async Task> GetUserAsync([FromQuery] PropertyFilter? filter = null, CancellationToken cancellationToken = default)
{
IUser? internalUser = await _userCollection.GetUserAsync(User, cancellationToken);
if (internalUser == null)
{
return NotFound();
}
IAvatar? avatar = (_avatarService == null) ? (IAvatar?)null : await _avatarService.GetAvatarAsync(internalUser, cancellationToken);
IUserClaims claims = await _userCollection.GetClaimsAsync(internalUser.Id, cancellationToken);
IUserSettings settings = await _userCollection.GetSettingsAsync(internalUser.Id, cancellationToken);
GetUserResponse response = internalUser.ToApiResponse(avatar, claims, settings);
response.DashboardFeatures = GetDashboardFeatures(_globalConfig.Value, _settings.CurrentValue, User);
return PropertyFilter.Apply(response, filter);
}
GetDashboardFeaturesResponse GetDashboardFeatures(GlobalConfig globalConfig, ServerSettings settings, ClaimsPrincipal principal)
{
GetDashboardFeaturesResponse response = new GetDashboardFeaturesResponse();
response.ShowLandingPage = globalConfig.Dashboard.ShowLandingPage;
response.LandingPageRoute = globalConfig.Dashboard.LandingPageRoute;
response.ShowCI = globalConfig.Dashboard.ShowCI;
response.ShowAgents = globalConfig.Dashboard.ShowAgents;
response.ShowAgentRegistration = globalConfig.Dashboard.ShowAgentRegistration;
response.ShowPerforceServers = globalConfig.Dashboard.ShowPerforceServers;
response.ShowDeviceManager = globalConfig.Dashboard.ShowDeviceManager;
response.ShowTests = globalConfig.Dashboard.ShowTests;
response.ShowNoticeEditor = globalConfig.Authorize(NoticeAclAction.CreateNotice, principal) || globalConfig.Authorize(NoticeAclAction.UpdateNotice, principal);
response.ShowAccounts = settings.AuthMethod == EpicGames.Horde.Server.AuthMethod.Horde && globalConfig.Authorize(AccountAclAction.UpdateAccount, principal);
foreach (IPluginResponseFilter responseFilter in _responseFilters)
{
responseFilter.Apply(HttpContext, response);
}
return response;
}
///
/// Updates the logged in user
///
/// Http result code
[HttpPut]
[Route("/api/v1/user")]
public async Task UpdateUserAsync(UpdateUserRequest request)
{
UserId? userId = User.GetUserId();
if (userId == null)
{
return BadRequest("Current user does not have a registered profile");
}
await _userCollection.UpdateSettingsAsync(userId.Value, request.EnableExperimentalFeatures, request.AlwaysTagPreflightCL, request.DashboardSettings?.ToBsonValue(), request.AddPinnedJobIds?.Select(x => JobId.Parse(x)), request.RemovePinnedJobIds?.Select(x => JobId.Parse(x)), null, request.AddPinnedBisectTaskIds?.Select(x => BisectTaskId.Parse(x)), request.RemovePinnedBisectTaskIds?.Select(x => BisectTaskId.Parse(x)));
return Ok();
}
///
/// Gets claims for the current user
///
[HttpGet]
[Route("/api/v1/user/claims")]
public ActionResult