1package chat 2 3import ( 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 15type ConvDevConversationBackedStorage struct { 16 globals.Contextified 17 utils.DebugLabeler 18 19 adminOnly bool 20 topicType chat1.TopicType 21 ri func() chat1.RemoteInterface 22} 23 24var _ types.ConvConversationBackedStorage = &ConvDevConversationBackedStorage{} 25 26func 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 37func (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 51func (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 93func (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 111func (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 150func (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} 180