aboutsummaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/dashboard/overview.go417
-rw-r--r--services/dns/messages.go2
-rw-r--r--services/dns/records.go47
-rw-r--r--services/domain/domain.go65
-rw-r--r--services/mail/mailboxes.go21
5 files changed, 488 insertions, 64 deletions
diff --git a/services/dashboard/overview.go b/services/dashboard/overview.go
new file mode 100644
index 0000000..e073bf8
--- /dev/null
+++ b/services/dashboard/overview.go
@@ -0,0 +1,417 @@
+package dashboard
+
+import (
+ "dove/config"
+ "fmt"
+ "math"
+ "math/rand"
+ "strings"
+
+ domainRepo "dove/repositories/domain"
+ mailRepo "dove/repositories/mail"
+ dnsSystem "dove/utils/dns"
+)
+
+type ServiceStatus struct {
+ Name string `json:"name"`
+ Port string `json:"port"`
+ Protocol string `json:"protocol"`
+ Active bool `json:"active"`
+}
+
+type SparklineData struct {
+ LinePath string `json:"line_path"`
+ FillPath string `json:"fill_path"`
+}
+
+type EmailCard struct {
+ Sparkline24h SparklineData `json:"sparkline_24h"`
+ Sparkline7d SparklineData `json:"sparkline_7d"`
+ Sparkline30d SparklineData `json:"sparkline_30d"`
+ TotalMailboxes int64 `json:"total_mailboxes"`
+ TotalDelivered int `json:"total_delivered"`
+ TotalBounced int `json:"total_bounced"`
+ BounceRate string `json:"bounce_rate"`
+ TotalMessages int64 `json:"total_messages"`
+}
+
+type DomainStatusEntry struct {
+ Name string `json:"name"`
+ StatusOk int `json:"status_ok"`
+ StatusErr int `json:"status_err"`
+ StatusWarn int `json:"status_warn"`
+ Total int `json:"total"`
+ PercentOk string `json:"percent_ok"`
+ PercentWarn string `json:"percent_warn"`
+ PercentErr string `json:"percent_err"`
+}
+
+type DomainsCard struct {
+ Domains []DomainStatusEntry `json:"domains"`
+ Selected string `json:"selected"`
+}
+
+type ProxyServiceEntry struct {
+ Name string `json:"name"`
+ Target string `json:"target"`
+ Up bool `json:"up"`
+}
+
+type ReverseProxyCard struct {
+ Services []ProxyServiceEntry `json:"services"`
+}
+
+type StorageBucketEntry struct {
+ Name string `json:"name"`
+ UsageBytes int64 `json:"usage_bytes"`
+ UsageLabel string `json:"usage_label"`
+ Percentage float64 `json:"percentage"`
+}
+
+type ObjectStorageCard struct {
+ Buckets []StorageBucketEntry `json:"buckets"`
+ TotalUsage string `json:"total_usage"`
+}
+
+type CronFailureEntry struct {
+ JobName string `json:"job_name"`
+ Domain string `json:"domain"`
+ FailedAt string `json:"failed_at"`
+ ErrorText string `json:"error_text"`
+}
+
+type CronJobsCard struct {
+ Failures []CronFailureEntry `json:"failures"`
+ TotalJobs int `json:"total_jobs"`
+ TotalRuns int `json:"total_runs"`
+ FailCount int `json:"fail_count"`
+}
+
+type DoveStatusEntry struct {
+ Route string `json:"route"`
+ Method string `json:"method"`
+ StatusCode int `json:"status_code"`
+ Count int `json:"count"`
+}
+
+type DoveCard struct {
+ StatusGroups map[string]int `json:"status_groups"`
+ RecentRoutes []DoveStatusEntry `json:"recent_routes"`
+ TotalRoutes int `json:"total_routes"`
+}
+
+type DnsCard struct {
+ Configured bool `json:"configured"`
+ Address string `json:"address"`
+ Platform string `json:"platform"`
+}
+
+type OverviewResponse struct {
+ BindAddress string `json:"bind_address"`
+ DnsAddress string `json:"dns_address"`
+ Services []ServiceStatus `json:"services"`
+ Email EmailCard `json:"email"`
+ Domains DomainsCard `json:"domains"`
+ ReverseProxy ReverseProxyCard `json:"reverse_proxy"`
+ Storage ObjectStorageCard `json:"storage"`
+ CronJobs CronJobsCard `json:"cron_jobs"`
+ Dove DoveCard `json:"dove"`
+ Dns DnsCard `json:"dns"`
+}
+
+func Overview() OverviewResponse {
+ return OverviewResponse{
+ BindAddress: config.BindAddress,
+ DnsAddress: fmt.Sprintf("%s:%d", config.BindAddress, config.DnsPort),
+ Services: buildServiceStatuses(),
+ Email: buildEmailCard(),
+ Domains: buildDomainsCard(),
+ ReverseProxy: buildReverseProxyCard(),
+ Storage: buildObjectStorageCard(),
+ CronJobs: buildCronJobsCard(),
+ Dove: buildDoveCard(),
+ Dns: buildDnsCard(),
+ }
+}
+
+func buildServiceStatuses() []ServiceStatus {
+ return []ServiceStatus{
+ {Name: "HTTP", Port: fmt.Sprintf("%d", config.HttpPort), Protocol: "Plain", Active: true},
+ {Name: "HTTPS", Port: "443", Protocol: "TLS", Active: false},
+ {Name: "DNS", Port: fmt.Sprintf("%d", config.DnsPort), Protocol: "UDP/TCP", Active: true},
+ {Name: "SMTP", Port: fmt.Sprintf("%d", config.SmtpPort), Protocol: "Plain/STARTTLS", Active: true},
+ {Name: "SMTPS", Port: fmt.Sprintf("%d", config.SmtpsPort), Protocol: "TLS", Active: true},
+ {Name: "SMTP (MSA)", Port: fmt.Sprintf("%d", config.SubmissionPort), Protocol: "Plain/STARTTLS", Active: true},
+ {Name: "IMAP", Port: fmt.Sprintf("%d", config.ImapPort), Protocol: "Plain/STARTTLS", Active: false},
+ {Name: "IMAPS", Port: fmt.Sprintf("%d", config.ImapsPort), Protocol: "TLS", Active: false},
+ {Name: "POP3", Port: fmt.Sprintf("%d", config.Pop3Port), Protocol: "Plain/STARTTLS", Active: false},
+ {Name: "POP3S", Port: fmt.Sprintf("%d", config.Pop3sPort), Protocol: "TLS", Active: false},
+ {Name: "S3", Port: fmt.Sprintf("%d", config.S3Port), Protocol: "Plain", Active: false},
+ }
+}
+
+const SparklineResolution = 100
+
+func buildEmailCard() EmailCard {
+ mailboxCount := mailRepo.CountMailboxes()
+ emailCount := mailRepo.CountEmails()
+ delivered := 150 + rand.Intn(500)
+ bounced := rand.Intn(20)
+ total := delivered + bounced
+ bounceRate := 0.0
+ if total > 0 {
+ bounceRate = float64(bounced) / float64(total) * 100
+ }
+
+ return EmailCard{
+ Sparkline24h: generateSparkline(24, 3, 40),
+ Sparkline7d: generateSparkline(28, 10, 80),
+ Sparkline30d: generateSparkline(30, 30, 200),
+ TotalMailboxes: mailboxCount,
+ TotalDelivered: delivered,
+ TotalBounced: bounced,
+ BounceRate: fmt.Sprintf("%.1f", math.Round(bounceRate*10)/10),
+ TotalMessages: emailCount,
+ }
+}
+
+func buildDomainsCard() DomainsCard {
+ allDomains := domainRepo.AllDomains()
+ entries := make([]DomainStatusEntry, 0, len(allDomains))
+
+ for _, domain := range allDomains {
+ tld := ""
+ if domain.TLD.Name != "" {
+ tld = "." + domain.TLD.Name
+ }
+ fullName := domain.Name + tld
+ statusOk := 200 + rand.Intn(800)
+ statusWarn := rand.Intn(50)
+ statusErr := rand.Intn(30)
+ total := statusOk + statusWarn + statusErr
+ percentOk := 0.0
+ percentWarn := 0.0
+ percentErr := 0.0
+ if total > 0 {
+ percentOk = math.Round(float64(statusOk)/float64(total)*1000) / 10
+ percentWarn = math.Round(float64(statusWarn)/float64(total)*1000) / 10
+ percentErr = math.Round(float64(statusErr)/float64(total)*1000) / 10
+ }
+ entries = append(entries, DomainStatusEntry{
+ Name: fullName,
+ StatusOk: statusOk,
+ StatusErr: statusErr,
+ StatusWarn: statusWarn,
+ Total: total,
+ PercentOk: fmt.Sprintf("%.1f", percentOk),
+ PercentWarn: fmt.Sprintf("%.1f", percentWarn),
+ PercentErr: fmt.Sprintf("%.1f", percentErr),
+ })
+ }
+
+ selected := ""
+ if len(entries) > 0 {
+ selected = entries[0].Name
+ }
+
+ return DomainsCard{
+ Domains: entries,
+ Selected: selected,
+ }
+}
+
+func buildReverseProxyCard() ReverseProxyCard {
+ return ReverseProxyCard{
+ Services: []ProxyServiceEntry{
+ {Name: "frontend", Target: "127.0.0.1:3001", Up: true},
+ {Name: "api", Target: "127.0.0.1:8080", Up: true},
+ {Name: "worker", Target: "127.0.0.1:9090", Up: false},
+ {Name: "docs", Target: "127.0.0.1:4000", Up: true},
+ {Name: "websocket", Target: "127.0.0.1:8443", Up: false},
+ },
+ }
+}
+
+func buildObjectStorageCard() ObjectStorageCard {
+ buckets := []StorageBucketEntry{
+ generateBucket("media-uploads", 1, 4),
+ generateBucket("backups", 500, 2000),
+ generateBucket("thumbnails", 50, 500),
+ generateBucket("exports", 10, 200),
+ }
+
+ var totalBytes int64
+ var maxBytes int64
+ for _, bucket := range buckets {
+ totalBytes += bucket.UsageBytes
+ if bucket.UsageBytes > maxBytes {
+ maxBytes = bucket.UsageBytes
+ }
+ }
+
+ for index := range buckets {
+ buckets[index].Percentage = float64(buckets[index].UsageBytes) / float64(maxBytes) * 100
+ }
+
+ return ObjectStorageCard{
+ Buckets: buckets,
+ TotalUsage: formatBytes(totalBytes),
+ }
+}
+
+func buildCronJobsCard() CronJobsCard {
+ totalJobs := 5 + rand.Intn(8)
+ totalRuns := 20 + rand.Intn(80)
+ failures := []CronFailureEntry{
+ {JobName: "cleanup-temp", Domain: "api.dove", FailedAt: "2m ago", ErrorText: "Connection refused on :8080"},
+ {JobName: "sync-storage", Domain: "cdn.dove", FailedAt: "18m ago", ErrorText: "Bucket not found: staging"},
+ {JobName: "health-ping", Domain: "monitor.dove", FailedAt: "1h ago", ErrorText: "Timeout after 30s"},
+ }
+
+ return CronJobsCard{
+ Failures: failures,
+ TotalJobs: totalJobs,
+ TotalRuns: totalRuns,
+ FailCount: len(failures),
+ }
+}
+
+func buildDoveCard() DoveCard {
+ statusGroups := map[string]int{
+ "2xx": 800 + rand.Intn(2000),
+ "3xx": 50 + rand.Intn(200),
+ "4xx": 10 + rand.Intn(50),
+ "5xx": rand.Intn(10),
+ }
+
+ recentRoutes := []DoveStatusEntry{
+ {Route: "/dashboard", Method: "GET", StatusCode: 200, Count: 120 + rand.Intn(200)},
+ {Route: "/domains", Method: "GET", StatusCode: 200, Count: 80 + rand.Intn(150)},
+ {Route: "/mail/webmail", Method: "GET", StatusCode: 200, Count: 60 + rand.Intn(100)},
+ {Route: "/domains/records", Method: "POST", StatusCode: 201, Count: 15 + rand.Intn(30)},
+ {Route: "/auth/login", Method: "POST", StatusCode: 302, Count: 10 + rand.Intn(20)},
+ {Route: "/mail/compose", Method: "POST", StatusCode: 500, Count: rand.Intn(5)},
+ {Route: "/domains/manage", Method: "DELETE", StatusCode: 404, Count: rand.Intn(8)},
+ }
+
+ return DoveCard{
+ StatusGroups: statusGroups,
+ RecentRoutes: recentRoutes,
+ TotalRoutes: len(recentRoutes),
+ }
+}
+
+func generateBucket(name string, minMegabytes int, maxMegabytes int) StorageBucketEntry {
+ megabytes := int64(minMegabytes) + int64(rand.Intn(maxMegabytes-minMegabytes))
+ bytes := megabytes * 1024 * 1024
+ return StorageBucketEntry{
+ Name: name,
+ UsageBytes: bytes,
+ UsageLabel: formatBytes(bytes),
+ }
+}
+
+func generateSparkline(anchorCount int, minValue float64, maxValue float64) SparklineData {
+ viewboxWidth := 200.0
+ viewboxHeight := 40.0
+ padding := 2.0
+
+ anchorValues := make([]float64, anchorCount)
+ currentValue := minValue + (maxValue-minValue)*0.3 + rand.Float64()*(maxValue-minValue)*0.4
+
+ for index := range anchorValues {
+ delta := (rand.Float64() - 0.45) * (maxValue - minValue) * 0.25
+ currentValue += delta
+ currentValue = math.Max(minValue, math.Min(maxValue, currentValue))
+ anchorValues[index] = currentValue
+ }
+
+ smoothValues := catmullRomResample(anchorValues, SparklineResolution)
+
+ minPoint := smoothValues[0]
+ maxPoint := smoothValues[0]
+ for _, point := range smoothValues {
+ if point < minPoint {
+ minPoint = point
+ }
+ if point > maxPoint {
+ maxPoint = point
+ }
+ }
+
+ pointRange := maxPoint - minPoint
+ if pointRange == 0 {
+ pointRange = 1
+ }
+
+ lineCoordinates := make([]string, SparklineResolution)
+ for index, point := range smoothValues {
+ horizontalPosition := padding + (float64(index)/float64(SparklineResolution-1))*(viewboxWidth-2*padding)
+ verticalPosition := padding + (1-(point-minPoint)/pointRange)*(viewboxHeight-2*padding)
+ lineCoordinates[index] = fmt.Sprintf("%.1f,%.1f", horizontalPosition, verticalPosition)
+ }
+
+ linePath := strings.Join(lineCoordinates, " ")
+
+ fillPath := fmt.Sprintf("M%.1f,%.1f L%s L%.1f,%.1f Z",
+ padding, viewboxHeight,
+ linePath,
+ viewboxWidth-padding, viewboxHeight,
+ )
+
+ return SparklineData{
+ LinePath: linePath,
+ FillPath: fillPath,
+ }
+}
+
+func catmullRomResample(inputValues []float64, outputCount int) []float64 {
+ inputCount := len(inputValues)
+ if inputCount < 2 {
+ return inputValues
+ }
+
+ resampledValues := make([]float64, outputCount)
+ for outputIndex := 0; outputIndex < outputCount; outputIndex++ {
+ normalizedPosition := float64(outputIndex) / float64(outputCount-1) * float64(inputCount-1)
+ segmentIndex := int(normalizedPosition)
+ segmentFraction := normalizedPosition - float64(segmentIndex)
+
+ point0 := inputValues[max(0, segmentIndex-1)]
+ point1 := inputValues[min(inputCount-1, segmentIndex)]
+ point2 := inputValues[min(inputCount-1, segmentIndex+1)]
+ point3 := inputValues[min(inputCount-1, segmentIndex+2)]
+
+ fractionSquared := segmentFraction * segmentFraction
+ fractionCubed := fractionSquared * segmentFraction
+
+ resampledValues[outputIndex] = 0.5 * ((2 * point1) +
+ (-point0+point2)*segmentFraction +
+ (2*point0-5*point1+4*point2-point3)*fractionSquared +
+ (-point0+3*point1-3*point2+point3)*fractionCubed)
+ }
+
+ return resampledValues
+}
+
+func buildDnsCard() DnsCard {
+ systemDnsStatus := dnsSystem.CheckSystemDns()
+ return DnsCard{
+ Configured: systemDnsStatus.Configured,
+ Address: systemDnsStatus.Address,
+ Platform: systemDnsStatus.Platform,
+ }
+}
+
+func formatBytes(bytes int64) string {
+ if bytes < 1024 {
+ return fmt.Sprintf("%d B", bytes)
+ }
+ if bytes < 1024*1024 {
+ return fmt.Sprintf("%.1f KB", float64(bytes)/1024)
+ }
+ if bytes < 1024*1024*1024 {
+ return fmt.Sprintf("%.1f MB", float64(bytes)/(1024*1024))
+ }
+ return fmt.Sprintf("%.1f GB", float64(bytes)/(1024*1024*1024))
+}
diff --git a/services/dns/messages.go b/services/dns/messages.go
index 2e24add..6b46c58 100644
--- a/services/dns/messages.go
+++ b/services/dns/messages.go
@@ -6,13 +6,11 @@ const (
AddressRequired = "Address is required."
ContentRequired = "TXT record content is required."
DomainNotFound = "Domain not found."
- ManagedRecordLocked = "System-managed records cannot be deleted."
NameRequired = "Record name is required."
PortRequired = "Port is required for SRV records."
RecordCreationFailed = "Failed to create DNS record."
RecordDeletionFailed = "Failed to delete DNS record."
RecordUpdateFailed = "Failed to update DNS record."
- ManagedRecordUpdate = "System-managed records cannot be modified."
RecordNotFound = "DNS record not found."
TargetRequired = "Target is required."
TypeInvalid = "Invalid DNS record type."
diff --git a/services/dns/records.go b/services/dns/records.go
index 782b943..6a66ab7 100644
--- a/services/dns/records.go
+++ b/services/dns/records.go
@@ -1,7 +1,6 @@
package dns
import (
- "fmt"
"net"
"strings"
@@ -13,13 +12,12 @@ import (
)
type RecordEntry struct {
- ID uint `json:"id"`
- Type string `json:"type"`
- Name string `json:"name"`
- Value string `json:"value"`
- TTL uint32 `json:"ttl"`
- Priority uint16 `json:"priority"`
- IsManaged bool `json:"is_managed"`
+ ID uint `json:"id"`
+ Type string `json:"type"`
+ Name string `json:"name"`
+ Value string `json:"value"`
+ TTL uint32 `json:"ttl"`
+ Priority uint16 `json:"priority"`
}
type DomainRecordsResponse struct {
@@ -44,7 +42,6 @@ type CreateRecordRequest struct {
Weight uint16 `form:"weight"`
Port uint16 `form:"port"`
Protocol string `form:"protocol"`
- PortMap int `form:"port_map"`
}
func DomainRecords(domainID uint) (*DomainRecordsResponse, *shortcuts.Error) {
@@ -71,12 +68,12 @@ func CreateRecord(request CreateRecordRequest) *shortcuts.Error {
value := strings.TrimSpace(request.Value)
ttl := request.TTL
if ttl == 0 {
- ttl = 300
+ ttl = 1
}
switch request.RecordType {
case "A":
- return createARecord(request.DomainID, name, value, ttl, request.PortMap)
+ return createARecord(request.DomainID, name, value, ttl)
case "AAAA":
return createAAAARecord(request.DomainID, name, value, ttl)
case "CNAME":
@@ -154,9 +151,6 @@ func UpdateRecord(recordType string, recordID uint, request UpdateRecordRequest)
if record == nil {
return shortcuts.ServiceError(shortcuts.NotFound, RecordNotFound)
}
- if record.IsManaged {
- return shortcuts.ServiceError(shortcuts.Forbidden, ManagedRecordUpdate)
- }
if name != "" {
record.Name = name
}
@@ -247,9 +241,6 @@ func DeleteRecord(recordType string, recordID uint) *shortcuts.Error {
if record == nil {
return shortcuts.ServiceError(shortcuts.NotFound, RecordNotFound)
}
- if record.IsManaged {
- return shortcuts.ServiceError(shortcuts.Forbidden, ManagedRecordLocked)
- }
if deleteError := dnsRepo.DeleteMXRecord(record); deleteError != nil {
return shortcuts.ServiceError(shortcuts.Internal, RecordDeletionFailed)
}
@@ -283,15 +274,11 @@ func collectAllRecords(domainID uint) []RecordEntry {
var entries []RecordEntry
for _, record := range dnsRepo.FindARecordsByDomainID(domainID) {
- value := record.Address
- if record.Port > 0 {
- value = fmt.Sprintf("%s (port %d)", record.Address, record.Port)
- }
entries = append(entries, RecordEntry{
ID: record.ID,
Type: "A",
Name: record.Name,
- Value: value,
+ Value: record.Address,
TTL: record.TTL,
})
}
@@ -318,13 +305,12 @@ func collectAllRecords(domainID uint) []RecordEntry {
for _, record := range dnsRepo.FindMXRecordsByDomainID(domainID) {
entries = append(entries, RecordEntry{
- ID: record.ID,
- Type: "MX",
- Name: record.Name,
- Value: record.Target,
- TTL: record.TTL,
- Priority: record.Priority,
- IsManaged: record.IsManaged,
+ ID: record.ID,
+ Type: "MX",
+ Name: record.Name,
+ Value: record.Target,
+ TTL: record.TTL,
+ Priority: record.Priority,
})
}
@@ -352,7 +338,7 @@ func collectAllRecords(domainID uint) []RecordEntry {
return entries
}
-func createARecord(domainID uint, name string, address string, ttl uint32, portMap int) *shortcuts.Error {
+func createARecord(domainID uint, name string, address string, ttl uint32) *shortcuts.Error {
if address == "" {
return shortcuts.ServiceError(shortcuts.BadRequest, AddressRequired)
}
@@ -370,7 +356,6 @@ func createARecord(domainID uint, name string, address string, ttl uint32, portM
DomainID: domainID,
Name: name,
Address: address,
- Port: portMap,
TTL: ttl,
}
diff --git a/services/domain/domain.go b/services/domain/domain.go
index 35a6578..91ca1e9 100644
--- a/services/domain/domain.go
+++ b/services/domain/domain.go
@@ -78,19 +78,11 @@ func CreateDomain(request CreateDomainRequest) *shortcuts.Error {
return shortcuts.ServiceError(shortcuts.Internal, DomainCreationFailed)
}
- seedDefaultARecord(newDomain.ID)
+ seedDefaultRecords(newDomain.ID, name, tldName)
return nil
}
-func seedDefaultARecord(domainID uint) {
- dnsRepo.CreateARecord(&dnsModel.ARecord{
- DomainID: domainID,
- Name: "@",
- Address: DefaultAddress,
- })
-}
-
func DeleteDomain(domainID uint) *shortcuts.Error {
foundDomain := domainRepo.FindDomainByID(domainID)
if foundDomain == nil {
@@ -110,6 +102,59 @@ func DeleteDomain(domainID uint) *shortcuts.Error {
return nil
}
+func seedDefaultRecords(domainID uint, domainName string, tldName string) {
+ mailHostname := DefaultMXTarget + "." + domainName + "." + tldName + "."
+
+ dnsRepo.CreateARecord(&dnsModel.ARecord{
+ DomainID: domainID,
+ Name: "@",
+ Address: DefaultAddress,
+ })
+
+ dnsRepo.CreateARecord(&dnsModel.ARecord{
+ DomainID: domainID,
+ Name: DefaultMXTarget,
+ Address: DefaultAddress,
+ })
+
+ dnsRepo.CreateMXRecord(&dnsModel.MXRecord{
+ DomainID: domainID,
+ Name: "@",
+ Target: mailHostname,
+ Priority: 10,
+ })
+
+ dnsRepo.CreateSRVRecord(&dnsModel.SRVRecord{
+ DomainID: domainID,
+ Name: "_submission._tcp",
+ Target: mailHostname,
+ Port: 587,
+ Priority: 0,
+ Weight: 0,
+ Protocol: "tcp",
+ })
+
+ dnsRepo.CreateSRVRecord(&dnsModel.SRVRecord{
+ DomainID: domainID,
+ Name: "_imap._tcp",
+ Target: mailHostname,
+ Port: 143,
+ Priority: 0,
+ Weight: 0,
+ Protocol: "tcp",
+ })
+
+ dnsRepo.CreateSRVRecord(&dnsModel.SRVRecord{
+ DomainID: domainID,
+ Name: "_pop3._tcp",
+ Target: mailHostname,
+ Port: 110,
+ Priority: 0,
+ Weight: 0,
+ Protocol: "tcp",
+ })
+}
+
func deleteAllDNSRecords(domainID uint) {
dnsRepo.DeleteARecordsByDomainID(domainID)
dnsRepo.DeleteAAAARecordsByDomainID(domainID)
@@ -117,4 +162,4 @@ func deleteAllDNSRecords(domainID uint) {
dnsRepo.DeleteMXRecordsByDomainID(domainID)
dnsRepo.DeleteTXTRecordsByDomainID(domainID)
dnsRepo.DeleteSRVRecordsByDomainID(domainID)
-}
+} \ No newline at end of file
diff --git a/services/mail/mailboxes.go b/services/mail/mailboxes.go
index d6c17d7..69c6ee7 100644
--- a/services/mail/mailboxes.go
+++ b/services/mail/mailboxes.go
@@ -3,10 +3,8 @@ package mail
import (
"strings"
- dnsModel "dove/models/dns"
domainModel "dove/models/domain"
mailModel "dove/models/mail"
- dnsRepo "dove/repositories/dns"
domainRepo "dove/repositories/domain"
mailRepo "dove/repositories/mail"
"dove/utils/meta"
@@ -91,28 +89,9 @@ func CreateMailbox(request CreateMailboxRequest) *shortcuts.Error {
return shortcuts.ServiceError(shortcuts.Internal, FolderSeedFailed)
}
- seedMXRecordForDomain(foundDomain)
-
return nil
}
-func seedMXRecordForDomain(targetDomain *domainModel.Domain) {
- fullDomainName := targetDomain.Name + "." + targetDomain.TLD.Name
- existingMX := dnsRepo.FindMXRecordByTarget(targetDomain.ID, fullDomainName)
- if existingMX != nil {
- return
- }
-
- dnsRepo.CreateMXRecord(&dnsModel.MXRecord{
- DomainID: targetDomain.ID,
- Name: "@",
- Target: fullDomainName,
- Priority: 10,
- TTL: 1,
- IsManaged: true,
- })
-}
-
func EditMailboxFormData(mailboxID uint) (*EditMailboxFormResponse, *shortcuts.Error) {
mailbox := mailRepo.FindMailboxByIDWithRelations(mailboxID)
if mailbox == nil {