feat: Implement error handling and response structure for API

- Added standardized error response structure in `errors.go` for consistent error handling across the API.
- Implemented specific response functions for various HTTP status codes (400, 401, 403, 404, 500) to enhance error reporting.
- Introduced validation error handling to provide detailed feedback on input validation issues.

test: Add comprehensive tests for share handler functionality

- Created a suite of tests for share handler endpoints, covering scenarios for creating, listing, deleting shares, and managing share links.
- Included tests for permission checks, validation errors, and edge cases such as unauthorized access and invalid document IDs.

chore: Set up test utilities and database for integration tests

- Established a base handler suite for common setup tasks in tests, including database initialization and teardown.
- Implemented test data seeding to facilitate consistent testing across different scenarios.

migration: Add public sharing support in the database schema

- Modified the `documents` table to include `share_token` and `is_public` columns for managing public document sharing.
- Added constraints to ensure data integrity, preventing public documents from lacking a share token.
This commit is contained in:
M1ngdaXie
2026-01-05 15:25:46 -08:00
parent 7f5f32179b
commit 8ae7fd96e8
15 changed files with 1870 additions and 118 deletions

View File

@@ -11,8 +11,15 @@ import (
"github.com/google/uuid"
)
// CreateDocumentShare creates a new share
func (s *PostgresStore) CreateDocumentShare(ctx context.Context, documentID, userID uuid.UUID, permission string, createdBy *uuid.UUID) (*models.DocumentShare, error) {
// CreateDocumentShare creates a new share or updates existing one
// Returns the share and a boolean indicating if it was newly created (true) or updated (false)
func (s *PostgresStore) CreateDocumentShare(ctx context.Context, documentID, userID uuid.UUID, permission string, createdBy *uuid.UUID) (*models.DocumentShare, bool, error) {
// First check if share already exists
var existingID uuid.UUID
checkQuery := `SELECT id FROM document_shares WHERE document_id = $1 AND user_id = $2`
err := s.db.QueryRowContext(ctx, checkQuery, documentID, userID).Scan(&existingID)
isNewShare := err != nil // If error (not found), it's a new share
query := `
INSERT INTO document_shares (document_id, user_id, permission, created_by)
VALUES ($1, $2, $3, $4)
@@ -21,15 +28,15 @@ func (s *PostgresStore) CreateDocumentShare(ctx context.Context, documentID, use
`
var share models.DocumentShare
err := s.db.QueryRowContext(ctx, query, documentID, userID, permission, createdBy).Scan(
err = s.db.QueryRowContext(ctx, query, documentID, userID, permission, createdBy).Scan(
&share.ID, &share.DocumentID, &share.UserID, &share.Permission,
&share.CreatedAt, &share.CreatedBy,
)
if err != nil {
return nil, err
return nil, false, err
}
return &share, nil
return &share, isNewShare, nil
}
// ListDocumentShares lists all shares for a document