Go · 1965 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package lifecycle
4
5 import (
6 "context"
7 "errors"
8 "fmt"
9
10 "github.com/tenseleyFlow/shithub/internal/auth/audit"
11 "github.com/tenseleyFlow/shithub/internal/entitlements"
12 reposdb "github.com/tenseleyFlow/shithub/internal/repos/sqlc"
13 )
14
15 // ErrInvalidVisibility is returned when a caller passes a value that
16 // isn't "public" or "private". Handlers should map to a 400.
17 var ErrInvalidVisibility = errors.New("lifecycle: visibility must be public or private")
18
19 // SetVisibility flips a repo between public and private. Forks remain
20 // independent (separate repos at the data layer), and existing clones
21 // already pulled remain — that's git's nature, not a bug. The UI is
22 // responsible for surfacing the "future clones will be private"
23 // caveat to the user.
24 func SetVisibility(ctx context.Context, deps Deps, actorUserID, repoID int64, newVisibility string) error {
25 switch newVisibility {
26 case "public", "private":
27 default:
28 return ErrInvalidVisibility
29 }
30
31 rq := reposdb.New()
32 repo, err := rq.GetRepoByID(ctx, deps.Pool, repoID)
33 if err != nil {
34 return fmt.Errorf("load repo: %w", err)
35 }
36 if string(repo.Visibility) == newVisibility {
37 return nil // idempotent no-op
38 }
39 if repo.OwnerOrgID.Valid && newVisibility == "private" {
40 check, err := entitlements.CheckRepoPrivateVisibility(ctx, entitlements.Deps{Pool: deps.Pool}, repo.OwnerOrgID.Int64, repo.ID)
41 if err != nil {
42 return err
43 }
44 if err := check.Err(); err != nil {
45 return err
46 }
47 }
48
49 if err := rq.SetRepoVisibility(ctx, deps.Pool, reposdb.SetRepoVisibilityParams{
50 ID: repoID,
51 Visibility: reposdb.RepoVisibility(newVisibility),
52 }); err != nil {
53 return fmt.Errorf("set visibility: %w", err)
54 }
55 if deps.Audit != nil {
56 _ = deps.Audit.Record(ctx, deps.Pool, actorUserID,
57 audit.ActionRepoVisibilityChanged, audit.TargetRepo, repoID,
58 map[string]any{"from": string(repo.Visibility), "to": newVisibility})
59 }
60 return nil
61 }
62