diff --git a/core/models/assets.go b/core/models/assets.go index 562186ba9..c68dc32d8 100644 --- a/core/models/assets.go +++ b/core/models/assets.go @@ -65,6 +65,7 @@ type OrgAssets struct { topicsByID map[TopicID]*Topic topicsByUUID map[assets.TopicUUID]*Topic + optIns []assets.OptIn resthooks []assets.Resthook templates []assets.Template triggers []*Trigger @@ -233,6 +234,15 @@ func NewOrgAssets(ctx context.Context, rt *runtime.Runtime, orgID OrgID, prev *O oa.labelsByUUID = prev.labelsByUUID } + if prev == nil || refresh&RefreshOptIns > 0 { + oa.optIns, err = loadOptIns(ctx, db, orgID) + if err != nil { + return nil, errors.Wrapf(err, "error loading optins for org %d", orgID) + } + } else { + oa.optIns = prev.optIns + } + if prev == nil || refresh&RefreshResthooks > 0 { oa.resthooks, err = loadResthooks(ctx, db, orgID) if err != nil { @@ -633,7 +643,7 @@ func (a *OrgAssets) Locations() ([]assets.LocationHierarchy, error) { } func (a *OrgAssets) OptIns() ([]assets.OptIn, error) { - return nil, nil // TODO + return a.optIns, nil } func (a *OrgAssets) Resthooks() ([]assets.Resthook, error) { diff --git a/core/models/channels.go b/core/models/channels.go index ec9909371..9e7e97caa 100644 --- a/core/models/channels.go +++ b/core/models/channels.go @@ -214,7 +214,7 @@ SELECT ROW_TO_JSON(r) FROM (SELECT END FROM unnest(regexp_split_to_array(c.role,'')) AS r) ) as roles, - CASE WHEN channel_type IN ('FBA') THEN {'optins'}::text[] ELSE {}::text[] END, + CASE WHEN channel_type IN ('FBA') THEN '{"optins"}'::text[] ELSE '{}'::text[] END, jsonb_extract_path(c.config, 'matching_prefixes') AS match_prefixes, jsonb_extract_path(c.config, 'allow_international') AS allow_international, jsonb_extract_path(c.config, 'machine_detection') AS machine_detection diff --git a/core/models/optins.go b/core/models/optins.go new file mode 100644 index 000000000..0f6403a59 --- /dev/null +++ b/core/models/optins.go @@ -0,0 +1,62 @@ +package models + +import ( + "context" + "database/sql" + "time" + + "github.com/nyaruka/gocommon/dbutil" + "github.com/nyaruka/goflow/assets" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// OptInID is our type for the database id of an optin +type OptInID int + +// OptIn is the mailroom type for optins +type OptIn struct { + o struct { + ID OptInID `json:"id"` + UUID assets.OptInUUID `json:"uuid"` + Name string `json:"name"` + } +} + +func (o *OptIn) ID() OptInID { return o.o.ID } +func (o *OptIn) UUID() assets.OptInUUID { return o.o.UUID } +func (o *OptIn) Name() string { return o.o.Name } + +const sqlSelectOptInsByOrg = ` +SELECT ROW_TO_JSON(r) FROM ( + SELECT id, uuid, name + FROM msgs_optin o + WHERE o.org_id = $1 AND o.is_active + ORDER BY o.id ASC +) o;` + +// loads the optins for the passed in org +func loadOptIns(ctx context.Context, db *sql.DB, orgID OrgID) ([]assets.OptIn, error) { + start := time.Now() + + rows, err := db.QueryContext(ctx, sqlSelectOptInsByOrg, orgID) + if err != nil { + return nil, errors.Wrapf(err, "error querying resthooks for org: %d", orgID) + } + defer rows.Close() + + optIns := make([]assets.OptIn, 0, 10) + for rows.Next() { + optIn := &OptIn{} + err = dbutil.ScanJSON(rows, &optIn.o) + if err != nil { + return nil, errors.Wrap(err, "error scanning resthook row") + } + + optIns = append(optIns, optIn) + } + + logrus.WithField("elapsed", time.Since(start)).WithField("org_id", orgID).WithField("count", len(optIns)).Debug("loaded resthooks") + + return optIns, nil +}