diff --git a/src/assets/css/chat.scss b/src/assets/css/chat.scss
index f949b52..ecb8ad3 100644
--- a/src/assets/css/chat.scss
+++ b/src/assets/css/chat.scss
@@ -863,6 +863,12 @@ $admin-fg: white;
margin-left: 6px;
}
+ .member .user-power {
+ margin-left: 6px;
+ color: #aaa;
+ font-size: 0.8rem;
+ }
+
.member .start-private-chat {
margin-left: 38px;
}
diff --git a/src/assets/translations/en.json b/src/assets/translations/en.json
index 1b0b494..08292f7 100644
--- a/src/assets/translations/en.json
+++ b/src/assets/translations/en.json
@@ -26,7 +26,12 @@
"undo": "Undo",
"join": "Join",
"ignore": "Ignore",
- "loading": "Loading {appName}"
+ "loading": "Loading {appName}",
+ "user_kick": "Kick this user",
+ "user_kick_and_ban": "Kick and ban this user",
+ "user_make_admin": "Make administrator",
+ "user_make_moderator": "Make moderator",
+ "user_revoke_moderator": "Revoke moderator"
},
"message": {
"you": "You",
@@ -37,6 +42,12 @@
"user_changed_room_avatar": "{user} changed the room avatar",
"user_encrypted_room": "{user} made the room encrypted",
"user_was_invited": "{user} was invited to the chat...",
+ "user_was_kicked": "{user} was kicked from the chat.",
+ "user_was_kicked_by_you": "You kicked {user} from the chat.",
+ "user_was_kicked_you": "You were kicked from the chat.",
+ "user_was_banned": "{user} was kicked and banned from the chat.",
+ "user_was_banned_by_you": "You kicked and banned {user} from the chat.",
+ "user_was_banned_you": "You were kicked and banned from the chat.",
"user_joined": "{user} joined the chat",
"user_left": "{user} left the chat",
"user_said": "{user} said:",
@@ -229,7 +240,9 @@
"leave_room": "Leave",
"version_info": "Powered by Guardian Project. Version: {version}",
"scan_code": "Scan to join the room",
- "export_room": "Export chat"
+ "export_room": "Export chat",
+ "user_admin": "Administrator",
+ "user_moderator": "Moderator"
},
"room_info_sheet": {
"this_room": "This room",
diff --git a/src/components/RoomInfo.vue b/src/components/RoomInfo.vue
index 52fb29a..93e9557 100644
--- a/src/components/RoomInfo.vue
+++ b/src/components/RoomInfo.vue
@@ -195,7 +195,22 @@
})
}}
+
+ {{ $t("room_info.user_admin") }}
+
+
+ {{ $t("room_info.user_moderator") }}
+
{{ $t("menu.start_private_chat") }}
+
+
{{ String.fromCharCode(160) }}
+
{{ $t("menu.user_kick") }}
+
{{ $t("menu.user_kick_and_ban") }}
+
+ {{ String.fromCharCode(160) }}
+ {{ $t("menu.user_make_admin") }}
+ {{ $t("menu.user_make_moderator") }}
+ {{ $t("menu.user_revoke_moderator") }}
member.powerLevel && this.room.currentState && this.room.currentState.hasSufficientPowerLevelFor("kick", me.powerLevel);
+ }
+ return false;
+ },
+ canBanUser(member) {
+ if (this.room) {
+ const myUserId = this.$matrix.currentUserId;
+ const me = this.room.getMember(myUserId);
+ return me && me.powerLevelNorm > member.powerLevelNorm && this.room.currentState && this.room.currentState.hasSufficientPowerLevelFor("ban", me.powerLevel);
+ }
+ return false;
+ },
+ // TODO - following power level comparisons assume that default power levels are used in the room!
+ isAdmin(member) {
+ return member.powerLevelNorm > 50;
+ },
+ isModerator(member) {
+ return member.powerLevelNorm > 0 && member.powerLevelNorm <= 50;
+ },
+ /**
+ * Return true if WE can make the member an admin
+ * @param member
+ */
+ canMakeAdmin(ignoredmember) {
+ if (this.room) {
+ const myUserId = this.$matrix.currentUserId;
+ const me = this.room.getMember(myUserId);
+ return me && this.isAdmin(me);
+ }
+ return false;
+ },
+
+ /**
+ * Return true if WE can make the member a moderator
+ * @param member
+ */
+ canMakeModerator(ignoredmember) {
+ if (this.room) {
+ const myUserId = this.$matrix.currentUserId;
+ const me = this.room.getMember(myUserId);
+ return me && this.isAdmin(me);
+ }
+ return false;
+ },
+ /**
+ * Return true if WE can "unmake" the member a moderator
+ * @param member
+ */
+ canRevokeModerator(member) {
+ if (this.room) {
+ const myUserId = this.$matrix.currentUserId;
+ const me = this.room.getMember(myUserId);
+ return me && this.isAdmin(me) && me.powerLevel > member.powerLevel;
+ }
+ return false;
+ },
+ makeAdmin(member) {
+ if (this.room) {
+ this.$matrix.makeAdmin(this.room.roomId, member.userId)
+ }
+ },
+ makeModerator(member) {
+ if (this.room) {
+ this.$matrix.makeModerator(this.room.roomId, member.userId)
+ }
+ },
+ revokeModerator(member) {
+ if (this.room) {
+ this.$matrix.revokeModerator(this.room.roomId, member.userId)
+ }
+ },
+ kickUser(member) {
+ if (this.room) {
+ this.$matrix.kickUser(this.room.roomId, member.userId)
+ }
+ },
+ banUser(member) {
+ if (this.room) {
+ this.$matrix.banUser(this.room.roomId, member.userId)
+ }
}
},
};
diff --git a/src/components/chatMixin.js b/src/components/chatMixin.js
index 970fe16..d87a548 100644
--- a/src/components/chatMixin.js
+++ b/src/components/chatMixin.js
@@ -22,6 +22,8 @@ import MessageOutgoingVideoExport from "./messages/export/MessageOutgoingVideoEx
import ContactJoin from "./messages/ContactJoin.vue";
import ContactLeave from "./messages/ContactLeave.vue";
import ContactInvited from "./messages/ContactInvited.vue";
+import ContactKicked from "./messages/ContactKicked.vue";
+import ContactBanned from "./messages/ContactBanned.vue";
import ContactChanged from "./messages/ContactChanged.vue";
import RoomCreated from "./messages/RoomCreated.vue";
import RoomAliased from "./messages/RoomAliased.vue";
@@ -66,6 +68,8 @@ export default {
ContactJoin,
ContactLeave,
ContactInvited,
+ ContactKicked,
+ ContactBanned,
ContactChanged,
RoomCreated,
RoomAliased,
@@ -123,9 +127,15 @@ export default {
return ContactJoin;
}
} else if (event.getContent().membership == "leave") {
+ if ((event.getPrevContent() || {}).membership == "join" &&
+ event.getStateKey() != event.getSender()) {
+ return ContactKicked;
+ }
return ContactLeave;
} else if (event.getContent().membership == "invite") {
return ContactInvited;
+ } else if (event.getContent().membership == "ban") {
+ return ContactBanned;
}
break;
diff --git a/src/components/messages/ContactBanned.vue b/src/components/messages/ContactBanned.vue
new file mode 100644
index 0000000..37c2a45
--- /dev/null
+++ b/src/components/messages/ContactBanned.vue
@@ -0,0 +1,25 @@
+
+
+
+ {{ (event.getStateKey() == this.$matrix.currentUserId) ?
+ $t('message.user_was_banned_you')
+ :
+ event.getSender() == this.$matrix.currentUserId ?
+ $t('message.user_was_banned_by_you',{user: eventStateKeyDisplayName(event)})
+ :
+ $t('message.user_was_banned',{user: eventStateKeyDisplayName(event)})
+ }}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/messages/ContactChanged.vue b/src/components/messages/ContactChanged.vue
index 95622dc..e03d24a 100644
--- a/src/components/messages/ContactChanged.vue
+++ b/src/components/messages/ContactChanged.vue
@@ -33,7 +33,7 @@ export default {
if (this.displayNameChange) {
return this.event.getPrevContent().displayname;
}
- return this.stateEventDisplayName(this.event);
+ return this.eventStateKeyDisplayName(this.event);
},
}
};
diff --git a/src/components/messages/ContactInvited.vue b/src/components/messages/ContactInvited.vue
index 85f96a8..110c43e 100644
--- a/src/components/messages/ContactInvited.vue
+++ b/src/components/messages/ContactInvited.vue
@@ -1,7 +1,7 @@
- {{ $t('message.user_was_invited', {user: event.getContent().displayname || stateEventDisplayName(event)}) }}
+ {{ $t('message.user_was_invited', {user: event.getContent().displayname || eventStateKeyDisplayName(event)}) }}
diff --git a/src/components/messages/ContactJoin.vue b/src/components/messages/ContactJoin.vue
index b8bce13..d8aa6d8 100644
--- a/src/components/messages/ContactJoin.vue
+++ b/src/components/messages/ContactJoin.vue
@@ -1,7 +1,7 @@
- {{ $t('message.user_joined',{user: stateEventDisplayName(event)}) }}
+ {{ $t('message.user_joined',{user: eventSenderDisplayName(event)}) }}
diff --git a/src/components/messages/ContactKicked.vue b/src/components/messages/ContactKicked.vue
new file mode 100644
index 0000000..b34da00
--- /dev/null
+++ b/src/components/messages/ContactKicked.vue
@@ -0,0 +1,25 @@
+
+
+
+ {{ (event.getStateKey() == this.$matrix.currentUserId) ?
+ $t('message.user_was_kicked_you')
+ :
+ event.getSender() == this.$matrix.currentUserId ?
+ $t('message.user_was_kicked_by_you',{user: eventStateKeyDisplayName(event)})
+ :
+ $t('message.user_was_kicked',{user: eventStateKeyDisplayName(event)})
+ }}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/messages/ContactLeave.vue b/src/components/messages/ContactLeave.vue
index 0b77831..1e40799 100644
--- a/src/components/messages/ContactLeave.vue
+++ b/src/components/messages/ContactLeave.vue
@@ -1,7 +1,7 @@
- {{ $t('message.user_left',{user: stateEventDisplayName(event)}) }}
+ {{ $t('message.user_left',{user: eventStateKeyDisplayName(event)}) }}
diff --git a/src/components/messages/MessageIncoming.vue b/src/components/messages/MessageIncoming.vue
index 9c31eb3..e1f1727 100644
--- a/src/components/messages/MessageIncoming.vue
+++ b/src/components/messages/MessageIncoming.vue
@@ -2,7 +2,7 @@
-
{{ messageEventDisplayName(event) }}
+
{{ eventSenderDisplayName(event) }}
{{ formatTime(event.event.origin_server_ts) }}
@@ -10,7 +10,7 @@
{{
- messageEventDisplayName(event).substring(0, 1).toUpperCase()
+ eventSenderDisplayName(event).substring(0, 1).toUpperCase()
}}
diff --git a/src/components/messages/RoomAliased.vue b/src/components/messages/RoomAliased.vue
index 5a908e6..9c87f29 100644
--- a/src/components/messages/RoomAliased.vue
+++ b/src/components/messages/RoomAliased.vue
@@ -1,6 +1,6 @@
- {{ $t('message.user_aliased_room', {user: stateEventDisplayName(event), alias: event.getContent().alias}) }}
+ {{ $t('message.user_aliased_room', {user: eventSenderDisplayName(event), alias: event.getContent().alias}) }}
diff --git a/src/components/messages/RoomAvatarChanged.vue b/src/components/messages/RoomAvatarChanged.vue
index 7645e80..cc68bca 100644
--- a/src/components/messages/RoomAvatarChanged.vue
+++ b/src/components/messages/RoomAvatarChanged.vue
@@ -1,7 +1,7 @@
- {{ $t('message.user_changed_room_avatar',{user: stateEventDisplayName(event)}) }}
+ {{ $t('message.user_changed_room_avatar',{user: eventSenderDisplayName(event)}) }}
diff --git a/src/components/messages/RoomCreated.vue b/src/components/messages/RoomCreated.vue
index 9603e0f..c83ad15 100644
--- a/src/components/messages/RoomCreated.vue
+++ b/src/components/messages/RoomCreated.vue
@@ -1,6 +1,6 @@
- {{ $t('message.user_created_room', {user: stateEventDisplayName(event)}) }}
+ {{ $t('message.user_created_room', {user: eventSenderDisplayName(event)}) }}
diff --git a/src/components/messages/RoomDeletionNotice.vue b/src/components/messages/RoomDeletionNotice.vue
index 9a2f476..f8b7524 100644
--- a/src/components/messages/RoomDeletionNotice.vue
+++ b/src/components/messages/RoomDeletionNotice.vue
@@ -4,7 +4,7 @@
👋
{{
$t("purge_room.room_deletion_notice", {
- user: stateEventDisplayName(event),
+ user: eventSenderDisplayName(event),
})
}}
diff --git a/src/components/messages/RoomEncrypted.vue b/src/components/messages/RoomEncrypted.vue
index 669b6e7..874d989 100644
--- a/src/components/messages/RoomEncrypted.vue
+++ b/src/components/messages/RoomEncrypted.vue
@@ -1,6 +1,6 @@
- {{ $t('message.user_encrypted_room', {user: stateEventDisplayName(event)}) }}
+ {{ $t('message.user_encrypted_room', {user: eventSenderDisplayName(event)}) }}
diff --git a/src/components/messages/RoomGuestAccessChanged.vue b/src/components/messages/RoomGuestAccessChanged.vue
index 13d7f27..b89501c 100644
--- a/src/components/messages/RoomGuestAccessChanged.vue
+++ b/src/components/messages/RoomGuestAccessChanged.vue
@@ -3,10 +3,10 @@
{{
openToGuests
? $t("message.user_changed_guest_access_open", {
- user: stateEventDisplayName(event),
+ user: eventSenderDisplayName(event),
})
: $t("message.user_changed_guest_access_closed", {
- user: stateEventDisplayName(event),
+ user: eventSenderDisplayName(event),
})
}}
diff --git a/src/components/messages/RoomHistoryVisibility.vue b/src/components/messages/RoomHistoryVisibility.vue
index 19892f4..a6e1592 100644
--- a/src/components/messages/RoomHistoryVisibility.vue
+++ b/src/components/messages/RoomHistoryVisibility.vue
@@ -1,7 +1,7 @@
- {{ $t('message.user_changed_room_history',{user: stateEventDisplayName(event), type: history(event)}) }}
+ {{ $t('message.user_changed_room_history',{user: eventSenderDisplayName(event), type: history(event)}) }}
diff --git a/src/components/messages/RoomJoinRules.vue b/src/components/messages/RoomJoinRules.vue
index f80dbff..0ee433b 100644
--- a/src/components/messages/RoomJoinRules.vue
+++ b/src/components/messages/RoomJoinRules.vue
@@ -1,7 +1,7 @@
- {{ $t('message.user_changed_join_rules', { user: stateEventDisplayName(event), type: joinRule(event)}) }}
+ {{ $t('message.user_changed_join_rules', { user: eventSenderDisplayName(event), type: joinRule(event)}) }}
diff --git a/src/components/messages/RoomNameChanged.vue b/src/components/messages/RoomNameChanged.vue
index ba152b8..1e844c5 100644
--- a/src/components/messages/RoomNameChanged.vue
+++ b/src/components/messages/RoomNameChanged.vue
@@ -1,7 +1,7 @@
- {{ $t('message.user_changed_room_name', {user: stateEventDisplayName(event), name: event.getContent().name}) }}
+ {{ $t('message.user_changed_room_name', {user: eventSenderDisplayName(event), name: event.getContent().name}) }}
diff --git a/src/components/messages/RoomTopicChanged.vue b/src/components/messages/RoomTopicChanged.vue
index 6ac9992..9268756 100644
--- a/src/components/messages/RoomTopicChanged.vue
+++ b/src/components/messages/RoomTopicChanged.vue
@@ -1,7 +1,7 @@
- {{ $t('message.user_changed_room_topic', {user: stateEventDisplayName(event), topic: event.getContent().topic}) }}
+ {{ $t('message.user_changed_room_topic', {user: eventSenderDisplayName(event), topic: event.getContent().topic}) }}
diff --git a/src/components/messages/messageMixin.js b/src/components/messages/messageMixin.js
index 1820781..7aea0ba 100644
--- a/src/components/messages/messageMixin.js
+++ b/src/components/messages/messageMixin.js
@@ -50,7 +50,7 @@ export default {
const originalEvent = this.timelineSet.findEventById(originalEventId);
if (originalEvent) {
this.inReplyToEvent = originalEvent;
- this.inReplyToSender = this.messageEventDisplayName(originalEvent);
+ this.inReplyToSender = this.eventSenderDisplayName(originalEvent);
}
}
}
@@ -157,7 +157,7 @@ export default {
/**
* Get a display name given an event.
*/
- stateEventDisplayName(event) {
+ eventSenderDisplayName(event) {
if (event.getSender() == this.$matrix.currentUserId) {
return this.$t('message.you');
}
@@ -167,11 +167,26 @@ export default {
return member.name;
}
}
- return event.getContent().displayname || event.event.state_key;
+ return event.getContent().displayname || event.getSender();
},
- messageEventDisplayName(event) {
- return this.stateEventDisplayName(event);
+ /**
+ * In the case where the state_key points out a userId for an operation (e.g. membership events)
+ * return the display name of the affected user.
+ * @param event
+ * @returns
+ */
+ eventStateKeyDisplayName(event) {
+ if (event.getStateKey() == this.$matrix.currentUserId) {
+ return this.$t('message.you');
+ }
+ if (this.room) {
+ const member = this.room.getMember(event.getStateKey());
+ if (member) {
+ return member.name;
+ }
+ }
+ return event.getStateKey();
},
messageEventAvatar(event) {
diff --git a/src/services/matrix.service.js b/src/services/matrix.service.js
index 158c971..ffe78fd 100644
--- a/src/services/matrix.service.js
+++ b/src/services/matrix.service.js
@@ -356,19 +356,22 @@ export default {
event.getRoomId() == this.currentRoom.roomId
) {
// Don't use this.currentRoomId, may be an alias. We need the real id!
- if (
+ if ((
event.getContent().membership == "leave" &&
(event.getPrevContent() || {}).membership == "join" &&
event.getStateKey() == this.currentUserId &&
event.getSender() != this.currentUserId
- ) {
- // We were kicked
+ ) || (event.getContent().membership == "ban" && event.getStateKey() == this.currentUserId)) {
+ // We were kicked or banned
+ // If this is a live event (not just backpaging) then redirect to goodbye!
+ if (this.matrixClientReady) {
const wasPurged =
event.getContent().reason == "Room Deleted";
this.$navigation.push(
{ name: "Goodbye", params: { roomWasPurged: wasPurged } },
-1
);
+ }
}
}
}
@@ -546,6 +549,63 @@ export default {
});
},
+ kickUser(roomId, userId) {
+ if (this.matrixClient && roomId && userId) {
+ this.matrixClient.kick(
+ roomId,
+ userId,
+ ""
+ )
+ }
+ },
+
+ banUser(roomId, userId) {
+ if (this.matrixClient && roomId && userId) {
+ this.matrixClient.ban(
+ roomId,
+ userId,
+ ""
+ )
+ }
+ },
+
+ makeAdmin(roomId, userId) {
+ if (this.matrixClient && roomId && userId) {
+ const room = this.getRoom(roomId);
+ if (room && room.currentState) {
+ const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
+ if (powerLevelEvent) {
+ this.matrixClient.setPowerLevel(roomId, userId, 100, powerLevelEvent);
+ }
+ }
+ }
+ },
+
+ makeModerator(roomId, userId) {
+ if (this.matrixClient && roomId && userId) {
+ const room = this.getRoom(roomId);
+ console.log("Room", room);
+ if (room && room.currentState) {
+ const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
+ if (powerLevelEvent) {
+ this.matrixClient.setPowerLevel(roomId, userId, 50, powerLevelEvent);
+ }
+ }
+ }
+ },
+
+ revokeModerator(roomId, userId) {
+ if (this.matrixClient && roomId && userId) {
+ const room = this.getRoom(roomId);
+ if (room && room.currentState) {
+ const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
+ if (powerLevelEvent) {
+ this.matrixClient.setPowerLevel(roomId, userId, 0, powerLevelEvent);
+ }
+ }
+ }
+ },
+
/**
* Purge the room with the given id! This means:
* - Make room invite only