riff.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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. "time"
  20. "github.com/88250/gulu"
  21. "github.com/gin-gonic/gin"
  22. "github.com/siyuan-note/riff"
  23. "github.com/siyuan-note/siyuan/kernel/model"
  24. "github.com/siyuan-note/siyuan/kernel/util"
  25. )
  26. func getRiffCardsByBlockIDs(c *gin.Context) {
  27. ret := gulu.Ret.NewResult()
  28. defer c.JSON(http.StatusOK, ret)
  29. arg, ok := util.JsonArg(c, ret)
  30. if !ok {
  31. return
  32. }
  33. blockIDsArg := arg["blockIDs"].([]interface{})
  34. var blockIDs []string
  35. for _, blockID := range blockIDsArg {
  36. blockIDs = append(blockIDs, blockID.(string))
  37. }
  38. blocks := model.GetFlashcardsByBlockIDs(blockIDs)
  39. ret.Data = map[string]interface{}{
  40. "blocks": blocks,
  41. }
  42. }
  43. func batchSetRiffCardsDueTime(c *gin.Context) {
  44. ret := gulu.Ret.NewResult()
  45. defer c.JSON(http.StatusOK, ret)
  46. arg, ok := util.JsonArg(c, ret)
  47. if !ok {
  48. return
  49. }
  50. var cardDues []*model.SetFlashcardDueTime
  51. for _, cardDueArg := range arg["cardDues"].([]interface{}) {
  52. cardDue := cardDueArg.(map[string]interface{})
  53. cardDues = append(cardDues, &model.SetFlashcardDueTime{
  54. ID: cardDue["id"].(string),
  55. Due: cardDue["due"].(string),
  56. })
  57. }
  58. err := model.SetFlashcardsDueTime(cardDues)
  59. if nil != err {
  60. ret.Code = -1
  61. ret.Msg = err.Error()
  62. }
  63. }
  64. func resetRiffCards(c *gin.Context) {
  65. ret := gulu.Ret.NewResult()
  66. defer c.JSON(http.StatusOK, ret)
  67. arg, ok := util.JsonArg(c, ret)
  68. if !ok {
  69. return
  70. }
  71. typ := arg["type"].(string) // notebook, tree, deck
  72. id := arg["id"].(string) // notebook ID, root ID, deck ID
  73. deckID := arg["deckID"].(string) // deck ID
  74. blockIDsArg := arg["blockIDs"] // 如果不传入 blockIDs (或者传入实参为空数组),则重置所有卡片
  75. var blockIDs []string
  76. if nil != blockIDsArg {
  77. for _, blockID := range blockIDsArg.([]interface{}) {
  78. blockIDs = append(blockIDs, blockID.(string))
  79. }
  80. }
  81. model.ResetFlashcards(typ, id, deckID, blockIDs)
  82. }
  83. func getNotebookRiffCards(c *gin.Context) {
  84. ret := gulu.Ret.NewResult()
  85. defer c.JSON(http.StatusOK, ret)
  86. arg, ok := util.JsonArg(c, ret)
  87. if !ok {
  88. return
  89. }
  90. notebookID := arg["id"].(string)
  91. page := int(arg["page"].(float64))
  92. pageSize := 20
  93. if nil != arg["pageSize"] {
  94. pageSize = int(arg["pageSize"].(float64))
  95. }
  96. blockIDs, total, pageCount := model.GetNotebookFlashcards(notebookID, page, pageSize)
  97. ret.Data = map[string]interface{}{
  98. "blocks": blockIDs,
  99. "total": total,
  100. "pageCount": pageCount,
  101. }
  102. }
  103. func getTreeRiffCards(c *gin.Context) {
  104. ret := gulu.Ret.NewResult()
  105. defer c.JSON(http.StatusOK, ret)
  106. arg, ok := util.JsonArg(c, ret)
  107. if !ok {
  108. return
  109. }
  110. rootID := arg["id"].(string)
  111. page := int(arg["page"].(float64))
  112. pageSize := 20
  113. if nil != arg["pageSize"] {
  114. pageSize = int(arg["pageSize"].(float64))
  115. }
  116. blockIDs, total, pageCount := model.GetTreeFlashcards(rootID, page, pageSize)
  117. ret.Data = map[string]interface{}{
  118. "blocks": blockIDs,
  119. "total": total,
  120. "pageCount": pageCount,
  121. }
  122. }
  123. func getRiffCards(c *gin.Context) {
  124. ret := gulu.Ret.NewResult()
  125. defer c.JSON(http.StatusOK, ret)
  126. arg, ok := util.JsonArg(c, ret)
  127. if !ok {
  128. return
  129. }
  130. deckID := arg["id"].(string)
  131. page := int(arg["page"].(float64))
  132. pageSize := 20
  133. if nil != arg["pageSize"] {
  134. pageSize = int(arg["pageSize"].(float64))
  135. }
  136. blocks, total, pageCount := model.GetDeckFlashcards(deckID, page, pageSize)
  137. ret.Data = map[string]interface{}{
  138. "blocks": blocks,
  139. "total": total,
  140. "pageCount": pageCount,
  141. }
  142. }
  143. func reviewRiffCard(c *gin.Context) {
  144. ret := gulu.Ret.NewResult()
  145. defer c.JSON(http.StatusOK, ret)
  146. arg, ok := util.JsonArg(c, ret)
  147. if !ok {
  148. return
  149. }
  150. deckID := arg["deckID"].(string)
  151. cardID := arg["cardID"].(string)
  152. rating := int(arg["rating"].(float64))
  153. reviewedCardIDs := getReviewedCards(arg)
  154. err := model.ReviewFlashcard(deckID, cardID, riff.Rating(rating), reviewedCardIDs)
  155. if nil != err {
  156. ret.Code = -1
  157. ret.Msg = err.Error()
  158. return
  159. }
  160. }
  161. func skipReviewRiffCard(c *gin.Context) {
  162. ret := gulu.Ret.NewResult()
  163. defer c.JSON(http.StatusOK, ret)
  164. arg, ok := util.JsonArg(c, ret)
  165. if !ok {
  166. return
  167. }
  168. deckID := arg["deckID"].(string)
  169. cardID := arg["cardID"].(string)
  170. err := model.SkipReviewFlashcard(deckID, cardID)
  171. if nil != err {
  172. ret.Code = -1
  173. ret.Msg = err.Error()
  174. return
  175. }
  176. }
  177. func getNotebookRiffDueCards(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. notebookID := arg["notebook"].(string)
  185. reviewedCardIDs := getReviewedCards(arg)
  186. cards, unreviewedCount, unreviewedNewCardCount, unreviewedOldCardCount, err := model.GetNotebookDueFlashcards(notebookID, reviewedCardIDs)
  187. if nil != err {
  188. ret.Code = -1
  189. ret.Msg = err.Error()
  190. return
  191. }
  192. ret.Data = map[string]interface{}{
  193. "cards": cards,
  194. "unreviewedCount": unreviewedCount,
  195. "unreviewedNewCardCount": unreviewedNewCardCount,
  196. "unreviewedOldCardCount": unreviewedOldCardCount,
  197. }
  198. }
  199. func getTreeRiffDueCards(c *gin.Context) {
  200. ret := gulu.Ret.NewResult()
  201. defer c.JSON(http.StatusOK, ret)
  202. arg, ok := util.JsonArg(c, ret)
  203. if !ok {
  204. return
  205. }
  206. rootID := arg["rootID"].(string)
  207. reviewedCardIDs := getReviewedCards(arg)
  208. cards, unreviewedCount, unreviewedNewCardCount, unreviewedOldCardCount, err := model.GetTreeDueFlashcards(rootID, reviewedCardIDs)
  209. if nil != err {
  210. ret.Code = -1
  211. ret.Msg = err.Error()
  212. return
  213. }
  214. ret.Data = map[string]interface{}{
  215. "cards": cards,
  216. "unreviewedCount": unreviewedCount,
  217. "unreviewedNewCardCount": unreviewedNewCardCount,
  218. "unreviewedOldCardCount": unreviewedOldCardCount,
  219. }
  220. }
  221. func getRiffDueCards(c *gin.Context) {
  222. ret := gulu.Ret.NewResult()
  223. defer c.JSON(http.StatusOK, ret)
  224. arg, ok := util.JsonArg(c, ret)
  225. if !ok {
  226. return
  227. }
  228. deckID := arg["deckID"].(string)
  229. reviewedCardIDs := getReviewedCards(arg)
  230. cards, unreviewedCount, unreviewedNewCardCount, unreviewedOldCardCount, err := model.GetDueFlashcards(deckID, reviewedCardIDs)
  231. if nil != err {
  232. ret.Code = -1
  233. ret.Msg = err.Error()
  234. return
  235. }
  236. ret.Data = map[string]interface{}{
  237. "cards": cards,
  238. "unreviewedCount": unreviewedCount,
  239. "unreviewedNewCardCount": unreviewedNewCardCount,
  240. "unreviewedOldCardCount": unreviewedOldCardCount,
  241. }
  242. }
  243. func getReviewedCards(arg map[string]interface{}) (ret []string) {
  244. if nil == arg["reviewedCards"] {
  245. return
  246. }
  247. reviewedCardsArg := arg["reviewedCards"].([]interface{})
  248. for _, card := range reviewedCardsArg {
  249. c := card.(map[string]interface{})
  250. cardID := c["cardID"].(string)
  251. ret = append(ret, cardID)
  252. }
  253. return
  254. }
  255. func removeRiffCards(c *gin.Context) {
  256. ret := gulu.Ret.NewResult()
  257. defer c.JSON(http.StatusOK, ret)
  258. arg, ok := util.JsonArg(c, ret)
  259. if !ok {
  260. return
  261. }
  262. deckID := arg["deckID"].(string)
  263. blockIDsArg := arg["blockIDs"].([]interface{})
  264. var blockIDs []string
  265. for _, blockID := range blockIDsArg {
  266. blockIDs = append(blockIDs, blockID.(string))
  267. }
  268. transactions := []*model.Transaction{
  269. {
  270. DoOperations: []*model.Operation{
  271. {
  272. Action: "removeFlashcards",
  273. DeckID: deckID,
  274. BlockIDs: blockIDs,
  275. },
  276. },
  277. },
  278. }
  279. model.PerformTransactions(&transactions)
  280. model.WaitForWritingFiles()
  281. if "" != deckID {
  282. deck := model.Decks[deckID]
  283. ret.Data = deckData(deck)
  284. }
  285. // All 卡包不返回数据
  286. }
  287. func addRiffCards(c *gin.Context) {
  288. ret := gulu.Ret.NewResult()
  289. defer c.JSON(http.StatusOK, ret)
  290. arg, ok := util.JsonArg(c, ret)
  291. if !ok {
  292. return
  293. }
  294. deckID := arg["deckID"].(string)
  295. blockIDsArg := arg["blockIDs"].([]interface{})
  296. var blockIDs []string
  297. for _, blockID := range blockIDsArg {
  298. blockIDs = append(blockIDs, blockID.(string))
  299. }
  300. transactions := []*model.Transaction{
  301. {
  302. DoOperations: []*model.Operation{
  303. {
  304. Action: "addFlashcards",
  305. DeckID: deckID,
  306. BlockIDs: blockIDs,
  307. },
  308. },
  309. },
  310. }
  311. model.PerformTransactions(&transactions)
  312. model.WaitForWritingFiles()
  313. deck := model.Decks[deckID]
  314. ret.Data = deckData(deck)
  315. }
  316. func renameRiffDeck(c *gin.Context) {
  317. ret := gulu.Ret.NewResult()
  318. defer c.JSON(http.StatusOK, ret)
  319. arg, ok := util.JsonArg(c, ret)
  320. if !ok {
  321. return
  322. }
  323. deckID := arg["deckID"].(string)
  324. name := arg["name"].(string)
  325. err := model.RenameDeck(deckID, name)
  326. if nil != err {
  327. ret.Code = -1
  328. ret.Msg = err.Error()
  329. return
  330. }
  331. }
  332. func removeRiffDeck(c *gin.Context) {
  333. ret := gulu.Ret.NewResult()
  334. defer c.JSON(http.StatusOK, ret)
  335. arg, ok := util.JsonArg(c, ret)
  336. if !ok {
  337. return
  338. }
  339. deckID := arg["deckID"].(string)
  340. err := model.RemoveDeck(deckID)
  341. if nil != err {
  342. ret.Code = -1
  343. ret.Msg = err.Error()
  344. return
  345. }
  346. }
  347. func createRiffDeck(c *gin.Context) {
  348. ret := gulu.Ret.NewResult()
  349. defer c.JSON(http.StatusOK, ret)
  350. arg, ok := util.JsonArg(c, ret)
  351. if !ok {
  352. return
  353. }
  354. name := arg["name"].(string)
  355. deck, err := model.CreateDeck(name)
  356. if nil != err {
  357. ret.Code = -1
  358. ret.Msg = err.Error()
  359. return
  360. }
  361. ret.Data = deckData(deck)
  362. }
  363. func getRiffDecks(c *gin.Context) {
  364. ret := gulu.Ret.NewResult()
  365. defer c.JSON(http.StatusOK, ret)
  366. decks := model.GetDecks()
  367. var data []interface{}
  368. for _, deck := range decks {
  369. data = append(data, deckData(deck))
  370. }
  371. if 1 > len(data) {
  372. data = []interface{}{}
  373. }
  374. ret.Data = data
  375. }
  376. func deckData(deck *riff.Deck) map[string]interface{} {
  377. return map[string]interface{}{
  378. "id": deck.ID,
  379. "name": deck.Name,
  380. "size": deck.CountCards(),
  381. "created": time.UnixMilli(deck.Created).Format("2006-01-02 15:04:05"),
  382. "updated": time.UnixMilli(deck.Updated).Format("2006-01-02 15:04:05"),
  383. }
  384. }