chore: add join codes to all new rooms and add join code to existing room on visit invite page if user has permission (#3463)

This commit is contained in:
ggurdin 2025-07-15 11:29:44 -04:00 committed by GitHub
parent 8493e28d96
commit e9af147257
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 183 additions and 148 deletions

View file

@ -5,7 +5,7 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/chat_settings/pages/pangea_chat_access_settings.dart';
import 'package:fluffychat/pangea/spaces/utils/client_spaces_extension.dart';
import 'package:fluffychat/pangea/extensions/join_rule_extension.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_modal_action_popup.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
@ -70,8 +70,7 @@ class ChatAccessSettingsController extends State<ChatAccessSettings> {
try {
// #Pangea
// await room.setJoinRules(newJoinRules);
await room.client.pangeaSetJoinRules(
room.id,
await room.pangeaSetJoinRules(
newJoinRules.toString().replaceAll('JoinRules.', ''),
);
// Pangea#

View file

@ -15,11 +15,10 @@ import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart';
import 'package:fluffychat/pangea/chat_settings/pages/pangea_chat_details.dart';
import 'package:fluffychat/pangea/chat_settings/utils/download_chat.dart';
import 'package:fluffychat/pangea/chat_settings/utils/download_file.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
import 'package:fluffychat/pangea/extensions/join_rule_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/spaces/utils/space_code.dart';
import 'package:fluffychat/utils/file_selector.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/platform_infos.dart';
@ -339,7 +338,6 @@ class ChatDetailsController extends State<ChatDetails> {
future: () async {
final activeSpace = client.getRoomById(roomId!)!;
await activeSpace.postLoad();
final accessCode = await SpaceCodeUtil.generateSpaceCode(client);
final resp = await client.createRoom(
name: names,
@ -347,18 +345,14 @@ class ChatDetailsController extends State<ChatDetails> {
creationContent: {'type': 'm.space'},
initialState: [
RoomDefaults.defaultSpacePowerLevels(client.userID!),
StateEvent(
type: EventTypes.RoomJoinRules,
content: {
'join_rule': 'knock_restricted',
'allow': [
{
"type": "m.room_membership",
"room_id": roomId!,
}
],
ModelKey.accessCode: accessCode,
},
await client.pangeaJoinRules(
'knock_restricted',
allow: [
{
"type": "m.room_membership",
"room_id": roomId!,
}
],
),
],
);

View file

@ -23,8 +23,8 @@ import 'package:fluffychat/pangea/chat_settings/utils/delete_room.dart';
import 'package:fluffychat/pangea/chat_settings/widgets/delete_space_dialog.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/extensions/join_rule_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/spaces/utils/client_spaces_extension.dart';
import 'package:fluffychat/pangea/subscription/widgets/subscription_snackbar.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
@ -1057,7 +1057,7 @@ class ChatListController extends State<ChatList>
);
// #Pangea
try {
await space.client.setSpaceChildAccess(room.id);
await space.setSpaceChildAccess();
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
@ -1077,7 +1077,7 @@ class ChatListController extends State<ChatList>
},
);
try {
await room.client.resetSpaceChildAccess(room.id);
await room.resetSpaceChildAccess();
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(

View file

@ -12,6 +12,7 @@ import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
import 'package:fluffychat/pangea/chat/constants/default_power_level.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart';
import 'package:fluffychat/pangea/extensions/join_rule_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/spaces/utils/client_spaces_extension.dart';
import 'package:fluffychat/utils/file_selector.dart';
@ -142,19 +143,21 @@ class NewGroupController extends State<NewGroup> {
RoomDefaults.defaultPowerLevels(
Matrix.of(context).client.userID!,
),
if (widget.spaceId != null)
StateEvent(
type: EventTypes.RoomJoinRules,
content: {
'join_rule': 'knock_restricted',
'allow': [
{
"type": "m.room_membership",
"room_id": widget.spaceId,
}
],
},
),
await Matrix.of(context).client.pangeaJoinRules(
widget.spaceId != null
? 'knock_restricted'
: JoinRules.public
.toString()
.replaceAll('JoinRules.', ''),
allow: widget.spaceId != null
? [
{
"type": "m.room_membership",
"room_id": widget.spaceId,
}
]
: null,
),
// Pangea#
],
// #Pangea

View file

@ -9,6 +9,9 @@ import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
import 'package:fluffychat/pangea/chat_settings/pages/pangea_invitation_selection_view.dart';
import 'package:fluffychat/pangea/common/config/environment.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/extensions/join_rule_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/utils/localized_exception_extension.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
@ -131,6 +134,8 @@ class PangeaInvitationSelectionController
controller.addListener(() {
setState(() {});
});
_addJoinCode();
}
String filterLabel(InvitationFilter filter) {
@ -321,6 +326,22 @@ class PangeaInvitationSelectionController
);
}
Future<void> _addJoinCode() async {
if (_room == null || _room!.classCode != null) return;
if (!_room!.canChangeStateEvent(EventTypes.RoomJoinRules)) return;
try {
await _room!.addJoinCode();
if (mounted) setState(() {});
} catch (e, s) {
ErrorHandler.logError(
e: e,
s: s,
data: {'roomId': _room!.id},
);
}
}
Future<void> searchUser(BuildContext context, String text) async {
coolDown?.cancel();
if (text.isEmpty) {

View file

@ -262,7 +262,7 @@ class PangeaInvitationSelectionView extends StatelessWidget {
Row(
spacing: 12.0,
children: [
if (room.isSpace && room.classCode != null)
if (room.classCode != null)
Expanded(
child: PopupMenuButton<int>(
borderRadius: BorderRadius.circular(32.0),
@ -342,7 +342,7 @@ class PangeaInvitationSelectionView extends StatelessWidget {
],
),
),
room.isSpace && room.classCode != null
room.classCode != null
? doneButton
: Expanded(child: doneButton),
],

View file

@ -0,0 +1,110 @@
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/spaces/utils/space_code.dart';
extension JoinRuleExtension on Client {
Future<StateEvent> pangeaJoinRules(
String joinRule, {
List<Map<String, dynamic>>? allow,
}) async {
String? joinCode;
try {
joinCode = await SpaceCodeUtil.generateSpaceCode(this);
} catch (e, s) {
ErrorHandler.logError(
e: e,
s: s,
data: {
'joinRule': joinRule,
},
);
}
return StateEvent(
type: EventTypes.RoomJoinRules,
content: {
ModelKey.joinRule: joinRule,
if (joinCode != null) ModelKey.accessCode: joinCode,
if (allow != null) 'allow': allow,
},
);
}
}
extension JoinRuleExtensionOnRoom on Room {
Future<void> addJoinCode() async {
if (!canChangeStateEvent(EventTypes.RoomJoinRules)) {
throw Exception('Cannot change join rules for this room');
}
final currentJoinRules = getState(EventTypes.RoomJoinRules)?.content ?? {};
if (currentJoinRules[ModelKey.accessCode] != null) return;
final joinCode = await SpaceCodeUtil.generateSpaceCode(client);
currentJoinRules[ModelKey.accessCode] = joinCode;
await client.setRoomStateWithKey(
id,
EventTypes.RoomJoinRules,
'',
currentJoinRules,
);
}
/// Keep the room's current join rule state event content (except for what's intentionally replaced)
/// since space's access codes were stored there. Don't want to accidentally remove them.
Future<void> pangeaSetJoinRules(
String joinRule, {
List<Map<String, dynamic>>? allow,
}) async {
final currentJoinRule = getState(
EventTypes.RoomJoinRules,
)?.content ??
{};
if (currentJoinRule[ModelKey.joinRule] == joinRule &&
(currentJoinRule['allow'] == allow)) {
return; // No change needed
}
currentJoinRule[ModelKey.joinRule] = joinRule;
currentJoinRule['allow'] = allow;
await client.setRoomStateWithKey(
id,
EventTypes.RoomJoinRules,
'',
currentJoinRule,
);
}
Future<void> setSpaceChildAccess() async {
await pangeaSetJoinRules(
'knock_restricted',
allow: [
{
"type": "m.room_membership",
"room_id": id,
}
],
);
await client.setRoomVisibilityOnDirectory(
id,
visibility: Visibility.private,
);
}
Future<void> resetSpaceChildAccess() async {
await pangeaSetJoinRules(
JoinRules.knock.toString().replaceAll('JoinRules.', ''),
);
await client.setRoomVisibilityOnDirectory(
id,
visibility: Visibility.private,
);
}
}

View file

@ -2,7 +2,6 @@ part of "pangea_room_extension.dart";
extension SpaceRoomExtension on Room {
String? get classCode {
if (!isSpace) return null;
final roomJoinRules = getState(EventTypes.RoomJoinRules, "");
if (roomJoinRules != null) {
final accessCode = roomJoinRules.content.tryGet(ModelKey.accessCode);

View file

@ -5,11 +5,10 @@ import 'package:http/http.dart' as http;
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/chat/constants/default_power_level.dart';
import 'package:fluffychat/pangea/common/constants/model_keys.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/extensions/join_rule_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/spaces/constants/space_constants.dart';
import 'package:fluffychat/pangea/spaces/utils/space_code.dart';
extension SpacesClientExtension on Client {
Future<String> createPangeaSpace({
@ -21,17 +20,15 @@ extension SpacesClientExtension on Client {
Uint8List? avatar,
Uri? avatarUrl,
}) async {
final joinCode = await SpaceCodeUtil.generateSpaceCode(this);
final roomId = await createRoom(
creationContent: {'type': RoomCreationTypes.mSpace},
visibility: visibility,
name: name.trim(),
powerLevelContentOverride: {'events_default': 100},
initialState: [
..._spaceInitialState(
userID!,
joinCode,
joinRules: joinRules,
RoomDefaults.defaultSpacePowerLevels(userID!),
await pangeaJoinRules(
joinRules.toString().replaceAll('JoinRules.', ''),
),
if (avatar != null)
StateEvent(
@ -123,17 +120,14 @@ extension SpacesClientExtension on Client {
content: {'url': introChatUploadURL.toString()},
),
RoomDefaults.defaultPowerLevels(userID!),
StateEvent(
type: EventTypes.RoomJoinRules,
content: {
'join_rule': 'knock_restricted',
'allow': [
{
"type": "m.room_membership",
"room_id": space.id,
}
],
},
await pangeaJoinRules(
'knock_restricted',
allow: [
{
"type": "m.room_membership",
"room_id": space.id,
}
],
),
],
);
@ -151,17 +145,14 @@ extension SpacesClientExtension on Client {
content: {'url': announcementsChatUploadURL.toString()},
),
RoomDefaults.restrictedPowerLevels(userID!),
StateEvent(
type: EventTypes.RoomJoinRules,
content: {
'join_rule': 'knock_restricted',
'allow': [
{
"type": "m.room_membership",
"room_id": space.id,
}
],
},
await pangeaJoinRules(
'knock_restricted',
allow: [
{
"type": "m.room_membership",
"room_id": space.id,
}
],
),
],
);
@ -195,86 +186,4 @@ extension SpacesClientExtension on Client {
addAnnouncementsChatFuture,
]);
}
List<StateEvent> _spaceInitialState(
String userID,
String joinCode, {
required JoinRules joinRules,
}) {
return [
RoomDefaults.defaultSpacePowerLevels(userID),
StateEvent(
type: EventTypes.RoomJoinRules,
content: {
ModelKey.joinRule: joinRules.toString().replaceAll('JoinRules.', ''),
ModelKey.accessCode: joinCode,
},
),
];
}
/// Keep the room's current join rule state event content (except for what's intentionally replaced)
/// since space's access codes were stored there. Don't want to accidentally remove them.
Future<void> pangeaSetJoinRules(
String roomId,
String joinRule, {
List<Map<String, dynamic>>? allow,
}) async {
final room = getRoomById(roomId);
if (room == null) {
throw Exception('Room not found for user ID: $userID');
}
final currentJoinRule = room
.getState(
EventTypes.RoomJoinRules,
)
?.content ??
{};
if (currentJoinRule[ModelKey.joinRule] == joinRule &&
(currentJoinRule['allow'] == allow)) {
return; // No change needed
}
currentJoinRule[ModelKey.joinRule] = joinRule;
currentJoinRule['allow'] = allow;
await setRoomStateWithKey(
roomId,
EventTypes.RoomJoinRules,
'',
currentJoinRule,
);
}
Future<void> setSpaceChildAccess(String roomId) async {
await pangeaSetJoinRules(
roomId,
'knock_restricted',
allow: [
{
"type": "m.room_membership",
"room_id": id,
}
],
);
await setRoomVisibilityOnDirectory(
roomId,
visibility: Visibility.private,
);
}
Future<void> resetSpaceChildAccess(String roomId) async {
await pangeaSetJoinRules(
roomId,
JoinRules.knock.toString().replaceAll('JoinRules.', ''),
);
await setRoomVisibilityOnDirectory(
roomId,
visibility: Visibility.private,
);
}
}