* Upsert user to local users table * Called on user.created and user.updated events
(user: UserData)
| 239 | * Called on user.created and user.updated events |
| 240 | */ |
| 241 | async function upsertUser(user: UserData): Promise<void> { |
| 242 | const pool = getPool(); |
| 243 | |
| 244 | // Resolve names: prefer WorkOS values, but when WorkOS sends empty names, |
| 245 | // preserve existing DB values or backfill from Slack mapping |
| 246 | let firstName = user.first_name; |
| 247 | let lastName = user.last_name; |
| 248 | |
| 249 | if (!firstName?.trim() || !lastName?.trim()) { |
| 250 | const existing = await pool.query<{ |
| 251 | first_name: string | null; |
| 252 | last_name: string | null; |
| 253 | slack_real_name: string | null; |
| 254 | slack_display_name: string | null; |
| 255 | }>( |
| 256 | `SELECT u.first_name, u.last_name, sm.slack_real_name, sm.slack_display_name |
| 257 | FROM users u |
| 258 | LEFT JOIN slack_user_mappings sm ON sm.slack_user_id = u.primary_slack_user_id |
| 259 | WHERE u.workos_user_id = $1`, |
| 260 | [user.id] |
| 261 | ); |
| 262 | |
| 263 | if (existing.rows.length > 0) { |
| 264 | const row = existing.rows[0]; |
| 265 | |
| 266 | // Keep existing DB names if WorkOS sends empty |
| 267 | if (!firstName?.trim()) firstName = row.first_name; |
| 268 | if (!lastName?.trim()) lastName = row.last_name; |
| 269 | |
| 270 | // Backfill from Slack if still empty |
| 271 | if (!firstName?.trim() && !lastName?.trim()) { |
| 272 | const slackName = row.slack_real_name || row.slack_display_name; |
| 273 | if (slackName) { |
| 274 | const parts = slackName.trim().split(/\s+/); |
| 275 | firstName = parts[0]; |
| 276 | lastName = parts.length > 1 ? parts.slice(1).join(' ') : null; |
| 277 | } |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | await pool.query( |
| 283 | `INSERT INTO users ( |
| 284 | workos_user_id, |
| 285 | email, |
| 286 | first_name, |
| 287 | last_name, |
| 288 | email_verified, |
| 289 | workos_created_at, |
| 290 | workos_updated_at, |
| 291 | created_at, |
| 292 | updated_at |
| 293 | ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) |
| 294 | ON CONFLICT (workos_user_id) DO UPDATE SET |
| 295 | email = EXCLUDED.email, |
| 296 | first_name = COALESCE(NULLIF(TRIM(EXCLUDED.first_name), ''), users.first_name), |
| 297 | last_name = COALESCE(NULLIF(TRIM(EXCLUDED.last_name), ''), users.last_name), |
| 298 | email_verified = EXCLUDED.email_verified, |