Добавлен playlist shared
This commit is contained in:
80
PlaylistShared/Components/Pages/CreatePlaylist.razor
Normal file
80
PlaylistShared/Components/Pages/CreatePlaylist.razor
Normal file
@@ -0,0 +1,80 @@
|
||||
@page "/createplaylist"
|
||||
@attribute [Authorize]
|
||||
@using System.Security.Claims
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject AppDbContext Db
|
||||
@inject IYandexMusicService YandexService
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
<h3>Создание общего плейлиста</h3>
|
||||
|
||||
<EditForm Model="@model" OnValidSubmit="@HandleSubmit">
|
||||
<div class="mb-3">
|
||||
<label for="title">Название плейлиста</label>
|
||||
<InputText id="title" class="form-control" @bind-Value="model.Title" />
|
||||
<ValidationMessage For="@(() => model.Title)" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="description">Описание (необязательно)</label>
|
||||
<InputText id="description" class="form-control" @bind-Value="model.Description" />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" disabled="@isLoading">@(isLoading ? "Создание..." : "Создать")</button>
|
||||
</EditForm>
|
||||
|
||||
@code {
|
||||
private CreateModel model = new();
|
||||
private bool isLoading;
|
||||
private string? userId;
|
||||
|
||||
public class CreateModel
|
||||
{
|
||||
[Required]
|
||||
public string Title { get; set; } = "";
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
userId = authState.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
}
|
||||
|
||||
private async Task HandleSubmit()
|
||||
{
|
||||
if (string.IsNullOrEmpty(userId))
|
||||
{
|
||||
// пользователь не авторизован
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading = true;
|
||||
try
|
||||
{
|
||||
// 1. Создаём плейлист в Яндекс Музыке
|
||||
var yandexId = await YandexService.CreatePlaylistAsync(userId, model.Title);
|
||||
// 2. Сохраняем в БД
|
||||
var playlist = new SharedPlaylist
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
OwnerUserId = userId,
|
||||
YandexPlaylistId = yandexId,
|
||||
Title = model.Title,
|
||||
Description = model.Description,
|
||||
ShareSlug = Guid.NewGuid().ToString("N"),
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
Db.SharedPlaylists.Add(playlist);
|
||||
await Db.SaveChangesAsync();
|
||||
Navigation.NavigateTo("/myplaylists");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// показать ошибку (можно добавить переменную errorMessage)
|
||||
}
|
||||
finally
|
||||
{
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
PlaylistShared/Components/Pages/Login.razor
Normal file
7
PlaylistShared/Components/Pages/Login.razor
Normal file
@@ -0,0 +1,7 @@
|
||||
@page "/Login"
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@using Microsoft.AspNetCore.Authentication
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
|
||||
<h3>Вход через Яндекс</h3>
|
||||
<a class="btn btn-primary" href="/signin-yandex">Войти через Яндекс</a>
|
||||
12
PlaylistShared/Components/Pages/Logout.razor
Normal file
12
PlaylistShared/Components/Pages/Logout.razor
Normal file
@@ -0,0 +1,12 @@
|
||||
@page "/Logout"
|
||||
@using Microsoft.AspNetCore.Identity
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@code {
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await SignInManager.SignOutAsync();
|
||||
Navigation.NavigateTo("/", true);
|
||||
}
|
||||
}
|
||||
57
PlaylistShared/Components/Pages/MyPlaylists.razor
Normal file
57
PlaylistShared/Components/Pages/MyPlaylists.razor
Normal file
@@ -0,0 +1,57 @@
|
||||
@page "/myplaylists"
|
||||
@attribute [Authorize]
|
||||
@using System.Security.Claims
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject AppDbContext Db
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
<h3>Мои плейлисты</h3>
|
||||
<a href="/createplaylist" class="btn btn-success mb-3">Создать новый плейлист</a>
|
||||
|
||||
@if (playlists == null)
|
||||
{
|
||||
<p>Загрузка...</p>
|
||||
}
|
||||
else if (!playlists.Any())
|
||||
{
|
||||
<p>У вас пока нет общих плейлистов. Создайте первый!</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr><th>Название</th><th>Дата создания</th><th>Ссылка</th><th>Настройки</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var pl in playlists)
|
||||
{
|
||||
<tr>
|
||||
<td>@pl.Title</td>
|
||||
<td>@pl.CreatedAt.ToShortDateString()</td>
|
||||
<td><a href="/playlist/@pl.ShareSlug">открыть</a></td>
|
||||
<td><a href="/settings/@pl.Id">настройки</a></td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<SharedPlaylist>? playlists;
|
||||
private string? userId;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
userId = authState.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
if (userId != null)
|
||||
{
|
||||
playlists = await Db.SharedPlaylists
|
||||
.Where(p => p.OwnerUserId == userId)
|
||||
.OrderByDescending(p => p.CreatedAt)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
5
PlaylistShared/Components/Pages/NotFound.razor
Normal file
5
PlaylistShared/Components/Pages/NotFound.razor
Normal file
@@ -0,0 +1,5 @@
|
||||
@page "/not-found"
|
||||
@layout MainLayout
|
||||
|
||||
<h3>Not Found</h3>
|
||||
<p>Sorry, the content you are looking for does not exist.</p>
|
||||
92
PlaylistShared/Components/Pages/PlaylistDetails.razor
Normal file
92
PlaylistShared/Components/Pages/PlaylistDetails.razor
Normal file
@@ -0,0 +1,92 @@
|
||||
@page "/playlist/{slug}"
|
||||
@using System.Security.Claims
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using PlaylistShared.Data.Entities
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject AppDbContext Db
|
||||
@inject IYandexMusicService YandexService
|
||||
@inject IJSRuntime Js
|
||||
@inject HttpClient Http
|
||||
|
||||
<h3>@playlist?.Title</h3>
|
||||
<p>Владелец: @playlist?.Owner?.UserName</p>
|
||||
<p>Описание: @playlist?.Description</p>
|
||||
|
||||
@if (canAdd)
|
||||
{
|
||||
<div class="mb-3">
|
||||
<input type="text" id="trackId" placeholder="ID трека Яндекс.Музыки" class="form-control" />
|
||||
<input type="text" id="trackTitle" placeholder="Название трека" class="form-control mt-1" />
|
||||
<input type="text" id="artistName" placeholder="Исполнитель" class="form-control mt-1" />
|
||||
<button class="btn btn-primary mt-2" id="addTrackBtn">Добавить</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
<ul id="trackList" class="list-group">
|
||||
@foreach (var track in tracks)
|
||||
{
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center" data-track-id="@track.YandexTrackId">
|
||||
<div>
|
||||
<strong>@track.Title</strong> - @track.Artist
|
||||
</div>
|
||||
@if (canDelete(track))
|
||||
{
|
||||
<button class="btn btn-sm btn-danger deleteTrackBtn" data-track-id="@track.YandexTrackId">Удалить</button>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
@code {
|
||||
[Parameter] public string slug { get; set; } = "";
|
||||
|
||||
private SharedPlaylist? playlist;
|
||||
private List<PlaylistTrack> tracks = new();
|
||||
private bool canAdd;
|
||||
private string? currentUserId;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
currentUserId = authState.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
|
||||
playlist = await Db.SharedPlaylists
|
||||
.Include(p => p.Owner)
|
||||
.Include(p => p.Tracks)
|
||||
.FirstOrDefaultAsync(p => p.ShareSlug == slug);
|
||||
if (playlist == null) return;
|
||||
|
||||
canAdd = playlist.Permissions.Add switch
|
||||
{
|
||||
AccessLevel.All => true,
|
||||
AccessLevel.Authorized => currentUserId != null,
|
||||
_ => false
|
||||
};
|
||||
|
||||
// Здесь можно при желании синхронизировать с Яндекс API, но пока используем локальный кеш
|
||||
// var yandexTracks = await YandexService.GetPlaylistTracksAsync(playlist.OwnerUserId, playlist.YandexPlaylistId);
|
||||
tracks = playlist.Tracks.OrderBy(t => t.AddedAt).ToList();
|
||||
}
|
||||
|
||||
private bool canDelete(PlaylistTrack track)
|
||||
{
|
||||
if (currentUserId == playlist?.OwnerUserId) return true;
|
||||
return playlist?.Permissions.Delete switch
|
||||
{
|
||||
DeleteAccessLevel.All => true,
|
||||
DeleteAccessLevel.Authorized => currentUserId != null,
|
||||
DeleteAccessLevel.AdderOnly => currentUserId != null && currentUserId == track.AddedByUserId,
|
||||
DeleteAccessLevel.OwnerOnly => false,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender && playlist != null)
|
||||
{
|
||||
await Js.InvokeVoidAsync("initPlaylistInteractions", playlist.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
82
PlaylistShared/Components/Pages/PlaylistSettings.razor
Normal file
82
PlaylistShared/Components/Pages/PlaylistSettings.razor
Normal file
@@ -0,0 +1,82 @@
|
||||
@page "/settings/{id:guid}"
|
||||
@attribute [Authorize]
|
||||
@using System.Security.Claims
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using PlaylistShared.Data.Entities
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject AppDbContext Db
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
<h3>Настройки плейлиста</h3>
|
||||
|
||||
@if (playlist == null)
|
||||
{
|
||||
<p>Загрузка...</p>
|
||||
}
|
||||
else if (!isOwner)
|
||||
{
|
||||
<p>Только владелец может изменять настройки.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<EditForm Model="@playlist.Permissions" OnValidSubmit="@SaveSettings">
|
||||
<div class="mb-3">
|
||||
<label>Кто может просматривать</label>
|
||||
<InputSelect @bind-Value="playlist.Permissions.View" class="form-control">
|
||||
<option value="@AccessLevel.All">Все</option>
|
||||
<option value="@AccessLevel.Authorized">Авторизованные</option>
|
||||
<option value="@AccessLevel.None">Никто</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label>Кто может добавлять треки</label>
|
||||
<InputSelect @bind-Value="playlist.Permissions.Add" class="form-control">
|
||||
<option value="@AccessLevel.All">Все</option>
|
||||
<option value="@AccessLevel.Authorized">Авторизованные</option>
|
||||
<option value="@AccessLevel.None">Никто</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label>Кто может удалять треки</label>
|
||||
<InputSelect @bind-Value="playlist.Permissions.Delete" class="form-control">
|
||||
<option value="@DeleteAccessLevel.All">Все</option>
|
||||
<option value="@DeleteAccessLevel.Authorized">Авторизованные</option>
|
||||
<option value="@DeleteAccessLevel.AdderOnly">Тот, кто добавил</option>
|
||||
<option value="@DeleteAccessLevel.OwnerOnly">Только владелец</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Сохранить</button>
|
||||
</EditForm>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter] public Guid id { get; set; }
|
||||
private SharedPlaylist? playlist;
|
||||
private bool isOwner;
|
||||
private string? currentUserId;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||
currentUserId = authState.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
|
||||
playlist = await Db.SharedPlaylists
|
||||
.Include(p => p.Owner)
|
||||
.FirstOrDefaultAsync(p => p.Id == id);
|
||||
if (playlist != null)
|
||||
{
|
||||
isOwner = currentUserId == playlist.OwnerUserId;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSettings()
|
||||
{
|
||||
if (playlist != null)
|
||||
{
|
||||
Db.SharedPlaylists.Update(playlist);
|
||||
await Db.SaveChangesAsync();
|
||||
Navigation.NavigateTo("/myplaylists");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user