🗑️ Remove built-in frontend serving code
This commit is contained in:
@@ -1,24 +0,0 @@
|
|||||||
using DysonNetwork.Shared.Data;
|
|
||||||
using DysonNetwork.Shared.PageData;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Drive.Pages.Data;
|
|
||||||
|
|
||||||
public class VersionPageData : IPageDataProvider
|
|
||||||
{
|
|
||||||
public bool CanHandlePath(PathString path) => true;
|
|
||||||
|
|
||||||
public Task<IDictionary<string, object?>> GetAppDataAsync(HttpContext context)
|
|
||||||
{
|
|
||||||
var versionData = new AppVersion
|
|
||||||
{
|
|
||||||
Version = ThisAssembly.AssemblyVersion,
|
|
||||||
Commit = ThisAssembly.GitCommitId,
|
|
||||||
UpdateDate = ThisAssembly.GitCommitDate
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = typeof(AppVersion).GetProperties()
|
|
||||||
.ToDictionary(property => property.Name, property => property.GetValue(versionData));
|
|
||||||
|
|
||||||
return Task.FromResult<IDictionary<string, object?>>(result);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,9 +1,7 @@
|
|||||||
using DysonNetwork.Drive;
|
using DysonNetwork.Drive;
|
||||||
using DysonNetwork.Drive.Pages.Data;
|
|
||||||
using DysonNetwork.Drive.Startup;
|
using DysonNetwork.Drive.Startup;
|
||||||
using DysonNetwork.Shared.Auth;
|
using DysonNetwork.Shared.Auth;
|
||||||
using DysonNetwork.Shared.Http;
|
using DysonNetwork.Shared.Http;
|
||||||
using DysonNetwork.Shared.PageData;
|
|
||||||
using DysonNetwork.Shared.Registry;
|
using DysonNetwork.Shared.Registry;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using tusdotnet.Stores;
|
using tusdotnet.Stores;
|
||||||
@@ -35,8 +33,6 @@ builder.Services.AddAppBusinessServices();
|
|||||||
// Add scheduled jobs
|
// Add scheduled jobs
|
||||||
builder.Services.AddAppScheduledJobs();
|
builder.Services.AddAppScheduledJobs();
|
||||||
|
|
||||||
builder.Services.AddTransient<IPageDataProvider, VersionPageData>();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
app.MapDefaultEndpoints();
|
app.MapDefaultEndpoints();
|
||||||
@@ -48,13 +44,6 @@ using (var scope = app.Services.CreateScope())
|
|||||||
await db.Database.MigrateAsync();
|
await db.Database.MigrateAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
var tusDiskStore = app.Services.GetRequiredService<TusDiskStore>();
|
|
||||||
|
|
||||||
// Configure application middleware pipeline
|
|
||||||
app.ConfigureAppMiddleware(tusDiskStore, builder.Environment.ContentRootPath);
|
|
||||||
|
|
||||||
app.MapPages(Path.Combine(app.Environment.WebRootPath, "dist", "index.html"));
|
|
||||||
|
|
||||||
// Configure gRPC
|
// Configure gRPC
|
||||||
app.ConfigureGrpcServices();
|
app.ConfigureGrpcServices();
|
||||||
|
|
||||||
|
@@ -7,7 +7,7 @@ namespace DysonNetwork.Drive.Startup;
|
|||||||
|
|
||||||
public static class ApplicationBuilderExtensions
|
public static class ApplicationBuilderExtensions
|
||||||
{
|
{
|
||||||
public static WebApplication ConfigureAppMiddleware(this WebApplication app, ITusStore tusStore, string contentRoot)
|
public static WebApplication ConfigureAppMiddleware(this WebApplication app, ITusStore tusStore)
|
||||||
{
|
{
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
@@ -28,12 +28,6 @@ public static class ApplicationBuilderExtensions
|
|||||||
.AllowAnyMethod()
|
.AllowAnyMethod()
|
||||||
);
|
);
|
||||||
|
|
||||||
app.UseDefaultFiles();
|
|
||||||
app.UseStaticFiles(new StaticFileOptions
|
|
||||||
{
|
|
||||||
FileProvider = new PhysicalFileProvider(Path.Combine(contentRoot, "wwwroot", "dist"))
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapTus("/api/tus", _ => Task.FromResult(TusService.BuildConfiguration(tusStore, app.Configuration)));
|
app.MapTus("/api/tus", _ => Task.FromResult(TusService.BuildConfiguration(tusStore, app.Configuration)));
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
|
@@ -2,8 +2,8 @@ using System.Globalization;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using DysonNetwork.Pass.Auth;
|
using DysonNetwork.Pass.Auth;
|
||||||
using DysonNetwork.Pass.Auth.OpenId;
|
using DysonNetwork.Pass.Auth.OpenId;
|
||||||
using DysonNetwork.Pass.Email;
|
|
||||||
using DysonNetwork.Pass.Localization;
|
using DysonNetwork.Pass.Localization;
|
||||||
|
using DysonNetwork.Pass.Mailer;
|
||||||
using DysonNetwork.Pass.Permission;
|
using DysonNetwork.Pass.Permission;
|
||||||
using DysonNetwork.Shared.Cache;
|
using DysonNetwork.Shared.Cache;
|
||||||
using DysonNetwork.Shared.Data;
|
using DysonNetwork.Shared.Data;
|
||||||
@@ -452,7 +452,7 @@ public class AccountService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
await mailer
|
await mailer
|
||||||
.SendTemplatedEmailAsync<Pages.Emails.VerificationEmail, VerificationEmailModel>(
|
.SendTemplatedEmailAsync<Emails.VerificationEmail, VerificationEmailModel>(
|
||||||
account.Nick,
|
account.Nick,
|
||||||
contact.Content,
|
contact.Content,
|
||||||
emailLocalizer["VerificationEmail"],
|
emailLocalizer["VerificationEmail"],
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using DysonNetwork.Pass.Email;
|
using DysonNetwork.Pass.Emails;
|
||||||
using DysonNetwork.Pass.Pages.Emails;
|
using DysonNetwork.Pass.Mailer;
|
||||||
using DysonNetwork.Pass.Permission;
|
using DysonNetwork.Pass.Permission;
|
||||||
using DysonNetwork.Shared.Cache;
|
using DysonNetwork.Shared.Cache;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@@ -136,13 +136,4 @@
|
|||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<AdditionalFiles Include="Pages\Emails\AccountDeletionEmail.razor" />
|
|
||||||
<AdditionalFiles Include="Pages\Emails\ContactVerificationEmail.razor" />
|
|
||||||
<AdditionalFiles Include="Pages\Emails\EmailLayout.razor" />
|
|
||||||
<AdditionalFiles Include="Pages\Emails\LandingEmail.razor" />
|
|
||||||
<AdditionalFiles Include="Pages\Emails\PasswordResetEmail.razor" />
|
|
||||||
<AdditionalFiles Include="Pages\Emails\VerificationEmail.razor" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace DysonNetwork.Pass.Email;
|
namespace DysonNetwork.Pass.Mailer;
|
||||||
|
|
||||||
public class LandingEmailModel
|
public class LandingEmailModel
|
||||||
{
|
{
|
@@ -1,7 +1,7 @@
|
|||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Email;
|
namespace DysonNetwork.Pass.Mailer;
|
||||||
|
|
||||||
public class EmailService(
|
public class EmailService(
|
||||||
RingService.RingServiceClient pusher,
|
RingService.RingServiceClient pusher,
|
@@ -1,15 +1,7 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
|
||||||
using RouteData = Microsoft.AspNetCore.Routing.RouteData;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Email;
|
namespace DysonNetwork.Pass.Mailer;
|
||||||
|
|
||||||
public class RazorViewRenderer(
|
public class RazorViewRenderer(
|
||||||
IServiceProvider serviceProvider,
|
IServiceProvider serviceProvider,
|
@@ -1,52 +0,0 @@
|
|||||||
using System.Net;
|
|
||||||
using DysonNetwork.Pass.Wallet;
|
|
||||||
using DysonNetwork.Shared.PageData;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using OpenGraphNet;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Pages.Data;
|
|
||||||
|
|
||||||
public class AccountPageData(AppDatabase db, SubscriptionService subscriptions, IConfiguration configuration)
|
|
||||||
: IPageDataProvider
|
|
||||||
{
|
|
||||||
private readonly string _siteUrl = configuration["SiteUrl"]!;
|
|
||||||
|
|
||||||
public bool CanHandlePath(PathString path) =>
|
|
||||||
path.StartsWithSegments("/accounts") || path.ToString().StartsWith("/@");
|
|
||||||
|
|
||||||
public async Task<IDictionary<string, object?>> GetAppDataAsync(HttpContext context)
|
|
||||||
{
|
|
||||||
var path = context.Request.Path.Value!;
|
|
||||||
var startIndex = path.StartsWith("/accounts/") ? "/accounts/".Length : "/@".Length;
|
|
||||||
var endIndex = path.IndexOf('/', startIndex);
|
|
||||||
var username = endIndex == -1 ? path[startIndex..] : path.Substring(startIndex, endIndex - startIndex);
|
|
||||||
username = WebUtility.UrlDecode(username);
|
|
||||||
if (username.StartsWith("@"))
|
|
||||||
username = username[1..];
|
|
||||||
|
|
||||||
var account = await db.Accounts
|
|
||||||
.Include(e => e.Badges)
|
|
||||||
.Include(e => e.Profile)
|
|
||||||
.Where(a => a.Name == username)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
if (account is null) return new Dictionary<string, object?>();
|
|
||||||
|
|
||||||
var perk = await subscriptions.GetPerkSubscriptionAsync(account.Id);
|
|
||||||
account.PerkSubscription = perk?.ToReference();
|
|
||||||
|
|
||||||
var og = OpenGraph.MakeGraph(
|
|
||||||
title: account.Nick,
|
|
||||||
type: "profile",
|
|
||||||
image: $"{_siteUrl}/cgi/drive/files/{account.Profile.Picture?.Id}?original=true",
|
|
||||||
url: $"{_siteUrl}/@{username}",
|
|
||||||
description: account.Profile.Bio ?? $"@{account.Name} profile on the Solar Network",
|
|
||||||
siteName: "Solarpass"
|
|
||||||
);
|
|
||||||
|
|
||||||
return new Dictionary<string, object?>()
|
|
||||||
{
|
|
||||||
["Account"] = account,
|
|
||||||
["OpenGraph"] = og
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,20 +0,0 @@
|
|||||||
using DysonNetwork.Shared.PageData;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Pages.Data;
|
|
||||||
|
|
||||||
public class CaptchaPageData(IConfiguration configuration) : IPageDataProvider
|
|
||||||
{
|
|
||||||
public bool CanHandlePath(PathString path) => path == "/captcha";
|
|
||||||
|
|
||||||
public Task<IDictionary<string, object?>> GetAppDataAsync(HttpContext context)
|
|
||||||
{
|
|
||||||
var provider = configuration.GetSection("Captcha")["Provider"]?.ToLower();
|
|
||||||
var apiKey = configuration.GetSection("Captcha")["ApiKey"];
|
|
||||||
|
|
||||||
return Task.FromResult<IDictionary<string, object?>>(new Dictionary<string, object?>
|
|
||||||
{
|
|
||||||
["Provider"] = provider,
|
|
||||||
["ApiKey"] = apiKey
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,24 +0,0 @@
|
|||||||
using DysonNetwork.Shared.Data;
|
|
||||||
using DysonNetwork.Shared.PageData;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Pages.Data;
|
|
||||||
|
|
||||||
public class VersionPageData : IPageDataProvider
|
|
||||||
{
|
|
||||||
public bool CanHandlePath(PathString path) => true;
|
|
||||||
|
|
||||||
public Task<IDictionary<string, object?>> GetAppDataAsync(HttpContext context)
|
|
||||||
{
|
|
||||||
var versionData = new AppVersion
|
|
||||||
{
|
|
||||||
Version = ThisAssembly.AssemblyVersion,
|
|
||||||
Commit = ThisAssembly.GitCommitId,
|
|
||||||
UpdateDate = ThisAssembly.GitCommitDate
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = typeof(AppVersion).GetProperties()
|
|
||||||
.ToDictionary(property => property.Name, property => property.GetValue(versionData));
|
|
||||||
|
|
||||||
return Task.FromResult<IDictionary<string, object?>>(result);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,8 +1,6 @@
|
|||||||
using DysonNetwork.Pass;
|
using DysonNetwork.Pass;
|
||||||
using DysonNetwork.Pass.Pages.Data;
|
|
||||||
using DysonNetwork.Pass.Startup;
|
using DysonNetwork.Pass.Startup;
|
||||||
using DysonNetwork.Shared.Http;
|
using DysonNetwork.Shared.Http;
|
||||||
using DysonNetwork.Shared.PageData;
|
|
||||||
using DysonNetwork.Shared.Registry;
|
using DysonNetwork.Shared.Registry;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
@@ -31,10 +29,6 @@ builder.Services.AddAppBusinessServices(builder.Configuration);
|
|||||||
// Add scheduled jobs
|
// Add scheduled jobs
|
||||||
builder.Services.AddAppScheduledJobs();
|
builder.Services.AddAppScheduledJobs();
|
||||||
|
|
||||||
builder.Services.AddTransient<IPageDataProvider, VersionPageData>();
|
|
||||||
builder.Services.AddTransient<IPageDataProvider, CaptchaPageData>();
|
|
||||||
builder.Services.AddTransient<IPageDataProvider, AccountPageData>();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
app.MapDefaultEndpoints();
|
app.MapDefaultEndpoints();
|
||||||
@@ -47,9 +41,7 @@ using (var scope = app.Services.CreateScope())
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure application middleware pipeline
|
// Configure application middleware pipeline
|
||||||
app.ConfigureAppMiddleware(builder.Configuration, builder.Environment.ContentRootPath);
|
app.ConfigureAppMiddleware(builder.Configuration);
|
||||||
|
|
||||||
app.MapPages(Path.Combine(builder.Environment.WebRootPath, "dist", "index.html"));
|
|
||||||
|
|
||||||
// Configure gRPC
|
// Configure gRPC
|
||||||
app.ConfigureGrpcServices();
|
app.ConfigureGrpcServices();
|
||||||
|
@@ -14,7 +14,7 @@ namespace DysonNetwork.Pass.Startup;
|
|||||||
|
|
||||||
public static class ApplicationConfiguration
|
public static class ApplicationConfiguration
|
||||||
{
|
{
|
||||||
public static WebApplication ConfigureAppMiddleware(this WebApplication app, IConfiguration configuration, string contentRoot)
|
public static WebApplication ConfigureAppMiddleware(this WebApplication app, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
app.MapMetrics();
|
app.MapMetrics();
|
||||||
app.MapOpenApi();
|
app.MapOpenApi();
|
||||||
@@ -41,12 +41,6 @@ public static class ApplicationConfiguration
|
|||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
app.UseMiddleware<PermissionMiddleware>();
|
app.UseMiddleware<PermissionMiddleware>();
|
||||||
|
|
||||||
app.UseDefaultFiles();
|
|
||||||
app.UseStaticFiles(new StaticFileOptions
|
|
||||||
{
|
|
||||||
FileProvider = new PhysicalFileProvider(Path.Combine(contentRoot, "wwwroot", "dist"))
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapControllers().RequireRateLimiting("fixed");
|
app.MapControllers().RequireRateLimiting("fixed");
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
|
@@ -2,7 +2,6 @@ using System.Globalization;
|
|||||||
using DysonNetwork.Pass.Account;
|
using DysonNetwork.Pass.Account;
|
||||||
using DysonNetwork.Pass.Auth;
|
using DysonNetwork.Pass.Auth;
|
||||||
using DysonNetwork.Pass.Auth.OpenId;
|
using DysonNetwork.Pass.Auth.OpenId;
|
||||||
using DysonNetwork.Pass.Email;
|
|
||||||
using DysonNetwork.Pass.Localization;
|
using DysonNetwork.Pass.Localization;
|
||||||
using DysonNetwork.Pass.Permission;
|
using DysonNetwork.Pass.Permission;
|
||||||
using DysonNetwork.Pass.Wallet;
|
using DysonNetwork.Pass.Wallet;
|
||||||
@@ -19,6 +18,7 @@ using DysonNetwork.Pass.Auth.OidcProvider.Services;
|
|||||||
using DysonNetwork.Pass.Credit;
|
using DysonNetwork.Pass.Credit;
|
||||||
using DysonNetwork.Pass.Handlers;
|
using DysonNetwork.Pass.Handlers;
|
||||||
using DysonNetwork.Pass.Leveling;
|
using DysonNetwork.Pass.Leveling;
|
||||||
|
using DysonNetwork.Pass.Mailer;
|
||||||
using DysonNetwork.Pass.Safety;
|
using DysonNetwork.Pass.Safety;
|
||||||
using DysonNetwork.Pass.Wallet.PaymentHandlers;
|
using DysonNetwork.Pass.Wallet.PaymentHandlers;
|
||||||
using DysonNetwork.Shared.Cache;
|
using DysonNetwork.Shared.Cache;
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Shared.PageData;
|
|
||||||
|
|
||||||
public interface IPageDataProvider
|
|
||||||
{
|
|
||||||
bool CanHandlePath(PathString path);
|
|
||||||
Task<IDictionary<string, object?>> GetAppDataAsync(HttpContext context);
|
|
||||||
}
|
|
@@ -1,80 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Routing;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using NodaTime;
|
|
||||||
using NodaTime.Serialization.SystemTextJson;
|
|
||||||
using OpenGraphNet;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Shared.PageData;
|
|
||||||
|
|
||||||
public static class PageStartup
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The method setup the single page application routes for you.
|
|
||||||
/// Before you calling this, ensure you have setup the static files and default files:
|
|
||||||
/// <code>
|
|
||||||
/// app.UseDefaultFiles();
|
|
||||||
/// app.UseStaticFiles(new StaticFileOptions
|
|
||||||
/// {
|
|
||||||
/// FileProvider = new PhysicalFileProvider(Path.Combine(contentRoot, "wwwroot", "dist"))
|
|
||||||
/// });
|
|
||||||
/// </code>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="app"></param>
|
|
||||||
/// <param name="defaultFile"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static WebApplication MapPages(this WebApplication app, string defaultFile)
|
|
||||||
{
|
|
||||||
var jsonOpts = new JsonSerializerOptions
|
|
||||||
{
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
|
||||||
DictionaryKeyPolicy = JsonNamingPolicy.SnakeCaseLower,
|
|
||||||
PropertyNameCaseInsensitive = true,
|
|
||||||
}.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
|
|
||||||
|
|
||||||
#pragma warning disable ASP0016
|
|
||||||
app.MapFallback(async context =>
|
|
||||||
{
|
|
||||||
if (context.Request.Path.StartsWithSegments("/api") || context.Request.Path.StartsWithSegments("/cgi"))
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = StatusCodes.Status404NotFound;
|
|
||||||
await context.Response.WriteAsync("Not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = await File.ReadAllTextAsync(defaultFile);
|
|
||||||
|
|
||||||
using var scope = app.Services.CreateScope();
|
|
||||||
var providers = scope.ServiceProvider.GetServices<IPageDataProvider>();
|
|
||||||
|
|
||||||
var matches = providers
|
|
||||||
.Where(p => p.CanHandlePath(context.Request.Path))
|
|
||||||
.Select(p => p.GetAppDataAsync(context))
|
|
||||||
.ToList();
|
|
||||||
var results = await Task.WhenAll(matches);
|
|
||||||
|
|
||||||
var appData = new Dictionary<string, object?>();
|
|
||||||
foreach (var result in results)
|
|
||||||
foreach (var (key, value) in result)
|
|
||||||
appData[key] = value;
|
|
||||||
|
|
||||||
OpenGraph? og = null;
|
|
||||||
if (appData.TryGetValue("OpenGraph", out var openGraph) && openGraph is OpenGraph gog)
|
|
||||||
og = gog;
|
|
||||||
|
|
||||||
var json = JsonSerializer.Serialize(appData, jsonOpts);
|
|
||||||
html = html.Replace("<app-data />", $"<script>window.DyPrefetch = {json};</script>");
|
|
||||||
|
|
||||||
if (og is not null)
|
|
||||||
html = html.Replace("<og-data />", og.ToString());
|
|
||||||
|
|
||||||
context.Response.ContentType = "text/html";
|
|
||||||
await context.Response.WriteAsync(html);
|
|
||||||
});
|
|
||||||
#pragma warning restore ASP0016
|
|
||||||
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,72 +0,0 @@
|
|||||||
using System.Net;
|
|
||||||
using DysonNetwork.Shared.PageData;
|
|
||||||
using DysonNetwork.Shared.Proto;
|
|
||||||
using DysonNetwork.Sphere.Post;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using OpenGraphNet;
|
|
||||||
|
|
||||||
namespace DysonNetwork.Sphere.PageData;
|
|
||||||
|
|
||||||
public class PostPageData(
|
|
||||||
AppDatabase db,
|
|
||||||
AccountService.AccountServiceClient accounts,
|
|
||||||
Publisher.PublisherService pub,
|
|
||||||
PostService ps,
|
|
||||||
IConfiguration configuration
|
|
||||||
)
|
|
||||||
: IPageDataProvider
|
|
||||||
{
|
|
||||||
private readonly string _siteUrl = configuration["SiteUrl"]!;
|
|
||||||
|
|
||||||
public bool CanHandlePath(PathString path) =>
|
|
||||||
path.StartsWithSegments("/posts");
|
|
||||||
|
|
||||||
public async Task<IDictionary<string, object?>> GetAppDataAsync(HttpContext context)
|
|
||||||
{
|
|
||||||
var path = context.Request.Path.Value!;
|
|
||||||
var startIndex = "/posts/".Length;
|
|
||||||
var endIndex = path.IndexOf('/', startIndex);
|
|
||||||
var slug = endIndex == -1 ? path[startIndex..] : path.Substring(startIndex, endIndex - startIndex);
|
|
||||||
slug = WebUtility.UrlDecode(slug);
|
|
||||||
|
|
||||||
var postId = Guid.TryParse(slug, out var postIdGuid) ? postIdGuid : Guid.Empty;
|
|
||||||
if (postId == Guid.Empty) return new Dictionary<string, object?>();
|
|
||||||
|
|
||||||
context.Items.TryGetValue("CurrentUser", out var currentUserValue);
|
|
||||||
var currentUser = currentUserValue as Account;
|
|
||||||
List<Guid> userFriends = [];
|
|
||||||
if (currentUser != null)
|
|
||||||
{
|
|
||||||
var friendsResponse = await accounts.ListFriendsAsync(new ListRelationshipSimpleRequest
|
|
||||||
{ AccountId = currentUser.Id });
|
|
||||||
userFriends = friendsResponse.AccountsId.Select(Guid.Parse).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
var userPublishers = currentUser is null ? [] : await pub.GetUserPublishers(Guid.Parse(currentUser.Id));
|
|
||||||
|
|
||||||
var post = await db.Posts
|
|
||||||
.Where(e => e.Id == postId)
|
|
||||||
.Include(e => e.Publisher)
|
|
||||||
.Include(e => e.Tags)
|
|
||||||
.Include(e => e.Categories)
|
|
||||||
.FilterWithVisibility(currentUser, userFriends, userPublishers)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
if (post == null) return new Dictionary<string, object?>();
|
|
||||||
post = await ps.LoadPostInfo(post, currentUser);
|
|
||||||
|
|
||||||
var og = OpenGraph.MakeGraph(
|
|
||||||
title: post.Title ?? $"Post from {post.Publisher.Name}",
|
|
||||||
type: "article",
|
|
||||||
image: $"{_siteUrl}/cgi/drive/files/{post.Publisher.Background?.Id}?original=true",
|
|
||||||
url: $"{_siteUrl}/@{slug}",
|
|
||||||
description: post.Description ?? (post.Content?.Length > 80 ? post.Content?[..80] : post.Content) ?? "Posted with some media",
|
|
||||||
siteName: "Solar Network"
|
|
||||||
);
|
|
||||||
|
|
||||||
return new Dictionary<string, object?>()
|
|
||||||
{
|
|
||||||
["Post"] = post,
|
|
||||||
["OpenGraph"] = og
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,9 +1,7 @@
|
|||||||
using DysonNetwork.Shared.Auth;
|
using DysonNetwork.Shared.Auth;
|
||||||
using DysonNetwork.Shared.Http;
|
using DysonNetwork.Shared.Http;
|
||||||
using DysonNetwork.Shared.PageData;
|
|
||||||
using DysonNetwork.Shared.Registry;
|
using DysonNetwork.Shared.Registry;
|
||||||
using DysonNetwork.Sphere;
|
using DysonNetwork.Sphere;
|
||||||
using DysonNetwork.Sphere.PageData;
|
|
||||||
using DysonNetwork.Sphere.Startup;
|
using DysonNetwork.Sphere.Startup;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
@@ -35,8 +33,6 @@ builder.Services.AddAppBusinessServices(builder.Configuration);
|
|||||||
// Add scheduled jobs
|
// Add scheduled jobs
|
||||||
builder.Services.AddAppScheduledJobs();
|
builder.Services.AddAppScheduledJobs();
|
||||||
|
|
||||||
builder.Services.AddTransient<IPageDataProvider, PostPageData>();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
app.MapDefaultEndpoints();
|
app.MapDefaultEndpoints();
|
||||||
@@ -51,12 +47,4 @@ using (var scope = app.Services.CreateScope())
|
|||||||
// Configure application middleware pipeline
|
// Configure application middleware pipeline
|
||||||
app.ConfigureAppMiddleware(builder.Configuration);
|
app.ConfigureAppMiddleware(builder.Configuration);
|
||||||
|
|
||||||
app.UseDefaultFiles();
|
|
||||||
app.UseStaticFiles(new StaticFileOptions
|
|
||||||
{
|
|
||||||
FileProvider = new PhysicalFileProvider(Path.Combine(app.Environment.ContentRootPath, "wwwroot", "dist"))
|
|
||||||
});
|
|
||||||
|
|
||||||
app.MapPages(Path.Combine(app.Environment.WebRootPath, "dist", "index.html"));
|
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
Reference in New Issue
Block a user