From 24edac891e4c29cfad662193f1c40dfc6f888c9f Mon Sep 17 00:00:00 2001 From: Liang Ding Date: Mon, 7 Nov 2022 21:12:29 +0800 Subject: [PATCH] =?UTF-8?q?:recycle:=20=E9=87=8D=E6=9E=84=20`=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=8E=86=E5=8F=B2`=20=E6=9F=A5=E8=AF=A2=20https://git?= =?UTF-8?q?hub.com/siyuan-note/siyuan/issues/6504?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/api/history.go | 31 +++++++++++++++++++++++++ kernel/api/router.go | 1 + kernel/model/history.go | 51 +++++++++++++++++++++++++++++++++++++++++ kernel/sql/history.go | 25 ++++++++++++++++++++ 4 files changed, 108 insertions(+) diff --git a/kernel/api/history.go b/kernel/api/history.go index b3652d0de..712d712e3 100644 --- a/kernel/api/history.go +++ b/kernel/api/history.go @@ -61,6 +61,37 @@ func searchHistory(c *gin.Context) { } } +func getHistoryItems(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + created := arg["created"].(string) + + notebook := "" + if nil != arg["notebook"] { + notebook = arg["notebook"].(string) + } + typ := model.HistoryTypeDoc + if nil != arg["type"] { + typ = int(arg["type"].(float64)) + } + + query := arg["query"].(string) + op := "all" + if nil != arg["op"] { + op = arg["op"].(string) + } + histories := model.FullTextSearchHistoryItems(created, query, notebook, op, typ) + ret.Data = map[string]interface{}{ + "items": histories, + } +} + func reindexHistory(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 351f4f9d3..379fd3027 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -111,6 +111,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/history/clearWorkspaceHistory", model.CheckAuth, model.CheckReadonly, clearWorkspaceHistory) ginServer.Handle("POST", "/api/history/reindexHistory", model.CheckAuth, model.CheckReadonly, reindexHistory) ginServer.Handle("POST", "/api/history/searchHistory", model.CheckAuth, model.CheckReadonly, searchHistory) + ginServer.Handle("POST", "/api/history/getHistoryItems", model.CheckAuth, model.CheckReadonly, getHistoryItems) ginServer.Handle("POST", "/api/outline/getDocOutline", model.CheckAuth, getDocOutline) ginServer.Handle("POST", "/api/bookmark/getBookmark", model.CheckAuth, getBookmark) diff --git a/kernel/model/history.go b/kernel/model/history.go index 5d5e7dd10..f9271b9a7 100644 --- a/kernel/model/history.go +++ b/kernel/model/history.go @@ -360,6 +360,38 @@ func FullTextSearchHistory(query, box, op string, typ, page int) (ret []string, return } +func FullTextSearchHistoryItems(created, query, box, op string, typ int) (ret []*HistoryItem) { + query = gulu.Str.RemoveInvisible(query) + if "" != query { + query = stringQuery(query) + } + + table := "histories_fts_case_insensitive" + stmt := "SELECT * FROM " + table + " WHERE " + if "" != query { + stmt += table + " MATCH '{title content}:(" + query + ")'" + } else { + stmt += "1=1" + } + + if HistoryTypeDocName == typ { + stmt = strings.ReplaceAll(stmt, "{title content}", "{title}") + } + + if HistoryTypeDocName == typ || HistoryTypeDoc == typ { + if "all" != op { + stmt += " AND op = '" + op + "'" + } + stmt += " AND path LIKE '%/" + box + "/%' AND path LIKE '%.sy'" + } else if HistoryTypeAsset == typ { + stmt += " AND path LIKE '%/assets/%'" + } + stmt += " AND created = '" + created + "' ORDER BY created DESC LIMIT " + fmt.Sprintf("%d", Conf.Search.Limit) + sqlHistories := sql.SelectHistoriesRawStmt(stmt) + ret = fromSQLHistories(sqlHistories) + return +} + func GetNotebookHistory() (ret []*History, err error) { ret = []*History{} @@ -656,3 +688,22 @@ func indexHistoryDir(name string, luteEngine *lute.Lute) { } return } + +func fromSQLHistories(sqlHistories []*sql.History) (ret []*HistoryItem) { + if 1 > len(sqlHistories) { + ret = []*HistoryItem{} + return + } + + for _, sqlHistory := range sqlHistories { + item := &HistoryItem{ + Title: sqlHistory.Title, + Path: filepath.Join(util.HistoryDir, sqlHistory.Path), + } + if HistoryTypeAsset == sqlHistory.Type { + item.Path = filepath.ToSlash(strings.TrimPrefix(item.Path, util.WorkspaceDir)) + } + ret = append(ret, item) + } + return +} diff --git a/kernel/sql/history.go b/kernel/sql/history.go index 50e1ec636..a939a5f53 100644 --- a/kernel/sql/history.go +++ b/kernel/sql/history.go @@ -69,6 +69,31 @@ func QueryHistory(stmt string) (ret []map[string]interface{}, err error) { return } +func SelectHistoriesRawStmt(stmt string) (ret []*History) { + rows, err := historyDB.Query(stmt) + if nil != err { + logging.LogWarnf("sql query [%s] failed: %s", stmt, err) + return + } + defer rows.Close() + for rows.Next() { + if history := scanHistoryRows(rows); nil != history { + ret = append(ret, history) + } + } + return +} + +func scanHistoryRows(rows *sql.Rows) (ret *History) { + var history History + if err := rows.Scan(&history.Type, &history.Op, &history.Title, &history.Content, &history.Path, &history.Created); nil != err { + logging.LogErrorf("query scan field failed: %s\n%s", err, logging.ShortStack()) + return + } + ret = &history + return +} + func queryHistory(query string, args ...interface{}) (*sql.Rows, error) { query = strings.TrimSpace(query) if "" == query {