Skip to content

Commit 9420de6

Browse files
committed
feat: adding a request interception middleware for website maintenance
1 parent 9419ea2 commit 9420de6

File tree

2 files changed

+168
-143
lines changed

2 files changed

+168
-143
lines changed
Lines changed: 145 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,143 +1,145 @@
1-
'use client'
2-
3-
import toast from 'react-hot-toast'
4-
import { useEffect, useState } from 'react'
5-
import {
6-
Button,
7-
Link,
8-
Modal,
9-
ModalBody,
10-
ModalContent,
11-
ModalFooter,
12-
ModalHeader
13-
} from '@heroui/react'
14-
import { kunFetchGet, kunFetchPost } from '~/utils/kunFetch'
15-
import { KunCaptchaCanvas } from './CaptchaCanvas'
16-
import { KunLoading } from '../Loading'
17-
import { kunCaptchaErrorMessageMap } from '~/constants/captcha'
18-
import type { KunCaptchaImage } from './captcha'
19-
20-
interface CaptchaModalProps {
21-
isOpen: boolean
22-
onClose: () => void
23-
onSuccess: (code: string) => void
24-
hint?: string
25-
}
26-
27-
export const KunCaptchaModal = ({
28-
isOpen,
29-
onClose,
30-
onSuccess,
31-
hint
32-
}: CaptchaModalProps) => {
33-
const [selectedImages, setSelectedImages] = useState<Set<string>>(new Set())
34-
const [images, setImages] = useState<KunCaptchaImage[]>([])
35-
const [sessionId, setSessionId] = useState<string>('')
36-
const [loading, setLoading] = useState(true)
37-
const [errorCount, setErrorCount] = useState(0)
38-
39-
useEffect(() => {
40-
if (isOpen) {
41-
loadCaptcha()
42-
}
43-
}, [isOpen])
44-
45-
const loadCaptcha = async () => {
46-
if (errorCount < 6) {
47-
setErrorCount((prev) => prev + 1)
48-
}
49-
50-
setLoading(true)
51-
const { images, sessionId } = await kunFetchGet<{
52-
images: KunCaptchaImage[]
53-
sessionId: string
54-
}>('/auth/captcha')
55-
56-
setImages(images)
57-
setSessionId(sessionId)
58-
setSelectedImages(new Set())
59-
60-
setLoading(false)
61-
}
62-
63-
const toggleImageSelection = (id: string) => {
64-
const newSelection = new Set(selectedImages)
65-
if (newSelection.has(id)) {
66-
newSelection.delete(id)
67-
} else {
68-
newSelection.add(id)
69-
}
70-
setSelectedImages(newSelection)
71-
}
72-
73-
const handleVerify = async () => {
74-
const response = await kunFetchPost<KunResponse<{ code: string }>>(
75-
'/auth/captcha',
76-
{ sessionId, selectedIds: Array.from(selectedImages) }
77-
)
78-
if (typeof response === 'string') {
79-
toast.error(kunCaptchaErrorMessageMap[errorCount])
80-
loadCaptcha()
81-
} else {
82-
onSuccess(response.code)
83-
}
84-
}
85-
86-
return (
87-
<Modal isOpen={isOpen} onClose={onClose}>
88-
<ModalContent>
89-
<ModalHeader className="flex-col gap-2">
90-
<h3 className="text-lg">验证</h3>
91-
<p className="font-medium">请选择下面所有的 白毛 女孩子</p>
92-
{hint && (
93-
<p className="text-sm font-medium text-default-500">{hint}</p>
94-
)}
95-
</ModalHeader>
96-
<ModalBody>
97-
{loading ? (
98-
<KunLoading hint="正在加载验证..." />
99-
) : (
100-
<div className="grid grid-cols-2 gap-4">
101-
{images.map((image) => (
102-
<div key={image.id} className="aspect-square">
103-
<KunCaptchaCanvas
104-
image={image}
105-
isSelected={selectedImages.has(image.id)}
106-
onSelect={() => toggleImageSelection(image.id)}
107-
/>
108-
</div>
109-
))}
110-
</div>
111-
)}
112-
</ModalBody>
113-
<ModalFooter className="flex-col">
114-
<p className="text-sm">
115-
{' '}
116-
<Link
117-
size="sm"
118-
isExternal
119-
showAnchorIcon
120-
href="https://sticker.kungal.com"
121-
>
122-
鲲 Galgame 表情包
123-
</Link>{' '}
124-
提供技术支持
125-
</p>
126-
127-
<div className="ml-auto space-x-2">
128-
<Button color="danger" variant="light" onPress={onClose}>
129-
取消
130-
</Button>
131-
<Button
132-
color="primary"
133-
onPress={handleVerify}
134-
isDisabled={selectedImages.size === 0}
135-
>
136-
确定
137-
</Button>
138-
</div>
139-
</ModalFooter>
140-
</ModalContent>
141-
</Modal>
142-
)
143-
}
1+
'use client'
2+
3+
import toast from 'react-hot-toast'
4+
import { useEffect, useState } from 'react'
5+
import {
6+
Button,
7+
Link,
8+
Modal,
9+
ModalBody,
10+
ModalContent,
11+
ModalFooter,
12+
ModalHeader
13+
} from '@heroui/react'
14+
import { kunFetchGet, kunFetchPost } from '~/utils/kunFetch'
15+
import { KunCaptchaCanvas } from './CaptchaCanvas'
16+
import { KunLoading } from '../Loading'
17+
import { kunCaptchaErrorMessageMap } from '~/constants/captcha'
18+
import type { KunCaptchaImage } from './captcha'
19+
import { kunErrorHandler } from '~/utils/kunErrorHandler'
20+
21+
interface CaptchaModalProps {
22+
isOpen: boolean
23+
onClose: () => void
24+
onSuccess: (code: string) => void
25+
hint?: string
26+
}
27+
28+
export const KunCaptchaModal = ({
29+
isOpen,
30+
onClose,
31+
onSuccess,
32+
hint
33+
}: CaptchaModalProps) => {
34+
const [selectedImages, setSelectedImages] = useState<Set<string>>(new Set())
35+
const [images, setImages] = useState<KunCaptchaImage[]>([])
36+
const [sessionId, setSessionId] = useState<string>('')
37+
const [loading, setLoading] = useState(true)
38+
const [errorCount, setErrorCount] = useState(0)
39+
40+
useEffect(() => {
41+
if (isOpen) {
42+
loadCaptcha()
43+
}
44+
}, [isOpen])
45+
46+
const loadCaptcha = async () => {
47+
if (errorCount < 6) {
48+
setErrorCount((prev) => prev + 1)
49+
}
50+
51+
setLoading(true)
52+
const { images, sessionId } = await kunFetchGet<{
53+
images: KunCaptchaImage[]
54+
sessionId: string
55+
}>('/auth/captcha')
56+
57+
setImages(images)
58+
setSessionId(sessionId)
59+
setSelectedImages(new Set())
60+
61+
setLoading(false)
62+
}
63+
64+
const toggleImageSelection = (id: string) => {
65+
const newSelection = new Set(selectedImages)
66+
if (newSelection.has(id)) {
67+
newSelection.delete(id)
68+
} else {
69+
newSelection.add(id)
70+
}
71+
setSelectedImages(newSelection)
72+
}
73+
74+
const handleVerify = async () => {
75+
const response = await kunFetchPost<KunResponse<{ code: string }>>(
76+
'/auth/captcha',
77+
{ sessionId, selectedIds: Array.from(selectedImages) }
78+
)
79+
if (typeof response === 'string') {
80+
toast.error(response)
81+
toast.error(kunCaptchaErrorMessageMap[errorCount])
82+
loadCaptcha()
83+
} else {
84+
onSuccess(response.code)
85+
}
86+
}
87+
88+
return (
89+
<Modal isOpen={isOpen} onClose={onClose}>
90+
<ModalContent>
91+
<ModalHeader className="flex-col gap-2">
92+
<h3 className="text-lg">验证</h3>
93+
<p className="font-medium">请选择下面所有的 白毛 女孩子</p>
94+
{hint && (
95+
<p className="text-sm font-medium text-default-500">{hint}</p>
96+
)}
97+
</ModalHeader>
98+
<ModalBody>
99+
{loading ? (
100+
<KunLoading hint="正在加载验证..." />
101+
) : (
102+
<div className="grid grid-cols-2 gap-4">
103+
{images.map((image) => (
104+
<div key={image.id} className="aspect-square">
105+
<KunCaptchaCanvas
106+
image={image}
107+
isSelected={selectedImages.has(image.id)}
108+
onSelect={() => toggleImageSelection(image.id)}
109+
/>
110+
</div>
111+
))}
112+
</div>
113+
)}
114+
</ModalBody>
115+
<ModalFooter className="flex-col">
116+
<p className="text-sm">
117+
{' '}
118+
<Link
119+
size="sm"
120+
isExternal
121+
showAnchorIcon
122+
href="https://sticker.kungal.com"
123+
>
124+
鲲 Galgame 表情包
125+
</Link>{' '}
126+
提供技术支持
127+
</p>
128+
129+
<div className="ml-auto space-x-2">
130+
<Button color="danger" variant="light" onPress={onClose}>
131+
取消
132+
</Button>
133+
<Button
134+
color="primary"
135+
onPress={handleVerify}
136+
isDisabled={selectedImages.size === 0}
137+
>
138+
确定
139+
</Button>
140+
</div>
141+
</ModalFooter>
142+
</ModalContent>
143+
</Modal>
144+
)
145+
}

middleware.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { NextRequest } from 'next/server'
2+
import { NextResponse } from 'next/server'
3+
4+
export async function middleware(request: NextRequest) {
5+
const { pathname } = request.nextUrl
6+
const method = request.method.toUpperCase()
7+
8+
if (method === 'GET') {
9+
return NextResponse.next()
10+
}
11+
12+
if (pathname === '/api/patch/views' && method === 'PUT') {
13+
return NextResponse.next()
14+
}
15+
16+
const msg =
17+
'网站目前正在数据同步中, 约 2025 年 11 月 11 日晚 11 点完成同步(一天后),请一天后再来操作'
18+
return NextResponse.json(msg)
19+
}
20+
21+
export const config = {
22+
matcher: ['/api/:path*']
23+
}

0 commit comments

Comments
 (0)