Fix Matrix.Event.RoomMember

It now complies with the Matrix spec.
This commit is contained in:
Gergely Polonkai 2016-03-07 15:03:01 +01:00 committed by Gergely Polonkai
parent 26d144c593
commit f48eaf4c88
3 changed files with 243 additions and 16 deletions

View File

@ -24,13 +24,25 @@ public abstract class Matrix.Event.Base : GLib.Object, GLib.Initable {
private bool _inited = false; private bool _inited = false;
private Json.Node? _json; private Json.Node? _json;
protected string? _event_type = null;
/** /**
* The type of the event. It should be namespaced similar to the * The type of the event. It should be namespaced similar to the
* Java package naming conventions, * Java package naming conventions,
* e.g. `com.example.subdomain.event.type`. It cannot be changed * e.g. `com.example.subdomain.event.type`. It cannot be changed
* after object initialization. * after object initialization.
*/ */
public string? event_type { get; construct; default = null; } public string? event_type {
get {
return _event_type;
}
construct {
_event_type = value;
}
default = null;
}
/** /**
* The event as a JSON node. * The event as a JSON node.

View File

@ -19,15 +19,111 @@
/** /**
* Class for representing a room membership events * Class for representing a room membership events
* *
* The room membership event class. * Adjusts the membership state for a user in a room. It is preferable
* to use the membership APIs (`/rooms/<room id>/invite` etc) when
* performing membership actions rather than adjusting the state
* directly as there are a restricted set of valid
* transformations. For example, user A cannot force user B to join a
* room, and trying to force this state change directly will
* fail.
*
* The following membership states are specified:
*
* - invite - The user has been invited to join a room, but has not
* yet joined it. They may not participate in the room until they
* join.
*
* - join - The user has joined the room (possibly after accepting an
* invite), and may participate in it.
*
* - leave - The user was once joined to the room, but has since left
* (possibly by choice, or possibly by being kicked).
*
* - ban - The user has been banned from the room, and is no longer
* allowed to join it until they are un-banned from the room (by
* having their membership state set to a value other than ban).
*
* - knock - This is a reserved word, which currently has no meaning.
*
* The third_party_invite property will be set if this invite is an
* invite event and is the successor of an m.room.third_party_invite
* event, and absent otherwise.
*
* This event may also include an invite_room_state key outside the
* content key. If present, this contains an array of stripped state
* events. These events provide information on a few select state
* events such as the room name.
*/ */
public class Matrix.Event.RoomMember : Matrix.Event.State { public class Matrix.Event.RoomMember : Matrix.Event.State {
private List<Matrix.Event.State>? _invite_room_state = null;
/**
* The membership state of the user.
*/
public RoomMembership membership { public RoomMembership membership {
get; set; get;
set;
default = RoomMembership.UNKNOWN; default = RoomMembership.UNKNOWN;
} }
public string? avatar_url { get; set; }
public string? display_name { get; set; } /**
* The avatar URL for this user, if any. This is added by the
* homeserver.
*/
public string? avatar_url { get; set; default = null; }
/**
* The display name for this user, if any. This is added by the
* homeserver.
*/
public string? display_name { get; set; default = null; }
/**
* A name which can be displayed to represent the user instead of
* their third party identifier
*/
public string? tpi_display_name { get; set; default = null; }
/**
* The invited matrix user ID. Must be equal to the user_id
* property of the event.
*/
public string? tpi_signed_mxid { get; set; default = null; }
/**
* The token property of the containing third_party_invite object.
*/
public string? tpi_signed_token { get; set; default = null; }
/**
* A single signature from the verifying server, in the format
* specified by the Signing Events section of the server-server
* API.
*/
public Json.Node? tpi_signature { get; set; default = null; }
/**
* A subset of the state of the room at the time of the invite, if
* membership is invite.
*/
public List<Matrix.Event.State>? invite_room_state {
get {
return _invite_room_state;
}
set {
_invite_room_state = value.copy();
}
default = null;
}
/**
* The user ID whom this event relates to.
*/
public string? user_id { get; set; default = null; }
protected override void protected override void
from_json(Json.Node json_data) from_json(Json.Node json_data)
@ -37,6 +133,14 @@ public class Matrix.Event.RoomMember : Matrix.Event.State {
Json.Object content_root = root.get_member("content").get_object(); Json.Object content_root = root.get_member("content").get_object();
Json.Node? node; Json.Node? node;
// Even though the state_key is handled by the parent class,
// in this event type this actually means the sender
if ((node = root.get_member("state_key")) != null) {
_user_id = node.get_string();
} else {
warning("state_key (thus, a user ID) is missing from a m.room.member event");
}
if ((node = content_root.get_member("membership")) != null) { if ((node = content_root.get_member("membership")) != null) {
Matrix.RoomMembership? mship = (Matrix.RoomMembership?)_g_enum_nick_to_value( Matrix.RoomMembership? mship = (Matrix.RoomMembership?)_g_enum_nick_to_value(
typeof(Matrix.RoomMembership), typeof(Matrix.RoomMembership),
@ -57,6 +161,57 @@ public class Matrix.Event.RoomMember : Matrix.Event.State {
_display_name = node.get_string(); _display_name = node.get_string();
} }
if ((node = content_root.get_member("third_party_invite")) != null) {
var tpi_root = node.get_object();
if ((node = tpi_root.get_member("display_name")) != null) {
_tpi_display_name = node.get_string();
} else {
warning("content.third_party_invite.display_name is missing from a m.room.member event");
}
if ((node = tpi_root.get_member("signed")) != null) {
var signed_root = node.get_object();
if ((node = signed_root.get_member("mxid")) != null) {
tpi_signed_mxid = node.get_string();
} else {
warning("content.third_party_invit.signed.mxid is missing from a m.room.member event");
}
if ((node = signed_root.get_member("token")) != null) {
tpi_signed_token = node.get_string();
} else {
warning("content.third_party_invite.signed.token is missing from a m.room.member event");
}
if ((node = signed_root.get_member("signatures")) != null) {
tpi_signature = node;
} else {
warning("content.third_party_invite.signed.signatures is missing from a m.room.member event");
}
} else {
warning("content.third_party_invite.signed is missing from a m.room.member event");
}
}
if ((node = root.get_member("invite_room_state")) != null) {
var events = node.get_array();
if (events.get_length() > 0) {
_invite_room_state = null;
events.foreach_element((ary, idx, member_node) => {
try {
var evt = Matrix.Event.Base.new_from_json(
null, member_node);
_invite_room_state.prepend((Matrix.Event.State)evt);
} catch (GLib.Error e) {}
});
}
}
// Chain up // Chain up
base.from_json(json_data); base.from_json(json_data);
} }
@ -68,24 +223,26 @@ public class Matrix.Event.RoomMember : Matrix.Event.State {
Json.Object root, content_root; Json.Object root, content_root;
string? mship; string? mship;
if (membership == RoomMembership.UNKNOWN) {
throw new Matrix.Error.UNKNOWN_VALUE(
"Unknown membership value cannot be added to a room member event");
}
root = json_data.get_object(); root = json_data.get_object();
content_root = _json_object_node_ensure_field(json_data, content_root = _json_object_node_ensure_field(json_data,
"content", "content",
Json.NodeType.OBJECT) Json.NodeType.OBJECT)
.get_object(); .get_object();
root.set_string_member("state_key", state_key); // Im not sure if it is a good idea to set it here.
if (user_id != null) {
root.set_string_member("state_key", user_id);
}
if (membership == RoomMembership.UNKNOWN) {
throw new Matrix.Error.UNKNOWN_VALUE(
"Unknown membership value cannot be added to a room member event");
}
mship = _g_enum_value_to_nick(typeof(Matrix.RoomMembership), mship = _g_enum_value_to_nick(typeof(Matrix.RoomMembership),
membership); membership);
if (mship != null) { if (mship != null) {
content_root.set_string_member("membership", mship); content_root.set_string_member("membership", mship);
} }
@ -97,6 +254,65 @@ public class Matrix.Event.RoomMember : Matrix.Event.State {
content_root.set_string_member("displayname", display_name); content_root.set_string_member("displayname", display_name);
} }
var tpi_root = new Json.Object();
if (_tpi_display_name != null) {
tpi_root.set_string_member("display_name", tpi_display_name);
}
var tpi_signed_root = new Json.Object();
if (_tpi_signed_mxid != null) {
tpi_signed_root.set_string_member("mxid", tpi_signed_mxid);
}
if (_tpi_signed_token != null) {
tpi_signed_root.set_string_member("token", tpi_signed_token);
}
if (_tpi_signature != null) {
tpi_signed_root.set_member("signature", tpi_signature);
}
if ((tpi_signed_root.get_size() != 3)
&& (tpi_signed_root.get_size() != 0)) {
warning("3rd party invite data is not filled; ignoring");
tpi_signed_root = null;
}
if ((_tpi_display_name != null) && (tpi_signed_root.get_size() == 3)) {
var tpi_signed_node = new Json.Node(Json.NodeType.OBJECT);
tpi_signed_node.set_object(tpi_signed_root);
tpi_root.set_member("signed", tpi_signed_node);
}
if (tpi_root.get_size() == 2) {
var tpi_node = new Json.Node(Json.NodeType.OBJECT);
tpi_node.set_object(tpi_root);
content_root.set_member("third_party_invite", tpi_node);
} else if (tpi_root.get_size() != 0) {
warning("3rd party invite data is incomplete; ignoring");
}
if (_invite_room_state != null) {
var state_ary = new Json.Array();
foreach (var entry in _invite_room_state) {
var state_node = entry.get_stripped_node();
if (state_node != null) {
state_ary.add_element(state_node);
}
}
if (state_ary.get_length() > 0) {
var state_node = new Json.Node(Json.NodeType.ARRAY);
state_node.set_array(state_ary);
root.set_member("invite_room_state", state_node);
}
}
base.to_json(json_data); base.to_json(json_data);
} }
} }

View File

@ -63,9 +63,8 @@ cb_room_member_event(MatrixClient *client,
MatrixEventBase *event, MatrixEventBase *event,
gpointer user_data) gpointer user_data)
{ {
g_printerr("Incoming room member event from %s in room %s (%s)\n", g_printerr("Incoming room member event from %s via room %s\n",
matrix_event_room_get_sender(MATRIX_EVENT_ROOM(event)), matrix_event_room_member_get_user_id(MATRIX_EVENT_ROOM_MEMBER(event)),
matrix_event_room_get_room_id(MATRIX_EVENT_ROOM(event)),
room_id); room_id);
} }