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

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

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

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

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

@ -138,4 +138,27 @@ extension ChildrenAndParentsRoomExtension on Room {
child != null ? child._allSpaceChildRoomIds.contains(id) : false; child != null ? child._allSpaceChildRoomIds.contains(id) : false;
return canAddChild && !isCycle; 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); return _canAddAsParentOf(child, spaceMode: spaceMode);
} }
Future<void> pangeaSetSpaceChild(
String roomId, {
bool? suggested,
}) async =>
await _pangeaSetSpaceChild(roomId, suggested: suggested);
// class_and_exchange_settings // class_and_exchange_settings
DateTime? get rulesUpdatedAt => _rulesUpdatedAt; DateTime? get rulesUpdatedAt => _rulesUpdatedAt;

@ -116,7 +116,7 @@ extension RoomSettingsRoomExtension on Room {
Future<void> _setSuggestedInSpace(bool suggest, Room space) async { Future<void> _setSuggestedInSpace(bool suggest, Room space) async {
try { try {
await space.setSpaceChild(id, suggested: suggest); await space.pangeaSetSpaceChild(id, suggested: suggest);
} catch (err) { } catch (err) {
ErrorHandler.logError( ErrorHandler.logError(
e: "Failed to set suggestion status of room $id in space ${space.id}", 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 { class ClassChatPowerLevels {
static Future<Map<String, dynamic>> powerLevelOverrideForClassChat( static Future<Map<String, dynamic>> powerLevelOverrideForClassChat(
BuildContext context, BuildContext context,
List<Room> spaceParents, Room? parent,
) async { ) async {
final Client client = Matrix.of(context).client; final Client client = Matrix.of(context).client;
final Map<String, dynamic> powerLevelOverride = {}; final Map<String, dynamic> powerLevelOverride = {};
@ -18,8 +18,9 @@ class ClassChatPowerLevels {
powerLevelOverride['users'] = {}; powerLevelOverride['users'] = {};
final List<User> spaceAdmin = []; 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); spaceAdmin.addAll(classTeachers);
} }

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

Loading…
Cancel
Save