Skip to content

Auto-resync Slack details upon changes - #1525

Open
skyfallwastaken wants to merge 4 commits into
mainfrom
slack-auto-resync
Open

Auto-resync Slack details upon changes#1525
skyfallwastaken wants to merge 4 commits into
mainfrom
slack-auto-resync

Conversation

@skyfallwastaken

Copy link
Copy Markdown
Member

Summary of the problem

If you change your avatar or display name on Slack, it doesn't get picked up by Hackatime until a) the nightly re-sync completes, or b) you sign out and sign back in. Both are equally bad solutions!

Describe your changes

Listen for user_change events and trigger a re-sync if they're relevant!

Screenshots / Media

N/A

Copilot AI review requested due to automatic review settings August 4, 2026 23:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps

greptile-apps Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds signed Slack user_change event handling and synchronizes Slack names, avatars, and email identities through a background job. It also changes superseded Slack-email handling from demotion to deletion and makes the OAuth reconciliation transactional.

  • Adds a signed /slack/events callback and Slack manifest subscription.
  • Enqueues profile synchronization only when relevant profile fields differ.
  • Reconciles Slack email records during OAuth and background synchronization.
  • Adds request, job, and model tests for event handling and identity updates.

Confidence Score: 4/5

The PR should not merge until Slack email reconciliation is ownership-safe and atomic with the background profile save.

A Slack callback can permanently delete email records from an account selected only through an email match, and the background synchronization can commit email identity changes even when saving the associated profile subsequently fails.

Files Needing Attention: app/models/concerns/oauth_authentication.rb, app/models/concerns/slack_integration.rb, app/jobs/slack_profile_sync_job.rb

Important Files Changed

Filename Overview
app/controllers/slack_controller.rb Adds signature-verified Slack event handling and selectively queues profile synchronization.
app/models/concerns/slack_integration.rb Adds email reconciliation, but commits authentication-record changes before the encompassing profile save can succeed.
app/models/concerns/oauth_authentication.rb Makes OAuth email changes transactional, but the destructive reconciliation can target an account selected solely by matching email.
app/jobs/slack_profile_sync_job.rb Persists synchronized User fields after email reconciliation has already committed, permitting partial identity updates.
spec/requests/slack_spec.rb Covers URL verification, changed-email enqueueing, irrelevant events, and invalid signatures.
test/jobs/slack_profile_sync_job_test.rb Covers normal email reconciliation and conflicts but not a failure of user.save! after email changes commit.
test/models/user_test.rb Verifies the OAuth transaction restores email state when the User save fails.

Sequence Diagram

sequenceDiagram
  participant Slack
  participant Events as SlackController
  participant Job as SlackProfileSyncJob
  participant API as Slack API
  participant Email as EmailAddress
  participant User
  Slack->>Events: signed user_change event
  Events->>Job: enqueue user ID
  Job->>API: users.info
  API-->>Job: current profile and email
  Job->>Email: reconcile Slack email
  Email-->>Job: transaction commits
  Job->>User: save profile and slack_synced_at
  alt User save fails
    User-->>Job: persistence error
    Note over Email,User: Email changes remain committed
  end
Loading
Prompt To Fix All With AI
### Issue 1
app/models/concerns/oauth_authentication.rb:101
**OAuth deletes another account's emails**

If the Slack email is already attached to a different Hackatime user, `email_address.user` selects that user and this `destroy_all` permanently removes their other Slack-sourced email records before replacing their Slack credentials.

### Issue 2
app/models/concerns/slack_integration.rb:80-84
**Email reconciliation commits before profile**

When `user.save!` fails after a Slack email change, this inner transaction has already committed the replacement email and deleted the former email, leaving authentication records updated while the profile fields and `slack_synced_at` remain unsaved.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (3): Last reviewed commit: "Rollback Slack email changes when OAuth ..." | Re-trigger Greptile

Comment thread app/models/concerns/slack_integration.rb Outdated
Comment thread app/models/concerns/oauth_authentication.rb Outdated
user.country_code = country_code_from_ip(ip_address) if user.country_code.blank?
user.save!
User.transaction do
user.email_addresses.source_slack.where.not(email: email).destroy_all

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 OAuth deletes another account's emails

If the Slack email is already attached to a different Hackatime user, email_address.user selects that user and this destroy_all permanently removes their other Slack-sourced email records before replacing their Slack credentials.

Knowledge Base Used: Authentication: sessions, API keys, and OAuth

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/models/concerns/oauth_authentication.rb
Line: 101

Comment:
**OAuth deletes another account's emails**

If the Slack email is already attached to a different Hackatime user, `email_address.user` selects that user and this `destroy_all` permanently removes their other Slack-sourced email records before replacing their Slack credentials.

**Knowledge Base Used:** [Authentication: sessions, API keys, and OAuth](https://app.greptile.com/mahadk/-/custom-context/knowledge-base/hackclub/hackatime/-/docs/api-authentication.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +80 to +84
transaction do
email_address ||= email_addresses.create!(email: email, source: :slack)
email_addresses.source_slack.where.not(id: email_address.id).destroy_all
email_address.update!(source: :slack) unless email_address.source_slack?
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Email reconciliation commits before profile

When user.save! fails after a Slack email change, this inner transaction has already committed the replacement email and deleted the former email, leaving authentication records updated while the profile fields and slack_synced_at remain unsaved.

Knowledge Base Used: Authentication: sessions, API keys, and OAuth

Prompt To Fix With AI
This is a comment left during a code review.
Path: app/models/concerns/slack_integration.rb
Line: 80-84

Comment:
**Email reconciliation commits before profile**

When `user.save!` fails after a Slack email change, this inner transaction has already committed the replacement email and deleted the former email, leaving authentication records updated while the profile fields and `slack_synced_at` remain unsaved.

**Knowledge Base Used:** [Authentication: sessions, API keys, and OAuth](https://app.greptile.com/mahadk/-/custom-context/knowledge-base/hackclub/hackatime/-/docs/api-authentication.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants