github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/web/files/referencedby.go (about)

     1  package files
     2  
     3  import (
     4  	"net/http"
     5  
     6  	"github.com/cozy/cozy-stack/model/instance"
     7  	"github.com/cozy/cozy-stack/model/permission"
     8  	"github.com/cozy/cozy-stack/model/vfs"
     9  	"github.com/cozy/cozy-stack/pkg/config/config"
    10  	"github.com/cozy/cozy-stack/pkg/couchdb"
    11  	"github.com/cozy/cozy-stack/pkg/jsonapi"
    12  	"github.com/cozy/cozy-stack/web/middlewares"
    13  	"github.com/labstack/echo/v4"
    14  )
    15  
    16  func lockVFS(inst *instance.Instance) func() {
    17  	mu := config.Lock().ReadWrite(inst, "vfs")
    18  	_ = mu.Lock()
    19  	return mu.Unlock
    20  }
    21  
    22  // AddReferencedHandler is the echo.handler for adding referenced_by to
    23  // a file
    24  // POST /files/:file-id/relationships/referenced_by
    25  func AddReferencedHandler(c echo.Context) error {
    26  	instance := middlewares.GetInstance(c)
    27  
    28  	fileID := c.Param("file-id")
    29  	fs := instance.VFS()
    30  	dir, file, err := fs.DirOrFileByID(fileID)
    31  	if err != nil {
    32  		return WrapVfsError(err)
    33  	}
    34  
    35  	err = checkPerm(c, permission.PATCH, dir, file)
    36  	if err != nil {
    37  		return err
    38  	}
    39  
    40  	references, err := jsonapi.BindRelations(c.Request())
    41  	if err != nil {
    42  		return WrapVfsError(err)
    43  	}
    44  
    45  	var oldFile *vfs.FileDoc
    46  	if file != nil {
    47  		oldFile = file.Clone().(*vfs.FileDoc)
    48  		// Ensure the fullpaths are filled to realtime
    49  		_, _ = file.Path(fs)
    50  		_, _ = oldFile.Path(fs)
    51  	}
    52  	defer lockVFS(instance)()
    53  
    54  	var newRev string
    55  	var refs []couchdb.DocReference
    56  	if dir != nil {
    57  		dir.AddReferencedBy(references...)
    58  		updateDirCozyMetadata(c, dir)
    59  		err = couchdb.UpdateDoc(instance, dir)
    60  		newRev = dir.Rev()
    61  		refs = dir.ReferencedBy
    62  	} else {
    63  		file.AddReferencedBy(references...)
    64  		updateFileCozyMetadata(c, file, false)
    65  		err = couchdb.UpdateDocWithOld(instance, file, oldFile)
    66  		newRev = file.Rev()
    67  		refs = file.ReferencedBy
    68  	}
    69  
    70  	if err != nil {
    71  		return WrapVfsError(err)
    72  	}
    73  
    74  	count := len(refs)
    75  	meta := jsonapi.Meta{Rev: newRev, Count: &count}
    76  
    77  	return jsonapi.DataRelations(c, http.StatusOK, refs, &meta, nil, nil)
    78  }
    79  
    80  // RemoveReferencedHandler is the echo.handler for removing referenced_by to
    81  // a file
    82  // DELETE /files/:file-id/relationships/referenced_by
    83  func RemoveReferencedHandler(c echo.Context) error {
    84  	instance := middlewares.GetInstance(c)
    85  
    86  	fileID := c.Param("file-id")
    87  	fs := instance.VFS()
    88  	dir, file, err := fs.DirOrFileByID(fileID)
    89  	if err != nil {
    90  		return WrapVfsError(err)
    91  	}
    92  
    93  	err = checkPerm(c, permission.DELETE, nil, file)
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	references, err := jsonapi.BindRelations(c.Request())
    99  	if err != nil {
   100  		return WrapVfsError(err)
   101  	}
   102  
   103  	var oldFile *vfs.FileDoc
   104  	if file != nil {
   105  		oldFile = file.Clone().(*vfs.FileDoc)
   106  		// Ensure the fullpaths are filled to realtime
   107  		_, _ = file.Path(fs)
   108  		_, _ = oldFile.Path(fs)
   109  	}
   110  	defer lockVFS(instance)()
   111  
   112  	var newRev string
   113  	var refs []couchdb.DocReference
   114  	if dir != nil {
   115  		dir.RemoveReferencedBy(references...)
   116  		updateDirCozyMetadata(c, dir)
   117  		err = couchdb.UpdateDoc(instance, dir)
   118  		newRev = dir.Rev()
   119  		refs = dir.ReferencedBy
   120  	} else {
   121  		file.RemoveReferencedBy(references...)
   122  		updateFileCozyMetadata(c, file, false)
   123  		err = couchdb.UpdateDocWithOld(instance, file, oldFile)
   124  		newRev = file.Rev()
   125  		refs = file.ReferencedBy
   126  	}
   127  
   128  	if err != nil {
   129  		return WrapVfsError(err)
   130  	}
   131  
   132  	count := len(refs)
   133  	meta := jsonapi.Meta{Rev: newRev, Count: &count}
   134  
   135  	return jsonapi.DataRelations(c, http.StatusOK, refs, &meta, nil, nil)
   136  }