fix server location on device registration

This commit is contained in:
m
2026-07-28 21:45:02 +02:00
parent 7af44152d7
commit 7cc425d28b
7 changed files with 158 additions and 31 deletions
+67 -22
View File
@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"encoding/hex"
"errors"
"fmt"
"mime/multipart"
"os"
@@ -17,12 +18,13 @@ import (
)
type ResourceService struct {
db *sql.DB
queries *db.Queries
cfg *config.Config
}
func NewResourceService(queries *db.Queries, cfg *config.Config) *ResourceService {
return &ResourceService{queries: queries, cfg: cfg}
func NewResourceService(database *sql.DB, queries *db.Queries, cfg *config.Config) *ResourceService {
return &ResourceService{db: database, queries: queries, cfg: cfg}
}
func (s *ResourceService) Upload(file *multipart.FileHeader, ownerID string) (*model.UploadResult, error) {
@@ -53,13 +55,15 @@ func (s *ResourceService) Upload(file *multipart.FileHeader, ownerID string) (*m
return nil, fmt.Errorf("parse owner id: %w", err)
}
existing, err := s.queries.FindDuplicateByChecksum(context.Background(), db.FindDuplicateByChecksumParams{
ctx := context.Background()
existing, err := s.queries.FindDuplicateByChecksum(ctx, db.FindDuplicateByChecksumParams{
Checksum: checksum,
OwnerID: ownerUUID,
})
if err == nil && existing.ID != uuid.Nil {
os.Remove(dst)
placement, err := s.queries.GetServerPlacementByResource(context.Background(), existing.ID)
placement, err := s.queries.GetServerPlacementByResource(ctx, existing.ID)
if err == nil {
return &model.UploadResult{
ID: existing.ID.String(),
@@ -68,9 +72,18 @@ func (s *ResourceService) Upload(file *multipart.FileHeader, ownerID string) (*m
MimeType: existing.MimeType,
}, nil
}
return nil, fmt.Errorf("duplicate resource %s has no server placement — upload cannot proceed until resolved", existing.ID.String())
}
dbResource, err := s.queries.CreateResource(context.Background(), db.CreateResourceParams{
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return nil, fmt.Errorf("begin tx: %w", err)
}
defer tx.Rollback()
qtx := s.queries.WithTx(tx)
dbResource, err := qtx.CreateResource(ctx, db.CreateResourceParams{
Name: file.Filename,
MimeType: file.Header.Get("Content-Type"),
Size: info.Size(),
@@ -81,15 +94,24 @@ func (s *ResourceService) Upload(file *multipart.FileHeader, ownerID string) (*m
return nil, fmt.Errorf("create resource in db: %w", err)
}
placement, err := s.ensureServerPlacement(dbResource.ID, ownerUUID, dst)
placement, err := s.ensureServerPlacementQtx(qtx, dbResource.ID, ownerUUID, dst)
if err != nil {
return nil, fmt.Errorf("create server placement: %w", err)
}
if err := s.ensureOwnerRebac(dbResource.ID, ownerUUID); err != nil {
if _, err := qtx.CreateRebacRelation(ctx, db.CreateRebacRelationParams{
ResourceID: dbResource.ID,
SubjectUserID: ownerUUID,
Role: "owner",
GrantedBy: ownerUUID,
}); err != nil {
return nil, fmt.Errorf("create owner rebac: %w", err)
}
if err := tx.Commit(); err != nil {
return nil, fmt.Errorf("commit tx: %w", err)
}
return &model.UploadResult{
ID: dbResource.ID.String(),
Name: dbResource.Name,
@@ -99,12 +121,26 @@ func (s *ResourceService) Upload(file *multipart.FileHeader, ownerID string) (*m
}
func (s *ResourceService) ensureServerPlacement(resourceID, ownerID uuid.UUID, dst string) (db.ResourcePlacement, error) {
serverLoc, err := s.queries.GetServerStorageLocation(context.Background(), ownerID)
return s.ensureServerPlacementQtx(s.queries, resourceID, ownerID, dst)
}
func (s *ResourceService) ensureServerPlacementQtx(q *db.Queries, resourceID, ownerID uuid.UUID, dst string) (db.ResourcePlacement, error) {
ctx := context.Background()
serverLoc, err := q.GetServerStorageLocation(ctx, ownerID)
if err != nil {
return db.ResourcePlacement{}, fmt.Errorf("get server location: %w", err)
if errors.Is(err, sql.ErrNoRows) {
serverLoc, err = q.CreateStorageLocation(ctx, db.CreateStorageLocationParams{
UserID: ownerID,
DeviceName: "VaultDrop Server",
Role: "server",
})
}
if err != nil {
return db.ResourcePlacement{}, fmt.Errorf("get/create server location: %w", err)
}
}
placement, err := s.queries.CreatePlacement(context.Background(), db.CreatePlacementParams{
placement, err := q.CreatePlacement(ctx, db.CreatePlacementParams{
ResourceID: resourceID,
StorageLocationID: serverLoc.ID,
Status: "synced",
@@ -118,16 +154,6 @@ func (s *ResourceService) ensureServerPlacement(resourceID, ownerID uuid.UUID, d
return placement, nil
}
func (s *ResourceService) ensureOwnerRebac(resourceID, ownerID uuid.UUID) error {
_, err := s.queries.CreateRebacRelation(context.Background(), db.CreateRebacRelationParams{
ResourceID: resourceID,
SubjectUserID: ownerID,
Role: "owner",
GrantedBy: ownerID,
})
return err
}
func (s *ResourceService) List(ownerID string) ([]model.Resource, error) {
ownerUUID, _ := uuid.Parse(ownerID)
dbResources, err := s.queries.ListResourcesByOwner(context.Background(), ownerUUID)
@@ -243,7 +269,17 @@ func (s *ResourceService) MoveResources(resourceIDs []string, parentResourceID *
func (s *ResourceService) CreateFolder(name, ownerID string) (*model.Resource, error) {
ownerUUID, _ := uuid.Parse(ownerID)
r, err := s.queries.CreateFolder(context.Background(), db.CreateFolderParams{
ctx := context.Background()
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return nil, fmt.Errorf("begin tx: %w", err)
}
defer tx.Rollback()
qtx := s.queries.WithTx(tx)
r, err := qtx.CreateFolder(ctx, db.CreateFolderParams{
Name: name,
OwnerID: ownerUUID,
})
@@ -251,10 +287,19 @@ func (s *ResourceService) CreateFolder(name, ownerID string) (*model.Resource, e
return nil, fmt.Errorf("create folder: %w", err)
}
if err := s.ensureOwnerRebac(r.ID, ownerUUID); err != nil {
if _, err := qtx.CreateRebacRelation(ctx, db.CreateRebacRelationParams{
ResourceID: r.ID,
SubjectUserID: ownerUUID,
Role: "owner",
GrantedBy: ownerUUID,
}); err != nil {
return nil, fmt.Errorf("create owner rebac: %w", err)
}
if err := tx.Commit(); err != nil {
return nil, fmt.Errorf("commit tx: %w", err)
}
m := dbResourceToModel(r, nil)
return &m, nil
}