aboutsummaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-03-08 02:27:15 +0530
committerBobby <[email protected]>2026-03-08 02:27:15 +0530
commitcca905d35412f1549400fc3d1aca6dc704d8cae6 (patch)
tree0c0231f5c2ebaeb7700e08a2c1f07373d3251658 /services
parent547384c41181c034a5eaf340c5e569d36eb013be (diff)
downloaddove-cca905d35412f1549400fc3d1aca6dc704d8cae6.tar.xz
dove-cca905d35412f1549400fc3d1aca6dc704d8cae6.zip
feat(domains): add new TLD creation page and update sidebar
- Introduced a new HTMX template for creating TLDs. - Created a new Django template for the new TLD page. - Updated the sidebar to include a link to the domains section. refactor(types): remove unused types and consolidate request handling - Deleted unused type definitions related to authentication, errors, mailboxes, overview, requests, responses, and users. - Introduced a new collections package for generic data structures. - Refactored request handling to use a more streamlined approach with RequestInfo and Param types. fix(meta): improve pagination and sorting functionality - Updated pagination logic to handle default values and edge cases. - Introduced a new Sorting type for better sorting management in queries. chore(urls): refactor URL handling and registry - Replaced enums with string constants for HTTP methods. - Consolidated route registration logic and improved type safety with RegisteredRoute. style(shortcuts): clean up error handling and rendering functions - Enhanced error handling functions for better readability and maintainability. - Removed deprecated functions and improved the structure of rendering logic.
Diffstat (limited to 'services')
-rw-r--r--services/auth/auth.go43
-rw-r--r--services/auth/messages.go7
-rw-r--r--services/domain/domain.go68
-rw-r--r--services/domain/messages.go16
-rw-r--r--services/domain/tld.go56
-rw-r--r--services/mail/mailboxes.go64
-rw-r--r--services/mail/messages.go14
-rw-r--r--services/mail/users.go52
8 files changed, 320 insertions, 0 deletions
diff --git a/services/auth/auth.go b/services/auth/auth.go
new file mode 100644
index 0000000..89ef205
--- /dev/null
+++ b/services/auth/auth.go
@@ -0,0 +1,43 @@
+package auth
+
+import (
+ "dove/config"
+ authUtils "dove/utils/auth"
+ "dove/utils/shortcuts"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+type LoginRequest struct {
+ Username string `form:"username"`
+ Password string `form:"password"`
+}
+
+type MessageResponse struct {
+ Message string
+}
+
+func Authenticate(context *fiber.Ctx, request LoginRequest) (*MessageResponse, *shortcuts.Error) {
+ switch request.Username == config.Server.Username && request.Password == config.Server.Password {
+ case true:
+ if sessionError := authUtils.Authenticate(context); sessionError != nil {
+ return nil, shortcuts.ServiceError(shortcuts.Internal, sessionError.Error())
+ }
+
+ return &MessageResponse{
+ Message: Authenticated,
+ }, nil
+ default:
+ return nil, shortcuts.ServiceError(shortcuts.Unauthorized, InvalidCredentials)
+ }
+}
+
+func Deauthenticate(context *fiber.Ctx) (*MessageResponse, *shortcuts.Error) {
+ if sessionError := authUtils.Deauthenticate(context); sessionError != nil {
+ return nil, shortcuts.ServiceError(shortcuts.Internal, sessionError.Error())
+ }
+
+ return &MessageResponse{
+ Message: LoggedOut,
+ }, nil
+} \ No newline at end of file
diff --git a/services/auth/messages.go b/services/auth/messages.go
new file mode 100644
index 0000000..f295dce
--- /dev/null
+++ b/services/auth/messages.go
@@ -0,0 +1,7 @@
+package auth
+
+const (
+ Authenticated = "Authenticated successfully."
+ InvalidCredentials = "Invalid username or password."
+ LoggedOut = "Logged out successfully."
+)
diff --git a/services/domain/domain.go b/services/domain/domain.go
new file mode 100644
index 0000000..39d5894
--- /dev/null
+++ b/services/domain/domain.go
@@ -0,0 +1,68 @@
+package domain
+
+import (
+ "strings"
+
+ domainModel "dove/models/domain"
+ domainRepo "dove/repositories/domain"
+ "dove/utils/shortcuts"
+)
+
+type CreateDomainRequest struct {
+ Name string `form:"name"`
+ TLDName string `form:"tld_name"`
+}
+
+type DomainListResponse struct {
+ Domains []domainModel.Domain `json:"domains"`
+ TLDs []domainModel.TLD `json:"tlds"`
+}
+
+type DomainFormResponse struct {
+ TLDs []domainModel.TLD `json:"tlds"`
+}
+
+func ListDomains() DomainListResponse {
+ return DomainListResponse{
+ Domains: domainRepo.AllDomains(),
+ TLDs: domainRepo.AllTLDs(),
+ }
+}
+
+func DomainFormData() DomainFormResponse {
+ return DomainFormResponse{
+ TLDs: domainRepo.AllTLDs(),
+ }
+}
+
+func CreateDomain(request CreateDomainRequest) *shortcuts.Error {
+ name := strings.TrimSpace(strings.ToLower(request.Name))
+ tldName := strings.TrimSpace(strings.ToLower(request.TLDName))
+
+ switch {
+ case name == "":
+ return shortcuts.ServiceError(shortcuts.BadRequest, DomainNameRequired)
+ case tldName == "":
+ return shortcuts.ServiceError(shortcuts.BadRequest, DomainTLDRequired)
+ }
+
+ tld := domainRepo.FindTLDByName(tldName)
+
+ switch {
+ case tld == nil:
+ return shortcuts.ServiceError(shortcuts.Unprocessable, TLDNotFound)
+ case domainRepo.FindDomainByFullName(name, tldName) != nil:
+ return shortcuts.ServiceError(shortcuts.Unprocessable, DomainAlreadyExists)
+ }
+
+ newDomain := &domainModel.Domain{
+ Name: name,
+ TLDID: tld.ID,
+ }
+
+ if createError := domainRepo.CreateDomain(newDomain); createError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, DomainCreationFailed)
+ }
+
+ return nil
+}
diff --git a/services/domain/messages.go b/services/domain/messages.go
new file mode 100644
index 0000000..5e42a3a
--- /dev/null
+++ b/services/domain/messages.go
@@ -0,0 +1,16 @@
+package domain
+
+const (
+ DomainAlreadyExists = "A domain with this name already exists under this TLD."
+ DomainCreationFailed = "Failed to create domain."
+ 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."
+ TLDNameRequired = "TLD name is required."
+ TLDNotFound = "TLD not found."
+ TLDProtected = "Default TLDs cannot be deleted."
+ TLDUpdateFailed = "Failed to update TLD."
+)
diff --git a/services/domain/tld.go b/services/domain/tld.go
new file mode 100644
index 0000000..eb80c14
--- /dev/null
+++ b/services/domain/tld.go
@@ -0,0 +1,56 @@
+package domain
+
+import (
+ "strings"
+
+ domainModel "dove/models/domain"
+ domainRepo "dove/repositories/domain"
+ "dove/utils/shortcuts"
+)
+
+type CreateTLDRequest struct {
+ Name string `form:"name"`
+}
+
+func AllTLDs() []domainModel.TLD {
+ return domainRepo.AllTLDs()
+}
+
+func CreateTLD(request CreateTLDRequest) *shortcuts.Error {
+ name := strings.TrimSpace(strings.ToLower(request.Name))
+
+ switch {
+ case name == "":
+ return shortcuts.ServiceError(shortcuts.BadRequest, TLDNameRequired)
+ case domainRepo.FindTLDByName(name) != nil:
+ return shortcuts.ServiceError(shortcuts.Unprocessable, TLDAlreadyExists)
+ }
+
+ tld := &domainModel.TLD{
+ Name: name,
+ IsDefault: false,
+ }
+
+ if createError := domainRepo.CreateTLD(tld); createError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, TLDCreationFailed)
+ }
+
+ return nil
+}
+
+func DeleteTLD(name string) *shortcuts.Error {
+ tld := domainRepo.FindTLDByName(name)
+
+ switch {
+ case tld == nil:
+ return shortcuts.ServiceError(shortcuts.NotFound, TLDNotFound)
+ case tld.IsDefault:
+ return shortcuts.ServiceError(shortcuts.Forbidden, TLDProtected)
+ }
+
+ if deleteError := domainRepo.DeleteTLD(tld); deleteError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, TLDDeletionFailed)
+ }
+
+ return nil
+}
diff --git a/services/mail/mailboxes.go b/services/mail/mailboxes.go
new file mode 100644
index 0000000..b124dc9
--- /dev/null
+++ b/services/mail/mailboxes.go
@@ -0,0 +1,64 @@
+package mail
+
+import (
+ "strings"
+
+ "dove/models"
+ "dove/repositories"
+ "dove/utils/meta"
+ "dove/utils/shortcuts"
+)
+
+type CreateMailboxRequest struct {
+ Address string `form:"address"`
+ UserID uint `form:"user_id"`
+}
+
+type MailboxFormResponse struct {
+ Users []models.User `json:"users"`
+}
+
+type MailboxView struct {
+ Address string
+}
+
+func ListMailboxes(pagination meta.Pagination, sorting meta.Sorting, search string) meta.PaginatedResponse {
+ mailboxes, total := repositories.ListMailboxes(pagination, sorting, search)
+ return pagination.Response(mailboxes, total)
+}
+
+func MailboxFormData() MailboxFormResponse {
+ return MailboxFormResponse{
+ Users: repositories.AllUsers(),
+ }
+}
+
+func CreateMailbox(request CreateMailboxRequest) *shortcuts.Error {
+ address := strings.TrimSpace(request.Address)
+
+ switch {
+ case address == "":
+ return shortcuts.ServiceError(shortcuts.BadRequest, AddressRequired)
+ case request.UserID == 0:
+ return shortcuts.ServiceError(shortcuts.BadRequest, UserRequired)
+ }
+
+ if repositories.FindUserByID(request.UserID) == nil {
+ return shortcuts.ServiceError(shortcuts.Unprocessable, UserNotFound)
+ }
+
+ if repositories.FindMailboxByAddress(address) != nil {
+ return shortcuts.ServiceError(shortcuts.Unprocessable, AlreadyExists)
+ }
+
+ mailbox := &models.Mailbox{
+ Address: address,
+ UserID: request.UserID,
+ }
+
+ if createError := repositories.CreateMailbox(mailbox); createError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, CreationFailed)
+ }
+
+ return nil
+}
diff --git a/services/mail/messages.go b/services/mail/messages.go
new file mode 100644
index 0000000..300f716
--- /dev/null
+++ b/services/mail/messages.go
@@ -0,0 +1,14 @@
+package mail
+
+const (
+ AddressRequired = "Mailbox address is required."
+ AlreadyExists = "A mailbox with this address already exists."
+ CreationFailed = "Failed to create mailbox."
+ UserNotFound = "The selected user does not exist."
+ UserRequired = "A user must be selected for the mailbox."
+
+ DisplayNameRequired = "Display name is required."
+ UserAlreadyExists = "A user with this username already exists."
+ UserCreationFailed = "Failed to create user."
+ UsernameRequired = "Username is required."
+)
diff --git a/services/mail/users.go b/services/mail/users.go
new file mode 100644
index 0000000..9520219
--- /dev/null
+++ b/services/mail/users.go
@@ -0,0 +1,52 @@
+package mail
+
+import (
+ "strings"
+
+ "dove/models"
+ "dove/repositories"
+ "dove/utils/meta"
+ "dove/utils/shortcuts"
+)
+
+type CreateUserRequest struct {
+ Username string `form:"username"`
+ DisplayName string `form:"display_name"`
+}
+
+func ListUsers(pagination meta.Pagination, sorting meta.Sorting, search string) meta.PaginatedResponse {
+ users, total := repositories.ListUsers(pagination, sorting, search)
+ return pagination.Response(users, total)
+}
+
+func CreateUser(request CreateUserRequest) *shortcuts.Error {
+ username := strings.TrimSpace(request.Username)
+ displayName := strings.TrimSpace(request.DisplayName)
+
+ if username == "" {
+ return shortcuts.ServiceError(shortcuts.BadRequest, UsernameRequired)
+ }
+
+ if displayName == "" {
+ return shortcuts.ServiceError(shortcuts.BadRequest, DisplayNameRequired)
+ }
+
+ if repositories.FindUserByUsername(username) != nil {
+ return shortcuts.ServiceError(shortcuts.Unprocessable, UserAlreadyExists)
+ }
+
+ newUser := &models.User{
+ Username: username,
+ DisplayName: displayName,
+ }
+
+ if createError := repositories.CreateUser(newUser); createError != nil {
+ return shortcuts.ServiceError(shortcuts.Internal, UserCreationFailed)
+ }
+
+ return nil
+}
+
+func AllUsers() []models.User {
+ return repositories.AllUsers()
+}