github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/convdevstorage.go (about)

     1  package chat
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  
     7  	"github.com/keybase/client/go/chat/globals"
     8  	"github.com/keybase/client/go/chat/types"
     9  	"github.com/keybase/client/go/chat/utils"
    10  	"github.com/keybase/client/go/protocol/chat1"
    11  	"github.com/keybase/client/go/protocol/gregor1"
    12  	"github.com/keybase/client/go/protocol/keybase1"
    13  )
    14  
    15  type ConvDevConversationBackedStorage struct {
    16  	globals.Contextified
    17  	utils.DebugLabeler
    18  
    19  	adminOnly bool
    20  	topicType chat1.TopicType
    21  	ri        func() chat1.RemoteInterface
    22  }
    23  
    24  var _ types.ConvConversationBackedStorage = &ConvDevConversationBackedStorage{}
    25  
    26  func NewConvDevConversationBackedStorage(g *globals.Context, topicType chat1.TopicType, adminOnly bool,
    27  	ri func() chat1.RemoteInterface) *ConvDevConversationBackedStorage {
    28  	return &ConvDevConversationBackedStorage{
    29  		Contextified: globals.NewContextified(g),
    30  		DebugLabeler: utils.NewDebugLabeler(g.ExternalG(), "ConvDevConversationBackedStorage", false),
    31  		adminOnly:    adminOnly,
    32  		ri:           ri,
    33  		topicType:    topicType,
    34  	}
    35  }
    36  
    37  func (s *ConvDevConversationBackedStorage) getMembersType(conv chat1.ConversationLocal) chat1.ConversationMembersType {
    38  	return conv.GetMembersType()
    39  	/*
    40  		TODO: might need this, not sure
    41  		mt := conv.GetMembersType()
    42  		switch mt {
    43  		case chat1.ConversationMembersType_IMPTEAMUPGRADE:
    44  			return chat1.ConversationMembersType_IMPTEAMNATIVE
    45  		default:
    46  			return mt
    47  		}
    48  	*/
    49  }
    50  
    51  func (s *ConvDevConversationBackedStorage) PutToKnownConv(ctx context.Context, uid gregor1.UID,
    52  	conv chat1.ConversationLocal, src interface{}) (err error) {
    53  	if s.adminOnly && !conv.ReaderInfo.UntrustedTeamRole.IsAdminOrAbove() {
    54  		return NewDevStoragePermissionDeniedError(conv.ReaderInfo.UntrustedTeamRole)
    55  	}
    56  	dat, err := json.Marshal(src)
    57  	if err != nil {
    58  		return err
    59  	}
    60  	if _, _, err = NewBlockingSender(s.G(), NewBoxer(s.G()), s.ri).Send(ctx, conv.GetConvID(),
    61  		chat1.MessagePlaintext{
    62  			ClientHeader: chat1.MessageClientHeader{
    63  				Conv:        conv.Info.Triple,
    64  				TlfName:     conv.Info.TlfName,
    65  				MessageType: chat1.MessageType_TEXT,
    66  			},
    67  			MessageBody: chat1.NewMessageBodyWithText(chat1.MessageText{
    68  				Body: string(dat),
    69  			}),
    70  		}, 0, nil, nil, nil); err != nil {
    71  		return err
    72  	}
    73  	// only do min writer role stuff for team convs
    74  	if conv.GetMembersType() != chat1.ConversationMembersType_TEAM {
    75  		return nil
    76  	}
    77  	minWriterUnset := conv.ConvSettings == nil ||
    78  		conv.ConvSettings.MinWriterRoleInfo == nil ||
    79  		conv.ConvSettings.MinWriterRoleInfo.Role != keybase1.TeamRole_ADMIN
    80  	if s.adminOnly && minWriterUnset {
    81  		arg := chat1.SetConvMinWriterRoleArg{
    82  			ConvID: conv.Info.Id,
    83  			Role:   keybase1.TeamRole_ADMIN,
    84  		}
    85  		_, err := s.ri().SetConvMinWriterRole(ctx, arg)
    86  		if err != nil {
    87  			return err
    88  		}
    89  	}
    90  	return nil
    91  }
    92  
    93  func (s *ConvDevConversationBackedStorage) Put(ctx context.Context, uid gregor1.UID,
    94  	convID chat1.ConversationID, name string, src interface{}) (err error) {
    95  	defer s.Trace(ctx, &err, "Put(%s)", name)()
    96  
    97  	var conv chat1.ConversationLocal
    98  	baseConv, err := utils.GetVerifiedConv(ctx, s.G(), uid, convID, types.InboxSourceDataSourceAll)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	tlfname := baseConv.Info.TlfName
   103  	conv, _, err = NewConversation(ctx, s.G(), uid, tlfname, &name, s.topicType,
   104  		s.getMembersType(baseConv), keybase1.TLFVisibility_PRIVATE, nil, s.ri, NewConvFindExistingNormal)
   105  	if err != nil {
   106  		return err
   107  	}
   108  	return s.PutToKnownConv(ctx, uid, conv, src)
   109  }
   110  
   111  func (s *ConvDevConversationBackedStorage) GetFromKnownConv(ctx context.Context, uid gregor1.UID,
   112  	conv chat1.ConversationLocal, dest interface{}) (found bool, err error) {
   113  	defer s.Trace(ctx, &err, "GetFromKnownConv(%s)", conv.GetConvID())()
   114  	tv, err := s.G().ConvSource.Pull(ctx, conv.GetConvID(), uid, chat1.GetThreadReason_GENERAL, nil,
   115  		&chat1.GetThreadQuery{
   116  			MessageTypes: []chat1.MessageType{chat1.MessageType_TEXT},
   117  		}, &chat1.Pagination{Num: 1})
   118  	if err != nil {
   119  		return false, err
   120  	}
   121  	if len(tv.Messages) == 0 {
   122  		return false, nil
   123  	}
   124  	msg := tv.Messages[0]
   125  	if !msg.IsValid() {
   126  		return false, nil
   127  	}
   128  	body := msg.Valid().MessageBody
   129  	if !body.IsType(chat1.MessageType_TEXT) {
   130  		return false, nil
   131  	}
   132  
   133  	if conv.GetMembersType() == chat1.ConversationMembersType_TEAM && s.adminOnly {
   134  		if conv.ConvSettings == nil || conv.ConvSettings.MinWriterRoleInfo == nil {
   135  			return false, NewDevStorageAdminOnlyError("no conversation settings")
   136  		}
   137  		if conv.ConvSettings.MinWriterRoleInfo.Role != keybase1.TeamRole_ADMIN {
   138  			return false, NewDevStorageAdminOnlyError("minWriterRole was not admin")
   139  		}
   140  	}
   141  	if err = json.Unmarshal([]byte(body.Text().Body), dest); err != nil {
   142  		return false, err
   143  	}
   144  	if err = JoinConversation(ctx, s.G(), s.DebugLabeler, s.ri, uid, conv.GetConvID()); err != nil {
   145  		return false, err
   146  	}
   147  	return true, nil
   148  }
   149  
   150  func (s *ConvDevConversationBackedStorage) Get(ctx context.Context, uid gregor1.UID,
   151  	convID chat1.ConversationID, name string, dest interface{}, createConvIfMissing bool) (found bool, conv *chat1.ConversationLocal, err error) {
   152  	defer s.Trace(ctx, &err, "Get(%s)", name)()
   153  
   154  	baseConv, err := utils.GetVerifiedConv(ctx, s.G(), uid, convID, types.InboxSourceDataSourceAll)
   155  	if err != nil {
   156  		return false, conv, err
   157  	}
   158  	if !createConvIfMissing {
   159  		convs, err := FindConversations(ctx, s.G(), s.DebugLabeler, types.InboxSourceDataSourceAll, s.ri, uid,
   160  			baseConv.Info.TlfName, s.topicType, s.getMembersType(baseConv), keybase1.TLFVisibility_PRIVATE, name,
   161  			nil)
   162  		if err != nil {
   163  			return false, conv, err
   164  		}
   165  		if len(convs) == 0 {
   166  			return false, conv, nil
   167  		}
   168  		conv = &convs[0]
   169  	} else {
   170  		newconv, _, err := NewConversation(ctx, s.G(), uid, baseConv.Info.TlfName, &name, s.topicType,
   171  			s.getMembersType(baseConv), keybase1.TLFVisibility_PRIVATE, nil, s.ri, NewConvFindExistingNormal)
   172  		if err != nil {
   173  			return false, conv, err
   174  		}
   175  		conv = &newconv
   176  	}
   177  	found, err = s.GetFromKnownConv(ctx, uid, *conv, dest)
   178  	return found, conv, err
   179  }