hmn/src/website/api.go

106 lines
2.3 KiB
Go

package website
import (
"encoding/json"
"errors"
"io"
"net/http"
"strings"
"git.handmade.network/hmn/hmn/src/db"
"git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops"
"git.handmade.network/hmn/hmn/src/utils"
)
func APICheckUsername(c *RequestContext) ResponseData {
c.Req.ParseForm()
usernameArgs, hasUsername := c.Req.Form["username"]
found := false
canonicalUsername := ""
if hasUsername {
requestedUsername := usernameArgs[0]
found = true
c.Perf.StartBlock("SQL", "Fetch user")
user, err := db.QueryOne[models.User](c, c.Conn,
`
SELECT $columns
FROM
hmn_user
WHERE
LOWER(hmn_user.username) = LOWER($1)
AND status = ANY ($2)
`,
requestedUsername,
[]models.UserStatus{models.UserStatusConfirmed, models.UserStatusApproved},
)
c.Perf.EndBlock()
if err != nil {
if errors.Is(err, db.NotFound) {
found = false
} else {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user: %s", requestedUsername))
}
} else {
canonicalUsername = user.Username
}
}
var res ResponseData
addCORSHeaders(c, &res)
if found {
res.WriteJson(map[string]any{
"found": true,
"canonical": canonicalUsername,
}, nil)
} else {
res.WriteJson(map[string]any{
"found": false,
}, nil)
}
return res
}
func APINewsletterSignup(c *RequestContext) ResponseData {
bodyBytes := utils.Must1(io.ReadAll(c.Req.Body))
type Input struct {
Email string `json:"email"`
}
var input Input
err := json.Unmarshal(bodyBytes, &input)
if err != nil {
return c.ErrorResponse(http.StatusBadRequest, err)
}
var res ResponseData
sanitized := input.Email
sanitized = strings.TrimSpace(sanitized)
sanitized = strings.ToLower(sanitized)
if len(sanitized) > 200 {
res.StatusCode = http.StatusBadRequest
return res
}
if !strings.Contains(sanitized, "@") {
res.StatusCode = http.StatusBadRequest
res.WriteJson(map[string]any{
"error": "bad email",
}, nil)
return res
}
_, err = c.Conn.Exec(c,
`
INSERT INTO newsletter_emails (email) VALUES ($1)
ON CONFLICT DO NOTHING
`,
sanitized,
)
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to save email into database"))
}
res.WriteHeader(http.StatusNoContent)
return res
}