119 lines
4.1 KiB
Plaintext
119 lines
4.1 KiB
Plaintext
@page "/profile/{id:guid}"
|
|
@using Wave.Data
|
|
@using Microsoft.EntityFrameworkCore
|
|
@using Microsoft.Extensions.Options
|
|
@using Wave.Utilities
|
|
|
|
@inject NavigationManager Navigation
|
|
@inject IDbContextFactory<ApplicationDbContext> ContextFactory
|
|
@inject IOptions<Customization> Customizations
|
|
@inject IOptions<Features> Features
|
|
@inject IStringLocalizer<UserView> Localizer
|
|
@inject IMessageDisplay Message
|
|
|
|
<HeadContent>
|
|
@if (User is not null) {
|
|
<meta name="author" content="@User.Name">
|
|
<meta name="description" content="@string.Format(Localizer["Meta_Description"], User.Name, Customizations.Value.AppName)">
|
|
|
|
<!-- Open Graph -->
|
|
<meta property="og:title" content="@string.Format(Localizer["Meta_OpenGraph_Title"], User.Name, Customizations.Value.AppName)">
|
|
<meta property="og:description" content="@string.Format(Localizer["Meta_Description"], User.Name, Customizations.Value.AppName)">
|
|
<meta property="og:type" content="profile">
|
|
<meta property="og:image" content="@Navigation.ToAbsoluteUri("/api/user/pfp/" + User.Id)">
|
|
|
|
<meta property="og:site_name" content="@Customizations.Value.AppName">
|
|
@if (Features.Value.Rss) {
|
|
<link rel="alternate" type="application/rss+xml" title="RSS Feed on @Customizations.Value.AppName | User @User.FullName" href="/rss/rss.xml?author=@User.Id">
|
|
<link rel="alternate" type="application/atom+xml" title="Atom RSS Feed on @Customizations.Value.AppName | User @User.FullName" href="/rss/atom.xml?author=@User.Id">
|
|
}
|
|
}
|
|
@if (User is null) {
|
|
<meta name="robots" content="noindex">
|
|
}
|
|
</HeadContent>
|
|
|
|
<PageTitle>@($"{(User?.FullName ?? Localizer["NotFound_Title"])} {TitlePostfix}")</PageTitle>
|
|
|
|
@if (User is null) {
|
|
<h1 class="text-3xl lg:text-5xl font-light mb-6 text-primary">@Localizer["NotFound_Title"]</h1>
|
|
<p class="my-3">@Localizer["NotFound_Description"]</p>
|
|
<a class="btn btn-primary" href="/">@Localizer["NotFound_BackToHome_Label"]</a>
|
|
} else {
|
|
<h1 class="text-3xl lg:text-5xl font-light mb-6 text-primary">@Localizer["Title"]</h1>
|
|
|
|
<section class="flex flex-col md:flex-row gap-x-8">
|
|
<div class="shrink-0 md:w-40 lg:w-56">
|
|
<ProfilePictureComponent ProfileId="@User.Id" Size="400" />
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<h2 class="text-2xl lg:text-4xl mb-3">@User.Name</h2>
|
|
<p class="mb-3 flex-1">@User.AboutTheAuthor</p>
|
|
<div class="flex gap-2 flex-wrap">
|
|
@foreach (var link in User.Links) {
|
|
<UserLinkComponent Link="link" class="badge hover:badge-outline flex gap-2 p-4" />
|
|
}
|
|
<UserContactBadges User="User" />
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<hr class="my-3" />
|
|
|
|
@if (!string.IsNullOrWhiteSpace(User.Biography)) {
|
|
<section>
|
|
<h2 class="text-2xl lg:text-4xl mb-3">@Localizer["Biography"]</h2>
|
|
<div class="prose prose-sm lg:prose-base prose-neutral max-w-none">
|
|
@((MarkupString) User.BiographyHtml)
|
|
</div>
|
|
</section>
|
|
<hr class="my-3" />
|
|
}
|
|
|
|
<section>
|
|
<h2 class="text-2xl lg:text-4xl mb-3">@Localizer["Articles"]</h2>
|
|
<ArticleCardList Articles="@User.Articles.OrderByDescending(a => a.PublishDate).ToList()" />
|
|
|
|
</section>
|
|
}
|
|
|
|
@code {
|
|
[CascadingParameter(Name = "TitlePostfix")]
|
|
private string TitlePostfix { get; set; } = default!;
|
|
[CascadingParameter]
|
|
public required HttpContext HttpContext { get; set; }
|
|
|
|
[Parameter]
|
|
public Guid? Id { get; set; }
|
|
|
|
private ApplicationUser? User { get; set; }
|
|
|
|
protected override async Task OnInitializedAsync() {
|
|
if (User is not null) return;
|
|
await using var context = await ContextFactory.CreateDbContextAsync();
|
|
|
|
// Find user
|
|
if (Id is not null) {
|
|
var now = DateTimeOffset.UtcNow;
|
|
User = await context.Users
|
|
.IgnoreAutoIncludes().IgnoreQueryFilters()
|
|
.Include(u => u.Articles
|
|
.Where(a => !a.IsDeleted &&
|
|
a.Status == ArticleStatus.Published &&
|
|
a.PublishDate <= now))
|
|
.ThenInclude(a => a.Categories)
|
|
.AsSplitQuery()
|
|
.FirstOrDefaultAsync(u => u.Id == Id.ToString());
|
|
}
|
|
|
|
// Validate access to user
|
|
if (User is not null && (User.Articles.Count > 0 || HttpContext.User.IsInRole("Admin"))) {
|
|
} else if (User is not null && HttpContext.User.FindFirst("Id")?.Value == User.Id) {
|
|
Message.ShowWarning(Localizer["ProfileNotPublic_Message"]);
|
|
} else {
|
|
User = null;
|
|
}
|
|
}
|
|
|
|
}
|