92 lines
3.4 KiB
Plaintext
92 lines
3.4 KiB
Plaintext
@page "/article/{id:guid}"
|
|
@using Microsoft.EntityFrameworkCore
|
|
@using Wave.Data
|
|
@using System.Security.Claims
|
|
@using Microsoft.AspNetCore.Identity
|
|
@using System.Diagnostics.CodeAnalysis
|
|
|
|
@inject IDbContextFactory<ApplicationDbContext> ContextFactory;
|
|
@inject RoleManager<IdentityRole> RoleManager
|
|
@inject IStringLocalizer<ArticleView> Localizer
|
|
|
|
<PageTitle>@(TitlePrefix + Article.Title)</PageTitle>
|
|
|
|
<ErrorBoundary>
|
|
<ChildContent>
|
|
<AuthorizeView Policy="ArticleEditOrReviewPermissions">
|
|
<Authorized>
|
|
<ArticleComponent Article="@GetArticleProtected(context.User)" />
|
|
</Authorized>
|
|
<NotAuthorized>
|
|
<ArticleComponent Article="@GetArticlePublic()" />
|
|
</NotAuthorized>
|
|
</AuthorizeView>
|
|
</ChildContent>
|
|
<ErrorContent>
|
|
<h1 class="text-3xl lg:text-5xl font-light mb-6">@Localizer["NotFound_Title"]</h1>
|
|
<p class="my-3">@Localizer["NotFound_Description"]</p>
|
|
@if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")?.ToLower() == "development") {
|
|
<p>@context.Message</p>
|
|
}
|
|
</ErrorContent>
|
|
</ErrorBoundary>
|
|
|
|
@code {
|
|
[CascadingParameter(Name = "TitlePrefix")]
|
|
private string TitlePrefix { get; set; } = default!;
|
|
|
|
[Parameter]
|
|
public Guid Id { get; set; }
|
|
private Article Article { get; set; } = default!;
|
|
|
|
private Article GetArticlePublic() {
|
|
if (Article.Status >= ArticleStatus.Published && Article.PublishDate <= DateTimeOffset.UtcNow) {
|
|
return Article;
|
|
}
|
|
throw new ApplicationException("Article is not public.");
|
|
}
|
|
|
|
[SuppressMessage("ReSharper", "ConvertIfStatementToSwitchStatement")]
|
|
private Article GetArticleProtected(ClaimsPrincipal principal) {
|
|
// Admins always get access
|
|
if (principal.IsInRole("Admin")) {
|
|
return Article;
|
|
}
|
|
|
|
// You cannot access your own drafts
|
|
if (Article.Status is ArticleStatus.Draft) {
|
|
if (Article.Author.Id == principal.FindFirst("Id")!.Value) {
|
|
return Article;
|
|
}
|
|
throw new ApplicationException("Cannot access draft article without being author or admin.");
|
|
}
|
|
// InReview Articles can only be accessed by reviewers
|
|
if (Article.Status is ArticleStatus.InReview) {
|
|
if (principal.IsInRole("Reviewer")) {
|
|
return Article;
|
|
}
|
|
throw new ApplicationException("Cannot access in-review article without being a reviewer or admin.");
|
|
}
|
|
|
|
throw new ApplicationException("User does not have access to this article.");
|
|
}
|
|
|
|
protected override async Task OnInitializedAsync() {
|
|
// We need blocking calls here, bc otherwise Blazor will execute Render in parallel,
|
|
// running into a null pointer on the Article property and panicking
|
|
|
|
// ReSharper disable once MethodHasAsyncOverload
|
|
await using var context = ContextFactory.CreateDbContext();
|
|
// ReSharper disable once MethodHasAsyncOverload
|
|
var now = DateTimeOffset.UtcNow;
|
|
Article = context.Set<Article>()
|
|
.Include(a => a.Author)
|
|
.Include(a => a.Reviewer)
|
|
// .Where(a => a.Status >= ArticleStatus.Published && a.PublishDate <= now)
|
|
.First(a => a.Id == Id);
|
|
|
|
if (Article is null) throw new ApplicationException("Article not found.");
|
|
}
|
|
|
|
}
|