Refactor room creation to allow initial_state

This commit is contained in:
Neil Alexander 2021-07-21 10:36:01 +01:00
parent c6acb94af4
commit a021136576
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944

View file

@ -43,7 +43,7 @@ type createRoomRequest struct {
Visibility string `json:"visibility"` Visibility string `json:"visibility"`
Topic string `json:"topic"` Topic string `json:"topic"`
Preset string `json:"preset"` Preset string `json:"preset"`
CreationContent map[string]interface{} `json:"creation_content"` CreationContent json.RawMessage `json:"creation_content"`
InitialState []fledglingEvent `json:"initial_state"` InitialState []fledglingEvent `json:"initial_state"`
RoomAliasName string `json:"room_alias_name"` RoomAliasName string `json:"room_alias_name"`
GuestCanJoin bool `json:"guest_can_join"` GuestCanJoin bool `json:"guest_can_join"`
@ -177,11 +177,6 @@ func createRoom(
// Clobber keys: creator, room_version // Clobber keys: creator, room_version
if r.CreationContent == nil {
r.CreationContent = make(map[string]interface{}, 2)
}
r.CreationContent["creator"] = userID
roomVersion := roomserverVersion.DefaultRoomVersion() roomVersion := roomserverVersion.DefaultRoomVersion()
if r.RoomVersion != "" { if r.RoomVersion != "" {
candidateVersion := gomatrixserverlib.RoomVersion(r.RoomVersion) candidateVersion := gomatrixserverlib.RoomVersion(r.RoomVersion)
@ -194,7 +189,6 @@ func createRoom(
} }
roomVersion = candidateVersion roomVersion = candidateVersion
} }
r.CreationContent["room_version"] = roomVersion
// TODO: visibility/presets/raw initial state // TODO: visibility/presets/raw initial state
// TODO: Create room alias association // TODO: Create room alias association
@ -203,7 +197,7 @@ func createRoom(
logger.WithFields(log.Fields{ logger.WithFields(log.Fields{
"userID": userID, "userID": userID,
"roomID": roomID, "roomID": roomID,
"roomVersion": r.CreationContent["room_version"], "roomVersion": roomVersion,
}).Info("Creating new room") }).Info("Creating new room")
profile, err := appserviceAPI.RetrieveUserProfile(req.Context(), userID, asAPI, accountDB) profile, err := appserviceAPI.RetrieveUserProfile(req.Context(), userID, asAPI, accountDB)
@ -212,6 +206,98 @@ func createRoom(
return jsonerror.InternalServerError() return jsonerror.InternalServerError()
} }
powerLevelContent := eventutil.InitialPowerLevelsContent(userID)
joinRuleContent := gomatrixserverlib.JoinRuleContent{
JoinRule: gomatrixserverlib.Invite,
}
historyVisibilityContent := gomatrixserverlib.HistoryVisibilityContent{
HistoryVisibility: historyVisibilityShared,
}
if r.PowerLevelContentOverride != nil {
// Merge powerLevelContentOverride fields by unmarshalling it atop the defaults
err = json.Unmarshal(r.PowerLevelContentOverride, &powerLevelContent)
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: jsonerror.BadJSON("malformed power_level_content_override"),
}
}
}
switch r.Preset {
case presetPrivateChat:
joinRuleContent.JoinRule = gomatrixserverlib.Invite
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
case presetTrustedPrivateChat:
joinRuleContent.JoinRule = gomatrixserverlib.Invite
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
// TODO If trusted_private_chat, all invitees are given the same power level as the room creator.
case presetPublicChat:
joinRuleContent.JoinRule = gomatrixserverlib.Public
historyVisibilityContent.HistoryVisibility = historyVisibilityShared
}
createEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomCreate,
Content: gomatrixserverlib.CreateContent{
Creator: userID,
RoomVersion: &roomVersion,
},
}
powerLevelEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomPowerLevels,
Content: powerLevelContent,
}
joinRuleEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomJoinRules,
Content: joinRuleContent,
}
historyVisibilityEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomHistoryVisibility,
Content: historyVisibilityContent,
}
membershipEvent := fledglingEvent{
Type: gomatrixserverlib.MRoomHistoryVisibility,
StateKey: userID,
Content: gomatrixserverlib.MemberContent{
Membership: gomatrixserverlib.Join,
DisplayName: profile.DisplayName,
AvatarURL: profile.AvatarURL,
},
}
var nameEvent *fledglingEvent
var topicEvent *fledglingEvent
var guestAccessEvent *fledglingEvent
if r.Name != "" {
nameEvent = &fledglingEvent{
Type: gomatrixserverlib.MRoomName,
Content: eventutil.NameContent{
Name: r.Name,
},
}
}
if r.Topic != "" {
topicEvent = &fledglingEvent{
Type: "m.room.topic",
Content: eventutil.TopicContent{
Topic: r.Topic,
},
}
}
if r.GuestCanJoin {
guestAccessEvent = &fledglingEvent{
Type: "m.room.guest_access",
Content: eventutil.GuestAccessContent{
GuestAccess: "can_join",
},
}
}
var roomAlias string var roomAlias string
if r.RoomAliasName != "" { if r.RoomAliasName != "" {
roomAlias = fmt.Sprintf("#%s:%s", r.RoomAliasName, cfg.Matrix.ServerName) roomAlias = fmt.Sprintf("#%s:%s", r.RoomAliasName, cfg.Matrix.ServerName)
@ -232,42 +318,32 @@ func createRoom(
} }
} }
membershipContent := gomatrixserverlib.MemberContent{ var initialStateEvents []fledglingEvent
Membership: gomatrixserverlib.Join, for i := range r.InitialState {
DisplayName: profile.DisplayName, switch r.InitialState[i].Type {
AvatarURL: profile.AvatarURL, case gomatrixserverlib.MRoomCreate:
} createEvent = r.InitialState[i]
case gomatrixserverlib.MRoomPowerLevels:
powerLevelEvent = r.InitialState[i]
case gomatrixserverlib.MRoomJoinRules:
joinRuleEvent = r.InitialState[i]
case gomatrixserverlib.MRoomHistoryVisibility:
historyVisibilityEvent = r.InitialState[i]
case "m.room.guest_access":
guestAccessEvent = &r.InitialState[i]
case gomatrixserverlib.MRoomName:
nameEvent = &r.InitialState[i]
case "m.room.topic":
topicEvent = &r.InitialState[i]
var joinRules, historyVisibility string
switch r.Preset {
case presetPrivateChat:
joinRules = gomatrixserverlib.Invite
historyVisibility = historyVisibilityShared
case presetTrustedPrivateChat:
joinRules = gomatrixserverlib.Invite
historyVisibility = historyVisibilityShared
// TODO If trusted_private_chat, all invitees are given the same power level as the room creator.
case presetPublicChat:
joinRules = gomatrixserverlib.Public
historyVisibility = historyVisibilityShared
default: default:
// Default room rules, r.Preset was previously checked for valid values so initialStateEvents = append(initialStateEvents, r.InitialState[i])
// only a request with no preset should end up here.
joinRules = gomatrixserverlib.Invite
historyVisibility = historyVisibilityShared
}
var builtEvents []*gomatrixserverlib.HeaderedEvent
powerLevelContent := eventutil.InitialPowerLevelsContent(userID)
if r.PowerLevelContentOverride != nil {
// Merge powerLevelContentOverride fields by unmarshalling it atop the defaults
err = json.Unmarshal(r.PowerLevelContentOverride, &powerLevelContent)
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: jsonerror.BadJSON("malformed power_level_content_override"),
}
} }
} }
@ -290,11 +366,16 @@ func createRoom(
// harder to reason about, hence sticking to a strict static ordering. // harder to reason about, hence sticking to a strict static ordering.
// TODO: Synapse has txn/token ID on each event. Do we need to do this here? // TODO: Synapse has txn/token ID on each event. Do we need to do this here?
eventsToMake := []fledglingEvent{ eventsToMake := []fledglingEvent{
{"m.room.create", "", r.CreationContent}, createEvent, membershipEvent, powerLevelEvent, joinRuleEvent, historyVisibilityEvent,
{"m.room.member", userID, membershipContent}, }
{"m.room.power_levels", "", powerLevelContent}, if guestAccessEvent != nil {
{"m.room.join_rules", "", gomatrixserverlib.JoinRuleContent{JoinRule: joinRules}}, eventsToMake = append(eventsToMake, *guestAccessEvent)
{"m.room.history_visibility", "", eventutil.HistoryVisibilityContent{HistoryVisibility: historyVisibility}}, }
if nameEvent != nil {
eventsToMake = append(eventsToMake, *nameEvent)
}
if topicEvent != nil {
eventsToMake = append(eventsToMake, *topicEvent)
} }
if roomAlias != "" { if roomAlias != "" {
// TODO: bit of a chicken and egg problem here as the alias doesn't exist and cannot until we have made the room. // TODO: bit of a chicken and egg problem here as the alias doesn't exist and cannot until we have made the room.
@ -302,19 +383,12 @@ func createRoom(
// m.room.aliases is handled when we call roomserver.SetRoomAlias // m.room.aliases is handled when we call roomserver.SetRoomAlias
eventsToMake = append(eventsToMake, fledglingEvent{"m.room.canonical_alias", "", eventutil.CanonicalAlias{Alias: roomAlias}}) eventsToMake = append(eventsToMake, fledglingEvent{"m.room.canonical_alias", "", eventutil.CanonicalAlias{Alias: roomAlias}})
} }
if r.GuestCanJoin { eventsToMake = append(eventsToMake, initialStateEvents...)
eventsToMake = append(eventsToMake, fledglingEvent{"m.room.guest_access", "", eventutil.GuestAccessContent{GuestAccess: "can_join"}})
}
eventsToMake = append(eventsToMake, r.InitialState...)
if r.Name != "" {
eventsToMake = append(eventsToMake, fledglingEvent{"m.room.name", "", eventutil.NameContent{Name: r.Name}})
}
if r.Topic != "" {
eventsToMake = append(eventsToMake, fledglingEvent{"m.room.topic", "", eventutil.TopicContent{Topic: r.Topic}})
}
// TODO: invite events // TODO: invite events
// TODO: 3pid invite events // TODO: 3pid invite events
var builtEvents []*gomatrixserverlib.HeaderedEvent
authEvents := gomatrixserverlib.NewAuthEvents(nil) authEvents := gomatrixserverlib.NewAuthEvents(nil)
for i, e := range eventsToMake { for i, e := range eventsToMake {
depth := i + 1 // depth starts at 1 depth := i + 1 // depth starts at 1