feat(libs): create library by name only; root_path derived server-side as BOOKS_DIR/SafeName(name), validated at creation; drop root_path input from admin UI; align changelogs to bilingual template; trim AGENTS.md to rules not derivable from repo layout

This commit is contained in:
2026-09-07 21:56:59 +08:00
parent ca64bc0d73
commit 45eefd6741
9 changed files with 80 additions and 146 deletions
+11 -9
View File
@@ -47,29 +47,31 @@ func (h *H) ListLibraries(c *gin.Context) {
c.JSON(http.StatusOK, out)
}
// CreateLibrary: root_path 由服务端生成(BooksDir/SafeName(name)),不接受客户端指定
func (h *H) CreateLibrary(c *gin.Context) {
var req struct {
Name string `json:"name"`
RootPath string `json:"root_path"`
Name string `json:"name"`
}
if c.ShouldBindJSON(&req) != nil || req.Name == "" || req.RootPath == "" {
err(c, http.StatusBadRequest, "bad_request", "name and root_path required")
if c.ShouldBindJSON(&req) != nil {
err(c, http.StatusBadRequest, "bad_request", "name required")
return
}
if !filepath.IsAbs(req.RootPath) {
err(c, http.StatusBadRequest, "bad_request", "root_path must be absolute")
safe := bookfile.SafeName(req.Name)
if safe == "" || safe == ".." {
err(c, http.StatusBadRequest, "bad_request", "bad name")
return
}
id, e := h.st.CreateLibrary(c, req.Name, filepath.Clean(req.RootPath))
root := filepath.Join(filepath.Clean(h.cfg.BooksDir), safe)
id, e := h.st.CreateLibrary(c, req.Name, root)
if e != nil {
if isUnique(e) {
err(c, http.StatusConflict, "exists", "root_path taken")
err(c, http.StatusConflict, "exists", "name taken")
return
}
dbErr(c, e)
return
}
c.JSON(http.StatusCreated, gin.H{"id": id, "name": req.Name, "root_path": filepath.Clean(req.RootPath)})
c.JSON(http.StatusCreated, gin.H{"id": id, "name": req.Name, "root_path": root})
}
func (h *H) getLibrary(c *gin.Context) (store.Library, bool) {