Compare commits
	
		
			2 commits
		
	
	
		
			4a38cad0a4
			...
			7598df6018
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7598df6018 | |||
| a69cadf0a1 | 
					 18 changed files with 187 additions and 155 deletions
				
			
		| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
    "@radix-ui/react-icons": "^1.3.0",
 | 
			
		||||
    "@radix-ui/react-label": "^2.0.2",
 | 
			
		||||
    "@radix-ui/react-radio-group": "^1.1.3",
 | 
			
		||||
    "@radix-ui/react-separator": "^1.0.3",
 | 
			
		||||
    "@radix-ui/react-slot": "^1.0.2",
 | 
			
		||||
    "@radix-ui/react-tooltip": "^1.0.7",
 | 
			
		||||
    "class-variance-authority": "^0.7.0",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ import ProfilePage from "@/page/profilesPage.tsx";
 | 
			
		|||
import ContentInfoPage from "@/page/contentInfoPage.tsx";
 | 
			
		||||
import SettingPage from "@/page/settingPage.tsx";
 | 
			
		||||
import ComicPage from "@/page/reader/comicPage.tsx";
 | 
			
		||||
import DifferencePage from "./page/differencePage.tsx";
 | 
			
		||||
 | 
			
		||||
const App = () => {
 | 
			
		||||
	const { isDarkMode } = useTernaryDarkMode();
 | 
			
		||||
| 
						 | 
				
			
			@ -38,9 +39,7 @@ const App = () => {
 | 
			
		|||
					<Route path="/doc/:id" component={ContentInfoPage}/>
 | 
			
		||||
					<Route path="/setting" component={SettingPage} />
 | 
			
		||||
					<Route path="/doc/:id/reader" component={ComicPage}/>
 | 
			
		||||
					{/* 
 | 
			
		||||
						<Route path="/difference" component={<DifferencePage />}/>
 | 
			
		||||
					*/}
 | 
			
		||||
					<Route path="/difference" component={DifferencePage}/>
 | 
			
		||||
					<Route component={NotFoundPage} />
 | 
			
		||||
				</Switch>
 | 
			
		||||
			</Layout>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -120,7 +120,8 @@ export default function TagInput({
 | 
			
		|||
                    setTags(tags.filter(x=>x!==tag));
 | 
			
		||||
                }}>{tag}</li>)}
 | 
			
		||||
            </ul>
 | 
			
		||||
            <input ref={inputRef} type="text" className="flex-1 border-0 ml-2 focus:border-0 focus:outline-none" placeholder="Add tag"
 | 
			
		||||
            <input ref={inputRef} type="text" className="flex-1 border-0 ml-2 focus:border-0 focus:outline-none
 | 
			
		||||
            bg-transparent text-sm" placeholder="Add tag"
 | 
			
		||||
                onFocus={() => setIsFocused(true)} onBlur={() => setIsFocused(false)}
 | 
			
		||||
                value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => {
 | 
			
		||||
                    if (e.key === "Enter") {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										29
									
								
								packages/client/src/components/ui/separator.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								packages/client/src/components/ui/separator.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
import * as React from "react"
 | 
			
		||||
import * as SeparatorPrimitive from "@radix-ui/react-separator"
 | 
			
		||||
 | 
			
		||||
import { cn } from "@/lib/utils"
 | 
			
		||||
 | 
			
		||||
const Separator = React.forwardRef<
 | 
			
		||||
  React.ElementRef<typeof SeparatorPrimitive.Root>,
 | 
			
		||||
  React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
 | 
			
		||||
>(
 | 
			
		||||
  (
 | 
			
		||||
    { className, orientation = "horizontal", decorative = true, ...props },
 | 
			
		||||
    ref
 | 
			
		||||
  ) => (
 | 
			
		||||
    <SeparatorPrimitive.Root
 | 
			
		||||
      ref={ref}
 | 
			
		||||
      decorative={decorative}
 | 
			
		||||
      orientation={orientation}
 | 
			
		||||
      className={cn(
 | 
			
		||||
        "shrink-0 bg-border",
 | 
			
		||||
        orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
 | 
			
		||||
        className
 | 
			
		||||
      )}
 | 
			
		||||
      {...props}
 | 
			
		||||
    />
 | 
			
		||||
  )
 | 
			
		||||
)
 | 
			
		||||
Separator.displayName = SeparatorPrimitive.Root.displayName
 | 
			
		||||
 | 
			
		||||
export { Separator }
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
export const BASE_API_URL = 'http://localhost:8080/';
 | 
			
		||||
export const BASE_API_URL = 'http://localhost:5173/';
 | 
			
		||||
 | 
			
		||||
export async function fetcher(url: string) {
 | 
			
		||||
    const u = new URL(url, BASE_API_URL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										38
									
								
								packages/client/src/hook/useDifference.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								packages/client/src/hook/useDifference.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
import useSWR, { mutate } from "swr";
 | 
			
		||||
import { fetcher } from "./fetcher";
 | 
			
		||||
 | 
			
		||||
type FileDifference = {
 | 
			
		||||
    type: string;
 | 
			
		||||
    value: {
 | 
			
		||||
        type: string;
 | 
			
		||||
        path: string;
 | 
			
		||||
    }[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function useDifferenceDoc() {
 | 
			
		||||
    return useSWR<FileDifference[]>("/api/diff/list", fetcher);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function commit(path: string, type: string) {
 | 
			
		||||
    const res = await fetch("/api/diff/commit", {
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        body: JSON.stringify([{ path, type }]),
 | 
			
		||||
        headers: {
 | 
			
		||||
            "Content-Type": "application/json",
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
    mutate("/api/diff/list");
 | 
			
		||||
    return res.ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function commitAll(type: string) {
 | 
			
		||||
    const res = await fetch("/api/diff/commitall", {
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        body: JSON.stringify({ type }),
 | 
			
		||||
        headers: {
 | 
			
		||||
            "Content-Type": "application/json",
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
    mutate("/api/diff/list");
 | 
			
		||||
    return res.ok;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,126 +0,0 @@
 | 
			
		|||
// import { Box, Button, Paper, Typography } from "@mui/material";
 | 
			
		||||
// import React, { useContext, useEffect, useState } from "react";
 | 
			
		||||
// import { CommonMenuList, Headline } from "../component/mod";
 | 
			
		||||
// import { UserContext } from "../state";
 | 
			
		||||
// import { PagePad } from "../component/pagepad";
 | 
			
		||||
 | 
			
		||||
// type FileDifference = {
 | 
			
		||||
// 	type: string;
 | 
			
		||||
// 	value: {
 | 
			
		||||
// 		type: string;
 | 
			
		||||
// 		path: string;
 | 
			
		||||
// 	}[];
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
// function TypeDifference(prop: {
 | 
			
		||||
// 	content: FileDifference;
 | 
			
		||||
// 	onCommit: (v: { type: string; path: string }) => void;
 | 
			
		||||
// 	onCommitAll: (type: string) => void;
 | 
			
		||||
// }) {
 | 
			
		||||
// 	// const classes = useStyles();
 | 
			
		||||
// 	const x = prop.content;
 | 
			
		||||
// 	const [button_disable, set_disable] = useState(false);
 | 
			
		||||
 | 
			
		||||
// 	return (
 | 
			
		||||
// 		<Paper /*className={classes.paper}*/>
 | 
			
		||||
// 			<Box /*className={classes.contentTitle}*/>
 | 
			
		||||
// 				<Typography variant="h3">{x.type}</Typography>
 | 
			
		||||
// 				<Button
 | 
			
		||||
// 					variant="contained"
 | 
			
		||||
// 					key={x.type}
 | 
			
		||||
// 					onClick={() => {
 | 
			
		||||
// 						set_disable(true);
 | 
			
		||||
// 						prop.onCommitAll(x.type);
 | 
			
		||||
// 						set_disable(false);
 | 
			
		||||
// 					}}
 | 
			
		||||
// 				>
 | 
			
		||||
// 					Commit all
 | 
			
		||||
// 				</Button>
 | 
			
		||||
// 			</Box>
 | 
			
		||||
// 			{x.value.map((y) => (
 | 
			
		||||
// 				<Box sx={{ display: "flex" }} key={y.path}>
 | 
			
		||||
// 					<Button
 | 
			
		||||
// 						variant="contained"
 | 
			
		||||
// 						onClick={() => {
 | 
			
		||||
// 							set_disable(true);
 | 
			
		||||
// 							prop.onCommit(y);
 | 
			
		||||
// 							set_disable(false);
 | 
			
		||||
// 						}}
 | 
			
		||||
// 						disabled={button_disable}
 | 
			
		||||
// 					>
 | 
			
		||||
// 						Commit
 | 
			
		||||
// 					</Button>
 | 
			
		||||
// 					<Typography variant="h5">{y.path}</Typography>
 | 
			
		||||
// 				</Box>
 | 
			
		||||
// 			))}
 | 
			
		||||
// 		</Paper>
 | 
			
		||||
// 	);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// export function DifferencePage() {
 | 
			
		||||
// 	const ctx = useContext(UserContext);
 | 
			
		||||
// 	// const classes = useStyles();
 | 
			
		||||
// 	const [diffList, setDiffList] = useState<FileDifference[]>([]);
 | 
			
		||||
// 	const doLoad = async () => {
 | 
			
		||||
// 		const list = await fetch("/api/diff/list");
 | 
			
		||||
// 		if (list.ok) {
 | 
			
		||||
// 			const inner = await list.json();
 | 
			
		||||
// 			setDiffList(inner);
 | 
			
		||||
// 		} else {
 | 
			
		||||
// 			// setDiffList([]);
 | 
			
		||||
// 		}
 | 
			
		||||
// 	};
 | 
			
		||||
// 	const Commit = async (x: { type: string; path: string }) => {
 | 
			
		||||
// 		const res = await fetch("/api/diff/commit", {
 | 
			
		||||
// 			method: "POST",
 | 
			
		||||
// 			body: JSON.stringify([{ ...x }]),
 | 
			
		||||
// 			headers: {
 | 
			
		||||
// 				"content-type": "application/json",
 | 
			
		||||
// 			},
 | 
			
		||||
// 		});
 | 
			
		||||
// 		const bb = await res.json();
 | 
			
		||||
// 		if (bb.ok) {
 | 
			
		||||
// 			doLoad();
 | 
			
		||||
// 		} else {
 | 
			
		||||
// 			console.error("fail to add document");
 | 
			
		||||
// 		}
 | 
			
		||||
// 	};
 | 
			
		||||
// 	const CommitAll = async (type: string) => {
 | 
			
		||||
// 		const res = await fetch("/api/diff/commitall", {
 | 
			
		||||
// 			method: "POST",
 | 
			
		||||
// 			body: JSON.stringify({ type: type }),
 | 
			
		||||
// 			headers: {
 | 
			
		||||
// 				"content-type": "application/json",
 | 
			
		||||
// 			},
 | 
			
		||||
// 		});
 | 
			
		||||
// 		const bb = await res.json();
 | 
			
		||||
// 		if (bb.ok) {
 | 
			
		||||
// 			doLoad();
 | 
			
		||||
// 		} else {
 | 
			
		||||
// 			console.error("fail to add document");
 | 
			
		||||
// 		}
 | 
			
		||||
// 	};
 | 
			
		||||
// 	useEffect(() => {
 | 
			
		||||
// 		doLoad();
 | 
			
		||||
// 		const i = setInterval(doLoad, 5000);
 | 
			
		||||
// 		return () => {
 | 
			
		||||
// 			clearInterval(i);
 | 
			
		||||
// 		};
 | 
			
		||||
// 	}, []);
 | 
			
		||||
// 	const menu = CommonMenuList();
 | 
			
		||||
// 	return (
 | 
			
		||||
// 		<Headline menu={menu}>
 | 
			
		||||
// 			<PagePad>
 | 
			
		||||
// 				{ctx.username == "admin" ? (
 | 
			
		||||
// 					<div>
 | 
			
		||||
// 						{diffList.map((x) => (
 | 
			
		||||
// 							<TypeDifference key={x.type} content={x} onCommit={Commit} onCommitAll={CommitAll} />
 | 
			
		||||
// 						))}
 | 
			
		||||
// 					</div>
 | 
			
		||||
// 				) : (
 | 
			
		||||
// 					<Typography variant="h2">Not Allowed : please login as an admin</Typography>
 | 
			
		||||
// 				)}
 | 
			
		||||
// 			</PagePad>
 | 
			
		||||
// 		</Headline>
 | 
			
		||||
// 	);
 | 
			
		||||
// }
 | 
			
		||||
							
								
								
									
										63
									
								
								packages/client/src/page/differencePage.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								packages/client/src/page/differencePage.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
import { Button } from "@/components/ui/button";
 | 
			
		||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
 | 
			
		||||
import { Separator } from "@/components/ui/separator";
 | 
			
		||||
import { useDifferenceDoc, commit, commitAll } from "@/hook/useDifference";
 | 
			
		||||
import { useLogin } from "@/state/user";
 | 
			
		||||
import { Fragment } from "react/jsx-runtime";
 | 
			
		||||
 | 
			
		||||
export function DifferencePage() {
 | 
			
		||||
    const { data, isLoading, error } = useDifferenceDoc();
 | 
			
		||||
    const userInfo = useLogin();
 | 
			
		||||
 | 
			
		||||
    if (!userInfo) {
 | 
			
		||||
        return <div className="p-4">
 | 
			
		||||
            <h2 className="text-3xl">
 | 
			
		||||
                Not logged in
 | 
			
		||||
            </h2>
 | 
			
		||||
        </div>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (error) {
 | 
			
		||||
        return <div>Error: {String(error)}</div>
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div className="p-4">
 | 
			
		||||
            <Card>
 | 
			
		||||
                <CardHeader className="relative">
 | 
			
		||||
                    <Button className="absolute right-2 top-8" variant="ghost"
 | 
			
		||||
                        onClick={() => commitAll("comic")}
 | 
			
		||||
                    >Commit All</Button>
 | 
			
		||||
                    <CardTitle className="text-2xl">Difference</CardTitle>
 | 
			
		||||
                    <CardDescription>Scanned Files List</CardDescription>
 | 
			
		||||
                </CardHeader>
 | 
			
		||||
                <CardContent>
 | 
			
		||||
                    <Separator decorative />
 | 
			
		||||
                    {isLoading && <div>Loading...</div>}
 | 
			
		||||
                    {data?.map((c) => {
 | 
			
		||||
                        const x = c.value;
 | 
			
		||||
                        return (
 | 
			
		||||
                            <Fragment key={c.type}>
 | 
			
		||||
                                {x.map((y) => (
 | 
			
		||||
                                    <div key={y.path} className="flex items-center mt-2">
 | 
			
		||||
                                        <p
 | 
			
		||||
                                        className="flex-1 text-sm text-wrap">{y.path}</p>
 | 
			
		||||
                                        <Button
 | 
			
		||||
                                            className="flex-none ml-2"
 | 
			
		||||
                                            variant="outline"
 | 
			
		||||
                                            onClick={() => commit(y.path, y.type)}
 | 
			
		||||
                                        >
 | 
			
		||||
                                            Commit
 | 
			
		||||
                                        </Button>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                ))}
 | 
			
		||||
                            </Fragment>
 | 
			
		||||
                        )
 | 
			
		||||
                    })}
 | 
			
		||||
                </CardContent>
 | 
			
		||||
            </Card>
 | 
			
		||||
        </div>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default DifferencePage;
 | 
			
		||||
| 
						 | 
				
			
			@ -24,9 +24,10 @@ function getUserSessions() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
export async function refresh() {
 | 
			
		||||
	const u = new URL("/user/refresh", BASE_API_URL);
 | 
			
		||||
	const u = new URL("/api/user/refresh", BASE_API_URL);
 | 
			
		||||
    const res = await fetch(u, {
 | 
			
		||||
        method: "POST",
 | 
			
		||||
		credentials: "include",
 | 
			
		||||
    });
 | 
			
		||||
    if (res.status !== 200) throw new Error("Maybe Network Error");
 | 
			
		||||
    const r = (await res.json()) as LoginLocalStorage & { refresh: boolean };
 | 
			
		||||
| 
						 | 
				
			
			@ -49,9 +50,10 @@ export async function refresh() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
export const doLogout = async () => {
 | 
			
		||||
	const u = new URL("/user/refresh", BASE_API_URL);
 | 
			
		||||
	const u = new URL("/api/user/logout", BASE_API_URL);
 | 
			
		||||
	const req = await fetch(u, {
 | 
			
		||||
		method: "POST",
 | 
			
		||||
		credentials: "include",
 | 
			
		||||
	});
 | 
			
		||||
    const setVal = setAtomValue(userLoginStateAtom);
 | 
			
		||||
	try {
 | 
			
		||||
| 
						 | 
				
			
			@ -79,11 +81,12 @@ export const doLogin = async (userLoginInfo: {
 | 
			
		|||
	username: string;
 | 
			
		||||
	password: string;
 | 
			
		||||
}): Promise<string | LoginLocalStorage> => {
 | 
			
		||||
	const u = new URL("/user/refresh", BASE_API_URL);
 | 
			
		||||
	const u = new URL("/api/user/login", BASE_API_URL);
 | 
			
		||||
	const res = await fetch(u, {
 | 
			
		||||
		method: "POST",
 | 
			
		||||
		body: JSON.stringify(userLoginInfo),
 | 
			
		||||
		headers: { "content-type": "application/json" },
 | 
			
		||||
		credentials: "include",
 | 
			
		||||
	});
 | 
			
		||||
	const b = await res.json();
 | 
			
		||||
	if (res.status !== 200) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
{
 | 
			
		||||
    "watch": []
 | 
			
		||||
    "watch": ["testdata"]
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import { extname } from "node:path";
 | 
			
		||||
import type { DocumentBody } from "../model/doc";
 | 
			
		||||
import type { DocumentBody } from "dbtype/api";
 | 
			
		||||
import { readZip } from "../util/zipwrap";
 | 
			
		||||
import { type ContentConstructOption, createDefaultClass, registerContentReferrer } from "./file";
 | 
			
		||||
import { TextWriter } from "@zip.js/zip.js";
 | 
			
		||||
| 
						 | 
				
			
			@ -29,19 +29,18 @@ export class ComicReferrer extends createDefaultClass("comic") {
 | 
			
		|||
		const zip = await readZip(this.path);
 | 
			
		||||
		const entries = await zip.reader.getEntries();
 | 
			
		||||
		this.pagenum = entries.filter((x) => ImageExt.includes(extname(x.filename))).length;
 | 
			
		||||
		const entry = entries.find(x=> x.filename === "desc.json");
 | 
			
		||||
		if (entry === undefined) {
 | 
			
		||||
		const descEntry = entries.find(x=> x.filename === "desc.json");
 | 
			
		||||
		if (descEntry === undefined) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (entry.getData === undefined) {
 | 
			
		||||
		if (descEntry.getData === undefined) {
 | 
			
		||||
			throw new Error("entry.getData is undefined");
 | 
			
		||||
		}
 | 
			
		||||
		const textWriter = new TextWriter();
 | 
			
		||||
		const data = (await entry.getData(textWriter));
 | 
			
		||||
		const data = (await descEntry.getData(textWriter));
 | 
			
		||||
		this.desc = JSON.parse(data);
 | 
			
		||||
		if (this.desc === undefined) {
 | 
			
		||||
			throw new Error(`JSON.parse is returning undefined. ${this.path} desc.json format error`);
 | 
			
		||||
		}
 | 
			
		||||
		zip.reader.close()
 | 
			
		||||
			.then(() => zip.handle.close());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	async createDocumentBody(): Promise<DocumentBody> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,7 @@
 | 
			
		|||
import { createHash } from "node:crypto";
 | 
			
		||||
import { promises, type Stats } from "node:fs";
 | 
			
		||||
import { Context, DefaultContext, DefaultState, Middleware, Next } from "koa";
 | 
			
		||||
import Router from "koa-router";
 | 
			
		||||
import path, { extname } from "node:path";
 | 
			
		||||
import type { DocumentBody } from "../model/mod";
 | 
			
		||||
import type { DocumentBody } from "dbtype/api";
 | 
			
		||||
/**
 | 
			
		||||
 * content file or directory referrer
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -40,8 +38,9 @@ export const createDefaultClass = (type: string): ContentFileConstructor => {
 | 
			
		|||
			this.stat = undefined;
 | 
			
		||||
		}
 | 
			
		||||
		async createDocumentBody(): Promise<DocumentBody> {
 | 
			
		||||
			console.log(`createDocumentBody: ${this.path}`);
 | 
			
		||||
			const { base, dir, name } = path.parse(this.path);
 | 
			
		||||
 | 
			
		||||
			
 | 
			
		||||
			const ret = {
 | 
			
		||||
				title: name,
 | 
			
		||||
				basepath: dir,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,11 +73,13 @@ class SqliteDocumentAccessor implements DocumentAccessor {
 | 
			
		|||
			await trx.insertInto("tags")
 | 
			
		||||
				.values(tags.map((x) => ({ name: x })))
 | 
			
		||||
				// on conflict is supported in sqlite and postgresql.
 | 
			
		||||
				.onConflict((oc) => oc.doNothing());
 | 
			
		||||
				.onConflict((oc) => oc.doNothing())
 | 
			
		||||
				.execute();
 | 
			
		||||
 | 
			
		||||
			if (tags.length > 0) {
 | 
			
		||||
				await trx.insertInto("doc_tag_relation")
 | 
			
		||||
					.values(tags.map((x) => ({ doc_id: id, tag_name: x })));
 | 
			
		||||
					.values(tags.map((x) => ({ doc_id: id, tag_name: x })))
 | 
			
		||||
					.execute();
 | 
			
		||||
			}
 | 
			
		||||
			return id;
 | 
			
		||||
		});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ export class DiffManager {
 | 
			
		|||
			throw new Error("path is not exist");
 | 
			
		||||
		}
 | 
			
		||||
		await list.delete(c);
 | 
			
		||||
		console.log(`commit: ${c.path} ${c.type}`);
 | 
			
		||||
		const body = await c.createDocumentBody();
 | 
			
		||||
		const id = await this.doc_cntr.add(body);
 | 
			
		||||
		return id;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ type PostAddedBody = {
 | 
			
		|||
	path: string;
 | 
			
		||||
}[];
 | 
			
		||||
 | 
			
		||||
function checkPostAddedBody(body: any): body is PostAddedBody {
 | 
			
		||||
function checkPostAddedBody(body: unknown): body is PostAddedBody {
 | 
			
		||||
	if (Array.isArray(body)) {
 | 
			
		||||
		return body.map((x) => "type" in x && "path" in x).every((x) => x);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +43,7 @@ export const postAdded = (diffmgr: DiffManager) => async (ctx: Router.IRouterCon
 | 
			
		|||
		docs: results,
 | 
			
		||||
	};
 | 
			
		||||
	ctx.type = "json";
 | 
			
		||||
	await next();
 | 
			
		||||
};
 | 
			
		||||
export const postAddedAll = (diffmgr: DiffManager) => async (ctx: Router.IRouterContext, next: Koa.Next) => {
 | 
			
		||||
	if (!ctx.is("json")) {
 | 
			
		||||
| 
						 | 
				
			
			@ -64,6 +65,7 @@ export const postAddedAll = (diffmgr: DiffManager) => async (ctx: Router.IRouter
 | 
			
		|||
		ok: true,
 | 
			
		||||
	};
 | 
			
		||||
	ctx.type = "json";
 | 
			
		||||
	await next();
 | 
			
		||||
};
 | 
			
		||||
/*
 | 
			
		||||
export const getNotWatched = (diffmgr : DiffManager)=> (ctx:Router.IRouterContext,next:Koa.Next)=>{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,6 @@
 | 
			
		|||
import { request } from "node:http";
 | 
			
		||||
import { decode, sign, TokenExpiredError, verify } from "jsonwebtoken";
 | 
			
		||||
import Knex from "knex";
 | 
			
		||||
import { sign, TokenExpiredError, verify } from "jsonwebtoken";
 | 
			
		||||
import type Koa from "koa";
 | 
			
		||||
import Router from "koa-router";
 | 
			
		||||
import { createSqliteUserController } from "./db/mod";
 | 
			
		||||
import type { IUser, UserAccessor } from "./model/mod";
 | 
			
		||||
import { sendError } from "./route/error_handler";
 | 
			
		||||
import { get_setting } from "./SettingConfig";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ export async function readZip(path: string): Promise<{
 | 
			
		|||
	const fd = await open(path, "r");
 | 
			
		||||
	const reader = new ZipReader(new FileReader(fd), {
 | 
			
		||||
		useCompressionStream: true,
 | 
			
		||||
		preventClose: true,
 | 
			
		||||
		preventClose: false,
 | 
			
		||||
	});
 | 
			
		||||
	return { reader, handle: fd };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -23,6 +23,9 @@ importers:
 | 
			
		|||
      '@radix-ui/react-radio-group':
 | 
			
		||||
        specifier: ^1.1.3
 | 
			
		||||
        version: 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
 | 
			
		||||
      '@radix-ui/react-separator':
 | 
			
		||||
        specifier: ^1.0.3
 | 
			
		||||
        version: 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
 | 
			
		||||
      '@radix-ui/react-slot':
 | 
			
		||||
        specifier: ^1.0.2
 | 
			
		||||
        version: 1.0.2(@types/react@18.2.71)(react@18.2.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1284,6 +1287,27 @@ packages:
 | 
			
		|||
      react-dom: 18.2.0(react@18.2.0)
 | 
			
		||||
    dev: false
 | 
			
		||||
 | 
			
		||||
  /@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0):
 | 
			
		||||
    resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==}
 | 
			
		||||
    peerDependencies:
 | 
			
		||||
      '@types/react': '*'
 | 
			
		||||
      '@types/react-dom': '*'
 | 
			
		||||
      react: ^16.8 || ^17.0 || ^18.0
 | 
			
		||||
      react-dom: ^16.8 || ^17.0 || ^18.0
 | 
			
		||||
    peerDependenciesMeta:
 | 
			
		||||
      '@types/react':
 | 
			
		||||
        optional: true
 | 
			
		||||
      '@types/react-dom':
 | 
			
		||||
        optional: true
 | 
			
		||||
    dependencies:
 | 
			
		||||
      '@babel/runtime': 7.24.1
 | 
			
		||||
      '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)
 | 
			
		||||
      '@types/react': 18.2.71
 | 
			
		||||
      '@types/react-dom': 18.2.22
 | 
			
		||||
      react: 18.2.0
 | 
			
		||||
      react-dom: 18.2.0(react@18.2.0)
 | 
			
		||||
    dev: false
 | 
			
		||||
 | 
			
		||||
  /@radix-ui/react-slot@1.0.2(@types/react@18.2.71)(react@18.2.0):
 | 
			
		||||
    resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
 | 
			
		||||
    peerDependencies:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue