fix(slack): select widest-scope connector in sender

sendMessage and updateMessage used LoadAllByOrganizationIDProtocol
AndProvider and then picked connectors[0], which is ordered by
created_at ASC. On an organization with multiple Slack installs
only the oldest install ever received messages — re-installing
Slack to switch channels silently broke because the sort kept
the old row winning.

Switch to LoadOneByOrganizationIDAndProvider, which picks the
widest-scope row with updated_at DESC as the tiebreak. For Slack
the scope sets are typically identical across installs, so the
effective behavior becomes "most recent install wins" — the
expected behavior.

While here, prefix the remaining error messages in this file with
"cannot" to match the project convention.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
This commit is contained in:
Aurélien Sibiril
2026-04-09 01:05:26 +02:00
parent 08f163f02f
commit 816b9300ed

View File

@@ -148,39 +148,36 @@ func (s *Sender) sendMessage(ctx context.Context, tx pg.Querier, message *coreda
tenantID := message.ID.TenantID()
scope := coredata.NewScope(tenantID)
var connectors coredata.Connectors
if err := connectors.LoadAllByOrganizationIDProtocolAndProvider(
var c coredata.Connector
if err := c.LoadOneByOrganizationIDAndProvider(
ctx,
tx,
scope,
message.OrganizationID,
coredata.ConnectorProtocolOAuth2,
coredata.ConnectorProviderSlack,
s.encryptionKey,
message.OrganizationID,
coredata.ConnectorProviderSlack,
); err != nil {
return nil, nil, fmt.Errorf("cannot load slack connectors: %w", err)
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, nil, fmt.Errorf("cannot send slack message: no connector configured for organization")
}
return nil, nil, fmt.Errorf("cannot load slack connector: %w", err)
}
if len(connectors) == 0 {
return nil, nil, fmt.Errorf("no slack connectors configured for organization")
}
c := connectors[0]
if c.Connection == nil {
return nil, nil, fmt.Errorf("slack connector has nil connection")
return nil, nil, fmt.Errorf("cannot send slack message: connector has nil connection")
}
slackConn, ok := c.Connection.(*connector.SlackConnection)
if !ok {
return nil, nil, fmt.Errorf("slack connector must have SlackConnection type, got %T", c.Connection)
return nil, nil, fmt.Errorf("cannot send slack message: unexpected connection type %T", c.Connection)
}
if slackConn.Settings.ChannelID == "" {
return nil, nil, fmt.Errorf("slack connector %s has no channel ID", c.ID)
return nil, nil, fmt.Errorf("cannot send slack message: connector %s has no channel ID", c.ID)
}
if slackConn.AccessToken == "" {
return nil, nil, fmt.Errorf("slack connector %s has no access token", c.ID)
return nil, nil, fmt.Errorf("cannot send slack message: connector %s has no access token", c.ID)
}
client := NewClient(s.logger)
@@ -269,41 +266,38 @@ func (s *Sender) batchUpdateMessages(ctx context.Context) error {
func (s *Sender) updateMessage(ctx context.Context, tx pg.Querier, updateMessage *coredata.SlackMessage) error {
if updateMessage.ChannelID == nil || updateMessage.MessageTS == nil {
return fmt.Errorf("slack message has no channel ID or message TS")
return fmt.Errorf("cannot update slack message: missing channel ID or message TS")
}
tenantID := updateMessage.ID.TenantID()
scope := coredata.NewScope(tenantID)
var connectors coredata.Connectors
if err := connectors.LoadAllByOrganizationIDProtocolAndProvider(
var c coredata.Connector
if err := c.LoadOneByOrganizationIDAndProvider(
ctx,
tx,
scope,
updateMessage.OrganizationID,
coredata.ConnectorProtocolOAuth2,
coredata.ConnectorProviderSlack,
s.encryptionKey,
updateMessage.OrganizationID,
coredata.ConnectorProviderSlack,
); err != nil {
return fmt.Errorf("cannot load slack connectors: %w", err)
if errors.Is(err, coredata.ErrResourceNotFound) {
return fmt.Errorf("cannot update slack message: no connector configured for organization")
}
return fmt.Errorf("cannot load slack connector: %w", err)
}
if len(connectors) == 0 {
return fmt.Errorf("no slack connectors configured for organization")
}
c := connectors[0]
if c.Connection == nil {
return fmt.Errorf("slack connector has nil connection")
return fmt.Errorf("cannot update slack message: connector has nil connection")
}
slackConn, ok := c.Connection.(*connector.SlackConnection)
if !ok {
return fmt.Errorf("slack connector must have SlackConnection type, got %T", c.Connection)
return fmt.Errorf("cannot update slack message: unexpected connection type %T", c.Connection)
}
if slackConn.AccessToken == "" {
return fmt.Errorf("slack connector %s has no access token", c.ID)
return fmt.Errorf("cannot update slack message: connector %s has no access token", c.ID)
}
client := NewClient(s.logger)