2020-06-12 18:54:25 +02:00
#pragma warning disable CA1801
using System ;
using System.Collections.Generic ;
using System.ComponentModel.DataAnnotations ;
using System.Linq ;
using System.Threading ;
2020-06-22 15:44:11 +02:00
using Jellyfin.Api.Constants ;
2020-06-12 18:54:25 +02:00
using Jellyfin.Api.Helpers ;
2020-06-19 13:03:53 +02:00
using Jellyfin.Data.Enums ;
2020-06-12 18:54:25 +02:00
using MediaBrowser.Controller.Devices ;
using MediaBrowser.Controller.Library ;
using MediaBrowser.Controller.Net ;
using MediaBrowser.Controller.Session ;
using MediaBrowser.Model.Dto ;
using MediaBrowser.Model.Session ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Http ;
using Microsoft.AspNetCore.Mvc ;
namespace Jellyfin.Api.Controllers
{
/// <summary>
/// The session controller.
/// </summary>
2020-08-04 20:48:53 +02:00
[Route("")]
2020-06-12 18:54:25 +02:00
public class SessionController : BaseJellyfinApiController
{
private readonly ISessionManager _sessionManager ;
private readonly IUserManager _userManager ;
private readonly IAuthorizationContext _authContext ;
private readonly IDeviceManager _deviceManager ;
/// <summary>
/// Initializes a new instance of the <see cref="SessionController"/> class.
/// </summary>
/// <param name="sessionManager">Instance of <see cref="ISessionManager"/> interface.</param>
/// <param name="userManager">Instance of <see cref="IUserManager"/> interface.</param>
/// <param name="authContext">Instance of <see cref="IAuthorizationContext"/> interface.</param>
/// <param name="deviceManager">Instance of <see cref="IDeviceManager"/> interface.</param>
public SessionController (
ISessionManager sessionManager ,
IUserManager userManager ,
IAuthorizationContext authContext ,
2020-06-19 13:03:53 +02:00
IDeviceManager deviceManager )
2020-06-12 18:54:25 +02:00
{
_sessionManager = sessionManager ;
_userManager = userManager ;
_authContext = authContext ;
_deviceManager = deviceManager ;
}
/// <summary>
/// Gets a list of sessions.
/// </summary>
/// <param name="controllableByUserId">Filter by sessions that a given user is allowed to remote control.</param>
/// <param name="deviceId">Filter by device Id.</param>
/// <param name="activeWithinSeconds">Optional. Filter by sessions that were active in the last n seconds.</param>
/// <response code="200">List of sessions returned.</response>
/// <returns>An <see cref="IEnumerable{SessionInfo}"/> with the available sessions.</returns>
2020-08-04 20:48:53 +02:00
[HttpGet("Sessions")]
2020-06-22 15:44:11 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult < IEnumerable < SessionInfo > > GetSessions (
2020-07-07 17:10:51 +02:00
[FromQuery] Guid ? controllableByUserId ,
2020-06-27 18:50:44 +02:00
[FromQuery] string? deviceId ,
2020-06-12 18:54:25 +02:00
[FromQuery] int? activeWithinSeconds )
{
var result = _sessionManager . Sessions ;
if ( ! string . IsNullOrEmpty ( deviceId ) )
{
result = result . Where ( i = > string . Equals ( i . DeviceId , deviceId , StringComparison . OrdinalIgnoreCase ) ) ;
}
2020-07-07 17:10:51 +02:00
if ( controllableByUserId . HasValue & & ! controllableByUserId . Equals ( Guid . Empty ) )
2020-06-12 18:54:25 +02:00
{
result = result . Where ( i = > i . SupportsRemoteControl ) ;
2020-07-07 17:10:51 +02:00
var user = _userManager . GetUserById ( controllableByUserId . Value ) ;
2020-06-12 18:54:25 +02:00
2020-06-19 13:03:53 +02:00
if ( ! user . HasPermission ( PermissionKind . EnableRemoteControlOfOtherUsers ) )
2020-06-12 18:54:25 +02:00
{
2020-07-07 17:10:51 +02:00
result = result . Where ( i = > i . UserId . Equals ( Guid . Empty ) | | i . ContainsUser ( controllableByUserId . Value ) ) ;
2020-06-12 18:54:25 +02:00
}
2020-06-19 13:03:53 +02:00
if ( ! user . HasPermission ( PermissionKind . EnableSharedDeviceControl ) )
2020-06-12 18:54:25 +02:00
{
result = result . Where ( i = > ! i . UserId . Equals ( Guid . Empty ) ) ;
}
if ( activeWithinSeconds . HasValue & & activeWithinSeconds . Value > 0 )
{
var minActiveDate = DateTime . UtcNow . AddSeconds ( 0 - activeWithinSeconds . Value ) ;
result = result . Where ( i = > i . LastActivityDate > = minActiveDate ) ;
}
result = result . Where ( i = >
{
if ( ! string . IsNullOrWhiteSpace ( i . DeviceId ) )
{
if ( ! _deviceManager . CanAccessDevice ( user , i . DeviceId ) )
{
return false ;
}
}
return true ;
} ) ;
}
return Ok ( result ) ;
}
/// <summary>
/// Instructs a session to browse to an item or view.
/// </summary>
2020-06-21 02:02:07 +02:00
/// <param name="sessionId">The session Id.</param>
2020-06-12 18:54:25 +02:00
/// <param name="itemType">The type of item to browse to.</param>
/// <param name="itemId">The Id of the item.</param>
/// <param name="itemName">The name of the item.</param>
/// <response code="204">Instruction sent to session.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/{sessionId}/Viewing")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult DisplayContent (
2020-09-08 02:45:06 +02:00
[FromRoute, Required] string sessionId ,
[FromQuery, Required] string itemType ,
[FromQuery, Required] string itemId ,
[FromQuery, Required] string itemName )
2020-06-12 18:54:25 +02:00
{
var command = new BrowseRequest
{
ItemId = itemId ,
ItemName = itemName ,
ItemType = itemType
} ;
_sessionManager . SendBrowseCommand (
2020-06-19 13:03:53 +02:00
RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) . Id ,
2020-06-21 02:02:07 +02:00
sessionId ,
2020-06-12 18:54:25 +02:00
command ,
CancellationToken . None ) ;
return NoContent ( ) ;
}
/// <summary>
/// Instructs a session to play an item.
/// </summary>
2020-06-21 02:02:07 +02:00
/// <param name="sessionId">The session id.</param>
2020-09-08 02:59:55 +02:00
/// <param name="command">The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now.</param>
2020-06-12 18:54:25 +02:00
/// <param name="itemIds">The ids of the items to play, comma delimited.</param>
/// <param name="startPositionTicks">The starting position of the first item.</param>
/// <response code="204">Instruction sent to session.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-09-17 18:54:09 +02:00
[HttpPost("Sessions/{sessionId}/Playing")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult Play (
2020-09-08 02:45:06 +02:00
[FromRoute, Required] string sessionId ,
2020-09-08 02:59:55 +02:00
[FromRoute, Required] PlayCommand command ,
2020-09-17 18:54:09 +02:00
[FromQuery] Guid itemIds ,
2020-09-08 02:59:55 +02:00
[FromQuery] long? startPositionTicks )
2020-06-12 18:54:25 +02:00
{
2020-08-21 15:24:44 +02:00
var playRequest = new PlayRequest
2020-06-12 18:54:25 +02:00
{
2020-09-17 19:47:36 +02:00
ItemIds = new [ ] { itemIds } ,
2020-08-21 15:24:44 +02:00
StartPositionTicks = startPositionTicks ,
2020-09-08 02:59:55 +02:00
PlayCommand = command
2020-08-21 15:24:44 +02:00
} ;
2020-06-12 18:54:25 +02:00
_sessionManager . SendPlayCommand (
2020-06-19 13:03:53 +02:00
RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) . Id ,
2020-06-21 02:02:07 +02:00
sessionId ,
2020-06-12 18:54:25 +02:00
playRequest ,
CancellationToken . None ) ;
return NoContent ( ) ;
}
/// <summary>
/// Issues a playstate command to a client.
/// </summary>
2020-06-21 02:02:07 +02:00
/// <param name="sessionId">The session id.</param>
2020-06-12 18:54:25 +02:00
/// <param name="playstateRequest">The <see cref="PlaystateRequest"/>.</param>
/// <response code="204">Playstate command sent to session.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-09-17 18:54:09 +02:00
[HttpPost("Sessions/{sessionId}/Playing/{command}")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult SendPlaystateCommand (
2020-09-08 02:45:06 +02:00
[FromRoute, Required] string sessionId ,
2020-06-12 18:54:25 +02:00
[FromBody] PlaystateRequest playstateRequest )
{
_sessionManager . SendPlaystateCommand (
2020-06-19 13:03:53 +02:00
RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) . Id ,
2020-06-21 02:02:07 +02:00
sessionId ,
2020-06-12 18:54:25 +02:00
playstateRequest ,
CancellationToken . None ) ;
return NoContent ( ) ;
}
/// <summary>
/// Issues a system command to a client.
/// </summary>
2020-06-21 02:02:07 +02:00
/// <param name="sessionId">The session id.</param>
2020-06-12 18:54:25 +02:00
/// <param name="command">The command to send.</param>
/// <response code="204">System command sent to session.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/{sessionId}/System/{command}")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult SendSystemCommand (
2020-09-08 02:45:06 +02:00
[FromRoute, Required] string sessionId ,
[FromRoute, Required] string command )
2020-06-12 18:54:25 +02:00
{
var name = command ;
if ( Enum . TryParse ( name , true , out GeneralCommandType commandType ) )
{
name = commandType . ToString ( ) ;
}
2020-06-19 13:03:53 +02:00
var currentSession = RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) ;
2020-06-12 18:54:25 +02:00
var generalCommand = new GeneralCommand
{
Name = name ,
ControllingUserId = currentSession . UserId
} ;
2020-06-21 02:02:07 +02:00
_sessionManager . SendGeneralCommand ( currentSession . Id , sessionId , generalCommand , CancellationToken . None ) ;
2020-06-12 18:54:25 +02:00
return NoContent ( ) ;
}
/// <summary>
/// Issues a general command to a client.
/// </summary>
2020-06-21 02:02:07 +02:00
/// <param name="sessionId">The session id.</param>
2020-06-12 18:54:25 +02:00
/// <param name="command">The command to send.</param>
/// <response code="204">General command sent to session.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/{sessionId}/Command/{command}")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult SendGeneralCommand (
2020-09-08 02:45:06 +02:00
[FromRoute, Required] string sessionId ,
[FromRoute, Required] string command )
2020-06-12 18:54:25 +02:00
{
2020-06-19 13:03:53 +02:00
var currentSession = RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) ;
2020-06-12 18:54:25 +02:00
var generalCommand = new GeneralCommand
{
Name = command ,
ControllingUserId = currentSession . UserId
} ;
2020-06-21 02:02:07 +02:00
_sessionManager . SendGeneralCommand ( currentSession . Id , sessionId , generalCommand , CancellationToken . None ) ;
2020-06-12 18:54:25 +02:00
return NoContent ( ) ;
}
/// <summary>
/// Issues a full general command to a client.
/// </summary>
2020-06-21 02:02:07 +02:00
/// <param name="sessionId">The session id.</param>
2020-06-12 18:54:25 +02:00
/// <param name="command">The <see cref="GeneralCommand"/>.</param>
/// <response code="204">Full general command sent to session.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/{sessionId}/Command")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult SendFullGeneralCommand (
2020-09-08 02:45:06 +02:00
[FromRoute, Required] string sessionId ,
2020-06-12 18:54:25 +02:00
[FromBody, Required] GeneralCommand command )
{
2020-06-19 13:03:53 +02:00
var currentSession = RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) ;
2020-06-12 18:54:25 +02:00
if ( command = = null )
{
throw new ArgumentException ( "Request body may not be null" ) ;
}
command . ControllingUserId = currentSession . UserId ;
_sessionManager . SendGeneralCommand (
currentSession . Id ,
2020-06-21 02:02:07 +02:00
sessionId ,
2020-06-12 18:54:25 +02:00
command ,
CancellationToken . None ) ;
return NoContent ( ) ;
}
/// <summary>
/// Issues a command to a client to display a message to the user.
/// </summary>
2020-06-21 02:02:07 +02:00
/// <param name="sessionId">The session id.</param>
2020-06-12 18:54:25 +02:00
/// <param name="text">The message test.</param>
/// <param name="header">The message header.</param>
/// <param name="timeoutMs">The message timeout. If omitted the user will have to confirm viewing the message.</param>
/// <response code="204">Message sent.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/{sessionId}/Message")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult SendMessageCommand (
2020-09-08 02:45:06 +02:00
[FromRoute, Required] string sessionId ,
[FromQuery, Required] string text ,
2020-09-09 22:28:30 +02:00
[FromQuery] string? header ,
2020-06-12 18:54:25 +02:00
[FromQuery] long? timeoutMs )
{
var command = new MessageCommand
{
Header = string . IsNullOrEmpty ( header ) ? "Message from Server" : header ,
TimeoutMs = timeoutMs ,
Text = text
} ;
2020-06-21 02:02:07 +02:00
_sessionManager . SendMessageCommand ( RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) . Id , sessionId , command , CancellationToken . None ) ;
2020-06-12 18:54:25 +02:00
return NoContent ( ) ;
}
/// <summary>
/// Adds an additional user to a session.
/// </summary>
2020-06-21 02:02:07 +02:00
/// <param name="sessionId">The session id.</param>
2020-06-12 18:54:25 +02:00
/// <param name="userId">The user id.</param>
/// <response code="204">User added to session.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/{sessionId}/User/{userId}")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult AddUserToSession (
2020-09-08 02:45:06 +02:00
[FromRoute, Required] string sessionId ,
2020-09-06 17:07:27 +02:00
[FromRoute, Required] Guid userId )
2020-06-12 18:54:25 +02:00
{
2020-06-21 02:02:07 +02:00
_sessionManager . AddAdditionalUser ( sessionId , userId ) ;
2020-06-12 18:54:25 +02:00
return NoContent ( ) ;
}
/// <summary>
/// Removes an additional user from a session.
/// </summary>
2020-06-21 02:02:07 +02:00
/// <param name="sessionId">The session id.</param>
2020-06-12 18:54:25 +02:00
/// <param name="userId">The user id.</param>
/// <response code="204">User removed from session.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpDelete("Sessions/{sessionId}/User/{userId}")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult RemoveUserFromSession (
2020-09-08 02:45:06 +02:00
[FromRoute, Required] string sessionId ,
2020-09-06 17:07:27 +02:00
[FromRoute, Required] Guid userId )
2020-06-12 18:54:25 +02:00
{
2020-06-21 02:02:07 +02:00
_sessionManager . RemoveAdditionalUser ( sessionId , userId ) ;
2020-06-12 18:54:25 +02:00
return NoContent ( ) ;
}
/// <summary>
/// Updates capabilities for a device.
/// </summary>
/// <param name="id">The session id.</param>
/// <param name="playableMediaTypes">A list of playable media types, comma delimited. Audio, Video, Book, Photo.</param>
/// <param name="supportedCommands">A list of supported remote control commands, comma delimited.</param>
/// <param name="supportsMediaControl">Determines whether media can be played remotely..</param>
/// <param name="supportsSync">Determines whether sync is supported.</param>
/// <param name="supportsPersistentIdentifier">Determines whether the device supports a unique identifier.</param>
/// <response code="204">Capabilities posted.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/Capabilities")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult PostCapabilities (
2020-09-09 22:28:30 +02:00
[FromQuery] string? id ,
2020-06-27 18:50:44 +02:00
[FromQuery] string? playableMediaTypes ,
[FromQuery] string? supportedCommands ,
2020-07-07 17:10:51 +02:00
[FromQuery] bool supportsMediaControl = false ,
[FromQuery] bool supportsSync = false ,
2020-06-12 18:54:25 +02:00
[FromQuery] bool supportsPersistentIdentifier = true )
{
if ( string . IsNullOrWhiteSpace ( id ) )
{
2020-06-19 13:03:53 +02:00
id = RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) . Id ;
2020-06-12 18:54:25 +02:00
}
_sessionManager . ReportCapabilities ( id , new ClientCapabilities
{
PlayableMediaTypes = RequestHelpers . Split ( playableMediaTypes , ',' , true ) ,
SupportedCommands = RequestHelpers . Split ( supportedCommands , ',' , true ) ,
SupportsMediaControl = supportsMediaControl ,
SupportsSync = supportsSync ,
SupportsPersistentIdentifier = supportsPersistentIdentifier
} ) ;
return NoContent ( ) ;
}
/// <summary>
/// Updates capabilities for a device.
/// </summary>
/// <param name="id">The session id.</param>
/// <param name="capabilities">The <see cref="ClientCapabilities"/>.</param>
/// <response code="204">Capabilities updated.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/Capabilities/Full")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult PostFullCapabilities (
2020-08-09 22:12:39 +02:00
[FromQuery] string? id ,
2020-06-12 18:54:25 +02:00
[FromBody, Required] ClientCapabilities capabilities )
{
if ( string . IsNullOrWhiteSpace ( id ) )
{
2020-06-19 13:03:53 +02:00
id = RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) . Id ;
2020-06-12 18:54:25 +02:00
}
_sessionManager . ReportCapabilities ( id , capabilities ) ;
return NoContent ( ) ;
}
/// <summary>
/// Reports that a session is viewing an item.
/// </summary>
/// <param name="sessionId">The session id.</param>
/// <param name="itemId">The item id.</param>
/// <response code="204">Session reported to server.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/Viewing")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult ReportViewing (
2020-06-27 18:50:44 +02:00
[FromQuery] string? sessionId ,
[FromQuery] string? itemId )
2020-06-12 18:54:25 +02:00
{
2020-06-19 13:03:53 +02:00
string session = RequestHelpers . GetSession ( _sessionManager , _authContext , Request ) . Id ;
2020-06-12 18:54:25 +02:00
_sessionManager . ReportNowViewingItem ( session , itemId ) ;
return NoContent ( ) ;
}
/// <summary>
/// Reports that a session has ended.
/// </summary>
/// <response code="204">Session end reported to server.</response>
/// <returns>A <see cref="NoContentResult"/>.</returns>
2020-08-04 20:48:53 +02:00
[HttpPost("Sessions/Logout")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status204NoContent)]
public ActionResult ReportSessionEnded ( )
{
AuthorizationInfo auth = _authContext . GetAuthorizationInfo ( Request ) ;
_sessionManager . Logout ( auth . Token ) ;
return NoContent ( ) ;
}
/// <summary>
/// Get all auth providers.
/// </summary>
/// <response code="200">Auth providers retrieved.</response>
/// <returns>An <see cref="IEnumerable{NameIdPair}"/> with the auth providers.</returns>
2020-08-04 20:48:53 +02:00
[HttpGet("Auth/Providers")]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.RequiresElevation)]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status200OK)]
public ActionResult < IEnumerable < NameIdPair > > GetAuthProviders ( )
{
return _userManager . GetAuthenticationProviders ( ) ;
}
/// <summary>
/// Get all password reset providers.
/// </summary>
/// <response code="200">Password reset providers retrieved.</response>
/// <returns>An <see cref="IEnumerable{NameIdPair}"/> with the password reset providers.</returns>
2020-08-10 18:09:27 +02:00
[HttpGet("Auth/PasswordResetProviders")]
2020-06-12 18:54:25 +02:00
[ProducesResponseType(StatusCodes.Status200OK)]
2020-08-06 16:17:45 +02:00
[Authorize(Policy = Policies.RequiresElevation)]
2020-06-12 18:54:25 +02:00
public ActionResult < IEnumerable < NameIdPair > > GetPasswordResetProviders ( )
{
return _userManager . GetPasswordResetProviders ( ) ;
}
}
}