diff --git a/core/models/notifications.go b/core/models/notifications.go new file mode 100644 index 000000000..71601501d --- /dev/null +++ b/core/models/notifications.go @@ -0,0 +1,97 @@ +package models + +import ( + "context" + + "github.com/nyaruka/mailroom/utils/dbutil" + "github.com/pkg/errors" +) + +// LogID is our type for log ids +type LogID int + +type LogType string + +const ( + LogTypeBroadcastStarted LogType = "bcast:started" + LogTypeBroadcastCompleted LogType = "bcast:completed" + LogTypeChannelAlert LogType = "channel:alert" + LogTypeExportStarted LogType = "export:started" + LogTypeExportCompleted LogType = "export:completed" + LogTypeFlowStartStarted LogType = "start:started" + LogTypeFlowStartCompleted LogType = "start:completed" + LogTypeImportStarted LogType = "import:started" + LogTypeImportCompleted LogType = "import:completed" + LogTypeTicketOpened LogType = "ticket:opened" + LogTypeTicketNewMsgs LogType = "ticket:msgs" + LogTypeTicketAssignment LogType = "ticket:assign" + LogTypeTicketNote LogType = "ticket:note" +) + +type NotifyWho string + +const ( + NotifyAll NotifyWho = "all" + NotifyAllExceptUser NotifyWho = "all_except_user" + NotifyAdmins NotifyWho = "admins" + NotifyAdminsExceptUser NotifyWho = "admins_except_user" + NotifyUser NotifyWho = "user" + NotifyNobody NotifyWho = "nobody" +) + +type Log struct { + ID LogID `db:"id"` + OrgID OrgID `db:"org_id"` + LogType LogType `db:"log_type"` + CreatedByID UserID `db:"created_by_id"` + + BroadcastID BroadcastID `db:"broadcast_id"` + FlowStartID StartID `db:"flow_start_id"` + TicketID TicketID `db:"ticket_id"` +} + +type Notification struct { + ID LogID `db:"id"` + OrgID OrgID `db:"org_id"` + UserID UserID `db:"log_type"` + LogID LogID `db:"created_by_id"` +} + +func LogTicketOpened(ctx context.Context, db Queryer, oa *OrgAssets, ticket *Ticket) error { + return logAndNotify(ctx, db, oa, &Log{OrgID: ticket.OrgID(), LogType: LogTypeTicketOpened, TicketID: ticket.ID()}, NotifyAllExceptUser) +} + +const insertLogSQL = ` +INSERT INTO notifications_log(org_id, log_type, created_on, created_by_id, broadcast_id, flow_start_id, ticket_id) + VALUES(:org_id, :log_type, NOW(), :created_by_id, :broadcast_id, :flow_start_id, :ticket_id) +RETURNING id` + +const insertNotificationSQL = ` +INSERT INTO notifications_notification(org_id, user_id, log_id) + VALUES(:org_id, :user_id, :log_id)` + +func logAndNotify(ctx context.Context, db Queryer, oa *OrgAssets, log *Log, notifyWho NotifyWho) error { + err := dbutil.BulkQuery(ctx, db, insertLogSQL, []interface{}{log}) + if err != nil { + return errors.Wrapf(err, "error inserting %s log", log.LogType) + } + + userIDs, err := getUsersToNotify(oa, notifyWho, log.CreatedByID) + if err != nil { + return errors.Wrap(err, "error getting notification users") + } + + var notifications []interface{} + for _, userID := range userIDs { + notifications = append(notifications, &Notification{OrgID: log.OrgID, UserID: userID, LogID: log.ID}) + } + + err = dbutil.BulkQuery(ctx, db, insertNotificationSQL, notifications) + + return errors.Wrap(err, "error inserting notifications") +} + +func getUsersToNotify(oa *OrgAssets, who NotifyWho, user UserID) ([]UserID, error) { + // TODO + return nil, nil +} diff --git a/core/models/notifications_test.go b/core/models/notifications_test.go new file mode 100644 index 000000000..7eea59dda --- /dev/null +++ b/core/models/notifications_test.go @@ -0,0 +1,26 @@ +package models_test + +import ( + "testing" + + "github.com/nyaruka/mailroom/core/models" + "github.com/nyaruka/mailroom/testsuite" + "github.com/nyaruka/mailroom/testsuite/testdata" + "github.com/stretchr/testify/require" +) + +func TestNotifications(t *testing.T) { + ctx, _, db, _ := testsuite.Reset() + + oa, err := models.GetOrgAssets(ctx, db, testdata.Org1.ID) + require.NoError(t, err) + + ticket := testdata.InsertOpenTicket(db, testdata.Org1, testdata.Cathy, testdata.Internal, testdata.SupportTopic, "", "Where my pants", "", nil) + modelTicket := ticket.Load(db) + + err = models.LogTicketOpened(ctx, db, oa, modelTicket) + require.NoError(t, err) + + testsuite.AssertQuery(t, db, `SELECT org_id, log_type, ticket_id FROM notifications_log`). + Columns(map[string]interface{}{"org_id": int64(testdata.Org1.ID), "log_type": "ticket:opened", "ticket_id": int64(modelTicket.ID())}) +} diff --git a/mailroom_test.dump b/mailroom_test.dump index 2ee9b53cf..fa09ffa4f 100644 Binary files a/mailroom_test.dump and b/mailroom_test.dump differ