// Copyright Epic Games, Inc. All Rights Reserved.
using HordeServer.Api;
using HordeServer.Collections;
using HordeServer.Models;
using HordeServer.Services;
using HordeServer.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace HordeServer.Controllers
{
///
/// Controller for the /api/v1/agents endpoint
///
[ApiController]
[Authorize]
[Route("[controller]")]
public class SubscriptionsController : ControllerBase
{
///
/// The ACL service singleton
///
AclService AclService;
///
/// Collection of subscription documents
///
ISubscriptionCollection SubscriptionCollection;
///
/// Constructor
///
/// The acl service singleton
/// The collection of subscription documents
public SubscriptionsController(AclService AclService, ISubscriptionCollection SubscriptionCollection)
{
this.AclService = AclService;
this.SubscriptionCollection = SubscriptionCollection;
}
///
/// Find subscriptions matching a criteria
///
/// Name of the user
/// Filter for properties to return
/// List of subscriptions
[HttpGet]
[Route("/api/v1/subscriptions")]
[ProducesResponseType(typeof(List), 200)]
public async Task>> GetSubscriptionsAsync([FromQuery] string UserId, [FromQuery] PropertyFilter? Filter = null)
{
ObjectId UserIdValue;
if (!TryParseUserId(UserId, out UserIdValue))
{
return BadRequest("Invalid user id");
}
if (!await AclService.AuthorizeAsUserAsync(User, UserIdValue))
{
return Forbid();
}
List Results = await SubscriptionCollection.FindSubscriptionsAsync(UserIdValue);
return Results.ConvertAll(x => PropertyFilter.Apply(new GetSubscriptionResponse(x), Filter));
}
///
/// Find subscriptions matching a criteria
///
/// The subscription id
/// Filter for properties to return
/// List of subscriptions
[HttpGet]
[Route("/api/v1/subscriptions/{SubscriptionId}")]
[ProducesResponseType(typeof(GetSubscriptionResponse), 200)]
public async Task> GetSubscriptionAsync(string SubscriptionId, [FromQuery] PropertyFilter? Filter = null)
{
ISubscription? Subscription = await SubscriptionCollection.GetAsync(SubscriptionId);
if (Subscription == null)
{
return NotFound();
}
if (!await AclService.AuthorizeAsUserAsync(User, Subscription.UserId))
{
return Forbid();
}
return PropertyFilter.Apply(new GetSubscriptionResponse(Subscription), Filter);
}
///
/// Remove a subscription
///
/// The subscription id
/// Async task
[HttpDelete]
[Route("/api/v1/subscriptions/{SubscriptionId}")]
[ProducesResponseType(typeof(List), 200)]
public async Task DeleteSubscriptionAsync(string SubscriptionId)
{
ISubscription? Subscription = await SubscriptionCollection.GetAsync(SubscriptionId);
if (Subscription == null)
{
return NotFound();
}
if (!await AclService.AuthorizeAsUserAsync(User, Subscription.UserId))
{
return Forbid();
}
await SubscriptionCollection.RemoveAsync(new[] { Subscription });
return Ok();
}
///
/// Find subscriptions matching a criteria
///
/// The new subscriptions to create
/// List of subscriptions
[HttpPost]
[Route("/api/v1/subscriptions")]
public async Task>> CreateSubscriptionsAsync(List Subscriptions)
{
HashSet AuthorizedUsers = new HashSet();
ObjectId? CurrentUserId = User.GetUserId();
if(CurrentUserId != null)
{
AuthorizedUsers.Add(CurrentUserId.Value);
}
GlobalPermissionsCache Cache = new GlobalPermissionsCache();
List NewSubscriptions = new List();
foreach (CreateSubscriptionRequest Subscription in Subscriptions)
{
ObjectId NewUserId;
if (!TryParseUserId(Subscription.UserId, out NewUserId))
{
return BadRequest($"Invalid user id: '{Subscription.UserId}'.");
}
if (AuthorizedUsers.Add(NewUserId) && !await AclService.AuthorizeAsync(AclAction.Impersonate, User, Cache))
{
return Forbid();
}
NewSubscriptions.Add(new NewSubscription(Subscription.Event, NewUserId, Subscription.NotificationType));
}
List Results = await SubscriptionCollection.AddAsync(NewSubscriptions);
return Results.ConvertAll(x => new CreateSubscriptionResponse(x));
}
///
/// Parse a user id from a string. Allows passing the user's name as well as their objectid value.
///
///
///
///
bool TryParseUserId(string UserName, out ObjectId ObjectId)
{
ObjectId NewObjectId;
if (ObjectId.TryParse(UserName, out NewObjectId))
{
ObjectId = NewObjectId;
return true;
}
string? CurrentUserName = User.GetUserName();
if (CurrentUserName != null && String.Equals(UserName, CurrentUserName, StringComparison.OrdinalIgnoreCase))
{
ObjectId? CurrentUserId = User.GetUserId();
if (CurrentUserId != null)
{
ObjectId = CurrentUserId.Value;
return true;
}
}
ObjectId = default;
return false;
}
}
}