fix encoding url in archive
This commit is contained in:
@@ -1,13 +1,24 @@
|
||||
export async function ffetch<T>(
|
||||
url: string,
|
||||
onSuccess: (res: T) => void,
|
||||
onError: (err: string) => void,
|
||||
opt?: RequestInit,
|
||||
) {
|
||||
import { tryCatch } from 'fp-ts/TaskEither'
|
||||
import { flow } from 'fp-ts/lib/function'
|
||||
|
||||
export const ffetch = <T>(url: string, opt?: RequestInit) => flow(
|
||||
tryCatch(
|
||||
() => fetcher<T>(url, opt),
|
||||
(e) => `error while fetching: ${e}`
|
||||
)
|
||||
)
|
||||
|
||||
const fetcher = async <T>(url: string, opt?: RequestInit) => {
|
||||
const res = await fetch(url, opt)
|
||||
if (!res.ok) {
|
||||
onError(await res.text())
|
||||
return
|
||||
|
||||
if (opt && !opt.headers) {
|
||||
opt.headers = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
}
|
||||
onSuccess(await res.json() as T)
|
||||
|
||||
if (!res.ok) {
|
||||
throw await res.text()
|
||||
}
|
||||
return res.json() as T
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { pipe } from 'fp-ts/lib/function'
|
||||
import type { RPCResponse } from "./types"
|
||||
|
||||
/**
|
||||
@@ -10,15 +11,6 @@ export function validateIP(ipAddr: string): boolean {
|
||||
return ipRegex.test(ipAddr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a domain via regex.
|
||||
* The validation pass if the domain respects the following formats:
|
||||
* - localhost
|
||||
* - domain.tld
|
||||
* - dir.domain.tld
|
||||
* @param domainName
|
||||
* @returns domain validity test
|
||||
*/
|
||||
export function validateDomain(url: string): boolean {
|
||||
const urlRegex = /(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/
|
||||
const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
|
||||
@@ -28,17 +20,6 @@ export function validateDomain(url: string): boolean {
|
||||
return urlRegex.test(url) || name === 'localhost' && slugRegex.test(slug)
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a domain via regex.
|
||||
* Exapmples
|
||||
* - http://example.com
|
||||
* - https://example.com
|
||||
* - http://www.example.com
|
||||
* - https://www.example.com
|
||||
* - http://10.0.0.1/[something]/[something-else]
|
||||
* @param url
|
||||
* @returns url validity test
|
||||
*/
|
||||
export function isValidURL(url: string): boolean {
|
||||
let urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/
|
||||
return urlRegex.test(url)
|
||||
@@ -93,4 +74,11 @@ export function mapProcessStatus(status: number) {
|
||||
}
|
||||
|
||||
export const prefersDarkMode = () =>
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
|
||||
export const base64URLEncode = (s: string) => pipe(
|
||||
s,
|
||||
s => String.fromCodePoint(...new TextEncoder().encode(s)),
|
||||
btoa,
|
||||
encodeURIComponent
|
||||
)
|
||||
@@ -26,22 +26,26 @@ import FolderIcon from '@mui/icons-material/Folder'
|
||||
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'
|
||||
import VideoFileIcon from '@mui/icons-material/VideoFile'
|
||||
|
||||
import { matchW } from 'fp-ts/lib/TaskEither'
|
||||
import { pipe } from 'fp-ts/lib/function'
|
||||
import { useEffect, useMemo, useState, useTransition } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { BehaviorSubject, Subject, combineLatestWith, map, share } from 'rxjs'
|
||||
import { serverURL } from '../atoms/settings'
|
||||
import { useObservable } from '../hooks/observable'
|
||||
import { useToast } from '../hooks/toast'
|
||||
import { useI18n } from '../hooks/useI18n'
|
||||
import { ffetch } from '../lib/httpClient'
|
||||
import { DeleteRequest, DirectoryEntry } from '../types'
|
||||
import { roundMiB } from '../utils'
|
||||
import { base64URLEncode, roundMiB } from '../utils'
|
||||
|
||||
export default function Downloaded() {
|
||||
const serverAddr = useRecoilValue(serverURL)
|
||||
const navigate = useNavigate()
|
||||
|
||||
const { i18n } = useI18n()
|
||||
const { pushMessage } = useToast()
|
||||
|
||||
const [openDialog, setOpenDialog] = useState(false)
|
||||
|
||||
@@ -50,20 +54,24 @@ export default function Downloaded() {
|
||||
|
||||
const [isPending, startTransition] = useTransition()
|
||||
|
||||
const fetcher = () => ffetch<DirectoryEntry[]>(
|
||||
`${serverAddr}/archive/downloaded`,
|
||||
(d) => files$.next(d),
|
||||
() => navigate('/login'),
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
const fetcher = () => pipe(
|
||||
ffetch<DirectoryEntry[]>(
|
||||
`${serverAddr}/archive/downloaded`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
subdir: '',
|
||||
})
|
||||
}
|
||||
),
|
||||
matchW(
|
||||
(e) => {
|
||||
pushMessage(e)
|
||||
navigate('/login')
|
||||
},
|
||||
body: JSON.stringify({
|
||||
subdir: '',
|
||||
})
|
||||
}
|
||||
)
|
||||
(d) => files$.next(d),
|
||||
)
|
||||
)()
|
||||
|
||||
const fetcherSubfolder = (sub: string) => {
|
||||
const folders = sub.startsWith('/')
|
||||
@@ -137,9 +145,7 @@ export default function Downloaded() {
|
||||
}, [serverAddr])
|
||||
|
||||
const onFileClick = (path: string) => startTransition(() => {
|
||||
const encoded = btoa(
|
||||
String.fromCodePoint(...new TextEncoder().encode(path))
|
||||
)
|
||||
const encoded = base64URLEncode(path)
|
||||
|
||||
window.open(`${serverAddr}/archive/d/${encoded}`)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user