158 lines
7 KiB
Go
158 lines
7 KiB
Go
// monorepo/cloud/backend/internal/maplefile/service/collection/utils.go
|
|
package collection
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/gocql/gocql"
|
|
"go.uber.org/zap"
|
|
|
|
dom_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/collection"
|
|
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/validation"
|
|
)
|
|
|
|
// Helper function to get owner email from members list
|
|
// The owner is always a member with their email, so we can look them up
|
|
func getOwnerEmailFromMembers(collection *dom_collection.Collection) string {
|
|
if collection == nil {
|
|
return ""
|
|
}
|
|
for _, member := range collection.Members {
|
|
if member.RecipientID == collection.OwnerID {
|
|
return member.RecipientEmail
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Helper function to map a CollectionMembershipDTO to a CollectionMembership domain model
|
|
// This assumes a direct field-by-field copy is intended by the DTO structure.
|
|
func mapMembershipDTOToDomain(dto *CollectionMembershipDTO) dom_collection.CollectionMembership {
|
|
return dom_collection.CollectionMembership{
|
|
ID: dto.ID, // Copy DTO ID
|
|
CollectionID: dto.CollectionID, // Copy DTO CollectionID
|
|
RecipientID: dto.RecipientID, // Copy DTO RecipientID
|
|
RecipientEmail: dto.RecipientEmail, // Copy DTO RecipientEmail
|
|
GrantedByID: dto.GrantedByID, // Copy DTO GrantedByID
|
|
EncryptedCollectionKey: dto.EncryptedCollectionKey, // Copy DTO EncryptedCollectionKey
|
|
PermissionLevel: dto.PermissionLevel, // Copy DTO PermissionLevel
|
|
CreatedAt: dto.CreatedAt, // Copy DTO CreatedAt
|
|
IsInherited: dto.IsInherited, // Copy DTO IsInherited
|
|
InheritedFromID: dto.InheritedFromID, // Copy DTO InheritedFromID
|
|
// Note: ModifiedAt/By, Version are not in Membership DTO/Domain
|
|
}
|
|
}
|
|
|
|
// Helper function to map a CreateCollectionRequestDTO to a Collection domain model.
|
|
// This function recursively maps all fields, including nested members and children,
|
|
// copying values directly from the DTO. Server-side overrides for fields like
|
|
// ID, OwnerID, timestamps, and version are applied *after* this mapping in the Execute method.
|
|
// userID and now are passed for potential use in recursive calls if needed for consistency,
|
|
// though the primary goal here is to copy DTO values.
|
|
func mapCollectionDTOToDomain(dto *CreateCollectionRequestDTO, userID gocql.UUID, now time.Time) *dom_collection.Collection {
|
|
if dto == nil {
|
|
return nil
|
|
}
|
|
|
|
collection := &dom_collection.Collection{
|
|
// Copy all scalar/pointer fields directly from the DTO as requested by the prompt.
|
|
// Fields like ID, OwnerID, timestamps, and version from the DTO
|
|
// represent the client's proposed state and will be potentially
|
|
// overridden by server-managed values later in the Execute method.
|
|
ID: dto.ID,
|
|
OwnerID: dto.OwnerID,
|
|
EncryptedName: dto.EncryptedName,
|
|
EncryptedCustomIcon: dto.EncryptedCustomIcon,
|
|
CollectionType: dto.CollectionType,
|
|
EncryptedCollectionKey: dto.EncryptedCollectionKey,
|
|
ParentID: dto.ParentID,
|
|
AncestorIDs: dto.AncestorIDs,
|
|
CreatedAt: dto.CreatedAt,
|
|
CreatedByUserID: dto.CreatedByUserID,
|
|
ModifiedAt: dto.ModifiedAt,
|
|
ModifiedByUserID: dto.ModifiedByUserID,
|
|
}
|
|
|
|
// Map members slice from DTO to domain model slice
|
|
if len(dto.Members) > 0 {
|
|
collection.Members = make([]dom_collection.CollectionMembership, len(dto.Members))
|
|
for i, memberDTO := range dto.Members {
|
|
collection.Members[i] = mapMembershipDTOToDomain(memberDTO)
|
|
}
|
|
}
|
|
|
|
return collection
|
|
}
|
|
|
|
// Helper function to map a Collection domain model to a CollectionResponseDTO
|
|
// This function should ideally exclude sensitive data (like recipient-specific keys)
|
|
// that should not be part of a general response.
|
|
// fileCount is the number of active files in this collection (pass 0 if not known)
|
|
// ownerEmail is the email address of the collection owner (pass "" if not known)
|
|
func mapCollectionToDTO(collection *dom_collection.Collection, fileCount int, ownerEmail string) *CollectionResponseDTO {
|
|
if collection == nil {
|
|
return nil
|
|
}
|
|
|
|
responseDTO := &CollectionResponseDTO{
|
|
ID: collection.ID,
|
|
OwnerID: collection.OwnerID,
|
|
OwnerEmail: ownerEmail,
|
|
EncryptedName: collection.EncryptedName,
|
|
EncryptedCustomIcon: collection.EncryptedCustomIcon,
|
|
CollectionType: collection.CollectionType,
|
|
ParentID: collection.ParentID,
|
|
AncestorIDs: collection.AncestorIDs,
|
|
Tags: collection.Tags,
|
|
// Note: EncryptedCollectionKey from the domain model is the owner's key.
|
|
// Including it in the general response DTO might be acceptable if the response
|
|
// is only sent to the owner and contains *their* key. Otherwise, this field
|
|
// might need conditional inclusion or exclusion. The prompt does not require
|
|
// changing this, so we keep the original mapping which copies the owner's key.
|
|
EncryptedCollectionKey: collection.EncryptedCollectionKey,
|
|
CreatedAt: collection.CreatedAt,
|
|
ModifiedAt: collection.ModifiedAt,
|
|
FileCount: fileCount,
|
|
Version: collection.Version,
|
|
// Members slice needs mapping to MembershipResponseDTO
|
|
Members: make([]MembershipResponseDTO, len(collection.Members)),
|
|
}
|
|
|
|
// Map members
|
|
for i, member := range collection.Members {
|
|
responseDTO.Members[i] = MembershipResponseDTO{
|
|
ID: member.ID,
|
|
RecipientID: member.RecipientID,
|
|
RecipientEmail: member.RecipientEmail, // Email for display
|
|
PermissionLevel: member.PermissionLevel,
|
|
GrantedByID: member.GrantedByID,
|
|
CollectionID: member.CollectionID, // Redundant but useful
|
|
IsInherited: member.IsInherited,
|
|
InheritedFromID: member.InheritedFromID,
|
|
CreatedAt: member.CreatedAt,
|
|
// Note: EncryptedCollectionKey for this member is recipient-specific
|
|
// and should NOT be included in a general response DTO unless
|
|
// filtered for the specific recipient receiving the response.
|
|
// The MembershipResponseDTO does not have a field for this, which is correct.
|
|
EncryptedCollectionKey: member.EncryptedCollectionKey,
|
|
}
|
|
}
|
|
|
|
// Debug: Log what we're sending in the DTO
|
|
logger, _ := zap.NewDevelopment()
|
|
logger.Info("🔍 mapCollectionToDTO: Mapping collection to DTO",
|
|
zap.String("collection_id", collection.ID.String()),
|
|
zap.Int("domain_members_count", len(collection.Members)),
|
|
zap.Int("dto_members_count", len(responseDTO.Members)),
|
|
zap.Int("domain_tags_count", len(collection.Tags)),
|
|
zap.Int("dto_tags_count", len(responseDTO.Tags)))
|
|
for i, member := range responseDTO.Members {
|
|
logger.Info("🔍 mapCollectionToDTO: DTO member",
|
|
zap.Int("index", i),
|
|
zap.String("recipient_email", validation.MaskEmail(member.RecipientEmail)),
|
|
zap.String("recipient_id", member.RecipientID.String()),
|
|
zap.Int("encrypted_key_length", len(member.EncryptedCollectionKey)))
|
|
}
|
|
|
|
return responseDTO
|
|
}
|