diff --git a/backend/internal/core/dto/company.go b/backend/internal/core/dto/company.go index c6cf4d9..b9900b2 100644 --- a/backend/internal/core/dto/company.go +++ b/backend/internal/core/dto/company.go @@ -3,21 +3,25 @@ package dto import "time" type CreateCompanyRequest struct { - Name string `json:"name"` - CompanyName string `json:"companyName"` // Alternative field name - Document string `json:"document"` - Contact string `json:"contact"` - AdminEmail string `json:"admin_email"` - Email string `json:"email"` // Alternative field name - Password string `json:"password"` - Phone string `json:"phone"` - Website *string `json:"website,omitempty"` - Address *string `json:"address,omitempty"` - EmployeeCount *string `json:"employeeCount,omitempty"` - FoundedYear *int `json:"foundedYear,omitempty"` - Description *string `json:"description,omitempty"` - YearsInMarket *string `json:"years_in_market,omitempty"` - BirthDate *string `json:"birth_date,omitempty"` + Name string `json:"name"` + CompanyName string `json:"companyName"` // Alternative field name + Document string `json:"document"` + Contact string `json:"contact"` + AdminEmail string `json:"admin_email"` + Email string `json:"email"` // Alternative field name + Password string `json:"password"` + Phone string `json:"phone"` + Website *string `json:"website,omitempty"` + Address *string `json:"address,omitempty"` + City *string `json:"city,omitempty"` + State *string `json:"state,omitempty"` + ZipCode *string `json:"zip_code,omitempty"` + EmployeeCount *string `json:"employeeCount,omitempty"` + FoundedYear *int `json:"foundedYear,omitempty"` + Description *string `json:"description,omitempty"` + YearsInMarket *string `json:"years_in_market,omitempty"` + BirthDate *string `json:"birth_date,omitempty"` + AdminBirthDate *string `json:"admin_birth_date,omitempty"` } type CompanyResponse struct { diff --git a/backend/internal/core/usecases/tenant/create_company.go b/backend/internal/core/usecases/tenant/create_company.go index 47deb01..89d575a 100644 --- a/backend/internal/core/usecases/tenant/create_company.go +++ b/backend/internal/core/usecases/tenant/create_company.go @@ -1,127 +1,140 @@ -package tenant - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/rede5/gohorsejobs/backend/internal/core/domain/entity" - "github.com/rede5/gohorsejobs/backend/internal/core/dto" - "github.com/rede5/gohorsejobs/backend/internal/core/ports" - "github.com/rede5/gohorsejobs/backend/internal/utils" -) - -type CreateCompanyUseCase struct { - companyRepo ports.CompanyRepository - userRepo ports.UserRepository - authService ports.AuthService -} - -func NewCreateCompanyUseCase(cRepo ports.CompanyRepository, uRepo ports.UserRepository, auth ports.AuthService) *CreateCompanyUseCase { - return &CreateCompanyUseCase{ - companyRepo: cRepo, - userRepo: uRepo, - authService: auth, - } -} - -func (uc *CreateCompanyUseCase) Execute(ctx context.Context, input dto.CreateCompanyRequest) (*dto.CompanyResponse, error) { - // 0. Sanitize inputs - sanitizer := utils.DefaultSanitizer() - input.Name = sanitizer.SanitizeName(input.Name) - input.Contact = sanitizer.SanitizeString(input.Contact) - input.AdminEmail = sanitizer.SanitizeEmail(input.AdminEmail) - - // Validate name - if input.Name == "" { - return nil, errors.New("nome da empresa é obrigatório") - } - - // Validate document (flexible for global portal) - docValidator := utils.NewDocumentValidator("") - if input.Document != "" { - result := docValidator.ValidateDocument(input.Document, "") - if !result.Valid { - return nil, errors.New(result.Message) - } - input.Document = result.Clean - } - - // Ensure AdminEmail is set (fallback to Email) - if input.AdminEmail == "" { - input.AdminEmail = input.Email - } - if input.Contact == "" && input.Email != "" { - input.Contact = input.Email - } - - // Check if user already exists - existingUser, _ := uc.userRepo.FindByEmail(ctx, input.AdminEmail) - if existingUser != nil { - return nil, fmt.Errorf("user with email %s already exists", input.AdminEmail) - } - - // 1. Create Company Entity - company := entity.NewCompany("", input.Name, &input.Document, &input.Contact) - - // Map optional fields - if input.Phone != "" { - company.Phone = &input.Phone - } - if input.Website != nil { - company.Website = input.Website - } - if input.Description != nil { - company.Description = input.Description - } - if input.Address != nil { - company.Address = input.Address - } - if input.YearsInMarket != nil { - company.YearsInMarket = input.YearsInMarket - } - - savedCompany, err := uc.companyRepo.Save(ctx, company) - if err != nil { - return nil, err - } - - // 2. Create Admin User - pwd := input.Password - if pwd == "" { - pwd = "ChangeMe123!" - } - hashedPassword, _ := uc.authService.HashPassword(pwd) - - adminUser := entity.NewUser("", savedCompany.ID, "Admin", input.AdminEmail) - adminUser.PasswordHash = hashedPassword - - if input.BirthDate != nil { - layout := "2006-01-02" - if parsed, err := time.Parse(layout, *input.BirthDate); err == nil { - adminUser.BirthDate = &parsed - } - } - - adminUser.AssignRole(entity.Role{Name: entity.RoleAdmin}) - - _, err = uc.userRepo.Save(ctx, adminUser) - if err != nil { - return nil, err - } - - // 3. Generate Token for Auto-Login - token, err := uc.authService.GenerateToken(adminUser.ID, savedCompany.ID, []string{entity.RoleAdmin}) - if err != nil { - _ = err - } - - return &dto.CompanyResponse{ - ID: savedCompany.ID, - Name: savedCompany.Name, - Status: savedCompany.Status, - Token: token, - CreatedAt: savedCompany.CreatedAt, - }, nil -} +package tenant + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/rede5/gohorsejobs/backend/internal/core/domain/entity" + "github.com/rede5/gohorsejobs/backend/internal/core/dto" + "github.com/rede5/gohorsejobs/backend/internal/core/ports" + "github.com/rede5/gohorsejobs/backend/internal/utils" +) + +type CreateCompanyUseCase struct { + companyRepo ports.CompanyRepository + userRepo ports.UserRepository + authService ports.AuthService +} + +func NewCreateCompanyUseCase(cRepo ports.CompanyRepository, uRepo ports.UserRepository, auth ports.AuthService) *CreateCompanyUseCase { + return &CreateCompanyUseCase{ + companyRepo: cRepo, + userRepo: uRepo, + authService: auth, + } +} + +func (uc *CreateCompanyUseCase) Execute(ctx context.Context, input dto.CreateCompanyRequest) (*dto.CompanyResponse, error) { + if input.Name == "" && input.CompanyName != "" { + input.Name = input.CompanyName + } + + // 0. Sanitize inputs + sanitizer := utils.DefaultSanitizer() + input.Name = sanitizer.SanitizeName(input.Name) + input.Contact = sanitizer.SanitizeString(input.Contact) + input.AdminEmail = sanitizer.SanitizeEmail(input.AdminEmail) + + // Validate name + if input.Name == "" { + return nil, errors.New("nome da empresa é obrigatório") + } + + // Validate document (flexible for global portal) + docValidator := utils.NewDocumentValidator("") + if input.Document != "" { + result := docValidator.ValidateDocument(input.Document, "") + if !result.Valid { + return nil, errors.New(result.Message) + } + input.Document = result.Clean + } + + // Ensure AdminEmail is set (fallback to Email) + if input.AdminEmail == "" { + input.AdminEmail = input.Email + } + if input.Contact == "" && input.Email != "" { + input.Contact = input.Email + } + + // Check if user already exists + existingUser, _ := uc.userRepo.FindByEmail(ctx, input.AdminEmail) + if existingUser != nil { + return nil, fmt.Errorf("user with email %s already exists", input.AdminEmail) + } + + // 1. Create Company Entity + company := entity.NewCompany("", input.Name, &input.Document, &input.Contact) + + // Map optional fields + if input.Phone != "" { + company.Phone = &input.Phone + } + if input.Website != nil { + company.Website = input.Website + } + if input.Description != nil { + company.Description = input.Description + } + if input.Address != nil { + company.Address = input.Address + } + if input.YearsInMarket != nil { + company.YearsInMarket = input.YearsInMarket + } + + savedCompany, err := uc.companyRepo.Save(ctx, company) + if err != nil { + return nil, err + } + + // 2. Create Admin User + pwd := input.Password + if pwd == "" { + pwd = "ChangeMe123!" + } + hashedPassword, _ := uc.authService.HashPassword(pwd) + + adminUser := entity.NewUser("", savedCompany.ID, "Admin", input.AdminEmail) + adminUser.PasswordHash = hashedPassword + adminUser.Address = input.Address + adminUser.City = input.City + adminUser.State = input.State + adminUser.ZipCode = input.ZipCode + + birthDate := input.BirthDate + if birthDate == nil { + birthDate = input.AdminBirthDate + } + + if birthDate != nil { + layout := "2006-01-02" + if parsed, err := time.Parse(layout, *birthDate); err == nil { + adminUser.BirthDate = &parsed + } + } + + adminUser.AssignRole(entity.Role{Name: entity.RoleAdmin}) + + _, err = uc.userRepo.Save(ctx, adminUser) + if err != nil { + return nil, err + } + + // 3. Generate Token for Auto-Login + token, err := uc.authService.GenerateToken(adminUser.ID, savedCompany.ID, []string{entity.RoleAdmin}) + if err != nil { + _ = err + } + + return &dto.CompanyResponse{ + ID: savedCompany.ID, + Name: savedCompany.Name, + Status: savedCompany.Status, + Token: token, + CreatedAt: savedCompany.CreatedAt, + }, nil +} diff --git a/backend/internal/router/router.go b/backend/internal/router/router.go index d56c030..fa4fc80 100755 --- a/backend/internal/router/router.go +++ b/backend/internal/router/router.go @@ -358,6 +358,8 @@ func NewRouter() http.Handler { notificationHandler := handlers.NewNotificationHandler(notificationService) mux.Handle("PUT /api/v1/notifications/read-all", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.MarkAllAsRead))) mux.Handle("PUT /api/v1/notifications/{id}/read", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.MarkAsRead))) + mux.Handle("PATCH /api/v1/notifications/read-all", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.MarkAllAsRead))) + mux.Handle("PATCH /api/v1/notifications/{id}/read", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.MarkAsRead))) mux.Handle("POST /api/v1/notifications/fcm-token", authMiddleware.HeaderAuthGuard(http.HandlerFunc(notificationHandler.RegisterFCMToken))) // Swagger Route - available at /docs