search.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // SiYuan - Refactor your thinking
  2. // Copyright (c) 2020-present, b3log.org
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package api
  17. import (
  18. "net/http"
  19. "strings"
  20. "github.com/88250/gulu"
  21. "github.com/gin-gonic/gin"
  22. "github.com/siyuan-note/siyuan/kernel/model"
  23. "github.com/siyuan-note/siyuan/kernel/util"
  24. )
  25. func findReplace(c *gin.Context) {
  26. ret := gulu.Ret.NewResult()
  27. defer c.JSON(http.StatusOK, ret)
  28. arg, ok := util.JsonArg(c, ret)
  29. if !ok {
  30. return
  31. }
  32. _, _, paths, boxes, types, method, orderBy, groupBy := parseSearchArgs(arg)
  33. k := arg["k"].(string)
  34. r := arg["r"].(string)
  35. idsArg := arg["ids"].([]interface{})
  36. var ids []string
  37. for _, id := range idsArg {
  38. ids = append(ids, id.(string))
  39. }
  40. err := model.FindReplace(k, r, ids, paths, boxes, types, method, orderBy, groupBy)
  41. if nil != err {
  42. ret.Code = -1
  43. ret.Msg = err.Error()
  44. ret.Data = map[string]interface{}{"closeTimeout": 5000}
  45. return
  46. }
  47. return
  48. }
  49. func searchAsset(c *gin.Context) {
  50. ret := gulu.Ret.NewResult()
  51. defer c.JSON(http.StatusOK, ret)
  52. arg, ok := util.JsonArg(c, ret)
  53. if !ok {
  54. return
  55. }
  56. k := arg["k"].(string)
  57. ret.Data = model.SearchAssetsByName(k)
  58. return
  59. }
  60. func searchTag(c *gin.Context) {
  61. ret := gulu.Ret.NewResult()
  62. defer c.JSON(http.StatusOK, ret)
  63. arg, ok := util.JsonArg(c, ret)
  64. if !ok {
  65. return
  66. }
  67. k := arg["k"].(string)
  68. tags := model.SearchTags(k)
  69. if 1 > len(tags) {
  70. tags = []string{}
  71. }
  72. ret.Data = map[string]interface{}{
  73. "tags": tags,
  74. "k": k,
  75. }
  76. }
  77. func searchWidget(c *gin.Context) {
  78. ret := gulu.Ret.NewResult()
  79. defer c.JSON(http.StatusOK, ret)
  80. arg, ok := util.JsonArg(c, ret)
  81. if !ok {
  82. return
  83. }
  84. keyword := arg["k"].(string)
  85. blocks := model.SearchWidget(keyword)
  86. ret.Data = map[string]interface{}{
  87. "blocks": blocks,
  88. "k": keyword,
  89. }
  90. }
  91. func removeTemplate(c *gin.Context) {
  92. ret := gulu.Ret.NewResult()
  93. defer c.JSON(http.StatusOK, ret)
  94. arg, ok := util.JsonArg(c, ret)
  95. if !ok {
  96. return
  97. }
  98. path := arg["path"].(string)
  99. err := model.RemoveTemplate(path)
  100. if nil != err {
  101. ret.Code = -1
  102. ret.Msg = err.Error()
  103. return
  104. }
  105. }
  106. func searchTemplate(c *gin.Context) {
  107. ret := gulu.Ret.NewResult()
  108. defer c.JSON(http.StatusOK, ret)
  109. arg, ok := util.JsonArg(c, ret)
  110. if !ok {
  111. return
  112. }
  113. keyword := arg["k"].(string)
  114. blocks := model.SearchTemplate(keyword)
  115. ret.Data = map[string]interface{}{
  116. "blocks": blocks,
  117. "k": keyword,
  118. }
  119. }
  120. func searchEmbedBlock(c *gin.Context) {
  121. ret := gulu.Ret.NewResult()
  122. defer c.JSON(http.StatusOK, ret)
  123. arg, ok := util.JsonArg(c, ret)
  124. if !ok {
  125. return
  126. }
  127. embedBlockID := arg["embedBlockID"].(string)
  128. stmt := arg["stmt"].(string)
  129. excludeIDsArg := arg["excludeIDs"].([]interface{})
  130. var excludeIDs []string
  131. for _, excludeID := range excludeIDsArg {
  132. excludeIDs = append(excludeIDs, excludeID.(string))
  133. }
  134. headingMode := 0 // 0:带标题下方块
  135. headingModeArg := arg["headingMode"]
  136. if nil != headingModeArg {
  137. headingMode = int(headingModeArg.(float64))
  138. }
  139. breadcrumb := false
  140. breadcrumbArg := arg["breadcrumb"]
  141. if nil != breadcrumbArg {
  142. breadcrumb = breadcrumbArg.(bool)
  143. }
  144. blocks := model.SearchEmbedBlock(embedBlockID, stmt, excludeIDs, headingMode, breadcrumb)
  145. ret.Data = map[string]interface{}{
  146. "blocks": blocks,
  147. }
  148. }
  149. func searchRefBlock(c *gin.Context) {
  150. ret := gulu.Ret.NewResult()
  151. defer c.JSON(http.StatusOK, ret)
  152. arg, ok := util.JsonArg(c, ret)
  153. if !ok {
  154. return
  155. }
  156. reqId := arg["reqId"]
  157. ret.Data = map[string]interface{}{"reqId": reqId}
  158. if nil == arg["id"] {
  159. return
  160. }
  161. isSquareBrackets := false
  162. if isSquareBracketsArg := arg["isSquareBrackets"]; nil != isSquareBracketsArg {
  163. isSquareBrackets = isSquareBracketsArg.(bool)
  164. }
  165. rootID := arg["rootID"].(string)
  166. id := arg["id"].(string)
  167. keyword := arg["k"].(string)
  168. beforeLen := int(arg["beforeLen"].(float64))
  169. blocks, newDoc := model.SearchRefBlock(id, rootID, keyword, beforeLen, isSquareBrackets)
  170. ret.Data = map[string]interface{}{
  171. "blocks": blocks,
  172. "newDoc": newDoc,
  173. "k": util.EscapeHTML(keyword),
  174. "reqId": arg["reqId"],
  175. }
  176. }
  177. func fullTextSearchBlock(c *gin.Context) {
  178. ret := gulu.Ret.NewResult()
  179. defer c.JSON(http.StatusOK, ret)
  180. arg, ok := util.JsonArg(c, ret)
  181. if !ok {
  182. return
  183. }
  184. page, query, paths, boxes, types, method, orderBy, groupBy := parseSearchArgs(arg)
  185. blocks, matchedBlockCount, matchedRootCount, pageCount := model.FullTextSearchBlock(query, boxes, paths, types, method, orderBy, groupBy, page)
  186. ret.Data = map[string]interface{}{
  187. "blocks": blocks,
  188. "matchedBlockCount": matchedBlockCount,
  189. "matchedRootCount": matchedRootCount,
  190. "pageCount": pageCount,
  191. }
  192. }
  193. func parseSearchArgs(arg map[string]interface{}) (page int, query string, paths, boxes []string, types map[string]bool, method, orderBy, groupBy int) {
  194. page = 1
  195. if nil != arg["page"] {
  196. page = int(arg["page"].(float64))
  197. }
  198. if 0 >= page {
  199. page = 1
  200. }
  201. queryArg := arg["query"]
  202. if nil != queryArg {
  203. query = queryArg.(string)
  204. }
  205. pathsArg := arg["paths"]
  206. if nil != pathsArg {
  207. for _, p := range pathsArg.([]interface{}) {
  208. path := p.(string)
  209. box := strings.TrimSpace(strings.Split(path, "/")[0])
  210. if "" != box {
  211. boxes = append(boxes, box)
  212. }
  213. path = strings.TrimSpace(strings.TrimPrefix(path, box))
  214. if "" != path {
  215. paths = append(paths, path)
  216. }
  217. }
  218. paths = gulu.Str.RemoveDuplicatedElem(paths)
  219. boxes = gulu.Str.RemoveDuplicatedElem(boxes)
  220. }
  221. if nil != arg["types"] {
  222. typesArg := arg["types"].(map[string]interface{})
  223. types = map[string]bool{}
  224. for t, b := range typesArg {
  225. types[t] = b.(bool)
  226. }
  227. }
  228. // method:0:关键字,1:查询语法,2:SQL,3:正则表达式
  229. methodArg := arg["method"]
  230. if nil != methodArg {
  231. method = int(methodArg.(float64))
  232. }
  233. // orderBy:0:按块类型(默认),1:按创建时间升序,2:按创建时间降序,3:按更新时间升序,4:按更新时间降序,5:按内容顺序(仅在按文档分组时),6:按相关度升序,7:按相关度降序
  234. orderByArg := arg["orderBy"]
  235. if nil != orderByArg {
  236. orderBy = int(orderByArg.(float64))
  237. }
  238. // groupBy: 0:不分组,1:按文档分组
  239. groupByArg := arg["groupBy"]
  240. if nil != groupByArg {
  241. groupBy = int(groupByArg.(float64))
  242. }
  243. return
  244. }