package application import ( "context" "fmt" "io" filestorage "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/storage" mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" "github.com/google/uuid" ) // DocumentConfig defines entity-specific document configuration type DocumentConfig struct { // Storage prefix for this entity type StoragePrefix string // Namespace for account validation (empty if no validation needed) AccountNamespace string // Whether to validate against MobilityAccounts service RequiresAccountValidation bool // Custom validator function (optional) CustomValidator func(ctx context.Context, entityID string) error } // Pre-configured document configs for each entity type var ( BeneficiaryDocumentConfig = DocumentConfig{ StoragePrefix: filestorage.PREFIX_BENEFICIARIES, AccountNamespace: "parcoursmob_beneficiaries", RequiresAccountValidation: true, } SolidarityDriverDocumentConfig = DocumentConfig{ StoragePrefix: filestorage.PREFIX_SOLIDARITY_TRANSPORT_DRIVERS, AccountNamespace: "solidarity_drivers", RequiresAccountValidation: true, } OrganizedCarpoolDriverDocumentConfig = DocumentConfig{ StoragePrefix: filestorage.PREFIX_ORGANIZED_CARPOOL_DRIVERS, AccountNamespace: "organized_carpool_drivers", RequiresAccountValidation: true, } BookingDocumentConfig = DocumentConfig{ StoragePrefix: filestorage.PREFIX_BOOKINGS, RequiresAccountValidation: false, } ) // AddDocument adds a document for any entity with validation func (h *ApplicationHandler) AddDocument( ctx context.Context, config DocumentConfig, entityID string, file io.Reader, filename string, fileSize int64, documentType string, documentName string, ) error { // Perform validation if required if config.RequiresAccountValidation { if err := h.validateAccountForDocument(ctx, entityID, config.AccountNamespace); err != nil { return err } } // Custom validation if provided if config.CustomValidator != nil { if err := config.CustomValidator(ctx, entityID); err != nil { return err } } // Generate unique file ID fileid := uuid.NewString() // Prepare metadata metadata := map[string]string{ "type": documentType, "name": documentName, } // Construct file path filepath := fmt.Sprintf("%s/%s_%s", entityID, fileid, filename) // Store file return h.filestorage.Put(file, config.StoragePrefix, filepath, fileSize, metadata) } // GetDocument retrieves a document for any entity with validation func (h *ApplicationHandler) GetDocument( ctx context.Context, config DocumentConfig, entityID string, document string, ) (io.Reader, *filestorage.FileInfo, error) { // Perform validation if required if config.RequiresAccountValidation { if err := h.validateAccountForDocument(ctx, entityID, config.AccountNamespace); err != nil { return nil, nil, err } } // Custom validation if provided if config.CustomValidator != nil { if err := config.CustomValidator(ctx, entityID); err != nil { return nil, nil, err } } // Retrieve file filepath := fmt.Sprintf("%s/%s", entityID, document) return h.filestorage.Get(config.StoragePrefix, filepath) } // ListDocuments retrieves all documents for an entity func (h *ApplicationHandler) ListDocuments( config DocumentConfig, entityID string, ) []filestorage.FileInfo { prefix := fmt.Sprintf("%s/%s", config.StoragePrefix, entityID) return h.filestorage.List(prefix) } // DeleteDocument deletes a document for any entity with validation func (h *ApplicationHandler) DeleteDocument( ctx context.Context, config DocumentConfig, entityID string, document string, ) error { // Perform validation if required if config.RequiresAccountValidation { if err := h.validateAccountForDocument(ctx, entityID, config.AccountNamespace); err != nil { return err } } // Custom validation if provided if config.CustomValidator != nil { if err := config.CustomValidator(ctx, entityID); err != nil { return err } } // Delete file filepath := fmt.Sprintf("%s/%s", entityID, document) return h.filestorage.Delete(config.StoragePrefix, filepath) } // validateAccountForDocument validates entity against MobilityAccounts service func (h *ApplicationHandler) validateAccountForDocument(ctx context.Context, accountID string, expectedNamespace string) error { resp, err := h.services.GRPC.MobilityAccounts.GetAccount(ctx, &mobilityaccounts.GetAccountRequest{ Id: accountID, }) if err != nil { return err } if resp.Account.Namespace != expectedNamespace { return fmt.Errorf("account %s is not of type %s (namespace: %s)", accountID, expectedNamespace, resp.Account.Namespace) } return nil }