kc token public key/token issue, path root set to 1

This commit is contained in:
h z
2024-12-06 10:04:03 +00:00
parent da1860a269
commit 6d96b658f0
7 changed files with 215 additions and 29 deletions

View File

@@ -10,7 +10,8 @@ import { okaidia } from "react-syntax-highlighter/dist/esm/styles/prism";
import "katex/dist/katex.min.css";
import "./MarkdownEditor.css";
import config from "../../config";
import {fetch_} from "../../utils/requestUtils";
import { fetch_ } from "../../utils/requestUtils";
import PathManager from "../PathManager";
const MarkdownEditor = () => {
const { roles } = useContext(AuthContext);
@@ -18,7 +19,7 @@ const MarkdownEditor = () => {
const { id } = useParams();
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [path, setPath] = useState("");
const [pathId, setPathId] = useState(1);
useEffect(() => {
if (id) {
@@ -29,10 +30,10 @@ const MarkdownEditor = () => {
.then((data) => {
setTitle(data.title);
setContent(data.content);
setPath(data.path);
setPathId(data.path_id);
})
.catch((err) => {
console.error("failed to load markdown", err);
console.error("Failed to load markdown", err);
});
}
}, [id]);
@@ -42,26 +43,27 @@ const MarkdownEditor = () => {
const method = id ? "PUT" : "POST";
fetch_(url, {
method,
body: JSON.stringify({ title, content, path }),
body: JSON.stringify({ title, content, path_id: pathId }),
}, {
use_cache: false,
use_token: true,
}).then((res) => {
if(res.ok)
if (res.ok) {
navigate("/");
else
} else {
return res.json().then((data) => {
throw new Error(data.error || "Failed to load markdown");
throw new Error(data.error || "Failed to save markdown");
});
}
}).catch((err) => {
console.error("failed to load markdown", err);
})
console.error("Failed to save markdown", err);
});
};
const hasPermission = roles.includes("admin") || roles.includes("creator");
if (!hasPermission)
if (!hasPermission) {
return <div className="notification is-danger">Permission Denied</div>;
}
return (
<div className="container mt-5 markdown-editor-container">
@@ -84,18 +86,13 @@ const MarkdownEditor = () => {
</div>
</div>
{/* Path Field */}
{/* PathManager Field */}
<div className="field">
<label className="label">Path</label>
<div className="control">
<input
className="input"
type="text"
placeholder="Enter path"
value={path}
onChange={(e) => setPath(e.target.value)}
/>
</div>
<PathManager
currentPathId={pathId}
onPathChange={setPathId}
/>
</div>
{/* Content Field */}

View File

@@ -58,14 +58,22 @@ const MainNavigation = () => {
<span className="button is-primary is-light">
{user.profile.name}
</span>
<button className="button is-danger" onClick={logout}>
<button
className="button is-danger"
onClick={logout}
type="button"
>
Logout
</button>
</div>
</div>
) : (
<div className="navbar-item">
<button className="button is-primary" onClick={login}>
<button
className="button is-primary"
onClick={login}
type="button"
>
Login
</button>
</div>

View File

@@ -118,12 +118,14 @@ const PathNode = ({ path, isRoot = false }) => {
<button
onClick={handleEdit}
className="button is-small is-info is-light"
type="button"
>
Edit
</button>
<button
onClick={handleDelete}
className="button is-small is-danger is-light"
type="button"
>
Delete
</button>

View File

@@ -0,0 +1,57 @@
.path-manager {
border: 1px solid #ddd;
border-radius: 8px;
padding: 1rem;
background-color: #f9f9f9;
}
.path-manager-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 1rem;
}
.current-path {
font-weight: bold;
font-size: 1rem;
}
.sub-paths {
list-style: none;
padding: 0;
margin: 0;
}
.sub-path-item {
padding: 0.5rem;
font-size: 1rem;
color: #4a4a4a;
border-bottom: 1px solid #ddd;
cursor: pointer;
transition: background-color 0.2s;
}
.sub-path-item:last-child {
border-bottom: none;
}
.sub-path-item:hover {
background-color: #f0f0f0;
color: #00d1b2;
}
.path-manager-footer {
margin-top: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.path-manager-footer .input {
flex: 1;
}
.path-manager-footer .button {
white-space: nowrap;
}

View File

@@ -0,0 +1,116 @@
import React, { useEffect, useState } from "react";
import { fetch_ } from "../utils/requestUtils";
import config from "../config";
import "./PathManager.css";
const PathManager = ({ currentPathId = 1, onPathChange }) => {
const [currentPath, setCurrentPath] = useState("");
const [currentId, setCurrentId] = useState(currentPathId);
const [subPaths, setSubPaths] = useState([]);
const [newDirName, setNewDirName] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
fetchSubPaths(currentId);
}, [currentId]);
const fetchSubPaths = (pathId) => {
setLoading(true);
fetch_(`${config.BACKEND_HOST}/api/path/parent/${pathId}`, {}, { use_cache: false, use_token: true })
.then((data) => setSubPaths(data))
.catch((error) => console.error("Failed to fetch subdirectories:", error))
.finally(() => setLoading(false));
};
const handleSubPathClick = (subPath) => {
setCurrentPath(`${currentPath}/${subPath.name}`);
setCurrentId(subPath.id);
onPathChange(subPath.id);
};
const handleBackClick = () => {
if (currentId === 1) return;
const pathSegments = currentPath.split("/").filter(Boolean);
pathSegments.pop();
setCurrentPath(pathSegments.length > 0 ? `/${pathSegments.join("/")}` : "");
const parentId = pathSegments.length > 0
? subPaths.find((path) => path.name === pathSegments[pathSegments.length - 1])?.id || 0
: 1;
setCurrentId(parentId);
onPathChange(parentId);
};
const handleAddDirectory = () => {
if (!newDirName.trim()) {
alert("Directory name cannot be empty.");
return;
}
fetch_(`${config.BACKEND_HOST}/api/path/`, {
method: "POST",
body: JSON.stringify({ name: newDirName.trim(), parent_id: currentId }),
}, { use_cache: false, use_token: true })
.then((newDir) => {
setSubPaths([...subPaths, newDir]);
setNewDirName("");
alert("Directory created successfully!");
})
.catch((error) => {
console.error("Failed to create directory:", error);
alert("Failed to create directory.");
});
};
return (
<div className="path-manager">
<div className="path-manager-header">
<button
className="button is-small is-danger"
onClick={handleBackClick}
disabled={currentId === 1}
type="button"
>
Back
</button>
<div className="current-path">Current Path: {currentPath || "/"}</div>
</div>
<div className="path-manager-body">
{loading ? (
<p>Loading subdirectories...</p>
) : (
<ul className="sub-paths">
{subPaths.map((subPath) => (
<li
key={subPath.id}
className="sub-path-item is-clickable"
onClick={() => handleSubPathClick(subPath)}
>
{subPath.name}
</li>
))}
</ul>
)}
</div>
<div className="path-manager-footer">
<input
className="input is-small"
type="text"
placeholder="New directory name"
value={newDirName}
onChange={(e) => setNewDirName(e.target.value)}
/>
<button
className="button is-small is-primary"
onClick={handleAddDirectory}
disabled={loading || !newDirName.trim()}
type="button"
>
Add Directory
</button>
</div>
</div>
);
};
export default PathManager;

View File

@@ -6,7 +6,6 @@ const PermissionGuard = ({rolesRequired, children}) => {
const hasPermission = rolesRequired.some((role) => roles.includes(role));
if (!hasPermission) {
console.log("F");
return null;
}
return children;

View File

@@ -1,3 +1,5 @@
import {data} from "react-router-dom";
const ongoingRequests = new Map();
@@ -40,9 +42,15 @@ export async function fetch_(url, init = {}, init_options = {}){
headers: {
...(init.headers || {}),
...(token ? {Authorization: `Bearer ${token}`} : {}),
...(init.method && ['PUT', 'POST'].includes(init.method.toUpperCase())
? {'Content-Type': 'application/json'}
: {}),
}
};
if(options.use_cache && ongoingRequests.has(options.cache_key)){
return ongoingRequests.get(options.cache_key);
}
const now = Date.now();
const cached_data = localStorage.getItem(options.cache_key);
if(options.use_cache && cached_data){
@@ -54,11 +62,13 @@ export async function fetch_(url, init = {}, init_options = {}){
try {
const fetchPromise = fetch(url, request_options)
.then((response) => {
if(!response.ok)
if(!response.ok) {
throw new Error(`RESPONSE_ERROR: ${response.status}`);
}
return response.json();
})
.then((data) => {
if (options.use_cache)
{
localStorage.setItem(
@@ -79,9 +89,6 @@ export async function fetch_(url, init = {}, init_options = {}){
}
throw error;
}
}