From cca21c09d5a68de49e325f3652c3d5b29344ff36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20B=C3=B6sche?= Date: Sat, 24 Jan 2026 22:54:50 +0100 Subject: [PATCH] Allow NULL org_id in file_share_links for personal file sharing, update model and handlers --- go_cloud/internal/database/db.go | 43 ++++++++++++++++--- go_cloud/internal/http/routes.go | 2 +- go_cloud/internal/models/file_share_link.go | 2 +- .../0008_file_share_links_nullable_org.sql | 3 ++ ...008_file_share_links_nullable_org_down.sql | 3 ++ 5 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 go_cloud/migrations/0008_file_share_links_nullable_org.sql create mode 100644 go_cloud/migrations/0008_file_share_links_nullable_org_down.sql diff --git a/go_cloud/internal/database/db.go b/go_cloud/internal/database/db.go index 5828878..7c417eb 100644 --- a/go_cloud/internal/database/db.go +++ b/go_cloud/internal/database/db.go @@ -1153,22 +1153,38 @@ func (db *DB) MarkChallengeUsed(ctx context.Context, challenge []byte) error { // FileShareLink methods // CreateFileShareLink creates a new share link for a file -func (db *DB) CreateFileShareLink(ctx context.Context, token string, fileID, orgID, createdByUserID uuid.UUID) (*models.FileShareLink, error) { +func (db *DB) CreateFileShareLink(ctx context.Context, token string, fileID uuid.UUID, orgID *uuid.UUID, createdByUserID uuid.UUID) (*models.FileShareLink, error) { var link models.FileShareLink + var expiresAtNull sql.NullTime + var orgIDNull sql.NullString err := db.QueryRowContext(ctx, ` INSERT INTO file_share_links (token, file_id, org_id, created_by_user_id) VALUES ($1, $2, $3, $4) RETURNING id, token, file_id, org_id, created_by_user_id, created_at, updated_at, expires_at, is_revoked `, token, fileID, orgID, createdByUserID).Scan( - &link.ID, &link.Token, &link.FileID, &link.OrgID, &link.CreatedByUserID, - &link.CreatedAt, &link.UpdatedAt, &link.ExpiresAt, &link.IsRevoked) - return &link, err + &link.ID, &link.Token, &link.FileID, &orgIDNull, &link.CreatedByUserID, + &link.CreatedAt, &link.UpdatedAt, &expiresAtNull, &link.IsRevoked) + if err != nil { + return nil, err + } + if orgIDNull.Valid { + parsed, err := uuid.Parse(orgIDNull.String) + if err != nil { + return nil, err + } + link.OrgID = &parsed + } + if expiresAtNull.Valid { + link.ExpiresAt = &expiresAtNull.Time + } + return &link, nil } // GetFileShareLinkByFileID gets the active share link for a file func (db *DB) GetFileShareLinkByFileID(ctx context.Context, fileID uuid.UUID) (*models.FileShareLink, error) { var link models.FileShareLink var expiresAtNull sql.NullTime + var orgIDNull sql.NullString err := db.QueryRowContext(ctx, ` SELECT id, token, file_id, org_id, created_by_user_id, created_at, updated_at, expires_at, is_revoked FROM file_share_links @@ -1176,11 +1192,18 @@ func (db *DB) GetFileShareLinkByFileID(ctx context.Context, fileID uuid.UUID) (* ORDER BY created_at DESC LIMIT 1 `, fileID).Scan( - &link.ID, &link.Token, &link.FileID, &link.OrgID, &link.CreatedByUserID, + &link.ID, &link.Token, &link.FileID, &orgIDNull, &link.CreatedByUserID, &link.CreatedAt, &link.UpdatedAt, &expiresAtNull, &link.IsRevoked) if err != nil { return nil, err } + if orgIDNull.Valid { + parsed, err := uuid.Parse(orgIDNull.String) + if err != nil { + return nil, err + } + link.OrgID = &parsed + } if expiresAtNull.Valid { link.ExpiresAt = &expiresAtNull.Time } @@ -1191,16 +1214,24 @@ func (db *DB) GetFileShareLinkByFileID(ctx context.Context, fileID uuid.UUID) (* func (db *DB) GetFileShareLinkByToken(ctx context.Context, token string) (*models.FileShareLink, error) { var link models.FileShareLink var expiresAtNull sql.NullTime + var orgIDNull sql.NullString err := db.QueryRowContext(ctx, ` SELECT id, token, file_id, org_id, created_by_user_id, created_at, updated_at, expires_at, is_revoked FROM file_share_links WHERE token = $1 AND is_revoked = FALSE AND (expires_at IS NULL OR expires_at > NOW()) `, token).Scan( - &link.ID, &link.Token, &link.FileID, &link.OrgID, &link.CreatedByUserID, + &link.ID, &link.Token, &link.FileID, &orgIDNull, &link.CreatedByUserID, &link.CreatedAt, &link.UpdatedAt, &expiresAtNull, &link.IsRevoked) if err != nil { return nil, err } + if orgIDNull.Valid { + parsed, err := uuid.Parse(orgIDNull.String) + if err != nil { + return nil, err + } + link.OrgID = &parsed + } if expiresAtNull.Valid { link.ExpiresAt = &expiresAtNull.Time } diff --git a/go_cloud/internal/http/routes.go b/go_cloud/internal/http/routes.go index 58b51fe..5c8d041 100644 --- a/go_cloud/internal/http/routes.go +++ b/go_cloud/internal/http/routes.go @@ -3143,7 +3143,7 @@ func createUserFileShareLinkHandler(w http.ResponseWriter, r *http.Request, db * return } - link, err := db.CreateFileShareLink(r.Context(), token, fileUUID, userID, userID) + link, err := db.CreateFileShareLink(r.Context(), token, fileUUID, nil, userID) if err != nil { errors.LogError(r, err, "Failed to create share link") errors.WriteError(w, errors.CodeInternal, "Server error", http.StatusInternalServerError) diff --git a/go_cloud/internal/models/file_share_link.go b/go_cloud/internal/models/file_share_link.go index 31e3e7f..4014482 100644 --- a/go_cloud/internal/models/file_share_link.go +++ b/go_cloud/internal/models/file_share_link.go @@ -11,7 +11,7 @@ type FileShareLink struct { ID uuid.UUID `json:"id" db:"id"` Token string `json:"token" db:"token"` FileID uuid.UUID `json:"file_id" db:"file_id"` - OrgID uuid.UUID `json:"org_id" db:"org_id"` + OrgID *uuid.UUID `json:"org_id,omitempty" db:"org_id"` CreatedByUserID uuid.UUID `json:"created_by_user_id" db:"created_by_user_id"` CreatedAt time.Time `json:"created_at" db:"created_at"` UpdatedAt time.Time `json:"updated_at" db:"updated_at"` diff --git a/go_cloud/migrations/0008_file_share_links_nullable_org.sql b/go_cloud/migrations/0008_file_share_links_nullable_org.sql new file mode 100644 index 0000000..b8504f2 --- /dev/null +++ b/go_cloud/migrations/0008_file_share_links_nullable_org.sql @@ -0,0 +1,3 @@ +-- Make org_id nullable in file_share_links for personal file sharing + +ALTER TABLE file_share_links ALTER COLUMN org_id DROP NOT NULL; \ No newline at end of file diff --git a/go_cloud/migrations/0008_file_share_links_nullable_org_down.sql b/go_cloud/migrations/0008_file_share_links_nullable_org_down.sql new file mode 100644 index 0000000..3ed8bd3 --- /dev/null +++ b/go_cloud/migrations/0008_file_share_links_nullable_org_down.sql @@ -0,0 +1,3 @@ +-- Revert: Make org_id not nullable in file_share_links + +ALTER TABLE file_share_links ALTER COLUMN org_id SET NOT NULL; \ No newline at end of file