diff --git a/server/pkg/controller/file.go b/server/pkg/controller/file.go index 7e772084435..48c69caf651 100644 --- a/server/pkg/controller/file.go +++ b/server/pkg/controller/file.go @@ -210,12 +210,28 @@ func (c *FileController) Create(ctx *gin.Context, userID int64, file ente.File, } return file, stacktrace.Propagate(err, "") } - if usage == fileSize+thumbnailSize { - go c.EmailNotificationCtrl.OnFirstFileUpload(file.OwnerID, userAgent) + if usage == fileSize+thumbnailSize && app == ente.Photos { + go c.maybeSendFirstUploadEmail(file.OwnerID, userAgent) } return file, nil } +func (c *FileController) maybeSendFirstUploadEmail(userID int64, userAgent string) { + ctx := context.Background() + hasTrashItems, err := c.TrashRepository.HasItems(ctx, userID) + if err != nil { + log.WithFields(log.Fields{ + "user_id": userID, + }).WithError(err).Error("Failed to determine trash state before sending first upload email") + return + } + if !hasTrashItems { + c.EmailNotificationCtrl.OnFirstFileUpload(userID, userAgent) + return + } + log.WithField("user_id", userID).Debug("Skipping first upload email because trash is not empty") +} + // Update verifies permissions and updates the specified file func (c *FileController) Update(ctx context.Context, userID int64, file ente.File, app ente.App) (ente.UpdateFileResponse, error) { var response ente.UpdateFileResponse diff --git a/server/pkg/repo/trash.go b/server/pkg/repo/trash.go index 897520682b3..826ee554cd4 100644 --- a/server/pkg/repo/trash.go +++ b/server/pkg/repo/trash.go @@ -344,6 +344,21 @@ func (t *TrashRepository) GetTimeStampForLatestNonDeletedEntry(userID int64) (*i return updatedAt, stacktrace.Propagate(err, "") } +// HasItems returns true if the user has any entries in trash. +func (t *TrashRepository) HasItems(ctx context.Context, userID int64) (bool, error) { + row := t.DB.QueryRowContext(ctx, ` + SELECT exists( + SELECT 1 FROM trash + WHERE user_id = $1 + )`, userID) + var hasItems bool + err := row.Scan(&hasItems) + if errors.Is(err, sql.ErrNoRows) { + return false, nil + } + return hasItems, stacktrace.Propagate(err, "") +} + // GetUserIDToFileIDsMapForDeletion returns map of userID to fileIds, where the file ids which should be deleted by now func (t *TrashRepository) GetUserIDToFileIDsMapForDeletion() (map[int64][]int64, error) { rows, err := t.DB.Query(`SELECT user_id, file_id FROM trash