diff --git a/kernel/api/riff.go b/kernel/api/riff.go index 6884b69fa..39b35d7d1 100644 --- a/kernel/api/riff.go +++ b/kernel/api/riff.go @@ -27,6 +27,28 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) +func resetRiffCards(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + typ := arg["type"].(string) // notebook, tree, deck + id := arg["id"].(string) // notebook ID, root ID, deck ID + blockIDsArg := arg["blockIDs"] // 如果不传入 blockIDs (或者传入实参为空数组),则重置所有卡片 + var blockIDs []string + if nil != blockIDsArg { + for _, blockID := range blockIDsArg.([]interface{}) { + blockIDs = append(blockIDs, blockID.(string)) + } + } + + model.ResetFlashcards(typ, id, blockIDs) +} + func getNotebookRiffCards(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) @@ -76,7 +98,7 @@ func getRiffCards(c *gin.Context) { deckID := arg["id"].(string) page := int(arg["page"].(float64)) - blocks, total, pageCount := model.GetFlashcards(deckID, page) + blocks, total, pageCount := model.GetDeckFlashcards(deckID, page) ret.Data = map[string]interface{}{ "blocks": blocks, "total": total, diff --git a/kernel/api/router.go b/kernel/api/router.go index 919233d5b..58650b14a 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -362,6 +362,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/riff/getRiffCards", model.CheckAuth, getRiffCards) ginServer.Handle("POST", "/api/riff/getTreeRiffCards", model.CheckAuth, getTreeRiffCards) ginServer.Handle("POST", "/api/riff/getNotebookRiffCards", model.CheckAuth, getNotebookRiffCards) + ginServer.Handle("POST", "/api/riff/resetRiffCards", model.CheckAuth, resetRiffCards) ginServer.Handle("POST", "/api/notification/pushMsg", model.CheckAuth, pushMsg) ginServer.Handle("POST", "/api/notification/pushErrMsg", model.CheckAuth, pushErrMsg) diff --git a/kernel/model/flashcard.go b/kernel/model/flashcard.go index 5f9ca4a16..369f6b4dd 100644 --- a/kernel/model/flashcard.go +++ b/kernel/model/flashcard.go @@ -39,6 +39,80 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) +func ResetFlashcards(typ, id string, blockIDs []string) { + // Support resetting the learning progress of flashcards https://github.com/siyuan-note/siyuan/issues/9564 + + if 0 < len(blockIDs) { + resetFlashcards(id, blockIDs) + return + } + + var blocks []*Block + switch typ { + case "notebook": + for i := 1; ; i++ { + pagedBlocks, _, _ := GetNotebookFlashcards(id, i) + if 1 > len(blocks) { + break + } + blocks = append(blocks, pagedBlocks...) + } + for _, block := range blocks { + blockIDs = append(blockIDs, block.ID) + } + case "tree": + for i := 1; ; i++ { + pagedBlocks, _, _ := GetTreeFlashcards(id, i) + if 1 > len(blocks) { + break + } + blocks = append(blocks, pagedBlocks...) + } + for _, block := range blocks { + blockIDs = append(blockIDs, block.ID) + } + case "deck": + for i := 1; ; i++ { + pagedBlocks, _, _ := GetDeckFlashcards(id, i) + if 1 > len(blocks) { + break + } + blocks = append(blocks, pagedBlocks...) + } + default: + logging.LogErrorf("invalid type [%s]", typ) + } + + blockIDs = gulu.Str.RemoveDuplicatedElem(blockIDs) + resetFlashcards(id, blockIDs) +} + +func resetFlashcards(deckID string, blockIDs []string) { + transactions := []*Transaction{ + { + DoOperations: []*Operation{ + { + Action: "removeFlashcards", + DeckID: deckID, + BlockIDs: blockIDs, + }, + }, + }, + { + DoOperations: []*Operation{ + { + Action: "addFlashcards", + DeckID: deckID, + BlockIDs: blockIDs, + }, + }, + }, + } + + PerformTransactions(&transactions) + WaitForWritingFiles() +} + func GetFlashcardNotebooks() (ret []*Box) { deck := Decks[builtinDeckID] if nil == deck { @@ -193,7 +267,7 @@ func getTreeFlashcards(rootID string) (ret []riff.Card) { return } -func GetFlashcards(deckID string, page int) (blocks []*Block, total, pageCount int) { +func GetDeckFlashcards(deckID string, page int) (blocks []*Block, total, pageCount int) { blocks = []*Block{} var cards []riff.Card if "" == deckID {