func TestSlackMeMessage(t *testing.T) { mockMatrixClient := &MockMatrixClient{} mockSlackClient := &MockSlackClient{} db := makeDB(t) rooms, err := NewRoomMap(db) if err != nil { t.Fatal(err) } rooms.Link(matrix.NewRoom("!abc123:matrix.org"), "CANTINA") echoSuppresser := common.NewEchoSuppresser() users, err := NewUserMap(db, http.Client{}, rooms, echoSuppresser) if err != nil { t.Fatal(err) } matrixUser := matrix.NewUser("@nancy:st.andrews", mockMatrixClient) slackUser := &slack.User{"U34", mockSlackClient} users.Link(matrixUser, slackUser) bridge := Bridge{users, rooms, nil, nil, http.Client{}, echoSuppresser, Config{}} bridge.OnSlackMessage(slack.Message{ Type: "message", Channel: "CANTINA", User: "******", Subtype: "me_message", Text: "takes more chances", }) want := []call{call{"SendEmote", []interface{}{"!abc123:matrix.org", "takes more chances"}}} if !reflect.DeepEqual(mockMatrixClient.calls, want) { t.Fatalf("Wrong Matrix calls, want %v got %v", want, mockMatrixClient.calls) } }
func makeBridge(t *testing.T, db *sql.DB) *Bridge { mockMatrixClient := &MockMatrixClient{} mockSlackClient := &MockSlackClient{} rooms, err := NewRoomMap(db) if err != nil { t.Fatal(err) } echoSuppresser := common.NewEchoSuppresser() users, err := NewUserMap(db, http.Client{}, rooms, echoSuppresser) if err != nil { t.Fatal(err) } matrixUser := matrix.NewUser("@nancy:st.andrews", mockMatrixClient) slackUser := &slack.User{"U34", mockSlackClient} users.Link(matrixUser, slackUser) // Subsequent calls should load link from database, but don't yet if err := rooms.Link(matrix.NewRoom("!abc123:matrix.org"), "CANTINA"); err != nil { t.Fatalf("Error linking rooms: %v", err) } return &Bridge{users, rooms, nil, nil, http.Client{}, echoSuppresser, Config{}} }
func TestMatrixImageMessage(t *testing.T) { mockMatrixClient := &MockMatrixClient{} mockSlackClient := &MockSlackClient{} db := makeDB(t) rooms, err := NewRoomMap(db) if err != nil { t.Fatal(err) } rooms.Link(matrix.NewRoom("!abc123:matrix.org"), "BOWLINGALLEY") echoSuppresser := common.NewEchoSuppresser() users, err := NewUserMap(db, http.Client{}, rooms, echoSuppresser) if err != nil { t.Fatal(err) } matrixUser := matrix.NewUser("@sean:st.andrews", mockMatrixClient) slackUser := &slack.User{"U35", mockSlackClient} users.Link(matrixUser, slackUser) bridge := Bridge{users, rooms, nil, nil, http.Client{}, echoSuppresser, Config{ HomeserverBaseURL: "https://some.url:1234", }} bridge.OnMatrixRoomMessage(matrix.RoomMessage{ Type: "m.room.message", Content: []byte(`{"msgtype": "m.image", "body": "It's Nancy!", "url": "mxc://some.homeserver/abcDEF"}`), UserID: "@sean:st.andrews", RoomID: "!abc123:matrix.org", }) want := []call{call{"SendImage", []interface{}{"BOWLINGALLEY", "It's Nancy!", "https://some.url:1234/_matrix/media/v1/download/some.homeserver/abcDEF"}}} if !reflect.DeepEqual(mockSlackClient.calls, want) { t.Fatalf("Wrong Slack calls, want %v got %v", want, mockSlackClient.calls) } }
func TestSlackMessageWithImage(t *testing.T) { mockMatrixClient := &MockMatrixClient{} mockSlackClient := &MockSlackClient{} db := makeDB(t) rooms, err := NewRoomMap(db) if err != nil { t.Fatal(err) } rooms.Link(matrix.NewRoom("!abc123:matrix.org"), "CANTINA") echoSuppresser := common.NewEchoSuppresser() users, err := NewUserMap(db, http.Client{}, rooms, echoSuppresser) if err != nil { t.Fatal(err) } matrixUser := matrix.NewUser("@nancy:st.andrews", mockMatrixClient) slackUser := &slack.User{"U34", mockSlackClient} users.Link(matrixUser, slackUser) bridge := Bridge{users, rooms, nil, nil, http.Client{}, echoSuppresser, Config{}} imageURL := "https://slack-files.com/files-pub/T02TMLW97-F0D2M81QA-38528eaf47/otters.jpg" bridge.OnSlackMessage(slack.Message{ Type: "message", Channel: "CANTINA", User: "******", Text: "Cute otter", File: &slack.File{ MIMEType: "image/jpeg", URL: imageURL, OriginalHeight: 768, OriginalWidth: 1024, Size: 90, CommentsCount: 1, InitialComment: &slack.Comment{ Comment: "omg", User: "******", }, }, }) want := []call{ call{"SendImage", []interface{}{"!abc123:matrix.org", "otters.jpg", matrix.Image{ URL: imageURL, Info: &matrix.ImageInfo{ Width: 1024, Height: 768, MIMEType: "image/jpeg", Size: 90, }, }}}, call{"SendText", []interface{}{"!abc123:matrix.org", "omg"}}, } if !reflect.DeepEqual(mockMatrixClient.calls, want) { t.Fatalf("Wrong Matrix calls, want:\n%v\ngot:\n%v", want, mockMatrixClient.calls) } }
func (b *Bridge) matrixUserFor(slackChannel, slackUserID string, matrixRoom *matrix.Room) *matrix.User { slackUserInRoom := b.SlackRoomMembers.Any(slackChannel) if slackUserInRoom == nil { return nil } resp, err := b.Client.Get(fmt.Sprintf("https://slack.com/api/users.info?token=%s&user=%s", slackUserInRoom.Client.AccessToken(), slackUserID)) if err != nil { log.Printf("Error looking up user %q: %v", slackUserID, err) return nil } defer resp.Body.Close() respBytes, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("Error reading user info response: %v", err) return nil } var r slackUserInfoResponse if err := json.Unmarshal(respBytes, &r); err != nil { log.Printf("Error unmarshaling user info response: %v (%s)", err, string(respBytes)) return nil } if r.User == nil { log.Printf("Ignoring slack message from non-slack user - probably our own Matrix bot") return nil } b.MatrixUsers.Mu.Lock() matrixUserID := b.Config.UserPrefix + r.User.Name + ":" + b.Config.HomeserverName user := b.MatrixUsers.Get_Locked(matrixUserID) if user == nil { client := matrix.NewBotClient(b.Config.MatrixASAccessToken, matrixUserID, b.Client, b.Config.HomeserverBaseURL, b.MatrixEchoSuppresser) user = matrix.NewUser(matrixUserID, client) b.MatrixUsers.Save_Locked(user) } b.MatrixUsers.Mu.Unlock() if !user.Rooms(false)[matrixRoom.ID] { if err := b.matrixBotClient().JoinRoom(matrixRoom.ID); err != nil { log.Printf("Error joining bot to room: %v", err) } if err := b.matrixBotClient().Invite(matrixRoom.ID, matrixUserID); err != nil { log.Printf("Error inviting to room: %v", err) } if err := user.JoinRoom(matrixRoom.ID); err != nil { log.Printf("Error joining room: %v", err) return nil } } return user }
func NewUserMap(db *sql.DB, httpClient http.Client, rooms *RoomMap, matrixEchoSuppresser *common.EchoSuppresser) (*UserMap, error) { m := &UserMap{ matrixToSlack: make(map[string]*slack.User), slackToMatrix: make(map[string]*matrix.User), db: db, matrixEchoSuppresser: matrixEchoSuppresser, } rows, err := db.Query("SELECT id, slack_user_id, slack_access_token, matrix_user_id, matrix_access_token, matrix_homeserver FROM users ORDER BY id ASC") if err != nil { return nil, err } for rows.Next() { var id int32 var slackID, matrixID string var slackToken, matrixToken, matrixHomeserver sql.NullString if err := rows.Scan(&id, &slackID, &slackToken, &matrixID, &matrixToken, &matrixHomeserver); err != nil { return nil, err } if !matrixToken.Valid { log.Printf("Skipping user matrix:%q = slack:%q because no matrix token", matrixID, slackID) continue } if !matrixHomeserver.Valid { log.Printf("Skipping user matrix:%q = slack:%q because no matrix homeserver", matrixID, slackID) continue } if !slackToken.Valid { log.Printf("Skipping user matrix:%q = slack:%q because no slack token", matrixID, slackID) continue } matrixClient := matrix.NewClient(matrixToken.String, httpClient, matrixHomeserver.String, m.matrixEchoSuppresser) matrixUser := matrix.NewUser(matrixID, matrixClient) slackClient := slack.NewClient(slackToken.String, httpClient, rooms.ShouldNotify) slackUser := &slack.User{slackID, slackClient} if err := m.Link(matrixUser, slackUser); err != nil { return nil, err } } if rows.Err() != nil { return nil, rows.Err() } return m, nil }
func TestUserMapLoadsConfig(t *testing.T) { dir, err := ioutil.TempDir("", "testdb") if err != nil { t.Fatal(err) } file := path.Join(dir, "sqlite3.db") db := makeDBAt(t, file) rooms, err := NewRoomMap(db) if err != nil { t.Fatal(err) } users, err := NewUserMap(db, http.Client{}, rooms, common.NewEchoSuppresser()) if err != nil { t.Fatal(err) } matrixID := "@foo:somewhere.com" slackID := "bar" matrixUser := matrix.NewUser(matrixID, &MockMatrixClient{}) users.Link(matrixUser, &slack.User{slackID, &MockSlackClient{}}) db.Close() db, err = sql.Open("sqlite3", file) if err != nil { t.Fatal(err) } rooms, err = NewRoomMap(db) if err != nil { t.Fatal(err) } users, err = NewUserMap(db, http.Client{}, rooms, common.NewEchoSuppresser()) if err != nil { t.Fatal(err) } got := users.SlackForMatrix(matrixID) if got == nil { t.Fatalf("got nil user, want user ID %q", slackID) } if got.UserID != slackID { t.Errorf("want %q got %q", slackID, got.UserID) } }