Only allow admins to change room mode

This commit is contained in:
N Pex 2023-08-07 14:13:35 +00:00
parent 31b7c4ed26
commit cfc14f05a0
6 changed files with 90 additions and 48 deletions

View file

@ -358,6 +358,7 @@ import AudioLayout from "./AudioLayout.vue";
import FileDropLayout from "./file_mode/FileDropLayout"; import FileDropLayout from "./file_mode/FileDropLayout";
import { requestNotificationAndServiceWorker, windowNotificationPermission, notificationCount } from "../plugins/notificationAndServiceWorker.js" import { requestNotificationAndServiceWorker, windowNotificationPermission, notificationCount } from "../plugins/notificationAndServiceWorker.js"
import logoMixin from "./logoMixin"; import logoMixin from "./logoMixin";
import roomTypeMixin from "./roomTypeMixin";
const sizeOf = require("image-size"); const sizeOf = require("image-size");
const dataUriToBuffer = require("data-uri-to-buffer"); const dataUriToBuffer = require("data-uri-to-buffer");
@ -393,7 +394,7 @@ ScrollPosition.prototype.prepareFor = function (direction) {
export default { export default {
name: "Chat", name: "Chat",
mixins: [chatMixin, logoMixin], mixins: [chatMixin, logoMixin, roomTypeMixin],
components: { components: {
ChatHeader, ChatHeader,
MessageOperations, MessageOperations,
@ -652,13 +653,13 @@ export default {
useVoiceMode: { useVoiceMode: {
get: function () { get: function () {
if (!this.$config.experimental_voice_mode) return false; if (!this.$config.experimental_voice_mode) return false;
return util.roomDisplayType(this.room) === ROOM_TYPE_VOICE_MODE; return (util.roomDisplayTypeOverride(this.room) || this.roomDisplayType) === ROOM_TYPE_VOICE_MODE;
}, },
}, },
useFileModeNonAdmin: { useFileModeNonAdmin: {
get: function() { get: function() {
if (!this.$config.experimental_file_mode) return false; if (!this.$config.experimental_file_mode) return false;
return util.roomDisplayType(this.room) === ROOM_TYPE_FILE_MODE && !this.canCreatePoll; // TODO - Check user or admin return (util.roomDisplayTypeOverride(this.room) || this.roomDisplayType) === ROOM_TYPE_FILE_MODE && !this.canCreatePoll; // TODO - Check user or admin
} }
}, },

View file

@ -138,9 +138,9 @@
</v-card-text> </v-card-text>
</v-card> </v-card>
<v-card class="account ma-3" flat v-if="availableRoomTypes.length > 1 || canChangeReadOnly()"> <v-card class="account ma-3" flat v-if="(iAmAdmin() && availableRoomTypes.length > 1) || canChangeReadOnly()">
<v-card-title class="h2 with-right-label"><div>{{ $t("room_info.experimental_features") }}</div><div></div></v-card-title> <v-card-title class="h2 with-right-label"><div>{{ $t("room_info.experimental_features") }}</div><div></div></v-card-title>
<v-card-text class="with-right-label" v-if="availableRoomTypes.length > 1"> <v-card-text class="with-right-label" v-if="iAmAdmin() && availableRoomTypes.length > 1">
<div> <div>
<div class="option-title">{{ $t('room_info.room_type') }}</div> <div class="option-title">{{ $t('room_info.room_type') }}</div>
</div> </div>
@ -257,7 +257,7 @@ import CopyLink from "../components/CopyLink.vue"
import RoomTypeSelector from "./RoomTypeSelector.vue"; import RoomTypeSelector from "./RoomTypeSelector.vue";
import roomInfoMixin from "./roomInfoMixin"; import roomInfoMixin from "./roomInfoMixin";
import roomTypeMixin from "./roomTypeMixin"; import roomTypeMixin from "./roomTypeMixin";
import util, { ROOM_TYPE_DEFAULT, ROOM_TYPE_FILE_MODE, ROOM_TYPE_VOICE_MODE } from "../plugins/utils"; import util, { STATE_EVENT_ROOM_TYPE } from "../plugins/utils";
export default { export default {
name: "RoomInfo", name: "RoomInfo",
@ -337,25 +337,29 @@ export default {
roomType: { roomType: {
get: function () { get: function () {
if (this.room && this.room.tags) { // if (this.room && this.room.tags) {
let options = this.room.tags["ui_options"] || {} // let options = this.room.tags["ui_options"] || {}
if (options["voice_mode"]) { // if (options["voice_mode"]) {
return ROOM_TYPE_VOICE_MODE; // return ROOM_TYPE_VOICE_MODE;
} else if (options["file_mode"]) { // } else if (options["file_mode"]) {
return ROOM_TYPE_FILE_MODE; // return ROOM_TYPE_FILE_MODE;
} // }
} // }
return ROOM_TYPE_DEFAULT; // return ROOM_TYPE_DEFAULT;
return util.roomDisplayTypeOverride(this.room) || this.roomDisplayType;
}, },
set: function (roomType) { set: function (roomType) {
if (this.room) { if (this.room) {
let tags = this.room.tags || {}; // let tags = this.room.tags || {};
let options = tags["ui_options"] || {} // let options = tags["ui_options"] || {}
options["voice_mode"] = (roomType == ROOM_TYPE_VOICE_MODE ? 1 : 0); // options["voice_mode"] = (roomType == ROOM_TYPE_VOICE_MODE ? 1 : 0);
options["file_mode"] = (roomType == ROOM_TYPE_FILE_MODE ? 1 : 0); // options["file_mode"] = (roomType == ROOM_TYPE_FILE_MODE ? 1 : 0);
tags["ui_options"] = options; // tags["ui_options"] = options;
this.room.tags = tags; // this.room.tags = tags;
this.$matrix.matrixClient.setRoomTag(this.room.roomId, "ui_options", options); // this.$matrix.matrixClient.setRoomTag(this.room.roomId, "ui_options", options);
if (this.iAmAdmin()) {
this.$matrix.matrixClient.sendStateEvent(this.room.roomId, STATE_EVENT_ROOM_TYPE, { type: roomType });
}
} }
}, },
}, },
@ -539,6 +543,12 @@ export default {
} }
return false; return false;
}, },
iAmAdmin() {
if (this.room) {
return this.room.currentState && this.room.currentState.maySendStateEvent("m.room.power_levels", this.$matrix.currentUserId);
}
return false;
},
// TODO - following power level comparisons assume that default power levels are used in the room! // TODO - following power level comparisons assume that default power levels are used in the room!
isAdmin(member) { isAdmin(member) {
return member.powerLevelNorm > 50; return member.powerLevelNorm > 50;

View file

@ -225,7 +225,7 @@ export default {
id: attachment.name, id: attachment.name,
status: this.statuses.INITIAL, status: this.statuses.INITIAL,
statusDate: Date.now, statusDate: Date.now,
attachment: attachment, attachment: attachment.actualFile || attachment,
progress: 0, progress: 0,
randomRotation: 0, randomRotation: 0,
randomTranslationX: 0, randomTranslationX: 0,

View file

@ -1,6 +1,8 @@
import utils from "../plugins/utils"; import utils from "../plugins/utils";
import roomTypeMixin from "./roomTypeMixin";
export default { export default {
mixins: [roomTypeMixin],
data() { data() {
return { return {
roomJoinRule: null, roomJoinRule: null,
@ -59,7 +61,7 @@ export default {
publicRoomLink() { publicRoomLink() {
if (this.room && this.roomJoinRule == "public") { if (this.room && this.roomJoinRule == "public") {
return this.$router.getRoomLink( return this.$router.getRoomLink(
this.room.getCanonicalAlias(), this.room.roomId, this.room.name, utils.roomDisplayTypeToQueryParam(this.room) this.room.getCanonicalAlias(), this.room.roomId, this.room.name, utils.roomDisplayTypeToQueryParam(this.room, this.roomDisplayType)
); );
} }
return null; return null;

View file

@ -1,6 +1,47 @@
import { ROOM_TYPE_VOICE_MODE, ROOM_TYPE_FILE_MODE, ROOM_TYPE_DEFAULT } from "../plugins/utils"; import { ROOM_TYPE_VOICE_MODE, ROOM_TYPE_FILE_MODE, ROOM_TYPE_DEFAULT, STATE_EVENT_ROOM_TYPE } from "../plugins/utils";
export default { export default {
data() {
return {
roomDisplayType: ROOM_TYPE_DEFAULT,
};
},
mounted() {
this.$matrix.on("Room.timeline", this.onRoomTypeMixinEvent);
},
destroyed() {
this.$matrix.off("Room.timeline", this.onRoomTypeMixinEvent);
},
watch: {
room: {
immediate: true,
handler(newVal) {
if (newVal) {
this.onRoomTypeMixinTypeEvent(newVal.currentState.getStateEvents(STATE_EVENT_ROOM_TYPE, "") || newVal.currentState.getStateEvents("m.room.create", ""));
} else {
this.roomDisplayType = ROOM_TYPE_DEFAULT;
}
},
},
},
methods: {
onRoomTypeMixinEvent(e) {
if (this.room && this.room.roomId == e.getRoomId() && e && e.getType() == STATE_EVENT_ROOM_TYPE) {
this.onRoomTypeMixinTypeEvent(e);
}
},
onRoomTypeMixinTypeEvent(e) {
if (e) {
const roomType = e.getContent().type;
// Validate value, or return default
if ([ROOM_TYPE_FILE_MODE, ROOM_TYPE_VOICE_MODE].includes(roomType)) {
this.roomDisplayType = roomType;
} else {
this.roomDisplayType = ROOM_TYPE_DEFAULT;
}
}
},
},
computed: { computed: {
availableRoomTypes() { availableRoomTypes() {
let types = [{ title: this.$t("room_info.room_type_default"), description: "", value: ROOM_TYPE_DEFAULT }]; let types = [{ title: this.$t("room_info.room_type_default"), description: "", value: ROOM_TYPE_DEFAULT }];

View file

@ -7,6 +7,8 @@ export const ROOM_TYPE_DEFAULT = "im.keanu.room_type_default";
export const ROOM_TYPE_VOICE_MODE = "im.keanu.room_type_voice"; export const ROOM_TYPE_VOICE_MODE = "im.keanu.room_type_voice";
export const ROOM_TYPE_FILE_MODE = "im.keanu.room_type_file"; export const ROOM_TYPE_FILE_MODE = "im.keanu.room_type_file";
export const STATE_EVENT_ROOM_TYPE = "im.keanu.room_type";
const sizeOf = require("image-size"); const sizeOf = require("image-size");
var dayjs = require('dayjs'); var dayjs = require('dayjs');
@ -482,19 +484,19 @@ class Util {
/** /**
* Return what "mode" to use for the given room. * Return what "mode" to use for the given room.
* *
* The default value is given by the room itself. If the "type" of the * The default value is given by the room itself (as state events, see roomTypeMixin).
* room is set to 'im.keanu.room_type_voice' then we default to voice mode, * This method just returns if the user has overridden this in room settings (this
* else if set to 'im.keanu.room_type_file' we default to file mode. * fact will be persisted as a user specific tag on the room). Note: currently override
* The user can then override this default by changing the "room type" * is disabled in the UI...
* in room settings (it will be persisted as a user specific tag on the room)
*/ */
roomDisplayType(roomOrNull) { roomDisplayTypeOverride(roomOrNull) {
if (roomOrNull) { if (roomOrNull) {
const room = roomOrNull; const room = roomOrNull;
// Have we changed our local view mode of this room? // Have we changed our local view mode of this room?
const tags = room.tags; const tags = room.tags;
if (tags && tags["ui_options"]) { if (tags && tags["ui_options"]) {
console.error("We have a tag!");
if (tags["ui_options"]["voice_mode"] === 1) { if (tags["ui_options"]["voice_mode"] === 1) {
return ROOM_TYPE_VOICE_MODE; return ROOM_TYPE_VOICE_MODE;
} else if (tags["ui_options"]["file_mode"] === 1) { } else if (tags["ui_options"]["file_mode"] === 1) {
@ -504,30 +506,16 @@ class Util {
return ROOM_TYPE_DEFAULT; return ROOM_TYPE_DEFAULT;
} }
} }
// Was the room created with a voice mode type?
const createEvent = room.currentState.getStateEvents(
"m.room.create",
""
);
if (createEvent) {
const roomType = createEvent.getContent().type;
// Validate value, or return default
if ([ROOM_TYPE_FILE_MODE, ROOM_TYPE_VOICE_MODE].includes(roomType)) {
return roomType;
}
}
} }
return ROOM_TYPE_DEFAULT; return null;
} }
/** /**
* Return the room type for the current room * Return the room type for the current room
* @param {*} roomOrNull * @param {*} roomOrNull
*/ */
roomDisplayTypeToQueryParam(roomOrNull) { roomDisplayTypeToQueryParam(roomOrNull, roomDisplayType) {
const roomType = this.roomDisplayType(roomOrNull); const roomType = this.roomDisplayTypeOverride(roomOrNull) || roomDisplayType;
if (roomType === ROOM_TYPE_FILE_MODE) { if (roomType === ROOM_TYPE_FILE_MODE) {
// Send "file" here, so the receiver of the invite link knows to display the "file drop" join page // Send "file" here, so the receiver of the invite link knows to display the "file drop" join page
// instead of the standard one. // instead of the standard one.