Merge pull request #443 from pangeachat/only-one-direct-parent

prevent adding a room to multiple spaces
pull/1384/head
ggurdin 1 year ago committed by GitHub
commit 628871ed3d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -9,7 +9,6 @@ import 'package:fluffychat/pangea/constants/pangea_room_types.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
import 'package:fluffychat/pangea/utils/add_to_space.dart';
import 'package:fluffychat/pangea/utils/chat_list_handle_space_tap.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:fluffychat/pangea/utils/firebase_analytics.dart';
@ -843,18 +842,12 @@ class ChatListController extends State<ChatList>
if (firstSelectedRoom.isSpace && !space.isRoomAdmin) {
throw L10n.of(context)!.cantAddSpaceChild;
}
await pangeaAddToSpace(
space,
selectedRoomIds.toList(),
context,
pangeaController,
);
// if (space.canSendDefaultStates) {
// for (final roomId in selectedRoomIds) {
// await space.setSpaceChild(roomId);
// }
// }
if (space.canSendDefaultStates) {
for (final roomId in selectedRoomIds) {
await space.pangeaSetSpaceChild(roomId);
}
}
// Pangea#
},
);

@ -137,7 +137,11 @@ class ChatListHeader extends StatelessWidget implements PreferredSizeWidget {
]
: selectMode == SelectMode.select
? [
if (controller.spaces.isNotEmpty)
// #Pangea
// if (controller.spaces.isNotEmpty)
if (controller.spaces.isNotEmpty &&
controller.selectedRoomIds.length == 1)
// Pangea#
IconButton(
tooltip: L10n.of(context)!.addToSpace,
icon: const Icon(Icons.workspaces_outlined),

@ -856,24 +856,22 @@ class _SpaceViewState extends State<SpaceView> {
),
// Pangea#
),
// #Pangea
// if (activeSpace?.canChangeStateEvent(
// EventTypes.SpaceChild,
// ) ==
// true)
// Material(
// child: ListTile(
// leading: const CircleAvatar(
// child: Icon(Icons.group_add_outlined),
// ),
// title:
// Text(L10n.of(context)!.addChatOrSubSpace),
// trailing:
// const Icon(Icons.chevron_right_outlined),
// onTap: _addChatOrSubSpace,
// ),
// ),
// Pangea#
if (activeSpace?.canChangeStateEvent(
EventTypes.SpaceChild,
) ==
true)
Material(
child: ListTile(
leading: const CircleAvatar(
child: Icon(Icons.group_add_outlined),
),
title:
Text(L10n.of(context)!.addChatOrSubSpace),
trailing:
const Icon(Icons.chevron_right_outlined),
onTap: _addChatOrSubSpace,
),
),
],
);
}

