aboutsummaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-03-08 18:17:23 +0530
committerBobby <[email protected]>2026-03-08 18:17:23 +0530
commit1136af49815be77a0aca151f3b8ec7348bf4b4c8 (patch)
treeca4d94f981be59c51fa7d160e32be978a8d4b4fb /services
parentf48054e9bc5e4fb36b9aba9126c6ace9c5b1f470 (diff)
downloaddove-1136af49815be77a0aca151f3b8ec7348bf4b4c8.tar.xz
dove-1136af49815be77a0aca151f3b8ec7348bf4b4c8.zip
feat(dns): add update functionality for DNS records (MX, SRV, TXT)
- Implemented UpdateMXRecord, UpdateSRVRecord, and UpdateTXTRecord functions in their respective repositories. - Added UpdateRecord method in dns service to handle updates for various DNS record types. - Updated router to include a new route for updating DNS records. - Enhanced error messages for record updates in messages.go. - Modified the frontend forms to support editing DNS records with improved UI components. - Refactored existing domain management code to remove unused update functionality. - Improved email handling by adding MX record validation during email delivery.
Diffstat (limited to 'services')
-rw-r--r--services/auth/auth.go2
-rw-r--r--services/dns/messages.go2
-rw-r--r--services/dns/records.go129
-rw-r--r--services/domain/domain.go67
-rw-r--r--services/domain/messages.go35
-rw-r--r--services/mail/aliases.go2
-rw-r--r--services/mail/mailboxes.go1
-rw-r--r--services/mail/messages.go44
-rw-r--r--services/mail/users.go2
9 files changed, 173 insertions, 111 deletions
diff --git a/services/auth/auth.go b/services/auth/auth.go
index b8a0e13..6c6589b 100644
--- a/services/auth/auth.go
+++ b/services/auth/auth.go
@@ -40,4 +40,4 @@ func Deauthenticate(context *fiber.Ctx) (*MessageResponse, *shortcuts.Error) {
return &MessageResponse{
Message: LoggedOut,
}, nil
-} \ No newline at end of file
+}
diff --git a/services/dns/messages.go b/services/dns/messages.go
index 723661a..2e24add 100644
--- a/services/dns/messages.go
+++ b/services/dns/messages.go
@@ -11,6 +11,8 @@ const (
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 56ece1f..782b943 100644
--- a/services/dns/records.go
+++ b/services/dns/records.go
@@ -27,6 +27,13 @@ type DomainRecordsResponse struct {
Records []RecordEntry `json:"records"`
}
+type UpdateRecordRequest struct {
+ Name string `form:"name"`
+ Value string `form:"value"`
+ TTL uint32 `form:"ttl"`
+ Priority uint16 `form:"priority"`
+}
+
type CreateRecordRequest struct {
DomainID uint `form:"domain_id"`
RecordType string `form:"record_type"`
@@ -85,6 +92,127 @@ func CreateRecord(request CreateRecordRequest) *shortcuts.Error {
}
}
+func UpdateRecord(recordType string, recordID uint, request UpdateRecordRequest) *shortcuts.Error {
+ name := strings.TrimSpace(request.Name)
+ value := strings.TrimSpace(request.Value)
+ ttl := request.TTL
+ if ttl == 0 {
+ ttl = 1
+ }
+
+ switch recordType {
+ case "A":
+ record := dnsRepo.FindARecordByID(recordID)
+ if record == nil {
+ return shortcuts.ServiceError(shortcuts.NotFound, RecordNotFound)
+ }
+ if name != "" {
+ record.Name = name
+ }
+ if value != "" {
+ record.Address = value
+ }
+ record.TTL = ttl
+ if updateError := dnsRepo.UpdateARecord(record); updateError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, RecordUpdateFailed)
+ }
+
+ case "AAAA":
+ record := dnsRepo.FindAAAARecordByID(recordID)
+ if record == nil {
+ return shortcuts.ServiceError(shortcuts.NotFound, RecordNotFound)
+ }
+ if name != "" {
+ record.Name = name
+ }
+ if value != "" {
+ record.Address = value
+ }
+ record.TTL = ttl
+ if updateError := dnsRepo.UpdateAAAARecord(record); updateError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, RecordUpdateFailed)
+ }
+
+ case "CNAME":
+ record := dnsRepo.FindCNAMERecordByID(recordID)
+ if record == nil {
+ return shortcuts.ServiceError(shortcuts.NotFound, RecordNotFound)
+ }
+ if name != "" {
+ record.Name = name
+ }
+ if value != "" {
+ record.Target = value
+ }
+ record.TTL = ttl
+ if updateError := dnsRepo.UpdateCNAMERecord(record); updateError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, RecordUpdateFailed)
+ }
+
+ case "MX":
+ record := dnsRepo.FindMXRecordByID(recordID)
+ if record == nil {
+ return shortcuts.ServiceError(shortcuts.NotFound, RecordNotFound)
+ }
+ if record.IsManaged {
+ return shortcuts.ServiceError(shortcuts.Forbidden, ManagedRecordUpdate)
+ }
+ if name != "" {
+ record.Name = name
+ }
+ if value != "" {
+ record.Target = value
+ }
+ if request.Priority > 0 {
+ record.Priority = request.Priority
+ }
+ record.TTL = ttl
+ if updateError := dnsRepo.UpdateMXRecord(record); updateError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, RecordUpdateFailed)
+ }
+
+ case "TXT":
+ record := dnsRepo.FindTXTRecordByID(recordID)
+ if record == nil {
+ return shortcuts.ServiceError(shortcuts.NotFound, RecordNotFound)
+ }
+ if name != "" {
+ record.Name = name
+ }
+ if value != "" {
+ record.Content = value
+ }
+ record.TTL = ttl
+ if updateError := dnsRepo.UpdateTXTRecord(record); updateError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, RecordUpdateFailed)
+ }
+
+ case "SRV":
+ record := dnsRepo.FindSRVRecordByID(recordID)
+ if record == nil {
+ return shortcuts.ServiceError(shortcuts.NotFound, RecordNotFound)
+ }
+ if name != "" {
+ record.Name = name
+ }
+ if value != "" {
+ record.Target = value
+ }
+ if request.Priority > 0 {
+ record.Priority = request.Priority
+ }
+ record.TTL = ttl
+ if updateError := dnsRepo.UpdateSRVRecord(record); updateError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, RecordUpdateFailed)
+ }
+
+ default:
+ return shortcuts.ServiceError(shortcuts.BadRequest, TypeInvalid)
+ }
+
+ return nil
+}
+
func DeleteRecord(recordType string, recordID uint) *shortcuts.Error {
switch recordType {
case "A":
@@ -389,4 +517,3 @@ func createSRVRecord(domainID uint, name string, target string, ttl uint32, prio
return nil
}
-
diff --git a/services/domain/domain.go b/services/domain/domain.go
index ff3efa5..35a6578 100644
--- a/services/domain/domain.go
+++ b/services/domain/domain.go
@@ -17,16 +17,6 @@ type CreateDomainRequest struct {
TLDName string `form:"tld_name"`
}
-type UpdateDomainRequest struct {
- Name string `form:"name"`
- TLDName string `form:"tld_name"`
-}
-
-type EditDomainFormResponse struct {
- Domain domainModel.Domain `json:"domain"`
- TLDs []domainModel.TLD `json:"tlds"`
-}
-
type DomainListResponse struct {
Domains []domainModel.Domain `json:"domains"`
}
@@ -101,63 +91,6 @@ func seedDefaultARecord(domainID uint) {
})
}
-func EditDomainFormData(domainID uint) (*EditDomainFormResponse, *shortcuts.Error) {
- foundDomain := domainRepo.FindDomainByID(domainID)
- if foundDomain == nil {
- return nil, shortcuts.ServiceError(shortcuts.NotFound, DomainNotFound)
- }
-
- return &EditDomainFormResponse{
- Domain: *foundDomain,
- TLDs: domainRepo.AllTLDs(),
- }, nil
-}
-
-func UpdateDomain(domainID uint, request UpdateDomainRequest) *shortcuts.Error {
- foundDomain := domainRepo.FindDomainByID(domainID)
- if foundDomain == nil {
- return shortcuts.ServiceError(shortcuts.NotFound, DomainNotFound)
- }
-
- name := strings.TrimSpace(strings.ToLower(request.Name))
- tldName := strings.TrimSpace(strings.ToLower(request.TLDName))
-
- switch {
- case name == "":
- return shortcuts.ServiceError(shortcuts.BadRequest, DomainNameRequired)
- case !validate.DNSLabel(name):
- return shortcuts.ServiceError(shortcuts.BadRequest, DomainNameInvalid)
- case tldName == "":
- return shortcuts.ServiceError(shortcuts.BadRequest, DomainTLDRequired)
- }
-
- tld := domainRepo.FindTLDByName(tldName)
- if tld == nil {
- return shortcuts.ServiceError(shortcuts.Unprocessable, TLDNotFound)
- }
-
- nameChanged := name != foundDomain.Name || tld.ID != foundDomain.TLDID
-
- if nameChanged {
- if domainRepo.FindDomainByFullName(name, tldName) != nil {
- return shortcuts.ServiceError(shortcuts.Unprocessable, DomainAlreadyExists)
- }
- }
-
- foundDomain.Name = name
- foundDomain.TLDID = tld.ID
-
- if updateError := domainRepo.UpdateDomain(foundDomain); updateError != nil {
- return shortcuts.ServiceError(shortcuts.Internal, DomainUpdateFailed)
- }
-
- if nameChanged {
- mailRepo.RebuildMailboxAddressesByDomainID(foundDomain.ID)
- }
-
- return nil
-}
-
func DeleteDomain(domainID uint) *shortcuts.Error {
foundDomain := domainRepo.FindDomainByID(domainID)
if foundDomain == nil {
diff --git a/services/domain/messages.go b/services/domain/messages.go
index 583fab0..e8b0ae3 100644
--- a/services/domain/messages.go
+++ b/services/domain/messages.go
@@ -1,22 +1,21 @@
package domain
const (
- DomainAlreadyExists = "A domain with this name already exists under this TLD."
- DomainCreationFailed = "Failed to create domain."
- DomainDeletionFailed = "Failed to delete domain."
- DomainHasMailboxes = "Cannot delete a domain that has mailboxes. Remove all mailboxes first."
- DomainNameInvalid = "Domain name must contain only lowercase letters, numbers, and hyphens."
- DomainNameRequired = "Domain name is required."
- DomainNotFound = "Domain not found."
- DomainUpdateFailed = "Failed to update domain."
- DomainTLDRequired = "A TLD must be selected for the domain."
- TLDAlreadyExists = "A TLD with this name already exists."
- TLDCreationFailed = "Failed to create TLD."
- TLDDeletionFailed = "Failed to delete TLD."
- TLDHasDomains = "Cannot delete a TLD that has registered domains. Remove all domains first."
- TLDNameInvalid = "TLD name must contain only lowercase letters, numbers, and hyphens."
- TLDNameRequired = "TLD name is required."
- TLDNotFound = "TLD not found."
- TLDProtected = "Default TLDs cannot be deleted."
- TLDUpdateFailed = "Failed to update TLD."
+ DomainAlreadyExists = "A domain with this name already exists under this TLD."
+ DomainCreationFailed = "Failed to create domain."
+ DomainDeletionFailed = "Failed to delete domain."
+ DomainHasMailboxes = "Cannot delete a domain that has mailboxes. Remove all mailboxes first."
+ DomainNameInvalid = "Domain name must contain only lowercase letters, numbers, and hyphens."
+ DomainNameRequired = "Domain name is required."
+ DomainNotFound = "Domain not found."
+ DomainTLDRequired = "A TLD must be selected for the domain."
+ TLDAlreadyExists = "A TLD with this name already exists."
+ TLDCreationFailed = "Failed to create TLD."
+ TLDDeletionFailed = "Failed to delete TLD."
+ TLDHasDomains = "Cannot delete a TLD that has registered domains. Remove all domains first."
+ TLDNameInvalid = "TLD name must contain only lowercase letters, numbers, and hyphens."
+ TLDNameRequired = "TLD name is required."
+ TLDNotFound = "TLD not found."
+ TLDProtected = "Default TLDs cannot be deleted."
+ TLDUpdateFailed = "Failed to update TLD."
)
diff --git a/services/mail/aliases.go b/services/mail/aliases.go
index 2999681..be10eae 100644
--- a/services/mail/aliases.go
+++ b/services/mail/aliases.go
@@ -3,8 +3,8 @@ package mail
import (
"strings"
- domainRepo "dove/repositories/domain"
mailModel "dove/models/mail"
+ domainRepo "dove/repositories/domain"
mailRepo "dove/repositories/mail"
"dove/utils/shortcuts"
"dove/utils/validate"
diff --git a/services/mail/mailboxes.go b/services/mail/mailboxes.go
index 0f076ad..d6c17d7 100644
--- a/services/mail/mailboxes.go
+++ b/services/mail/mailboxes.go
@@ -108,6 +108,7 @@ func seedMXRecordForDomain(targetDomain *domainModel.Domain) {
Name: "@",
Target: fullDomainName,
Priority: 10,
+ TTL: 1,
IsManaged: true,
})
}
diff --git a/services/mail/messages.go b/services/mail/messages.go
index 530ea45..87917fb 100644
--- a/services/mail/messages.go
+++ b/services/mail/messages.go
@@ -8,17 +8,17 @@ const (
AliasInvalid = "Alias address must be a valid email format ([email protected])."
AliasNotFound = "Alias not found."
- LocalPartInvalid = "Local part must contain only lowercase letters, numbers, dots, hyphens, and underscores."
- LocalPartRequired = "The local part of the address is required."
- DomainRequired = "A domain must be selected for the mailbox."
- DomainNotFound = "The selected domain does not exist."
- AlreadyExists = "A mailbox with this address already exists."
- CreationFailed = "Failed to create mailbox."
- DeletionFailed = "Failed to delete mailbox."
- MailboxNotFound = "Mailbox not found."
+ LocalPartInvalid = "Local part must contain only lowercase letters, numbers, dots, hyphens, and underscores."
+ LocalPartRequired = "The local part of the address is required."
+ DomainRequired = "A domain must be selected for the mailbox."
+ DomainNotFound = "The selected domain does not exist."
+ AlreadyExists = "A mailbox with this address already exists."
+ CreationFailed = "Failed to create mailbox."
+ DeletionFailed = "Failed to delete mailbox."
+ MailboxNotFound = "Mailbox not found."
MailboxUpdateFailed = "Failed to update mailbox."
- UserNotFound = "The selected user does not exist."
- UserRequired = "A user must be selected for the mailbox."
+ UserNotFound = "The selected user does not exist."
+ UserRequired = "A user must be selected for the mailbox."
EmailNotFound = "Email not found."
EmailMoveFailed = "Failed to move email."
@@ -31,19 +31,19 @@ const (
LogPrefix = "mail"
- FolderCreationFailed = "Failed to create folder."
- FolderDeletionFailed = "Failed to delete folder."
- FolderNameRequired = "Folder name is required."
- FolderNotFound = "Folder not found."
- FolderSeedFailed = "Failed to create default folders."
- FolderIsSystem = "System folders cannot be deleted."
- FolderHasEmails = "Cannot delete a folder that contains emails. Move or delete the emails first."
+ FolderCreationFailed = "Failed to create folder."
+ FolderDeletionFailed = "Failed to delete folder."
+ FolderNameRequired = "Folder name is required."
+ FolderNotFound = "Folder not found."
+ FolderSeedFailed = "Failed to create default folders."
+ FolderIsSystem = "System folders cannot be deleted."
+ FolderHasEmails = "Cannot delete a folder that contains emails. Move or delete the emails first."
- NoMailboxesExist = "No mailboxes exist. Create a mailbox first."
- RecipientRequired = "A recipient address is required."
- RecipientNotFound = "The recipient mailbox does not exist."
- SenderRequired = "A sender mailbox must be selected."
- SubjectRequired = "Subject is required."
+ NoMailboxesExist = "No mailboxes exist. Create a mailbox first."
+ RecipientRequired = "A recipient address is required."
+ RecipientNotFound = "The recipient mailbox does not exist."
+ SenderRequired = "A sender mailbox must be selected."
+ SubjectRequired = "Subject is required."
DisplayNameRequired = "Display name is required."
UserAlreadyExists = "A user with this username already exists."
diff --git a/services/mail/users.go b/services/mail/users.go
index 025c411..3d77fde 100644
--- a/services/mail/users.go
+++ b/services/mail/users.go
@@ -103,4 +103,4 @@ func DeleteUser(userID uint) *shortcuts.Error {
func AllUsers() []mailModel.User {
return mailRepo.AllUsers()
-} \ No newline at end of file
+}