mirror of
https://github.com/ente-io/ente.git
synced 2025-05-05 21:07:28 +00:00
204 lines
7.1 KiB
Go
204 lines
7.1 KiB
Go
package collections
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/ente-io/museum/ente"
|
|
"github.com/ente-io/museum/pkg/controller/access"
|
|
"github.com/ente-io/museum/pkg/utils/auth"
|
|
"github.com/ente-io/stacktrace"
|
|
"github.com/gin-gonic/gin"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// AddFiles adds files to a collection
|
|
func (c *CollectionController) AddFiles(ctx *gin.Context, userID int64, files []ente.CollectionFileItem, cID int64) error {
|
|
|
|
resp, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{
|
|
CollectionID: cID,
|
|
ActorUserID: userID,
|
|
IncludeDeleted: false,
|
|
})
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "failed to verify collection access")
|
|
}
|
|
if !resp.Role.CanAdd() {
|
|
return stacktrace.Propagate(ente.ErrPermissionDenied, fmt.Sprintf("user %d with role %s can not add files", userID, *resp.Role))
|
|
}
|
|
|
|
collectionOwnerID := resp.Collection.Owner.ID
|
|
filesOwnerID := userID
|
|
// Verify that the user owns each file
|
|
fileIDs := make([]int64, 0)
|
|
for _, file := range files {
|
|
fileIDs = append(fileIDs, file.ID)
|
|
}
|
|
err = c.AccessCtrl.VerifyFileOwnership(ctx, &access.VerifyFileOwnershipParams{
|
|
ActorUserId: userID,
|
|
FileIDs: fileIDs,
|
|
})
|
|
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "Failed to verify fileOwnership")
|
|
}
|
|
err = c.CollectionRepo.AddFiles(cID, collectionOwnerID, files, filesOwnerID)
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RestoreFiles restore files from trash and add to the collection
|
|
func (c *CollectionController) RestoreFiles(ctx *gin.Context, userID int64, cID int64, files []ente.CollectionFileItem) error {
|
|
_, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{
|
|
CollectionID: cID,
|
|
ActorUserID: userID,
|
|
IncludeDeleted: false,
|
|
VerifyOwner: true,
|
|
})
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "failed to verify collection access")
|
|
}
|
|
// Verify that the user owns each file
|
|
for _, file := range files {
|
|
// todo #perf find owners of all files
|
|
ownerID, err := c.FileRepo.GetOwnerID(file.ID)
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
if ownerID != userID {
|
|
log.WithFields(log.Fields{
|
|
"file_id": file.ID,
|
|
"owner_id": ownerID,
|
|
"user_id": userID,
|
|
}).Error("invalid ops: can't add file which isn't owned by user")
|
|
return stacktrace.Propagate(ente.ErrPermissionDenied, "")
|
|
}
|
|
}
|
|
err = c.CollectionRepo.RestoreFiles(ctx, userID, cID, files)
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MoveFiles from one collection to another collection. Both the collections and files should belong to
|
|
// single user
|
|
func (c *CollectionController) MoveFiles(ctx *gin.Context, req ente.MoveFilesRequest) error {
|
|
userID := auth.GetUserID(ctx.Request.Header)
|
|
_, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{
|
|
CollectionID: req.FromCollectionID,
|
|
ActorUserID: userID,
|
|
IncludeDeleted: false,
|
|
VerifyOwner: true,
|
|
})
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "failed to verify if actor owns fromCollection")
|
|
}
|
|
|
|
_, err = c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{
|
|
CollectionID: req.ToCollectionID,
|
|
ActorUserID: userID,
|
|
IncludeDeleted: false,
|
|
VerifyOwner: true,
|
|
})
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "failed to verify if actor owns toCollection")
|
|
}
|
|
|
|
// Verify that the user owns each file
|
|
fileIDs := make([]int64, 0)
|
|
for _, file := range req.Files {
|
|
fileIDs = append(fileIDs, file.ID)
|
|
}
|
|
err = c.AccessCtrl.VerifyFileOwnership(ctx, &access.VerifyFileOwnershipParams{
|
|
ActorUserId: userID,
|
|
FileIDs: fileIDs,
|
|
})
|
|
if err != nil {
|
|
stacktrace.Propagate(err, "Failed to verify fileOwnership")
|
|
}
|
|
err = c.CollectionRepo.MoveFiles(ctx, req.ToCollectionID, req.FromCollectionID, req.Files, userID, userID)
|
|
return stacktrace.Propagate(err, "") // return nil if err is nil
|
|
}
|
|
|
|
// RemoveFilesV3 removes files from a collection as long as owner(s) of the file is different from collection owner
|
|
func (c *CollectionController) RemoveFilesV3(ctx *gin.Context, req ente.RemoveFilesV3Request) error {
|
|
actorUserID := auth.GetUserID(ctx.Request.Header)
|
|
resp, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{
|
|
CollectionID: req.CollectionID,
|
|
ActorUserID: actorUserID,
|
|
VerifyOwner: false,
|
|
})
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "failed to verify collection access")
|
|
}
|
|
err = c.isRemoveAllowed(ctx, actorUserID, resp.Collection.Owner.ID, req.FileIDs)
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "file removal check failed")
|
|
}
|
|
err = c.CollectionRepo.RemoveFilesV3(ctx, req.CollectionID, req.FileIDs)
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "failed to remove files")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// isRemoveAllowed verifies that given set of files can be removed from the collection or not
|
|
func (c *CollectionController) isRemoveAllowed(ctx *gin.Context, actorUserID int64, collectionOwnerID int64, fileIDs []int64) error {
|
|
ownerToFilesMap, err := c.FileRepo.GetOwnerToFileIDsMap(ctx, fileIDs)
|
|
if err != nil {
|
|
return stacktrace.Propagate(err, "failed to get owner to fileIDs map")
|
|
}
|
|
// verify that none of the file belongs to the collection owner
|
|
if _, ok := ownerToFilesMap[collectionOwnerID]; ok {
|
|
return ente.NewBadRequestWithMessage("can not remove files owned by album owner")
|
|
}
|
|
|
|
if collectionOwnerID != actorUserID {
|
|
// verify that user is only trying to remove files owned by them
|
|
if len(ownerToFilesMap) > 1 {
|
|
return stacktrace.Propagate(ente.ErrPermissionDenied, "can not remove files owned by others")
|
|
}
|
|
// verify that user is only trying to remove files owned by them
|
|
if _, ok := ownerToFilesMap[actorUserID]; !ok {
|
|
return stacktrace.Propagate(ente.ErrPermissionDenied, "can not remove files owned by others")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *CollectionController) IsCopyAllowed(ctx *gin.Context, actorUserID int64, req ente.CopyFileSyncRequest) error {
|
|
// verify that srcCollectionID is accessible by actorUserID
|
|
if _, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{
|
|
CollectionID: req.SrcCollectionID,
|
|
ActorUserID: actorUserID,
|
|
}); err != nil {
|
|
return stacktrace.Propagate(err, "failed to verify srcCollection access")
|
|
}
|
|
// verify that dstCollectionID is owned by actorUserID
|
|
if _, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{
|
|
CollectionID: req.DstCollection,
|
|
ActorUserID: actorUserID,
|
|
VerifyOwner: true,
|
|
}); err != nil {
|
|
return stacktrace.Propagate(err, "failed to ownership of the dstCollection access")
|
|
}
|
|
// verify that all FileIDs exists in the srcCollection
|
|
fileIDs := make([]int64, len(req.CollectionFileItems))
|
|
for idx, file := range req.CollectionFileItems {
|
|
fileIDs[idx] = file.ID
|
|
}
|
|
if err := c.CollectionRepo.VerifyAllFileIDsExistsInCollection(ctx, req.SrcCollectionID, fileIDs); err != nil {
|
|
return stacktrace.Propagate(err, "failed to verify fileIDs in srcCollection")
|
|
}
|
|
dsMap, err := c.FileRepo.GetOwnerToFileIDsMap(ctx, fileIDs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// verify that none of the file belongs to actorUserID
|
|
if _, ok := dsMap[actorUserID]; ok {
|
|
return ente.NewBadRequestWithMessage("can not copy files owned by actor")
|
|
}
|
|
return nil
|
|
}
|