Merge pull request #497 from pangeachat/remove-postloads
reduced the number of calls to postLoad and the number of awaits for …
This commit is contained in:
commit
9cb6faf43c
15 changed files with 246 additions and 337 deletions
|
|
@ -908,13 +908,14 @@ class ChatListController extends State<ChatList>
|
|||
|
||||
// #Pangea
|
||||
if (mounted) {
|
||||
// TODO try not to await so much
|
||||
GoogleAnalytics.analyticsUserUpdate(client.userID);
|
||||
await pangeaController.subscriptionController.initialize();
|
||||
await pangeaController.myAnalytics.initialize();
|
||||
pangeaController.afterSyncAndFirstLoginInitialization(context);
|
||||
await pangeaController.inviteBotToExistingSpaces();
|
||||
await pangeaController.setPangeaPushRules();
|
||||
await client.migrateAnalyticsRooms();
|
||||
client.migrateAnalyticsRooms();
|
||||
} else {
|
||||
ErrorHandler.logError(
|
||||
m: "didn't run afterSyncAndFirstLoginInitialization because not mounted",
|
||||
|
|
|
|||
|
|
@ -31,18 +31,16 @@ class ClassController extends BaseController {
|
|||
setState(data: {"activeSpaceId": classId});
|
||||
}
|
||||
|
||||
Future<void> fixClassPowerLevels() async {
|
||||
try {
|
||||
final teacherSpaces =
|
||||
await _pangeaController.matrixState.client.spacesImTeaching;
|
||||
final List<Future<void>> classFixes = List<Room>.from(teacherSpaces)
|
||||
.map((adminSpace) => adminSpace.setClassPowerLevels())
|
||||
.toList();
|
||||
await Future.wait(classFixes);
|
||||
} catch (err, stack) {
|
||||
debugger(when: kDebugMode);
|
||||
ErrorHandler.logError(e: err, s: stack);
|
||||
}
|
||||
/// For all the spaces that the user is teaching, set the power levels
|
||||
/// to enable all other users to add child rooms to the space.
|
||||
void fixClassPowerLevels() {
|
||||
Future.wait(
|
||||
_pangeaController.matrixState.client.spacesImTeaching.map(
|
||||
(space) => space.setClassPowerLevels().catchError((err, s) {
|
||||
ErrorHandler.logError(e: err, s: s);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> checkForClassCodeAndSubscription(BuildContext context) async {
|
||||
|
|
@ -131,10 +129,10 @@ class ClassController extends BaseController {
|
|||
_pangeaController.matrixState.client.getRoomById(classChunk.roomId);
|
||||
|
||||
// when possible, add user's analytics room the to space they joined
|
||||
await joinedSpace?.addAnalyticsRoomsToSpace();
|
||||
joinedSpace?.addAnalyticsRoomsToSpace();
|
||||
|
||||
// and invite the space's teachers to the user's analytics rooms
|
||||
await joinedSpace?.inviteSpaceTeachersToAnalyticsRooms();
|
||||
joinedSpace?.inviteSpaceTeachersToAnalyticsRooms();
|
||||
GoogleAnalytics.joinClass(classCode);
|
||||
return;
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -198,9 +198,7 @@ class AnalyticsController extends BaseController {
|
|||
// gets all the summary analytics events for the students
|
||||
// in a space since the current timespace's cut off date
|
||||
|
||||
// ensure that all the space's events are loaded (mainly the for langCode)
|
||||
// and that the participants are loaded
|
||||
await space.postLoad();
|
||||
// ensure that the participants of the space are loaded
|
||||
await space.requestParticipants();
|
||||
|
||||
// TODO switch to using list of futures
|
||||
|
|
@ -439,7 +437,6 @@ class AnalyticsController extends BaseController {
|
|||
timeSpan: currentAnalyticsTimeSpan,
|
||||
);
|
||||
}
|
||||
await space.postLoad();
|
||||
}
|
||||
|
||||
DateTime? lastUpdated;
|
||||
|
|
@ -545,7 +542,6 @@ class AnalyticsController extends BaseController {
|
|||
Future<List<ConstructAnalyticsEvent>> allSpaceMemberConstructs(
|
||||
Room space,
|
||||
) async {
|
||||
await space.postLoad();
|
||||
await space.requestParticipants();
|
||||
final List<ConstructAnalyticsEvent> constructEvents = [];
|
||||
for (final student in space.students) {
|
||||
|
|
@ -788,7 +784,6 @@ class AnalyticsController extends BaseController {
|
|||
);
|
||||
return [];
|
||||
}
|
||||
await space.postLoad();
|
||||
}
|
||||
|
||||
DateTime? lastUpdated;
|
||||
|
|
|
|||
|
|
@ -81,8 +81,7 @@ class PangeaController {
|
|||
BuildContext context,
|
||||
) async {
|
||||
await classController.checkForClassCodeAndSubscription(context);
|
||||
// startChatWithBotIfNotPresent();
|
||||
await classController.fixClassPowerLevels();
|
||||
classController.fixClassPowerLevels();
|
||||
}
|
||||
|
||||
/// Initialize controllers
|
||||
|
|
|
|||
|
|
@ -1,48 +1,40 @@
|
|||
part of "client_extension.dart";
|
||||
|
||||
extension AnalyticsClientExtension on Client {
|
||||
// get analytics room matching targetlanguage
|
||||
// if not present, create it and invite teachers of that language
|
||||
// set description to let people know what the hell it is
|
||||
/// Get the logged in user's analytics room matching
|
||||
/// a given langCode. If not present, create it.
|
||||
Future<Room> _getMyAnalyticsRoom(String langCode) async {
|
||||
await roomsLoading;
|
||||
// ensure room state events (room create,
|
||||
// to check for analytics type) are loaded
|
||||
for (final room in rooms) {
|
||||
if (room.partial) await room.postLoad();
|
||||
}
|
||||
|
||||
final Room? analyticsRoom = analyticsRoomLocal(langCode);
|
||||
|
||||
final Room? analyticsRoom = _analyticsRoomLocal(langCode);
|
||||
if (analyticsRoom != null) return analyticsRoom;
|
||||
|
||||
return _makeAnalyticsRoom(langCode);
|
||||
}
|
||||
|
||||
//note: if langCode is null and user has >1 analyticsRooms then this could
|
||||
//return the wrong one. this is to account for when an exchange might not
|
||||
//be in a class.
|
||||
Room? _analyticsRoomLocal(String? langCode, [String? userIdParam]) {
|
||||
/// Get local analytics room for a given langCode and
|
||||
/// optional userId (if not specified, uses current user).
|
||||
/// If user is invited to the room, joins the room.
|
||||
Room? _analyticsRoomLocal(String langCode, [String? userIdParam]) {
|
||||
final Room? analyticsRoom = rooms.firstWhereOrNull((e) {
|
||||
return e.isAnalyticsRoom &&
|
||||
e.isAnalyticsRoomOfUser(userIdParam ?? userID!) &&
|
||||
(langCode != null ? e.isMadeForLang(langCode) : true);
|
||||
e.isMadeForLang(langCode);
|
||||
});
|
||||
if (analyticsRoom != null &&
|
||||
analyticsRoom.membership == Membership.invite) {
|
||||
debugger(when: kDebugMode);
|
||||
analyticsRoom
|
||||
.join()
|
||||
.onError(
|
||||
analyticsRoom.join().onError(
|
||||
(error, stackTrace) =>
|
||||
ErrorHandler.logError(e: error, s: stackTrace),
|
||||
)
|
||||
.then((value) => analyticsRoom.postLoad());
|
||||
);
|
||||
return analyticsRoom;
|
||||
}
|
||||
return analyticsRoom;
|
||||
}
|
||||
|
||||
/// Creates an analytics room with the specified language code and returns the created room.
|
||||
/// Additionally, the room is added to the user's spaces and all teachers are invited to the room.
|
||||
///
|
||||
/// If the room does not appear immediately after creation, this method waits for it to appear in sync.
|
||||
/// Returns the created [Room] object.
|
||||
Future<Room> _makeAnalyticsRoom(String langCode) async {
|
||||
final String roomID = await createRoom(
|
||||
creationContent: {
|
||||
|
|
@ -53,7 +45,6 @@ extension AnalyticsClientExtension on Client {
|
|||
topic: "This room stores learning analytics for $userID.",
|
||||
invite: [
|
||||
...(await myTeachers).map((e) => e.id),
|
||||
// BotName.localBot,
|
||||
BotName.byEnvironment,
|
||||
],
|
||||
);
|
||||
|
|
@ -66,14 +57,14 @@ extension AnalyticsClientExtension on Client {
|
|||
|
||||
// add this analytics room to all spaces so teachers can join them
|
||||
// via the space hierarchy
|
||||
await analyticsRoom?.addAnalyticsRoomToSpaces();
|
||||
analyticsRoom?.addAnalyticsRoomToSpaces();
|
||||
|
||||
// and invite all teachers to new analytics room
|
||||
await analyticsRoom?.inviteTeachersToAnalyticsRoom();
|
||||
analyticsRoom?.inviteTeachersToAnalyticsRoom();
|
||||
return getRoomById(roomID)!;
|
||||
}
|
||||
|
||||
// Get all my analytics rooms
|
||||
/// Get all my analytics rooms
|
||||
List<Room> get _allMyAnalyticsRooms => rooms
|
||||
.where(
|
||||
(e) => e.isAnalyticsRoomOfUser(userID!),
|
||||
|
|
@ -83,76 +74,77 @@ extension AnalyticsClientExtension on Client {
|
|||
// migration function to change analytics rooms' vsibility to public
|
||||
// so they will appear in the space hierarchy
|
||||
Future<void> _updateAnalyticsRoomVisibility() async {
|
||||
final List<Future> makePublicFutures = [];
|
||||
for (final Room room in allMyAnalyticsRooms) {
|
||||
final visability = await getRoomVisibilityOnDirectory(room.id);
|
||||
if (visability != Visibility.public) {
|
||||
await setRoomVisibilityOnDirectory(
|
||||
room.id,
|
||||
visibility: Visibility.public,
|
||||
);
|
||||
}
|
||||
}
|
||||
await Future.wait(makePublicFutures);
|
||||
await Future.wait(
|
||||
allMyAnalyticsRooms.map((room) async {
|
||||
final visability = await getRoomVisibilityOnDirectory(room.id);
|
||||
if (visability != Visibility.public) {
|
||||
await setRoomVisibilityOnDirectory(
|
||||
room.id,
|
||||
visibility: Visibility.public,
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Add all the users' analytics room to all the spaces the student studies in
|
||||
// So teachers can join them via space hierarchy
|
||||
// Will not always work, as there may be spaces where students don't have permission to add chats
|
||||
// But allows teachers to join analytics rooms without being invited
|
||||
Future<void> _addAnalyticsRoomsToAllSpaces() async {
|
||||
final List<Future> addFutures = [];
|
||||
/// Add all the users' analytics room to all the spaces the user is studying in
|
||||
/// so teachers can join them via space hierarchy.
|
||||
/// Allows teachers to join analytics rooms without being invited.
|
||||
void _addAnalyticsRoomsToAllSpaces() {
|
||||
for (final Room room in allMyAnalyticsRooms) {
|
||||
addFutures.add(room.addAnalyticsRoomToSpaces());
|
||||
room.addAnalyticsRoomToSpaces();
|
||||
}
|
||||
await Future.wait(addFutures);
|
||||
}
|
||||
|
||||
// Invite teachers to all my analytics room
|
||||
// Handles case when students cannot add analytics room to space(s)
|
||||
// So teacher is still able to get analytics data for this student
|
||||
Future<void> _inviteAllTeachersToAllAnalyticsRooms() async {
|
||||
final List<Future> inviteFutures = [];
|
||||
for (final Room analyticsRoom in allMyAnalyticsRooms) {
|
||||
inviteFutures.add(analyticsRoom.inviteTeachersToAnalyticsRoom());
|
||||
/// Invite teachers to all my analytics room.
|
||||
/// Handles case when students cannot add analytics room to space(s)
|
||||
/// so teacher is still able to get analytics data for this student
|
||||
void _inviteAllTeachersToAllAnalyticsRooms() {
|
||||
for (final Room room in allMyAnalyticsRooms) {
|
||||
room.inviteTeachersToAnalyticsRoom();
|
||||
}
|
||||
await Future.wait(inviteFutures);
|
||||
}
|
||||
|
||||
// Join all analytics rooms in all spaces
|
||||
// Allows teachers to join analytics rooms without being invited
|
||||
Future<void> _joinAnalyticsRoomsInAllSpaces() async {
|
||||
final List<Future> joinFutures = [];
|
||||
for (final Room space in (await _spacesImTeaching)) {
|
||||
joinFutures.add(space.joinAnalyticsRoomsInSpace());
|
||||
}
|
||||
await Future.wait(joinFutures);
|
||||
}
|
||||
|
||||
// Join invited analytics rooms
|
||||
// Checks for invites to any student analytics rooms
|
||||
// Handles case of analytics rooms that can't be added to some space(s)
|
||||
Future<void> _joinInvitedAnalyticsRooms() async {
|
||||
final List<Room> allRooms = List.from(rooms);
|
||||
for (final Room room in allRooms) {
|
||||
if (room.membership == Membership.invite && room.isAnalyticsRoom) {
|
||||
try {
|
||||
await room.join();
|
||||
} catch (err) {
|
||||
debugPrint("Failed to join analytics room ${room.id}");
|
||||
}
|
||||
}
|
||||
for (final Room space in _spacesImTeaching) {
|
||||
// Each call to joinAnalyticsRoomsInSpace calls getSpaceHierarchy, which has a
|
||||
// strict rate limit. So we wait a second between each call to prevent a 429 error.
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 1),
|
||||
() => space.joinAnalyticsRoomsInSpace(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to join all relevant analytics rooms
|
||||
// and set up those rooms to be joined by relevant teachers
|
||||
Future<void> _migrateAnalyticsRooms() async {
|
||||
await _updateAnalyticsRoomVisibility();
|
||||
await _addAnalyticsRoomsToAllSpaces();
|
||||
await _inviteAllTeachersToAllAnalyticsRooms();
|
||||
await _joinInvitedAnalyticsRooms();
|
||||
await _joinAnalyticsRoomsInAllSpaces();
|
||||
/// Join invited analytics rooms.
|
||||
/// Checks for invites to any student analytics rooms.
|
||||
/// Handles case of analytics rooms that can't be added to some space(s).
|
||||
void _joinInvitedAnalyticsRooms() {
|
||||
Future.wait(
|
||||
rooms
|
||||
.where(
|
||||
(room) =>
|
||||
room.membership == Membership.invite && room.isAnalyticsRoom,
|
||||
)
|
||||
.map(
|
||||
(room) => room.join().catchError((err, s) {
|
||||
ErrorHandler.logError(e: err, s: s);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Helper function to join all relevant analytics rooms
|
||||
/// and set up those rooms to be joined by other users.
|
||||
void _migrateAnalyticsRooms() {
|
||||
_updateAnalyticsRoomVisibility().then((_) {
|
||||
_addAnalyticsRoomsToAllSpaces();
|
||||
_inviteAllTeachersToAllAnalyticsRooms();
|
||||
_joinInvitedAnalyticsRooms();
|
||||
_joinAnalyticsRoomsInAllSpaces();
|
||||
});
|
||||
}
|
||||
|
||||
Future<Map<String, DateTime?>> _allAnalyticsRoomsLastUpdated() async {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fluffychat/pangea/constants/class_default_values.dart';
|
||||
import 'package:fluffychat/pangea/constants/model_keys.dart';
|
||||
import 'package:fluffychat/pangea/constants/pangea_event_types.dart';
|
||||
import 'package:fluffychat/pangea/constants/pangea_room_types.dart';
|
||||
|
|
@ -20,10 +19,15 @@ part "space_extension.dart";
|
|||
extension PangeaClient on Client {
|
||||
// analytics
|
||||
|
||||
/// Get the logged in user's analytics room matching
|
||||
/// a given langCode. If not present, create it.
|
||||
Future<Room> getMyAnalyticsRoom(String langCode) async =>
|
||||
await _getMyAnalyticsRoom(langCode);
|
||||
|
||||
Room? analyticsRoomLocal(String? langCode, [String? userIdParam]) =>
|
||||
/// Get local analytics room for a given langCode and
|
||||
/// optional userId (if not specified, uses current user).
|
||||
/// If user is invited to the room, joins the room.
|
||||
Room? analyticsRoomLocal(String langCode, [String? userIdParam]) =>
|
||||
_analyticsRoomLocal(langCode, userIdParam);
|
||||
|
||||
List<Room> get allMyAnalyticsRooms => _allMyAnalyticsRooms;
|
||||
|
|
@ -31,35 +35,24 @@ extension PangeaClient on Client {
|
|||
Future<void> updateAnalyticsRoomVisibility() async =>
|
||||
await _updateAnalyticsRoomVisibility();
|
||||
|
||||
Future<void> addAnalyticsRoomsToAllSpaces() async =>
|
||||
await _addAnalyticsRoomsToAllSpaces();
|
||||
|
||||
Future<void> inviteAllTeachersToAllAnalyticsRooms() async =>
|
||||
await _inviteAllTeachersToAllAnalyticsRooms();
|
||||
|
||||
Future<void> joinAnalyticsRoomsInAllSpaces() async =>
|
||||
await _joinAnalyticsRoomsInAllSpaces();
|
||||
|
||||
Future<void> joinInvitedAnalyticsRooms() async =>
|
||||
await _joinInvitedAnalyticsRooms();
|
||||
|
||||
Future<void> migrateAnalyticsRooms() async => await _migrateAnalyticsRooms();
|
||||
/// Helper function to join all relevant analytics rooms
|
||||
/// and set up those rooms to be joined by other users.
|
||||
void migrateAnalyticsRooms() => _migrateAnalyticsRooms();
|
||||
|
||||
Future<Map<String, DateTime?>> allAnalyticsRoomsLastUpdated() async =>
|
||||
await _allAnalyticsRoomsLastUpdated();
|
||||
|
||||
// spaces
|
||||
|
||||
Future<List<Room>> get spacesImTeaching async => await _spacesImTeaching;
|
||||
List<Room> get spacesImTeaching => _spacesImTeaching;
|
||||
|
||||
Future<List<Room>> get chatsImAStudentIn async => await _chatsImAStudentIn;
|
||||
|
||||
Future<List<Room>> get spaceImAStudentIn async => await _spacesImStudyingIn;
|
||||
List<Room> get spacesImAStudentIn => _spacesImStudyingIn;
|
||||
|
||||
List<Room> get spacesImIn => _spacesImIn;
|
||||
|
||||
Future<PangeaRoomRules?> get lastUpdatedRoomRules async =>
|
||||
await _lastUpdatedRoomRules;
|
||||
PangeaRoomRules? get lastUpdatedRoomRules => _lastUpdatedRoomRules;
|
||||
|
||||
// general_info
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,8 @@
|
|||
part of "client_extension.dart";
|
||||
|
||||
extension SpaceClientExtension on Client {
|
||||
Future<List<Room>> get _spacesImTeaching async {
|
||||
final allSpaces = rooms.where((room) => room.isSpace);
|
||||
for (final Room space in allSpaces) {
|
||||
if (space.getState(EventTypes.RoomPowerLevels) == null) {
|
||||
await space.postLoad();
|
||||
}
|
||||
}
|
||||
|
||||
final spaces = rooms
|
||||
.where(
|
||||
(e) =>
|
||||
(e.isSpace) &&
|
||||
e.ownPowerLevel == ClassDefaultValues.powerLevelOfAdmin,
|
||||
)
|
||||
.toList();
|
||||
return spaces;
|
||||
}
|
||||
List<Room> get _spacesImTeaching =>
|
||||
rooms.where((e) => e.isSpace && e.isRoomAdmin).toList();
|
||||
|
||||
Future<List<Room>> get _chatsImAStudentIn async {
|
||||
final List<String> nowteacherRoomIds = await teacherRoomIds;
|
||||
|
|
@ -31,39 +16,18 @@ extension SpaceClientExtension on Client {
|
|||
.toList();
|
||||
}
|
||||
|
||||
Future<List<Room>> get _spacesImStudyingIn async {
|
||||
final List<Room> joinedSpaces = rooms
|
||||
.where(
|
||||
(room) => room.isSpace && room.membership == Membership.join,
|
||||
)
|
||||
.toList();
|
||||
|
||||
for (final Room space in joinedSpaces) {
|
||||
if (space.getState(EventTypes.RoomPowerLevels) == null) {
|
||||
await space.postLoad();
|
||||
}
|
||||
}
|
||||
|
||||
final spaces = rooms
|
||||
.where(
|
||||
(e) =>
|
||||
e.isSpace &&
|
||||
e.ownPowerLevel < ClassDefaultValues.powerLevelOfAdmin,
|
||||
)
|
||||
.toList();
|
||||
return spaces;
|
||||
}
|
||||
List<Room> get _spacesImStudyingIn =>
|
||||
rooms.where((e) => e.isSpace && !e.isRoomAdmin).toList();
|
||||
|
||||
List<Room> get _spacesImIn => rooms.where((e) => e.isSpace).toList();
|
||||
|
||||
Future<PangeaRoomRules?> get _lastUpdatedRoomRules async =>
|
||||
(await _spacesImTeaching)
|
||||
.where((space) => space.rulesUpdatedAt != null)
|
||||
.sorted(
|
||||
(a, b) => b.rulesUpdatedAt!.compareTo(a.rulesUpdatedAt!),
|
||||
)
|
||||
.firstOrNull
|
||||
?.pangeaRoomRules;
|
||||
PangeaRoomRules? get _lastUpdatedRoomRules => _spacesImTeaching
|
||||
.where((space) => space.rulesUpdatedAt != null)
|
||||
.sorted(
|
||||
(a, b) => b.rulesUpdatedAt!.compareTo(a.rulesUpdatedAt!),
|
||||
)
|
||||
.firstOrNull
|
||||
?.pangeaRoomRules;
|
||||
|
||||
// LanguageSettingsModel? get _lastUpdatedLanguageSettings => rooms
|
||||
// .where((room) => room.isSpace && room.languageSettingsUpdatedAt != null)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ part of "pangea_room_extension.dart";
|
|||
|
||||
extension EventsRoomExtension on Room {
|
||||
Future<bool> _leaveIfFull() async {
|
||||
await postLoad();
|
||||
if (!isRoomAdmin &&
|
||||
(_capacity != null) &&
|
||||
(await _numNonAdmins) > (_capacity!)) {
|
||||
|
|
|
|||
|
|
@ -49,26 +49,35 @@ part "user_permissions_extension.dart";
|
|||
extension PangeaRoom on Room {
|
||||
// analytics
|
||||
|
||||
/// Join analytics rooms in space.
|
||||
/// Allows teachers to join analytics rooms without being invited.
|
||||
Future<void> joinAnalyticsRoomsInSpace() async =>
|
||||
await _joinAnalyticsRoomsInSpace();
|
||||
|
||||
Future<void> addAnalyticsRoomToSpace(Room analyticsRoom) async =>
|
||||
await _addAnalyticsRoomToSpace(analyticsRoom);
|
||||
|
||||
Future<void> addAnalyticsRoomToSpaces() async =>
|
||||
await _addAnalyticsRoomToSpaces();
|
||||
/// Add analytics room to all spaces the user is a student in (1 analytics room to all spaces).
|
||||
/// Enables teachers to join student analytics rooms via space hierarchy.
|
||||
/// Will not always work, as there may be spaces where students don't have permission to add chats,
|
||||
/// but allows teachers to join analytics rooms without being invited.
|
||||
void addAnalyticsRoomToSpaces() => _addAnalyticsRoomToSpaces();
|
||||
|
||||
Future<void> addAnalyticsRoomsToSpace() async =>
|
||||
await _addAnalyticsRoomsToSpace();
|
||||
/// Add all the user's analytics rooms to 1 space.
|
||||
void addAnalyticsRoomsToSpace() => _addAnalyticsRoomsToSpace();
|
||||
|
||||
/// Invite teachers of 1 space to 1 analytics room
|
||||
Future<void> inviteSpaceTeachersToAnalyticsRoom(Room analyticsRoom) async =>
|
||||
await _inviteSpaceTeachersToAnalyticsRoom(analyticsRoom);
|
||||
|
||||
Future<void> inviteTeachersToAnalyticsRoom() async =>
|
||||
await _inviteTeachersToAnalyticsRoom();
|
||||
/// Invite all the user's teachers to 1 analytics room.
|
||||
/// Handles case when students cannot add analytics room to space
|
||||
/// so teacher is still able to get analytics data for this student.
|
||||
void inviteTeachersToAnalyticsRoom() => _inviteTeachersToAnalyticsRoom();
|
||||
|
||||
Future<void> inviteSpaceTeachersToAnalyticsRooms() async =>
|
||||
await _inviteSpaceTeachersToAnalyticsRooms();
|
||||
/// Invite teachers of 1 space to all users' analytics rooms
|
||||
void inviteSpaceTeachersToAnalyticsRooms() =>
|
||||
_inviteSpaceTeachersToAnalyticsRooms();
|
||||
|
||||
Future<AnalyticsEvent?> getLastAnalyticsEvent(
|
||||
String type,
|
||||
|
|
@ -147,6 +156,12 @@ extension PangeaRoom on Room {
|
|||
|
||||
Future<List<User>> get teachers async => await _teachers;
|
||||
|
||||
/// Synchronous version of teachers getter. Does not request
|
||||
/// participants, so this list may not be complete.
|
||||
List<User> get teachersLocal => _teachersLocal;
|
||||
|
||||
/// If the user is an admin of this space, and the space's
|
||||
/// m.space.child power level hasn't yet been set, so it to 0
|
||||
Future<void> setClassPowerLevels() async => await _setClassPowerLevels();
|
||||
|
||||
Event? get pangeaRoomRulesStateEvent => _pangeaRoomRulesStateEvent;
|
||||
|
|
|
|||
|
|
@ -1,57 +1,44 @@
|
|||
part of "pangea_room_extension.dart";
|
||||
|
||||
extension AnalyticsRoomExtension on Room {
|
||||
// Join analytics rooms in space
|
||||
// Allows teachers to join analytics rooms without being invited
|
||||
/// Join analytics rooms in space.
|
||||
/// Allows teachers to join analytics rooms without being invited.
|
||||
Future<void> _joinAnalyticsRoomsInSpace() async {
|
||||
if (!isSpace) {
|
||||
debugPrint("joinAnalyticsRoomsInSpace called on non-space room");
|
||||
Sentry.addBreadcrumb(
|
||||
Breadcrumb(
|
||||
message: "joinAnalyticsRoomsInSpace called on non-space room",
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// added delay because without it power levels don't load and user is not
|
||||
// recognized as admin
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
await postLoad();
|
||||
|
||||
if (!isRoomAdmin) {
|
||||
debugPrint("joinAnalyticsRoomsInSpace called by non-admin");
|
||||
Sentry.addBreadcrumb(
|
||||
Breadcrumb(
|
||||
message: "joinAnalyticsRoomsInSpace called by non-admin",
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final spaceHierarchy = await client.getSpaceHierarchy(
|
||||
id,
|
||||
maxDepth: 1,
|
||||
);
|
||||
|
||||
final List<String> analyticsRoomIds = spaceHierarchy.rooms
|
||||
.where(
|
||||
(r) => r.roomType == PangeaRoomTypes.analytics,
|
||||
)
|
||||
.map((r) => r.roomId)
|
||||
.toList();
|
||||
|
||||
for (final String roomID in analyticsRoomIds) {
|
||||
try {
|
||||
await joinSpaceChild(roomID);
|
||||
} catch (err, s) {
|
||||
debugPrint("Failed to join analytics room $roomID in space $id");
|
||||
ErrorHandler.logError(
|
||||
e: err,
|
||||
m: "Failed to join analytics room $roomID in space $id",
|
||||
s: s,
|
||||
);
|
||||
try {
|
||||
if (!isSpace) {
|
||||
debugger(when: kDebugMode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isRoomAdmin) return;
|
||||
final spaceHierarchy = await client.getSpaceHierarchy(
|
||||
id,
|
||||
maxDepth: 1,
|
||||
);
|
||||
|
||||
final List<String> analyticsRoomIds = spaceHierarchy.rooms
|
||||
.where((r) => r.roomType == PangeaRoomTypes.analytics)
|
||||
.map((r) => r.roomId)
|
||||
.toList();
|
||||
|
||||
await Future.wait(
|
||||
analyticsRoomIds.map(
|
||||
(roomID) => joinSpaceChild(roomID).catchError((err, s) {
|
||||
debugPrint("Failed to join analytics room $roomID in space $id");
|
||||
ErrorHandler.logError(
|
||||
e: err,
|
||||
m: "Failed to join analytics room $roomID in space $id",
|
||||
s: s,
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
} catch (err, s) {
|
||||
ErrorHandler.logError(
|
||||
e: err,
|
||||
s: s,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,107 +71,70 @@ extension AnalyticsRoomExtension on Room {
|
|||
}
|
||||
}
|
||||
|
||||
// Add analytics room to all spaces the user is a student in (1 analytics room to all spaces)
|
||||
// So teachers can join them via space hierarchy
|
||||
// Will not always work, as there may be spaces where students don't have permission to add chats
|
||||
// But allows teachers to join analytics rooms without being invited
|
||||
Future<void> _addAnalyticsRoomToSpaces() async {
|
||||
if (!isAnalyticsRoomOfUser(client.userID!)) {
|
||||
debugPrint("addAnalyticsRoomToSpaces called on non-analytics room");
|
||||
Sentry.addBreadcrumb(
|
||||
Breadcrumb(
|
||||
message: "addAnalyticsRoomToSpaces called on non-analytics room",
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Room space in (await client.spaceImAStudentIn)) {
|
||||
if (space.spaceChildren.any((sc) => sc.roomId == id)) continue;
|
||||
await space.addAnalyticsRoomToSpace(this);
|
||||
}
|
||||
/// Add analytics room to all spaces the user is a student in (1 analytics room to all spaces).
|
||||
/// Enables teachers to join student analytics rooms via space hierarchy.
|
||||
/// Will not always work, as there may be spaces where students don't have permission to add chats,
|
||||
/// but allows teachers to join analytics rooms without being invited.
|
||||
void _addAnalyticsRoomToSpaces() {
|
||||
if (!isAnalyticsRoomOfUser(client.userID!)) return;
|
||||
Future.wait(
|
||||
client.spacesImAStudentIn
|
||||
.where((space) => !space.spaceChildren.any((sc) => sc.roomId == id))
|
||||
.map((space) => space.addAnalyticsRoomToSpace(this)),
|
||||
);
|
||||
}
|
||||
|
||||
// Add all analytics rooms to space
|
||||
// Similar to addAnalyticsRoomToSpaces, but all analytics room to 1 space
|
||||
Future<void> _addAnalyticsRoomsToSpace() async {
|
||||
await postLoad();
|
||||
final List<Room> allMyAnalyticsRooms = client.allMyAnalyticsRooms;
|
||||
for (final Room analyticsRoom in allMyAnalyticsRooms) {
|
||||
await addAnalyticsRoomToSpace(analyticsRoom);
|
||||
}
|
||||
/// Add all the user's analytics rooms to 1 space.
|
||||
void _addAnalyticsRoomsToSpace() {
|
||||
Future.wait(
|
||||
client.allMyAnalyticsRooms.map((room) => addAnalyticsRoomToSpace(room)),
|
||||
);
|
||||
}
|
||||
|
||||
// invite teachers of 1 space to 1 analytics room
|
||||
/// Invite teachers of 1 space to 1 analytics room
|
||||
Future<void> _inviteSpaceTeachersToAnalyticsRoom(Room analyticsRoom) async {
|
||||
if (!isSpace) {
|
||||
debugPrint(
|
||||
"inviteSpaceTeachersToAnalyticsRoom called on non-space room",
|
||||
);
|
||||
Sentry.addBreadcrumb(
|
||||
Breadcrumb(
|
||||
message:
|
||||
"inviteSpaceTeachersToAnalyticsRoom called on non-space room",
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!isSpace) return;
|
||||
if (!analyticsRoom.participantListComplete) {
|
||||
await analyticsRoom.requestParticipants();
|
||||
}
|
||||
|
||||
final List<User> participants = analyticsRoom.getParticipants();
|
||||
for (final User teacher in (await teachers)) {
|
||||
if (!participants.any((p) => p.id == teacher.id)) {
|
||||
try {
|
||||
await analyticsRoom.invite(teacher.id);
|
||||
} catch (err, s) {
|
||||
debugPrint(
|
||||
"Failed to invite teacher ${teacher.id} to analytics room ${analyticsRoom.id}",
|
||||
);
|
||||
final List<User> uninvitedTeachers = teachersLocal
|
||||
.where((teacher) => !participants.contains(teacher))
|
||||
.toList();
|
||||
|
||||
Future.wait(
|
||||
uninvitedTeachers.map(
|
||||
(teacher) => analyticsRoom.invite(teacher.id).catchError((err, s) {
|
||||
ErrorHandler.logError(
|
||||
e: err,
|
||||
m: "Failed to invite teacher ${teacher.id} to analytics room ${analyticsRoom.id}",
|
||||
s: s,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Invite all teachers to 1 analytics room
|
||||
// Handles case when students cannot add analytics room to space
|
||||
// So teacher is still able to get analytics data for this student
|
||||
Future<void> _inviteTeachersToAnalyticsRoom() async {
|
||||
if (client.userID == null) {
|
||||
debugPrint("inviteTeachersToAnalyticsRoom called with null userId");
|
||||
Sentry.addBreadcrumb(
|
||||
Breadcrumb(
|
||||
message: "inviteTeachersToAnalyticsRoom called with null userId",
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAnalyticsRoomOfUser(client.userID!)) {
|
||||
debugPrint("inviteTeachersToAnalyticsRoom called on non-analytics room");
|
||||
Sentry.addBreadcrumb(
|
||||
Breadcrumb(
|
||||
message: "inviteTeachersToAnalyticsRoom called on non-analytics room",
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Room space in (await client.spaceImAStudentIn)) {
|
||||
await space.inviteSpaceTeachersToAnalyticsRoom(this);
|
||||
}
|
||||
/// Invite all the user's teachers to 1 analytics room.
|
||||
/// Handles case when students cannot add analytics room to space
|
||||
/// so teacher is still able to get analytics data for this student.
|
||||
void _inviteTeachersToAnalyticsRoom() {
|
||||
if (client.userID == null || !isAnalyticsRoomOfUser(client.userID!)) return;
|
||||
Future.wait(
|
||||
client.spacesImAStudentIn.map(
|
||||
(space) => inviteSpaceTeachersToAnalyticsRoom(this),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Invite teachers of 1 space to all users' analytics rooms
|
||||
Future<void> _inviteSpaceTeachersToAnalyticsRooms() async {
|
||||
for (final Room analyticsRoom in client.allMyAnalyticsRooms) {
|
||||
await inviteSpaceTeachersToAnalyticsRoom(analyticsRoom);
|
||||
}
|
||||
/// Invite teachers of 1 space to all users' analytics rooms
|
||||
void _inviteSpaceTeachersToAnalyticsRooms() {
|
||||
Future.wait(
|
||||
client.allMyAnalyticsRooms.map(
|
||||
(room) => inviteSpaceTeachersToAnalyticsRoom(room),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<AnalyticsEvent?> _getLastAnalyticsEvent(
|
||||
|
|
|
|||
|
|
@ -55,27 +55,39 @@ extension SpaceRoomExtension on Room {
|
|||
: participants;
|
||||
}
|
||||
|
||||
/// Synchronous version of _teachers. Does not request participants, so this list may not be complete.
|
||||
List<User> get _teachersLocal {
|
||||
if (!isSpace) return [];
|
||||
return getParticipants()
|
||||
.where(
|
||||
(e) =>
|
||||
e.powerLevel == ClassDefaultValues.powerLevelOfAdmin &&
|
||||
e.id != BotName.byEnvironment,
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// If the user is an admin of this space, and the space's
|
||||
/// m.space.child power level hasn't yet been set, so it to 0
|
||||
Future<void> _setClassPowerLevels() async {
|
||||
try {
|
||||
if (ownPowerLevel < ClassDefaultValues.powerLevelOfAdmin) {
|
||||
return;
|
||||
}
|
||||
if (!isRoomAdmin) return;
|
||||
final dynamic currentPower = getState(EventTypes.RoomPowerLevels);
|
||||
if (currentPower is! Event?) {
|
||||
return;
|
||||
}
|
||||
final Map<String, dynamic>? currentPowerContent =
|
||||
if (currentPower is! Event?) return;
|
||||
|
||||
final currentPowerContent =
|
||||
currentPower?.content["events"] as Map<String, dynamic>?;
|
||||
final spaceChildPower = currentPowerContent?[EventTypes.SpaceChild];
|
||||
|
||||
if (spaceChildPower == null && currentPowerContent != null) {
|
||||
currentPowerContent["events"][EventTypes.SpaceChild] = 0;
|
||||
currentPowerContent[EventTypes.SpaceChild] = 0;
|
||||
currentPower!.content["events"] = currentPowerContent;
|
||||
|
||||
await client.setRoomStateWithKey(
|
||||
id,
|
||||
EventTypes.RoomPowerLevels,
|
||||
currentPower?.stateKey ?? "",
|
||||
currentPowerContent,
|
||||
currentPower.stateKey ?? "",
|
||||
currentPower.content,
|
||||
);
|
||||
}
|
||||
} catch (err, s) {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ class SpaceAnalyticsV2Controller extends State<SpaceAnalyticsPage> {
|
|||
|
||||
Future<void> getChatAndStudents() async {
|
||||
try {
|
||||
await spaceRoom?.postLoad();
|
||||
await spaceRoom?.requestParticipants();
|
||||
|
||||
if (spaceRoom != null) {
|
||||
|
|
|
|||
|
|
@ -49,15 +49,8 @@ class StudentAnalyticsController extends State<StudentAnalyticsPage> {
|
|||
return _chats;
|
||||
}
|
||||
|
||||
List<Room> _spaces = [];
|
||||
List<Room> get spaces {
|
||||
if (_spaces.isEmpty) {
|
||||
_pangeaController.matrixState.client.spaceImAStudentIn.then((result) {
|
||||
setState(() => _spaces = result);
|
||||
});
|
||||
}
|
||||
return _spaces;
|
||||
}
|
||||
List<Room> get spaces =>
|
||||
_pangeaController.matrixState.client.spacesImAStudentIn;
|
||||
|
||||
String? get userId {
|
||||
final id = _pangeaController.matrixState.client.userID;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ void chatListHandleSpaceTap(
|
|||
if (await space.leaveIfFull()) {
|
||||
throw L10n.of(context)!.roomFull;
|
||||
}
|
||||
await space.postLoad();
|
||||
setActiveSpaceAndCloseChat();
|
||||
},
|
||||
onError: (exception) {
|
||||
|
|
@ -72,7 +71,7 @@ void chatListHandleSpaceTap(
|
|||
throw L10n.of(context)!.roomFull;
|
||||
}
|
||||
if (space.isSpace) {
|
||||
await space.joinAnalyticsRoomsInSpace();
|
||||
space.joinAnalyticsRoomsInSpace();
|
||||
}
|
||||
setActiveSpaceAndCloseChat();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
|
|
|
|||
|
|
@ -111,12 +111,12 @@ abstract class ClientManager {
|
|||
// To make room emotes work
|
||||
'im.ponies.room_emotes',
|
||||
// #Pangea
|
||||
PangeaEventTypes.languageSettings,
|
||||
// The things in this list will be loaded in the first sync, without having
|
||||
// to postLoad to confirm that these state events are completely loaded
|
||||
PangeaEventTypes.rules,
|
||||
PangeaEventTypes.botOptions,
|
||||
EventTypes.RoomTopic,
|
||||
EventTypes.RoomAvatar,
|
||||
PangeaEventTypes.capacity,
|
||||
EventTypes.RoomPowerLevels,
|
||||
// Pangea#
|
||||
},
|
||||
logLevel: kReleaseMode ? Level.warning : Level.verbose,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue