Monorepo for Tangled tangled.org
2

Configure Feed

Select the types of activity you want to include in your feed.

1package knotserver 2 3import ( 4 "context" 5 "fmt" 6 "log/slog" 7 "slices" 8 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 11 "tangled.org/core/knotserver/db" 12 "tangled.org/core/rbac" 13) 14 15const ( 16 collaboratorBackfillMigration = "backfill-collaborators-from-casbin-v1" 17 knotMemberBackfillMigration = "backfill-knot-members-from-casbin-v1" 18) 19 20func BackfillKnotMembers( 21 ctx context.Context, 22 d *db.DB, 23 e *rbac.Enforcer, 24 ownerDid string, 25 logger *slog.Logger, 26) error { 27 l := logger.With("migration", knotMemberBackfillMigration) 28 29 applied, err := d.IsMigrationApplied(knotMemberBackfillMigration) 30 if err != nil { 31 return fmt.Errorf("check migration applied: %w", err) 32 } 33 if applied { 34 return nil 35 } 36 37 owner, err := syntax.ParseDID(ownerDid) 38 if err != nil { 39 return fmt.Errorf("invalid knot owner DID %q: %w", ownerDid, err) 40 } 41 42 members, err := e.GetKnotUsersByRole("server:member", rbac.ThisServer) 43 if err != nil { 44 return fmt.Errorf("list members: %w", err) 45 } 46 owners, err := e.GetKnotUsersByRole("server:owner", rbac.ThisServer) 47 if err != nil { 48 return fmt.Errorf("list owners: %w", err) 49 } 50 51 var rows []db.KnotMember 52 for _, candidate := range members { 53 if slices.Contains(owners, candidate) { 54 continue 55 } 56 subject, err := syntax.ParseDID(candidate) 57 if err != nil { 58 l.Warn("skipping member with invalid DID", "candidate", candidate, "err", err) 59 continue 60 } 61 rows = append(rows, db.KnotMember{Did: owner, Subject: subject}) 62 } 63 64 if err := d.ApplyKnotMemberBackfill(ctx, rows, knotMemberBackfillMigration); err != nil { 65 return fmt.Errorf("apply backfill: %w", err) 66 } 67 68 l.Info("backfilled knot members from casbin", "count", len(rows)) 69 return nil 70} 71 72func BackfillCollaborators( 73 ctx context.Context, 74 d *db.DB, 75 e *rbac.Enforcer, 76 logger *slog.Logger, 77 markApplied bool, 78) error { 79 l := logger.With("migration", collaboratorBackfillMigration) 80 81 applied, err := d.IsMigrationApplied(collaboratorBackfillMigration) 82 if err != nil { 83 return fmt.Errorf("check migration applied: %w", err) 84 } 85 if applied { 86 return nil 87 } 88 89 repoDids, err := d.ListRepoDids() 90 if err != nil { 91 return fmt.Errorf("list repos: %w", err) 92 } 93 94 var rows []db.Collaborator 95 for _, repoDid := range repoDids { 96 ownerDid, _, err := d.GetRepoKeyOwner(repoDid) 97 if err != nil { 98 l.Warn("skipping repo during collaborator backfill", "repoDid", repoDid, "err", err) 99 continue 100 } 101 102 repo, err := syntax.ParseDID(repoDid) 103 if err != nil { 104 l.Warn("skipping repo with invalid DID", "repoDid", repoDid, "err", err) 105 continue 106 } 107 owner, err := syntax.ParseDID(ownerDid) 108 if err != nil { 109 l.Warn("skipping repo with invalid owner DID", "repoDid", repoDid, "owner", ownerDid, "err", err) 110 continue 111 } 112 113 collaborators, err := e.GetUserByRoleInRepo("repo:collaborator", rbac.ThisServer, repoDid) 114 if err != nil { 115 return fmt.Errorf("list collaborators for %s: %w", repoDid, err) 116 } 117 118 for _, candidate := range collaborators { 119 subject, err := syntax.ParseDID(candidate) 120 if err != nil { 121 l.Warn("skipping collaborator with invalid DID", "repoDid", repoDid, "candidate", candidate, "err", err) 122 continue 123 } 124 rows = append(rows, db.Collaborator{ 125 RepoDid: repo, 126 Subject: subject, 127 AddedBy: owner, 128 }) 129 } 130 } 131 132 if err := d.ApplyCollaboratorBackfill(ctx, rows, collaboratorBackfillMigration, markApplied); err != nil { 133 return fmt.Errorf("apply backfill: %w", err) 134 } 135 136 l.Info("backfilled collaborators from casbin", "count", len(rows), "repos", len(repoDids), "marked", markApplied) 137 return nil 138}