// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using EpicGames.Horde.Users; using HordeServer.Utilities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace HordeServer.Users { /// /// Controller for the /api/v1/users endpoint /// [ApiController] [Authorize] [Route("[controller]")] public class UsersController : HordeControllerBase { /// /// The user collection instance /// IUserCollection UserCollection { get; set; } /// /// The avatar service /// IAvatarService? AvatarService { get; set; } /// /// Constructor /// /// /// public UsersController(IUserCollection userCollection, IAvatarService? avatarService) { UserCollection = userCollection; AvatarService = avatarService; } /// /// Gets information about a user by id, specify "current" for id to get the currently logged in user /// /// Http result code [HttpGet] [Route("/api/v1/users/{id}")] [ProducesResponseType(typeof(List), 200)] public async Task> GetUserAsync(string id, [FromQuery] PropertyFilter? filter = null, CancellationToken cancellationToken = default) { UserId? userId = ParseUserId(id); if (userId == null) { return BadRequest("Invalid user id '{Id}'", id); } IUser? user = await UserCollection.GetUserAsync(userId.Value, cancellationToken); if (user == null) { return NotFound(userId.Value); } IAvatar? avatar = (AvatarService == null) ? (IAvatar?)null : await AvatarService.GetAvatarAsync(user, cancellationToken); IUserClaims? claims = await UserCollection.GetClaimsAsync(user.Id, cancellationToken); IUserSettings? settings = await UserCollection.GetSettingsAsync(user.Id, cancellationToken); return PropertyFilter.Apply(user.ToApiResponse(avatar, claims, settings), filter); } /// /// Gets a list of users /// /// List of user responses [HttpGet] [Route("/api/v1/users")] [ProducesResponseType(typeof(List), 200)] public async Task>> FindUsersAsync( [FromQuery] string[]? ids = null, [FromQuery] string? nameRegex = null, [FromQuery] int index = 0, [FromQuery] int count = 100, [FromQuery] bool includeClaims = false, [FromQuery] bool includeAvatar = false, CancellationToken cancellationToken = default) { UserId[]? userIds = null; if (ids != null && ids.Length > 0) { userIds = ids.Select(x => UserId.Parse(x)).ToArray(); } IReadOnlyList users = await UserCollection.FindUsersAsync(userIds, nameRegex, index, count, cancellationToken); List response = new List(); foreach (IUser user in users) { IAvatar? avatar = (AvatarService == null || !includeAvatar) ? (IAvatar?)null : await AvatarService.GetAvatarAsync(user, cancellationToken); IUserClaims? claims = (!includeClaims) ? null : await UserCollection.GetClaimsAsync(user.Id, cancellationToken); response.Add(user.ToApiResponse(avatar, claims, null)); } return response; } UserId? ParseUserId(string id) { if (id.Equals("current", StringComparison.OrdinalIgnoreCase)) { return User.GetUserId(); } else if (UserId.TryParse(id, out UserId result)) { return result; } return null; } } }