From ad19d5dd7a894bada1df9be941bc10491f62c68d Mon Sep 17 00:00:00 2001 From: Rowan Seymour Date: Tue, 6 Aug 2024 15:34:02 -0500 Subject: [PATCH] Implement opening ticket with note as two events --- flows/actions/base_test.go | 2 +- flows/actions/open_ticket.go | 5 +- flows/actions/testdata/open_ticket.json | 57 +++++++++++++------ flows/contact_test.go | 2 +- flows/events/base_test.go | 13 ++++- flows/events/ticket_note_added.go | 35 ++++++++++++ flows/events/ticket_opened.go | 5 +- flows/modifiers/testdata/ticket.json | 11 ++-- flows/modifiers/ticket.go | 5 +- flows/tickets.go | 13 ++--- flows/tickets_test.go | 10 +--- flows/triggers/base_test.go | 2 +- .../TestTriggerMarshaling_ticket_closed.snap | 3 +- test/testdata/runner/ticketing.test.json | 33 +++++++---- 14 files changed, 132 insertions(+), 64 deletions(-) create mode 100644 flows/events/ticket_note_added.go diff --git a/flows/actions/base_test.go b/flows/actions/base_test.go index 36b926f19..14d777a4b 100644 --- a/flows/actions/base_test.go +++ b/flows/actions/base_test.go @@ -172,7 +172,7 @@ func testActionType(t *testing.T, assetsJSON json.RawMessage, typeName string) { if tc.HasTicket { topic := sa.Topics().Get("0d9a2c56-6fc2-4f27-93c5-a6322e26b740") - contact.SetTicket(flows.NewTicket("7f44b065-ec28-4d7a-bbb4-0bda3b75b19d", topic, nil, "Help")) + contact.SetTicket(flows.NewTicket("7f44b065-ec28-4d7a-bbb4-0bda3b75b19d", topic, nil)) } // and switch their language diff --git a/flows/actions/open_ticket.go b/flows/actions/open_ticket.go index 73ef6f366..ecba7289d 100644 --- a/flows/actions/open_ticket.go +++ b/flows/actions/open_ticket.go @@ -1,6 +1,8 @@ package actions import ( + "strings" + "github.com/nyaruka/goflow/assets" "github.com/nyaruka/goflow/flows" "github.com/nyaruka/goflow/flows/events" @@ -34,7 +36,7 @@ type OpenTicketAction struct { onlineAction Topic *assets.TopicReference `json:"topic" validate:"omitempty"` - Body string `json:"body" engine:"evaluated"` + Body string `json:"body" engine:"evaluated"` // TODO will become "note" in future migration Assignee *assets.UserReference `json:"assignee" validate:"omitempty"` ResultName string `json:"result_name" validate:"required"` } @@ -68,6 +70,7 @@ func (a *OpenTicketAction) Execute(run flows.Run, step flows.Step, logModifier f } evaluatedNote, _ := run.EvaluateTemplate(a.Body, logEvent) + evaluatedNote = strings.TrimSpace(evaluatedNote) ticket := a.open(run, topic, assignee, evaluatedNote, logModifier, logEvent) if ticket != nil { diff --git a/flows/actions/testdata/open_ticket.json b/flows/actions/testdata/open_ticket.json index 1ad420c10..f694fac20 100644 --- a/flows/actions/testdata/open_ticket.json +++ b/flows/actions/testdata/open_ticket.json @@ -119,10 +119,15 @@ "assignee": { "email": "bob@nyaruka.com", "name": "Bob" - }, - "note": "Last message: Hi everybody" + } } }, + { + "type": "ticket_note_added", + "created_on": "2018-10-18T14:20:30.000123456Z", + "step_uuid": "59d74b86-3e2f-4a93-aece-b05d2fdcde0c", + "note": "Last message: Hi everybody" + }, { "type": "contact_groups_changed", "created_on": "2018-10-18T14:20:30.000123456Z", @@ -183,8 +188,7 @@ "assignee": { "email": "bob@nyaruka.com", "name": "Bob" - }, - "note": "Last message: Hi everybody" + } } }, "templates": [ @@ -229,10 +233,15 @@ "topic": { "uuid": "0d9a2c56-6fc2-4f27-93c5-a6322e26b740", "name": "General" - }, - "note": "Last message: Hi everybody" + } } }, + { + "type": "ticket_note_added", + "created_on": "2018-10-18T14:20:30.000123456Z", + "step_uuid": "59d74b86-3e2f-4a93-aece-b05d2fdcde0c", + "note": "Last message: Hi everybody" + }, { "type": "contact_groups_changed", "created_on": "2018-10-18T14:20:30.000123456Z", @@ -289,8 +298,7 @@ "topic": { "uuid": "0d9a2c56-6fc2-4f27-93c5-a6322e26b740", "name": "General" - }, - "note": "Last message: Hi everybody" + } } }, "templates": [ @@ -333,10 +341,15 @@ "assignee": { "email": "jim@nyaruka.com", "name": "Jim" - }, - "note": "Last message: Hi everybody" + } } }, + { + "type": "ticket_note_added", + "created_on": "2018-10-18T14:20:30.000123456Z", + "step_uuid": "59d74b86-3e2f-4a93-aece-b05d2fdcde0c", + "note": "Last message: Hi everybody" + }, { "type": "contact_groups_changed", "created_on": "2018-10-18T14:20:30.000123456Z", @@ -397,8 +410,7 @@ "assignee": { "email": "jim@nyaruka.com", "name": "Jim" - }, - "note": "Last message: Hi everybody" + } } }, "templates": [ @@ -450,10 +462,15 @@ "topic": { "uuid": "472a7a73-96cb-4736-b567-056d987cc5b4", "name": "Weather" - }, - "note": "Last message: Hi everybody" + } } }, + { + "type": "ticket_note_added", + "created_on": "2018-10-18T14:20:30.000123456Z", + "step_uuid": "59d74b86-3e2f-4a93-aece-b05d2fdcde0c", + "note": "Last message: Hi everybody" + }, { "type": "contact_groups_changed", "created_on": "2018-10-18T14:20:30.000123456Z", @@ -510,8 +527,7 @@ "topic": { "uuid": "472a7a73-96cb-4736-b567-056d987cc5b4", "name": "Weather" - }, - "note": "Last message: Hi everybody" + } } }, "templates": [ @@ -558,10 +574,15 @@ "topic": { "uuid": "0d9a2c56-6fc2-4f27-93c5-a6322e26b740", "name": "General" - }, - "note": "Where are my cookies? " + } } }, + { + "type": "ticket_note_added", + "created_on": "2018-10-18T14:20:30.000123456Z", + "step_uuid": "59d74b86-3e2f-4a93-aece-b05d2fdcde0c", + "note": "Where are my cookies? " + }, { "type": "contact_groups_changed", "created_on": "2018-10-18T14:20:30.000123456Z", diff --git a/flows/contact_test.go b/flows/contact_test.go index 3b1b234e3..39d0ed81a 100644 --- a/flows/contact_test.go +++ b/flows/contact_test.go @@ -139,7 +139,7 @@ func TestContact(t *testing.T) { assert.Nil(t, contact.Ticket()) weather := sa.Topics().Get("472a7a73-96cb-4736-b567-056d987cc5b4") - ticket := flows.OpenTicket(weather, nil, "spam?") + ticket := flows.OpenTicket(weather, nil) contact.SetTicket(ticket) assert.NotNil(t, contact.Ticket()) diff --git a/flows/events/base_test.go b/flows/events/base_test.go index 2e7b756ce..1f2d3d44c 100644 --- a/flows/events/base_test.go +++ b/flows/events/base_test.go @@ -48,7 +48,7 @@ func TestEventMarshaling(t *testing.T) { weather := session.Assets().Topics().Get("472a7a73-96cb-4736-b567-056d987cc5b4") user := session.Assets().Users().Get("bob@nyaruka.com") facebook := session.Assets().Channels().Get("4bb288a0-7fca-4da1-abe8-59a593aff648") - ticket := flows.NewTicket("7481888c-07dd-47dc-bf22-ef7448696ffe", weather, user, "this is weird") + ticket := flows.NewTicket("7481888c-07dd-47dc-bf22-ef7448696ffe", weather, user) eventTests := []struct { event flows.Event @@ -610,6 +610,14 @@ func TestEventMarshaling(t *testing.T) { } }`, }, + { + events.NewTicketNoteAdded("this is weird"), + `{ + "type": "ticket_note_added", + "created_on": "2018-10-18T14:20:30.000123456Z", + "note": "this is weird" + }`, + }, { events.NewTicketOpened(ticket), `{ @@ -624,8 +632,7 @@ func TestEventMarshaling(t *testing.T) { "assignee": { "email": "bob@nyaruka.com", "name": "Bob" - }, - "note": "this is weird" + } } }`, }, diff --git a/flows/events/ticket_note_added.go b/flows/events/ticket_note_added.go new file mode 100644 index 000000000..7dad5eceb --- /dev/null +++ b/flows/events/ticket_note_added.go @@ -0,0 +1,35 @@ +package events + +import ( + "github.com/nyaruka/goflow/flows" +) + +func init() { + registerType(TypeTicketNoteAdded, func() flows.Event { return &TicketNoteAddedEvent{} }) +} + +// TypeTicketNoteAdded is the type for our ticket note added events +const TypeTicketNoteAdded string = "ticket_note_added" + +// TicketNoteAddedEvent events are created when a note is added to the currently open ticket. +// +// { +// "type": "ticket_note_added", +// "created_on": "2006-01-02T15:04:05Z", +// "note": "this is weird" +// } +// +// @event ticket_note_added +type TicketNoteAddedEvent struct { + BaseEvent + + Note string `json:"note"` +} + +// NewTicketNoteAdded returns a new ticket note added event +func NewTicketNoteAdded(note string) *TicketNoteAddedEvent { + return &TicketNoteAddedEvent{ + BaseEvent: NewBaseEvent(TypeTicketNoteAdded), + Note: note, + } +} diff --git a/flows/events/ticket_opened.go b/flows/events/ticket_opened.go index 8e6a6185b..3e87ebd34 100644 --- a/flows/events/ticket_opened.go +++ b/flows/events/ticket_opened.go @@ -16,7 +16,6 @@ type Ticket struct { UUID flows.TicketUUID `json:"uuid" validate:"required,uuid4"` Topic *assets.TopicReference `json:"topic" validate:"omitempty"` Assignee *assets.UserReference `json:"assignee,omitempty" validate:"omitempty"` - Note string `json:"note,omitempty"` } // TicketOpenedEvent events are created when a new ticket is opened. @@ -30,8 +29,7 @@ type Ticket struct { // "uuid": "add17edf-0b6e-4311-bcd7-a64b2a459157", // "name": "Weather" // }, -// "assignee": {"email": "bob@nyaruka.com", "name": "Bob"}, -// "note": "this is weird" +// "assignee": {"email": "bob@nyaruka.com", "name": "Bob"} // } // } // @@ -50,7 +48,6 @@ func NewTicketOpened(ticket *flows.Ticket) *TicketOpenedEvent { UUID: ticket.UUID(), Topic: ticket.Topic().Reference(), Assignee: ticket.Assignee().Reference(), - Note: ticket.Note(), }, } } diff --git a/flows/modifiers/testdata/ticket.json b/flows/modifiers/testdata/ticket.json index 9a9d53e55..89a4916b8 100644 --- a/flows/modifiers/testdata/ticket.json +++ b/flows/modifiers/testdata/ticket.json @@ -35,8 +35,7 @@ "assignee": { "email": "bob@nyaruka.com", "name": "Bob" - }, - "note": "this is a note" + } } }, "events": [ @@ -52,9 +51,13 @@ "assignee": { "email": "bob@nyaruka.com", "name": "Bob" - }, - "note": "this is a note" + } } + }, + { + "type": "ticket_note_added", + "created_on": "2018-10-18T14:20:30.000123456Z", + "note": "this is a note" } ] }, diff --git a/flows/modifiers/ticket.go b/flows/modifiers/ticket.go index 3699916d0..be8aa5da0 100644 --- a/flows/modifiers/ticket.go +++ b/flows/modifiers/ticket.go @@ -44,8 +44,11 @@ func (m *TicketModifier) Apply(eng flows.Engine, env envs.Environment, sa flows. return false } - ticket := flows.OpenTicket(m.topic, m.assignee, m.note) + ticket := flows.OpenTicket(m.topic, m.assignee) log(events.NewTicketOpened(ticket)) + if m.note != "" { + log(events.NewTicketNoteAdded(m.note)) + } contact.SetTicket(ticket) return true diff --git a/flows/tickets.go b/flows/tickets.go index f0cc9d8d5..ba6ee8af2 100644 --- a/flows/tickets.go +++ b/flows/tickets.go @@ -17,28 +17,25 @@ type Ticket struct { uuid TicketUUID topic *Topic assignee *User - note string } // NewTicket creates a new ticket -func NewTicket(uuid TicketUUID, topic *Topic, assignee *User, note string) *Ticket { +func NewTicket(uuid TicketUUID, topic *Topic, assignee *User) *Ticket { return &Ticket{ uuid: uuid, topic: topic, assignee: assignee, - note: note, } } // OpenTicket creates a new ticket. Used by ticketing services to open a new ticket. -func OpenTicket(topic *Topic, assignee *User, note string) *Ticket { - return NewTicket(TicketUUID(uuids.NewV4()), topic, assignee, note) +func OpenTicket(topic *Topic, assignee *User) *Ticket { + return NewTicket(TicketUUID(uuids.NewV4()), topic, assignee) } func (t *Ticket) UUID() TicketUUID { return t.uuid } func (t *Ticket) Topic() *Topic { return t.topic } func (t *Ticket) Assignee() *User { return t.assignee } -func (t *Ticket) Note() string { return t.note } // Context returns the properties available in expressions // @@ -63,7 +60,6 @@ type ticketEnvelope struct { UUID TicketUUID `json:"uuid" validate:"required,uuid4"` Topic *assets.TopicReference `json:"topic" validate:"omitempty"` Assignee *assets.UserReference `json:"assignee,omitempty" validate:"omitempty"` - Note string `json:"note,omitempty"` } // ReadTicket decodes a contact from the passed in JSON. If the topic or assigned user can't @@ -91,7 +87,7 @@ func ReadTicket(sa SessionAssets, data []byte, missing assets.MissingCallback) ( } } - return &Ticket{uuid: e.UUID, topic: topic, assignee: assignee, note: e.Note}, nil + return &Ticket{uuid: e.UUID, topic: topic, assignee: assignee}, nil } // MarshalJSON marshals this ticket into JSON @@ -110,6 +106,5 @@ func (t *Ticket) MarshalJSON() ([]byte, error) { UUID: t.uuid, Topic: topicRef, Assignee: assigneeRef, - Note: t.note, }) } diff --git a/flows/tickets_test.go b/flows/tickets_test.go index 974871c57..26072fd6b 100644 --- a/flows/tickets_test.go +++ b/flows/tickets_test.go @@ -68,15 +68,13 @@ func TestTickets(t *testing.T) { ticket1, err := flows.ReadTicket(sa, []byte(`{ "uuid": "349c851f-3f8e-4353-8bf2-8e90b6d73530", "topic": {"uuid": "fd3ffcf3-c609-423e-b40f-f7f291a91cc6", "name": "Deleted"}, - "assignee": {"email": "dave@nyaruka.com", "name": "Dave"}, - "note": "this is weird" + "assignee": {"email": "dave@nyaruka.com", "name": "Dave"} }`), missing) require.NoError(t, err) assert.Equal(t, flows.TicketUUID("349c851f-3f8e-4353-8bf2-8e90b6d73530"), ticket1.UUID()) assert.Nil(t, ticket1.Topic()) assert.Nil(t, ticket1.Assignee()) - assert.Equal(t, "this is weird", ticket1.Note()) // check that missing topic and assignee are logged as a missing dependencies assert.Equal(t, 2, len(missingRefs)) @@ -88,18 +86,16 @@ func TestTickets(t *testing.T) { ticket2, err := flows.ReadTicket(sa, []byte(`{ "uuid": "5a4af021-d2c2-47fc-9abc-abbb8635d8c0", "topic": {"uuid": "472a7a73-96cb-4736-b567-056d987cc5b4", "name": "Weather"}, - "assignee": {"email": "bob@nyaruka.com", "name": "Bob"}, - "note": "this is weird" + "assignee": {"email": "bob@nyaruka.com", "name": "Bob"} }`), missing) require.NoError(t, err) assert.Equal(t, 0, len(missingRefs)) assert.Equal(t, "Bob", ticket2.Assignee().Name()) - ticket3 := flows.OpenTicket(weather, bob, "spam?") + ticket3 := flows.OpenTicket(weather, bob) assert.Equal(t, flows.TicketUUID("1ae96956-4b34-433e-8d1a-f05fe6923d6d"), ticket3.UUID()) assert.Equal(t, weather, ticket3.Topic()) assert.Equal(t, "Bob", ticket2.Assignee().Name()) - assert.Equal(t, ticket3.Note(), "spam?") } diff --git a/flows/triggers/base_test.go b/flows/triggers/base_test.go index 33a4e0f42..a5ba4daad 100644 --- a/flows/triggers/base_test.go +++ b/flows/triggers/base_test.go @@ -184,7 +184,7 @@ func TestTriggerMarshaling(t *testing.T) { jotd := sa.OptIns().Get("248be71d-78e9-4d71-a6c4-9981d369e5cb") weather := sa.Topics().Get("472a7a73-96cb-4736-b567-056d987cc5b4") user := sa.Users().Get("bob@nyaruka.com") - ticket := flows.NewTicket("276c2e43-d6f9-4c36-8e54-b5af5039acf6", weather, user, "this is weird") + ticket := flows.NewTicket("276c2e43-d6f9-4c36-8e54-b5af5039acf6", weather, user) contact := flows.NewEmptyContact(sa, "Bob", i18n.Language("eng"), nil) contact.AddURN(urns.URN("tel:+12065551212"), nil) diff --git a/flows/triggers/testdata/TestTriggerMarshaling_ticket_closed.snap b/flows/triggers/testdata/TestTriggerMarshaling_ticket_closed.snap index 71a53f577..c5d1fa818 100644 --- a/flows/triggers/testdata/TestTriggerMarshaling_ticket_closed.snap +++ b/flows/triggers/testdata/TestTriggerMarshaling_ticket_closed.snap @@ -34,8 +34,7 @@ "assignee": { "email": "bob@nyaruka.com", "name": "Bob McTickets" - }, - "note": "this is weird" + } } } } \ No newline at end of file diff --git a/test/testdata/runner/ticketing.test.json b/test/testdata/runner/ticketing.test.json index e9078661d..a53baff64 100644 --- a/test/testdata/runner/ticketing.test.json +++ b/test/testdata/runner/ticketing.test.json @@ -163,7 +163,6 @@ "created_on": "2018-07-06T12:30:18.123456789Z", "step_uuid": "970b8069-50f5-4f6f-8f41-6b2d9f33d623", "ticket": { - "note": "Last message: Rats", "topic": { "name": "Weather", "uuid": "472a7a73-96cb-4736-b567-056d987cc5b4" @@ -172,9 +171,15 @@ }, "type": "ticket_opened" }, + { + "created_on": "2018-07-06T12:30:20.123456789Z", + "note": "Last message: Rats", + "step_uuid": "970b8069-50f5-4f6f-8f41-6b2d9f33d623", + "type": "ticket_note_added" + }, { "category": "Success", - "created_on": "2018-07-06T12:30:22.123456789Z", + "created_on": "2018-07-06T12:30:24.123456789Z", "name": "Ticket", "step_uuid": "970b8069-50f5-4f6f-8f41-6b2d9f33d623", "type": "run_result_changed", @@ -182,7 +187,7 @@ }, { "body": "[{\"assignee\":null,\"topic\":{\"name\":\"Weather\",\"uuid\":\"472a7a73-96cb-4736-b567-056d987cc5b4\"},\"uuid\":\"5ecda5fc-951c-437b-a17e-f85e49829fb9\"}]", - "created_on": "2018-07-06T12:30:26.123456789Z", + "created_on": "2018-07-06T12:30:28.123456789Z", "step_uuid": "312d3af0-a565-4c96-ba00-bd7f0d08e671", "subject": "New ticket: 5ecda5fc-951c-437b-a17e-f85e49829fb9", "to": [ @@ -206,7 +211,7 @@ "flow_uuid": "3486fc59-d417-4189-93cd-e0aa8e3112ac", "node_uuid": "145eb3d3-b841-4e66-abac-297ae525c7ad", "operand": "5ecda5fc-951c-437b-a17e-f85e49829fb9", - "time": "2018-07-06T12:30:24.123456789Z" + "time": "2018-07-06T12:30:26.123456789Z" } ], "session": { @@ -218,7 +223,6 @@ "name": "Ben Haggerty", "status": "active", "ticket": { - "note": "Last message: Rats", "topic": { "name": "Weather", "uuid": "472a7a73-96cb-4736-b567-056d987cc5b4" @@ -295,7 +299,6 @@ "created_on": "2018-07-06T12:30:18.123456789Z", "step_uuid": "970b8069-50f5-4f6f-8f41-6b2d9f33d623", "ticket": { - "note": "Last message: Rats", "topic": { "name": "Weather", "uuid": "472a7a73-96cb-4736-b567-056d987cc5b4" @@ -304,9 +307,15 @@ }, "type": "ticket_opened" }, + { + "created_on": "2018-07-06T12:30:20.123456789Z", + "note": "Last message: Rats", + "step_uuid": "970b8069-50f5-4f6f-8f41-6b2d9f33d623", + "type": "ticket_note_added" + }, { "category": "Success", - "created_on": "2018-07-06T12:30:22.123456789Z", + "created_on": "2018-07-06T12:30:24.123456789Z", "name": "Ticket", "step_uuid": "970b8069-50f5-4f6f-8f41-6b2d9f33d623", "type": "run_result_changed", @@ -314,7 +323,7 @@ }, { "body": "[{\"assignee\":null,\"topic\":{\"name\":\"Weather\",\"uuid\":\"472a7a73-96cb-4736-b567-056d987cc5b4\"},\"uuid\":\"5ecda5fc-951c-437b-a17e-f85e49829fb9\"}]", - "created_on": "2018-07-06T12:30:26.123456789Z", + "created_on": "2018-07-06T12:30:28.123456789Z", "step_uuid": "312d3af0-a565-4c96-ba00-bd7f0d08e671", "subject": "New ticket: 5ecda5fc-951c-437b-a17e-f85e49829fb9", "to": [ @@ -323,12 +332,12 @@ "type": "email_sent" } ], - "exited_on": "2018-07-06T12:30:28.123456789Z", + "exited_on": "2018-07-06T12:30:30.123456789Z", "flow": { "name": "Support", "uuid": "3486fc59-d417-4189-93cd-e0aa8e3112ac" }, - "modified_on": "2018-07-06T12:30:28.123456789Z", + "modified_on": "2018-07-06T12:30:30.123456789Z", "path": [ { "arrived_on": "2018-07-06T12:30:01.123456789Z", @@ -349,7 +358,7 @@ "uuid": "970b8069-50f5-4f6f-8f41-6b2d9f33d623" }, { - "arrived_on": "2018-07-06T12:30:25.123456789Z", + "arrived_on": "2018-07-06T12:30:27.123456789Z", "exit_uuid": "b6562dea-d21c-4a99-b904-0fb9583fb5ab", "node_uuid": "ac3fcd8e-e7bb-4545-865d-39424a8f1d7b", "uuid": "312d3af0-a565-4c96-ba00-bd7f0d08e671" @@ -366,7 +375,7 @@ }, "ticket": { "category": "Success", - "created_on": "2018-07-06T12:30:20.123456789Z", + "created_on": "2018-07-06T12:30:22.123456789Z", "name": "Ticket", "node_uuid": "145eb3d3-b841-4e66-abac-297ae525c7ad", "value": "5ecda5fc-951c-437b-a17e-f85e49829fb9"