()
| 54 | * which has access to WorkOS user data for email matching. |
| 55 | */ |
| 56 | export async function syncSlackUsers(): Promise<SyncSlackUsersResult> { |
| 57 | if (!isSlackConfigured()) { |
| 58 | return { |
| 59 | total_synced: 0, |
| 60 | new_users: 0, |
| 61 | updated_users: 0, |
| 62 | auto_mapped: 0, |
| 63 | errors: ['Slack is not configured (ADDIE_BOT_TOKEN missing)'], |
| 64 | }; |
| 65 | } |
| 66 | |
| 67 | const result: SyncSlackUsersResult = { |
| 68 | total_synced: 0, |
| 69 | new_users: 0, |
| 70 | updated_users: 0, |
| 71 | auto_mapped: 0, |
| 72 | errors: [], |
| 73 | }; |
| 74 | |
| 75 | try { |
| 76 | logger.debug('Starting Slack user sync'); |
| 77 | |
| 78 | // Fetch all users from Slack |
| 79 | const slackUsers = await getSlackUsers(); |
| 80 | logger.debug({ count: slackUsers.length }, 'Fetched users from Slack'); |
| 81 | |
| 82 | // Get existing mappings to track new vs updated |
| 83 | const existingBefore = new Set<string>(); |
| 84 | const existingMappings = await slackDb.getAllMappings({ includeBots: true, includeDeleted: true }); |
| 85 | for (const mapping of existingMappings) { |
| 86 | existingBefore.add(mapping.slack_user_id); |
| 87 | } |
| 88 | |
| 89 | // Upsert each user |
| 90 | for (const user of slackUsers) { |
| 91 | try { |
| 92 | const email = user.profile?.email || null; |
| 93 | const displayName = user.profile?.display_name || user.profile?.display_name_normalized || null; |
| 94 | const realName = user.profile?.real_name || user.real_name || null; |
| 95 | |
| 96 | await slackDb.upsertSlackUser({ |
| 97 | slack_user_id: user.id, |
| 98 | slack_email: email, |
| 99 | slack_display_name: displayName, |
| 100 | slack_real_name: realName, |
| 101 | slack_is_bot: user.is_bot, |
| 102 | slack_is_deleted: user.deleted, |
| 103 | slack_tz_offset: user.tz_offset ?? null, |
| 104 | }); |
| 105 | |
| 106 | result.total_synced++; |
| 107 | |
| 108 | if (existingBefore.has(user.id)) { |
| 109 | result.updated_users++; |
| 110 | } else { |
| 111 | result.new_users++; |
| 112 | } |
| 113 | } catch (error) { |
no test coverage detected