feat: harden auth ops and deployment baseline

This commit is contained in:
2026-06-27 10:53:53 +09:00
parent a6ca30eec8
commit 28060b71be
41 changed files with 714 additions and 208 deletions
@@ -1,11 +1,12 @@
@page "/admin/blog/create"
@using TaxBaik.Application.DTOs
@using TaxBaik.Application.Services
@using TaxBaik.Domain.Interfaces
@attribute [Authorize]
@inject BlogService BlogService
@inject ICategoryRepository CategoryRepository
@inject NavigationManager Navigation
@inject Snackbar Snackbar
@inject ISnackbar Snackbar
<PageTitle>새 포스트 작성</PageTitle>
@@ -49,7 +50,7 @@
</MudPaper>
@code {
private MudForm form;
private MudForm? form;
private List<Domain.Entities.Category> categories = [];
private CreatePostModel model = new();
@@ -60,18 +61,43 @@
private async Task SavePost()
{
// TODO: Implement BlogService.CreateAsync
Navigation.NavigateTo("/taxbaik/admin/blog");
if (form == null)
return;
await form.Validate();
if (!form.IsValid)
return;
try
{
await BlogService.CreateAsync(new CreateBlogPostDto
{
Title = model.Title,
Content = model.Content,
CategoryId = model.CategoryId,
Tags = model.Tags,
SeoTitle = model.SeoTitle,
SeoDescription = model.SeoDescription,
IsPublished = model.IsPublished
});
Snackbar.Add("포스트가 저장되었습니다.", Severity.Success);
Navigation.NavigateTo("/taxbaik/admin/blog");
}
catch (ValidationException ex)
{
Snackbar.Add(ex.Message, Severity.Error);
}
}
private class CreatePostModel
{
public string Title { get; set; }
public string Content { get; set; }
public int CategoryId { get; set; }
public string Tags { get; set; }
public string SeoTitle { get; set; }
public string SeoDescription { get; set; }
public string Title { get; set; } = "";
public string Content { get; set; } = "";
public int? CategoryId { get; set; }
public string? Tags { get; set; }
public string? SeoTitle { get; set; }
public string? SeoDescription { get; set; }
public bool IsPublished { get; set; }
}
}
@@ -2,7 +2,7 @@
@attribute [Authorize]
@inject IApiClient ApiClient
@inject DialogService DialogService
@inject Snackbar Snackbar
@inject ISnackbar Snackbar
<PageTitle>블로그 관리</PageTitle>
@@ -17,7 +17,8 @@
<PropertyColumn Property="x => x.Title" Title="제목" />
<PropertyColumn Property="x => x.IsPublished" Title="발행">
<CellTemplate Context="cell">
<MudCheckBox @bind-Checked="@cell.Item.IsPublished" />
<MudCheckBox T="bool" Value="@cell.Item.IsPublished"
ValueChanged="@(async (bool value) => await TogglePublish(cell.Item, value))" />
</CellTemplate>
</PropertyColumn>
<PropertyColumn Property="x => x.ViewCount" Title="조회수" />
@@ -54,14 +55,37 @@
isLoading = false;
}
private async Task TogglePublish(int postId, bool isPublished)
private async Task TogglePublish(TaxBaik.Domain.Entities.BlogPost post, bool isPublished)
{
// Publish status update via API
var previous = post.IsPublished;
post.IsPublished = isPublished;
var result = await ApiClient.PutAsync<TaxBaik.Domain.Entities.BlogPost>($"blog/{post.Id}", new
{
post.Title,
post.Content,
post.CategoryId,
post.Tags,
post.SeoTitle,
post.SeoDescription,
post.ThumbnailUrl,
IsPublished = isPublished,
post.AuthorId
});
if (result == null)
{
post.IsPublished = previous;
Snackbar.Add("발행 상태 변경에 실패했습니다.", Severity.Error);
return;
}
Snackbar.Add("발행 상태가 변경되었습니다.", Severity.Success);
}
private async Task DeletePost(int postId)
{
await ApiClient.DeleteAsync($"blog/{postId}");
Snackbar.Add("포스트가 삭제되었습니다.", Severity.Success);
await LoadPosts();
}
}