From 550c3ab6999274382577574c36dc025ac96fff5f Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Mon, 14 Oct 2024 23:43:19 +1100 Subject: [PATCH] ideal case of private class code --- lib/pages/new_space/new_space.dart | 20 +++++-- lib/pangea/constants/model_keys.dart | 4 ++ lib/pangea/controllers/class_controller.dart | 59 +++++++++++-------- .../space_settings_extension.dart | 10 +++- lib/pangea/utils/space_code.dart | 30 +++++++--- 5 files changed, 83 insertions(+), 40 deletions(-) diff --git a/lib/pages/new_space/new_space.dart b/lib/pages/new_space/new_space.dart index 0b1faf674..9f4465c6e 100644 --- a/lib/pages/new_space/new_space.dart +++ b/lib/pages/new_space/new_space.dart @@ -150,7 +150,10 @@ class NewSpaceController extends State { try { final avatar = this.avatar; avatarUrl ??= avatar == null ? null : await client.uploadContent(avatar); - + final classCode = await SpaceCodeUtil.generateSpaceCode(client); + if (classCode == null) { + return; + } final spaceId = await client.createRoom( // #Pangea // preset: publicGroup @@ -164,7 +167,7 @@ class NewSpaceController extends State { // roomAliasName: publicGroup // ? nameController.text.trim().toLowerCase().replaceAll(' ', '_') // : null, - roomAliasName: SpaceCodeUtil.generateSpaceCode(), + roomAliasName: classCode, // Pangea# name: nameController.text.trim(), topic: topicController.text.isEmpty ? null : topicController.text, @@ -178,14 +181,21 @@ class NewSpaceController extends State { : null, // Pangea# initialState: [ + // #Pangea + ...initialState, + // Pangea# if (avatar != null) sdk.StateEvent( type: sdk.EventTypes.RoomAvatar, content: {'url': avatarUrl.toString()}, ), - // #Pangea - ...initialState, - // Pangea# + sdk.StateEvent( + type: sdk.EventTypes.RoomJoinRules, + content: { + 'join_rule': 'knock', + 'access_code': classCode, + }, + ), ], ); // #Pangea diff --git a/lib/pangea/constants/model_keys.dart b/lib/pangea/constants/model_keys.dart index 195e919b4..962532c9f 100644 --- a/lib/pangea/constants/model_keys.dart +++ b/lib/pangea/constants/model_keys.dart @@ -123,4 +123,8 @@ class ModelKey { static const String prevEventId = "prev_event_id"; static const String prevLastUpdated = "prev_last_updated"; + + // room code + static const String joinRule = "join_rule"; + static const String accessCode = "access_code"; } diff --git a/lib/pangea/controllers/class_controller.dart b/lib/pangea/controllers/class_controller.dart index 157a11b59..48623fe9d 100644 --- a/lib/pangea/controllers/class_controller.dart +++ b/lib/pangea/controllers/class_controller.dart @@ -1,7 +1,7 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:developer'; -import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/constants/local.key.dart'; import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; @@ -9,15 +9,15 @@ import 'package:fluffychat/pangea/extensions/client_extension/client_extension.d import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/models/space_model.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; +import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/utils/space_code.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:matrix/matrix.dart'; -import '../../widgets/matrix.dart'; -import '../utils/firebase_analytics.dart'; import 'base_controller.dart'; class ClassController extends BaseController { @@ -65,47 +65,56 @@ class ClassController extends BaseController { } Future joinClasswithCode(BuildContext context, String classCode) async { + final client = Matrix.of(context).client; try { - final QueryPublicRoomsResponse queryPublicRoomsResponse = - await Matrix.of(context).client.queryPublicRooms( - limit: 1, - filter: PublicRoomQueryFilter(genericSearchTerm: classCode), - ); - - final PublicRoomsChunk? classChunk = - queryPublicRoomsResponse.chunk.firstWhereOrNull((element) { - return element.canonicalAlias?.replaceAll("#", "").split(":")[0] == - classCode; - }); - - if (classChunk == null) { + final knockResponse = await client.httpClient.post( + Uri.parse( + '${client.homeserver}/_synapse/client/pangea/v1/knock_with_code', + ), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ${client.accessToken}', + }, + body: jsonEncode({'access_code': classCode}), + ); + if (knockResponse.statusCode != 200) { SpaceCodeUtil.messageSnack( context, L10n.of(context)!.unableToFindClass, ); return; } - + final knockResult = jsonDecode(knockResponse.body); + final foundClasses = knockResult['rooms']; + if (!(foundClasses is List && foundClasses.isNotEmpty)) { + SpaceCodeUtil.messageSnack( + context, + L10n.of(context)!.unableToFindClass, + ); + return; + } + final chosenClassId = foundClasses.first; + await client.joinRoomById(chosenClassId); if (_pangeaController.matrixState.client.rooms - .any((room) => room.id == classChunk.roomId)) { - setActiveSpaceIdInChatListController(classChunk.roomId); + .any((room) => room.id == chosenClassId)) { + setActiveSpaceIdInChatListController(chosenClassId); SpaceCodeUtil.messageSnack(context, L10n.of(context)!.alreadyInClass); return; } - await _pangeaController.matrixState.client.joinRoom(classChunk.roomId); + await _pangeaController.matrixState.client.joinRoom(chosenClassId); - if (_pangeaController.matrixState.client.getRoomById(classChunk.roomId) == + if (_pangeaController.matrixState.client.getRoomById(chosenClassId) == null) { await _pangeaController.matrixState.client.waitForRoomInSync( - classChunk.roomId, + chosenClassId, join: true, ); } // If the room is full, leave final room = - _pangeaController.matrixState.client.getRoomById(classChunk.roomId); + _pangeaController.matrixState.client.getRoomById(chosenClassId); if (room == null) { return; } @@ -121,12 +130,12 @@ class ClassController extends BaseController { return; } - setActiveSpaceIdInChatListController(classChunk.roomId); + setActiveSpaceIdInChatListController(chosenClassId); // add the user's analytics room to this joined space // so their teachers can join them via the space hierarchy final Room? joinedSpace = - _pangeaController.matrixState.client.getRoomById(classChunk.roomId); + _pangeaController.matrixState.client.getRoomById(chosenClassId); // when possible, add user's analytics room the to space they joined joinedSpace?.addAnalyticsRoomsToSpace(); diff --git a/lib/pangea/extensions/pangea_room_extension/space_settings_extension.dart b/lib/pangea/extensions/pangea_room_extension/space_settings_extension.dart index 6354de96e..fce45f17a 100644 --- a/lib/pangea/extensions/pangea_room_extension/space_settings_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension/space_settings_extension.dart @@ -15,8 +15,14 @@ extension SpaceRoomExtension on Room { } return "Not in a class!"; } - - return canonicalAlias.replaceAll(":$domainString", "").replaceAll("#", ""); + final roomJoinRules = getState(EventTypes.RoomJoinRules, ""); + if (roomJoinRules != null) { + final accessCode = roomJoinRules.content.tryGet(ModelKey.accessCode); + if (accessCode is String) { + return accessCode; + } + } + return "No class code!"; } void _checkClass() { diff --git a/lib/pangea/utils/space_code.dart b/lib/pangea/utils/space_code.dart index 9b1a44525..376450101 100644 --- a/lib/pangea/utils/space_code.dart +++ b/lib/pangea/utils/space_code.dart @@ -1,10 +1,10 @@ -import 'dart:math'; +import 'dart:convert'; import 'package:adaptive_dialog/adaptive_dialog.dart'; +import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; - -import '../controllers/pangea_controller.dart'; +import 'package:matrix/matrix.dart'; class SpaceCodeUtil { static const codeLength = 6; @@ -13,11 +13,25 @@ class SpaceCodeUtil { return spacecode == null || spacecode.length > 4; } - static String generateSpaceCode() { - final r = Random(); - const chars = 'AaBbCcDdEeFfGgHhiJjKkLMmNnoPpQqRrSsTtUuVvWwXxYyZz1234567890'; - return List.generate(codeLength, (index) => chars[r.nextInt(chars.length)]) - .join(); + static Future generateSpaceCode(Client client) async { + final response = await client.httpClient.get( + Uri.parse( + '${client.homeserver}/_synapse/client/pangea/v1/request_room_code', + ), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ${client.accessToken}', + }, + ); + if (response.statusCode != 200) { + return null; + } + final roomCodeResult = jsonDecode(response.body); + if (roomCodeResult['access_code'] is String) { + return roomCodeResult['access_code'] as String; + } else { + throw Exception('Invalid response, access_code not found $response'); + } } static Future joinWithSpaceCodeDialog(