Incidents calls

This commit is contained in:
Daniel Ponte 2024-12-29 15:08:06 -05:00
parent 80d3377187
commit 82d2d5c340
8 changed files with 123 additions and 30 deletions

View file

@ -1,3 +1,6 @@
# this is used to compose URLs, for example in M3U responses.
# set it to what users access the instance as.
baseURL: "https://stillbox.example.com/"
db:
connect: 'postgres://postgres:password@localhost:5432/example'
partition:

57
internal/jsontypes/url.go Normal file
View file

@ -0,0 +1,57 @@
package jsontypes
import (
"encoding/json"
"net/url"
"gopkg.in/yaml.v3"
)
type URL url.URL
func (u *URL) URL() url.URL {
return url.URL(*u)
}
func (u *URL) UnmarshalJSON(b []byte) error {
var s string
err := json.Unmarshal(b, &s)
if err != nil {
return err
}
ur, err := url.Parse(s)
if err != nil {
return err
}
*u = URL(*ur)
return nil
}
func (u *URL) UnmarshalYAML(n *yaml.Node) error {
var s string
err := n.Decode(&s)
if err != nil {
return err
}
ur, err := url.Parse(s)
if err != nil {
return err
}
*u = URL(*ur)
return nil
}
func (u *URL) UnmarshalText(t []byte) error {
ur, err := url.Parse(string(t))
if err != nil {
return err
}
*u = URL(*ur)
return nil
}

View file

@ -1,6 +1,8 @@
package jsontypes
import (
"encoding/json"
"github.com/google/uuid"
)
@ -17,6 +19,28 @@ func (u *UUIDs) UUIDs() []uuid.UUID {
return r
}
func (u *UUIDs) UnmarshalJSON(b []byte) error {
var ss []string
err := json.Unmarshal(b, &ss)
if err != nil {
return err
}
usl := make([]UUID, 0, len(ss))
for _, s := range ss {
uu, err := uuid.Parse(s)
if err != nil {
return err
}
usl = append(usl, UUID(uu))
}
*u = usl
return nil
}
func (u UUID) UUID() uuid.UUID {
return uuid.UUID(u)
}

View file

@ -16,6 +16,7 @@ type Configuration struct {
}
type Config struct {
BaseURL jsontypes.URL `yaml:"baseURL"`
DB DB `yaml:"db"`
CORS CORS `yaml:"cors"`
Auth Auth `yaml:"auth"`

View file

@ -62,7 +62,7 @@ func (c *Configuration) read() error {
})
if err != nil {
return fmt.Errorf("unmarshal err: %w", err)
return fmt.Errorf("config: %w", err)
}
return nil

View file

@ -3,6 +3,7 @@ package rest
import (
"errors"
"net/http"
"net/url"
"dynatron.me/x/stillbox/pkg/talkgroups/tgstore"
@ -19,10 +20,11 @@ type API interface {
}
type api struct {
baseURL url.URL
}
func New() *api {
s := new(api)
func New(baseURL url.URL) *api {
s := &api{baseURL}
return s
}
@ -33,7 +35,7 @@ func (a *api) Subrouter() http.Handler {
r.Mount("/talkgroup", new(talkgroupAPI).Subrouter())
r.Mount("/call", new(callsAPI).Subrouter())
r.Mount("/user", new(usersAPI).Subrouter())
r.Mount("/incident", new(incidentsAPI).Subrouter())
r.Mount("/incident", newIncidentsAPI(&a.baseURL).Subrouter())
return r
}

View file

@ -5,8 +5,11 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"dynatron.me/x/stillbox/internal/common"
"dynatron.me/x/stillbox/internal/forms"
"dynatron.me/x/stillbox/internal/jsontypes"
"dynatron.me/x/stillbox/pkg/database"
"dynatron.me/x/stillbox/pkg/incidents"
"dynatron.me/x/stillbox/pkg/incidents/incstore"
@ -17,6 +20,11 @@ import (
)
type incidentsAPI struct {
baseURL *url.URL
}
func newIncidentsAPI(baseURL *url.URL) API {
return &incidentsAPI{baseURL}
}
func (ia *incidentsAPI) Subrouter() http.Handler {
@ -25,13 +33,13 @@ func (ia *incidentsAPI) Subrouter() http.Handler {
r.Get(`/{id:[a-f0-9-]+}`, ia.getIncident)
r.Get(`/{id:[a-f0-9-]+}.m3u`, ia.getCallsM3U)
r.Post(`/create`, ia.createIncident)
r.Post(`/new`, ia.createIncident)
r.Post(`/`, ia.listIncidents)
r.Post(`/{id:[a-f0-9-]+}/calls`, ia.postCalls)
r.Put(`/{id:[a-f0-9]+}`, ia.updateIncident)
r.Delete(`/{id:[a-f0-9]+}`, ia.deleteIncident)
r.Delete(`/{id:[a-f0-9-]+}`, ia.deleteIncident)
return r
}
@ -148,10 +156,10 @@ func (ia *incidentsAPI) deleteIncident(w http.ResponseWriter, r *http.Request) {
}
type CallIncidentParams struct {
Add []uuid.UUID `json:"add"`
Add jsontypes.UUIDs `json:"add"`
Notes json.RawMessage `json:"notes"`
Remove []uuid.UUID `json:"remove"`
Remove jsontypes.UUIDs `json:"remove"`
}
func (ia *incidentsAPI) postCalls(w http.ResponseWriter, r *http.Request) {
@ -170,7 +178,7 @@ func (ia *incidentsAPI) postCalls(w http.ResponseWriter, r *http.Request) {
return
}
err = incs.AddRemoveIncidentCalls(ctx, id, p.Add, p.Notes, p.Remove)
err = incs.AddRemoveIncidentCalls(ctx, id, p.Add.UUIDs(), p.Notes, p.Remove.UUIDs())
if err != nil {
wErr(w, r, autoError(err))
return
@ -197,9 +205,7 @@ func (ia *incidentsAPI) getCallsM3U(w http.ResponseWriter, r *http.Request) {
var b bytes.Buffer
callUrl := r.URL
callUrl.RawQuery = ""
callUrl.Fragment = ""
callUrl := common.PtrTo(*ia.baseURL)
b.WriteString("#EXTM3U\n\n")
for _, c := range inc.Calls {
@ -213,7 +219,7 @@ func (ia *incidentsAPI) getCallsM3U(w http.ResponseWriter, r *http.Request) {
from = fmt.Sprintf(" from %d", c.Source)
}
callUrl.Path = "/api/call/%s" + c.ID.String()
callUrl.Path = "/api/call/" + c.ID.String()
fmt.Fprintf(w, "#EXTINF:%d,%s%s (%s)\n%s\n\n",
c.Duration.Seconds(),

View file

@ -71,7 +71,7 @@ func New(ctx context.Context, cfg *config.Configuration) (*Server, error) {
}
tgCache := tgstore.NewCache()
api := rest.New()
api := rest.New(cfg.BaseURL.URL())
srv := &Server{
auth: authenticator,