Incidents calls
This commit is contained in:
parent
80d3377187
commit
82d2d5c340
8 changed files with 123 additions and 30 deletions
|
@ -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
57
internal/jsontypes/url.go
Normal 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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
@ -26,12 +50,12 @@ func (u *UUID) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
func (u *UUID) UnmarshalJSON(b []byte) error {
|
||||
id, err := uuid.Parse(string(b[:]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*u = UUID(id)
|
||||
return nil
|
||||
id, err := uuid.Parse(string(b[:]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*u = UUID(id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *UUID) UnmarshalText(t []byte) error {
|
||||
|
|
|
@ -16,16 +16,17 @@ type Configuration struct {
|
|||
}
|
||||
|
||||
type Config struct {
|
||||
DB DB `yaml:"db"`
|
||||
CORS CORS `yaml:"cors"`
|
||||
Auth Auth `yaml:"auth"`
|
||||
Alerting Alerting `yaml:"alerting"`
|
||||
Log []Logger `yaml:"log"`
|
||||
Listen string `yaml:"listen"`
|
||||
Public bool `yaml:"public"`
|
||||
RateLimit RateLimit `yaml:"rateLimit"`
|
||||
Notify Notify `yaml:"notify"`
|
||||
Relay []Relay `yaml:"relay"`
|
||||
BaseURL jsontypes.URL `yaml:"baseURL"`
|
||||
DB DB `yaml:"db"`
|
||||
CORS CORS `yaml:"cors"`
|
||||
Auth Auth `yaml:"auth"`
|
||||
Alerting Alerting `yaml:"alerting"`
|
||||
Log []Logger `yaml:"log"`
|
||||
Listen string `yaml:"listen"`
|
||||
Public bool `yaml:"public"`
|
||||
RateLimit RateLimit `yaml:"rateLimit"`
|
||||
Notify Notify `yaml:"notify"`
|
||||
Relay []Relay `yaml:"relay"`
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue