Brendan Abolivier 2 years ago
commit
e02cc07970
Signed by: Brendan Abolivier <contact@brendanabolivier.com> GPG key ID: 8EF1500759F70623
6 changed files with 256 additions and 0 deletions
  1. 16
    0
      .editorconfig
  2. 5
    0
      .gitignore
  3. 30
    0
      src/config/config.go
  4. 28
    0
      src/fixer/log_config.go
  5. 140
    0
      src/fixer/main.go
  6. 37
    0
      vendor/manifest

+ 16
- 0
.editorconfig View File

@@ -0,0 +1,16 @@
1
+root = true
2
+
3
+[*]
4
+charset = utf-8
5
+
6
+end_of_line = lf
7
+insert_final_newline = false
8
+trim_trailing_whitespace = true
9
+
10
+[*.go]
11
+indent_style = tab
12
+indent_size = 4
13
+
14
+[*.{yml,yaml}]
15
+indent_style = space
16
+indent_size = 2

+ 5
- 0
.gitignore View File

@@ -0,0 +1,5 @@
1
+bin
2
+pkg
3
+vendor/src
4
+
5
+config.yaml

+ 30
- 0
src/config/config.go View File

@@ -0,0 +1,30 @@
1
+package config
2
+
3
+import (
4
+	"io/ioutil"
5
+
6
+	"gopkg.in/yaml.v2"
7
+)
8
+
9
+type Config struct {
10
+	Matrix MatrixConfig `yaml:"matrix"`
11
+}
12
+
13
+type MatrixConfig struct {
14
+	HomeserverURL string `yaml:"homeserver_url"`
15
+	ServerName    string `yaml:"server_name"`
16
+	Localpart     string `yaml:"localpart"`
17
+	AccessToken   string `yaml:"access_token"`
18
+}
19
+
20
+func Parse(path string) (cfg *Config, err error) {
21
+	cfg = new(Config)
22
+
23
+	content, err := ioutil.ReadFile(path)
24
+	if err != nil {
25
+		return
26
+	}
27
+
28
+	err = yaml.Unmarshal(content, cfg)
29
+	return
30
+}

+ 28
- 0
src/fixer/log_config.go View File

@@ -0,0 +1,28 @@
1
+package main
2
+
3
+import (
4
+	"github.com/sirupsen/logrus"
5
+)
6
+
7
+type utcFormatter struct {
8
+	logrus.Formatter
9
+}
10
+
11
+func (f utcFormatter) Format(entry *logrus.Entry) ([]byte, error) {
12
+	entry.Time = entry.Time.UTC()
13
+	return f.Formatter.Format(entry)
14
+}
15
+
16
+func logConfig() error {
17
+	logrus.SetFormatter(&utcFormatter{
18
+		&logrus.TextFormatter{
19
+			TimestampFormat:  "2006-01-02T15:04:05.000000000Z07:00",
20
+			FullTimestamp:    true,
21
+			DisableColors:    false,
22
+			DisableTimestamp: false,
23
+			DisableSorting:   false,
24
+		},
25
+	})
26
+
27
+	return nil
28
+}

+ 140
- 0
src/fixer/main.go View File