@ -134,7 +134,7 @@ class NewGroupController extends State<NewGroup> {
powerLevelContentOverride:
await ClassChatPowerLevels.powerLevelOverrideForClassChat(
context,
addToSpaceKey.currentState!.parents,
addToSpaceKey.currentState!.parent,
),
invite: [
if (addConversationBotKey.currentState?.addBot ?? false)

@ -171,7 +171,7 @@ class NewSpaceController extends State<NewSpace> {
powerLevelContentOverride: addToSpaceKey.currentState != null
? await ClassChatPowerLevels.powerLevelOverrideForClassChat(
context,
addToSpaceKey.currentState!.parents,
addToSpaceKey.currentState!.parent,
)
: null,
// initialState: [

@ -138,4 +138,27 @@ extension ChildrenAndParentsRoomExtension on Room {
child != null ? child._allSpaceChildRoomIds.contains(id) : false;
return canAddChild && !isCycle;
}
/// Wrapper around call to setSpaceChild with added functionality
/// to prevent adding one room to multiple spaces
Future<void> _pangeaSetSpaceChild(
String roomId, {
bool? suggested,
}) async {
final Room? child = client.getRoomById(roomId);
if (child != null) {
final List<Room> spaceParents = child.pangeaSpaceParents;
for (final Room parent in spaceParents) {
try {
await parent.removeSpaceChild(roomId);
} catch (e) {
ErrorHandler.logError(
e: e,
m: 'Failed to remove child from parent',
);
}
}
await setSpaceChild(roomId, suggested: suggested);
}
}
}

@ -116,6 +116,12 @@ extension PangeaRoom on Room {
return _canAddAsParentOf(child, spaceMode: spaceMode);
}
Future<void> pangeaSetSpaceChild(
String roomId, {
bool? suggested,
}) async =>
await _pangeaSetSpaceChild(roomId, suggested: suggested);
// class_and_exchange_settings
DateTime? get rulesUpdatedAt => _rulesUpdatedAt;

@ -116,7 +116,7 @@ extension RoomSettingsRoomExtension on Room {
Future<void> _setSuggestedInSpace(bool suggest, Room space) async {
try {
await space.setSpaceChild(id, suggested: suggest);
await space.pangeaSetSpaceChild(id, suggested: suggest);
} catch (err) {
ErrorHandler.logError(
e: "Failed to set suggestion status of room $id in space ${space.id}",

@ -1,41 +0,0 @@
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart';
bool canAddToSpace(Room space, PangeaController pangeaController) {
final bool pangeaPermission =
pangeaController.permissionsController.canUserGroupChat(roomID: space.id);
final Map<String, dynamic> powerLevelsMap =
space.getState(EventTypes.RoomPowerLevels)?.content ?? {};
final pl = powerLevelsMap
.tryGetMap<String, dynamic>('events')
?.tryGet<int>(EventTypes.SpaceChild) ??
powerLevelsMap.tryGet<int>('events_default') ??
50;
return space.ownPowerLevel >= pl && pangeaPermission;
}
bool chatIsInSpace(Room chat, Room space) {
return chat.spaceParents.map((e) => e.roomId).toList().contains(space.id);
}
Future<void> pangeaAddToSpace(
Room space,
List<String> selectedRoomIds,
BuildContext context,
PangeaController pangeaController, {
bool suggested = true,
}) async {
if (!canAddToSpace(space, pangeaController)) {
throw L10n.of(context)!.noAddToSpacePermissions;
}
for (final roomId in selectedRoomIds) {
final Room? room = Matrix.of(context).client.getRoomById(roomId);
if (room != null && chatIsInSpace(room, space)) {
throw L10n.of(context)!.alreadyInSpace;
}
await space.setSpaceChild(roomId, suggested: suggested);
}
}

@ -8,7 +8,7 @@ import '../extensions/pangea_room_extension/pangea_room_extension.dart';
class ClassChatPowerLevels {
static Future<Map<String, dynamic>> powerLevelOverrideForClassChat(
BuildContext context,
List<Room> spaceParents,
Room? parent,
) async {
final Client client = Matrix.of(context).client;
final Map<String, dynamic> powerLevelOverride = {};
@ -18,8 +18,9 @@ class ClassChatPowerLevels {
powerLevelOverride['users'] = {};
final List<User> spaceAdmin = [];
for (final classRoom in spaceParents) {
final List<User> classTeachers = await classRoom.teachers;
if (parent != null) {
final List<User> classTeachers = await parent.teachers;
spaceAdmin.addAll(classTeachers);
}

@ -32,7 +32,7 @@ class AddToSpaceToggles extends StatefulWidget {
class AddToSpaceState extends State<AddToSpaceToggles> {
late Room? room;
late List<Room> parents;
late Room? parent;
late List<Room> possibleParents;
late bool isOpen;
late bool isSuggested;
@ -70,20 +70,17 @@ class AddToSpaceState extends State<AddToSpaceToggles> {
)
.toList();
parents = widget.roomId != null
? possibleParents
.where(
(r) =>
r.spaceChildren.any((room) => room.roomId == widget.roomId),
)
.toList()
: [];
parent = widget.roomId != null
? possibleParents.firstWhereOrNull(
(r) => r.spaceChildren.any((room) => room.roomId == widget.roomId),
)
: null;
if (widget.activeSpaceId != null) {
final activeSpace =
Matrix.of(context).client.getRoomById(widget.activeSpaceId!);
if (activeSpace != null && activeSpace.canIAddSpaceChild(null)) {
parents.add(activeSpace);
parent = activeSpace;
} else {
ErrorHandler.logError(
e: Exception('activeSpaceId ${widget.activeSpaceId} not found'),
@ -95,9 +92,9 @@ class AddToSpaceState extends State<AddToSpaceToggles> {
//if possibleParent in parents, put first
//use sort but use any instead of contains because contains uses == and we want to compare by id
possibleParents.sort((a, b) {
if (parents.any((parent) => parent.id == a.id)) {
if (parent?.id == a.id) {
return -1;
} else if (parents.any((parent) => parent.id == b.id)) {
} else if (parent?.id == b.id) {
return 1;
} else {
return a.name.compareTo(b.name);
@ -109,18 +106,15 @@ class AddToSpaceState extends State<AddToSpaceToggles> {
Future<void> _addSingleSpace(String roomToAddId, Room newParent) async {
GoogleAnalytics.addParent(roomToAddId, newParent.classCode);
await newParent.setSpaceChild(
await newParent.pangeaSetSpaceChild(
roomToAddId,
suggested: isSuggested,
);
}
Future<void> addSpaces(String roomToAddId) async {
final List<Future<void>> addFutures = [];
for (final Room parent in parents) {
addFutures.add(_addSingleSpace(roomToAddId, parent));
}
await addFutures.wait;
if (parent == null) return;
await _addSingleSpace(roomToAddId, parent!);
}
Future<void> handleAdd(bool add, Room possibleParent) async {
@ -142,11 +136,7 @@ class AddToSpaceState extends State<AddToSpaceToggles> {
}
setState(
() => add
? parents.add(possibleParent)
: parents.removeWhere(
(parent) => parent.id == possibleParent.id,
),
() => add ? parent = possibleParent : parent = null,
);
}
@ -164,7 +154,7 @@ class AddToSpaceState extends State<AddToSpaceToggles> {
SwitchListTile.adaptive(
title: possibleParent.nameAndRoomTypeIcon(),
activeColor: AppConfig.activeToggleColor,
value: parents.any((r) => r.id == possibleParent.id),
value: parent?.id == possibleParent.id,
onChanged: (bool add) => canAdd
? handleAdd(add, possibleParent)
: ScaffoldMessenger.of(context).showSnackBar(

Loading…
Cancel
Save