github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/teams/showcase_helper.go (about) 1 package teams 2 3 import ( 4 "errors" 5 6 "golang.org/x/net/context" 7 8 "github.com/keybase/client/go/libkb" 9 "github.com/keybase/client/go/protocol/keybase1" 10 ) 11 12 func GetTeamShowcase(ctx context.Context, g *libkb.GlobalContext, teamID keybase1.TeamID) (ret keybase1.TeamShowcase, err error) { 13 arg := apiArg("team/get") 14 arg.Args.Add("id", libkb.S{Val: teamID.String()}) 15 arg.Args.Add("showcase_only", libkb.B{Val: true}) 16 17 var rt rawTeam 18 mctx := libkb.NewMetaContext(ctx, g) 19 if err := mctx.G().API.GetDecode(mctx, arg, &rt); err != nil { 20 return ret, err 21 } 22 return rt.Showcase, nil 23 } 24 25 type memberShowcaseRes struct { 26 Status libkb.AppStatus `json:"status"` 27 IsShowcased bool `json:"is_showcased"` 28 } 29 30 func (c *memberShowcaseRes) GetAppStatus() *libkb.AppStatus { 31 return &c.Status 32 } 33 34 func GetTeamAndMemberShowcase(ctx context.Context, g *libkb.GlobalContext, id keybase1.TeamID) (ret keybase1.TeamAndMemberShowcase, 35 err error) { 36 t, err := Load(ctx, g, keybase1.LoadTeamArg{ 37 ID: id, 38 Public: false, 39 ForceRepoll: true, 40 AllowNameLookupBurstCache: true, 41 }) 42 if err != nil { 43 return ret, fixupTeamGetError(ctx, g, err, id.String(), false) 44 } 45 46 role, err := t.myRole(ctx) 47 if err != nil { 48 return ret, err 49 } 50 51 arg := apiArg("team/get") 52 arg.Args.Add("id", libkb.S{Val: t.ID.String()}) 53 arg.Args.Add("showcase_only", libkb.B{Val: true}) 54 55 var teamRet rawTeam 56 mctx := libkb.NewMetaContext(ctx, g) 57 if err := mctx.G().API.GetDecode(mctx, arg, &teamRet); err != nil { 58 return ret, err 59 } 60 ret.TeamShowcase = teamRet.Showcase 61 62 // team/member_showcase endpoint is available either for 63 // admins/owners, or for everyone if AnyMemberShowcase is set, 64 // but this does not include implicit admins. 65 if (teamRet.Showcase.AnyMemberShowcase && role != keybase1.TeamRole_NONE) || role.IsOrAbove(keybase1.TeamRole_ADMIN) { 66 arg = apiArg("team/member_showcase") 67 arg.Args.Add("tid", libkb.S{Val: t.ID.String()}) 68 69 var memberRet memberShowcaseRes 70 if err := mctx.G().API.GetDecode(mctx, arg, &memberRet); err != nil { 71 if appErr, ok := err.(libkb.AppStatusError); ok && 72 appErr.Code == int(keybase1.StatusCode_SCTeamShowcasePermDenied) { 73 // It is possible that we were still a member when 74 // GetForTeamManagement* was called, but we are not a member 75 // anymore, so `team/member_showcase` fails. Note that this 76 // endpoint does not work for implicit admins, hence the role 77 // checks before calling it - but if we have outdated team 78 // information, we might still end up here not being allowed 79 // to call it and getting this error. 80 mctx.Debug("GetTeamAndMemberShowcase hit a race with team %q", t.Name()) 81 return ret, nil 82 } 83 84 return ret, err 85 } 86 87 ret.IsMemberShowcased = memberRet.IsShowcased 88 } 89 90 return ret, nil 91 } 92 93 func SetTeamShowcase(ctx context.Context, g *libkb.GlobalContext, teamID keybase1.TeamID, isShowcased *bool, 94 description *string, anyMemberShowcase *bool) error { 95 t, err := GetForTeamManagementByTeamID(ctx, g, teamID, true) 96 if err != nil { 97 return err 98 } 99 100 if isShowcased == nil && description == nil && anyMemberShowcase == nil { 101 return errors.New("at least one argument has to be non-nil") 102 } 103 104 arg := apiArg("team/team_showcase") 105 arg.Args.Add("tid", libkb.S{Val: string(t.ID)}) 106 if isShowcased != nil { 107 arg.Args.Add("is_showcased", libkb.B{Val: *isShowcased}) 108 } 109 if description != nil { 110 if len(*description) > 0 { 111 arg.Args.Add("description", libkb.S{Val: *description}) 112 } else { 113 arg.Args.Add("clear_description", libkb.B{Val: true}) 114 } 115 } 116 if anyMemberShowcase != nil { 117 arg.Args.Add("any_member_showcase", libkb.B{Val: *anyMemberShowcase}) 118 } 119 mctx := libkb.NewMetaContext(ctx, g) 120 if _, err := mctx.G().API.Post(mctx, arg); err != nil { 121 return err 122 } 123 return t.notifyNoChainChange(ctx, keybase1.TeamChangeSet{Misc: true}) 124 } 125 126 func SetTeamMemberShowcase(ctx context.Context, g *libkb.GlobalContext, teamID keybase1.TeamID, isShowcased bool) error { 127 mctx := libkb.NewMetaContext(ctx, g) 128 t, err := GetForTeamManagementByTeamID(ctx, g, teamID, false /* needAdmin */) 129 if err != nil { 130 return err 131 } 132 arg := apiArg("team/member_showcase") 133 arg.Args.Add("tid", libkb.S{Val: string(teamID)}) 134 arg.Args.Add("is_showcased", libkb.B{Val: isShowcased}) 135 _, err = mctx.G().API.Post(mctx, arg) 136 if err != nil { 137 return err 138 } 139 140 // Clear usercard cache so when user goes to People tab, 141 // fresh card will be loaded. 142 u := g.ActiveDevice.UID() 143 mctx.Debug("Clearing Card cache for %s", u) 144 if err := g.CardCache().Delete(u); err != nil { 145 mctx.Debug("Error in CardCache.Delete: %s", err) 146 } 147 g.UserChanged(ctx, u) 148 return t.notifyNoChainChange(ctx, keybase1.TeamChangeSet{Misc: true}) 149 }