128 lines
3.5 KiB
Go
128 lines
3.5 KiB
Go
package company
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"mime/multipart"
|
|
|
|
"tm/pkg/filestore"
|
|
)
|
|
|
|
const (
|
|
companyDocumentCategory = "company_document"
|
|
maxCompanyDocumentsUpload = 20
|
|
)
|
|
|
|
// UploadDocumentsResponse is returned after uploading company documents.
|
|
type UploadDocumentsResponse struct {
|
|
DocumentFileIDs []string `json:"document_file_ids"`
|
|
Uploaded []filestore.UploadedFileResult `json:"uploaded"`
|
|
Failed []filestore.FailedUploadResult `json:"failed,omitempty"`
|
|
}
|
|
|
|
// UploadDocuments uploads one or more files and appends their IDs to the company.
|
|
func (s *companyService) UploadDocuments(ctx context.Context, companyID, uploadedBy string, files []*multipart.FileHeader) (*UploadDocumentsResponse, error) {
|
|
if s.fileStore == nil {
|
|
return nil, errors.New("file storage is not configured")
|
|
}
|
|
if len(files) == 0 {
|
|
return nil, errors.New("no files provided")
|
|
}
|
|
if len(files) > maxCompanyDocumentsUpload {
|
|
return nil, errors.New("too many files in request")
|
|
}
|
|
|
|
company, err := s.repository.GetByID(ctx, companyID)
|
|
if err != nil {
|
|
return nil, errors.New("company not found")
|
|
}
|
|
|
|
opts := filestore.UploadOptions{
|
|
UploadedBy: uploadedBy,
|
|
Category: companyDocumentCategory,
|
|
MaxSize: filestore.MaxUploadSize,
|
|
Extra: map[string]string{
|
|
"company_id": companyID,
|
|
},
|
|
}
|
|
|
|
uploaded := make([]filestore.UploadedFileResult, 0, len(files))
|
|
failed := make([]filestore.FailedUploadResult, 0)
|
|
newIDs := make([]string, 0, len(files))
|
|
|
|
for _, file := range files {
|
|
result, uploadErr := filestore.UploadFromMultipartFile(s.fileStore, file, opts)
|
|
if uploadErr != nil {
|
|
code := filestore.ErrCodeUploadFailed
|
|
var fsErr *filestore.FileStoreError
|
|
if errors.As(uploadErr, &fsErr) {
|
|
code = fsErr.Code
|
|
}
|
|
failed = append(failed, filestore.FailedUploadResult{
|
|
Filename: file.Filename,
|
|
Error: uploadErr.Error(),
|
|
Code: code,
|
|
})
|
|
continue
|
|
}
|
|
uploaded = append(uploaded, result)
|
|
newIDs = append(newIDs, result.FileID)
|
|
}
|
|
|
|
if len(uploaded) == 0 {
|
|
s.logger.Warn("Company document upload failed for all files", map[string]interface{}{
|
|
"company_id": companyID,
|
|
"file_count": len(files),
|
|
})
|
|
return &UploadDocumentsResponse{
|
|
DocumentFileIDs: company.DocumentFileIDs,
|
|
Uploaded: uploaded,
|
|
Failed: failed,
|
|
}, errors.New("all file uploads failed")
|
|
}
|
|
|
|
company.DocumentFileIDs = mergeDocumentFileIDs(company.DocumentFileIDs, newIDs)
|
|
if err := s.repository.Update(ctx, company); err != nil {
|
|
s.logger.Error("Failed to save company documents", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"company_id": companyID,
|
|
})
|
|
return nil, errors.New("failed to update company documents")
|
|
}
|
|
|
|
s.logger.Info("Company documents uploaded", map[string]interface{}{
|
|
"company_id": companyID,
|
|
"uploaded_count": len(uploaded),
|
|
"failed_count": len(failed),
|
|
"documents_total": len(company.DocumentFileIDs),
|
|
})
|
|
|
|
return &UploadDocumentsResponse{
|
|
DocumentFileIDs: company.DocumentFileIDs,
|
|
Uploaded: uploaded,
|
|
Failed: failed,
|
|
}, nil
|
|
}
|
|
|
|
func mergeDocumentFileIDs(existing, additional []string) []string {
|
|
seen := make(map[string]struct{}, len(existing)+len(additional))
|
|
merged := make([]string, 0, len(existing)+len(additional))
|
|
|
|
appendUnique := func(ids []string) {
|
|
for _, id := range ids {
|
|
if id == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[id]; ok {
|
|
continue
|
|
}
|
|
seen[id] = struct{}{}
|
|
merged = append(merged, id)
|
|
}
|
|
}
|
|
|
|
appendUnique(existing)
|
|
appendUnique(additional)
|
|
return merged
|
|
}
|