diff --git a/kernel/api/notebook.go b/kernel/api/notebook.go index c00f4d274..39b6842cb 100644 --- a/kernel/api/notebook.go +++ b/kernel/api/notebook.go @@ -28,6 +28,33 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) +func getNotebookInfo(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + boxID := arg["notebook"].(string) + if util.InvalidIDPattern(boxID, ret) { + return + } + + box := model.Conf.Box(boxID) + if nil == box { + ret.Code = -1 + ret.Msg = "notebook [" + boxID + "] not found" + return + } + + boxInfo := box.GetInfo() + ret.Data = map[string]interface{}{ + "boxInfo": boxInfo, + } +} + func setNotebookIcon(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) diff --git a/kernel/api/router.go b/kernel/api/router.go index 44f000342..5463e6cd9 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -90,6 +90,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/notebook/renameNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameNotebook) ginServer.Handle("POST", "/api/notebook/changeSortNotebook", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, changeSortNotebook) ginServer.Handle("POST", "/api/notebook/setNotebookIcon", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setNotebookIcon) + ginServer.Handle("POST", "/api/notebook/getNotebookInfo", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getNotebookInfo) ginServer.Handle("POST", "/api/filetree/searchDocs", model.CheckAuth, searchDocs) ginServer.Handle("POST", "/api/filetree/listDocsByPath", model.CheckAuth, listDocsByPath) diff --git a/kernel/model/box.go b/kernel/model/box.go index 3135e5d72..c8eb0c34b 100644 --- a/kernel/model/box.go +++ b/kernel/model/box.go @@ -58,8 +58,6 @@ type Box struct { NewFlashcardCount int `json:"newFlashcardCount"` DueFlashcardCount int `json:"dueFlashcardCount"` FlashcardCount int `json:"flashcardCount"` - - historyGenerated int64 // 最近一次历史生成时间 } func StatJob() { @@ -384,6 +382,70 @@ func (box *Box) listFiles(files, ret *[]*FileInfo) { return } +type BoxInfo struct { + ID string `json:"id"` + Name string `json:"name"` + DocCount int `json:"docCount"` + Size uint64 `json:"size"` + HSize string `json:"hSize"` + Mtime int64 `json:"mtime"` + CTime int64 `json:"ctime"` + HMtime string `json:"hMtime"` + HCtime string `json:"hCtime"` +} + +func (box *Box) GetInfo() (ret *BoxInfo) { + ret = &BoxInfo{ + ID: box.ID, + Name: box.Name, + } + + fileInfos := box.ListFiles("/") + + t, _ := time.ParseInLocation("20060102150405", box.ID[:14], time.Local) + ret.CTime = t.Unix() + ret.HCtime = t.Format("2006-01-02 15:04:05") + ", " + util.HumanizeTime(t, Conf.Lang) + + docLatestModTime := t + for _, fileInfo := range fileInfos { + if fileInfo.isdir { + continue + } + + if strings.HasPrefix(fileInfo.name, ".") { + continue + } + + if !strings.HasSuffix(fileInfo.path, ".sy") { + continue + } + + id := strings.TrimSuffix(fileInfo.name, ".sy") + if !ast.IsNodeIDPattern(id) { + continue + } + + absPath := filepath.Join(util.DataDir, box.ID, fileInfo.path) + info, err := os.Stat(absPath) + if err != nil { + logging.LogErrorf("stat [%s] failed: %s", absPath, err) + continue + } + + ret.DocCount++ + ret.Size += uint64(info.Size()) + docModT := info.ModTime() + if docModT.After(docLatestModTime) { + docLatestModTime = docModT + } + } + + ret.HSize = humanize.BytesCustomCeil(ret.Size, 2) + ret.Mtime = docLatestModTime.Unix() + ret.HMtime = docLatestModTime.Format("2006-01-02 15:04:05") + ", " + util.HumanizeTime(docLatestModTime, Conf.Lang) + return +} + func isSkipFile(filename string) bool { return strings.HasPrefix(filename, ".") || "node_modules" == filename || "dist" == filename || "target" == filename }