forked from Kieran/void.cat
Inject tags to index.html
This commit is contained in:
parent
b9a9d7bd26
commit
c019dcb3fb
@ -23,4 +23,6 @@
|
|||||||
LICENSE
|
LICENSE
|
||||||
README.md
|
README.md
|
||||||
**/appsettings.*.json
|
**/appsettings.*.json
|
||||||
**/data
|
**/data
|
||||||
|
**/build
|
||||||
|
**/dist
|
@ -1,6 +1,6 @@
|
|||||||
using System.Text.RegularExpressions;
|
using AngleSharp;
|
||||||
|
using AngleSharp.Dom;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using VoidCat.Model;
|
using VoidCat.Model;
|
||||||
using VoidCat.Services.Abstractions;
|
using VoidCat.Services.Abstractions;
|
||||||
|
|
||||||
@ -10,11 +10,13 @@ public class IndexController : Controller
|
|||||||
{
|
{
|
||||||
private readonly IWebHostEnvironment _webHost;
|
private readonly IWebHostEnvironment _webHost;
|
||||||
private readonly IFileMetadataStore _fileMetadata;
|
private readonly IFileMetadataStore _fileMetadata;
|
||||||
|
private readonly VoidSettings _settings;
|
||||||
|
|
||||||
public IndexController(IFileMetadataStore fileMetadata, IWebHostEnvironment webHost)
|
public IndexController(IFileMetadataStore fileMetadata, IWebHostEnvironment webHost, VoidSettings settings)
|
||||||
{
|
{
|
||||||
_fileMetadata = fileMetadata;
|
_fileMetadata = fileMetadata;
|
||||||
_webHost = webHost;
|
_webHost = webHost;
|
||||||
|
_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -28,22 +30,57 @@ public class IndexController : Controller
|
|||||||
{
|
{
|
||||||
id.TryFromBase58Guid(out var gid);
|
id.TryFromBase58Guid(out var gid);
|
||||||
|
|
||||||
var manifestPath = Path.Combine(_webHost.WebRootPath, "asset-manifest.json");
|
var ubDownload = new UriBuilder(_settings.SiteUrl)
|
||||||
if (!System.IO.File.Exists(manifestPath)) return StatusCode(500);
|
{
|
||||||
|
Path = $"/d/{gid.ToBase58()}"
|
||||||
|
};
|
||||||
|
|
||||||
// old format hash, return 404
|
var ubView = new UriBuilder(_settings.SiteUrl)
|
||||||
if (id.Length == 40 && Regex.IsMatch(id, @"[0-9a-z]{40}"))
|
|
||||||
{
|
{
|
||||||
Response.StatusCode = 404;
|
Path = $"/{gid.ToBase58()}"
|
||||||
|
};
|
||||||
|
|
||||||
|
var indexPath = Path.Combine(_webHost.WebRootPath, "index.html");
|
||||||
|
var indexContent = await System.IO.File.ReadAllTextAsync(indexPath);
|
||||||
|
|
||||||
|
var meta = (await _fileMetadata.Get(gid))?.ToMeta(false);
|
||||||
|
var tags = new List<KeyValuePair<string, string>>()
|
||||||
|
{
|
||||||
|
new("site_name", "void.cat"),
|
||||||
|
new("title", meta?.Name ?? ""),
|
||||||
|
new("description", meta?.Description ?? ""),
|
||||||
|
new("url", ubView.Uri.ToString()),
|
||||||
|
};
|
||||||
|
|
||||||
|
var mime = meta?.MimeType;
|
||||||
|
if (mime?.StartsWith("image/") ?? false)
|
||||||
|
{
|
||||||
|
tags.Add(new("type", "image"));
|
||||||
|
tags.Add(new("image", ubDownload.Uri.ToString()));
|
||||||
|
tags.Add(new("image:type", mime));
|
||||||
}
|
}
|
||||||
|
else if (mime?.StartsWith("video/") ?? false)
|
||||||
var jsonManifest = await System.IO.File.ReadAllTextAsync(manifestPath);
|
|
||||||
return View("~/Pages/Index.cshtml", new IndexModel
|
|
||||||
{
|
{
|
||||||
Id = gid,
|
tags.Add(new("type", "video.other"));
|
||||||
Meta = (await _fileMetadata.Get(gid))?.ToMeta(false),
|
tags.Add(new("image", ""));
|
||||||
Manifest = JsonConvert.DeserializeObject<AssetManifest>(jsonManifest)!
|
tags.Add(new("video", ubDownload.Uri.ToString()));
|
||||||
});
|
tags.Add(new("video:url", ubDownload.Uri.ToString()));
|
||||||
|
tags.Add(new("video:secure_url", ubDownload.Uri.ToString()));
|
||||||
|
tags.Add(new("video:type", mime));
|
||||||
|
}
|
||||||
|
else if (mime?.StartsWith("audio/") ?? false)
|
||||||
|
{
|
||||||
|
tags.Add(new("type", "audio.other"));
|
||||||
|
tags.Add(new("audio", ubDownload.Uri.ToString()));
|
||||||
|
tags.Add(new("audio:type", mime));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tags.Add(new("type", "website"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var injectedHtml = await InjectTags(indexContent, tags);
|
||||||
|
return Content(injectedHtml?.ToHtml() ?? indexContent, "text/html");
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IndexModel
|
public class IndexModel
|
||||||
@ -59,4 +96,41 @@ public class IndexController : Controller
|
|||||||
public Dictionary<string, string> Files { get; init; }
|
public Dictionary<string, string> Files { get; init; }
|
||||||
public List<string> Entrypoints { get; init; }
|
public List<string> Entrypoints { get; init; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private async Task<IDocument?> InjectTags(string html, List<KeyValuePair<string, string>> tags)
|
||||||
|
{
|
||||||
|
var config = Configuration.Default;
|
||||||
|
var context = BrowsingContext.New(config);
|
||||||
|
var doc = await context.OpenAsync(c => c.Content(html));
|
||||||
|
|
||||||
|
foreach (var tag in tags)
|
||||||
|
{
|
||||||
|
var ogTag = doc.CreateElement("meta");
|
||||||
|
ogTag.SetAttribute("property", $"og:{tag.Key}");
|
||||||
|
ogTag.SetAttribute("content", tag.Value);
|
||||||
|
doc.Head?.AppendChild(ogTag);
|
||||||
|
switch (tag.Key.ToLower())
|
||||||
|
{
|
||||||
|
case "title":
|
||||||
|
{
|
||||||
|
var titleTag = doc.Head?.QuerySelector("title");
|
||||||
|
if (titleTag != default)
|
||||||
|
{
|
||||||
|
titleTag.TextContent = tag.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "description":
|
||||||
|
{
|
||||||
|
var descriptionTag = doc.Head?.QuerySelector("meta[name='description']");
|
||||||
|
descriptionTag?.SetAttribute("content", tag.Value);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
@using VoidCat.Model
|
|
||||||
@model VoidCat.Controllers.IndexController.IndexModel
|
|
||||||
@inject VoidSettings Settings
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
||||||
<meta name="theme-color" content="#000000"/>
|
|
||||||
<link rel="icon" href="/favicon.ico"/>
|
|
||||||
<link rel="apple-touch-icon" href="/logo.png"/>
|
|
||||||
<link rel="manifest" href="/manifest.json"/>
|
|
||||||
|
|
||||||
@if (Model.Meta != default)
|
|
||||||
{
|
|
||||||
var ubDownload = new UriBuilder(Settings.SiteUrl)
|
|
||||||
{
|
|
||||||
Path = $"/d/{Model.Id.ToBase58()}"
|
|
||||||
};
|
|
||||||
var ubView = new UriBuilder(Settings.SiteUrl)
|
|
||||||
{
|
|
||||||
Path = $"/{Model.Id.ToBase58()}"
|
|
||||||
};
|
|
||||||
|
|
||||||
<title>void.cat - @Model.Meta.Name</title>
|
|
||||||
<meta name="description" content="@Model.Meta.Description"/>
|
|
||||||
<meta property="og:site_name" content="void.cat"/>
|
|
||||||
<meta property="og:title" content="@Model.Meta.Name"/>
|
|
||||||
<meta property="og:description" content="@Model.Meta.Description"/>
|
|
||||||
<meta property="og:url" content="@ubView"/>
|
|
||||||
|
|
||||||
var mime = Model.Meta.MimeType;
|
|
||||||
if (!string.IsNullOrEmpty(mime))
|
|
||||||
{
|
|
||||||
if (mime.StartsWith("image/"))
|
|
||||||
{
|
|
||||||
<meta property="og:type" content="image"/>
|
|
||||||
<meta property="og:image" content="@ubDownload"/>
|
|
||||||
<meta property="og:image:type" content="@mime"/>
|
|
||||||
}
|
|
||||||
else if (mime.StartsWith("video/"))
|
|
||||||
{
|
|
||||||
<meta property="og:type" content="video.other"/>
|
|
||||||
<meta property="og:image" content=""/>
|
|
||||||
<meta property="og:video" content="@ubDownload"/>
|
|
||||||
<meta property="og:video:url" content="@ubDownload"/>
|
|
||||||
<meta property="og:video:secure_url" content="@ubDownload"/>
|
|
||||||
<meta property="og:video:type" content="@mime"/>
|
|
||||||
}
|
|
||||||
else if (mime.StartsWith("audio/"))
|
|
||||||
{
|
|
||||||
<meta property="og:type" content="audio.other"/>
|
|
||||||
<meta property="og:audio" content="@ubDownload"/>
|
|
||||||
<meta property="og:audio:type" content="@mime"/>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<title>void.cat</title>
|
|
||||||
<meta property="og:type" content="website"/>
|
|
||||||
<meta name="description" content="void.cat - free, simple file sharing."/>
|
|
||||||
}
|
|
||||||
|
|
||||||
@foreach (var ep in Model.Manifest.Entrypoints)
|
|
||||||
{
|
|
||||||
switch (System.IO.Path.GetExtension(ep))
|
|
||||||
{
|
|
||||||
case ".css":
|
|
||||||
{
|
|
||||||
<link rel="stylesheet" href="@ep"/>
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ".js":
|
|
||||||
{
|
|
||||||
<script defer src="@ep"></script>
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="root"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -13,6 +13,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AngleSharp" Version="1.0.7" />
|
||||||
<PackageReference Include="AWSSDK.S3" Version="3.7.103.41" />
|
<PackageReference Include="AWSSDK.S3" Version="3.7.103.41" />
|
||||||
<PackageReference Include="BencodeNET" Version="5.0.0" />
|
<PackageReference Include="BencodeNET" Version="5.0.0" />
|
||||||
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.3.21" />
|
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.3.21" />
|
||||||
|
@ -1,192 +1,192 @@
|
|||||||
import {
|
import {
|
||||||
AdminProfile,
|
AdminProfile,
|
||||||
AdminUserListResult,
|
AdminUserListResult,
|
||||||
ApiError,
|
ApiError,
|
||||||
ApiKey,
|
ApiKey,
|
||||||
LoginSession,
|
LoginSession,
|
||||||
PagedRequest,
|
PagedRequest,
|
||||||
PagedResponse,
|
PagedResponse,
|
||||||
PaymentOrder,
|
PaymentOrder,
|
||||||
Profile,
|
Profile,
|
||||||
SetPaymentConfigRequest,
|
SetPaymentConfigRequest,
|
||||||
SiteInfoResponse,
|
SiteInfoResponse,
|
||||||
VoidFileResponse,
|
VoidFileResponse,
|
||||||
} from "./index";
|
} from "./index";
|
||||||
import {
|
import {
|
||||||
ProgressHandler,
|
ProgressHandler,
|
||||||
ProxyChallengeHandler,
|
ProxyChallengeHandler,
|
||||||
StateChangeHandler,
|
StateChangeHandler,
|
||||||
VoidUploader,
|
VoidUploader,
|
||||||
} from "./upload";
|
} from "./upload";
|
||||||
import { StreamUploader } from "./stream-uploader";
|
import {StreamUploader} from "./stream-uploader";
|
||||||
import { XHRUploader } from "./xhr-uploader";
|
import {XHRUploader} from "./xhr-uploader";
|
||||||
|
|
||||||
export type AuthHandler = (url: string, method: string) => Promise<string>;
|
export type AuthHandler = (url: string, method: string) => Promise<string>;
|
||||||
|
|
||||||
export class VoidApi {
|
export class VoidApi {
|
||||||
readonly #uri: string;
|
readonly #uri: string;
|
||||||
readonly #auth?: AuthHandler;
|
readonly #auth?: AuthHandler;
|
||||||
|
|
||||||
constructor(uri: string, auth?: AuthHandler) {
|
constructor(uri?: string, auth?: AuthHandler) {
|
||||||
this.#uri = uri;
|
this.#uri = uri ?? "";
|
||||||
this.#auth = auth;
|
this.#auth = auth;
|
||||||
}
|
|
||||||
|
|
||||||
async #req<T>(method: string, url: string, body?: object): Promise<T> {
|
|
||||||
const absoluteUrl = `${this.#uri}${url}`;
|
|
||||||
const headers: HeadersInit = {
|
|
||||||
Accept: "application/json",
|
|
||||||
};
|
|
||||||
if (this.#auth) {
|
|
||||||
headers["Authorization"] = await this.#auth(absoluteUrl, method);
|
|
||||||
}
|
|
||||||
if (body) {
|
|
||||||
headers["Content-Type"] = "application/json";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetch(absoluteUrl, {
|
async #req<T>(method: string, url: string, body?: object): Promise<T> {
|
||||||
method,
|
const absoluteUrl = `${this.#uri}${url}`;
|
||||||
headers,
|
const headers: HeadersInit = {
|
||||||
mode: "cors",
|
Accept: "application/json",
|
||||||
body: body ? JSON.stringify(body) : undefined,
|
};
|
||||||
});
|
if (this.#auth) {
|
||||||
const text = await res.text();
|
headers["Authorization"] = await this.#auth(absoluteUrl, method);
|
||||||
if (res.ok) {
|
}
|
||||||
return text ? (JSON.parse(text) as T) : ({} as T);
|
if (body) {
|
||||||
} else {
|
headers["Content-Type"] = "application/json";
|
||||||
throw new ApiError(res.status, text);
|
}
|
||||||
|
|
||||||
|
const res = await fetch(absoluteUrl, {
|
||||||
|
method,
|
||||||
|
headers,
|
||||||
|
mode: "cors",
|
||||||
|
body: body ? JSON.stringify(body) : undefined,
|
||||||
|
});
|
||||||
|
const text = await res.text();
|
||||||
|
if (res.ok) {
|
||||||
|
return text ? (JSON.parse(text) as T) : ({} as T);
|
||||||
|
} else {
|
||||||
|
throw new ApiError(res.status, text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get uploader for uploading files
|
* Get uploader for uploading files
|
||||||
*/
|
*/
|
||||||
getUploader(
|
getUploader(
|
||||||
file: File | Blob,
|
file: File | Blob,
|
||||||
stateChange?: StateChangeHandler,
|
stateChange?: StateChangeHandler,
|
||||||
progress?: ProgressHandler,
|
progress?: ProgressHandler,
|
||||||
proxyChallenge?: ProxyChallengeHandler,
|
proxyChallenge?: ProxyChallengeHandler,
|
||||||
chunkSize?: number,
|
chunkSize?: number,
|
||||||
): VoidUploader {
|
): VoidUploader {
|
||||||
if (StreamUploader.canUse()) {
|
if (StreamUploader.canUse()) {
|
||||||
return new StreamUploader(
|
return new StreamUploader(
|
||||||
this.#uri,
|
this.#uri,
|
||||||
file,
|
file,
|
||||||
stateChange,
|
stateChange,
|
||||||
progress,
|
progress,
|
||||||
proxyChallenge,
|
proxyChallenge,
|
||||||
this.#auth,
|
this.#auth,
|
||||||
chunkSize,
|
chunkSize,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return new XHRUploader(
|
return new XHRUploader(
|
||||||
this.#uri,
|
this.#uri,
|
||||||
file,
|
file,
|
||||||
stateChange,
|
stateChange,
|
||||||
progress,
|
progress,
|
||||||
proxyChallenge,
|
proxyChallenge,
|
||||||
this.#auth,
|
this.#auth,
|
||||||
chunkSize,
|
chunkSize,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General site information
|
* General site information
|
||||||
*/
|
*/
|
||||||
info() {
|
info() {
|
||||||
return this.#req<SiteInfoResponse>("GET", "/info");
|
return this.#req<SiteInfoResponse>("GET", "/info");
|
||||||
}
|
}
|
||||||
|
|
||||||
fileInfo(id: string) {
|
fileInfo(id: string) {
|
||||||
return this.#req<VoidFileResponse>("GET", `/upload/${id}`);
|
return this.#req<VoidFileResponse>("GET", `/upload/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
setPaymentConfig(id: string, cfg: SetPaymentConfigRequest) {
|
setPaymentConfig(id: string, cfg: SetPaymentConfigRequest) {
|
||||||
return this.#req("POST", `/upload/${id}/payment`, cfg);
|
return this.#req("POST", `/upload/${id}/payment`, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
createOrder(id: string) {
|
createOrder(id: string) {
|
||||||
return this.#req<PaymentOrder>("GET", `/upload/${id}/payment`);
|
return this.#req<PaymentOrder>("GET", `/upload/${id}/payment`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOrder(file: string, order: string) {
|
getOrder(file: string, order: string) {
|
||||||
return this.#req<PaymentOrder>("GET", `/upload/${file}/payment/${order}`);
|
return this.#req<PaymentOrder>("GET", `/upload/${file}/payment/${order}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
login(username: string, password: string, captcha?: string) {
|
login(username: string, password: string, captcha?: string) {
|
||||||
return this.#req<LoginSession>("POST", `/auth/login`, {
|
return this.#req<LoginSession>("POST", `/auth/login`, {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
captcha,
|
captcha,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
register(username: string, password: string, captcha?: string) {
|
register(username: string, password: string, captcha?: string) {
|
||||||
return this.#req<LoginSession>("POST", `/auth/register`, {
|
return this.#req<LoginSession>("POST", `/auth/register`, {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
captcha,
|
captcha,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getUser(id: string) {
|
getUser(id: string) {
|
||||||
return this.#req<Profile>("GET", `/user/${id}`);
|
return this.#req<Profile>("GET", `/user/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUser(u: Profile) {
|
updateUser(u: Profile) {
|
||||||
return this.#req<void>("POST", `/user/${u.id}`, u);
|
return this.#req<void>("POST", `/user/${u.id}`, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
listUserFiles(uid: string, pageReq: PagedRequest) {
|
listUserFiles(uid: string, pageReq: PagedRequest) {
|
||||||
return this.#req<PagedResponse<VoidFileResponse>>(
|
return this.#req<PagedResponse<VoidFileResponse>>(
|
||||||
"POST",
|
"POST",
|
||||||
`/user/${uid}/files`,
|
`/user/${uid}/files`,
|
||||||
pageReq,
|
pageReq,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
submitVerifyCode(uid: string, code: string) {
|
submitVerifyCode(uid: string, code: string) {
|
||||||
return this.#req<void>("POST", `/user/${uid}/verify`, { code });
|
return this.#req<void>("POST", `/user/${uid}/verify`, {code});
|
||||||
}
|
}
|
||||||
|
|
||||||
sendNewCode(uid: string) {
|
sendNewCode(uid: string) {
|
||||||
return this.#req<void>("GET", `/user/${uid}/verify`);
|
return this.#req<void>("GET", `/user/${uid}/verify`);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFileMetadata(id: string, meta: any) {
|
updateFileMetadata(id: string, meta: any) {
|
||||||
return this.#req<void>("POST", `/upload/${id}/meta`, meta);
|
return this.#req<void>("POST", `/upload/${id}/meta`, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
listApiKeys() {
|
listApiKeys() {
|
||||||
return this.#req<Array<ApiKey>>("GET", `/auth/api-key`);
|
return this.#req<Array<ApiKey>>("GET", `/auth/api-key`);
|
||||||
}
|
}
|
||||||
|
|
||||||
createApiKey(req: any) {
|
createApiKey(req: any) {
|
||||||
return this.#req<ApiKey>("POST", `/auth/api-key`, req);
|
return this.#req<ApiKey>("POST", `/auth/api-key`, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
adminListFiles(pageReq: PagedRequest) {
|
adminListFiles(pageReq: PagedRequest) {
|
||||||
return this.#req<PagedResponse<VoidFileResponse>>(
|
return this.#req<PagedResponse<VoidFileResponse>>(
|
||||||
"POST",
|
"POST",
|
||||||
"/admin/file",
|
"/admin/file",
|
||||||
pageReq,
|
pageReq,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
adminDeleteFile(id: string) {
|
adminDeleteFile(id: string) {
|
||||||
return this.#req<void>("DELETE", `/admin/file/${id}`);
|
return this.#req<void>("DELETE", `/admin/file/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
adminUserList(pageReq: PagedRequest) {
|
adminUserList(pageReq: PagedRequest) {
|
||||||
return this.#req<PagedResponse<AdminUserListResult>>(
|
return this.#req<PagedResponse<AdminUserListResult>>(
|
||||||
"POST",
|
"POST",
|
||||||
`/admin/users`,
|
`/admin/users`,
|
||||||
pageReq,
|
pageReq,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
adminUpdateUser(u: AdminProfile) {
|
adminUpdateUser(u: AdminProfile) {
|
||||||
return this.#req<void>("POST", `/admin/update-user`, u);
|
return this.#req<void>("POST", `/admin/update-user`, u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,7 +248,7 @@ export function FilePreview() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (info) {
|
if (info) {
|
||||||
const fileLink = info.metadata?.url ?? `${import.meta.env.VITE_API_HOST}/d/${info.id}`;
|
const fileLink = info.metadata?.url ?? `${import.meta.env.VITE_API_HOST ?? ""}/d/${info.id}`;
|
||||||
setFileSize(info.metadata?.size ?? 0);
|
setFileSize(info.metadata?.size ?? 0);
|
||||||
|
|
||||||
const order = window.localStorage.getItem(`payment-${info.id}`);
|
const order = window.localStorage.getItem(`payment-${info.id}`);
|
||||||
|
@ -20,8 +20,9 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
assetsInclude: [],
|
assetsInclude: [],
|
||||||
build: {
|
build: {
|
||||||
outDir: "build",
|
outDir: "build"
|
||||||
},
|
},
|
||||||
|
base: "/",
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"files": {
|
|
||||||
"main.js": "/static/js/bundle.js",
|
|
||||||
"index.html": "/index.html",
|
|
||||||
"bundle.js.map": "/static/js/bundle.js.map",
|
|
||||||
},
|
|
||||||
"entrypoints": [
|
|
||||||
"static/js/bundle.js"
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user