Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 51 additions & 4 deletions lib/models/room-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,33 @@ RoomState.prototype.getUserIdsWithDisplayName = function(displayName) {
return this._displayNameToUserIds[displayName] || [];
};

/**
* Short-form for maySendEvent('m.room.message', userId)
* @param {string} userId The user ID of the user to test permission for
* @return {boolean} true if the given user ID should be permitted to send
* message events into the given room.
*/
RoomState.prototype.maySendMessage = function(userId) {
return this._maySendEventOfType('m.room.message', userId, false);
};

/**
* Returns true if the given user ID has permission to send a normal
* event of type `eventType` into this room.
* @param {string} type The type of event to test
* @param {string} userId The user ID of the user to test permission for
* @param {boolean} state If true, tests if the user may send a state

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't exist

event of this type. Otherwise tests whether
they may send a regular event.
* @return {boolean} true if the given user ID should be permitted to send
* the given type of event into this room,
* according to the room's state.
*/
RoomState.prototype.maySendEvent = function(eventType, userId) {
return this._maySendEventOfType(eventType, userId, false);
};


/**
* Returns true if the given MatrixClient has permission to send a state
* event of type `stateEventType` into this room.
Expand All @@ -265,6 +292,22 @@ RoomState.prototype.mayClientSendStateEvent = function(stateEventType, cli) {
* according to the room's state.
*/
RoomState.prototype.maySendStateEvent = function(stateEventType, userId) {
return this._maySendEventOfType(stateEventType, userId, true);
};

/**
* Returns true if the given user ID has permission to send a normal or state
* event of type `eventType` into this room.
* @param {string} type The type of event to test
* @param {string} userId The user ID of the user to test permission for
* @param {boolean} state If true, tests if the user may send a state
event of this type. Otherwise tests whether
they may send a regular event.
* @return {boolean} true if the given user ID should be permitted to send
* the given type of event into this room,
* according to the room's state.
*/
RoomState.prototype._maySendEventOfType = function(eventType, userId, state) {
var member = this.getMember(userId);
if (!member || member.membership == 'leave') { return false; }

Expand All @@ -277,6 +320,7 @@ RoomState.prototype.maySendStateEvent = function(stateEventType, userId) {
var user_levels = [];

var state_default = 0;
var events_default = 0;
if (power_levels_event) {
power_levels = power_levels_event.getContent();
events_levels = power_levels.events || {};
Expand All @@ -289,13 +333,16 @@ RoomState.prototype.maySendStateEvent = function(stateEventType, userId) {
} else {
state_default = 50;
}
if (power_levels.events_default !== undefined) {
events_default = power_levels.events_default;
}
}

var state_event_level = state_default;
if (events_levels[stateEventType] !== undefined) {
state_event_level = events_levels[stateEventType];
var required_level = state ? state_default : events_default;
if (events_levels[eventType] !== undefined) {
required_level = events_levels[eventType];
}
return member.powerLevel >= state_event_level;
return member.powerLevel >= required_level;
};

/**
Expand Down
70 changes: 70 additions & 0 deletions spec/unit/room-state.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,4 +362,74 @@ describe("RoomState", function() {
expect(state.maySendStateEvent('m.room.other_thing', userB)).toEqual(false);
});
});

describe("maySendEvent", function() {
it("should say non-joined members may not send events",
function() {
expect(state.maySendEvent(
'm.room.message', "@nobody:nowhere"
)).toEqual(false);
expect(state.maySendMessage("@nobody:nowhere")).toEqual(false);
});

it("should say any member may send events with no power level event",
function() {
expect(state.maySendEvent('m.room.message', userA)).toEqual(true);
expect(state.maySendMessage(userA)).toEqual(true);
});

it("should obey events_default",
function() {
var powerLevelEvent = {
type: "m.room.power_levels", room: roomId, user: userA, event: true,
content: {
users_default: 10,
state_default: 30,
events_default: 25,
users: {
}
}
};
powerLevelEvent.content.users[userA] = 26;
powerLevelEvent.content.users[userB] = 24;

state.setStateEvents([utils.mkEvent(powerLevelEvent)]);

expect(state.maySendEvent('m.room.message', userA)).toEqual(true);
expect(state.maySendEvent('m.room.message', userB)).toEqual(false);

expect(state.maySendMessage(userA)).toEqual(true);
expect(state.maySendMessage(userB)).toEqual(false);
});

it("should honour explicit event power levels in the power_levels event",
function() {
var powerLevelEvent = {
type: "m.room.power_levels", room: roomId, user: userA, event: true,
content: {
events: {
"m.room.other_thing": 33
},
users_default: 10,
state_default: 50,
events_default: 25,
users: {
}
}
};
powerLevelEvent.content.users[userA] = 40;
powerLevelEvent.content.users[userB] = 30;

state.setStateEvents([utils.mkEvent(powerLevelEvent)]);

expect(state.maySendEvent('m.room.message', userA)).toEqual(true);
expect(state.maySendEvent('m.room.message', userB)).toEqual(true);

expect(state.maySendMessage(userA)).toEqual(true);
expect(state.maySendMessage(userB)).toEqual(true);

expect(state.maySendEvent('m.room.other_thing', userA)).toEqual(true);
expect(state.maySendEvent('m.room.other_thing', userB)).toEqual(false);
});
});
});