Initial commit including .env
This commit is contained in:
386
controllers/clientController.go
Normal file
386
controllers/clientController.go
Normal file
@@ -0,0 +1,386 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"doormile/db"
|
||||
"doormile/dto"
|
||||
"doormile/models"
|
||||
"doormile/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func RegisterClient(c *fiber.Ctx) error {
|
||||
var input dto.CreateClientRequest
|
||||
if err := c.BodyParser(&input); err != nil {
|
||||
return utils.BadRequest(c, "invalid request body")
|
||||
}
|
||||
|
||||
if input.FirstName == "" || input.Phone == "" {
|
||||
return utils.BadRequest(c, "first_name and phone are required")
|
||||
}
|
||||
|
||||
if input.RegistrationSource == "" {
|
||||
input.RegistrationSource = DetermineSource(string(c.Request().Header.UserAgent()))
|
||||
}
|
||||
if input.DataConsent == "" {
|
||||
input.DataConsent = "full"
|
||||
}
|
||||
if input.Status == "" {
|
||||
input.Status = "newClient"
|
||||
}
|
||||
|
||||
createAuth := input.Email != "" && input.Password != ""
|
||||
|
||||
var hashedPassword string
|
||||
if createAuth {
|
||||
var err error
|
||||
hashedPassword, err = utils.HashPassword(input.Password)
|
||||
if err != nil {
|
||||
return utils.Internal(c, "failed to process registration")
|
||||
}
|
||||
}
|
||||
|
||||
tx := db.DB.Begin()
|
||||
|
||||
var existingClient models.DoormileClient
|
||||
if tx.Where("phone = ?", input.Phone).First(&existingClient).Error == nil {
|
||||
tx.Rollback()
|
||||
return utils.Conflict(c, "a client with this phone number already exists")
|
||||
}
|
||||
|
||||
if createAuth {
|
||||
var existingAuth models.DoormileAuth
|
||||
if tx.Where("email = ?", input.Email).First(&existingAuth).Error == nil {
|
||||
tx.Rollback()
|
||||
return utils.Conflict(c, "this email address is already registered")
|
||||
}
|
||||
}
|
||||
|
||||
client := models.DoormileClient{
|
||||
FirstName: input.FirstName,
|
||||
LastName: input.LastName,
|
||||
Phone: input.Phone,
|
||||
Address: input.Address,
|
||||
City: input.City,
|
||||
State: input.State,
|
||||
Neighbourhood: input.Neighbourhood,
|
||||
Pincode: input.Pincode,
|
||||
SurveyLat: input.SurveyLat,
|
||||
SurveyLong: input.SurveyLong,
|
||||
SurveyAddress: input.SurveyAddress,
|
||||
SurveyZone: input.SurveyZone,
|
||||
SurveyPincode: input.SurveyPincode,
|
||||
BusinessType: input.BusinessType,
|
||||
Status: input.Status,
|
||||
ShippingFrequency: input.ShippingFrequency,
|
||||
LogisticsSegment: input.LogisticsSegment,
|
||||
TransitFrom: input.TransitFrom,
|
||||
TransitTo: input.TransitTo,
|
||||
DataConsent: input.DataConsent,
|
||||
RegistrationSource: input.RegistrationSource,
|
||||
RegisteredByID: input.RegisteredByID,
|
||||
}
|
||||
|
||||
if input.DataConsent == "full" {
|
||||
client.ParcelVolume = input.ParcelVolume
|
||||
client.ActiveContracts = input.ActiveContracts
|
||||
client.LogisticsProvider = input.LogisticsProvider
|
||||
client.ProviderEfficiency = input.ProviderEfficiency
|
||||
client.Notes = input.Notes
|
||||
} else {
|
||||
client.ParcelVolume = 0
|
||||
client.ActiveContracts = 0
|
||||
client.LogisticsProvider = "Not disclosed"
|
||||
client.ProviderEfficiency = ""
|
||||
client.Notes = ""
|
||||
}
|
||||
|
||||
if err := tx.Create(&client).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return utils.Internal(c, "failed to create client")
|
||||
}
|
||||
|
||||
email, role := "", ""
|
||||
if createAuth {
|
||||
auth := models.DoormileAuth{
|
||||
ClientID: &client.ID,
|
||||
Email: input.Email,
|
||||
PasswordHash: hashedPassword,
|
||||
Role: "user",
|
||||
}
|
||||
if err := tx.Create(&auth).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return utils.Internal(c, "failed to create auth credentials")
|
||||
}
|
||||
email = auth.Email
|
||||
role = auth.Role
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return utils.Created(c, buildClientResponse(client, email, role))
|
||||
}
|
||||
|
||||
func GetClients(c *fiber.Ctx) error {
|
||||
var clients []models.DoormileClient
|
||||
if err := db.DB.Find(&clients).Error; err != nil {
|
||||
return utils.Internal(c, "failed to fetch clients")
|
||||
}
|
||||
|
||||
// Bulk load auth records once and map by client_id for O(1) lookup
|
||||
var auths []models.DoormileAuth
|
||||
db.DB.Find(&auths)
|
||||
authByClientID := make(map[uint64]models.DoormileAuth, len(auths))
|
||||
for _, a := range auths {
|
||||
if a.ClientID != nil {
|
||||
authByClientID[*a.ClientID] = a
|
||||
}
|
||||
}
|
||||
|
||||
responses := make([]dto.ClientResponse, 0, len(clients))
|
||||
for _, client := range clients {
|
||||
auth := authByClientID[client.ID]
|
||||
responses = append(responses, buildClientResponse(client, auth.Email, auth.Role))
|
||||
}
|
||||
|
||||
return utils.List(c, responses, int64(len(responses)))
|
||||
}
|
||||
|
||||
func GetClientDetails(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
return utils.BadRequest(c, "invalid client ID")
|
||||
}
|
||||
|
||||
var client models.DoormileClient
|
||||
if err := db.DB.First(&client, id).Error; err != nil {
|
||||
return utils.NotFound(c, "client not found")
|
||||
}
|
||||
|
||||
var auth models.DoormileAuth
|
||||
email, role := "", ""
|
||||
if db.DB.Where("client_id = ?", id).First(&auth).Error == nil {
|
||||
email = auth.Email
|
||||
role = auth.Role
|
||||
}
|
||||
|
||||
return utils.OK(c, buildClientResponse(client, email, role))
|
||||
}
|
||||
|
||||
func UpdateClient(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
return utils.BadRequest(c, "invalid client ID")
|
||||
}
|
||||
|
||||
var client models.DoormileClient
|
||||
if err := db.DB.First(&client, id).Error; err != nil {
|
||||
return utils.NotFound(c, "client not found")
|
||||
}
|
||||
|
||||
var input dto.CreateClientRequest
|
||||
if err := c.BodyParser(&input); err != nil {
|
||||
return utils.BadRequest(c, "invalid request body")
|
||||
}
|
||||
|
||||
if input.FirstName != "" {
|
||||
client.FirstName = input.FirstName
|
||||
}
|
||||
if input.LastName != "" {
|
||||
client.LastName = input.LastName
|
||||
}
|
||||
if input.Phone != "" {
|
||||
client.Phone = input.Phone
|
||||
}
|
||||
if input.Address != "" {
|
||||
client.Address = input.Address
|
||||
}
|
||||
if input.City != "" {
|
||||
client.City = input.City
|
||||
}
|
||||
if input.State != "" {
|
||||
client.State = input.State
|
||||
}
|
||||
if input.Neighbourhood != "" {
|
||||
client.Neighbourhood = input.Neighbourhood
|
||||
}
|
||||
if input.Pincode != "" {
|
||||
client.Pincode = input.Pincode
|
||||
}
|
||||
if input.SurveyLat != 0 {
|
||||
client.SurveyLat = input.SurveyLat
|
||||
}
|
||||
if input.SurveyLong != 0 {
|
||||
client.SurveyLong = input.SurveyLong
|
||||
}
|
||||
if input.SurveyAddress != "" {
|
||||
client.SurveyAddress = input.SurveyAddress
|
||||
}
|
||||
if input.SurveyZone != "" {
|
||||
client.SurveyZone = input.SurveyZone
|
||||
}
|
||||
if input.SurveyPincode != "" {
|
||||
client.SurveyPincode = input.SurveyPincode
|
||||
}
|
||||
if input.BusinessType != "" {
|
||||
client.BusinessType = input.BusinessType
|
||||
}
|
||||
if input.Status != "" {
|
||||
client.Status = input.Status
|
||||
}
|
||||
if input.ShippingFrequency != "" {
|
||||
client.ShippingFrequency = input.ShippingFrequency
|
||||
}
|
||||
if input.LogisticsSegment != "" {
|
||||
client.LogisticsSegment = input.LogisticsSegment
|
||||
}
|
||||
if input.TransitFrom != "" {
|
||||
client.TransitFrom = input.TransitFrom
|
||||
}
|
||||
if input.TransitTo != "" {
|
||||
client.TransitTo = input.TransitTo
|
||||
}
|
||||
if input.RegistrationSource != "" {
|
||||
client.RegistrationSource = input.RegistrationSource
|
||||
}
|
||||
if input.RegisteredByID != 0 {
|
||||
client.RegisteredByID = input.RegisteredByID
|
||||
}
|
||||
client.Notes = input.Notes
|
||||
|
||||
if input.DataConsent != "" {
|
||||
client.DataConsent = input.DataConsent
|
||||
}
|
||||
|
||||
if client.DataConsent == "full" {
|
||||
client.ParcelVolume = input.ParcelVolume
|
||||
client.ActiveContracts = input.ActiveContracts
|
||||
client.LogisticsProvider = input.LogisticsProvider
|
||||
client.ProviderEfficiency = input.ProviderEfficiency
|
||||
} else {
|
||||
client.ParcelVolume = 0
|
||||
client.ActiveContracts = 0
|
||||
client.LogisticsProvider = "Not disclosed"
|
||||
client.ProviderEfficiency = ""
|
||||
client.Notes = ""
|
||||
}
|
||||
|
||||
tx := db.DB.Begin()
|
||||
|
||||
if err := tx.Save(&client).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return utils.Internal(c, "failed to update client")
|
||||
}
|
||||
|
||||
var auth models.DoormileAuth
|
||||
email, role := "", ""
|
||||
if db.DB.Where("client_id = ?", id).First(&auth).Error == nil {
|
||||
email = auth.Email
|
||||
role = auth.Role
|
||||
}
|
||||
|
||||
authUpdated := false
|
||||
if input.Email != "" && input.Email != auth.Email {
|
||||
auth.Email = input.Email
|
||||
email = input.Email
|
||||
authUpdated = true
|
||||
}
|
||||
if input.Password != "" {
|
||||
hashed, err := utils.HashPassword(input.Password)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return utils.Internal(c, "failed to process password update")
|
||||
}
|
||||
auth.PasswordHash = hashed
|
||||
authUpdated = true
|
||||
}
|
||||
if authUpdated && auth.ID != 0 {
|
||||
if err := tx.Save(&auth).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return utils.Internal(c, "failed to update credentials")
|
||||
}
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return utils.OK(c, buildClientResponse(client, email, role))
|
||||
}
|
||||
|
||||
func DeleteClient(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
return utils.BadRequest(c, "invalid client ID")
|
||||
}
|
||||
|
||||
var client models.DoormileClient
|
||||
if err := db.DB.First(&client, id).Error; err != nil {
|
||||
return utils.NotFound(c, "client not found")
|
||||
}
|
||||
|
||||
tx := db.DB.Begin()
|
||||
|
||||
if err := tx.Where("client_id = ?", id).Delete(&models.DoormileAuth{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return utils.Internal(c, "failed to delete client credentials")
|
||||
}
|
||||
|
||||
if err := tx.Delete(&client).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return utils.Internal(c, "failed to delete client")
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return utils.Message(c, "client deleted successfully")
|
||||
}
|
||||
|
||||
func buildClientResponse(client models.DoormileClient, email, role string) dto.ClientResponse {
|
||||
return dto.ClientResponse{
|
||||
ID: client.ID,
|
||||
CreatedAt: client.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
LastUpdated: client.UpdatedAt.Format("2006-01-02"),
|
||||
FirstName: client.FirstName,
|
||||
LastName: client.LastName,
|
||||
Email: email,
|
||||
Phone: client.Phone,
|
||||
Address: client.Address,
|
||||
City: client.City,
|
||||
State: client.State,
|
||||
Neighbourhood: client.Neighbourhood,
|
||||
Pincode: client.Pincode,
|
||||
SurveyLat: client.SurveyLat,
|
||||
SurveyLong: client.SurveyLong,
|
||||
SurveyAddress: client.SurveyAddress,
|
||||
SurveyZone: client.SurveyZone,
|
||||
SurveyPincode: client.SurveyPincode,
|
||||
BusinessType: client.BusinessType,
|
||||
Status: client.Status,
|
||||
ShippingFrequency: client.ShippingFrequency,
|
||||
LogisticsSegment: client.LogisticsSegment,
|
||||
TransitFrom: client.TransitFrom,
|
||||
TransitTo: client.TransitTo,
|
||||
ParcelVolume: client.ParcelVolume,
|
||||
ActiveContracts: client.ActiveContracts,
|
||||
LogisticsProvider: client.LogisticsProvider,
|
||||
ProviderEfficiency: client.ProviderEfficiency,
|
||||
Notes: client.Notes,
|
||||
DataConsent: client.DataConsent,
|
||||
RegistrationSource: client.RegistrationSource,
|
||||
RegisteredByID: client.RegisteredByID,
|
||||
Role: role,
|
||||
}
|
||||
}
|
||||
|
||||
func DetermineSource(userAgent string) string {
|
||||
ua := strings.ToLower(userAgent)
|
||||
if strings.Contains(ua, "dart") || strings.Contains(ua, "flutter") || strings.Contains(ua, "doormile") {
|
||||
return "mobile"
|
||||
}
|
||||
if strings.Contains(ua, "mozilla") || strings.Contains(ua, "chrome") || strings.Contains(ua, "safari") {
|
||||
return "web"
|
||||
}
|
||||
return "api_tool"
|
||||
}
|
||||
Reference in New Issue
Block a user