服务器配置

This commit is contained in:
tianmo committed 2026-10-17 16:09:31 +08:00
1 parent a1b4a63552
commit fa7c8244b0
33 files changed
+1882 -363

No files matched your search

+5 -1
View File
@@ -218,6 +218,8 @@ export function useAuth() {
domainSeparation?: boolean
siteBaseUrl?: string
imageBaseUrl?: string
videoBaseUrl?: string
fileBaseUrl?: string
}): Promise<AuthActionResult> {
const validationError = validateAuthInput(input.username, input.password)
if (validationError) {
@@ -236,7 +238,9 @@ export function useAuth() {
allowRegistration: input.allowRegistration,
domainSeparation: input.domainSeparation,
siteBaseUrl: input.siteBaseUrl,
imageBaseUrl: input.imageBaseUrl
imageBaseUrl: input.imageBaseUrl,
videoBaseUrl: input.videoBaseUrl,
fileBaseUrl: input.fileBaseUrl
}
}
)
+39 -4
View File
@@ -47,6 +47,9 @@ async function copyToClipboard(text: string): Promise<boolean> {
export function useMediaUpload(kind: UploadMediaKind) {
const toast = useToast()
const { t } = useI18n()
const {
load: loadUploadPolicy
} = useUploadPolicy()
const {
autoCopyMarkdown,
copyFormat,
@@ -176,13 +179,45 @@ export function useMediaUpload(kind: UploadMediaKind) {
async function uploadFiles(files: File[]) {
if (!files.length || uploading.value) return
if (files.length > MAX_FILES) {
const currentPolicy = await loadUploadPolicy().catch(() => null)
const acceptedFiles = files.filter((file) => {
const extension = file.name.split('.').pop()?.toLowerCase() ?? ''
if (
kind === 'video'
&& currentPolicy
&& !currentPolicy.allowedVideoExtensions.includes(extension)
) {
toast.add({
title: `${file.name}:${t('files.videoFormatBlocked', {
format: extension ? extension.toUpperCase() : '—'
})}`,
color: 'error'
})
return false
}
if (
kind === 'file'
&& currentPolicy?.forbiddenFileExtensions.includes(extension)
) {
toast.add({
title: `${file.name}:${t('files.fileFormatBlocked', {
format: extension.toUpperCase()
})}`,
color: 'error'
})
return false
}
return true
})
if (!acceptedFiles.length) return
if (acceptedFiles.length > MAX_FILES) {
toast.add({ title: t('files.maxFiles', { n: MAX_FILES }), color: 'warning' })
return
}
uploading.value = true
progressItems.value = files.map(file => ({
progressItems.value = acceptedFiles.map(file => ({
name: file.name,
status: 'pending',
progress: 0
@@ -190,7 +225,7 @@ export function useMediaUpload(kind: UploadMediaKind) {
try {
const formData = new FormData()
for (const file of files) {
for (const file of acceptedFiles) {
formData.append('files', file, file.name)
}
@@ -215,7 +250,7 @@ export function useMediaUpload(kind: UploadMediaKind) {
await loadApiToken()
}
progressItems.value = files.map((file) => {
progressItems.value = acceptedFiles.map((file) => {
const failed = response.errors.find(error => error.name === file.name)
return {
name: file.name,
+40
View File
@@ -0,0 +1,40 @@
interface UploadPolicy {
allowedMimeTypes: string[]
allowedVideoExtensions: string[]
forbiddenFileExtensions: string[]
}
const policy = ref<UploadPolicy | null>(null)
const loading = ref(false)
let pending: Promise<UploadPolicy> | null = null
export function useUploadPolicy() {
async function load(force = false): Promise<UploadPolicy> {
if (policy.value && !force) return policy.value
if (pending && !force) return pending
loading.value = true
pending = $fetch<UploadPolicy>('/api/upload-policy', {
credentials: 'include'
})
.then((data) => {
policy.value = {
allowedMimeTypes: [...data.allowedMimeTypes],
allowedVideoExtensions: [...data.allowedVideoExtensions],
forbiddenFileExtensions: [...data.forbiddenFileExtensions]
}
return policy.value
})
.finally(() => {
loading.value = false
pending = null
})
return pending
}
return {
policy,
loading,
load
}
}