mirror of
https://github.com/warmbly/warmbly.git
synced 2026-09-05 16:02:48 +00:00
110 lines
3.1 KiB
Go
110 lines
3.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/warmbly/warmbly/internal/api/middleware"
|
|
"github.com/warmbly/warmbly/internal/errx"
|
|
"github.com/warmbly/warmbly/internal/models"
|
|
)
|
|
|
|
// verifyEmailRequest is the optional JSON body for VerifyEmail. The address may
|
|
// also be passed as the `email` query param; the body takes precedence.
|
|
type verifyEmailRequest struct {
|
|
Email string `json:"email"`
|
|
}
|
|
|
|
// VerifyEmail verifies a single email address on demand through whichever
|
|
// verifier the workspace uses (its connected provider, else the built-in
|
|
// check) and returns the emailverify.Result. Nothing is stored.
|
|
//
|
|
// Control-plane only: the SMTP RCPT probe behind the built-in check runs from
|
|
// the backend (a non-sending IP), never a worker. See internal/pkg/emailverify.
|
|
func (h *Handler) VerifyEmail(c *gin.Context) {
|
|
if _, err := middleware.GetUserUUID(c); err != nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
if h.EmailVerifyService == nil {
|
|
errx.JSON(c, errx.InternalError())
|
|
return
|
|
}
|
|
orgID, ok := requireOrgID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
var req verifyEmailRequest
|
|
// Body is optional; ignore a bind error and fall back to the query param.
|
|
_ = c.ShouldBindJSON(&req)
|
|
email := strings.TrimSpace(req.Email)
|
|
if email == "" {
|
|
email = strings.TrimSpace(c.Query("email"))
|
|
}
|
|
if email == "" {
|
|
errx.JSON(c, errx.ErrEmail)
|
|
return
|
|
}
|
|
|
|
res := h.EmailVerifyService.VerifyAddress(c.Request.Context(), orgID, email)
|
|
c.JSON(http.StatusOK, res)
|
|
}
|
|
|
|
// GetContactVerification reports which verifier the workspace uses, its
|
|
// remaining credits, and the contacts by verdict.
|
|
// GET /contacts/verification
|
|
func (h *Handler) GetContactVerification(c *gin.Context) {
|
|
if h.EmailVerifyService == nil {
|
|
errx.JSON(c, errx.InternalError())
|
|
return
|
|
}
|
|
orgID, ok := requireOrgID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
out, xerr := h.EmailVerifyService.Overview(c.Request.Context(), orgID)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, out)
|
|
}
|
|
|
|
// RequestContactVerification queues a re-check of the listed contacts, or
|
|
// records a manual verdict on them.
|
|
// POST /contacts/verification
|
|
func (h *Handler) RequestContactVerification(c *gin.Context) {
|
|
if h.EmailVerifyService == nil {
|
|
errx.JSON(c, errx.InternalError())
|
|
return
|
|
}
|
|
orgID, ok := requireOrgID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
var req models.ContactVerificationRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
errx.JSON(c, errx.ErrInvalid)
|
|
return
|
|
}
|
|
if len(req.Contacts) > maxBulkOperationSize {
|
|
errx.JSON(c, errx.NewWithIdentifier(errx.BadRequest, "too_many_contacts",
|
|
"too many contacts, maximum is "+itoa(maxBulkOperationSize)+" per request"))
|
|
return
|
|
}
|
|
resp, xerr := h.EmailVerifyService.Request(c.Request.Context(), orgID, req)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
// The audit spine refreshes every teammate's contact lists; verdicts
|
|
// then land live as the background pass records them.
|
|
h.auditOrg(c, models.AuditActionUpdate, models.AuditEntityContact, nil, nil, map[string]string{
|
|
"verification": req.Action, "count": itoa(resp.Affected),
|
|
})
|
|
c.JSON(http.StatusOK, resp)
|
|
}
|