feat: geolocate anonymous widget visitors
Build and publish Docker images / Build and publish images (push) Successful in 2m10s

This commit is contained in:
2026-09-15 08:54:13 +08:00
parent 5a0e9ecada
commit 4d684a71eb
28 changed files with 1502 additions and 104 deletions
@@ -120,6 +120,7 @@ func (h *WidgetHandler) Init(c *gin.Context) {
if identifierHash == "" {
identifierHash = c.Query("identifier_hash")
}
req.ClientIP = c.ClientIP()
if req.Identifier != "" && identifierHash != "" {
// Resolve the inbox to get its hmac_token for verification
inbox, err := h.widgetService.GetInboxByWebsiteToken(c.Request.Context(), req.WebsiteToken)
@@ -159,6 +160,7 @@ func (h *WidgetHandler) Config(c *gin.Context) {
if req.WidgetToken == "" {
req.WidgetToken = widgetTokenFromRequest(c)
}
req.ClientIP = c.ClientIP()
resp, err := h.widgetService.Init(c.Request.Context(), req)
if err != nil {
@@ -631,6 +633,7 @@ func (h *WidgetHandler) SetUser(c *gin.Context) {
PhoneNumber: req.PhoneNumber,
CustomAttributes: req.CustomAttributes,
AdditionalAttributes: req.AdditionalAttributes,
ClientIP: c.ClientIP(),
})
if err != nil {
c.JSON(widgetErrorStatus(err), gin.H{"error": err.Error()})
@@ -987,6 +990,7 @@ func (h *WidgetHandler) PublicCreateContact(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body", "details": err.Error()})
return
}
req.ClientIP = c.ClientIP()
resp, err := h.widgetService.PublicCreateContact(c.Request.Context(), c.Param("inbox_id"), req)
if err != nil {
c.JSON(widgetErrorStatus(err), gin.H{"error": err.Error()})
@@ -1010,6 +1014,7 @@ func (h *WidgetHandler) PublicUpdateContact(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body", "details": err.Error()})
return
}
req.ClientIP = c.ClientIP()
resp, err := h.widgetService.PublicUpdateContact(c.Request.Context(), c.Param("inbox_id"), c.Param("contact_id"), req)
if err != nil {
c.JSON(widgetErrorStatus(err), gin.H{"error": err.Error()})
@@ -1205,6 +1210,7 @@ func (h *WidgetHandler) SubmitOfflineMessage(c *gin.Context) {
referer := c.Request.Referer()
browserInfo := c.GetHeader("User-Agent")
submission.ClientIP = c.ClientIP()
msg, err := h.widgetService.SubmitOfflineMessage(
c.Request.Context(),
@@ -1428,7 +1434,7 @@ func widgetContactFullPayload(contact *model.Contact) gin.H {
"avatar_url": contact.AvatarURL,
"identifier": contact.Identifier,
"custom_attributes": contact.CustomAttributes,
"additional_attributes": contact.AdditionalAttributes,
"additional_attributes": service.PublicWidgetAdditionalAttributes(contact.AdditionalAttributes),
}
}