feat: add captcha support for user login and enhance user profile page

- Refactored userLogin function to include captcha handling.
- Introduced getCaptchaConfig API to fetch captcha configuration.
- Added Captcha component to handle different captcha providers (hCaptcha, reCaptcha, Turnstile).
- Updated LoginForm component to integrate captcha verification.
- Created UserProfile component to display user information with avatar.
- Implemented getUserByUsername API to fetch user details by username.
- Removed deprecated LoginRequest interface from user model.
- Enhanced navbar and layout with animation effects.
- Removed unused user page component and added dynamic user profile routing.
- Updated localization files to include captcha-related messages.
- Improved Gravatar component for better avatar handling.
This commit is contained in:
2025-09-10 21:15:36 +08:00
parent a7da023b1e
commit 4781d81869
28 changed files with 1048 additions and 701 deletions

63
web/pnpm-lock.yaml generated
View File

@ -8,6 +8,12 @@ importers:
.:
dependencies:
'@hcaptcha/react-hcaptcha':
specifier: ^1.12.1
version: 1.12.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@marsidev/react-turnstile':
specifier: ^1.3.0
version: 1.3.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-checkbox':
specifier: ^1.3.3
version: 1.3.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@ -71,6 +77,9 @@ importers:
react-dom:
specifier: 19.1.0
version: 19.1.0(react@19.1.0)
react-google-recaptcha-v3:
specifier: ^1.11.0
version: 1.11.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react-icons:
specifier: ^5.5.0
version: 5.5.0(react@19.1.0)
@ -130,6 +139,10 @@ packages:
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
engines: {node: '>=6.9.0'}
'@babel/runtime@7.28.4':
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
engines: {node: '>=6.9.0'}
'@emnapi/core@1.4.4':
resolution: {integrity: sha512-A9CnAbC6ARNMKcIcrQwq6HeHCjpcBZ5wSx4U01WXCqEKlrzB9F9315WDNHkrs2xbx7YjjSxbUYxuN6EQzpcY2g==}
@ -195,6 +208,15 @@ packages:
'@formatjs/intl-localematcher@0.6.1':
resolution: {integrity: sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==}
'@hcaptcha/loader@2.0.1':
resolution: {integrity: sha512-L36qqdOmv8fL6VBZcH34JUI0/SvC5KPOZ5N/m+5pQAPPhtXXRdU4o9iosZr12hWAM2qf5hC92kmi+XdqxKOEZQ==}
'@hcaptcha/react-hcaptcha@1.12.1':
resolution: {integrity: sha512-/A08MOAHa5L9B8UfNRkTR/+x2dOyfk3pI1/qgXI4NpDl/z4CjnSxaYCDtkbD21vEocN1KKCggQD3wJ7OcY494w==}
peerDependencies:
react: '>= 16.3.0'
react-dom: '>= 16.3.0'
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@ -354,6 +376,12 @@ packages:
'@jridgewell/trace-mapping@0.3.29':
resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
'@marsidev/react-turnstile@1.3.0':
resolution: {integrity: sha512-VO99Nynt+j4ETfMImQCj5LgbUKZ9mWPpy3RjP/3e/3vZu+FIphjEdU6g+cq4FeDoNshSxLlRzBTKcH5JMeM1GQ==}
peerDependencies:
react: ^17.0.2 || ^18.0.0 || ^19.0
react-dom: ^17.0.2 || ^18.0.0 || ^19.0
'@mdx-js/mdx@3.1.0':
resolution: {integrity: sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==}
@ -1689,6 +1717,9 @@ packages:
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
engines: {node: '>=12.0.0'}
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@ -2320,6 +2351,12 @@ packages:
peerDependencies:
react: ^19.1.0
react-google-recaptcha-v3@1.11.0:
resolution: {integrity: sha512-kLQqpz/77m8+trpBwzqcxNtvWZYoZ/YO6Vm2cVTHW8hs80BWUfDpC7RDwuAvpswwtSYApWfaSpIDFWAIBNIYxQ==}
peerDependencies:
react: ^16.3 || ^17.0 || ^18.0 || ^19.0
react-dom: ^17.0 || ^18.0 || ^19.0
react-icons@5.5.0:
resolution: {integrity: sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==}
peerDependencies:
@ -2788,6 +2825,8 @@ snapshots:
'@babel/helper-validator-identifier@7.27.1': {}
'@babel/runtime@7.28.4': {}
'@emnapi/core@1.4.4':
dependencies:
'@emnapi/wasi-threads': 1.0.3
@ -2878,6 +2917,15 @@ snapshots:
dependencies:
tslib: 2.8.1
'@hcaptcha/loader@2.0.1': {}
'@hcaptcha/react-hcaptcha@1.12.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@babel/runtime': 7.28.4
'@hcaptcha/loader': 2.0.1
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.6':
@ -2995,6 +3043,11 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.4
'@marsidev/react-turnstile@1.3.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
'@mdx-js/mdx@3.1.0(acorn@8.15.0)':
dependencies:
'@types/estree': 1.0.8
@ -4499,6 +4552,10 @@ snapshots:
highlight.js@11.11.1: {}
hoist-non-react-statics@3.3.2:
dependencies:
react-is: 16.13.1
ignore@5.3.2: {}
ignore@7.0.5: {}
@ -5313,6 +5370,12 @@ snapshots:
react: 19.1.0
scheduler: 0.26.0
react-google-recaptcha-v3@1.11.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies:
hoist-non-react-statics: 3.3.2
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
react-icons@5.5.0(react@19.1.0):
dependencies:
react: 19.1.0