Move bizdev/freedoc/intent/projectworkflow/squad giant files into ≤800-line use-case siblings without behavior change; short tests green.
190 lines
4.3 KiB
Go
190 lines
4.3 KiB
Go
package freedoc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
// ShareDocument 将私密文档共享至项目参考库(仅 owner 可操作)
|
|
func (s *Service) ShareDocument(ctx context.Context, userID int, docID string) (*FreeformDocument, error) {
|
|
if docID == "" {
|
|
return nil, ErrNotFound
|
|
}
|
|
|
|
if s.pool != nil {
|
|
var doc FreeformDocument
|
|
row := s.pool.QueryRow(ctx, `
|
|
SELECT doc_id, project_id, owner_user_id, space, is_deleted
|
|
FROM freeform_documents WHERE doc_id = $1
|
|
`, docID)
|
|
if err := row.Scan(&doc.DocID, &doc.ProjectID, &doc.OwnerUserID, &doc.Space, &doc.IsDeleted); err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, ErrNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
if doc.IsDeleted {
|
|
return nil, ErrNotFound
|
|
}
|
|
if doc.OwnerUserID != userID {
|
|
return nil, ErrForbidden
|
|
}
|
|
|
|
now := time.Now()
|
|
_, err := s.pool.Exec(ctx, `
|
|
UPDATE freeform_documents
|
|
SET space = 'project_shared', updated_at = $1
|
|
WHERE doc_id = $2
|
|
`, now, docID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, _ = s.pool.Exec(ctx, `
|
|
INSERT INTO document_access_audit (doc_id, user_id, action, success, created_at)
|
|
VALUES ($1, $2, 'share', TRUE, $3)
|
|
`, docID, userID, now)
|
|
|
|
doc.Space = "project_shared"
|
|
doc.UpdatedAt = now
|
|
return &doc, nil
|
|
}
|
|
|
|
// 内存模式
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
doc, ok := s.memDocs[docID]
|
|
if !ok || doc.IsDeleted {
|
|
return nil, ErrNotFound
|
|
}
|
|
if doc.OwnerUserID != userID {
|
|
return nil, ErrForbidden
|
|
}
|
|
doc.Space = "project_shared"
|
|
doc.UpdatedAt = time.Now()
|
|
return doc, nil
|
|
}
|
|
|
|
// UnshareDocument 撤回共享,恢复为个人私密
|
|
func (s *Service) UnshareDocument(ctx context.Context, userID int, docID string) (*FreeformDocument, error) {
|
|
if docID == "" {
|
|
return nil, ErrNotFound
|
|
}
|
|
|
|
if s.pool != nil {
|
|
var doc FreeformDocument
|
|
row := s.pool.QueryRow(ctx, `
|
|
SELECT doc_id, project_id, owner_user_id, space, is_deleted
|
|
FROM freeform_documents WHERE doc_id = $1
|
|
`, docID)
|
|
if err := row.Scan(&doc.DocID, &doc.ProjectID, &doc.OwnerUserID, &doc.Space, &doc.IsDeleted); err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, ErrNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
if doc.IsDeleted {
|
|
return nil, ErrNotFound
|
|
}
|
|
if doc.OwnerUserID != userID {
|
|
return nil, ErrForbidden
|
|
}
|
|
|
|
now := time.Now()
|
|
_, err := s.pool.Exec(ctx, `
|
|
UPDATE freeform_documents
|
|
SET space = 'my_private', updated_at = $1
|
|
WHERE doc_id = $2
|
|
`, now, docID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, _ = s.pool.Exec(ctx, `
|
|
INSERT INTO document_access_audit (doc_id, user_id, action, success, created_at)
|
|
VALUES ($1, $2, 'unshare', TRUE, $3)
|
|
`, docID, userID, now)
|
|
|
|
doc.Space = "my_private"
|
|
doc.UpdatedAt = now
|
|
return &doc, nil
|
|
}
|
|
|
|
// 内存模式
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
doc, ok := s.memDocs[docID]
|
|
if !ok || doc.IsDeleted {
|
|
return nil, ErrNotFound
|
|
}
|
|
if doc.OwnerUserID != userID {
|
|
return nil, ErrForbidden
|
|
}
|
|
doc.Space = "my_private"
|
|
doc.UpdatedAt = time.Now()
|
|
return doc, nil
|
|
}
|
|
|
|
// DeleteDocument 软删除文档(仅 owner 可操作)
|
|
func (s *Service) DeleteDocument(ctx context.Context, userID int, docID string) error {
|
|
if docID == "" {
|
|
return ErrNotFound
|
|
}
|
|
|
|
if s.pool != nil {
|
|
var doc FreeformDocument
|
|
row := s.pool.QueryRow(ctx, `
|
|
SELECT doc_id, owner_user_id, is_deleted
|
|
FROM freeform_documents WHERE doc_id = $1
|
|
`, docID)
|
|
if err := row.Scan(&doc.DocID, &doc.OwnerUserID, &doc.IsDeleted); err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return ErrNotFound
|
|
}
|
|
return err
|
|
}
|
|
if doc.IsDeleted {
|
|
return nil
|
|
}
|
|
if doc.OwnerUserID != userID {
|
|
return ErrForbidden
|
|
}
|
|
|
|
now := time.Now()
|
|
_, err := s.pool.Exec(ctx, `
|
|
UPDATE freeform_documents
|
|
SET is_deleted = TRUE, deleted_at = $1, space = 'trash'
|
|
WHERE doc_id = $2
|
|
`, now, docID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, _ = s.pool.Exec(ctx, `
|
|
INSERT INTO document_access_audit (doc_id, user_id, action, success, created_at)
|
|
VALUES ($1, $2, 'delete', TRUE, $3)
|
|
`, docID, userID, now)
|
|
|
|
return nil
|
|
}
|
|
|
|
// 内存模式
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
doc, ok := s.memDocs[docID]
|
|
if !ok || doc.IsDeleted {
|
|
return ErrNotFound
|
|
}
|
|
if doc.OwnerUserID != userID {
|
|
return ErrForbidden
|
|
}
|
|
doc.IsDeleted = true
|
|
now := time.Now()
|
|
doc.DeletedAt = &now
|
|
doc.Space = "trash"
|
|
return nil
|
|
}
|