stillbox/pkg/rest/calls.go

126 lines
2.4 KiB
Go
Raw Normal View History

package rest
import (
"errors"
"fmt"
"mime"
"net/http"
"path/filepath"
"dynatron.me/x/stillbox/internal/common"
"dynatron.me/x/stillbox/internal/forms"
"dynatron.me/x/stillbox/pkg/calls/callstore"
"dynatron.me/x/stillbox/pkg/database"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
)
const (
fileNameDateFmt = "2006-01-02_150405"
)
var (
ErrNoCall = errors.New("no call specified")
)
type callsAPI struct {
}
func (ca *callsAPI) Subrouter() http.Handler {
r := chi.NewMux()
r.Get(`/{call:[a-f0-9-]+}`, ca.getAudio)
r.Get(`/{call:[a-f0-9-]+}/{download:download}`, ca.getAudio)
2024-12-20 14:01:36 -05:00
r.Post(`/`, ca.listCalls)
return r
}
func (ca *callsAPI) getAudio(w http.ResponseWriter, r *http.Request) {
p := struct {
CallID *uuid.UUID `param:"call"`
Download *string `param:"download"`
}{}
err := decodeParams(&p, r)
if err != nil {
wErr(w, r, badRequest(err))
return
}
if p.CallID == nil {
wErr(w, r, badRequest(ErrNoCall))
return
}
ctx := r.Context()
calls := callstore.FromCtx(ctx)
call, err := calls.CallAudio(ctx, *p.CallID)
if err != nil {
wErr(w, r, autoError(err))
return
}
octetStream := "application/octet-stream"
var ext string
if call.AudioType == nil && call.AudioName != nil {
ext = filepath.Ext(*call.AudioName)
if ext != "" {
mt := mime.TypeByExtension(ext)
if mt != "" {
call.AudioType = &mt
}
}
}
if call.AudioType == nil {
call.AudioType = &octetStream
}
if call.AudioName == nil {
call.AudioName = common.PtrTo(call.CallDate.Time().Format(fileNameDateFmt))
}
disposition := "inline"
if p.Download != nil {
disposition = "attachment"
}
w.Header().Add("Content-Type", *call.AudioType)
w.Header().Add("Content-Disposition",
fmt.Sprintf(`%s; filename="%s"`, disposition, *call.AudioName))
_, _ = w.Write(call.AudioBlob)
}
func (ca *callsAPI) listCalls(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
cSt := callstore.FromCtx(ctx)
var par callstore.CallsParams
err := forms.Unmarshal(r, &par, forms.WithTag("json"), forms.WithAcceptBlank(), forms.WithOmitEmpty())
if err != nil {
wErr(w, r, badRequest(err))
return
}
calls, count, err := cSt.Calls(ctx, par)
if err != nil {
wErr(w, r, autoError(err))
return
}
res := struct {
Calls []database.ListCallsPRow `json:"calls"`
Count int `json:"count"`
}{
Calls: calls,
Count: count,
}
respond(w, r, res)
}