first commit
This commit is contained in:
440
backend/internal/application/dto/dto.go
Normal file
440
backend/internal/application/dto/dto.go
Normal file
@@ -0,0 +1,440 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"github.com/noteapp/backend/internal/domain/entities"
|
||||
)
|
||||
|
||||
// ========== AUTH DTOs ==========
|
||||
|
||||
// RegisterRequest represents a registration request
|
||||
type RegisterRequest struct {
|
||||
Email string `json:"email" validate:"required,email"`
|
||||
Username string `json:"username" validate:"required,min=3,max=20"`
|
||||
Password string `json:"password" validate:"required,min=8"`
|
||||
PasswordConfirm string `json:"password_confirm" validate:"required,eqfield=Password"`
|
||||
FirstName string `json:"first_name" validate:"max=50"`
|
||||
LastName string `json:"last_name" validate:"max=50"`
|
||||
}
|
||||
|
||||
// LoginRequest represents a login request
|
||||
type LoginRequest struct {
|
||||
Email string `json:"email" validate:"required,email"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
}
|
||||
|
||||
// LoginResponse represents a login response
|
||||
type LoginResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
User *UserDTO `json:"user"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
}
|
||||
|
||||
// AuthProviderDTO represents an OAuth/OIDC provider in API responses.
|
||||
type AuthProviderDTO struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
AuthorizationURL string `json:"authorization_url,omitempty"`
|
||||
TokenURL string `json:"token_url,omitempty"`
|
||||
UserInfoURL string `json:"userinfo_url,omitempty"`
|
||||
Scopes []string `json:"scopes"`
|
||||
IDTokenClaim string `json:"id_token_claim,omitempty"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
// CreateAuthProviderRequest represents an OAuth/OIDC provider creation request.
|
||||
type CreateAuthProviderRequest struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
AuthorizationURL string `json:"authorization_url"`
|
||||
TokenURL string `json:"token_url"`
|
||||
UserInfoURL string `json:"userinfo_url"`
|
||||
Scopes []string `json:"scopes"`
|
||||
IDTokenClaim string `json:"id_token_claim,omitempty"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
// FeatureFlagsDTO represents app-wide feature flags in API responses.
|
||||
type FeatureFlagsDTO struct {
|
||||
RegistrationEnabled bool `json:"registration_enabled"`
|
||||
ProviderLoginEnabled bool `json:"provider_login_enabled"`
|
||||
PublicSharingEnabled bool `json:"public_sharing_enabled"`
|
||||
}
|
||||
|
||||
// UpdateFeatureFlagsRequest represents admin payload for feature flag updates.
|
||||
type UpdateFeatureFlagsRequest struct {
|
||||
RegistrationEnabled bool `json:"registration_enabled"`
|
||||
ProviderLoginEnabled bool `json:"provider_login_enabled"`
|
||||
PublicSharingEnabled bool `json:"public_sharing_enabled"`
|
||||
}
|
||||
|
||||
// UserDTO represents a user in API responses
|
||||
type UserDTO struct {
|
||||
ID string `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
GroupIDs []string `json:"group_ids,omitempty"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
}
|
||||
|
||||
// NewUserDTO creates a DTO from a user entity
|
||||
func NewUserDTO(user *entities.User) *UserDTO {
|
||||
groupIDs := make([]string, 0, len(user.GroupIDs))
|
||||
for _, groupID := range user.GroupIDs {
|
||||
groupIDs = append(groupIDs, groupID.Hex())
|
||||
}
|
||||
|
||||
return &UserDTO{
|
||||
ID: user.ID.Hex(),
|
||||
Email: user.Email,
|
||||
Username: user.Username,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Avatar: user.Avatar,
|
||||
GroupIDs: groupIDs,
|
||||
Permissions: user.Permissions,
|
||||
EmailVerified: user.EmailVerified,
|
||||
}
|
||||
}
|
||||
|
||||
// AdminUserDTO extends UserDTO with admin-visible fields
|
||||
type AdminUserDTO struct {
|
||||
*UserDTO
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// PermissionGroupDTO represents a permission group in API responses.
|
||||
type PermissionGroupDTO struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Permissions []string `json:"permissions"`
|
||||
IsSystem bool `json:"is_system"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// CreatePermissionGroupRequest represents group creation input.
|
||||
type CreatePermissionGroupRequest struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
|
||||
// UpdatePermissionGroupRequest represents group update input.
|
||||
type UpdatePermissionGroupRequest struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
|
||||
// UpdateUserGroupsRequest represents user group assignment input.
|
||||
type UpdateUserGroupsRequest struct {
|
||||
GroupIDs []string `json:"group_ids"`
|
||||
}
|
||||
|
||||
// NewAdminUserDTO creates an admin DTO from a user entity
|
||||
func NewAdminUserDTO(user *entities.User) *AdminUserDTO {
|
||||
return &AdminUserDTO{
|
||||
UserDTO: NewUserDTO(user),
|
||||
IsActive: user.IsActive,
|
||||
CreatedAt: user.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
}
|
||||
}
|
||||
|
||||
// NewPermissionGroupDTO creates a DTO from a permission group entity.
|
||||
func NewPermissionGroupDTO(group *entities.PermissionGroup) *PermissionGroupDTO {
|
||||
return &PermissionGroupDTO{
|
||||
ID: group.ID.Hex(),
|
||||
Name: group.Name,
|
||||
Description: group.Description,
|
||||
Permissions: group.Permissions,
|
||||
IsSystem: group.IsSystem,
|
||||
CreatedAt: group.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: group.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
}
|
||||
}
|
||||
|
||||
// AddSpaceMemberRequest represents a request to add a member to a space
|
||||
type AddSpaceMemberRequest struct {
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
|
||||
// SpaceMemberDTO represents a member in a space
|
||||
type SpaceMemberDTO struct {
|
||||
UserID string `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
JoinedAt string `json:"joined_at"`
|
||||
}
|
||||
|
||||
// UserOptionDTO is a lightweight user object for dropdowns
|
||||
type UserOptionDTO struct {
|
||||
ID string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// NewAuthProviderDTO creates a DTO from an auth provider entity.
|
||||
func NewAuthProviderDTO(provider *entities.AuthProvider) *AuthProviderDTO {
|
||||
return &AuthProviderDTO{
|
||||
ID: provider.ID.Hex(),
|
||||
Name: provider.Name,
|
||||
Type: provider.Type,
|
||||
AuthorizationURL: provider.AuthorizationURL,
|
||||
TokenURL: provider.TokenURL,
|
||||
UserInfoURL: provider.UserInfoURL,
|
||||
Scopes: provider.Scopes,
|
||||
IDTokenClaim: provider.IDTokenClaim,
|
||||
IsActive: provider.IsActive,
|
||||
}
|
||||
}
|
||||
|
||||
// NewFeatureFlagsDTO creates a DTO from feature flags entity.
|
||||
func NewFeatureFlagsDTO(flags *entities.FeatureFlags) *FeatureFlagsDTO {
|
||||
if flags == nil {
|
||||
flags = entities.NewDefaultFeatureFlags()
|
||||
}
|
||||
|
||||
return &FeatureFlagsDTO{
|
||||
RegistrationEnabled: flags.RegistrationEnabled,
|
||||
ProviderLoginEnabled: flags.ProviderLoginEnabled,
|
||||
PublicSharingEnabled: flags.PublicSharingEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
// ========== SPACE DTOs ==========
|
||||
|
||||
// CreateSpaceRequest represents a space creation request
|
||||
type CreateSpaceRequest struct {
|
||||
Name string `json:"name" validate:"required,min=1,max=100"`
|
||||
Description string `json:"description" validate:"max=500"`
|
||||
Icon string `json:"icon,omitempty" validate:"max=20"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
}
|
||||
|
||||
// SpaceDTO represents a space in API responses
|
||||
type SpaceDTO struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PermissionKey string `json:"permission_key"`
|
||||
Description string `json:"description"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
OwnerID string `json:"owner_id"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// NewSpaceDTO creates a DTO from a space entity
|
||||
func NewSpaceDTO(space *entities.Space) *SpaceDTO {
|
||||
dto := &SpaceDTO{
|
||||
ID: space.ID.Hex(),
|
||||
Name: space.Name,
|
||||
PermissionKey: entities.SpacePermissionToken(space.Name),
|
||||
Description: space.Description,
|
||||
Icon: space.Icon,
|
||||
OwnerID: space.OwnerID.Hex(),
|
||||
IsPublic: space.IsPublic,
|
||||
CreatedAt: space.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: space.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
}
|
||||
return dto
|
||||
}
|
||||
|
||||
// ========== NOTE DTOs ==========
|
||||
|
||||
// CreateNoteRequest represents a note creation request
|
||||
type CreateNoteRequest struct {
|
||||
Title string `json:"title" validate:"required,min=1,max=255"`
|
||||
Description string `json:"description" validate:"max=500"`
|
||||
Content string `json:"content"`
|
||||
NotePassword string `json:"note_password,omitempty" validate:"omitempty,min=4,max=128"`
|
||||
Tags []string `json:"tags"`
|
||||
CategoryID *string `json:"category_id,omitempty"`
|
||||
IsPinned bool `json:"is_pinned"`
|
||||
IsFavorite bool `json:"is_favorite"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
}
|
||||
|
||||
// UpdateNoteRequest represents a note update request
|
||||
type UpdateNoteRequest struct {
|
||||
Title string `json:"title" validate:"min=1,max=255"`
|
||||
Description *string `json:"description,omitempty" validate:"omitempty,max=500"`
|
||||
Content string `json:"content"`
|
||||
NotePassword *string `json:"note_password,omitempty" validate:"omitempty,max=128"`
|
||||
Tags []string `json:"tags"`
|
||||
CategoryID *string `json:"category_id,omitempty"`
|
||||
IsPinned *bool `json:"is_pinned"`
|
||||
IsFavorite *bool `json:"is_favorite"`
|
||||
IsPublic *bool `json:"is_public,omitempty"`
|
||||
}
|
||||
|
||||
// UnlockNoteRequest represents a password unlock request for protected notes
|
||||
type UnlockNoteRequest struct {
|
||||
Password string `json:"password" validate:"required,min=1,max=128"`
|
||||
}
|
||||
|
||||
// NoteDTO represents a note in API responses
|
||||
type NoteDTO struct {
|
||||
ID string `json:"id"`
|
||||
SpaceID string `json:"space_id"`
|
||||
CategoryID *string `json:"category_id,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Content string `json:"content"`
|
||||
Tags []string `json:"tags"`
|
||||
IsPinned bool `json:"is_pinned"`
|
||||
IsFavorite bool `json:"is_favorite"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
IsPasswordProtected bool `json:"is_password_protected"`
|
||||
CreatedBy string `json:"created_by"`
|
||||
UpdatedBy string `json:"updated_by"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// NoteListItemDTO represents a lightweight note payload for list/tree endpoints
|
||||
type NoteListItemDTO struct {
|
||||
ID string `json:"id"`
|
||||
SpaceID string `json:"space_id"`
|
||||
CategoryID *string `json:"category_id,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
IsPinned bool `json:"is_pinned"`
|
||||
IsFavorite bool `json:"is_favorite"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
IsPasswordProtected bool `json:"is_password_protected"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// NewNoteDTO creates a DTO from a note entity
|
||||
func NewNoteDTO(note *entities.Note) *NoteDTO {
|
||||
var categoryID *string
|
||||
if note.CategoryID != nil {
|
||||
id := note.CategoryID.Hex()
|
||||
categoryID = &id
|
||||
}
|
||||
return &NoteDTO{
|
||||
ID: note.ID.Hex(),
|
||||
SpaceID: note.SpaceID.Hex(),
|
||||
CategoryID: categoryID,
|
||||
Title: note.Title,
|
||||
Description: note.Description,
|
||||
Content: note.Content,
|
||||
Tags: note.Tags,
|
||||
IsPinned: note.IsPinned,
|
||||
IsFavorite: note.IsFavorite,
|
||||
IsPublic: note.IsPublic,
|
||||
IsPasswordProtected: note.IsPasswordProtected,
|
||||
CreatedBy: note.CreatedBy.Hex(),
|
||||
UpdatedBy: note.UpdatedBy.Hex(),
|
||||
CreatedAt: note.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: note.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
}
|
||||
}
|
||||
|
||||
// NewNoteListItemDTO creates a lightweight DTO from a note entity
|
||||
func NewNoteListItemDTO(note *entities.Note) *NoteListItemDTO {
|
||||
var categoryID *string
|
||||
if note.CategoryID != nil {
|
||||
id := note.CategoryID.Hex()
|
||||
categoryID = &id
|
||||
}
|
||||
|
||||
return &NoteListItemDTO{
|
||||
ID: note.ID.Hex(),
|
||||
SpaceID: note.SpaceID.Hex(),
|
||||
CategoryID: categoryID,
|
||||
Title: note.Title,
|
||||
Description: note.Description,
|
||||
IsPinned: note.IsPinned,
|
||||
IsFavorite: note.IsFavorite,
|
||||
IsPublic: note.IsPublic,
|
||||
IsPasswordProtected: note.IsPasswordProtected,
|
||||
UpdatedAt: note.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
}
|
||||
}
|
||||
|
||||
// ========== CATEGORY DTOs ==========
|
||||
|
||||
// CreateCategoryRequest represents a category creation request
|
||||
type CreateCategoryRequest struct {
|
||||
Name string `json:"name" validate:"required,min=1,max=100"`
|
||||
Description string `json:"description" validate:"max=500"`
|
||||
ParentID *string `json:"parent_id,omitempty"`
|
||||
Icon string `json:"icon,omitempty" validate:"max=20"`
|
||||
}
|
||||
|
||||
// UpdateCategoryRequest represents a category update request
|
||||
type UpdateCategoryRequest struct {
|
||||
Name string `json:"name" validate:"min=1,max=100"`
|
||||
Description string `json:"description" validate:"max=500"`
|
||||
Icon string `json:"icon,omitempty" validate:"max=20"`
|
||||
}
|
||||
|
||||
// CategoryDTO represents a category in API responses
|
||||
type CategoryDTO struct {
|
||||
ID string `json:"id"`
|
||||
SpaceID string `json:"space_id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ParentID *string `json:"parent_id,omitempty"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
Order int `json:"order"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// CategoryTreeDTO represents a category with its subcategories and notes
|
||||
type CategoryTreeDTO struct {
|
||||
*CategoryDTO
|
||||
Subcategories []*CategoryTreeDTO `json:"subcategories"`
|
||||
Notes []*NoteListItemDTO `json:"notes"`
|
||||
}
|
||||
|
||||
// NewCategoryDTO creates a DTO from a category entity
|
||||
func NewCategoryDTO(category *entities.Category) *CategoryDTO {
|
||||
var parentID *string
|
||||
if category.ParentID != nil {
|
||||
id := category.ParentID.Hex()
|
||||
parentID = &id
|
||||
}
|
||||
return &CategoryDTO{
|
||||
ID: category.ID.Hex(),
|
||||
SpaceID: category.SpaceID.Hex(),
|
||||
Name: category.Name,
|
||||
Description: category.Description,
|
||||
ParentID: parentID,
|
||||
Icon: category.Icon,
|
||||
Order: category.Order,
|
||||
CreatedAt: category.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: category.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
}
|
||||
}
|
||||
|
||||
// ========== ERROR DTOs ==========
|
||||
|
||||
// ErrorResponse represents an error response
|
||||
type ErrorResponse struct {
|
||||
Error string `json:"error"`
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
// ValidationError represents a validation error
|
||||
type ValidationError struct {
|
||||
Field string `json:"field"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// ValidationErrorResponse represents multiple validation errors
|
||||
type ValidationErrorResponse struct {
|
||||
Errors []ValidationError `json:"errors"`
|
||||
}
|
||||
Reference in New Issue
Block a user