Files
PlaylistShared/PlaylistShared.Api/Controllers/SharedPlaylistController.cs

200 lines
10 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using PlaylistShared.Api.Entities;
using PlaylistShared.Api.Extensions;
using PlaylistShared.Api.Services;
using PlaylistShared.Shared;
using PlaylistShared.Shared.DTO;
using PlaylistShared.Shared.Shared;
using YandexMusic.API.Models.Playlist;
[ApiController]
[Route("api/[controller]")]
public class SharedPlaylistController : ControllerBase
{
private readonly SharedPlaylistService _sharedService;
private readonly YandexMusicService _yandexService;
private readonly UserManager<ApplicationUser> _userManager;
private readonly UserSessionService _userSessionService;
private readonly TrackAdditionLogService _trackAdditionLogService;
private readonly TrackRemovalLogService _trackRemovalLogService;
public SharedPlaylistController(
SharedPlaylistService sharedService,
YandexMusicService yandexService,
UserManager<ApplicationUser> userManager,
TrackAdditionLogService trackAdditionLogService,
TrackRemovalLogService trackRemovalLogService,
UserSessionService userSessionService)
{
_sharedService = sharedService;
_yandexService = yandexService;
_userManager = userManager;
_trackAdditionLogService = trackAdditionLogService;
_trackRemovalLogService = trackRemovalLogService;
_userSessionService = userSessionService;
}
// GET /api/sharedplaylist/{token}
[HttpGet("{token}")]
public async Task<ActionResult<ApiResponse<SharedPlaylistDto>>> GetByToken(string token)
{
var playlist = await _sharedService.GetByTokenAsync(token);
if (playlist == null)
return NotFound(ApiResponse<SharedPlaylistDto>.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" }));
var currentUserId = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
var userIdGuid = !string.IsNullOrEmpty(currentUserId) ? Guid.Parse(currentUserId) : (Guid?)null;
// Проверка прав просмотра (требует доступа к сущности)
var entity = await _sharedService.GetEntityByTokenAsync(token);
if (entity == null || !await _sharedService.CanViewAsync(entity, userIdGuid))
return Unauthorized(ApiResponse<SharedPlaylistDto>.Fail(new ErrorResponse { StatusCode = 401, Message = "Недостаточно прав" }));
return Ok(ApiResponse<SharedPlaylistDto>.Ok(playlist));
}
// GET /api/sharedplaylist/{token}/tracks
[HttpGet("{token}/tracks")]
public async Task<ActionResult<ApiResponse<YandexPlaylistData>>> GetTracks(string token)
{
var currentUserId = User.GetUserIdOrNull();
var playlist = await _sharedService.GetEntityByTokenAsync(token);
if (playlist == null)
return NotFound(ApiResponse<YandexPlaylistData>.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" }));
if (!await _sharedService.CanViewAsync(playlist, currentUserId))
return Unauthorized();
var creator = await _userManager.FindByIdAsync(playlist.CreatorUserId.ToString());
if (creator == null)
return StatusCode(500, ApiResponse<YandexPlaylistData>.Fail(new ErrorResponse { StatusCode = 500, Message = "Владелец плейлиста не найден" }));
var yandexPlaylist = await _yandexService.GetPlaylistAsync(creator, playlist.YandexPlaylistOwnerUid, playlist.YandexPlaylistKind);
if (yandexPlaylist == null)
return NotFound(ApiResponse<YandexPlaylistData>.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден в Яндекс.Музыке" }));
var dto = MapToYandexPlaylistData(yandexPlaylist);
return Ok(ApiResponse<YandexPlaylistData>.Ok(dto));
}
// PUT /api/sharedplaylist/{token}/permissions
[HttpPut("{token}/permissions")]
[Authorize]
public async Task<ActionResult<ApiResponse<SharedPlaylistDto>>> UpdatePermissions(string token, [FromBody] UpdatePermissionsDto dto)
{
var userId = User.GetUserId();
var playlist = await _sharedService.GetEntityByTokenAsync(token);
if (playlist == null)
return NotFound(ApiResponse<SharedPlaylistDto>.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" }));
if (playlist.CreatorUserId != userId)
return Forbid();
var updated = await _sharedService.UpdatePermissionsAsync(playlist.Id, dto);
if (updated == null)
return BadRequest(ApiResponse<SharedPlaylistDto>.Fail(new ErrorResponse { StatusCode = 400, Message = "Ошибка обновления прав" }));
return Ok(ApiResponse<SharedPlaylistDto>.Ok(updated));
}
// POST /api/sharedplaylist/{token}/add-tracks
[HttpPost("{token}/add-tracks")]
public async Task<ActionResult<ApiResponse<object>>> AddTracks(string token, [FromBody] AddTracksRequest request)
{
var currentUserId = User.GetUserIdOrNull();
var playlist = await _sharedService.GetEntityByTokenAsync(token);
if (playlist == null)
return NotFound(ApiResponse<object>.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" }));
if (!await _sharedService.CanAddTrackAsync(playlist, currentUserId))
return StatusCode(403, ApiResponse<object>.Fail(new ErrorResponse { StatusCode = 403, Message = "Недостаточно прав для добавления треков" }));
var creator = await _userManager.FindByIdAsync(playlist.CreatorUserId.ToString());
if (creator == null)
return StatusCode(500, ApiResponse<object>.Fail(new ErrorResponse { StatusCode = 500, Message = "Владелец плейлиста не найден" }));
var updatedPlaylist = await _yandexService.AddTracksAsync(creator, playlist.YandexPlaylistOwnerUid, playlist.YandexPlaylistKind, request.TrackIds);
if (updatedPlaylist == null)
return StatusCode(500, ApiResponse<object>.Fail(new ErrorResponse { StatusCode = 500, Message = "Ошибка при добавлении треков" }));
var session = await _userSessionService.GetOrCreateCurrentSessionAsync(currentUserId);
var sessionId = session.SessionId;
foreach (var trackId in request.TrackIds)
{
await _trackAdditionLogService.LogAdditionAsync(playlist.Id, trackId, currentUserId, sessionId);
}
return Ok(ApiResponse<object>.Ok(new { message = "Треки добавлены" }));
}
// POST /api/sharedplaylist/{token}/remove-tracks
[HttpPost("{token}/remove-tracks")]
public async Task<ActionResult<ApiResponse<object>>> RemoveTracks(string token, [FromBody] RemoveTracksRequest request)
{
var currentUserId = User.GetUserIdOrNull();
var playlist = await _sharedService.GetEntityByTokenAsync(token);
if (playlist == null)
return NotFound(ApiResponse<object>.Fail(new ErrorResponse { StatusCode = 404, Message = "Плейлист не найден" }));
var session = await _userSessionService.GetOrCreateCurrentSessionAsync(currentUserId);
var sessionId = session.SessionId;
foreach (var trackId in request.TrackIds)
{
if (!await _sharedService.CanRemoveTrackAsync(playlist, currentUserId, trackId, sessionId))
return StatusCode(403, ApiResponse<object>.Fail(new ErrorResponse { StatusCode = 403, Message = $"Недостаточно прав для удаления трека {trackId}" }));
}
var creator = await _userManager.FindByIdAsync(playlist.CreatorUserId.ToString());
if (creator == null)
return StatusCode(500, ApiResponse<object>.Fail(new ErrorResponse { StatusCode = 500, Message = "Владелец плейлиста не найден" }));
var updatedPlaylist = await _yandexService.RemoveTracksAsync(creator, playlist.YandexPlaylistOwnerUid, playlist.YandexPlaylistKind, request.TrackIds);
if (updatedPlaylist == null)
return StatusCode(500, ApiResponse<object>.Fail(new ErrorResponse { StatusCode = 500, Message = "Ошибка при удалении треков" }));
foreach (var trackId in request.TrackIds)
{
await _trackRemovalLogService.LogRemovalAsync(playlist.Id, trackId, currentUserId, sessionId);
await _trackAdditionLogService.RemoveLogsForTrackAsync(playlist.Id, trackId);
}
return Ok(ApiResponse<object>.Ok(new { message = "Треки удалены" }));
}
// POST /api/sharedplaylist/{token}/add-track-by-link
[HttpPost("{token}/add-track-by-link")]
public async Task<ActionResult<ApiResponse<object>>> AddTrackByLink(string token, [FromBody] AddTrackByLinkRequest request)
{
var trackId = ExtractTrackIdFromLink(request.Link);
if (string.IsNullOrEmpty(trackId))
return BadRequest(ApiResponse<object>.Fail(new ErrorResponse { StatusCode = 400, Message = "Неверный формат ссылки" }));
return await AddTracks(token, new AddTracksRequest { TrackIds = new List<string> { trackId } });
}
private string? ExtractTrackIdFromLink(string link)
{
var match = System.Text.RegularExpressions.Regex.Match(link, @"/track/(\d+)");
return match.Success ? match.Groups[1].Value : null;
}
private YandexPlaylistData MapToYandexPlaylistData(YPlaylist playlist)
{
return new YandexPlaylistData
{
Title = playlist.Title ?? "",
Description = playlist.Description ?? "",
Tracks = playlist.Tracks?.Select(t => new YandexTrack
{
TrackId = t.Track?.Id ?? "",
Title = t.Track?.Title ?? "",
Artists = t.Track?.Artists?.Select(a => a.Name).ToList() ?? new List<string>(),
DurationMs = (int)(t.Track?.DurationMs ?? 0),
CoverUri = t.Track?.CoverUri ?? ""
}).ToList() ?? new List<YandexTrack>()
};
}
}