Initial endpoints
This commit is contained in:
parent
cac95e1b25
commit
b5af8b0878
18 changed files with 676 additions and 257 deletions
|
@ -32,7 +32,7 @@ func call(url string, call *calls.Call) error {
|
|||
var buf bytes.Buffer
|
||||
body := multipart.NewWriter(&buf)
|
||||
|
||||
err := forms.Marshal(call, body)
|
||||
err := forms.Marshal(call, body, forms.WithTag("json"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("relay form parse: %w", err)
|
||||
}
|
||||
|
@ -88,6 +88,8 @@ func TestMarshal(t *testing.T) {
|
|||
t.Run(tc.name, func(t *testing.T) {
|
||||
var serr error
|
||||
var called bool
|
||||
|
||||
// setup request handler
|
||||
h := hand(func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
serr = r.ParseMultipartForm(1024 * 1024 * 2)
|
||||
|
@ -112,6 +114,7 @@ func TestMarshal(t *testing.T) {
|
|||
})
|
||||
svr := httptest.NewServer(h)
|
||||
|
||||
// perform the request
|
||||
err := call(svr.URL, &tc.call)
|
||||
assert.True(t, called)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -33,7 +33,6 @@ type callUploadRequest struct {
|
|||
Key string `form:"key"`
|
||||
Patches []int `form:"patches"`
|
||||
Source int `form:"source"`
|
||||
Sources []int `form:"sources"`
|
||||
System int `form:"system"`
|
||||
SystemLabel string `form:"systemLabel"`
|
||||
Talkgroup int `form:"talkgroup"`
|
||||
|
|
|
@ -28,6 +28,14 @@ func (t *Time) UnmarshalYAML(n *yaml.Node) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func TimePtrFromTSTZ(t pgtype.Timestamptz) *Time {
|
||||
if t.Valid {
|
||||
return (*Time)(&t.Time)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Time) PGTypeTSTZ() pgtype.Timestamptz {
|
||||
if t == nil {
|
||||
return pgtype.Timestamptz{Valid: false}
|
||||
|
|
|
@ -42,26 +42,25 @@ type CallAudio struct {
|
|||
}
|
||||
|
||||
type Call struct {
|
||||
ID uuid.UUID `form:"-"`
|
||||
Audio []byte `form:"audio" filenameField:"AudioName"`
|
||||
AudioName string `form:"audioName"`
|
||||
AudioType string `form:"audioType"`
|
||||
Duration CallDuration `form:"-"`
|
||||
DateTime time.Time `form:"dateTime"`
|
||||
Frequencies []int `form:"frequencies"`
|
||||
Frequency int `form:"frequency"`
|
||||
Patches []int `form:"patches"`
|
||||
Source int `form:"source"`
|
||||
Sources []int `form:"sources"`
|
||||
System int `form:"system"`
|
||||
Submitter *auth.UserID `form:"-"`
|
||||
SystemLabel string `form:"systemLabel"`
|
||||
Talkgroup int `form:"talkgroup"`
|
||||
TalkgroupGroup *string `form:"talkgroupGroup"`
|
||||
TalkgroupLabel *string `form:"talkgroupLabel"`
|
||||
TGAlphaTag *string `form:"talkgroupTag"` // not 1:1
|
||||
ID uuid.UUID `json:"-"`
|
||||
Audio []byte `json:"audio,omitempty" filenameField:"AudioName"`
|
||||
AudioName string `json:"audioName,omitempty"`
|
||||
AudioType string `json:"audioType,omitempty"`
|
||||
Duration CallDuration `json:"-"`
|
||||
DateTime time.Time `json:"dateTime,omitempty"`
|
||||
Frequencies []int `json:"frequencies,omitempty"`
|
||||
Frequency int `json:"frequency,omitempty"`
|
||||
Patches []int `json:"patches,omitempty"`
|
||||
Source int `json:"source,omitempty"`
|
||||
System int `json:"system,omitempty"`
|
||||
Submitter *auth.UserID `json:"-,omitempty"`
|
||||
SystemLabel string `json:"systemLabel,omitempty"`
|
||||
Talkgroup int `json:"talkgroup,omitempty"`
|
||||
TalkgroupGroup *string `json:"talkgroupGroup,omitempty"`
|
||||
TalkgroupLabel *string `json:"talkgroupLabel,omitempty"`
|
||||
TGAlphaTag *string `json:"talkgroupTag,omitempty"`
|
||||
|
||||
shouldStore bool `form:"-"`
|
||||
shouldStore bool `json:"-"`
|
||||
}
|
||||
|
||||
func (c *Call) String() string {
|
||||
|
@ -114,7 +113,6 @@ func (c *Call) ToPB() *pb.Call {
|
|||
Frequency: int64(c.Frequency),
|
||||
Frequencies: toInt64Slice(c.Frequencies),
|
||||
Patches: toInt32Slice(c.Patches),
|
||||
Sources: toInt32Slice(c.Sources),
|
||||
Duration: c.Duration.MsInt32Ptr(),
|
||||
Audio: c.Audio,
|
||||
}
|
||||
|
|
|
@ -157,7 +157,21 @@ func (q *Queries) CleanupSweptCalls(ctx context.Context, rangeStart pgtype.Times
|
|||
}
|
||||
|
||||
const getCallAudioByID = `-- name: GetCallAudioByID :one
|
||||
SELECT call_date, audio_name, audio_type, audio_blob FROM calls WHERE id = $1
|
||||
SELECT
|
||||
c.call_date,
|
||||
c.audio_name,
|
||||
c.audio_type,
|
||||
c.audio_blob
|
||||
FROM calls c
|
||||
WHERE c.id = $1
|
||||
UNION
|
||||
SELECT
|
||||
sc.call_date,
|
||||
sc.audio_name,
|
||||
sc.audio_type,
|
||||
sc.audio_blob
|
||||
FROM swept_calls sc
|
||||
WHERE sc.id = $1
|
||||
`
|
||||
|
||||
type GetCallAudioByIDRow struct {
|
||||
|
|
|
@ -131,36 +131,85 @@ func (q *Queries) GetIncident(ctx context.Context, id uuid.UUID) (Incident, erro
|
|||
return i, err
|
||||
}
|
||||
|
||||
const incidentCalls = `-- name: IncidentCalls :many
|
||||
SELECT
|
||||
ic.incident_id, call_date,
|
||||
ic.call_id,
|
||||
ic.notes
|
||||
FROM incidents_calls ic
|
||||
const getIncidentCalls = `-- name: GetIncidentCalls :many
|
||||
SELECT ic.call_id, ic.call_date, ic.notes, c.submitter, c.system, c.talkgroup, c.audio_name, c.duration, c.audio_type, c.audio_url, c.frequency, c.frequencies, c.patches, c.source, c.transcript
|
||||
FROM incidents_calls ic, LATERAL (
|
||||
SELECT
|
||||
ca.submitter,
|
||||
ca.system,
|
||||
ca.talkgroup,
|
||||
ca.audio_name,
|
||||
ca.duration,
|
||||
ca.audio_type,
|
||||
ca.audio_url,
|
||||
ca.frequency,
|
||||
ca.frequencies,
|
||||
ca.patches,
|
||||
ca.source,
|
||||
ca.transcript
|
||||
FROM calls ca WHERE ca.id = ic.calls_tbl_id AND ca.call_date = ic.call_date
|
||||
UNION
|
||||
SELECT
|
||||
sc.submitter,
|
||||
sc.system,
|
||||
sc.talkgroup,
|
||||
sc.audio_name,
|
||||
sc.duration,
|
||||
sc.audio_type,
|
||||
sc.audio_url,
|
||||
sc.frequency,
|
||||
sc.frequencies,
|
||||
sc.patches,
|
||||
sc.source,
|
||||
sc.transcript
|
||||
FROM swept_calls sc WHERE sc.id = ic.swept_call_id
|
||||
) c
|
||||
WHERE ic.incident_id = $1
|
||||
`
|
||||
|
||||
type IncidentCallsRow struct {
|
||||
IncidentID uuid.UUID `json:"incident_id"`
|
||||
CallDate pgtype.Timestamptz `json:"call_date"`
|
||||
CallID uuid.UUID `json:"call_id"`
|
||||
Notes []byte `json:"notes"`
|
||||
type GetIncidentCallsRow struct {
|
||||
CallID uuid.UUID `json:"call_id"`
|
||||
CallDate pgtype.Timestamptz `json:"call_date"`
|
||||
Notes []byte `json:"notes"`
|
||||
Submitter *int32 `json:"submitter"`
|
||||
System int `json:"system"`
|
||||
Talkgroup int `json:"talkgroup"`
|
||||
AudioName *string `json:"audio_name"`
|
||||
Duration *int32 `json:"duration"`
|
||||
AudioType *string `json:"audio_type"`
|
||||
AudioUrl *string `json:"audio_url"`
|
||||
Frequency int `json:"frequency"`
|
||||
Frequencies []int `json:"frequencies"`
|
||||
Patches []int `json:"patches"`
|
||||
Source int `json:"source"`
|
||||
Transcript *string `json:"transcript"`
|
||||
}
|
||||
|
||||
// INCOMPLETE
|
||||
func (q *Queries) IncidentCalls(ctx context.Context) ([]IncidentCallsRow, error) {
|
||||
rows, err := q.db.Query(ctx, incidentCalls)
|
||||
func (q *Queries) GetIncidentCalls(ctx context.Context, id uuid.UUID) ([]GetIncidentCallsRow, error) {
|
||||
rows, err := q.db.Query(ctx, getIncidentCalls, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []IncidentCallsRow
|
||||
var items []GetIncidentCallsRow
|
||||
for rows.Next() {
|
||||
var i IncidentCallsRow
|
||||
var i GetIncidentCallsRow
|
||||
if err := rows.Scan(
|
||||
&i.IncidentID,
|
||||
&i.CallDate,
|
||||
&i.CallID,
|
||||
&i.CallDate,
|
||||
&i.Notes,
|
||||
&i.Submitter,
|
||||
&i.System,
|
||||
&i.Talkgroup,
|
||||
&i.AudioName,
|
||||
&i.Duration,
|
||||
&i.AudioType,
|
||||
&i.AudioUrl,
|
||||
&i.Frequency,
|
||||
&i.Frequencies,
|
||||
&i.Patches,
|
||||
&i.Source,
|
||||
&i.Transcript,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -253,6 +302,27 @@ func (q *Queries) ListIncidentsP(ctx context.Context, arg ListIncidentsPParams)
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const removeFromIncident = `-- name: RemoveFromIncident :exec
|
||||
DELETE FROM incidents_calls ic
|
||||
WHERE ic.incident_id = $1 AND ic.call_id = ANY($2::UUID[])
|
||||
`
|
||||
|
||||
func (q *Queries) RemoveFromIncident(ctx context.Context, iD uuid.UUID, callIds []uuid.UUID) error {
|
||||
_, err := q.db.Exec(ctx, removeFromIncident, iD, callIds)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateCallIncidentNotes = `-- name: UpdateCallIncidentNotes :exec
|
||||
UPDATE incidents_Calls
|
||||
SET notes = $1
|
||||
WHERE incident_id = $2 AND call_id = $3
|
||||
`
|
||||
|
||||
func (q *Queries) UpdateCallIncidentNotes(ctx context.Context, notes []byte, incidentID uuid.UUID, callID uuid.UUID) error {
|
||||
_, err := q.db.Exec(ctx, updateCallIncidentNotes, notes, incidentID, callID)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateIncident = `-- name: UpdateIncident :one
|
||||
UPDATE incidents
|
||||
SET
|
||||
|
|
|
@ -1377,6 +1377,65 @@ func (_c *Store_GetIncident_Call) RunAndReturn(run func(context.Context, uuid.UU
|
|||
return _c
|
||||
}
|
||||
|
||||
// GetIncidentCalls provides a mock function with given fields: ctx, id
|
||||
func (_m *Store) GetIncidentCalls(ctx context.Context, id uuid.UUID) ([]database.GetIncidentCallsRow, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetIncidentCalls")
|
||||
}
|
||||
|
||||
var r0 []database.GetIncidentCallsRow
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) ([]database.GetIncidentCallsRow, error)); ok {
|
||||
return rf(ctx, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID) []database.GetIncidentCallsRow); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]database.GetIncidentCallsRow)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, uuid.UUID) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Store_GetIncidentCalls_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetIncidentCalls'
|
||||
type Store_GetIncidentCalls_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetIncidentCalls is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - id uuid.UUID
|
||||
func (_e *Store_Expecter) GetIncidentCalls(ctx interface{}, id interface{}) *Store_GetIncidentCalls_Call {
|
||||
return &Store_GetIncidentCalls_Call{Call: _e.mock.On("GetIncidentCalls", ctx, id)}
|
||||
}
|
||||
|
||||
func (_c *Store_GetIncidentCalls_Call) Run(run func(ctx context.Context, id uuid.UUID)) *Store_GetIncidentCalls_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(uuid.UUID))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_GetIncidentCalls_Call) Return(_a0 []database.GetIncidentCallsRow, _a1 error) *Store_GetIncidentCalls_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_GetIncidentCalls_Call) RunAndReturn(run func(context.Context, uuid.UUID) ([]database.GetIncidentCallsRow, error)) *Store_GetIncidentCalls_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetSystemName provides a mock function with given fields: ctx, systemID
|
||||
func (_m *Store) GetSystemName(ctx context.Context, systemID int) (string, error) {
|
||||
ret := _m.Called(ctx, systemID)
|
||||
|
@ -2594,64 +2653,6 @@ func (_c *Store_InTx_Call) RunAndReturn(run func(context.Context, func(database.
|
|||
return _c
|
||||
}
|
||||
|
||||
// IncidentCalls provides a mock function with given fields: ctx
|
||||
func (_m *Store) IncidentCalls(ctx context.Context) ([]database.IncidentCallsRow, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for IncidentCalls")
|
||||
}
|
||||
|
||||
var r0 []database.IncidentCallsRow
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) ([]database.IncidentCallsRow, error)); ok {
|
||||
return rf(ctx)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) []database.IncidentCallsRow); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]database.IncidentCallsRow)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Store_IncidentCalls_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IncidentCalls'
|
||||
type Store_IncidentCalls_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// IncidentCalls is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *Store_Expecter) IncidentCalls(ctx interface{}) *Store_IncidentCalls_Call {
|
||||
return &Store_IncidentCalls_Call{Call: _e.mock.On("IncidentCalls", ctx)}
|
||||
}
|
||||
|
||||
func (_c *Store_IncidentCalls_Call) Run(run func(ctx context.Context)) *Store_IncidentCalls_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_IncidentCalls_Call) Return(_a0 []database.IncidentCallsRow, _a1 error) *Store_IncidentCalls_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_IncidentCalls_Call) RunAndReturn(run func(context.Context) ([]database.IncidentCallsRow, error)) *Store_IncidentCalls_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// ListCallsCount provides a mock function with given fields: ctx, arg
|
||||
func (_m *Store) ListCallsCount(ctx context.Context, arg database.ListCallsCountParams) (int64, error) {
|
||||
ret := _m.Called(ctx, arg)
|
||||
|
@ -2885,6 +2886,54 @@ func (_c *Store_ListIncidentsP_Call) RunAndReturn(run func(context.Context, data
|
|||
return _c
|
||||
}
|
||||
|
||||
// RemoveFromIncident provides a mock function with given fields: ctx, iD, callIds
|
||||
func (_m *Store) RemoveFromIncident(ctx context.Context, iD uuid.UUID, callIds []uuid.UUID) error {
|
||||
ret := _m.Called(ctx, iD, callIds)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RemoveFromIncident")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, []uuid.UUID) error); ok {
|
||||
r0 = rf(ctx, iD, callIds)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Store_RemoveFromIncident_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveFromIncident'
|
||||
type Store_RemoveFromIncident_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// RemoveFromIncident is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - iD uuid.UUID
|
||||
// - callIds []uuid.UUID
|
||||
func (_e *Store_Expecter) RemoveFromIncident(ctx interface{}, iD interface{}, callIds interface{}) *Store_RemoveFromIncident_Call {
|
||||
return &Store_RemoveFromIncident_Call{Call: _e.mock.On("RemoveFromIncident", ctx, iD, callIds)}
|
||||
}
|
||||
|
||||
func (_c *Store_RemoveFromIncident_Call) Run(run func(ctx context.Context, iD uuid.UUID, callIds []uuid.UUID)) *Store_RemoveFromIncident_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(uuid.UUID), args[2].([]uuid.UUID))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_RemoveFromIncident_Call) Return(_a0 error) *Store_RemoveFromIncident_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_RemoveFromIncident_Call) RunAndReturn(run func(context.Context, uuid.UUID, []uuid.UUID) error) *Store_RemoveFromIncident_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// RestoreTalkgroupVersion provides a mock function with given fields: ctx, versionIds
|
||||
func (_m *Store) RestoreTalkgroupVersion(ctx context.Context, versionIds int) (database.Talkgroup, error) {
|
||||
ret := _m.Called(ctx, versionIds)
|
||||
|
@ -3244,6 +3293,55 @@ func (_c *Store_SweepCalls_Call) RunAndReturn(run func(context.Context, pgtype.T
|
|||
return _c
|
||||
}
|
||||
|
||||
// UpdateCallIncidentNotes provides a mock function with given fields: ctx, notes, incidentID, callID
|
||||
func (_m *Store) UpdateCallIncidentNotes(ctx context.Context, notes []byte, incidentID uuid.UUID, callID uuid.UUID) error {
|
||||
ret := _m.Called(ctx, notes, incidentID, callID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateCallIncidentNotes")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, []byte, uuid.UUID, uuid.UUID) error); ok {
|
||||
r0 = rf(ctx, notes, incidentID, callID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Store_UpdateCallIncidentNotes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateCallIncidentNotes'
|
||||
type Store_UpdateCallIncidentNotes_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// UpdateCallIncidentNotes is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - notes []byte
|
||||
// - incidentID uuid.UUID
|
||||
// - callID uuid.UUID
|
||||
func (_e *Store_Expecter) UpdateCallIncidentNotes(ctx interface{}, notes interface{}, incidentID interface{}, callID interface{}) *Store_UpdateCallIncidentNotes_Call {
|
||||
return &Store_UpdateCallIncidentNotes_Call{Call: _e.mock.On("UpdateCallIncidentNotes", ctx, notes, incidentID, callID)}
|
||||
}
|
||||
|
||||
func (_c *Store_UpdateCallIncidentNotes_Call) Run(run func(ctx context.Context, notes []byte, incidentID uuid.UUID, callID uuid.UUID)) *Store_UpdateCallIncidentNotes_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].([]byte), args[2].(uuid.UUID), args[3].(uuid.UUID))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_UpdateCallIncidentNotes_Call) Return(_a0 error) *Store_UpdateCallIncidentNotes_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_UpdateCallIncidentNotes_Call) RunAndReturn(run func(context.Context, []byte, uuid.UUID, uuid.UUID) error) *Store_UpdateCallIncidentNotes_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// UpdateIncident provides a mock function with given fields: ctx, arg
|
||||
func (_m *Store) UpdateIncident(ctx context.Context, arg database.UpdateIncidentParams) (database.Incident, error) {
|
||||
ret := _m.Called(ctx, arg)
|
||||
|
|
|
@ -33,6 +33,7 @@ type Querier interface {
|
|||
GetCallAudioByID(ctx context.Context, id uuid.UUID) (GetCallAudioByIDRow, error)
|
||||
GetDatabaseSize(ctx context.Context) (string, error)
|
||||
GetIncident(ctx context.Context, id uuid.UUID) (Incident, error)
|
||||
GetIncidentCalls(ctx context.Context, id uuid.UUID) ([]GetIncidentCallsRow, error)
|
||||
GetSystemName(ctx context.Context, systemID int) (string, error)
|
||||
GetTalkgroup(ctx context.Context, systemID int32, tGID int32) (GetTalkgroupRow, error)
|
||||
GetTalkgroupIDsByTags(ctx context.Context, anyTags []string, allTags []string, notTags []string) ([]GetTalkgroupIDsByTagsRow, error)
|
||||
|
@ -50,12 +51,11 @@ type Querier interface {
|
|||
GetUserByUID(ctx context.Context, id int) (User, error)
|
||||
GetUserByUsername(ctx context.Context, username string) (User, error)
|
||||
GetUsers(ctx context.Context) ([]User, error)
|
||||
// INCOMPLETE
|
||||
IncidentCalls(ctx context.Context) ([]IncidentCallsRow, error)
|
||||
ListCallsCount(ctx context.Context, arg ListCallsCountParams) (int64, error)
|
||||
ListCallsP(ctx context.Context, arg ListCallsPParams) ([]ListCallsPRow, error)
|
||||
ListIncidentsCount(ctx context.Context, start pgtype.Timestamptz, end pgtype.Timestamptz) (int64, error)
|
||||
ListIncidentsP(ctx context.Context, arg ListIncidentsPParams) ([]Incident, error)
|
||||
RemoveFromIncident(ctx context.Context, iD uuid.UUID, callIds []uuid.UUID) error
|
||||
RestoreTalkgroupVersion(ctx context.Context, versionIds int) (Talkgroup, error)
|
||||
SetAppPrefs(ctx context.Context, appName string, prefs []byte, uid int) error
|
||||
SetCallTranscript(ctx context.Context, iD uuid.UUID, transcript *string) error
|
||||
|
@ -63,6 +63,7 @@ type Querier interface {
|
|||
StoreDeletedTGVersion(ctx context.Context, systemID *int32, tGID *int32, submitter *int32) error
|
||||
StoreTGVersion(ctx context.Context, arg []StoreTGVersionParams) *StoreTGVersionBatchResults
|
||||
SweepCalls(ctx context.Context, rangeStart pgtype.Timestamptz, rangeEnd pgtype.Timestamptz) (int64, error)
|
||||
UpdateCallIncidentNotes(ctx context.Context, notes []byte, incidentID uuid.UUID, callID uuid.UUID) error
|
||||
UpdateIncident(ctx context.Context, arg UpdateIncidentParams) (Incident, error)
|
||||
UpdatePassword(ctx context.Context, username string, password string) error
|
||||
UpdateTalkgroup(ctx context.Context, arg UpdateTalkgroupParams) (Talkgroup, error)
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package incidents
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/jsontypes"
|
||||
"dynatron.me/x/stillbox/pkg/calls"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
|
@ -13,4 +16,10 @@ type Incident struct {
|
|||
EndTime *jsontypes.Time `json:"endTime"`
|
||||
Location jsontypes.Location `json:"location"`
|
||||
Metadata jsontypes.Metadata `json:"metadata"`
|
||||
Calls []IncidentCall `json:"calls"`
|
||||
}
|
||||
|
||||
type IncidentCall struct {
|
||||
calls.Call
|
||||
Notes json.RawMessage `json:"notes"`
|
||||
}
|
||||
|
|
|
@ -2,9 +2,12 @@ package incstore
|
|||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/common"
|
||||
"dynatron.me/x/stillbox/internal/jsontypes"
|
||||
"dynatron.me/x/stillbox/pkg/auth"
|
||||
"dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
"dynatron.me/x/stillbox/pkg/incidents"
|
||||
"github.com/google/uuid"
|
||||
|
@ -25,13 +28,16 @@ type Store interface {
|
|||
|
||||
// AddToIncident adds the specified call IDs to an incident.
|
||||
// If not nil, notes must be valid json.
|
||||
AddToIncident(ctx context.Context, incidentID uuid.UUID, callIDs []uuid.UUID, notes []byte) error
|
||||
AddRemoveIncidentCalls(ctx context.Context, incidentID uuid.UUID, addCallIDs []uuid.UUID, notes []byte, removeCallIDs []uuid.UUID) error
|
||||
|
||||
// UpdateNotes updates the notes for a call-incident mapping.
|
||||
UpdateNotes(ctx context.Context, incidentID uuid.UUID, callID uuid.UUID, notes []byte) error
|
||||
|
||||
// Incidents gets incidents matching parameters and pagination.
|
||||
Incidents(ctx context.Context, p IncidentsParams) (incs []database.Incident, totalCount int, err error)
|
||||
|
||||
// Incident gets a single incident.
|
||||
Incident(ctx context.Context, id uuid.UUID) (database.Incident, error)
|
||||
Incident(ctx context.Context, id uuid.UUID) (*incidents.Incident, error)
|
||||
|
||||
// UpdateIncident updates an incident.
|
||||
UpdateIncident(ctx context.Context, id uuid.UUID, p UpdateIncidentParams) (database.Incident, error)
|
||||
|
@ -79,18 +85,32 @@ func (s *store) CreateIncident(ctx context.Context, inc incidents.Incident) (dat
|
|||
return dbInc, err
|
||||
}
|
||||
|
||||
func (s *store) AddToIncident(ctx context.Context, incidentID uuid.UUID, callIDs []uuid.UUID, notes []byte) error {
|
||||
db := database.FromCtx(ctx)
|
||||
func (s *store) AddRemoveIncidentCalls(ctx context.Context, incidentID uuid.UUID, addCallIDs []uuid.UUID, notes []byte, removeCallIDs []uuid.UUID) error {
|
||||
return database.FromCtx(ctx).InTx(ctx, func(db database.Store) error {
|
||||
if len(addCallIDs) > 0 {
|
||||
var noteAr [][]byte
|
||||
if notes != nil {
|
||||
noteAr = make([][]byte, len(addCallIDs))
|
||||
for i := range addCallIDs {
|
||||
noteAr[i] = notes
|
||||
}
|
||||
}
|
||||
|
||||
var noteAr [][]byte
|
||||
if notes != nil {
|
||||
noteAr = make([][]byte, len(callIDs))
|
||||
for i := range callIDs {
|
||||
noteAr[i] = notes
|
||||
err := db.AddToIncident(ctx, incidentID, addCallIDs, noteAr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return db.AddToIncident(ctx, incidentID, callIDs, noteAr)
|
||||
if len(removeCallIDs) > 0 {
|
||||
err := db.RemoveFromIncident(ctx, incidentID, removeCallIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}, pgx.TxOptions{})
|
||||
}
|
||||
|
||||
func (s *store) Incidents(ctx context.Context, p IncidentsParams) (rows []database.Incident, totalCount int, err error) {
|
||||
|
@ -123,8 +143,67 @@ func (s *store) Incidents(ctx context.Context, p IncidentsParams) (rows []databa
|
|||
return rows, int(count), err
|
||||
}
|
||||
|
||||
func (s *store) Incident(ctx context.Context, id uuid.UUID) (database.Incident, error) {
|
||||
return database.FromCtx(ctx).GetIncident(ctx, id)
|
||||
func fromDBIncident(id uuid.UUID, d database.Incident) incidents.Incident {
|
||||
return incidents.Incident{
|
||||
ID: id,
|
||||
Name: d.Name,
|
||||
Description: d.Description,
|
||||
StartTime: jsontypes.TimePtrFromTSTZ(d.StartTime),
|
||||
EndTime: jsontypes.TimePtrFromTSTZ(d.EndTime),
|
||||
Metadata: d.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
func fromDBCalls(d []database.GetIncidentCallsRow) []incidents.IncidentCall {
|
||||
r := make([]incidents.IncidentCall, 0, len(d))
|
||||
for _, v := range d {
|
||||
dur := calls.CallDuration(time.Duration(common.ZeroIfNil(v.Duration)) * time.Millisecond)
|
||||
sub := common.PtrTo(auth.UserID(common.ZeroIfNil(v.Submitter)))
|
||||
r = append(r, incidents.IncidentCall{
|
||||
Call: calls.Call{
|
||||
ID: v.CallID,
|
||||
AudioName: common.ZeroIfNil(v.AudioName),
|
||||
AudioType: common.ZeroIfNil(v.AudioType),
|
||||
Duration: dur,
|
||||
DateTime: v.CallDate.Time,
|
||||
Frequencies: v.Frequencies,
|
||||
Frequency: v.Frequency,
|
||||
Patches: v.Patches,
|
||||
Source: v.Source,
|
||||
System: v.System,
|
||||
Submitter: sub,
|
||||
Talkgroup: v.Talkgroup,
|
||||
},
|
||||
Notes: v.Notes,
|
||||
})
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (s *store) Incident(ctx context.Context, id uuid.UUID) (*incidents.Incident, error) {
|
||||
var r incidents.Incident
|
||||
txErr := database.FromCtx(ctx).InTx(ctx, func(db database.Store) error {
|
||||
inc, err := db.GetIncident(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
calls, err := db.GetIncidentCalls(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r = fromDBIncident(id, inc)
|
||||
r.Calls = fromDBCalls(calls)
|
||||
|
||||
return nil
|
||||
}, pgx.TxOptions{})
|
||||
if txErr != nil {
|
||||
return nil, txErr
|
||||
}
|
||||
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
type UpdateIncidentParams struct {
|
||||
|
@ -157,3 +236,7 @@ func (s *store) UpdateIncident(ctx context.Context, id uuid.UUID, p UpdateIncide
|
|||
func (s *store) DeleteIncident(ctx context.Context, id uuid.UUID) error {
|
||||
return database.FromCtx(ctx).DeleteIncident(ctx, id)
|
||||
}
|
||||
|
||||
func (s *store) UpdateNotes(ctx context.Context, incidentID uuid.UUID, callID uuid.UUID, notes []byte) error {
|
||||
return database.FromCtx(ctx).UpdateCallIncidentNotes(ctx, notes, incidentID, callID)
|
||||
}
|
||||
|
|
|
@ -298,9 +298,8 @@ type Call struct {
|
|||
Frequency int64 `protobuf:"varint,8,opt,name=frequency,proto3" json:"frequency,omitempty"`
|
||||
Frequencies []int64 `protobuf:"varint,9,rep,packed,name=frequencies,proto3" json:"frequencies,omitempty"`
|
||||
Patches []int32 `protobuf:"varint,10,rep,packed,name=patches,proto3" json:"patches,omitempty"`
|
||||
Sources []int32 `protobuf:"varint,11,rep,packed,name=sources,proto3" json:"sources,omitempty"`
|
||||
Duration *int32 `protobuf:"varint,12,opt,name=duration,proto3,oneof" json:"duration,omitempty"`
|
||||
Audio []byte `protobuf:"bytes,13,opt,name=audio,proto3" json:"audio,omitempty"`
|
||||
Duration *int32 `protobuf:"varint,11,opt,name=duration,proto3,oneof" json:"duration,omitempty"`
|
||||
Audio []byte `protobuf:"bytes,12,opt,name=audio,proto3" json:"audio,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Call) Reset() {
|
||||
|
@ -405,13 +404,6 @@ func (x *Call) GetPatches() []int32 {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (x *Call) GetSources() []int32 {
|
||||
if x != nil {
|
||||
return x.Sources
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Call) GetDuration() int32 {
|
||||
if x != nil && x.Duration != nil {
|
||||
return *x.Duration
|
||||
|
@ -1195,7 +1187,7 @@ var file_stillbox_proto_rawDesc = []byte{
|
|||
0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x06, 0x74, 0x67, 0x49, 0x6e, 0x66,
|
||||
0x6f, 0x42, 0x12, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x72, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||
0x64, 0x5f, 0x69, 0x64, 0x22, 0x91, 0x03, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x0e, 0x0a,
|
||||
0x64, 0x5f, 0x69, 0x64, 0x22, 0xf7, 0x02, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x0e, 0x0a,
|
||||
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a,
|
||||
0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61,
|
||||
|
@ -1214,112 +1206,111 @@ var file_stillbox_proto_rawDesc = []byte{
|
|||
0x0a, 0x0b, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x09, 0x20,
|
||||
0x03, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28,
|
||||
0x05, 0x52, 0x07, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x05, 0x52, 0x07, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x18, 0x0d,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x42, 0x0b, 0x0a, 0x09, 0x5f,
|
||||
0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3e, 0x0a, 0x05, 0x48, 0x65, 0x6c, 0x6c,
|
||||
0x6f, 0x12, 0x35, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f,
|
||||
0x78, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x1d, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72,
|
||||
0x50, 0x6f, 0x70, 0x75, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x4a, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2b, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62,
|
||||
0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x22, 0x78, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||
0x6d, 0x70, 0x52, 0x08, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03,
|
||||
0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x22, 0xed, 0x01,
|
||||
0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x22, 0x0a, 0x0a, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52,
|
||||
0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a,
|
||||
0x0c, 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x4c,
|
||||
0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x6c, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x12, 0x39, 0x0a, 0x0e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x74, 0x69,
|
||||
0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x48, 0x00, 0x52, 0x0d,
|
||||
0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x34, 0x0a,
|
||||
0x0a, 0x74, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x07, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x08, 0x64, 0x75,
|
||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x08,
|
||||
0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x14, 0x0a, 0x05, 0x61,
|
||||
0x75, 0x64, 0x69, 0x6f, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x61, 0x75, 0x64, 0x69,
|
||||
0x6f, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3e,
|
||||
0x0a, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x35, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73,
|
||||
0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x1d,
|
||||
0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x50, 0x6f, 0x70, 0x75, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x6d,
|
||||
0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x4a, 0x0a,
|
||||
0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2b, 0x0a, 0x07,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e,
|
||||
0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0x78, 0x0a, 0x0c, 0x4e, 0x6f, 0x74,
|
||||
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x09, 0x64, 0x61, 0x74,
|
||||
0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69,
|
||||
0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x03, 0x6d, 0x73, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75,
|
||||
0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x55, 0x72, 0x6c, 0x22, 0xed, 0x01, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12,
|
||||
0x22, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64,
|
||||
0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x0c, 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x73, 0x74, 0x69, 0x6c,
|
||||
0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x6c, 0x69, 0x76,
|
||||
0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x39, 0x0a, 0x0e, 0x73, 0x65, 0x61, 0x72,
|
||||
0x63, 0x68, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x10, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x53, 0x65, 0x61, 0x72,
|
||||
0x63, 0x68, 0x48, 0x00, 0x52, 0x0d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x12, 0x34, 0x0a, 0x0a, 0x74, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62,
|
||||
0x6f, 0x78, 0x2e, 0x54, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x48, 0x00, 0x52, 0x09,
|
||||
0x74, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x5f, 0x69, 0x64, 0x22, 0xf2, 0x02, 0x0a, 0x0d, 0x54, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75,
|
||||
0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x23, 0x0a, 0x02, 0x74, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x13, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x54, 0x61, 0x6c,
|
||||
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x48, 0x00, 0x52, 0x09, 0x74, 0x67, 0x43, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x42, 0x0d,
|
||||
0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x22, 0xf2, 0x02,
|
||||
0x0a, 0x0d, 0x54, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12,
|
||||
0x23, 0x0a, 0x02, 0x74, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x74,
|
||||
0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x54, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70,
|
||||
0x52, 0x02, 0x74, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65,
|
||||
0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x19,
|
||||
0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52,
|
||||
0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x61, 0x6c, 0x70,
|
||||
0x68, 0x61, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x08,
|
||||
0x61, 0x6c, 0x70, 0x68, 0x61, 0x54, 0x61, 0x67, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x66,
|
||||
0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x48, 0x03,
|
||||
0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x88, 0x01, 0x01, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61,
|
||||
0x67, 0x73, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x08,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x48, 0x04, 0x52,
|
||||
0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, 0x01, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x6c, 0x65, 0x61, 0x72, 0x6e, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6c,
|
||||
0x65, 0x61, 0x72, 0x6e, 0x65, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42,
|
||||
0x08, 0x0a, 0x06, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x61, 0x6c,
|
||||
0x70, 0x68, 0x61, 0x5f, 0x74, 0x61, 0x67, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x66, 0x72, 0x65, 0x71,
|
||||
0x75, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
|
||||
0x74, 0x61, 0x22, 0x7a, 0x0a, 0x04, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x2e, 0x0a, 0x05, 0x73, 0x74,
|
||||
0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x73, 0x74, 0x69, 0x6c,
|
||||
0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00,
|
||||
0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x06, 0x66, 0x69,
|
||||
0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x74, 0x69,
|
||||
0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x01, 0x52, 0x06,
|
||||
0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x73, 0x74,
|
||||
0x61, 0x74, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x41,
|
||||
0x0a, 0x09, 0x54, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73,
|
||||
0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x79, 0x73,
|
||||
0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75,
|
||||
0x70, 0x22, 0x83, 0x02, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x0a,
|
||||
0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x13, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x54, 0x61, 0x6c, 0x6b,
|
||||
0x67, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0a, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70,
|
||||
0x73, 0x12, 0x3a, 0x0a, 0x0e, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x5f,
|
||||
0x6e, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x74, 0x69, 0x6c,
|
||||
0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x54, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0d,
|
||||
0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x4e, 0x6f, 0x74, 0x12, 0x2c, 0x0a,
|
||||
0x12, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x5f,
|
||||
0x61, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x74, 0x61, 0x6c, 0x6b, 0x67,
|
||||
0x72, 0x6f, 0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x41, 0x6c, 0x6c, 0x12, 0x2c, 0x0a, 0x12, 0x74,
|
||||
0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x5f, 0x61, 0x6e,
|
||||
0x79, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x41, 0x6e, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x74, 0x61, 0x6c,
|
||||
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x5f, 0x6e, 0x6f, 0x74, 0x18,
|
||||
0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70,
|
||||
0x54, 0x61, 0x67, 0x73, 0x4e, 0x6f, 0x74, 0x22, 0x08, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63,
|
||||
0x68, 0x22, 0x92, 0x01, 0x0a, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f,
|
||||
0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x62,
|
||||
0x75, 0x69, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x62, 0x75, 0x69, 0x6c,
|
||||
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x17, 0x0a,
|
||||
0x07, 0x64, 0x62, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x64, 0x62, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x37, 0x0a, 0x09, 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74,
|
||||
0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x4c, 0x53, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45,
|
||||
0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x53, 0x5f, 0x4c, 0x49, 0x56, 0x45, 0x10, 0x01,
|
||||
0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x53, 0x5f, 0x50, 0x41, 0x55, 0x53, 0x45, 0x44, 0x10, 0x02, 0x42,
|
||||
0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x02, 0x74, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x79,
|
||||
0x73, 0x74, 0x65, 0x6d, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x88, 0x01, 0x01, 0x12,
|
||||
0x20, 0x0a, 0x09, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01,
|
||||
0x28, 0x09, 0x48, 0x02, 0x52, 0x08, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x54, 0x61, 0x67, 0x88, 0x01,
|
||||
0x01, 0x12, 0x21, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x05, 0x48, 0x03, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63,
|
||||
0x79, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61,
|
||||
0x64, 0x61, 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72,
|
||||
0x75, 0x63, 0x74, 0x48, 0x04, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x88,
|
||||
0x01, 0x01, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x65, 0x61, 0x72, 0x6e, 0x65, 0x64, 0x18, 0x09, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x07, 0x6c, 0x65, 0x61, 0x72, 0x6e, 0x65, 0x64, 0x42, 0x07, 0x0a, 0x05,
|
||||
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x42,
|
||||
0x0c, 0x0a, 0x0a, 0x5f, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x5f, 0x74, 0x61, 0x67, 0x42, 0x0c, 0x0a,
|
||||
0x0a, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x0b, 0x0a, 0x09, 0x5f,
|
||||
0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x7a, 0x0a, 0x04, 0x4c, 0x69, 0x76, 0x65,
|
||||
0x12, 0x2e, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x13, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x53,
|
||||
0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x88, 0x01, 0x01,
|
||||
0x12, 0x2d, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x10, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x46, 0x69, 0x6c, 0x74,
|
||||
0x65, 0x72, 0x48, 0x01, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x88, 0x01, 0x01, 0x42,
|
||||
0x08, 0x0a, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x66, 0x69,
|
||||
0x6c, 0x74, 0x65, 0x72, 0x22, 0x41, 0x0a, 0x09, 0x54, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75,
|
||||
0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x6c,
|
||||
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x61,
|
||||
0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x83, 0x02, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x74,
|
||||
0x65, 0x72, 0x12, 0x33, 0x0a, 0x0a, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73,
|
||||
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f,
|
||||
0x78, 0x2e, 0x54, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0a, 0x74, 0x61, 0x6c,
|
||||
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x3a, 0x0a, 0x0e, 0x74, 0x61, 0x6c, 0x6b, 0x67,
|
||||
0x72, 0x6f, 0x75, 0x70, 0x73, 0x5f, 0x6e, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x13, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x54, 0x61, 0x6c, 0x6b, 0x67,
|
||||
0x72, 0x6f, 0x75, 0x70, 0x52, 0x0d, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73,
|
||||
0x4e, 0x6f, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70,
|
||||
0x5f, 0x74, 0x61, 0x67, 0x73, 0x5f, 0x61, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x10, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x41, 0x6c,
|
||||
0x6c, 0x12, 0x2c, 0x0a, 0x12, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x74,
|
||||
0x61, 0x67, 0x73, 0x5f, 0x61, 0x6e, 0x79, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x74,
|
||||
0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x41, 0x6e, 0x79, 0x12,
|
||||
0x2c, 0x0a, 0x12, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x74, 0x61, 0x67,
|
||||
0x73, 0x5f, 0x6e, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x74, 0x61, 0x6c,
|
||||
0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x54, 0x61, 0x67, 0x73, 0x4e, 0x6f, 0x74, 0x22, 0x08, 0x0a,
|
||||
0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x22, 0x92, 0x01, 0x0a, 0x0a, 0x53, 0x65, 0x72, 0x76,
|
||||
0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x05, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66,
|
||||
0x6f, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66,
|
||||
0x6f, 0x72, 0x6d, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x62, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x62, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x37, 0x0a, 0x09,
|
||||
0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x4c, 0x53, 0x5f,
|
||||
0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x53, 0x5f,
|
||||
0x4c, 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x53, 0x5f, 0x50, 0x41, 0x55,
|
||||
0x53, 0x45, 0x44, 0x10, 0x02, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -34,9 +34,8 @@ message Call {
|
|||
int64 frequency = 8;
|
||||
repeated int64 frequencies = 9;
|
||||
repeated int32 patches = 10;
|
||||
repeated int32 sources = 11;
|
||||
optional int32 duration = 12;
|
||||
bytes audio = 13;
|
||||
optional int32 duration = 11;
|
||||
bytes audio = 12;
|
||||
}
|
||||
|
||||
message Hello {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/go-viper/mapstructure/v2"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
@ -174,6 +175,21 @@ func decodeParams(d interface{}, r *http.Request) error {
|
|||
return dec.Decode(m)
|
||||
}
|
||||
|
||||
// idOnlyParam checks for a sole URL parameter, id, and writes an errorif this fails.
|
||||
func idOnlyParam(w http.ResponseWriter, r *http.Request) (uuid.UUID, error) {
|
||||
params := struct {
|
||||
ID uuid.UUID `param:"id"`
|
||||
}{}
|
||||
|
||||
err := decodeParams(¶ms, r)
|
||||
if err != nil {
|
||||
wErr(w, r, badRequest(err))
|
||||
return uuid.UUID{}, err
|
||||
}
|
||||
|
||||
return params.ID, nil
|
||||
}
|
||||
|
||||
func respond(w http.ResponseWriter, r *http.Request, v interface{}) {
|
||||
render.DefaultResponder(w, r, v)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/forms"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
"dynatron.me/x/stillbox/pkg/incidents"
|
||||
"dynatron.me/x/stillbox/pkg/incidents/incstore"
|
||||
"dynatron.me/x/stillbox/pkg/talkgroups/tgstore"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
|
@ -19,9 +23,11 @@ func (ia *incidentsAPI) Subrouter() http.Handler {
|
|||
r := chi.NewMux()
|
||||
|
||||
r.Get(`/{id:[a-f0-9-]+}`, ia.getIncident)
|
||||
r.Get(`/{id:[a-f0-9-]+}.m3u`, ia.getCallsM3U)
|
||||
|
||||
r.Post(`/create`, ia.createIncident)
|
||||
r.Post(`/`, ia.listIncidents)
|
||||
r.Post(`/{id:[a-f0-9-]+}/calls`, ia.postCalls)
|
||||
|
||||
r.Put(`/{id:[a-f0-9]+}`, ia.updateIncident)
|
||||
|
||||
|
@ -79,17 +85,12 @@ func (ia *incidentsAPI) getIncident(w http.ResponseWriter, r *http.Request) {
|
|||
ctx := r.Context()
|
||||
incs := incstore.FromCtx(ctx)
|
||||
|
||||
params := struct {
|
||||
ID uuid.UUID `param:"id"`
|
||||
}{}
|
||||
|
||||
err := decodeParams(¶ms, r)
|
||||
id, err := idOnlyParam(w, r)
|
||||
if err != nil {
|
||||
wErr(w, r, badRequest(err))
|
||||
return
|
||||
}
|
||||
|
||||
inc, err := incs.Incident(ctx, params.ID)
|
||||
inc, err := incs.Incident(ctx, id)
|
||||
if err != nil {
|
||||
wErr(w, r, autoError(err))
|
||||
return
|
||||
|
@ -102,13 +103,8 @@ func (ia *incidentsAPI) updateIncident(w http.ResponseWriter, r *http.Request) {
|
|||
ctx := r.Context()
|
||||
incs := incstore.FromCtx(ctx)
|
||||
|
||||
urlParams := struct {
|
||||
ID uuid.UUID `param:"id"`
|
||||
}{}
|
||||
|
||||
err := decodeParams(&urlParams, r)
|
||||
id, err := idOnlyParam(w, r)
|
||||
if err != nil {
|
||||
wErr(w, r, badRequest(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -119,7 +115,7 @@ func (ia *incidentsAPI) updateIncident(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
inc, err := incs.UpdateIncident(ctx, urlParams.ID, p)
|
||||
inc, err := incs.UpdateIncident(ctx, id, p)
|
||||
if err != nil {
|
||||
wErr(w, r, autoError(err))
|
||||
return
|
||||
|
@ -150,3 +146,87 @@ func (ia *incidentsAPI) deleteIncident(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
type CallIncidentParams struct {
|
||||
Add []uuid.UUID `json:"add"`
|
||||
Notes json.RawMessage `json:"notes"`
|
||||
|
||||
Remove []uuid.UUID `json:"remove"`
|
||||
}
|
||||
|
||||
func (ia *incidentsAPI) postCalls(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
incs := incstore.FromCtx(ctx)
|
||||
|
||||
id, err := idOnlyParam(w, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
p := CallIncidentParams{}
|
||||
err = forms.Unmarshal(r, &p, forms.WithTag("json"), forms.WithAcceptBlank(), forms.WithOmitEmpty())
|
||||
if err != nil {
|
||||
wErr(w, r, badRequest(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = incs.AddRemoveIncidentCalls(ctx, id, p.Add, p.Notes, p.Remove)
|
||||
if err != nil {
|
||||
wErr(w, r, autoError(err))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (ia *incidentsAPI) getCallsM3U(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
incs := incstore.FromCtx(ctx)
|
||||
tgst := tgstore.FromCtx(ctx)
|
||||
|
||||
id, err := idOnlyParam(w, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
inc, err := incs.Incident(ctx, id)
|
||||
if err != nil {
|
||||
wErr(w, r, autoError(err))
|
||||
return
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
callUrl := r.URL
|
||||
callUrl.RawQuery = ""
|
||||
callUrl.Fragment = ""
|
||||
|
||||
b.WriteString("#EXTM3U\n\n")
|
||||
for _, c := range inc.Calls {
|
||||
tg, err := tgst.TG(ctx, c.TalkgroupTuple())
|
||||
if err != nil {
|
||||
wErr(w, r, autoError(err))
|
||||
return
|
||||
}
|
||||
var from string
|
||||
if c.Source != 0 {
|
||||
from = fmt.Sprintf(" from %d", c.Source)
|
||||
}
|
||||
|
||||
callUrl.Path = "/api/call/%s" + c.ID.String()
|
||||
|
||||
fmt.Fprintf(w, "#EXTINF:%d,%s%s (%s)\n%s\n\n",
|
||||
c.Duration.Seconds(),
|
||||
tg.StringTag(true),
|
||||
from,
|
||||
c.DateTime.Format("15:04 01/02"),
|
||||
callUrl,
|
||||
)
|
||||
}
|
||||
|
||||
// Not a lot of agreement on which MIME type to use for non-HLS m3u,
|
||||
// let's hope this is good enough
|
||||
w.Header().Set("Content-Type", "audio/x-mpegurl")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = b.WriteTo(w)
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ func (s *Relay) Call(ctx context.Context, call *calls.Call) error {
|
|||
var buf bytes.Buffer
|
||||
body := multipart.NewWriter(&buf)
|
||||
|
||||
err := forms.Marshal(call, body)
|
||||
err := forms.Marshal(call, body, forms.WithTag("json"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("relay form parse: %w", err)
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ type CallUploadRequest struct {
|
|||
Key string `form:"key"`
|
||||
Patches []int `form:"patches"`
|
||||
Source int `form:"source"`
|
||||
Sources []int `form:"sources"`
|
||||
System int `form:"system"`
|
||||
SystemLabel string `form:"systemLabel"`
|
||||
Talkgroup int `form:"talkgroup"`
|
||||
|
|
|
@ -38,7 +38,22 @@ source
|
|||
);
|
||||
|
||||
-- name: GetCallAudioByID :one
|
||||
SELECT call_date, audio_name, audio_type, audio_blob FROM calls WHERE id = @id;
|
||||
SELECT
|
||||
c.call_date,
|
||||
c.audio_name,
|
||||
c.audio_type,
|
||||
c.audio_blob
|
||||
FROM calls c
|
||||
WHERE c.id = @id
|
||||
UNION
|
||||
SELECT
|
||||
sc.call_date,
|
||||
sc.audio_name,
|
||||
sc.audio_type,
|
||||
sc.audio_blob
|
||||
FROM swept_calls sc
|
||||
WHERE sc.id = @id
|
||||
;
|
||||
|
||||
-- name: SetCallTranscript :exec
|
||||
UPDATE calls SET transcript = $2 WHERE id = $1;
|
||||
|
|
|
@ -20,6 +20,15 @@ FROM inp
|
|||
JOIN calls c ON c.id = inp.id
|
||||
;
|
||||
|
||||
-- name: RemoveFromIncident :exec
|
||||
DELETE FROM incidents_calls ic
|
||||
WHERE ic.incident_id = @id AND ic.call_id = ANY(@call_ids::UUID[]);
|
||||
|
||||
-- name: UpdateCallIncidentNotes :exec
|
||||
UPDATE incidents_Calls
|
||||
SET notes = @notes
|
||||
WHERE incident_id = @incident_id AND call_id = @call_id;
|
||||
|
||||
-- name: CreateIncident :one
|
||||
INSERT INTO incidents (
|
||||
id,
|
||||
|
@ -73,13 +82,40 @@ CASE WHEN sqlc.narg('end')::TIMESTAMPTZ IS NOT NULL THEN
|
|||
i.start_time <= sqlc.narg('end') ELSE TRUE END
|
||||
;
|
||||
|
||||
-- name: IncidentCalls :many
|
||||
-- INCOMPLETE
|
||||
SELECT
|
||||
ic.incident_id, call_date,
|
||||
ic.call_id,
|
||||
ic.notes
|
||||
FROM incidents_calls ic;
|
||||
-- name: GetIncidentCalls :many
|
||||
SELECT ic.call_id, ic.call_date, ic.notes, c.*
|
||||
FROM incidents_calls ic, LATERAL (
|
||||
SELECT
|
||||
ca.submitter,
|
||||
ca.system,
|
||||
ca.talkgroup,
|
||||
ca.audio_name,
|
||||
ca.duration,
|
||||
ca.audio_type,
|
||||
ca.audio_url,
|
||||
ca.frequency,
|
||||
ca.frequencies,
|
||||
ca.patches,
|
||||
ca.source,
|
||||
ca.transcript
|
||||
FROM calls ca WHERE ca.id = ic.calls_tbl_id AND ca.call_date = ic.call_date
|
||||
UNION
|
||||
SELECT
|
||||
sc.submitter,
|
||||
sc.system,
|
||||
sc.talkgroup,
|
||||
sc.audio_name,
|
||||
sc.duration,
|
||||
sc.audio_type,
|
||||
sc.audio_url,
|
||||
sc.frequency,
|
||||
sc.frequencies,
|
||||
sc.patches,
|
||||
sc.source,
|
||||
sc.transcript
|
||||
FROM swept_calls sc WHERE sc.id = ic.swept_call_id
|
||||
) c
|
||||
WHERE ic.incident_id = @id;
|
||||
|
||||
-- name: GetIncident :one
|
||||
SELECT
|
||||
|
|
Loading…
Reference in a new issue