@@ -0,0 +1,140 @@
1
+package main
2
+
3
+import (
4
+	"flag"
5
+	"fmt"
6
+	"os"
7
+
8
+	"config"
9
+
10
+	"github.com/matrix-org/gomatrix"
11
+	"github.com/sirupsen/logrus"
12
+)
13
+
14
+// Fixed variables
15
+var (
16
+	// ErrEmptyRoomID is fired if no room ID localpart has been provided, and is
17
+	// followed by the command's usage.
18
+	ErrEmptyRoomID = fmt.Errorf("The room ID localpart cannot be empty")
19
+	// ErrInvalidRoomMembersNb is fired if the number of joined members in the
20
+	// room isn't 3 (i.e.: the user, their friend, and the Facebook bot).
21
+	ErrInvalidRoomMembersNb = fmt.Errorf("Invalid number of members in the room: either the friend hasn't joined yet, or there's more than one friend in the room")
22
+	// WarnNoAvatar is displayed if the friend doesn't have an avatar.
23
+	WarnNoAvatar = "The friend doesn't have an avatar set"
24
+	// WarnNoDisplayName is displayed if the friend doesn't have a display name.
25
+	WarnNoDisplayName = "The friend doesn't have a display name set"
26
+	// InfoAvatarUpdated is displayed if the room's avatar has been updated.
27
+	InfoAvatarUpdated = "Room's avatar updated"
28
+	// InfoNameUpdated is displayed if the room's name has been updated.
29
+	InfoNameUpdated = "Room's name updated"
30
+	// InfoProcessIsOver is displayed once the whole process is over, just before
31
+	// exiting.
32
+	InfoProcessIsOver = "The room has been fully updated. Don't forget to mark it as direct chat in Riot, and to edit its push rules."
33
+)
34
+
35
+// Command line flags
36
+var (
37
+	localpart  = flag.String("room-id-localpart", "", "Room ID localpart")
38
+	configFile = flag.String("config", "config.yaml", "Configuration file")
39
+)
40
+
41
+// MRoomAvatarContent represents the content of the "m.room.avatar" state event.
42
+// https://matrix.org/docs/spec/client_server/r0.3.0.html#m-room-avatar
43
+type MRoomAvatarContent struct {
44
+	URL string `json:"url"`
45
+}
46
+
47
+// MRoomNameContent represents the content of the "m.room.name" state event.
48
+// https://matrix.org/docs/spec/client_server/r0.3.0.html#m-room-name
49
+type MRoomNameContent struct {
50
+	Name string `json:"name"`
51
+}
52
+
53
+func main() {
54
+	logConfig()
55
+
56
+	flag.Parse()
57
+
58
+	if len(*localpart) == 0 {
59
+		logrus.Error(ErrEmptyRoomID)
60
+		flag.Usage()
61
+		os.Exit(1)
62
+	}
63
+
64
+	cfg, err := config.Parse(*configFile)
65
+	if err != nil {
66
+		panic(err)
67
+	}
68
+
69
+	roomID := fmt.Sprintf("!%s:%s", *localpart, cfg.Matrix.ServerName)
70
+	userID := fmt.Sprintf("@%s:%s", cfg.Matrix.Localpart, cfg.Matrix.ServerName)
71
+
72
+	cli, err := gomatrix.NewClient(cfg.Matrix.HomeserverURL, userID, cfg.Matrix.AccessToken)
73
+	if err != nil {
74
+		logrus.Panic(err)
75
+	}
76
+
77
+	membersResp, err := cli.JoinedMembers(roomID)
78
+	if err != nil {
79
+		logrus.Panic(err)
80
+	}
81
+
82
+	displayNameResp, err := cli.GetOwnDisplayName()
83
+	if err != nil {
84
+		logrus.Panic(err)
85
+	}
86
+
87
+	if len(membersResp.Joined) != 3 {
88
+		logrus.Error(ErrInvalidRoomMembersNb)
89
+		os.Exit(1)
90
+	}
91
+
92
+	var avatarURL, displayName string
93
+	for _, member := range membersResp.Joined {
94
+		if member.DisplayName != nil && *(member.DisplayName) != displayNameResp.DisplayName {
95
+			displayName = *(member.DisplayName)
96
+			if member.AvatarURL != nil {
97
+				avatarURL = *(member.AvatarURL)
98
+			}
99
+		}
100
+	}
101
+
102
+	logrus.WithFields(logrus.Fields{
103
+		"display_name": displayName,
104
+		"avatar_url":   avatarURL,
105
+	}).Info("Found the friend")
106
+
107
+	if len(avatarURL) > 0 {
108
+		if _, err := cli.SendStateEvent(
109
+			roomID,
110
+			"m.room.avatar",
111
+			"",
112
+			MRoomAvatarContent{
113
+				URL: avatarURL,
114
+			},
115
+		); err != nil {
116
+			logrus.Panic(err)
117
+		}
118
+		logrus.Info(InfoAvatarUpdated)
119
+	} else {
120
+		logrus.Warn(WarnNoAvatar)
121
+	}
122
+
123
+	if len(displayName) > 0 {
124
+		if _, err := cli.SendStateEvent(
125
+			roomID,
126
+			"m.room.name",
127
+			"",
128
+			MRoomNameContent{
129
+				Name: displayName + " (Facebook)", // TODO: Allow custom suffix
130
+			},
131
+		); err != nil {
132
+			logrus.Panic(err)
133
+		}
134
+		logrus.Info(InfoNameUpdated)
135
+	} else {
136
+		logrus.Warn(WarnNoDisplayName)
137
+	}
138
+
139
+	logrus.Info(InfoProcessIsOver)
140
+}

+ 37
- 0
vendor/manifest View File

@@ -0,0 +1,37 @@
1
+{
2
+	"version": 0,
3
+	"dependencies": [
4
+		{
5
+			"importpath": "github.com/matrix-org/gomatrix",
6
+			"repository": "https://github.com/matrix-org/gomatrix",
7
+			"revision": "eb6a57bae949723df0d4947a03d4136a1f64b784",
8
+			"branch": "master"
9
+		},
10
+		{
11
+			"importpath": "github.com/sirupsen/logrus",
12
+			"repository": "https://github.com/sirupsen/logrus",
13
+			"revision": "ea8897e79973357ba785ac2533559a6297e83c44",
14
+			"branch": "master"
15
+		},
16
+		{
17
+			"importpath": "golang.org/x/crypto/ssh/terminal",
18
+			"repository": "https://go.googlesource.com/crypto",
19
+			"revision": "1a580b3eff7814fc9b40602fd35256c63b50f491",
20
+			"branch": "master",
21
+			"path": "/ssh/terminal"
22
+		},
23
+		{
24
+			"importpath": "golang.org/x/sys/unix",
25
+			"repository": "https://go.googlesource.com/sys",
26
+			"revision": "88eb85aaee56831ad49eaf7aa80d73de9814cde2",
27
+			"branch": "master",
28
+			"path": "/unix"
29
+		},
30
+		{
31
+			"importpath": "gopkg.in/yaml.v2",
32
+			"repository": "https://gopkg.in/yaml.v2",
33
+			"revision": "5420a8b6744d3b0345ab293f6fcba19c978f1183",
34
+			"branch": "master"
35
+		}
36
+	]
37
+}