Merge branch 'vector' of github.com:matrix-org/matrix-react-sdk into erikj/room_editing

pull/1/head
Erik Johnston 2015-07-21 14:14:48 +01:00
commit 89f6459915
2 changed files with 247 additions and 8 deletions

View File

@ -67,7 +67,35 @@ module.exports = React.createClass({
if (this.state.active >= 0) { if (this.state.active >= 0) {
activeAgo = this.getDuration(this.state.active); activeAgo = this.getDuration(this.state.active);
} }
var kickButton, banButton, muteButton, giveModButton;
if (this.state.can.kick) {
kickButton = <div className="mx_MemberInfo_button" onClick={this.onKick}>
Kick
</div>;
}
if (this.state.can.ban) {
banButton = <div className="mx_MemberInfo_button" onClick={this.onBan}>
Ban
</div>;
}
if (this.state.can.mute) {
var muteLabel = this.state.muted ? "Unmute" : "Mute";
muteButton = <div className="mx_MemberInfo_button" onClick={this.onMuteToggle}>
{muteLabel}
</div>;
}
if (this.state.can.modifyLevel) {
var giveOpLabel = this.state.isTargetMod ? "Revoke Mod" : "Make Mod";
giveModButton = <div className="mx_MemberInfo_button" onClick={this.onModToggle}>
{giveOpLabel}
</div>
}
var opLabel;
if (this.state.isTargetMod) {
var level = this.props.member.powerLevelNorm + "%";
opLabel = <div className="mx_MemberInfo_field">Moderator ({level})</div>
}
return ( return (
<div className="mx_MemberInfo"> <div className="mx_MemberInfo">
<img className="mx_MemberInfo_chevron" src="img/chevron-right.png" width="9" height="16" /> <img className="mx_MemberInfo_chevron" src="img/chevron-right.png" width="9" height="16" />
@ -78,9 +106,14 @@ module.exports = React.createClass({
width="128" height="128" alt=""/> width="128" height="128" alt=""/>
</div> </div>
<div className="mx_MemberInfo_field">{this.props.member.userId}</div> <div className="mx_MemberInfo_field">{this.props.member.userId}</div>
{opLabel}
<div className="mx_MemberInfo_field">Presence: {this.state.presence}</div> <div className="mx_MemberInfo_field">Presence: {this.state.presence}</div>
<div className="mx_MemberInfo_field">Last active: {activeAgo}</div> <div className="mx_MemberInfo_field">Last active: {activeAgo}</div>
<div className="mx_MemberInfo_button" onClick={this.onChatClick}>Start chat</div> <div className="mx_MemberInfo_button" onClick={this.onChatClick}>Start chat</div>
{muteButton}
{kickButton}
{banButton}
{giveModButton}
</div> </div>
); );
} }

View File

@ -18,15 +18,27 @@ limitations under the License.
* State vars: * State vars:
* 'presence' : string (online|offline|unavailable etc) * 'presence' : string (online|offline|unavailable etc)
* 'active' : number (ms ago; can be -1) * 'active' : number (ms ago; can be -1)
* 'can': {
* kick: boolean,
* ban: boolean,
* mute: boolean,
* modifyLevel: boolean
* },
* 'muted': boolean,
* 'isTargetMod': boolean
*/ */
'use strict'; 'use strict';
var MatrixClientPeg = require("../../MatrixClientPeg"); var MatrixClientPeg = require("../../MatrixClientPeg");
var dis = require("../../dispatcher"); var dis = require("../../dispatcher");
var Modal = require("../../Modal");
var ComponentBroker = require('../../ComponentBroker');
var ErrorDialog = ComponentBroker.get("organisms/ErrorDialog");
module.exports = { module.exports = {
componentDidMount: function() { componentDidMount: function() {
var self = this; var self = this;
// listen for presence changes
function updateUserState(event, user) { function updateUserState(event, user) {
if (!self.props.member) { return; } if (!self.props.member) { return; }
@ -40,20 +52,145 @@ module.exports = {
MatrixClientPeg.get().on("User.presence", updateUserState); MatrixClientPeg.get().on("User.presence", updateUserState);
this.userPresenceFn = updateUserState; this.userPresenceFn = updateUserState;
if (this.props.member) { // listen for power level changes
var usr = MatrixClientPeg.get().getUser(this.props.member.userId); function updatePowerLevel(event, member) {
if (!usr) { if (!self.props.member) { return; }
if (member.roomId !== self.props.member.roomId) {
return; return;
} }
this.setState({ // only interested in changes to us or them
presence: usr.presence, var myUserId = MatrixClientPeg.get().credentials.userId;
active: usr.lastActiveAgo if ([myUserId, self.props.member.userId].indexOf(member.userId) === -1) {
}); return;
}
self.setState(self._calculateOpsPermissions());
}
MatrixClientPeg.get().on("RoomMember.powerLevel", updatePowerLevel);
this.updatePowerLevelFn = updatePowerLevel;
// work out the current state
if (this.props.member) {
var usr = MatrixClientPeg.get().getUser(this.props.member.userId) || {};
var memberState = this._calculateOpsPermissions();
memberState.presence = usr.presence || "offline";
memberState.active = usr.lastActiveAgo || -1;
this.setState(memberState);
} }
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
MatrixClientPeg.get().removeListener("User.presence", this.userPresenceFn); MatrixClientPeg.get().removeListener("User.presence", this.userPresenceFn);
MatrixClientPeg.get().removeListener(
"RoomMember.powerLevel", this.updatePowerLevelFn
);
},
onKick: function() {
var roomId = this.props.member.roomId;
var target = this.props.member.userId;
var self = this;
MatrixClientPeg.get().kick(roomId, target).done(function() {
// NO-OP; rely on the m.room.member event coming down else we could
// get out of sync if we force setState here!
console.log("Kick success");
}, function(err) {
Modal.createDialog(ErrorDialog, {
title: "Kick error",
description: err.message
});
});
},
onBan: function() {
var roomId = this.props.member.roomId;
var target = this.props.member.userId;
var self = this;
MatrixClientPeg.get().ban(roomId, target).done(function() {
// NO-OP; rely on the m.room.member event coming down else we could
// get out of sync if we force setState here!
console.log("Ban success");
}, function(err) {
Modal.createDialog(ErrorDialog, {
title: "Ban error",
description: err.message
});
});
},
onMuteToggle: function() {
var roomId = this.props.member.roomId;
var target = this.props.member.userId;
var self = this;
var room = MatrixClientPeg.get().getRoom(roomId);
if (!room) {
return;
}
var powerLevelEvent = room.currentState.getStateEvents(
"m.room.power_levels", ""
);
if (!powerLevelEvent) {
return;
}
var isMuted = this.state.muted;
var powerLevels = powerLevelEvent.getContent();
var levelToSend = (
(powerLevels.events ? powerLevels.events["m.room.message"] : null) ||
powerLevels.events_default
);
var level;
if (isMuted) { // unmute
level = levelToSend;
}
else { // mute
level = levelToSend - 1;
}
MatrixClientPeg.get().setPowerLevel(roomId, target, level, powerLevelEvent).done(
function() {
// NO-OP; rely on the m.room.member event coming down else we could
// get out of sync if we force setState here!
console.log("Mute toggle success");
}, function(err) {
Modal.createDialog(ErrorDialog, {
title: "Mute error",
description: err.message
});
});
},
onModToggle: function() {
var roomId = this.props.member.roomId;
var target = this.props.member.userId;
var room = MatrixClientPeg.get().getRoom(roomId);
if (!room) {
return;
}
var powerLevelEvent = room.currentState.getStateEvents(
"m.room.power_levels", ""
);
if (!powerLevelEvent) {
return;
}
var me = room.getMember(MatrixClientPeg.get().credentials.userId);
if (!me) {
return;
}
var defaultLevel = powerLevelEvent.getContent().users_default;
var modLevel = me.powerLevel - 1;
// toggle the level
var newLevel = this.state.isTargetMod ? defaultLevel : modLevel;
MatrixClientPeg.get().setPowerLevel(roomId, target, newLevel, powerLevelEvent).done(
function() {
// NO-OP; rely on the m.room.member event coming down else we could
// get out of sync if we force setState here!
console.log("Mod toggle success");
}, function(err) {
Modal.createDialog(ErrorDialog, {
title: "Mod error",
description: err.message
});
});
}, },
onChatClick: function() { onChatClick: function() {
@ -108,8 +245,77 @@ module.exports = {
getInitialState: function() { getInitialState: function() {
return { return {
presence: "offline", presence: "offline",
active: -1 active: -1,
can: {
kick: false,
ban: false,
mute: false,
modifyLevel: false
},
muted: false,
isTargetMod: false
} }
},
_calculateOpsPermissions: function() {
var defaultPerms = {
can: {},
muted: false,
modifyLevel: false
};
var room = MatrixClientPeg.get().getRoom(this.props.member.roomId);
if (!room) {
return defaultPerms;
}
var powerLevels = room.currentState.getStateEvents(
"m.room.power_levels", ""
);
if (!powerLevels) {
return defaultPerms;
}
var me = room.getMember(MatrixClientPeg.get().credentials.userId);
var them = this.props.member;
return {
can: this._calculateCanPermissions(
me, them, powerLevels.getContent()
),
muted: this._isMuted(them, powerLevels.getContent()),
isTargetMod: them.powerLevel > powerLevels.getContent().users_default
};
},
_calculateCanPermissions: function(me, them, powerLevels) {
var can = {
kick: false,
ban: false,
mute: false,
modifyLevel: false
};
var canAffectUser = them.powerLevel < me.powerLevel;
if (!canAffectUser) {
console.log("Cannot affect user: %s >= %s", them.powerLevel, me.powerLevel);
return can;
}
var editPowerLevel = (
(powerLevels.events ? powerLevels.events["m.room.power_levels"] : null) ||
powerLevels.state_default
);
can.kick = me.powerLevel >= powerLevels.kick;
can.ban = me.powerLevel >= powerLevels.ban;
can.mute = me.powerLevel >= editPowerLevel;
can.modifyLevel = me.powerLevel > them.powerLevel;
return can;
},
_isMuted: function(member, powerLevelContent) {
if (!powerLevelContent || !member) {
return false;
}
var levelToSend = (
(powerLevelContent.events ? powerLevelContent.events["m.room.message"] : null) ||
powerLevelContent.events_default
);
return member.powerLevel < levelToSend;
} }
}; };