Compare commits

...

4 Commits

Author SHA1 Message Date
Neeraj Gupta
7f8cadc022 Merge branch 'main' into meta_files 2025-09-09 10:07:07 +05:30
Neeraj Gupta
e9970cf1f3 Merge remote-tracking branch 'origin/main' into meta_files 2025-09-04 10:55:31 +05:30
Neeraj Gupta
0ec6e2e0ae refactor 2025-08-19 16:18:07 +05:30
Neeraj Gupta
3442648826 Support for creating meta only files 2025-08-19 14:56:24 +05:30
5 changed files with 140 additions and 3 deletions

View File

@@ -480,6 +480,7 @@ func main() {
privateAPI.GET("/files/data/preview", fileHandler.GetPreviewURL)
privateAPI.POST("/files", fileHandler.CreateOrUpdate)
privateAPI.POST("/files/meta", fileHandler.CreateMetaFile)
privateAPI.POST("/files/copy", fileHandler.CopyFiles)
privateAPI.PUT("/files/update", fileHandler.Update)
privateAPI.POST("/files/trash", fileHandler.Trash)

View File

@@ -26,6 +26,20 @@ type File struct {
Info *FileInfo `json:"info,omitempty"`
}
type MetaFile struct {
ID int64 `json:"id"`
OwnerID int64 `json:"ownerID"`
CollectionID int64 `json:"collectionID"`
EncryptedKey string `json:"encryptedKey"`
KeyDecryptionNonce string `json:"keyDecryptionNonce"`
Metadata FileAttributes `json:"metadata" binding:"required"`
// IsDeleted is True when the file ID is removed from the CollectionID
IsDeleted bool `json:"isDeleted"`
UpdationTime int64 `json:"updationTime"`
MagicMetadata *MagicMetadata `json:"magicMetadata,omitempty"`
PubicMagicMetadata *MagicMetadata `json:"pubMagicMetadata,omitempty"`
}
// FileInfo has information about storage used by the file & it's metadata(future)
type FileInfo struct {
FileSize int64 `json:"fileSize,omitempty"`

View File

@@ -2,14 +2,15 @@ package api
import (
"fmt"
"github.com/ente-io/museum/pkg/controller/file_copy"
"github.com/ente-io/museum/pkg/controller/filedata"
"github.com/ente-io/museum/pkg/controller/public"
"net/http"
"os"
"strconv"
"strings"
"github.com/ente-io/museum/pkg/controller/file_copy"
"github.com/ente-io/museum/pkg/controller/filedata"
"github.com/ente-io/museum/pkg/controller/public"
"github.com/ente-io/stacktrace"
"github.com/gin-contrib/requestid"
log "github.com/sirupsen/logrus"
@@ -66,6 +67,32 @@ func (h *FileHandler) CreateOrUpdate(c *gin.Context) {
c.JSON(http.StatusOK, response)
}
// CreateMetaFile creates an entry for a file
func (h *FileHandler) CreateMetaFile(c *gin.Context) {
userID := auth.GetUserID(c.Request.Header)
var file ente.MetaFile
if err := c.ShouldBindJSON(&file); err != nil {
handler.Error(c, stacktrace.Propagate(err, ""))
return
}
if file.ID != 0 {
handler.Error(c, stacktrace.Propagate(ente.ErrBadRequest, "fileID can't be set when creating a new file"))
return
}
file.UpdationTime = time.Microseconds()
// get an ente.App from the ?app= query parameter with a default of photos
enteApp := auth.GetApp(c)
file.OwnerID = userID
file.IsDeleted = false
resp, err := h.Controller.CreateMetaFile(c, userID, file, c.Request.UserAgent(), enteApp)
if err != nil {
handler.Error(c, stacktrace.Propagate(err, ""))
return
}
c.JSON(http.StatusOK, resp)
}
// CopyFiles copies files that are owned by another user
func (h *FileHandler) CopyFiles(c *gin.Context) {
var req ente.CopyFileSyncRequest

View File

@@ -0,0 +1,28 @@
package controller
import (
"github.com/ente-io/museum/ente"
"github.com/ente-io/stacktrace"
"github.com/gin-gonic/gin"
)
// CreateMetaFile adds an entry for a file in the respective tables
func (c *FileController) CreateMetaFile(ctx *gin.Context, userID int64, file ente.MetaFile, userAgent string, app ente.App) (*ente.File, error) {
collection, collErr := c.CollectionRepo.Get(file.CollectionID)
if collErr != nil {
return nil, stacktrace.Propagate(collErr, "")
}
// Verify that user owns the collection.
// Warning: Do not remove this check
if collection.Owner.ID != userID {
return nil, stacktrace.Propagate(ente.ErrPermissionDenied, "collection doesn't belong to user")
}
if collection.IsDeleted {
return nil, stacktrace.Propagate(ente.ErrCollectionDeleted, "collection has been deleted")
}
if file.OwnerID != userID {
return nil, stacktrace.Propagate(ente.ErrPermissionDenied, "file ownerID doesn't match with userID")
}
resp, err := c.FileRepo.CreateMetaFile(file, userID, app)
return resp, stacktrace.Propagate(err, "failed to create meta file")
}

View File

@@ -126,6 +126,73 @@ func (repo *FileRepository) Create(
return file, usage, stacktrace.Propagate(err, "")
}
// CreateMetaFile creates an entry in the database for the given file
func (repo *FileRepository) CreateMetaFile(
metaFile ente.MetaFile,
collectionOwnerID int64,
app ente.App,
) (*ente.File, error) {
ctx := context.Background()
tx, err := repo.DB.BeginTx(ctx, nil)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
if metaFile.OwnerID != collectionOwnerID {
return nil, stacktrace.Propagate(errors.New("both file and collection should belong to same owner"), "")
}
var fileID int64
info := &ente.FileInfo{
FileSize: 0,
ThumbnailSize: 0,
}
err = tx.QueryRowContext(ctx, `INSERT INTO files
(owner_id, encrypted_metadata,
file_decryption_header, thumbnail_decryption_header, metadata_decryption_header,
magic_metadata, pub_magic_metadata, info, updation_time)
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING file_id`,
metaFile.OwnerID, metaFile.Metadata.EncryptedData, "",
"", metaFile.Metadata.DecryptionHeader,
metaFile.MagicMetadata, metaFile.PubicMagicMetadata, info,
metaFile.UpdationTime).Scan(&fileID)
if err != nil {
tx.Rollback()
return nil, stacktrace.Propagate(err, "")
}
_, err = tx.ExecContext(ctx, `INSERT INTO collection_files
(collection_id, file_id, encrypted_key, key_decryption_nonce, is_deleted, updation_time, c_owner_id, f_owner_id)
VALUES($1, $2, $3, $4, $5, $6, $7, $8)`, metaFile.CollectionID, metaFile.ID,
metaFile.EncryptedKey, metaFile.KeyDecryptionNonce, false, metaFile.UpdationTime, metaFile.OwnerID, collectionOwnerID)
if err != nil {
tx.Rollback()
return nil, stacktrace.Propagate(err, "")
}
_, err = tx.ExecContext(ctx, `UPDATE collections SET updation_time = $1
WHERE collection_id = $2`, metaFile.UpdationTime, metaFile.CollectionID)
if err != nil {
tx.Rollback()
return nil, stacktrace.Propagate(err, "")
}
err = tx.Commit()
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
var file ente.File = ente.File{
ID: fileID,
UpdationTime: metaFile.UpdationTime,
OwnerID: metaFile.OwnerID,
Metadata: metaFile.Metadata,
PubicMagicMetadata: metaFile.PubicMagicMetadata,
MagicMetadata: metaFile.MagicMetadata,
EncryptedKey: metaFile.EncryptedKey,
KeyDecryptionNonce: metaFile.KeyDecryptionNonce,
Info: info,
CollectionID: collectionOwnerID,
}
return &file, stacktrace.Propagate(err, "")
}
// markAsNeedingReplication inserts new entries in object_copies, setting the
// current hot DC as the source copy.
//