Skip to content

Commit

Permalink
Remove ticketers
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanseymour committed Oct 17, 2023
1 parent d0e8358 commit 728f681
Show file tree
Hide file tree
Showing 59 changed files with 93 additions and 4,636 deletions.
3 changes: 0 additions & 3 deletions cmd/mailroom/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ import (
_ "github.com/nyaruka/mailroom/core/tasks/timeouts"
_ "github.com/nyaruka/mailroom/services/ivr/twiml"
_ "github.com/nyaruka/mailroom/services/ivr/vonage"
_ "github.com/nyaruka/mailroom/services/tickets/intern"
_ "github.com/nyaruka/mailroom/services/tickets/mailgun"
_ "github.com/nyaruka/mailroom/services/tickets/zendesk"
_ "github.com/nyaruka/mailroom/web/contact"
_ "github.com/nyaruka/mailroom/web/docs"
_ "github.com/nyaruka/mailroom/web/flow"
Expand Down
22 changes: 0 additions & 22 deletions core/goflow/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"sync"

"github.com/nyaruka/gocommon/urns"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/flows"
"github.com/nyaruka/goflow/flows/engine"
"github.com/nyaruka/goflow/services/webhooks"
Expand All @@ -17,7 +16,6 @@ var engInit, simulatorInit sync.Once

var emailFactory func(*runtime.Config) engine.EmailServiceFactory
var classificationFactory func(*runtime.Config) engine.ClassificationServiceFactory
var ticketFactory func(*runtime.Config) engine.TicketServiceFactory
var airtimeFactory func(*runtime.Config) engine.AirtimeServiceFactory

// RegisterEmailServiceFactory can be used by outside callers to register a email factory
Expand All @@ -32,12 +30,6 @@ func RegisterClassificationServiceFactory(f func(*runtime.Config) engine.Classif
classificationFactory = f
}

// RegisterTicketServiceFactory can be used by outside callers to register a ticket service factory
// for use by the engine
func RegisterTicketServiceFactory(f func(*runtime.Config) engine.TicketServiceFactory) {
ticketFactory = f
}

// RegisterAirtimeServiceFactory can be used by outside callers to register a airtime factory
// for use by the engine
func RegisterAirtimeServiceFactory(f func(*runtime.Config) engine.AirtimeServiceFactory) {
Expand All @@ -58,7 +50,6 @@ func Engine(c *runtime.Config) flows.Engine {
WithWebhookServiceFactory(webhooks.NewServiceFactory(httpClient, httpRetries, httpAccess, webhookHeaders, c.WebhooksMaxBodyBytes)).
WithClassificationServiceFactory(classificationFactory(c)).
WithEmailServiceFactory(emailFactory(c)).
WithTicketServiceFactory(ticketFactory(c)).
WithAirtimeServiceFactory(airtimeFactory(c)).
WithMaxStepsPerSprint(c.MaxStepsPerSprint).
WithMaxResumesPerSession(c.MaxResumesPerSession).
Expand All @@ -84,7 +75,6 @@ func Simulator(c *runtime.Config) flows.Engine {
WithWebhookServiceFactory(webhooks.NewServiceFactory(httpClient, nil, httpAccess, webhookHeaders, c.WebhooksMaxBodyBytes)).
WithClassificationServiceFactory(classificationFactory(c)). // simulated sessions do real classification
WithEmailServiceFactory(simulatorEmailServiceFactory). // but faked emails
WithTicketServiceFactory(simulatorTicketServiceFactory). // and faked tickets
WithAirtimeServiceFactory(simulatorAirtimeServiceFactory). // and faked airtime transfers
WithMaxStepsPerSprint(c.MaxStepsPerSprint).
WithMaxResumesPerSession(c.MaxResumesPerSession).
Expand All @@ -106,18 +96,6 @@ func (s *simulatorEmailService) Send(addresses []string, subject, body string) e
return nil
}

func simulatorTicketServiceFactory(ticketer *flows.Ticketer) (flows.TicketService, error) {
return &simulatorTicketService{ticketer: ticketer}, nil
}

type simulatorTicketService struct {
ticketer *flows.Ticketer
}

func (s *simulatorTicketService) Open(env envs.Environment, contact *flows.Contact, topic *flows.Topic, body string, assignee *flows.User, logHTTP flows.HTTPLogCallback) (*flows.Ticket, error) {
return flows.OpenTicket(s.ticketer, topic, body, assignee), nil
}

func simulatorAirtimeServiceFactory(flows.SessionAssets) (flows.AirtimeService, error) {
return &simulatorAirtimeService{}, nil
}
Expand Down
20 changes: 0 additions & 20 deletions core/goflow/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import (
"github.com/nyaruka/gocommon/urns"
"github.com/nyaruka/goflow/flows"
"github.com/nyaruka/mailroom/core/goflow"
"github.com/nyaruka/mailroom/core/models"
"github.com/nyaruka/mailroom/testsuite"
"github.com/nyaruka/mailroom/testsuite/testdata"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -58,24 +56,6 @@ func TestSimulatorAirtime(t *testing.T) {
}, transfer)
}

func TestSimulatorTicket(t *testing.T) {
ctx, rt := testsuite.Runtime()

ticketer, err := models.LookupTicketerByUUID(ctx, rt.DB.DB, testdata.Mailgun.UUID)
require.NoError(t, err)

svc, err := goflow.Simulator(rt.Config).Services().Ticket(flows.NewTicketer(ticketer))
assert.NoError(t, err)

oa, err := models.GetOrgAssets(ctx, rt, testdata.Org1.ID)
require.NoError(t, err)

ticket, err := svc.Open(nil, nil, oa.SessionAssets().Topics().FindByName("General"), "Where are my cookies?", nil, nil)
assert.NoError(t, err)
assert.Equal(t, testdata.Mailgun.UUID, ticket.Ticketer().UUID())
assert.Equal(t, "Where are my cookies?", ticket.Body())
}

func TestSimulatorWebhook(t *testing.T) {
_, rt := testsuite.Runtime()

Expand Down
20 changes: 0 additions & 20 deletions core/handlers/service_called.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,12 @@ func handleServiceCalled(ctx context.Context, rt *runtime.Runtime, tx *sqlx.Tx,
slog.Debug("service called", "contact", scene.ContactUUID(), "session", scene.SessionID(), "service", event.Service)

var classifier *models.Classifier
var ticketer *models.Ticketer

if event.Service == "classifier" {
classifier = oa.ClassifierByUUID(event.Classifier.UUID)
if classifier == nil {
return errors.Errorf("unable to find classifier with UUID: %s", event.Classifier.UUID)
}
} else if event.Service == "ticketer" {
ticketer = oa.TicketerByUUID(event.Ticketer.UUID)
if ticketer == nil {
return errors.Errorf("unable to find ticketer with UUID: %s", event.Ticketer.UUID)
}
}

// create a log for each HTTP call
Expand All @@ -58,21 +52,7 @@ func handleServiceCalled(ctx context.Context, rt *runtime.Runtime, tx *sqlx.Tx,
httpLog.Retries,
httpLog.CreatedOn,
)
} else if event.Service == "ticketer" {
log = models.NewTicketerCalledLog(
oa.OrgID(),
ticketer.ID(),
httpLog.URL,
httpLog.StatusCode,
httpLog.Request,
httpLog.Response,
httpLog.Status != flows.CallStatusSuccess,
time.Duration(httpLog.ElapsedMS)*time.Millisecond,
httpLog.Retries,
httpLog.CreatedOn,
)
}

scene.AppendToEventPreCommitHook(hooks.InsertHTTPLogsHook, log)
}

Expand Down
12 changes: 0 additions & 12 deletions core/handlers/ticket_opened.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/nyaruka/mailroom/core/hooks"
"github.com/nyaruka/mailroom/core/models"
"github.com/nyaruka/mailroom/runtime"
"github.com/nyaruka/mailroom/services/tickets"
"github.com/pkg/errors"
)

Expand All @@ -24,11 +23,6 @@ func handleTicketOpened(ctx context.Context, rt *runtime.Runtime, tx *sqlx.Tx, o

slog.Debug("ticket opened", "contact", scene.ContactUUID(), "session", scene.SessionID(), "ticket", event.Ticket.UUID)

ticketer := oa.TicketerByUUID(event.Ticket.Ticketer.UUID)
if ticketer == nil {
return errors.Errorf("unable to find ticketer with UUID: %s", event.Ticket.Ticketer.UUID)
}

var topicID models.TopicID
if event.Ticket.Topic != nil {
topic := oa.TopicByUUID(event.Ticket.Topic.UUID)
Expand Down Expand Up @@ -62,15 +56,9 @@ func handleTicketOpened(ctx context.Context, rt *runtime.Runtime, tx *sqlx.Tx, o
scene.UserID(),
openedInID,
scene.ContactID(),
ticketer.ID(),
event.Ticket.ExternalID,
topicID,
event.Ticket.Body,
assigneeID,
map[string]any{
"contact-uuid": scene.Contact().UUID(),
"contact-display": tickets.GetContactDisplay(oa.Env(), scene.Contact()),
},
)

scene.AppendToEventPreCommitHook(hooks.InsertTicketsHook, ticket)
Expand Down
32 changes: 4 additions & 28 deletions core/handlers/ticket_opened_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"github.com/nyaruka/goflow/flows"
"github.com/nyaruka/goflow/flows/actions"
"github.com/nyaruka/mailroom/core/handlers"
_ "github.com/nyaruka/mailroom/services/tickets/mailgun"
_ "github.com/nyaruka/mailroom/services/tickets/zendesk"
"github.com/nyaruka/mailroom/testsuite"
"github.com/nyaruka/mailroom/testsuite/testdata"
)
Expand Down Expand Up @@ -45,7 +43,6 @@ func TestTicketOpened(t *testing.T) {
testdata.Cathy: []flows.Action{
actions.NewOpenTicket(
handlers.NewActionUUID(),
assets.NewTicketerReference(testdata.Mailgun.UUID, "Mailgun (IT Support)"),
assets.NewTopicReference(testdata.SupportTopic.UUID, "Support"),
"Where are my cookies?",
assets.NewUserReference(testdata.Admin.Email, "Admin"),
Expand All @@ -55,7 +52,6 @@ func TestTicketOpened(t *testing.T) {
testdata.Bob: []flows.Action{
actions.NewOpenTicket(
handlers.NewActionUUID(),
assets.NewTicketerReference(testdata.Zendesk.UUID, "Zendesk (Nyaruka)"),
nil,
"I've found some cookies",
nil,
Expand All @@ -65,35 +61,15 @@ func TestTicketOpened(t *testing.T) {
},
SQLAssertions: []handlers.SQLAssertion{
{ // cathy's old ticket will still be open and cathy's new ticket will have been created
SQL: "select count(*) from tickets_ticket where contact_id = $1 AND status = 'O' AND ticketer_id = $2",
Args: []any{testdata.Cathy.ID, testdata.Mailgun.ID},
SQL: "select count(*) from tickets_ticket where contact_id = $1 AND status = 'O'",
Args: []any{testdata.Cathy.ID},
Count: 1,
},
{ // and there's an HTTP log for that
SQL: "select count(*) from request_logs_httplog where ticketer_id = $1",
Args: []any{testdata.Mailgun.ID},
Count: 1,
},
{ // which doesn't include our API token
SQL: "select count(*) from request_logs_httplog where ticketer_id = $1 AND request like '%sesame%'",
Args: []any{testdata.Mailgun.ID},
Count: 0,
},
{ // bob's ticket will have been created too
SQL: "select count(*) from tickets_ticket where contact_id = $1 AND status = 'O' AND ticketer_id = $2",
Args: []any{testdata.Bob.ID, testdata.Zendesk.ID},
SQL: "select count(*) from tickets_ticket where contact_id = $1 AND status = 'O'",
Args: []any{testdata.Bob.ID},
Count: 1,
},
{ // and there's an HTTP log for that
SQL: "select count(*) from request_logs_httplog where ticketer_id = $1",
Args: []any{testdata.Zendesk.ID},
Count: 1,
},
{ // which doesn't include our API token
SQL: "select count(*) from request_logs_httplog where ticketer_id = $1 AND request like '%523562%'",
Args: []any{testdata.Zendesk.ID},
Count: 0,
},
{ // and we have 2 ticket opened events for the 2 tickets opened
SQL: "select count(*) from tickets_ticketevent where event_type = 'O'",
Count: 2,
Expand Down
40 changes: 3 additions & 37 deletions core/models/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,9 @@ const (
RefreshOptIns = Refresh(1 << 11)
RefreshResthooks = Refresh(1 << 12)
RefreshTemplates = Refresh(1 << 13)
RefreshTicketers = Refresh(1 << 14)
RefreshTopics = Refresh(1 << 15)
RefreshTriggers = Refresh(1 << 16)
RefreshUsers = Refresh(1 << 17)
RefreshTopics = Refresh(1 << 14)
RefreshTriggers = Refresh(1 << 15)
RefreshUsers = Refresh(1 << 16)
)

// OrgAssets is our top level cache of all things contained in an org. It is used to build
Expand Down Expand Up @@ -89,10 +88,6 @@ type OrgAssets struct {
optInsByID map[OptInID]*OptIn
optInsByUUID map[assets.OptInUUID]*OptIn

ticketers []assets.Ticketer
ticketersByID map[TicketerID]*Ticketer
ticketersByUUID map[assets.TicketerUUID]*Ticketer

topics []assets.Topic
topicsByID map[TopicID]*Topic
topicsByUUID map[assets.TopicUUID]*Topic
Expand Down Expand Up @@ -358,23 +353,6 @@ func NewOrgAssets(ctx context.Context, rt *runtime.Runtime, orgID OrgID, prev *O
oa.flowByID = prev.flowByID
}

if prev == nil || refresh&RefreshTicketers > 0 {
oa.ticketers, err = loadAssetType(ctx, db, orgID, "ticketers", loadTicketers)
if err != nil {
return nil, errors.Wrapf(err, "error loading ticketer assets for org %d", orgID)
}
oa.ticketersByID = make(map[TicketerID]*Ticketer)
oa.ticketersByUUID = make(map[assets.TicketerUUID]*Ticketer)
for _, t := range oa.ticketers {
oa.ticketersByID[t.(*Ticketer).ID()] = t.(*Ticketer)
oa.ticketersByUUID[t.UUID()] = t.(*Ticketer)
}
} else {
oa.ticketers = prev.ticketers
oa.ticketersByID = prev.ticketersByID
oa.ticketersByUUID = prev.ticketersByUUID
}

if prev == nil || refresh&RefreshTopics > 0 {
oa.topics, err = loadAssetType(ctx, db, orgID, "topics", loadTopics)
if err != nil {
Expand Down Expand Up @@ -687,18 +665,6 @@ func (a *OrgAssets) Globals() ([]assets.Global, error) {
return a.globals, nil
}

func (a *OrgAssets) Ticketers() ([]assets.Ticketer, error) {
return a.ticketers, nil
}

func (a *OrgAssets) TicketerByID(id TicketerID) *Ticketer {
return a.ticketersByID[id]
}

func (a *OrgAssets) TicketerByUUID(uuid assets.TicketerUUID) *Ticketer {
return a.ticketersByUUID[uuid]
}

func (a *OrgAssets) Topics() ([]assets.Topic, error) {
return a.topics, nil
}
Expand Down
11 changes: 2 additions & 9 deletions core/models/contacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,8 @@ func (c *Contact) FlowContact(oa *OrgAssets) (*flows.Contact, error) {

// convert our ticket to a flow ticket
var ticket *flows.Ticket
var err error
if c.ticket != nil {
ticket, err = c.ticket.FlowTicket(oa)
if err != nil {
return nil, errors.Wrapf(err, "error creating flow ticket")
}
ticket = c.ticket.FlowTicket(oa)
}

// create our flow contact
Expand Down Expand Up @@ -331,10 +327,7 @@ func LoadContacts(ctx context.Context, db Queryer, oa *OrgAssets, ids []ContactI
// grab the last opened open ticket
if len(e.Tickets) > 0 {
t := e.Tickets[0]
ticketer := oa.TicketerByID(t.TicketerID)
if ticketer != nil {
contact.ticket = NewTicket(t.UUID, oa.OrgID(), NilUserID, NilFlowID, contact.ID(), ticketer.ID(), t.ExternalID, t.TopicID, t.Body, t.AssigneeID, nil)
}
contact.ticket = NewTicket(t.UUID, oa.OrgID(), NilUserID, NilFlowID, contact.ID(), t.TopicID, t.Body, t.AssigneeID)
}

contacts = append(contacts, contact)
Expand Down
9 changes: 3 additions & 6 deletions core/models/contacts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,11 @@ func TestContacts(t *testing.T) {
defer testsuite.Reset(testsuite.ResetAll)

// for now it's still possible to have more than one open ticket in the database
testdata.InsertOpenTicket(rt, testdata.Org1, testdata.Cathy, testdata.Zendesk, testdata.SupportTopic, "Where are my shoes?", "1234", time.Now(), testdata.Agent)
testdata.InsertOpenTicket(rt, testdata.Org1, testdata.Cathy, testdata.Zendesk, testdata.SalesTopic, "Where are my pants?", "2345", time.Now(), nil)
testdata.InsertOpenTicket(rt, testdata.Org1, testdata.Cathy, testdata.SupportTopic, "Where are my shoes?", time.Now(), testdata.Agent)
testdata.InsertOpenTicket(rt, testdata.Org1, testdata.Cathy, testdata.SalesTopic, "Where are my pants?", time.Now(), nil)

testdata.InsertContactURN(rt, testdata.Org1, testdata.Bob, "whatsapp:250788373373", 999, nil)
testdata.InsertOpenTicket(rt, testdata.Org1, testdata.Bob, testdata.Mailgun, testdata.DefaultTopic, "His name is Bob", "", time.Now(), testdata.Editor)

// delete mailgun ticketer
rt.DB.MustExec(`UPDATE tickets_ticketer SET is_active = false WHERE id = $1`, testdata.Mailgun.ID)
testdata.InsertOpenTicket(rt, testdata.Org1, testdata.Bob, testdata.DefaultTopic, "His name is Bob", time.Now(), testdata.Editor)

org, err := models.GetOrgAssetsWithRefresh(ctx, rt, testdata.Org1.ID, models.RefreshAll)
assert.NoError(t, err)
Expand Down
Loading

0 comments on commit 728f681

Please sign in to comment.