diff --git a/README.md b/README.md index bed34c5..0c4c300 100644 --- a/README.md +++ b/README.md @@ -411,10 +411,10 @@ Anonymous API can be called by anonymous. Currently only few APIs in font-end. -- `/#/share/39` +- `/#/files/39/share` Share a specific file. -- `/#/search-folders/2614` +- `/#/folders/2614` Show files in a specific folder. diff --git a/pkg/database/method.go b/pkg/database/method.go index 208fc1c..fc0294e 100644 --- a/pkg/database/method.go +++ b/pkg/database/method.go @@ -188,6 +188,15 @@ func (database *Database) FindFolder(folder string) (int64, error) { return id, nil } +func (database *Database) FindFile(folderId int64, filename string) (int64, error) { + var id int64 + err := database.stmt.findFile.QueryRow(folderId, filename).Scan(&id) + if err != nil { + return 0, err + } + return id, nil +} + func (database *Database) InsertFolder(folder string) (int64, error) { result, err := database.stmt.insertFolder.Exec(folder, filepath.Base(folder)) if err != nil { @@ -217,6 +226,13 @@ func (database *Database) Insert(path string, filesize int64) error { return err } } + + // if file exists, skip it + _, err = database.FindFile(folderId, filename) + if err == nil { + return nil + } + err = database.InsertFile(folderId, filename, filesize) if err != nil { return err diff --git a/pkg/database/sql_stmt.go b/pkg/database/sql_stmt.go index e1ebf95..2a5e354 100644 --- a/pkg/database/sql_stmt.go +++ b/pkg/database/sql_stmt.go @@ -21,7 +21,8 @@ var initFoldersTableQuery = `CREATE TABLE IF NOT EXISTS folders ( var initFeedbacksTableQuery = `CREATE TABLE IF NOT EXISTS feedbacks ( id INTEGER PRIMARY KEY, time INTEGER NOT NULL, - feedback TEXT NOT NULL + feedback TEXT NOT NULL, + header TEXT NOT NULL );` var initUsersTableQuery = `CREATE TABLE IF NOT EXISTS users ( @@ -104,6 +105,8 @@ VALUES (?, ?);` var findFolderQuery = `SELECT id FROM folders WHERE folder = ? LIMIT 1;` +var findFileQuery = `SELECT id FROM files WHERE folder_id = ? AND filename = ? LIMIT 1;` + var insertFileQuery = `INSERT INTO files (folder_id, filename, filesize) VALUES (?, ?, ?);` @@ -147,8 +150,8 @@ JOIN folders ON files.folder_id = folders.id ORDER BY RANDOM() LIMIT ?;` -var insertFeedbackQuery = `INSERT INTO feedbacks (time, feedback) -VALUES (?, ?);` +var insertFeedbackQuery = `INSERT INTO feedbacks (time, feedback, header) +VALUES (?, ?, ?);` type Stmt struct { initFilesTable *sql.Stmt @@ -166,6 +169,7 @@ type Stmt struct { insertFolder *sql.Stmt insertFile *sql.Stmt findFolder *sql.Stmt + findFile *sql.Stmt searchFiles *sql.Stmt getFolder *sql.Stmt dropFiles *sql.Stmt @@ -316,6 +320,12 @@ func NewPreparedStatement(sqlConn *sql.DB) (*Stmt, error) { return nil, err } + // init findFile statement + stmt.findFile, err = sqlConn.Prepare(findFileQuery) + if err != nil { + return nil, err + } + // init insertFile stmt stmt.insertFile, err = sqlConn.Prepare(insertFileQuery) if err != nil { diff --git a/web/src/App.js b/web/src/App.js index ca6839d..2896642 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -9,6 +9,7 @@ import "./App.css"; import GetRandomFiles from "./component/GetRandomFiles"; import SearchFiles from "./component/SearchFiles"; import SearchFolders from "./component/SearchFolders"; +import FilesInFolder from "./component/FilesInFolder"; import Manage from "./component/Manage"; import Share from "./component/Share"; import AudioPlayer from "./component/AudioPlayer"; @@ -28,10 +29,10 @@ function App() { Feeling luckly - + Files - + Folders @@ -47,20 +48,20 @@ function App() { element={} /> } /> } /> } + path="/folders/:id" + element={} /> } /> } /> diff --git a/web/src/component/AudioPlayer.js b/web/src/component/AudioPlayer.js index b3b7603..32bf105 100644 --- a/web/src/component/AudioPlayer.js +++ b/web/src/component/AudioPlayer.js @@ -80,7 +80,7 @@ function AudioPlayer(props) { + + + + + + ); +} + +export default FilesInFolder; diff --git a/web/src/component/FilesTable.js b/web/src/component/FilesTable.js index 1ebe780..7215f54 100644 --- a/web/src/component/FilesTable.js +++ b/web/src/component/FilesTable.js @@ -1,6 +1,9 @@ import FileEntry from "./FileEntry"; function FilesTable(props) { + if (props.files.length === 0) { + return null; + } return ( diff --git a/web/src/component/FoldersTable.js b/web/src/component/FoldersTable.js index 14b9654..11ce14e 100644 --- a/web/src/component/FoldersTable.js +++ b/web/src/component/FoldersTable.js @@ -2,6 +2,9 @@ import { useNavigate } from "react-router"; function FoldersTable(props) { let navigate = useNavigate(); + if (props.folders.length === 0) { + return null; + } return (
@@ -14,12 +17,12 @@ function FoldersTable(props) { {props.folders.map((folder) => ( - diff --git a/web/src/component/Manage.js b/web/src/component/Manage.js index ddabb0a..000c43e 100644 --- a/web/src/component/Manage.js +++ b/web/src/component/Manage.js @@ -1,9 +1,51 @@ +import { useState } from "react"; + function Manage() { - return ( -
-

Manage

-
- ) + const [token, setToken] = useState(""); + const [walkPath, setWalkPath] = useState(""); + + function updateDatabase() { + fetch("/api/v1/walk", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + token: token, + root: walkPath, + pattern: [".wav", ".mp3"], + }), + }) + .then((res) => res.json()) + .then((data) => { + console.log(data); + }); + } + + return ( +
+

Manage

+ setToken(e.target.value)} + /> + setWalkPath(e.target.value)} + /> + +
+ ); } export default Manage; diff --git a/web/src/component/SearchFiles.js b/web/src/component/SearchFiles.js index 361f22a..ff25333 100644 --- a/web/src/component/SearchFiles.js +++ b/web/src/component/SearchFiles.js @@ -9,25 +9,14 @@ function SearchFiles(props) { const limit = 10; function searchFiles() { - if ( - filename === "" && - (props.folder === undefined || props.folder.id === undefined) - ) { - return; - } - const folder = props.folder ? props.folder : {}; - const url = folder.id - ? "/api/v1/get_files_in_folder" - : "/api/v1/search_files"; setIsLoading(true); - fetch(url, { + fetch("/api/v1/search_files", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ filename: filename, limit: limit, offset: offset, - folder_id: folder.id, }), }) .then((response) => response.json()) @@ -36,7 +25,7 @@ function SearchFiles(props) { setFiles(files); }) .catch((error) => { - alert("get_files_in_folder error: " + error); + alert("search_files error: " + error); }) .finally(() => { setIsLoading(false); @@ -55,35 +44,29 @@ function SearchFiles(props) { setOffset(offsetValue); } - useEffect(() => searchFiles(), [offset, props.folder]); // eslint-disable-line react-hooks/exhaustive-deps + useEffect(() => searchFiles(), [offset]); // eslint-disable-line react-hooks/exhaustive-deps return (

Search Files

- {!props.folder && ( - setFilename(event.target.value)} - onKeyDown={(event) => { - if (event.key === "Enter") { - searchFiles(); - } - }} - type="text" - placeholder="Enter filename" - /> - )} + setFilename(event.target.value)} + onKeyDown={(event) => { + if (event.key === "Enter") { + searchFiles(); + } + }} + type="text" + placeholder="Enter filename" + /> - {props.folder && props.folder.foldername && ( - - )}
- - +
); }
navigate(`/search-folders/${folder.id}`)} + onClick={() => navigate(`/folders/${folder.id}`)} className="clickable" > {folder.foldername} navigate(`/search-folders/${folder.id}`)}> + navigate(`/folders/${folder.id}`)}>