mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-10-23 14:30:28 +02:00
feat: Enhance configuration forms and validation for storage providers
- Added hidden input fields to ensure critical values are submitted with the form for S3 and other storage providers. - Implemented JavaScript functionality to auto-populate hidden fields based on user input for S3-compatible providers. - Updated validation logic for WebDAV and SMB providers to ensure required fields are checked. - Enhanced the configuration handler to explicitly set fields for various storage provider types, including S3, Wasabi, MinIO, and B2. - Improved error handling and logging for form submissions and provider credential management.
This commit is contained in:
1 parent
776c4971a6
commit
dc665b9fa4
8 files changed
+661
-30
No files matched your search
@@ -169,9 +169,7 @@ func (sp *StorageProvider) SetAuthenticated(value bool) {
|
||||
func (sp *StorageProvider) IsOAuthProvider() bool {
|
||||
return sp.Type == ProviderTypeOneDrive ||
|
||||
sp.Type == ProviderTypeGoogleDrive ||
|
||||
sp.Type == ProviderTypeGooglePhoto ||
|
||||
sp.Type == ProviderTypeWebDAV ||
|
||||
sp.Type == ProviderTypeNextcloud
|
||||
sp.Type == ProviderTypeGooglePhoto
|
||||
}
|
||||
|
||||
// RequiresEncryption returns true if the provider has sensitive fields that need encryption
|
||||
|
||||
@@ -30,6 +30,8 @@ func (sp *StorageProvider) Validate() error {
|
||||
return sp.validateS3()
|
||||
case ProviderTypeFTP:
|
||||
return sp.validateFTP()
|
||||
case ProviderTypeWebDAV, ProviderTypeNextcloud:
|
||||
return sp.validateWebDAV()
|
||||
case ProviderTypeSMB:
|
||||
return sp.validateSMB()
|
||||
case ProviderTypeOneDrive:
|
||||
@@ -67,6 +69,24 @@ func (sp *StorageProvider) validateSFTP() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateWebDAV validates WebDAV-specific fields
|
||||
func (sp *StorageProvider) validateWebDAV() error {
|
||||
if strings.TrimSpace(sp.Host) == "" {
|
||||
return errors.New("host is required for WebDAV provider")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(sp.Username) == "" {
|
||||
return errors.New("username is required for WebDAV provider")
|
||||
}
|
||||
|
||||
// Either password or encrypted password must be provided
|
||||
if strings.TrimSpace(sp.Password) == "" && strings.TrimSpace(sp.EncryptedPassword) == "" {
|
||||
return errors.New("password is required for WebDAV provider")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateS3 validates S3-specific fields
|
||||
func (sp *StorageProvider) validateS3() error {
|
||||
// For S3, either AccessKey or Username is used
|
||||
@@ -115,10 +135,6 @@ func (sp *StorageProvider) validateSMB() error {
|
||||
return errors.New("host is required for SMB provider")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(sp.Share) == "" {
|
||||
return errors.New("share is required for SMB provider")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(sp.Username) == "" {
|
||||
return errors.New("username is required for SMB provider")
|
||||
}
|
||||
|
||||
@@ -191,6 +191,56 @@ func (db *DB) GenerateRcloneConfig(config *TransferConfig) error {
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to create source config (sftp): %v\nOutput: %s", err, output)
|
||||
}
|
||||
case "smb":
|
||||
args := []string{
|
||||
"config", "create", sourceName, "smb",
|
||||
"host", getStringValue(sourceCredentials, "host", config.SourceHost),
|
||||
"user", getStringValue(sourceCredentials, "username", config.SourceUser),
|
||||
"--non-interactive",
|
||||
"--config", configPath,
|
||||
"--log-level", "ERROR",
|
||||
}
|
||||
|
||||
// Get domain if provided
|
||||
domain := getStringValue(sourceCredentials, "domain", config.SourceDomain)
|
||||
if domain != "" {
|
||||
args = append(args, "domain", domain)
|
||||
}
|
||||
|
||||
// Get port if specified (default is 445)
|
||||
port := getIntValue(sourceCredentials, "port", config.SourcePort)
|
||||
if port > 0 && port != 445 {
|
||||
args = append(args, "port", fmt.Sprintf("%d", port))
|
||||
}
|
||||
|
||||
// Get share if provided
|
||||
share := getStringValue(sourceCredentials, "share", config.SourceShare)
|
||||
if share != "" {
|
||||
args = append(args, "share", share)
|
||||
}
|
||||
|
||||
// Handle password
|
||||
password := ""
|
||||
if config.SourcePassword != "" {
|
||||
password = config.SourcePassword
|
||||
} else if encryptedPwd, ok := sourceCredentials["encrypted_password"].(string); ok && encryptedPwd != "" {
|
||||
decryptedPwd, err := db.DecryptCredential(encryptedPwd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt source password: %v", err)
|
||||
}
|
||||
password = decryptedPwd
|
||||
} else if pwVal, ok := sourceCredentials["password"].(string); ok && pwVal != "" {
|
||||
password = pwVal
|
||||
}
|
||||
|
||||
if password != "" {
|
||||
args = append(args, "pass", password)
|
||||
}
|
||||
|
||||
cmd := exec.Command(rclonePath, args...)
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to create source config (smb): %v\nOutput: %s", err, output)
|
||||
}
|
||||
case "s3":
|
||||
args := []string{
|
||||
"config", "create", sourceName, "s3",
|
||||
@@ -269,12 +319,36 @@ func (db *DB) GenerateRcloneConfig(config *TransferConfig) error {
|
||||
case "b2":
|
||||
args := []string{
|
||||
"config", "create", sourceName, "b2",
|
||||
"account", config.SourceAccessKey, // B2 Account ID
|
||||
"key", config.SourceSecretKey, // B2 Application Key
|
||||
"--non-interactive",
|
||||
"--config", configPath,
|
||||
"--log-level", "ERROR",
|
||||
}
|
||||
// Handle account ID (access key)
|
||||
accountID := getStringValue(sourceCredentials, "access_key", config.SourceAccessKey)
|
||||
if accountID != "" {
|
||||
args = append(args, "account", accountID)
|
||||
}
|
||||
|
||||
// Handle secret key with proper decryption if from provider
|
||||
secretKey := ""
|
||||
if config.SourceSecretKey != "" {
|
||||
// Direct input from form (transient)
|
||||
secretKey = config.SourceSecretKey
|
||||
} else if encryptedSecret, ok := sourceCredentials["encrypted_secret_key"].(string); ok && encryptedSecret != "" {
|
||||
// Provider reference with encrypted secret
|
||||
decryptedSecret, err := db.DecryptCredential(encryptedSecret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt source secret key: %v", err)
|
||||
}
|
||||
secretKey = decryptedSecret
|
||||
} else if secretVal, ok := sourceCredentials["secret_key"].(string); ok && secretVal != "" {
|
||||
// Backward compatibility
|
||||
secretKey = secretVal
|
||||
}
|
||||
|
||||
if secretKey != "" {
|
||||
args = append(args, "key", secretKey)
|
||||
}
|
||||
if config.SourceEndpoint != "" {
|
||||
args = append(args, "endpoint", config.SourceEndpoint)
|
||||
}
|
||||
@@ -288,12 +362,32 @@ func (db *DB) GenerateRcloneConfig(config *TransferConfig) error {
|
||||
"provider", "Minio",
|
||||
"env_auth", "false",
|
||||
"access_key_id", getStringValue(sourceCredentials, "access_key", config.SourceAccessKey),
|
||||
"secret_access_key", getStringOrDefault(sourceCredentials, "secret_key", config.SourceSecretKey),
|
||||
"endpoint", getStringValue(sourceCredentials, "endpoint", config.SourceEndpoint),
|
||||
"--non-interactive",
|
||||
"--config", configPath,
|
||||
"--log-level", "ERROR",
|
||||
}
|
||||
// Handle secret key with proper decryption if from provider
|
||||
secretKey := ""
|
||||
if config.SourceSecretKey != "" {
|
||||
// Direct input from form (transient)
|
||||
secretKey = config.SourceSecretKey
|
||||
} else if encryptedSecret, ok := sourceCredentials["encrypted_secret_key"].(string); ok && encryptedSecret != "" {
|
||||
// Provider reference with encrypted secret
|
||||
decryptedSecret, err := db.DecryptCredential(encryptedSecret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt source secret key: %v", err)
|
||||
}
|
||||
secretKey = decryptedSecret
|
||||
} else if secretVal, ok := sourceCredentials["secret_key"].(string); ok && secretVal != "" {
|
||||
// Backward compatibility
|
||||
secretKey = secretVal
|
||||
}
|
||||
|
||||
if secretKey != "" {
|
||||
args = append(args, "secret_access_key", secretKey)
|
||||
}
|
||||
|
||||
// Add region if specified
|
||||
if getStringValue(sourceCredentials, "region", config.SourceRegion) != "" {
|
||||
args = append(args, "region", getStringValue(sourceCredentials, "region", config.SourceRegion))
|
||||
@@ -413,19 +507,89 @@ func (db *DB) GenerateRcloneConfig(config *TransferConfig) error {
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to create destination config (sftp): %v\nOutput: %s", err, output)
|
||||
}
|
||||
case "smb":
|
||||
args := []string{
|
||||
"config", "create", destName, "smb",
|
||||
"host", getStringValue(destCredentials, "host", config.DestHost),
|
||||
"user", getStringValue(destCredentials, "username", config.DestUser),
|
||||
"--non-interactive",
|
||||
"--config", configPath,
|
||||
"--log-level", "ERROR",
|
||||
}
|
||||
|
||||
// Get domain if provided
|
||||
domain := getStringValue(destCredentials, "domain", config.DestDomain)
|
||||
if domain != "" {
|
||||
args = append(args, "domain", domain)
|
||||
}
|
||||
|
||||
// Get port if specified (default is 445)
|
||||
port := getIntValue(destCredentials, "port", config.DestPort)
|
||||
if port > 0 && port != 445 {
|
||||
args = append(args, "port", fmt.Sprintf("%d", port))
|
||||
}
|
||||
|
||||
// Get share if provided
|
||||
share := getStringValue(destCredentials, "share", config.DestShare)
|
||||
if share != "" {
|
||||
args = append(args, "share", share)
|
||||
}
|
||||
|
||||
// Handle password
|
||||
password := ""
|
||||
if config.DestPassword != "" {
|
||||
password = config.DestPassword
|
||||
} else if encryptedPwd, ok := destCredentials["encrypted_password"].(string); ok && encryptedPwd != "" {
|
||||
decryptedPwd, err := db.DecryptCredential(encryptedPwd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt destination password: %v", err)
|
||||
}
|
||||
password = decryptedPwd
|
||||
} else if pwVal, ok := destCredentials["password"].(string); ok && pwVal != "" {
|
||||
password = pwVal
|
||||
}
|
||||
|
||||
if password != "" {
|
||||
args = append(args, "pass", password)
|
||||
}
|
||||
|
||||
cmd := exec.Command(rclonePath, args...)
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("failed to create destination config (smb): %v\nOutput: %s", err, output)
|
||||
}
|
||||
case "s3":
|
||||
args := []string{
|
||||
"config", "create", destName, "s3",
|
||||
"provider", "AWS", // Assuming AWS provider
|
||||
"env_auth", "false",
|
||||
"access_key_id", getStringValue(destCredentials, "access_key", config.DestAccessKey),
|
||||
"secret_access_key", getStringOrDefault(destCredentials, "secret_key", config.DestSecretKey),
|
||||
"region", getStringValue(destCredentials, "region", config.DestRegion),
|
||||
"--non-interactive",
|
||||
"--config", configPath,
|
||||
"--log-level", "ERROR",
|
||||
}
|
||||
|
||||
// Handle secret key with proper decryption if from provider
|
||||
secretKey := ""
|
||||
if config.DestSecretKey != "" {
|
||||
// Direct input from form (transient)
|
||||
secretKey = config.DestSecretKey
|
||||
} else if encryptedSecret, ok := destCredentials["encrypted_secret_key"].(string); ok && encryptedSecret != "" {
|
||||
// Provider reference with encrypted secret
|
||||
decryptedSecret, err := db.DecryptCredential(encryptedSecret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt destination secret key: %v", err)
|
||||
}
|
||||
secretKey = decryptedSecret
|
||||
} else if secretVal, ok := destCredentials["secret_key"].(string); ok && secretVal != "" {
|
||||
// Backward compatibility
|
||||
secretKey = secretVal
|
||||
}
|
||||
|
||||
if secretKey != "" {
|
||||
args = append(args, "secret_access_key", secretKey)
|
||||
}
|
||||
|
||||
endpoint := getStringValue(destCredentials, "endpoint", config.DestEndpoint)
|
||||
if endpoint != "" {
|
||||
args = append(args, "endpoint", endpoint)
|
||||
@@ -441,13 +605,33 @@ func (db *DB) GenerateRcloneConfig(config *TransferConfig) error {
|
||||
"provider", "Wasabi",
|
||||
"env_auth", "false",
|
||||
"access_key_id", getStringValue(destCredentials, "access_key", config.DestAccessKey),
|
||||
"secret_access_key", getStringOrDefault(destCredentials, "secret_key", config.DestSecretKey),
|
||||
"region", getStringValue(destCredentials, "region", config.DestRegion),
|
||||
"--non-interactive",
|
||||
"--config", configPath,
|
||||
"--log-level", "ERROR",
|
||||
}
|
||||
|
||||
// Handle secret key with proper decryption if from provider
|
||||
secretKey := ""
|
||||
if config.DestSecretKey != "" {
|
||||
// Direct input from form (transient)
|
||||
secretKey = config.DestSecretKey
|
||||
} else if encryptedSecret, ok := destCredentials["encrypted_secret_key"].(string); ok && encryptedSecret != "" {
|
||||
// Provider reference with encrypted secret
|
||||
decryptedSecret, err := db.DecryptCredential(encryptedSecret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt destination secret key: %v", err)
|
||||
}
|
||||
secretKey = decryptedSecret
|
||||
} else if secretVal, ok := destCredentials["secret_key"].(string); ok && secretVal != "" {
|
||||
// Backward compatibility
|
||||
secretKey = secretVal
|
||||
}
|
||||
|
||||
if secretKey != "" {
|
||||
args = append(args, "secret_access_key", secretKey)
|
||||
}
|
||||
|
||||
endpoint := getStringValue(destCredentials, "endpoint", config.DestEndpoint)
|
||||
if endpoint == "" {
|
||||
endpoint = "s3.wasabisys.com"
|
||||
@@ -472,6 +656,27 @@ func (db *DB) GenerateRcloneConfig(config *TransferConfig) error {
|
||||
args = append(args, "account", accountID)
|
||||
}
|
||||
|
||||
// Handle secret key with proper decryption if from provider
|
||||
secretKey := ""
|
||||
if config.DestSecretKey != "" {
|
||||
// Direct input from form (transient)
|
||||
secretKey = config.DestSecretKey
|
||||
} else if encryptedSecret, ok := destCredentials["encrypted_secret_key"].(string); ok && encryptedSecret != "" {
|
||||
// Provider reference with encrypted secret
|
||||
decryptedSecret, err := db.DecryptCredential(encryptedSecret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt destination secret key: %v", err)
|
||||
}
|
||||
secretKey = decryptedSecret
|
||||
} else if secretVal, ok := destCredentials["secret_key"].(string); ok && secretVal != "" {
|
||||
// Backward compatibility
|
||||
secretKey = secretVal
|
||||
}
|
||||
|
||||
if secretKey != "" {
|
||||
args = append(args, "key", secretKey)
|
||||
}
|
||||
|
||||
// Handle application key (secret key) with proper decryption if from provider
|
||||
appKey := ""
|
||||
if config.DestSecretKey != "" {
|
||||
@@ -508,12 +713,33 @@ func (db *DB) GenerateRcloneConfig(config *TransferConfig) error {
|
||||
"provider", "Minio",
|
||||
"env_auth", "false",
|
||||
"access_key_id", getStringValue(destCredentials, "access_key", config.DestAccessKey),
|
||||
"secret_access_key", getStringOrDefault(destCredentials, "secret_key", config.DestSecretKey),
|
||||
"endpoint", getStringValue(destCredentials, "endpoint", config.DestEndpoint),
|
||||
"--non-interactive",
|
||||
"--config", configPath,
|
||||
"--log-level", "ERROR",
|
||||
}
|
||||
|
||||
// Handle secret key with proper decryption if from provider
|
||||
secretKey := ""
|
||||
if config.DestSecretKey != "" {
|
||||
// Direct input from form (transient)
|
||||
secretKey = config.DestSecretKey
|
||||
} else if encryptedSecret, ok := destCredentials["encrypted_secret_key"].(string); ok && encryptedSecret != "" {
|
||||
// Provider reference with encrypted secret
|
||||
decryptedSecret, err := db.DecryptCredential(encryptedSecret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt destination secret key: %v", err)
|
||||
}
|
||||
secretKey = decryptedSecret
|
||||
} else if secretVal, ok := destCredentials["secret_key"].(string); ok && secretVal != "" {
|
||||
// Backward compatibility
|
||||
secretKey = secretVal
|
||||
}
|
||||
|
||||
if secretKey != "" {
|
||||
args = append(args, "secret_access_key", secretKey)
|
||||
}
|
||||
|
||||
// Add region if specified
|
||||
if getStringValue(destCredentials, "region", config.DestRegion) != "" {
|
||||
args = append(args, "region", getStringValue(destCredentials, "region", config.DestRegion))
|
||||
|
||||
@@ -104,7 +104,15 @@ func createTempTransferConfig(provider *db.StorageProvider) *db.TransferConfig {
|
||||
config.SetSourcePassiveMode(passive)
|
||||
}
|
||||
|
||||
case db.ProviderTypeS3:
|
||||
case db.ProviderTypeS3, db.ProviderTypeWasabi, db.ProviderTypeMinio:
|
||||
config.SourceAccessKey = provider.AccessKey
|
||||
config.SourceSecretKey = provider.SecretKey
|
||||
config.SourceBucket = provider.Bucket
|
||||
config.SourceRegion = provider.Region
|
||||
config.SourceEndpoint = provider.Endpoint
|
||||
|
||||
case db.ProviderTypeB2:
|
||||
// B2 uses AccessKey as account and SecretKey as application key
|
||||
config.SourceAccessKey = provider.AccessKey
|
||||
config.SourceSecretKey = provider.SecretKey
|
||||
config.SourceBucket = provider.Bucket
|
||||
@@ -162,13 +170,18 @@ func (s *ConnectorService) decryptProviderCredentials(provider *db.StorageProvid
|
||||
provider.Password = password
|
||||
}
|
||||
|
||||
case db.ProviderTypeS3:
|
||||
case db.ProviderTypeS3, db.ProviderTypeWasabi, db.ProviderTypeMinio, db.ProviderTypeB2:
|
||||
if provider.EncryptedSecretKey != "" {
|
||||
secretKey, err := s.credentialEncryptor.Decrypt(provider.EncryptedSecretKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decrypt secret key: %w", err)
|
||||
}
|
||||
provider.SecretKey = secretKey
|
||||
log.Printf("DEBUG: Decrypted secret key for %s provider (ID: %d, Type: %s) with length: %d",
|
||||
provider.Name, provider.ID, provider.Type, len(provider.SecretKey))
|
||||
} else {
|
||||
log.Printf("WARNING: No encrypted secret key found for %s provider (ID: %d, Type: %s)",
|
||||
provider.Name, provider.ID, provider.Type)
|
||||
}
|
||||
|
||||
case db.ProviderTypeOneDrive, db.ProviderTypeGoogleDrive, db.ProviderTypeGooglePhoto:
|
||||
|
||||
@@ -147,6 +147,112 @@ func (h *Handlers) HandleCreateConfig(c *gin.Context) {
|
||||
userID := c.GetUint("userID")
|
||||
config.CreatedBy = userID
|
||||
|
||||
// Explicitly set critical fields
|
||||
config.Name = c.PostForm("name")
|
||||
config.SourcePath = c.PostForm("source_path")
|
||||
config.DestinationPath = c.PostForm("destination_path")
|
||||
config.SourceType = c.PostForm("source_type")
|
||||
config.DestinationType = c.PostForm("destination_type")
|
||||
|
||||
// Debug logs
|
||||
log.Printf("DEBUG: Config data from form - Name: '%s', SourcePath: '%s', DestPath: '%s', SourceType: '%s', DestType: '%s'",
|
||||
config.Name, config.SourcePath, config.DestinationPath, config.SourceType, config.DestinationType)
|
||||
|
||||
// Additional fields we need to explicitly set
|
||||
if config.SourceType == "sftp" || config.SourceType == "ftp" || config.SourceType == "hetzner" {
|
||||
config.SourceHost = c.PostForm("source_host")
|
||||
portStr := c.PostForm("source_port")
|
||||
if portStr != "" {
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err == nil {
|
||||
config.SourcePort = port
|
||||
}
|
||||
}
|
||||
config.SourceUser = c.PostForm("source_user")
|
||||
config.SourcePassword = c.PostForm("source_password")
|
||||
config.SourceKeyFile = c.PostForm("source_key_file")
|
||||
}
|
||||
|
||||
if config.DestinationType == "sftp" || config.DestinationType == "ftp" || config.DestinationType == "hetzner" {
|
||||
config.DestHost = c.PostForm("dest_host")
|
||||
portStr := c.PostForm("dest_port")
|
||||
if portStr != "" {
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err == nil {
|
||||
config.DestPort = port
|
||||
}
|
||||
}
|
||||
config.DestUser = c.PostForm("dest_user")
|
||||
config.DestPassword = c.PostForm("dest_password")
|
||||
config.DestKeyFile = c.PostForm("dest_key_file")
|
||||
}
|
||||
|
||||
// S3 and similar providers
|
||||
if config.SourceType == "s3" || config.SourceType == "wasabi" || config.SourceType == "minio" || config.SourceType == "b2" {
|
||||
config.SourceBucket = c.PostForm("source_bucket")
|
||||
config.SourceRegion = c.PostForm("source_region")
|
||||
config.SourceAccessKey = c.PostForm("source_access_key")
|
||||
config.SourceSecretKey = c.PostForm("source_secret_key")
|
||||
config.SourceEndpoint = c.PostForm("source_endpoint")
|
||||
|
||||
// Debug logging for S3-compatible providers
|
||||
log.Printf("DEBUG: S3-compatible source provider details - Type: %s, Bucket: %s, Region: %s, Endpoint: %s, Has Access Key: %t, Has Secret Key: %t",
|
||||
config.SourceType,
|
||||
config.SourceBucket,
|
||||
config.SourceRegion,
|
||||
config.SourceEndpoint,
|
||||
config.SourceAccessKey != "",
|
||||
config.SourceSecretKey != "")
|
||||
}
|
||||
|
||||
if config.DestinationType == "s3" || config.DestinationType == "wasabi" || config.DestinationType == "minio" || config.DestinationType == "b2" {
|
||||
config.DestBucket = c.PostForm("dest_bucket")
|
||||
config.DestRegion = c.PostForm("dest_region")
|
||||
config.DestAccessKey = c.PostForm("dest_access_key")
|
||||
config.DestSecretKey = c.PostForm("dest_secret_key")
|
||||
config.DestEndpoint = c.PostForm("dest_endpoint")
|
||||
|
||||
// Debug logging for S3-compatible providers
|
||||
log.Printf("DEBUG: S3-compatible destination provider details - Type: %s, Bucket: %s, Region: %s, Endpoint: %s, Has Access Key: %t, Has Secret Key: %t",
|
||||
config.DestinationType,
|
||||
config.DestBucket,
|
||||
config.DestRegion,
|
||||
config.DestEndpoint,
|
||||
config.DestAccessKey != "",
|
||||
config.DestSecretKey != "")
|
||||
}
|
||||
|
||||
// SMB specific fields
|
||||
if config.SourceType == "smb" {
|
||||
config.SourceShare = c.PostForm("source_share")
|
||||
config.SourceDomain = c.PostForm("source_domain")
|
||||
}
|
||||
|
||||
if config.DestinationType == "smb" {
|
||||
config.DestShare = c.PostForm("dest_share")
|
||||
config.DestDomain = c.PostForm("dest_domain")
|
||||
}
|
||||
|
||||
// File pattern fields
|
||||
config.FilePattern = c.PostForm("file_pattern")
|
||||
config.OutputPattern = c.PostForm("output_pattern")
|
||||
|
||||
// Archive path
|
||||
config.ArchivePath = c.PostForm("archive_path")
|
||||
|
||||
// Max concurrent transfers
|
||||
maxConcurrentStr := c.PostForm("max_concurrent_transfers")
|
||||
if maxConcurrentStr != "" {
|
||||
maxConcurrent, err := strconv.Atoi(maxConcurrentStr)
|
||||
if err == nil && maxConcurrent > 0 {
|
||||
config.MaxConcurrentTransfers = maxConcurrent
|
||||
} else {
|
||||
config.MaxConcurrentTransfers = 4 // Default value
|
||||
}
|
||||
} else {
|
||||
config.MaxConcurrentTransfers = 4 // Default value
|
||||
}
|
||||
|
||||
// Process Boolean fields
|
||||
skipProcessedVal := c.Request.FormValue("skip_processed_files")
|
||||
skipProcessedValue := skipProcessedVal == "on" || skipProcessedVal == "true"
|
||||
|
||||
@@ -441,7 +441,12 @@ func (h *Handlers) parseProviderFromForm(c *gin.Context) (db.StorageProvider, er
|
||||
return provider, fmt.Errorf("host is required")
|
||||
}
|
||||
|
||||
case db.ProviderTypeS3:
|
||||
case db.ProviderTypeWebDAV, db.ProviderTypeNextcloud:
|
||||
// WebDAV specific fields
|
||||
provider.Username = c.PostForm("username")
|
||||
provider.Password = c.PostForm("password")
|
||||
|
||||
case db.ProviderTypeS3, db.ProviderTypeWasabi, db.ProviderTypeMinio, db.ProviderTypeB2:
|
||||
// S3 specific fields
|
||||
provider.AccessKey = c.PostForm("accessKey")
|
||||
provider.SecretKey = c.PostForm("secretKey")
|
||||
@@ -458,8 +463,13 @@ func (h *Handlers) parseProviderFromForm(c *gin.Context) (db.StorageProvider, er
|
||||
return provider, fmt.Errorf("bucket is required")
|
||||
}
|
||||
|
||||
if provider.Region == "" {
|
||||
return provider, fmt.Errorf("region is required")
|
||||
// Validate region based on provider type
|
||||
// B2 doesn't require region or endpoint
|
||||
// Wasabi doesn't require region
|
||||
if provider.Type == db.ProviderTypeS3 || provider.Type == db.ProviderTypeMinio {
|
||||
if provider.Region == "" {
|
||||
return provider, fmt.Errorf("region is required for %s", provider.Type)
|
||||
}
|
||||
}
|
||||
|
||||
case db.ProviderTypeOneDrive, db.ProviderTypeGoogleDrive, db.ProviderTypeGooglePhoto:
|
||||
|
||||
Reference in new issue
Block a user