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  }