|
@@ -4,6 +4,7 @@ import (
|
4
|
4
|
"flag"
|
5
|
5
|
"fmt"
|
6
|
6
|
"os"
|
|
7
|
+ "regexp"
|
7
|
8
|
|
8
|
9
|
"config"
|
9
|
10
|
|
|
@@ -13,9 +14,9 @@ import (
|
13
|
14
|
|
14
|
15
|
// Fixed variables
|
15
|
16
|
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")
|
|
17
|
+ // ErrRoomIDEmptyOrInvalid is fired if no room ID localpart has been provided
|
|
18
|
+ // or is invalid, and is followed by the command's usage.
|
|
19
|
+ ErrRoomIDEmptyOrInvalid = fmt.Errorf("The room ID localpart is either empty or invalid")
|
19
|
20
|
// ErrInvalidRoomMembersNb is fired if the number of joined members in the
|
20
|
21
|
// room isn't 3 (i.e.: the user, their friend, and the Facebook bot).
|
21
|
22
|
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")
|
|
@@ -29,12 +30,12 @@ var (
|
29
|
30
|
InfoNameUpdated = "Room's name updated"
|
30
|
31
|
// InfoProcessIsOver is displayed once the whole process is over, just before
|
31
|
32
|
// 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
|
+ InfoProcessIsOver = "The room has been fully updated. Don't forget to mark it as direct chat in Riot, and to edit its notification rules."
|
33
|
34
|
)
|
34
|
35
|
|
35
|
36
|
// Command line flags
|
36
|
37
|
var (
|
37
|
|
- localpart = flag.String("room-id-localpart", "", "Room ID localpart")
|
|
38
|
+ localpart = flag.String("room-id-localpart", "", "Room ID localpart (i.e. 'ZUFHhmRzEyUdzljKRz')")
|
38
|
39
|
configFile = flag.String("config", "config.yaml", "Configuration file")
|
39
|
40
|
)
|
40
|
41
|
|
|
@@ -55,44 +56,57 @@ func main() {
|
55
|
56
|
|
56
|
57
|
flag.Parse()
|
57
|
58
|
|
58
|
|
- if len(*localpart) == 0 {
|
59
|
|
- logrus.Error(ErrEmptyRoomID)
|
|
59
|
+ // We need the room ID's localpart to be non-empty and only composed of letters.
|
|
60
|
+ roomIDLocalpartRgxp := regexp.MustCompile("^[a-zA-Z]+")
|
|
61
|
+ if len(*localpart) == 0 || !roomIDLocalpartRgxp.Match([]byte(*localpart)) {
|
|
62
|
+ logrus.Error(ErrRoomIDEmptyOrInvalid)
|
60
|
63
|
flag.Usage()
|
61
|
64
|
os.Exit(1)
|
62
|
65
|
}
|
63
|
66
|
|
|
67
|
+ // Load the configuration from the configuration file.
|
64
|
68
|
cfg, err := config.Parse(*configFile)
|
65
|
69
|
if err != nil {
|
66
|
70
|
panic(err)
|
67
|
71
|
}
|
68
|
72
|
|
|
73
|
+ // Compute the room's ID along with the current user's.
|
69
|
74
|
roomID := fmt.Sprintf("!%s:%s", *localpart, cfg.Matrix.ServerName)
|
70
|
75
|
userID := fmt.Sprintf("@%s:%s", cfg.Matrix.Localpart, cfg.Matrix.ServerName)
|
71
|
76
|
|
|
77
|
+ // Load the Matrix client from configuration data.
|
72
|
78
|
cli, err := gomatrix.NewClient(cfg.Matrix.HomeserverURL, userID, cfg.Matrix.AccessToken)
|
73
|
79
|
if err != nil {
|
74
|
80
|
logrus.Panic(err)
|
75
|
81
|
}
|
76
|
82
|
|
|
83
|
+ // Retrieve the list of joined members in the room.
|
77
|
84
|
membersResp, err := cli.JoinedMembers(roomID)
|
78
|
85
|
if err != nil {
|
79
|
86
|
logrus.Panic(err)
|
80
|
87
|
}
|
81
|
88
|
|
|
89
|
+ // Retrieve the current user's own display name.
|
82
|
90
|
displayNameResp, err := cli.GetOwnDisplayName()
|
83
|
91
|
if err != nil {
|
84
|
92
|
logrus.Panic(err)
|
85
|
93
|
}
|
86
|
94
|
|
|
95
|
+ // Check if the number of joined members is three, as it should be with a
|
|
96
|
+ // 1:1 puppeted chat (the current user, their friend, and the AS bot).
|
87
|
97
|
if len(membersResp.Joined) != 3 {
|
88
|
98
|
logrus.Error(ErrInvalidRoomMembersNb)
|
89
|
99
|
os.Exit(1)
|
90
|
100
|
}
|
91
|
101
|
|
|
102
|
+ // Iterate over the slice of joined members.
|
92
|
103
|
var avatarURL, displayName string
|
93
|
104
|
for _, member := range membersResp.Joined {
|
|
105
|
+ // The friend should be the only joined member who has a display name set
|
|
106
|
+ // which isn't the same as the current user's.
|
94
|
107
|
if member.DisplayName != nil && *(member.DisplayName) != displayNameResp.DisplayName {
|
95
|
108
|
displayName = *(member.DisplayName)
|
|
109
|
+ // If there's also an avatar set for the friend, use it.
|
96
|
110
|
if member.AvatarURL != nil {
|
97
|
111
|
avatarURL = *(member.AvatarURL)
|
98
|
112
|
}
|
|
@@ -104,6 +118,8 @@ func main() {
|
104
|
118
|
"avatar_url": avatarURL,
|
105
|
119
|
}).Info("Found the friend")
|
106
|
120
|
|
|
121
|
+ // If the avatar has been found, set it as the room's avatar using a
|
|
122
|
+ // m.room.avatar state event.
|
107
|
123
|
if len(avatarURL) > 0 {
|
108
|
124
|
if _, err := cli.SendStateEvent(
|
109
|
125
|
roomID,
|
|
@@ -117,9 +133,13 @@ func main() {
|
117
|
133
|
}
|
118
|
134
|
logrus.Info(InfoAvatarUpdated)
|
119
|
135
|
} else {
|
|
136
|
+ // Else print a warning so the user can see it clearly.
|
120
|
137
|
logrus.Warn(WarnNoAvatar)
|
121
|
138
|
}
|
122
|
139
|
|
|
140
|
+ // If the display name has been found, set it as the room's name using a
|
|
141
|
+ // m.room.name state event. This condition shouldn't be necessary, but heh,
|
|
142
|
+ // at least that might cover a potential regression from the bridge.
|
123
|
143
|
if len(displayName) > 0 {
|
124
|
144
|
if _, err := cli.SendStateEvent(
|
125
|
145
|
roomID,
|
|
@@ -133,8 +153,12 @@ func main() {
|
133
|
153
|
}
|
134
|
154
|
logrus.Info(InfoNameUpdated)
|
135
|
155
|
} else {
|
|
156
|
+ // Else print a warning so the user can see it clearly.
|
136
|
157
|
logrus.Warn(WarnNoDisplayName)
|
137
|
158
|
}
|
138
|
159
|
|
|
160
|
+ // Print a shiny message telling the user the process is over, but it's up
|
|
161
|
+ // to them to set the room as a direct chat and to update the room's push
|
|
162
|
+ // notification settings, since that's not supported by gomatrix.
|
139
|
163
|
logrus.Info(InfoProcessIsOver)
|
140
|
164
|
}
|