| 1 | // SPDX-License-Identifier: AGPL-3.0-or-later |
| 2 | |
| 3 | package social |
| 4 | |
| 5 | import ( |
| 6 | "context" |
| 7 | "fmt" |
| 8 | |
| 9 | socialdb "github.com/tenseleyFlow/shithub/internal/social/sqlc" |
| 10 | ) |
| 11 | |
| 12 | // AutoWatchOnCollab inserts a `level='all'` row when no preference |
| 13 | // exists. Triggered by S15's collaborator-add path. Non-destructive: |
| 14 | // if the user has already chosen a level (including `ignore`), their |
| 15 | // choice is preserved. |
| 16 | // |
| 17 | // Matches GitHub: collaborators get full notifications by default; |
| 18 | // they can opt down to `participating` or `ignore` later. |
| 19 | func AutoWatchOnCollab(ctx context.Context, deps Deps, userID, repoID int64) error { |
| 20 | return autoWatch(ctx, deps, userID, repoID, WatchAll) |
| 21 | } |
| 22 | |
| 23 | // AutoWatchOnInvolvement inserts a `level='participating'` row when |
| 24 | // no preference exists. Triggered by issues.AddComment, mention |
| 25 | // resolution, assignment, review-requested. Non-destructive. |
| 26 | // |
| 27 | // Matches GitHub: any first-touch involvement (commenting, getting |
| 28 | // mentioned, getting assigned) auto-subscribes the user to that |
| 29 | // thread's notifications, but only at the participating level so a |
| 30 | // drive-by mention doesn't flood them with future events. |
| 31 | func AutoWatchOnInvolvement(ctx context.Context, deps Deps, userID, repoID int64) error { |
| 32 | return autoWatch(ctx, deps, userID, repoID, WatchParticipating) |
| 33 | } |
| 34 | |
| 35 | // autoWatch is the shared implementation. The InsertIfAbsent query's |
| 36 | // ON CONFLICT DO NOTHING is what makes this safe to call repeatedly |
| 37 | // from any orchestrator without coordinating "first call" semantics. |
| 38 | func autoWatch(ctx context.Context, deps Deps, userID, repoID int64, level WatchLevel) error { |
| 39 | if userID == 0 { |
| 40 | // Anonymous can't auto-watch. Not an error — the caller may |
| 41 | // not know whether the actor is logged in. |
| 42 | return nil |
| 43 | } |
| 44 | if err := socialdb.New().InsertWatchIfAbsent(ctx, deps.Pool, socialdb.InsertWatchIfAbsentParams{ |
| 45 | UserID: userID, |
| 46 | RepoID: repoID, |
| 47 | Level: socialdb.WatchLevel(level), |
| 48 | }); err != nil { |
| 49 | return fmt.Errorf("auto-watch %s: %w", level, err) |
| 50 | } |
| 51 | return nil |
| 52 | } |
| 53 |