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  }