2024-12-02 17:53:43 -05:00
|
|
|
package rest
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"mime"
|
|
|
|
"net/http"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"dynatron.me/x/stillbox/internal/common"
|
2024-12-19 16:14:41 -05:00
|
|
|
"dynatron.me/x/stillbox/internal/forms"
|
|
|
|
"dynatron.me/x/stillbox/pkg/calls/callstore"
|
2024-12-02 17:53:43 -05:00
|
|
|
"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()
|
|
|
|
|
2024-12-19 16:14:41 -05:00
|
|
|
r.Get(`/{call:[a-f0-9-]+}`, ca.getAudio)
|
|
|
|
r.Get(`/{call:[a-f0-9-]+}/{download:download}`, ca.getAudio)
|
|
|
|
|
2024-12-27 13:14:45 -05:00
|
|
|
r.Post(`/`, ca.listCalls)
|
2024-12-02 17:53:43 -05:00
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
2024-12-19 16:14:41 -05:00
|
|
|
func (ca *callsAPI) getAudio(w http.ResponseWriter, r *http.Request) {
|
2024-12-02 17:53:43 -05:00
|
|
|
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()
|
2024-12-19 16:14:41 -05:00
|
|
|
calls := callstore.FromCtx(ctx)
|
2024-12-02 17:53:43 -05:00
|
|
|
|
2024-12-19 16:14:41 -05:00
|
|
|
call, err := calls.CallAudio(ctx, *p.CallID)
|
2024-12-02 17:53:43 -05:00
|
|
|
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 {
|
2024-12-19 16:14:41 -05:00
|
|
|
call.AudioName = common.PtrTo(call.CallDate.Time().Format(fileNameDateFmt))
|
2024-12-02 17:53:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2024-12-19 16:14:41 -05:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|