github.com/cozy/cozy-stack@v0.0.0-20240327093429-939e4a21320e/model/note/copy.go (about) 1 package note 2 3 import ( 4 "github.com/cozy/cozy-stack/model/instance" 5 "github.com/cozy/cozy-stack/model/vfs" 6 "github.com/cozy/prosemirror-go/model" 7 "github.com/gofrs/uuid/v5" 8 ) 9 10 // CopyFile is an overloaded version of Fs.CopyFile that take care of also 11 // copying the images in the note. 12 func CopyFile(inst *instance.Instance, olddoc, newdoc *vfs.FileDoc) error { 13 // Check available disk space 14 _, _, _, err := vfs.CheckAvailableDiskSpace(inst.VFS(), newdoc) 15 if err != nil { 16 return err 17 } 18 19 // Load data from the source note 20 noteDoc, err := get(inst, olddoc) 21 if err != nil { 22 return err 23 } 24 content, err := noteDoc.Content() 25 if err != nil { 26 return err 27 } 28 srcImages, err := getImages(inst, olddoc.ID()) 29 if err != nil { 30 return err 31 } 32 33 // We need a fileID for saving images 34 uuidv7, _ := uuid.NewV7() 35 newdoc.SetID(uuidv7.String()) 36 37 // id of the image in the source doc -> image in the destination doc 38 mapping := make(map[string]*Image) 39 var dstImages []*Image 40 for _, img := range srcImages { 41 if img.ToRemove { 42 continue 43 } 44 copied, err := CopyImageToAnotherNote(inst, img.ID(), newdoc) 45 if err != nil { 46 return err 47 } 48 mapping[img.ID()] = copied 49 dstImages = append(dstImages, copied) 50 } 51 52 updateProsemirrorImageURLs(content, mapping) 53 54 md := markdownSerializer(dstImages).Serialize(content) 55 if err != nil { 56 return err 57 } 58 body := []byte(md) 59 if hasImages(dstImages) { 60 body, _ = buildArchive(inst, []byte(md), dstImages) 61 } 62 newdoc.ByteSize = int64(len(body)) 63 newdoc.MD5Sum = nil 64 newdoc.Metadata["content"] = content.ToJSON() 65 66 file, err := inst.VFS().CreateFile(newdoc, nil) 67 if err != nil { 68 return err 69 } 70 _, err = file.Write(body) 71 if cerr := file.Close(); cerr != nil && err == nil { 72 err = cerr 73 } 74 return err 75 } 76 77 func updateProsemirrorImageURLs(node *model.Node, mapping map[string]*Image) { 78 if node.Type.Name == "media" { 79 nodeURL, _ := node.Attrs["url"].(string) 80 for id, img := range mapping { 81 if nodeURL == id { 82 node.Attrs["url"] = img.ID() 83 } 84 } 85 } 86 87 node.ForEach(func(child *model.Node, _ int, _ int) { 88 updateProsemirrorImageURLs(child, mapping) 89 }) 90 }