package controllers import ( "strings" "doormile/db" "doormile/models" "doormile/utils" "github.com/gofiber/fiber/v2" "gorm.io/gorm" "gorm.io/gorm/clause" ) // Device registration โ€” ยง10 of the contract. // // One row per device token rather than one column on the customer. A customer // with a phone and a tablet has to get the delivery notification on both, and // appcustomers.device_token could only ever hold whichever registered last โ€” // so the older device silently stopped receiving anything. // RegisterCxDevice records a push token for the signed-in customer. func RegisterCxDevice(c *fiber.Ctx) error { customerID := c.Locals("userid").(int) var req struct { Token string `json:"token"` Platform string `json:"platform"` AppVersion string `json:"appVersion"` } if err := c.BodyParser(&req); err != nil { return utils.CxBadRequest(c, "We could not read that request") } token := strings.TrimSpace(req.Token) if token == "" { return utils.CxBadRequest(c, "A device token is required") } platform := strings.ToLower(strings.TrimSpace(req.Platform)) if platform != "android" && platform != "ios" { platform = "" } device := models.CustomerDevice{ Appcustomerid: customerID, Token: token, Platform: platform, Appversion: strings.TrimSpace(req.AppVersion), Lastseenat: utils.DBNow(), } // A token can migrate between accounts โ€” a shared handset, or a customer // signing out and a second one signing in. Upserting on the token (rather // than inserting) reassigns it, which is the only outcome that does not // send one person's parcel updates to another person's phone. if err := db.DB.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "token"}}, DoUpdates: clause.AssignmentColumns([]string{ "appcustomerid", "platform", "appversion", "lastseenat", }), }).Create(&device).Error; err != nil { utils.Error("RegisterCxDevice: upsert failed", "customer_id", customerID, "error", err) return utils.CxInternal(c) } return utils.CxOK(c, fiber.Map{"registered": true}) } // UnregisterCxDevice drops a push token. Called on sign-out, so a signed-out // phone stops receiving updates about a pickup it can no longer open. func UnregisterCxDevice(c *fiber.Ctx) error { customerID := c.Locals("userid").(int) token := strings.TrimSpace(c.Params("token")) if token == "" { return utils.CxBadRequest(c, "A device token is required") } if err := db.DB.Where("appcustomerid = ? AND token = ?", customerID, token). Delete(&models.CustomerDevice{}).Error; err != nil && err != gorm.ErrRecordNotFound { utils.Error("UnregisterCxDevice: delete failed", "customer_id", customerID, "error", err) return utils.CxInternal(c) } return utils.CxOK(c, fiber.Map{"registered": false}) }