108 lines
3.2 KiB
Go
108 lines
3.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/noderunners/nip05api/internal/invoice"
|
|
"github.com/noderunners/nip05api/internal/nostr"
|
|
"github.com/noderunners/nip05api/internal/user"
|
|
)
|
|
|
|
type Invoices struct {
|
|
Service *invoice.Service
|
|
LightningEnabled bool
|
|
}
|
|
|
|
type createInvoiceReq struct {
|
|
Username string `json:"username"`
|
|
Pubkey string `json:"pubkey"`
|
|
SubscriptionType string `json:"subscription_type"`
|
|
Years int `json:"years"`
|
|
}
|
|
|
|
func (h *Invoices) Create(w http.ResponseWriter, r *http.Request) {
|
|
if !h.LightningEnabled {
|
|
WriteError(w, http.StatusServiceUnavailable, "LightningDisabled", "lightning payments are disabled")
|
|
return
|
|
}
|
|
var body createInvoiceReq
|
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
|
WriteError(w, http.StatusBadRequest, "ValidationError", "invalid JSON")
|
|
return
|
|
}
|
|
hexpk, err := nostr.NormalizePubkey(body.Pubkey)
|
|
if err != nil {
|
|
WriteError(w, http.StatusBadRequest, "ValidationError", "Invalid pubkey format")
|
|
return
|
|
}
|
|
subStr := strings.TrimSpace(body.SubscriptionType)
|
|
if subStr == "" {
|
|
subStr = string(user.SubLifetime)
|
|
}
|
|
sub := user.SubscriptionType(subStr)
|
|
if !sub.Valid() {
|
|
WriteError(w, http.StatusBadRequest, "ValidationError", "invalid subscription_type")
|
|
return
|
|
}
|
|
years := body.Years
|
|
if sub == user.SubYearly && years <= 0 {
|
|
years = 1
|
|
}
|
|
p, err := h.Service.Create(r.Context(), invoice.CreateRequest{
|
|
Username: body.Username,
|
|
Pubkey: hexpk,
|
|
SubscriptionType: sub,
|
|
Years: years,
|
|
})
|
|
if err != nil {
|
|
switch {
|
|
case errors.Is(err, invoice.ErrLifetimeAccess):
|
|
WriteError(w, http.StatusForbidden, "User already has lifetime access", "")
|
|
case errors.Is(err, invoice.ErrUsernameTaken),
|
|
errors.Is(err, user.ErrUsernameTaken):
|
|
WriteError(w, http.StatusConflict, "Conflict", "username unavailable")
|
|
case errors.Is(err, invoice.ErrUsernameMismatch):
|
|
WriteError(w, http.StatusConflict, "Conflict", err.Error())
|
|
case errors.Is(err, user.ErrInvalidUsername),
|
|
errors.Is(err, invoice.ErrInvalidYears):
|
|
WriteError(w, http.StatusBadRequest, "ValidationError", err.Error())
|
|
case errors.Is(err, invoice.ErrLNbits):
|
|
WriteError(w, http.StatusServiceUnavailable, "LightningError", err.Error())
|
|
default:
|
|
WriteError(w, http.StatusInternalServerError, "InternalError", err.Error())
|
|
}
|
|
return
|
|
}
|
|
WriteJSON(w, http.StatusOK, map[string]any{
|
|
"payment_hash": p.PaymentHash,
|
|
"payment_request": p.PaymentRequest,
|
|
"amount_sats": p.AmountSats,
|
|
"expires_at": p.ExpiresAt.UTC().Format(time.RFC3339),
|
|
"username": p.Username,
|
|
"is_renewal": p.IsRenewal,
|
|
})
|
|
}
|
|
|
|
func (h *Invoices) Get(w http.ResponseWriter, r *http.Request) {
|
|
hash := chi.URLParam(r, "payment_hash")
|
|
p, err := h.Service.Repo().Get(r.Context(), hash)
|
|
if errors.Is(err, invoice.ErrInvoiceNotFound) {
|
|
WriteError(w, http.StatusNotFound, "NotFound", "invoice not found")
|
|
return
|
|
}
|
|
if err != nil {
|
|
WriteError(w, http.StatusInternalServerError, "InternalError", err.Error())
|
|
return
|
|
}
|
|
WriteJSON(w, http.StatusOK, map[string]any{
|
|
"payment_hash": p.PaymentHash,
|
|
"status": string(p.Status()),
|
|
"username": p.Username,
|
|
})
|
|
}
|