Get rid of using headers to identify share type

This commit is contained in:
Daniel Ponte 2025-02-01 14:28:01 -05:00
parent 493913112d
commit 1232b6887a
8 changed files with 96 additions and 48 deletions

View file

@ -185,7 +185,7 @@ func (as *alerter) eval(ctx context.Context, now time.Time, testMode bool) ([]al
continue
}
if!tgr.Talkgroup.Alert {
if !tgr.Talkgroup.Alert {
continue
}
@ -395,4 +395,4 @@ func (*noopAlerter) SinkType() string { return "noopA
func (*noopAlerter) Call(_ context.Context, _ *calls.Call) error { return nil }
func (*noopAlerter) Go(_ context.Context) {}
func (*noopAlerter) Enabled() bool { return false }
func (*noopAlerter) HUP(_ *config.Config) { }
func (*noopAlerter) HUP(_ *config.Config) {}

View file

@ -145,7 +145,7 @@ func (s *store) CallAudio(ctx context.Context, id uuid.UUID) (*calls.CallAudio,
}
func (s *store) Call(ctx context.Context, id uuid.UUID) (*calls.Call, error) {
_, err := rbac.Check(ctx, rbac.UseResource(entities.ResourceCall), rbac.WithActions(entities.ActionRead))
_, err := rbac.Check(ctx, &calls.Call{ID: id}, rbac.WithActions(entities.ActionRead))
if err != nil {
return nil, err
}

View file

@ -79,7 +79,7 @@ var Policy = &restrict.PolicyDefinition{
},
entities.RoleAdmin: {
Description: "A superuser",
Parents: []string{entities.RoleUser},
Parents: []string{entities.RoleUser},
Grants: restrict.GrantsMap{
entities.ResourceIncident: {
&restrict.Permission{Action: entities.ActionRead},
@ -109,7 +109,7 @@ var Policy = &restrict.PolicyDefinition{
},
entities.RoleSystem: {
Description: "A system service",
Parents: []string{entities.RoleAdmin},
Parents: []string{entities.RoleAdmin},
},
entities.RolePublic: {
/*

View file

@ -51,8 +51,9 @@ func New(baseURL url.URL) *api {
s.shares = newShareAPI(&baseURL,
ShareHandlers{
ShareRequestCall: s.calls.shareCallRoute,
ShareRequestCallInfo: respondShareHandler(s.calls.getCallInfo),
ShareRequestCallDL: s.calls.shareCallDLRoute,
ShareRequestIncident: s.incidents.getIncident,
ShareRequestIncident: respondShareHandler(s.incidents.getIncident),
ShareRequestIncidentM3U: s.incidents.getCallsM3U,
ShareRequestTalkgroups: s.tgs.getTGsShareRoute,
},

View file

@ -1,6 +1,7 @@
package rest
import (
"context"
"errors"
"fmt"
"mime"
@ -11,7 +12,6 @@ import (
"dynatron.me/x/stillbox/internal/forms"
"dynatron.me/x/stillbox/pkg/calls/callstore"
"dynatron.me/x/stillbox/pkg/database"
"dynatron.me/x/stillbox/pkg/shares"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
@ -102,7 +102,12 @@ func (ca *callsAPI) getAudio(p getAudioParams, w http.ResponseWriter, r *http.Re
_, _ = w.Write(call.AudioBlob)
}
func (ca *callsAPI) shareCallRoute(id ID, _ *shares.Share, w http.ResponseWriter, r *http.Request) {
func (ca *callsAPI) getCallInfo(ctx context.Context, id ID) (SharedItem, error) {
cs := callstore.FromCtx(ctx)
return cs.Call(ctx, id.(uuid.UUID))
}
func (ca *callsAPI) shareCallRoute(id ID, w http.ResponseWriter, r *http.Request) {
p := getAudioParams{
CallID: common.PtrTo(id.(uuid.UUID)),
}
@ -110,7 +115,7 @@ func (ca *callsAPI) shareCallRoute(id ID, _ *shares.Share, w http.ResponseWriter
ca.getAudio(p, w, r)
}
func (ca *callsAPI) shareCallDLRoute(id ID, _ *shares.Share, w http.ResponseWriter, r *http.Request) {
func (ca *callsAPI) shareCallDLRoute(id ID, w http.ResponseWriter, r *http.Request) {
p := getAudioParams{
CallID: common.PtrTo(id.(uuid.UUID)),
Download: common.PtrTo("download"),

View file

@ -2,6 +2,7 @@ package rest
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
@ -12,7 +13,6 @@ import (
"dynatron.me/x/stillbox/internal/jsontypes"
"dynatron.me/x/stillbox/pkg/incidents"
"dynatron.me/x/stillbox/pkg/incidents/incstore"
"dynatron.me/x/stillbox/pkg/shares"
"dynatron.me/x/stillbox/pkg/talkgroups/tgstore"
"github.com/go-chi/chi/v5"
@ -91,22 +91,22 @@ func (ia *incidentsAPI) createIncident(w http.ResponseWriter, r *http.Request) {
func (ia *incidentsAPI) getIncidentRoute(w http.ResponseWriter, r *http.Request) {
id, err := idOnlyParam(w, r)
if err != nil {
wErr(w, r, autoError(err))
return
}
ia.getIncident(id, nil, w, r)
}
func (ia *incidentsAPI) getIncident(id ID, share *shares.Share, w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
incs := incstore.FromCtx(ctx)
inc, err := incs.Incident(ctx, id.(uuid.UUID))
e, err := ia.getIncident(r.Context(), id)
if err != nil {
wErr(w, r, autoError(err))
return
}
respond(w, r, inc)
respond(w, r, e)
}
func (ia *incidentsAPI) getIncident(ctx context.Context, id ID) (SharedItem, error) {
incs := incstore.FromCtx(ctx)
return incs.Incident(ctx, id.(uuid.UUID))
}
func (ia *incidentsAPI) updateIncident(w http.ResponseWriter, r *http.Request) {
@ -195,10 +195,10 @@ func (ia *incidentsAPI) getCallsM3URoute(w http.ResponseWriter, r *http.Request)
return
}
ia.getCallsM3U(id, nil, w, r)
ia.getCallsM3U(id, w, r)
}
func (ia *incidentsAPI) getCallsM3U(id ID, share *shares.Share, w http.ResponseWriter, r *http.Request) {
func (ia *incidentsAPI) getCallsM3U(id ID, w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
incs := incstore.FromCtx(ctx)
tgst := tgstore.FromCtx(ctx)
@ -214,6 +214,7 @@ func (ia *incidentsAPI) getCallsM3U(id ID, share *shares.Share, w http.ResponseW
callUrl := common.PtrTo(*ia.baseURL)
urlRoot := "/api/call"
filename := inc.PlaylistFilename()
share := ShareFrom(ctx)
if share != nil {
urlRoot = fmt.Sprintf("/share/%s/call/", share.ID)
filename += "_" + share.ID

View file

@ -1,6 +1,7 @@
package rest
import (
"context"
"errors"
"net/http"
"net/url"
@ -23,6 +24,7 @@ type ShareRequestType string
const (
ShareRequestCall ShareRequestType = "call"
ShareRequestCallInfo ShareRequestType = "callinfo"
ShareRequestCallDL ShareRequestType = "callDL"
ShareRequestIncident ShareRequestType = "incident"
ShareRequestIncidentM3U ShareRequestType = "m3u"
@ -31,7 +33,7 @@ const (
func (rt ShareRequestType) IsValid() bool {
switch rt {
case ShareRequestCall, ShareRequestCallDL, ShareRequestIncident,
case ShareRequestCall, ShareRequestCallInfo, ShareRequestCallDL, ShareRequestIncident,
ShareRequestIncidentM3U, ShareRequestTalkgroups:
return true
}
@ -39,25 +41,59 @@ func (rt ShareRequestType) IsValid() bool {
return false
}
func (rt ShareRequestType) IsValidSubtype() bool {
switch rt {
case ShareRequestCall, ShareRequestCallDL, ShareRequestTalkgroups:
return true
}
return false
}
type ID interface {
}
type HandlerFunc func(id ID, share *shares.Share, w http.ResponseWriter, r *http.Request)
type ShareHandlers map[ShareRequestType]HandlerFunc
type ShareHandlerFunc func(id ID, w http.ResponseWriter, r *http.Request)
type ShareHandlers map[ShareRequestType]ShareHandlerFunc
type shareAPI struct {
baseURL *url.URL
shnd ShareHandlers
}
type EntityFunc func(ctx context.Context, id ID) (SharedItem, error)
type SharedItem interface {
}
type shareResponse struct {
ID ID `json:"id"`
Type shares.EntityType `json:"type"`
Item SharedItem `json:"item,omitempty"`
}
func ShareFrom(ctx context.Context) *shares.Share {
if share, hasShare := entities.SubjectFrom(ctx).(*shares.Share); hasShare {
return share
}
return nil
}
func respondShareHandler(ie EntityFunc) ShareHandlerFunc {
return func(id ID, w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
share := ShareFrom(ctx)
if share == nil {
wErr(w, r, autoError(ErrBadShare))
return
}
res, err := ie(r.Context(), id)
if err != nil {
wErr(w, r, autoError(err))
return
}
sRes := shareResponse{
ID: id,
Type: share.Type,
Item: res,
}
respond(w, r, sRes)
}
}
func newShareAPI(baseURL *url.URL, shnd ShareHandlers) *shareAPI {
return &shareAPI{
baseURL: baseURL,
@ -135,12 +171,11 @@ func (sa *shareAPI) routeShare(w http.ResponseWriter, r *http.Request) {
} else {
switch sh.Type {
case shares.EntityCall:
rType = ShareRequestCall
rType = ShareRequestCallInfo
params.SubID = common.PtrTo(sh.EntityID.String())
case shares.EntityIncident:
rType = ShareRequestIncident
}
w.Header().Set("X-Share-Type", string(rType))
}
if !rType.IsValid() {
@ -158,21 +193,22 @@ func (sa *shareAPI) routeShare(w http.ResponseWriter, r *http.Request) {
switch rType {
case ShareRequestTalkgroups:
sa.shnd[rType](nil, sh, w, r)
case ShareRequestCall, ShareRequestCallDL:
if params.SubID == nil {
wErr(w, r, autoError(ErrBadShare))
return
sa.shnd[rType](nil, w, r)
case ShareRequestCall, ShareRequestCallInfo, ShareRequestCallDL:
var subIDU uuid.UUID
if params.SubID != nil {
subIDU, err = uuid.Parse(*params.SubID)
if err != nil {
wErr(w, r, badRequest(err))
return
}
} else {
subIDU = sh.EntityID
}
subIDU, err := uuid.Parse(*params.SubID)
if err != nil {
wErr(w, r, badRequest(err))
return
}
sa.shnd[rType](subIDU, sh, w, r)
sa.shnd[rType](subIDU, w, r)
case ShareRequestIncident, ShareRequestIncidentM3U:
sa.shnd[rType](sh.EntityID, sh, w, r)
sa.shnd[rType](sh.EntityID, w, r)
}
}

View file

@ -8,7 +8,6 @@ import (
"dynatron.me/x/stillbox/internal/forms"
"dynatron.me/x/stillbox/pkg/database"
"dynatron.me/x/stillbox/pkg/incidents/incstore"
"dynatron.me/x/stillbox/pkg/shares"
"dynatron.me/x/stillbox/pkg/talkgroups"
"dynatron.me/x/stillbox/pkg/talkgroups/tgstore"
"dynatron.me/x/stillbox/pkg/talkgroups/xport"
@ -161,10 +160,16 @@ func (tga *talkgroupAPI) postPaginated(w http.ResponseWriter, r *http.Request) {
respond(w, r, res)
}
func (tga *talkgroupAPI) getTGsShareRoute(_ ID, share *shares.Share, w http.ResponseWriter, r *http.Request) {
func (tga *talkgroupAPI) getTGsShareRoute(_ ID, w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
tgs := tgstore.FromCtx(ctx)
share := ShareFrom(ctx)
if share == nil {
wErr(w, r, autoError(ErrBadShare))
return
}
tgIDs, err := incstore.FromCtx(ctx).TGsIn(ctx, share.EntityID)
if err != nil {
wErr(w, r, autoError(err))