Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Ticket.opened_by and opened_in and set when opening tickets #641

Merged
merged 3 commits into from
Jul 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion core/handlers/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type TestCase struct {
Actions ContactActionMap
Msgs ContactMsgMap
Modifiers ContactModifierMap
ModifierUser *testdata.User
Assertions []Assertion
SQLAssertions []SQLAssertion
}
Expand Down Expand Up @@ -222,7 +223,7 @@ func RunTestCases(t *testing.T, ctx context.Context, rt *runtime.Runtime, tcs []
Events: make([]flows.Event, 0, len(mods)),
}

scene := models.NewSceneForContact(flowContact)
scene := models.NewSceneForContact(flowContact, tc.ModifierUser.SafeID())

// apply our modifiers
for _, mod := range mods {
Expand Down
11 changes: 11 additions & 0 deletions core/handlers/ticket_opened.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,20 @@ func handleTicketOpened(ctx context.Context, rt *runtime.Runtime, tx *sqlx.Tx, o
assigneeID = assignee.ID()
}

var openedInID models.FlowID
if scene.Session() != nil {
run, _ := scene.Session().FindStep(e.StepUUID())
flowAsset, _ := oa.FlowByUUID(run.FlowReference().UUID)
if flowAsset != nil {
openedInID = flowAsset.(*models.Flow).ID()
}
}

ticket := models.NewTicket(
event.Ticket.UUID,
oa.OrgID(),
scene.UserID(),
openedInID,
scene.ContactID(),
ticketer.ID(),
event.Ticket.ExternalID,
Expand Down
2 changes: 1 addition & 1 deletion core/handlers/ticket_opened_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestTicketOpened(t *testing.T) {
oa := testdata.Org1.Load(rt)

// an existing ticket
cathyTicket := models.NewTicket(flows.TicketUUID(uuids.New()), testdata.Org1.ID, testdata.Cathy.ID, testdata.Mailgun.ID, "748363", testdata.DefaultTopic.ID, "Who?", models.NilUserID, nil)
cathyTicket := models.NewTicket(flows.TicketUUID(uuids.New()), testdata.Org1.ID, testdata.Admin.ID, models.NilFlowID, testdata.Cathy.ID, testdata.Mailgun.ID, "748363", testdata.DefaultTopic.ID, "Who?", models.NilUserID, nil)
err := models.InsertTickets(ctx, db, oa, []*models.Ticket{cathyTicket})
require.NoError(t, err)

Expand Down
2 changes: 1 addition & 1 deletion core/models/contacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ func LoadContacts(ctx context.Context, db Queryer, oa *OrgAssets, ids []ContactI
for _, t := range e.Tickets {
ticketer := oa.TicketerByID(t.TicketerID)
if ticketer != nil {
tickets = append(tickets, NewTicket(t.UUID, oa.OrgID(), contact.ID(), ticketer.ID(), t.ExternalID, t.TopicID, t.Body, t.AssigneeID, nil))
tickets = append(tickets, NewTicket(t.UUID, oa.OrgID(), NilUserID, NilFlowID, contact.ID(), ticketer.ID(), t.ExternalID, t.TopicID, t.Body, t.AssigneeID, nil))
}
}
contact.tickets = tickets
Expand Down
27 changes: 15 additions & 12 deletions core/models/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,32 @@ import (
type Scene struct {
contact *flows.Contact
session *Session
userID UserID

preCommits map[EventCommitHook][]interface{}
postCommits map[EventCommitHook][]interface{}
}

// NewSceneForSession creates a new scene for the passed in session
func NewSceneForSession(session *Session) *Scene {
s := &Scene{
return &Scene{
contact: session.Contact(),
session: session,

preCommits: make(map[EventCommitHook][]interface{}),
postCommits: make(map[EventCommitHook][]interface{}),
}
return s
}

// NewSceneForContact creates a new scene for the passed in contact, session will be nil
func NewSceneForContact(contact *flows.Contact) *Scene {
s := &Scene{
func NewSceneForContact(contact *flows.Contact, userID UserID) *Scene {
return &Scene{
contact: contact,
userID: userID,

preCommits: make(map[EventCommitHook][]interface{}),
postCommits: make(map[EventCommitHook][]interface{}),
}
return s
}

// SessionID returns the session id for this scene if any
Expand All @@ -57,9 +57,10 @@ func (s *Scene) ContactID() ContactID { return ContactID(s.contact.ID(
func (s *Scene) ContactUUID() flows.ContactUUID { return s.contact.UUID() }

// Session returns the session for this scene if any
func (s *Scene) Session() *Session {
return s.session
}
func (s *Scene) Session() *Session { return s.session }

// User returns the user ID for this scene if any
func (s *Scene) UserID() UserID { return s.userID }

// AppendToEventPreCommitHook adds a new event to be handled by a pre commit hook
func (s *Scene) AppendToEventPreCommitHook(hook EventCommitHook, event interface{}) {
Expand Down Expand Up @@ -186,11 +187,11 @@ func ApplyEventPostCommitHooks(ctx context.Context, rt *runtime.Runtime, tx *sql
}

// HandleAndCommitEvents takes a set of contacts and events, handles the events and applies any hooks, and commits everything
func HandleAndCommitEvents(ctx context.Context, rt *runtime.Runtime, oa *OrgAssets, contactEvents map[*flows.Contact][]flows.Event) error {
func HandleAndCommitEvents(ctx context.Context, rt *runtime.Runtime, oa *OrgAssets, userID UserID, contactEvents map[*flows.Contact][]flows.Event) error {
// create scenes for each contact
scenes := make([]*Scene, 0, len(contactEvents))
for contact := range contactEvents {
scene := NewSceneForContact(contact)
scene := NewSceneForContact(contact, userID)
scenes = append(scenes, scene)
}

Expand Down Expand Up @@ -239,7 +240,9 @@ func HandleAndCommitEvents(ctx context.Context, rt *runtime.Runtime, oa *OrgAsse
}

// ApplyModifiers modifies contacts by applying modifiers and handling the resultant events
func ApplyModifiers(ctx context.Context, rt *runtime.Runtime, oa *OrgAssets, modifiersByContact map[*flows.Contact][]flows.Modifier) (map[*flows.Contact][]flows.Event, error) {
// Note that we don't load the user object from org assets because it's possible that the user isn't part
// of the org, e.g. customer support.
func ApplyModifiers(ctx context.Context, rt *runtime.Runtime, oa *OrgAssets, userID UserID, modifiersByContact map[*flows.Contact][]flows.Modifier) (map[*flows.Contact][]flows.Event, error) {
// create an environment instance with location support
env := flows.NewEnvironment(oa.Env(), oa.SessionAssets().Locations())

Expand All @@ -256,7 +259,7 @@ func ApplyModifiers(ctx context.Context, rt *runtime.Runtime, oa *OrgAssets, mod
eventsByContact[contact] = events
}

err := HandleAndCommitEvents(ctx, rt, oa, eventsByContact)
err := HandleAndCommitEvents(ctx, rt, oa, userID, eventsByContact)
if err != nil {
return nil, errors.Wrap(err, "error commiting events")
}
Expand Down
3 changes: 2 additions & 1 deletion core/models/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ func (b *ContactImportBatch) tryImport(ctx context.Context, rt *runtime.Runtime,
}

// and apply in bulk
_, err = ApplyModifiers(ctx, rt, oa, modifiersByContact)
// TODO pass user here who created the import?
_, err = ApplyModifiers(ctx, rt, oa, NilUserID, modifiersByContact)
if err != nil {
return errors.Wrap(err, "error applying modifiers")
}
Expand Down
152 changes: 79 additions & 73 deletions core/models/tickets.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ type Ticket struct {
AssigneeID UserID `db:"assignee_id"`
Config null.Map `db:"config"`
OpenedOn time.Time `db:"opened_on"`
OpenedByID UserID `db:"opened_by_id"`
OpenedInID FlowID `db:"opened_in_id"`
RepliedOn *time.Time `db:"replied_on"`
ModifiedOn time.Time `db:"modified_on"`
ClosedOn *time.Time `db:"closed_on"`
Expand All @@ -99,10 +101,12 @@ type Ticket struct {
}

// NewTicket creates a new open ticket
func NewTicket(uuid flows.TicketUUID, orgID OrgID, contactID ContactID, ticketerID TicketerID, externalID string, topicID TopicID, body string, assigneeID UserID, config map[string]interface{}) *Ticket {
func NewTicket(uuid flows.TicketUUID, orgID OrgID, userID UserID, flowID FlowID, contactID ContactID, ticketerID TicketerID, externalID string, topicID TopicID, body string, assigneeID UserID, config map[string]interface{}) *Ticket {
t := &Ticket{}
t.t.UUID = uuid
t.t.OrgID = orgID
t.t.OpenedByID = userID
t.t.OpenedInID = flowID
t.t.ContactID = contactID
t.t.TicketerID = ticketerID
t.t.ExternalID = null.String(externalID)
Expand Down Expand Up @@ -184,28 +188,28 @@ func (t *Ticket) ForwardIncoming(ctx context.Context, rt *runtime.Runtime, oa *O

const sqlSelectOpenTickets = `
SELECT
t.id AS id,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all this aliasing isn't needed

t.uuid AS uuid,
t.org_id AS org_id,
t.contact_id AS contact_id,
t.ticketer_id AS ticketer_id,
t.external_id AS external_id,
t.status AS status,
t.topic_id AS topic_id,
t.body AS body,
t.assignee_id AS assignee_id,
t.config AS config,
t.opened_on AS opened_on,
t.id,
t.uuid,
t.org_id,
t.contact_id,
t.ticketer_id,
t.external_id,
t.status,
t.topic_id,
t.body,
t.assignee_id,
t.config,
t.opened_on,
t.opened_by_id,
t.opened_in_id,
t.replied_on,
t.modified_on AS modified_on,
t.closed_on AS closed_on,
t.last_activity_on AS last_activity_on
t.modified_on,
t.closed_on,
t.last_activity_on
FROM
tickets_ticket t
WHERE
t.contact_id = $1 AND
t.status = 'O'
`
t.contact_id = $1 AND t.status = 'O'`

// LoadOpenTicketsForContact looks up the open tickets for the passed in contact
func LoadOpenTicketsForContact(ctx context.Context, db Queryer, contact *Contact) ([]*Ticket, error) {
Expand All @@ -214,27 +218,28 @@ func LoadOpenTicketsForContact(ctx context.Context, db Queryer, contact *Contact

const sqlSelectTicketsByID = `
SELECT
t.id AS id,
t.uuid AS uuid,
t.org_id AS org_id,
t.contact_id AS contact_id,
t.ticketer_id AS ticketer_id,
t.external_id AS external_id,
t.status AS status,
t.topic_id AS topic_id,
t.body AS body,
t.assignee_id AS assignee_id,
t.config AS config,
t.opened_on AS opened_on,
t.id,
t.uuid,
t.org_id,
t.contact_id,
t.ticketer_id,
t.external_id,
t.status,
t.topic_id,
t.body,
t.assignee_id,
t.config,
t.opened_on,
t.opened_by_id,
t.opened_in_id,
t.replied_on,
t.modified_on AS modified_on,
t.closed_on AS closed_on,
t.last_activity_on AS last_activity_on
t.modified_on,
t.closed_on,
t.last_activity_on
FROM
tickets_ticket t
WHERE
t.id = ANY($1)
`
t.id = ANY($1)`

// LoadTickets loads all of the tickets with the given ids
func LoadTickets(ctx context.Context, db Queryer, ids []TicketID) ([]*Ticket, error) {
Expand Down Expand Up @@ -263,27 +268,28 @@ func loadTickets(ctx context.Context, db Queryer, query string, params ...interf

const sqlSelectTicketByUUID = `
SELECT
t.id AS id,
t.uuid AS uuid,
t.org_id AS org_id,
t.contact_id AS contact_id,
t.ticketer_id AS ticketer_id,
t.external_id AS external_id,
t.status AS status,
t.topic_id AS topic_id,
t.body AS body,
t.assignee_id AS assignee_id,
t.config AS config,
t.opened_on AS opened_on,
t.id,
t.uuid,
t.org_id,
t.contact_id,
t.ticketer_id,
t.external_id,
t.status,
t.topic_id,
t.body,
t.assignee_id,
t.config,
t.opened_on,
t.opened_by_id,
t.opened_in_id,
t.replied_on,
t.modified_on AS modified_on,
t.closed_on AS closed_on,
t.last_activity_on AS last_activity_on
t.modified_on,
t.closed_on,
t.last_activity_on
FROM
tickets_ticket t
WHERE
t.uuid = $1
`
t.uuid = $1`

// LookupTicketByUUID looks up the ticket with the passed in UUID
func LookupTicketByUUID(ctx context.Context, db *sqlx.DB, uuid flows.TicketUUID) (*Ticket, error) {
Expand All @@ -292,28 +298,28 @@ func LookupTicketByUUID(ctx context.Context, db *sqlx.DB, uuid flows.TicketUUID)

const sqlSelectTicketByExternalID = `
SELECT
t.id AS id,
t.uuid AS uuid,
t.org_id AS org_id,
t.contact_id AS contact_id,
t.ticketer_id AS ticketer_id,
t.external_id AS external_id,
t.status AS status,
t.topic_id AS topic_id,
t.body AS body,
t.assignee_id AS assignee_id,
t.config AS config,
t.opened_on AS opened_on,
t.id,
t.uuid,
t.org_id,
t.contact_id,
t.ticketer_id,
t.external_id,
t.status,
t.topic_id,
t.body,
t.assignee_id,
t.config,
t.opened_on,
t.opened_by_id,
t.opened_in_id,
t.replied_on,
t.modified_on AS modified_on,
t.closed_on AS closed_on,
t.last_activity_on AS last_activity_on
t.modified_on,
t.closed_on,
t.last_activity_on
FROM
tickets_ticket t
WHERE
t.ticketer_id = $1 AND
t.external_id = $2
`
t.ticketer_id = $1 AND t.external_id = $2`

// LookupTicketByExternalID looks up the ticket with the passed in ticketer and external ID
func LookupTicketByExternalID(ctx context.Context, db Queryer, ticketerID TicketerID, externalID string) (*Ticket, error) {
Expand Down Expand Up @@ -342,8 +348,8 @@ func lookupTicket(ctx context.Context, db Queryer, query string, params ...inter

const sqlInsertTicket = `
INSERT INTO
tickets_ticket(uuid, org_id, contact_id, ticketer_id, external_id, status, topic_id, body, assignee_id, config, opened_on, modified_on, last_activity_on)
VALUES( :uuid, :org_id, :contact_id, :ticketer_id, :external_id, :status, :topic_id, :body, :assignee_id, :config, NOW(), NOW() , NOW())
tickets_ticket(uuid, org_id, contact_id, ticketer_id, external_id, status, topic_id, body, assignee_id, config, opened_on, opened_by_id, opened_in_id, modified_on, last_activity_on)
VALUES( :uuid, :org_id, :contact_id, :ticketer_id, :external_id, :status, :topic_id, :body, :assignee_id, :config, NOW(), :opened_by_id, :opened_in_id, NOW() , NOW())
RETURNING
id
`
Expand Down
6 changes: 6 additions & 0 deletions core/models/tickets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ func TestTickets(t *testing.T) {
ticket1 := models.NewTicket(
"2ef57efc-d85f-4291-b330-e4afe68af5fe",
testdata.Org1.ID,
testdata.Admin.ID,
models.NilFlowID,
testdata.Cathy.ID,
testdata.Mailgun.ID,
"EX12345",
Expand All @@ -82,6 +84,8 @@ func TestTickets(t *testing.T) {
ticket2 := models.NewTicket(
"64f81be1-00ff-48ef-9e51-97d6f924c1a4",
testdata.Org1.ID,
testdata.Admin.ID,
models.NilFlowID,
testdata.Bob.ID,
testdata.Zendesk.ID,
"EX7869",
Expand All @@ -93,6 +97,8 @@ func TestTickets(t *testing.T) {
ticket3 := models.NewTicket(
"28ef8ddc-b221-42f3-aeae-ee406fc9d716",
testdata.Org1.ID,
models.NilUserID,
testdata.Favorites.ID,
testdata.Alexandria.ID,
testdata.Zendesk.ID,
"EX6677",
Expand Down
Loading