diff --git a/core/goflow/engine.go b/core/goflow/engine.go index 9e73d3db9..92036c426 100644 --- a/core/goflow/engine.go +++ b/core/goflow/engine.go @@ -21,6 +21,7 @@ var ticketFactory func(*runtime.Config) engine.TicketServiceFactory var airtimeFactory func(*runtime.Config) engine.AirtimeServiceFactory var externalServiceFactory func(*runtime.Config) engine.ExternalServiceServiceFactory var msgCatalogFactory func(*runtime.Config) engine.MsgCatalogServiceFactory +var orgContextFactory func(*runtime.Config) engine.OrgContextServiceFactory // RegisterEmailServiceFactory can be used by outside callers to register a email factory // for use by the engine @@ -54,6 +55,10 @@ func RegisterMsgCatalogServiceFactory(f func(*runtime.Config) engine.MsgCatalogS msgCatalogFactory = f } +func RegisterOrgContextServiceFactory(f func(*runtime.Config) engine.OrgContextServiceFactory) { + orgContextFactory = f +} + // Engine returns the global engine instance for use with real sessions func Engine(c *runtime.Config) flows.Engine { engInit.Do(func() { @@ -71,6 +76,7 @@ func Engine(c *runtime.Config) flows.Engine { WithTicketServiceFactory(ticketFactory(c)). WithExternalServiceServiceFactory(externalServiceFactory((c))). WithMsgCatalogServiceFactory(msgCatalogFactory((c))). // msg catalog + WithOrgContextServiceFactory(orgContextFactory((c))). WithAirtimeServiceFactory(airtimeFactory(c)). WithMaxStepsPerSprint(c.MaxStepsPerSprint). WithMaxResumesPerSession(c.MaxResumesPerSession). diff --git a/core/models/assets.go b/core/models/assets.go index 218d252fd..7cf0ebbb9 100644 --- a/core/models/assets.go +++ b/core/models/assets.go @@ -27,6 +27,9 @@ type OrgAssets struct { org *Org + orgContexts []assets.OrgContext + contextByUUID map[assets.ChannelUUID]*OrgContext + sessionAssets flows.SessionAssets flowByUUID map[assets.FlowUUID]assets.Flow @@ -403,6 +406,27 @@ func NewOrgAssets(ctx context.Context, rt *runtime.Runtime, orgID OrgID, prev *O oa.msgCatalogsByUUID = prev.msgCatalogsByUUID } + if prev == nil || refresh&RefreshContext > 0 { + context := oa.org.ConfigValue("context", "") + c := &OrgContext{} + c.c.OrgContext = context + oa.orgContexts = append(oa.orgContexts, c) + if err != nil { + return nil, errors.Wrapf(err, "error loading context for org %d", orgID) + } + + oa.contextByUUID = make(map[assets.ChannelUUID]*OrgContext) + for _, a := range oa.orgContexts { + for c, _ := range oa.channelsByUUID { + oa.contextByUUID[c] = a.(*OrgContext) + } + } + + } else { + oa.orgContexts = prev.orgContexts + oa.contextByUUID = prev.contextByUUID + } + // intialize our session assets oa.sessionAssets, err = engine.NewSessionAssets(oa.Env(), oa, goflow.MigrationConfig(rt.Config)) if err != nil { @@ -437,6 +461,7 @@ const ( RefreshUsers = Refresh(1 << 16) RefreshExternalServices = Refresh(1 << 17) RefreshMsgCatalogs = Refresh(1 << 18) + RefreshContext = Refresh(1 << 19) ) // GetOrgAssets creates or gets org assets for the passed in org @@ -733,3 +758,7 @@ func (a *OrgAssets) ExternalServiceByUUID(uuid assets.ExternalServiceUUID) *Exte func (a *OrgAssets) MsgCatalogs() ([]assets.MsgCatalog, error) { return a.msgCatalogs, nil } + +func (a *OrgAssets) OrgContexts() ([]assets.OrgContext, error) { + return a.orgContexts, nil +} diff --git a/core/models/org_context.go b/core/models/org_context.go new file mode 100644 index 000000000..9b6dc529d --- /dev/null +++ b/core/models/org_context.go @@ -0,0 +1,76 @@ +package models + +import ( + "database/sql/driver" + "net/http" + + "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/goflow/assets" + "github.com/nyaruka/goflow/flows" + "github.com/nyaruka/goflow/flows/engine" + "github.com/nyaruka/mailroom/core/goflow" + "github.com/nyaruka/mailroom/runtime" + "github.com/nyaruka/null" + "github.com/pkg/errors" +) + +type OrgContextID null.Int + +func (i OrgContextID) MarshalJSON() ([]byte, error) { + return null.Int(i).MarshalJSON() +} + +func (i *OrgContextID) UnmarshalJSON(b []byte) error { + return null.UnmarshalInt(b, (*null.Int)(i)) +} + +func (i OrgContextID) Value() (driver.Value, error) { + return null.Int(i).Value() +} + +func (i *OrgContextID) Scan(value interface{}) error { + return null.ScanInt(value, (*null.Int)(i)) +} + +func init() { + goflow.RegisterOrgContextServiceFactory(orgContextServiceFactory) +} + +func orgContextServiceFactory(c *runtime.Config) engine.OrgContextServiceFactory { + return func(session flows.Session, orgContext *flows.OrgContext) (flows.OrgContextService, error) { + return orgContext.Asset().(*OrgContext).AsService(c, orgContext) + } +} + +type OrgContext struct { + c struct { + OrgContext string `json:"context"` + ChannelUUID assets.ChannelUUID `json:"channel_uuid"` + } +} + +func (c *OrgContext) Context() string { return c.c.OrgContext } +func (c *OrgContext) ChannelUUID() assets.ChannelUUID { return c.c.ChannelUUID } + +type OrgContextService interface { + flows.OrgContextService +} + +func (c *OrgContext) AsService(cfg *runtime.Config, context *flows.OrgContext) (OrgContextService, error) { + httpClient, httpRetries, _ := goflow.HTTP(cfg) + + initFunc := orgContextServices["org_context"] + if initFunc != nil { + return initFunc(cfg, httpClient, httpRetries, context, nil) + } + + return nil, errors.Errorf("unrecognized context %s", c.Context()) +} + +type OrgContextServiceFunc func(*runtime.Config, *http.Client, *httpx.RetryConfig, *flows.OrgContext, map[string]string) (OrgContextService, error) + +var orgContextServices = map[string]OrgContextServiceFunc{} + +func RegisterContextService(name string, initFunc OrgContextServiceFunc) { + orgContextServices[name] = initFunc +} diff --git a/go.mod b/go.mod index 5c1e4ea11..def979b4c 100644 --- a/go.mod +++ b/go.mod @@ -70,4 +70,4 @@ go 1.17 replace github.com/nyaruka/gocommon => github.com/Ilhasoft/gocommon v1.16.2-weni -replace github.com/nyaruka/goflow => github.com/weni-ai/goflow v0.4.1-goflow-0.144.3 +replace github.com/nyaruka/goflow => github.com/weni-ai/goflow v0.5.0-goflow-0.144.3-2-develop diff --git a/go.sum b/go.sum index 7b9b181aa..a7bf79159 100644 --- a/go.sum +++ b/go.sum @@ -204,8 +204,8 @@ github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLD github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= -github.com/weni-ai/goflow v0.4.1-goflow-0.144.3 h1:T4M8Unl869ouIFl39B7yOOIvL62cu0cyABdLwEvizzA= -github.com/weni-ai/goflow v0.4.1-goflow-0.144.3/go.mod h1:o0xaVWP9qNcauBSlcNLa79Fm2oCPV+BDpheFRa/D40c= +github.com/weni-ai/goflow v0.5.0-goflow-0.144.3-2-develop h1:QlFO11VA2uMPbWYWkbLQm+sjkiy4H0TBYcTO8U2vT68= +github.com/weni-ai/goflow v0.5.0-goflow-0.144.3-2-develop/go.mod h1:o0xaVWP9qNcauBSlcNLa79Fm2oCPV+BDpheFRa/D40c= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=