Encode usernames in API requests and navigation links to handle special characters.

This commit is contained in:
2025-06-23 21:33:55 +08:00
parent be067cc21a
commit 8136e32d55
4 changed files with 25 additions and 15 deletions

View File

@@ -581,7 +581,7 @@ class Network {
): Promise<PageResponse<Resource>> { ): Promise<PageResponse<Resource>> {
try { try {
const response = await axios.get( const response = await axios.get(
`${this.apiBaseUrl}/resource/user/${username}`, `${this.apiBaseUrl}/resource/user/${encodeURIComponent(username)}`,
{ {
params: { params: {
page, page,
@@ -978,7 +978,7 @@ class Network {
): Promise<PageResponse<CommentWithResource>> { ): Promise<PageResponse<CommentWithResource>> {
try { try {
const response = await axios.get( const response = await axios.get(
`${this.apiBaseUrl}/comments/user/${username}`, `${this.apiBaseUrl}/comments/user/${encodeURIComponent(username)}`,
{ {
params: { page }, params: { page },
}, },

View File

@@ -94,7 +94,9 @@ function ActivityCard({ activity }: { activity: Activity }) {
} else if (activity.type === ActivityType.ResourceCommented) { } else if (activity.type === ActivityType.ResourceCommented) {
content = ( content = (
<div className={"mt-2"}> <div className={"mt-2"}>
<div className={"text-sm mx-1 whitespace-pre-wrap"}>{activity.comment?.content}</div> <div className={"text-sm mx-1 whitespace-pre-wrap"}>
{activity.comment?.content}
</div>
<div className={"flex items-center mt-1"}> <div className={"flex items-center mt-1"}>
<MdArrowRight /> <MdArrowRight />
<span className={"text-sm text-base-content/80"}> <span className={"text-sm text-base-content/80"}>

View File

@@ -161,7 +161,7 @@ export default function ResourcePage() {
})} })}
<button <button
onClick={() => { onClick={() => {
navigate(`/user/${resource.author.username}`); navigate(`/user/${encodeURIComponent(resource.author.username)}`);
}} }}
className="border-b-2 mx-4 py-1 cursor-pointer border-transparent hover:border-primary transition-colors duration-200 ease-in-out" className="border-b-2 mx-4 py-1 cursor-pointer border-transparent hover:border-primary transition-colors duration-200 ease-in-out"
> >
@@ -1276,7 +1276,9 @@ function CommentTile({ comment }: { comment: Comment }) {
<div className={"flex flex-row items-center my-1 mx-1"}> <div className={"flex flex-row items-center my-1 mx-1"}>
<div <div
className="avatar cursor-pointer" className="avatar cursor-pointer"
onClick={() => navigate(`/user/${comment.user.username}`)} onClick={() =>
navigate(`/user/${encodeURIComponent(comment.user.username)}`)
}
> >
<div className="w-8 rounded-full"> <div className="w-8 rounded-full">
<img src={network.getUserAvatar(comment.user)} alt={"avatar"} /> <img src={network.getUserAvatar(comment.user)} alt={"avatar"} />
@@ -1285,7 +1287,9 @@ function CommentTile({ comment }: { comment: Comment }) {
<div className={"w-2"}></div> <div className={"w-2"}></div>
<div <div
className={"text-sm font-bold cursor-pointer"} className={"text-sm font-bold cursor-pointer"}
onClick={() => navigate(`/user/${comment.user.username}`)} onClick={() => {
navigate(`/user/${encodeURIComponent(comment.user.username)}`);
}}
> >
{comment.user.username} {comment.user.username}
</div> </div>
@@ -1388,11 +1392,7 @@ function DeleteFileDialog({
); );
} }
function EditCommentDialog({ function EditCommentDialog({ comment }: { comment: Comment }) {
comment,
}: {
comment: Comment;
}) {
const [isLoading, setLoading] = useState(false); const [isLoading, setLoading] = useState(false);
const [content, setContent] = useState(comment.content); const [content, setContent] = useState(comment.content);
const { t } = useTranslation(); const { t } = useTranslation();
@@ -1474,7 +1474,10 @@ function DeleteCommentDialog({ commentId }: { commentId: number }) {
const dialog = document.getElementById(id) as HTMLDialogElement; const dialog = document.getElementById(id) as HTMLDialogElement;
dialog.close(); dialog.close();
if (res.success) { if (res.success) {
showToast({ message: t("Comment deleted successfully"), type: "success" }); showToast({
message: t("Comment deleted successfully"),
type: "success",
});
reload(); reload();
} else { } else {
showToast({ message: res.message, type: "error" }); showToast({ message: res.message, type: "error" });
@@ -1498,7 +1501,9 @@ function DeleteCommentDialog({ commentId }: { commentId: number }) {
<div className="modal-box"> <div className="modal-box">
<h3 className="font-bold text-lg">{t("Delete Comment")}</h3> <h3 className="font-bold text-lg">{t("Delete Comment")}</h3>
<p className="py-4"> <p className="py-4">
{t("Are you sure you want to delete this comment? This action cannot be undone.")} {t(
"Are you sure you want to delete this comment? This action cannot be undone.",
)}
</p> </p>
<div className="modal-action"> <div className="modal-action">
<form method="dialog"> <form method="dialog">

View File

@@ -11,7 +11,10 @@ import { MdOutlineArrowRight } from "react-icons/md";
export default function UserPage() { export default function UserPage() {
const [user, setUser] = useState<User | null>(null); const [user, setUser] = useState<User | null>(null);
const { username } = useParams(); const { username: rawUsername } = useParams();
// 解码用户名,确保特殊字符被还原
const username = rawUsername ? decodeURIComponent(rawUsername) : "";
const [page, setPage] = useState(0); const [page, setPage] = useState(0);