|
|
|
|
@@ -2,19 +2,13 @@
|
|
|
|
|
/* eslint-disable id-length */
|
|
|
|
|
/* eslint-disable @typescript-eslint/no-unused-vars,, complexity */
|
|
|
|
|
import { Injectable, inject } from '@angular/core';
|
|
|
|
|
import {
|
|
|
|
|
NavigationEnd,
|
|
|
|
|
Router
|
|
|
|
|
} from '@angular/router';
|
|
|
|
|
import { NavigationEnd, Router } from '@angular/router';
|
|
|
|
|
import {
|
|
|
|
|
Actions,
|
|
|
|
|
createEffect,
|
|
|
|
|
ofType
|
|
|
|
|
} from '@ngrx/effects';
|
|
|
|
|
import {
|
|
|
|
|
Action,
|
|
|
|
|
Store
|
|
|
|
|
} from '@ngrx/store';
|
|
|
|
|
import { Action, Store } from '@ngrx/store';
|
|
|
|
|
import {
|
|
|
|
|
of,
|
|
|
|
|
from,
|
|
|
|
|
@@ -53,6 +47,12 @@ import {
|
|
|
|
|
type ServerSourceSelector,
|
|
|
|
|
ServerDirectoryFacade
|
|
|
|
|
} from '../../domains/server-directory';
|
|
|
|
|
import {
|
|
|
|
|
normalizeRoomAccessControl,
|
|
|
|
|
resolveLegacyRole,
|
|
|
|
|
resolveRoomPermission,
|
|
|
|
|
withLegacyRoomPermissions
|
|
|
|
|
} from '../../domains/access-control';
|
|
|
|
|
import {
|
|
|
|
|
ChatEvent,
|
|
|
|
|
Room,
|
|
|
|
|
@@ -392,6 +392,10 @@ export class RoomsEffects {
|
|
|
|
|
...room,
|
|
|
|
|
isPrivate: typeof serverInfo?.isPrivate === 'boolean' ? serverInfo.isPrivate : room.isPrivate,
|
|
|
|
|
channels: resolveRoomChannels(room.channels, serverInfo?.channels),
|
|
|
|
|
slowModeInterval: serverInfo?.slowModeInterval ?? room.slowModeInterval,
|
|
|
|
|
roles: serverInfo?.roles ?? room.roles,
|
|
|
|
|
roleAssignments: serverInfo?.roleAssignments ?? room.roleAssignments,
|
|
|
|
|
channelPermissions: serverInfo?.channelPermissions ?? room.channelPermissions,
|
|
|
|
|
sourceId: serverInfo?.sourceId ?? room.sourceId,
|
|
|
|
|
sourceName: serverInfo?.sourceName ?? room.sourceName,
|
|
|
|
|
sourceUrl: serverInfo?.sourceUrl ?? room.sourceUrl,
|
|
|
|
|
@@ -406,6 +410,10 @@ export class RoomsEffects {
|
|
|
|
|
sourceName: resolvedRoom.sourceName,
|
|
|
|
|
sourceUrl: resolvedRoom.sourceUrl,
|
|
|
|
|
channels: resolvedRoom.channels,
|
|
|
|
|
slowModeInterval: resolvedRoom.slowModeInterval,
|
|
|
|
|
roles: resolvedRoom.roles,
|
|
|
|
|
roleAssignments: resolvedRoom.roleAssignments,
|
|
|
|
|
channelPermissions: resolvedRoom.channelPermissions,
|
|
|
|
|
hasPassword: resolvedRoom.hasPassword,
|
|
|
|
|
isPrivate: resolvedRoom.isPrivate
|
|
|
|
|
});
|
|
|
|
|
@@ -426,6 +434,10 @@ export class RoomsEffects {
|
|
|
|
|
userCount: 1,
|
|
|
|
|
maxUsers: 50,
|
|
|
|
|
channels: resolveRoomChannels(undefined, serverInfo.channels),
|
|
|
|
|
slowModeInterval: serverInfo.slowModeInterval,
|
|
|
|
|
roles: serverInfo.roles,
|
|
|
|
|
roleAssignments: serverInfo.roleAssignments,
|
|
|
|
|
channelPermissions: serverInfo.channelPermissions,
|
|
|
|
|
sourceId: serverInfo.sourceId,
|
|
|
|
|
sourceName: serverInfo.sourceName,
|
|
|
|
|
sourceUrl: serverInfo.sourceUrl
|
|
|
|
|
@@ -451,6 +463,10 @@ export class RoomsEffects {
|
|
|
|
|
userCount: serverData.userCount,
|
|
|
|
|
maxUsers: serverData.maxUsers,
|
|
|
|
|
channels: resolveRoomChannels(undefined, serverData.channels),
|
|
|
|
|
slowModeInterval: serverData.slowModeInterval,
|
|
|
|
|
roles: serverData.roles,
|
|
|
|
|
roleAssignments: serverData.roleAssignments,
|
|
|
|
|
channelPermissions: serverData.channelPermissions,
|
|
|
|
|
sourceId: serverData.sourceId,
|
|
|
|
|
sourceName: serverData.sourceName,
|
|
|
|
|
sourceUrl: serverData.sourceUrl
|
|
|
|
|
@@ -498,105 +514,102 @@ export class RoomsEffects {
|
|
|
|
|
{ dispatch: false }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/** Remembers the viewed room whenever a room becomes active. */
|
|
|
|
|
persistLastViewedChatOnRoomActivation$ = createEffect(
|
|
|
|
|
() =>
|
|
|
|
|
this.actions$.pipe(
|
|
|
|
|
ofType(RoomsActions.createRoomSuccess, RoomsActions.joinRoomSuccess, RoomsActions.viewServerSuccess),
|
|
|
|
|
withLatestFrom(this.store.select(selectCurrentUser)),
|
|
|
|
|
tap(([
|
|
|
|
|
{ room },
|
|
|
|
|
currentUser
|
|
|
|
|
]) => {
|
|
|
|
|
if (!currentUser) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const persisted = loadLastViewedChatFromStorage(currentUser.id);
|
|
|
|
|
const channelId = persisted?.roomId === room.id
|
|
|
|
|
? resolveTextChannelId(room.channels, persisted.channelId)
|
|
|
|
|
: resolveTextChannelId(room.channels);
|
|
|
|
|
|
|
|
|
|
saveLastViewedChatToStorage({
|
|
|
|
|
userId: currentUser.id,
|
|
|
|
|
roomId: room.id,
|
|
|
|
|
channelId
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
),
|
|
|
|
|
{ dispatch: false }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/** Remembers the currently selected text channel for the active room. */
|
|
|
|
|
persistLastViewedChatOnChannelSelection$ = createEffect(
|
|
|
|
|
() =>
|
|
|
|
|
this.actions$.pipe(
|
|
|
|
|
ofType(RoomsActions.selectChannel),
|
|
|
|
|
withLatestFrom(this.store.select(selectCurrentRoom), this.store.select(selectCurrentUser)),
|
|
|
|
|
tap(([
|
|
|
|
|
{ channelId },
|
|
|
|
|
currentRoom,
|
|
|
|
|
currentUser
|
|
|
|
|
]) => {
|
|
|
|
|
if (!currentRoom || !currentUser) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const resolvedChannelId = resolveTextChannelId(currentRoom.channels, channelId);
|
|
|
|
|
|
|
|
|
|
if (!resolvedChannelId || resolvedChannelId !== channelId) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saveLastViewedChatToStorage({
|
|
|
|
|
userId: currentUser.id,
|
|
|
|
|
roomId: currentRoom.id,
|
|
|
|
|
channelId
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
),
|
|
|
|
|
{ dispatch: false }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/** Restores the last viewed text channel once the active room's channels are known. */
|
|
|
|
|
restoreLastViewedTextChannel$ = createEffect(() =>
|
|
|
|
|
/** Remembers the viewed room whenever a room becomes active. */
|
|
|
|
|
persistLastViewedChatOnRoomActivation$ = createEffect(
|
|
|
|
|
() =>
|
|
|
|
|
this.actions$.pipe(
|
|
|
|
|
ofType(
|
|
|
|
|
RoomsActions.createRoomSuccess,
|
|
|
|
|
RoomsActions.joinRoomSuccess,
|
|
|
|
|
RoomsActions.viewServerSuccess,
|
|
|
|
|
RoomsActions.updateRoom
|
|
|
|
|
),
|
|
|
|
|
withLatestFrom(
|
|
|
|
|
this.store.select(selectCurrentUser),
|
|
|
|
|
this.store.select(selectCurrentRoom),
|
|
|
|
|
this.store.select(selectActiveChannelId)
|
|
|
|
|
),
|
|
|
|
|
mergeMap(([
|
|
|
|
|
, currentUser,
|
|
|
|
|
currentRoom,
|
|
|
|
|
activeChannelId
|
|
|
|
|
]) => {
|
|
|
|
|
if (!currentUser || !currentRoom) {
|
|
|
|
|
return EMPTY;
|
|
|
|
|
ofType(RoomsActions.createRoomSuccess, RoomsActions.joinRoomSuccess, RoomsActions.viewServerSuccess),
|
|
|
|
|
withLatestFrom(this.store.select(selectCurrentUser)),
|
|
|
|
|
tap(([{ room }, currentUser]) => {
|
|
|
|
|
if (!currentUser) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const persisted = loadLastViewedChatFromStorage(currentUser.id);
|
|
|
|
|
const channelId = persisted?.roomId === room.id
|
|
|
|
|
? resolveTextChannelId(room.channels, persisted.channelId)
|
|
|
|
|
: resolveTextChannelId(room.channels);
|
|
|
|
|
|
|
|
|
|
if (!persisted || persisted.roomId !== currentRoom.id) {
|
|
|
|
|
return EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const channelId = resolveTextChannelId(currentRoom.channels, persisted.channelId);
|
|
|
|
|
|
|
|
|
|
if (!channelId || channelId === activeChannelId) {
|
|
|
|
|
return EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return of(RoomsActions.selectChannel({ channelId }));
|
|
|
|
|
saveLastViewedChatToStorage({
|
|
|
|
|
userId: currentUser.id,
|
|
|
|
|
roomId: room.id,
|
|
|
|
|
channelId
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
),
|
|
|
|
|
{ dispatch: false }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/** Remembers the currently selected text channel for the active room. */
|
|
|
|
|
persistLastViewedChatOnChannelSelection$ = createEffect(
|
|
|
|
|
() =>
|
|
|
|
|
this.actions$.pipe(
|
|
|
|
|
ofType(RoomsActions.selectChannel),
|
|
|
|
|
withLatestFrom(this.store.select(selectCurrentRoom), this.store.select(selectCurrentUser)),
|
|
|
|
|
tap(([
|
|
|
|
|
{ channelId },
|
|
|
|
|
currentRoom,
|
|
|
|
|
currentUser
|
|
|
|
|
]) => {
|
|
|
|
|
if (!currentRoom || !currentUser) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const resolvedChannelId = resolveTextChannelId(currentRoom.channels, channelId);
|
|
|
|
|
|
|
|
|
|
if (!resolvedChannelId || resolvedChannelId !== channelId) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saveLastViewedChatToStorage({
|
|
|
|
|
userId: currentUser.id,
|
|
|
|
|
roomId: currentRoom.id,
|
|
|
|
|
channelId
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
),
|
|
|
|
|
{ dispatch: false }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/** Restores the last viewed text channel once the active room's channels are known. */
|
|
|
|
|
restoreLastViewedTextChannel$ = createEffect(() =>
|
|
|
|
|
this.actions$.pipe(
|
|
|
|
|
ofType(
|
|
|
|
|
RoomsActions.createRoomSuccess,
|
|
|
|
|
RoomsActions.joinRoomSuccess,
|
|
|
|
|
RoomsActions.viewServerSuccess,
|
|
|
|
|
RoomsActions.updateRoom
|
|
|
|
|
),
|
|
|
|
|
withLatestFrom(
|
|
|
|
|
this.store.select(selectCurrentUser),
|
|
|
|
|
this.store.select(selectCurrentRoom),
|
|
|
|
|
this.store.select(selectActiveChannelId)
|
|
|
|
|
),
|
|
|
|
|
mergeMap(([
|
|
|
|
|
, currentUser,
|
|
|
|
|
currentRoom,
|
|
|
|
|
activeChannelId
|
|
|
|
|
]) => {
|
|
|
|
|
if (!currentUser || !currentRoom) {
|
|
|
|
|
return EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const persisted = loadLastViewedChatFromStorage(currentUser.id);
|
|
|
|
|
|
|
|
|
|
if (!persisted || persisted.roomId !== currentRoom.id) {
|
|
|
|
|
return EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const channelId = resolveTextChannelId(currentRoom.channels, persisted.channelId);
|
|
|
|
|
|
|
|
|
|
if (!channelId || channelId === activeChannelId) {
|
|
|
|
|
return EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return of(RoomsActions.selectChannel({ channelId }));
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
refreshServerOwnedRoomMetadata$ = createEffect(() =>
|
|
|
|
|
this.actions$.pipe(
|
|
|
|
|
@@ -621,6 +634,10 @@ export class RoomsEffects {
|
|
|
|
|
isPrivate: serverData.isPrivate,
|
|
|
|
|
maxUsers: serverData.maxUsers,
|
|
|
|
|
channels: resolveRoomChannels(room.channels, serverData.channels),
|
|
|
|
|
slowModeInterval: serverData.slowModeInterval ?? room.slowModeInterval,
|
|
|
|
|
roles: serverData.roles ?? room.roles,
|
|
|
|
|
roleAssignments: serverData.roleAssignments ?? room.roleAssignments,
|
|
|
|
|
channelPermissions: serverData.channelPermissions ?? room.channelPermissions,
|
|
|
|
|
sourceId: serverData.sourceId ?? room.sourceId,
|
|
|
|
|
sourceName: serverData.sourceName ?? room.sourceName,
|
|
|
|
|
sourceUrl: serverData.sourceUrl ?? room.sourceUrl
|
|
|
|
|
@@ -856,7 +873,7 @@ export class RoomsEffects {
|
|
|
|
|
|
|
|
|
|
const currentUserRole = this.getUserRoleForRoom(room, currentUser, currentRoom);
|
|
|
|
|
const isOwner = currentUserRole === 'host';
|
|
|
|
|
const canManageRoom = currentUserRole === 'host' || currentUserRole === 'admin';
|
|
|
|
|
const canManageRoom = isOwner || resolveRoomPermission(room, currentUser, 'manageServer');
|
|
|
|
|
|
|
|
|
|
if (!canManageRoom) {
|
|
|
|
|
return of(
|
|
|
|
|
@@ -949,7 +966,10 @@ export class RoomsEffects {
|
|
|
|
|
this.store.select(selectCurrentUser),
|
|
|
|
|
this.store.select(selectCurrentRoom)
|
|
|
|
|
),
|
|
|
|
|
tap(([, currentUser, currentRoom]) => {
|
|
|
|
|
tap(([
|
|
|
|
|
, currentUser,
|
|
|
|
|
currentRoom
|
|
|
|
|
]) => {
|
|
|
|
|
if (!currentUser || !currentRoom) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -1008,27 +1028,93 @@ export class RoomsEffects {
|
|
|
|
|
if (!room)
|
|
|
|
|
return EMPTY;
|
|
|
|
|
|
|
|
|
|
const isOwner =
|
|
|
|
|
room.hostId === currentUser.id ||
|
|
|
|
|
room.hostId === currentUser.oderId ||
|
|
|
|
|
(currentRoom?.id === room.id && currentUser.role === 'host');
|
|
|
|
|
const nextRoom = withLegacyRoomPermissions(room, permissions);
|
|
|
|
|
|
|
|
|
|
if (!isOwner)
|
|
|
|
|
return of(RoomsActions.updateRoomAccessControl({
|
|
|
|
|
roomId: room.id,
|
|
|
|
|
changes: {
|
|
|
|
|
roles: nextRoom.roles,
|
|
|
|
|
roleAssignments: nextRoom.roleAssignments,
|
|
|
|
|
channelPermissions: nextRoom.channelPermissions,
|
|
|
|
|
slowModeInterval: nextRoom.slowModeInterval
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
updateRoomAccessControl$ = createEffect(() =>
|
|
|
|
|
this.actions$.pipe(
|
|
|
|
|
ofType(RoomsActions.updateRoomAccessControl),
|
|
|
|
|
withLatestFrom(
|
|
|
|
|
this.store.select(selectCurrentUser),
|
|
|
|
|
this.store.select(selectCurrentRoom),
|
|
|
|
|
this.store.select(selectSavedRooms)
|
|
|
|
|
),
|
|
|
|
|
mergeMap(([
|
|
|
|
|
{ roomId, changes },
|
|
|
|
|
currentUser,
|
|
|
|
|
currentRoom,
|
|
|
|
|
savedRooms
|
|
|
|
|
]) => {
|
|
|
|
|
if (!currentUser)
|
|
|
|
|
return EMPTY;
|
|
|
|
|
|
|
|
|
|
const updated: Partial<Room> = {
|
|
|
|
|
permissions: { ...(room.permissions || {}),
|
|
|
|
|
...permissions } as RoomPermissions
|
|
|
|
|
const room = this.resolveRoom(roomId, currentRoom, savedRooms);
|
|
|
|
|
|
|
|
|
|
if (!room)
|
|
|
|
|
return EMPTY;
|
|
|
|
|
|
|
|
|
|
const requiresRoleManagement = !!changes.roles || !!changes.roleAssignments || !!changes.channelPermissions;
|
|
|
|
|
const requiresServerManagement = typeof changes.slowModeInterval === 'number';
|
|
|
|
|
const isOwner = room.hostId === currentUser.id || room.hostId === currentUser.oderId;
|
|
|
|
|
const canManageRoles = isOwner || resolveRoomPermission(room, currentUser, 'manageRoles');
|
|
|
|
|
const canManageServer = isOwner || resolveRoomPermission(room, currentUser, 'manageServer');
|
|
|
|
|
|
|
|
|
|
if ((requiresRoleManagement && !canManageRoles) || (requiresServerManagement && !canManageServer)) {
|
|
|
|
|
return EMPTY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const nextRoom = normalizeRoomAccessControl({
|
|
|
|
|
...room,
|
|
|
|
|
...changes
|
|
|
|
|
});
|
|
|
|
|
const nextChanges: Partial<Room> = {
|
|
|
|
|
roles: nextRoom.roles,
|
|
|
|
|
roleAssignments: nextRoom.roleAssignments,
|
|
|
|
|
channelPermissions: nextRoom.channelPermissions,
|
|
|
|
|
slowModeInterval: nextRoom.slowModeInterval,
|
|
|
|
|
permissions: nextRoom.permissions,
|
|
|
|
|
members: nextRoom.members
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.webrtc.broadcastMessage({
|
|
|
|
|
type: 'room-permissions-update',
|
|
|
|
|
roomId: room.id,
|
|
|
|
|
permissions: updated.permissions
|
|
|
|
|
permissions: nextRoom.permissions,
|
|
|
|
|
room: {
|
|
|
|
|
roles: nextRoom.roles,
|
|
|
|
|
roleAssignments: nextRoom.roleAssignments,
|
|
|
|
|
channelPermissions: nextRoom.channelPermissions,
|
|
|
|
|
slowModeInterval: nextRoom.slowModeInterval
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.serverDirectory.updateServer(room.id, {
|
|
|
|
|
currentOwnerId: currentUser.id,
|
|
|
|
|
roles: nextRoom.roles,
|
|
|
|
|
roleAssignments: nextRoom.roleAssignments,
|
|
|
|
|
channelPermissions: nextRoom.channelPermissions,
|
|
|
|
|
slowModeInterval: nextRoom.slowModeInterval
|
|
|
|
|
}, {
|
|
|
|
|
sourceId: room.sourceId,
|
|
|
|
|
sourceUrl: room.sourceUrl
|
|
|
|
|
}).subscribe({
|
|
|
|
|
error: () => {}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return of(RoomsActions.updateRoom({ roomId: room.id,
|
|
|
|
|
changes: updated }));
|
|
|
|
|
changes: nextChanges }));
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
@@ -1047,12 +1133,8 @@ export class RoomsEffects {
|
|
|
|
|
return of(RoomsActions.updateServerIconFailure({ error: 'Not in room' }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const role = currentUser.role;
|
|
|
|
|
const perms = currentRoom.permissions || {};
|
|
|
|
|
const isOwner = currentRoom.hostId === currentUser.id;
|
|
|
|
|
const canByRole =
|
|
|
|
|
(role === 'admin' && perms.adminsManageIcon) ||
|
|
|
|
|
(role === 'moderator' && perms.moderatorsManageIcon);
|
|
|
|
|
const canByRole = resolveRoomPermission(currentRoom, currentUser, 'manageIcon');
|
|
|
|
|
|
|
|
|
|
if (!isOwner && !canByRole) {
|
|
|
|
|
return of(RoomsActions.updateServerIconFailure({ error: 'Permission denied' }));
|
|
|
|
|
@@ -1472,6 +1554,7 @@ export class RoomsEffects {
|
|
|
|
|
serverDescription: room.description,
|
|
|
|
|
serverRoute: `/room/${room.id}`
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.voiceSessionService.setViewingVoiceServer(wasViewingVoiceServer);
|
|
|
|
|
this.webrtc.broadcastMessage({
|
|
|
|
|
type: 'voice-state',
|
|
|
|
|
@@ -1522,9 +1605,13 @@ export class RoomsEffects {
|
|
|
|
|
maxUsers: typeof room.maxUsers === 'number' ? room.maxUsers : undefined,
|
|
|
|
|
icon: typeof room.icon === 'string' ? room.icon : undefined,
|
|
|
|
|
iconUpdatedAt: typeof room.iconUpdatedAt === 'number' ? room.iconUpdatedAt : undefined,
|
|
|
|
|
slowModeInterval: typeof room.slowModeInterval === 'number' ? room.slowModeInterval : undefined,
|
|
|
|
|
permissions: room.permissions ? { ...room.permissions } : undefined,
|
|
|
|
|
channels: Array.isArray(room.channels) ? room.channels : undefined,
|
|
|
|
|
members: Array.isArray(room.members) ? room.members : undefined,
|
|
|
|
|
roles: Array.isArray(room.roles) ? room.roles : undefined,
|
|
|
|
|
roleAssignments: Array.isArray(room.roleAssignments) ? room.roleAssignments : undefined,
|
|
|
|
|
channelPermissions: Array.isArray(room.channelPermissions) ? room.channelPermissions : undefined,
|
|
|
|
|
sourceId: typeof room.sourceId === 'string' ? room.sourceId : undefined,
|
|
|
|
|
sourceName: typeof room.sourceName === 'string' ? room.sourceName : undefined,
|
|
|
|
|
sourceUrl: typeof room.sourceUrl === 'string' ? room.sourceUrl : undefined
|
|
|
|
|
@@ -1665,16 +1752,23 @@ export class RoomsEffects {
|
|
|
|
|
const roomId = typeof event.roomId === 'string' ? event.roomId : currentRoom?.id;
|
|
|
|
|
const room = this.resolveRoom(roomId, currentRoom, savedRooms);
|
|
|
|
|
const permissions = event.permissions as Partial<RoomPermissions> | undefined;
|
|
|
|
|
const incomingRoom = event.room as Partial<Room> | undefined;
|
|
|
|
|
|
|
|
|
|
if (!room || !permissions)
|
|
|
|
|
if (!room || (!permissions && !incomingRoom))
|
|
|
|
|
return EMPTY;
|
|
|
|
|
|
|
|
|
|
return of(
|
|
|
|
|
RoomsActions.updateRoom({
|
|
|
|
|
roomId: room.id,
|
|
|
|
|
changes: {
|
|
|
|
|
permissions: { ...(room.permissions || {}),
|
|
|
|
|
...permissions } as RoomPermissions
|
|
|
|
|
permissions: permissions
|
|
|
|
|
? { ...(room.permissions || {}),
|
|
|
|
|
...permissions } as RoomPermissions
|
|
|
|
|
: room.permissions,
|
|
|
|
|
roles: Array.isArray(incomingRoom?.roles) ? incomingRoom.roles : room.roles,
|
|
|
|
|
roleAssignments: Array.isArray(incomingRoom?.roleAssignments) ? incomingRoom.roleAssignments : room.roleAssignments,
|
|
|
|
|
channelPermissions: Array.isArray(incomingRoom?.channelPermissions) ? incomingRoom.channelPermissions : room.channelPermissions,
|
|
|
|
|
slowModeInterval: typeof incomingRoom?.slowModeInterval === 'number' ? incomingRoom.slowModeInterval : room.slowModeInterval
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
@@ -1764,11 +1858,8 @@ export class RoomsEffects {
|
|
|
|
|
if (!sender)
|
|
|
|
|
return EMPTY;
|
|
|
|
|
|
|
|
|
|
const perms = room.permissions || {};
|
|
|
|
|
const isOwner = room.hostId === sender.id;
|
|
|
|
|
const canByRole =
|
|
|
|
|
(sender.role === 'admin' && perms.adminsManageIcon) ||
|
|
|
|
|
(sender.role === 'moderator' && perms.moderatorsManageIcon);
|
|
|
|
|
const canByRole = resolveRoomPermission(room, sender, 'manageIcon');
|
|
|
|
|
|
|
|
|
|
if (!isOwner && !canByRole)
|
|
|
|
|
return EMPTY;
|
|
|
|
|
@@ -2004,15 +2095,7 @@ export class RoomsEffects {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private getUserRoleForRoom(room: Room, currentUser: User, currentRoom: Room | null): User['role'] | null {
|
|
|
|
|
if (room.hostId === currentUser.id || room.hostId === currentUser.oderId)
|
|
|
|
|
return 'host';
|
|
|
|
|
|
|
|
|
|
if (currentRoom?.id === room.id && currentUser.role)
|
|
|
|
|
return currentUser.role;
|
|
|
|
|
|
|
|
|
|
return findRoomMember(room.members ?? [], currentUser.id)?.role
|
|
|
|
|
|| findRoomMember(room.members ?? [], currentUser.oderId)?.role
|
|
|
|
|
|| null;
|
|
|
|
|
return resolveLegacyRole(currentRoom?.id === room.id ? currentRoom : room, currentUser);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private canManageChannelsInRoom(
|
|
|
|
|
@@ -2021,21 +2104,7 @@ export class RoomsEffects {
|
|
|
|
|
currentRoom: Room | null,
|
|
|
|
|
currentUserRole = this.getUserRoleForRoom(room, currentUser, currentRoom)
|
|
|
|
|
): boolean {
|
|
|
|
|
if (currentUserRole === 'host') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const permissions = room.permissions || {};
|
|
|
|
|
|
|
|
|
|
if (currentUserRole === 'admin' && permissions.adminsManageRooms) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (currentUserRole === 'moderator' && permissions.moderatorsManageRooms) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
return currentUserRole === 'host' || resolveRoomPermission(room, currentUser, 'manageChannels');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private getPersistedCurrentUserId(): string | null {
|
|
|
|
|
|