switch from children / grandchilden to full space tree. Resolve error with data from visible chats also being counted in private chat analytics

pull/1183/head
ggurdin 1 year ago
parent 9b6466c09c
commit 2b4ada3202

@ -129,6 +129,15 @@ class AnalyticsController extends BaseController {
return null;
}
// Map of space ids to the last fetched hierarchy. Used when filtering
// private chat analytics to determine which children are already visible
// in the chat list
final Map<String, List<String>> _lastFetchedHierarchies = {};
void setLatestHierarchy(String spaceId, GetSpaceHierarchyResponse resp) {
final List<String> roomIds = resp.rooms.map((room) => room.roomId).toList();
_lastFetchedHierarchies[spaceId] = roomIds;
}
//////////////////////////// MESSAGE SUMMARY ANALYTICS ////////////////////////////
Future<List<SummaryAnalyticsEvent>> mySummaryAnalytics() async {
@ -188,10 +197,7 @@ class AnalyticsController extends BaseController {
}
}
// get a list of all the space's children, including sub-space children
final resp = await space.client.getSpaceHierarchy(space.id);
final List<String> spaceChildrenIds =
resp.rooms.map((room) => room.roomId).toList();
final List<String> spaceChildrenIds = space.allSpaceChildRoomIds;
// filter out the analyics events that don't belong to the space's children
final List<SummaryAnalyticsEvent> allAnalyticsEvents = [];
@ -288,22 +294,32 @@ class AnalyticsController extends BaseController {
return filtered;
}
List<SummaryAnalyticsEvent> filterPrivateChatAnalytics(
Future<List<SummaryAnalyticsEvent>> filterPrivateChatAnalytics(
List<SummaryAnalyticsEvent> unfiltered,
Room? space,
) {
final List<String> directChatIds =
space?.childrenAndGrandChildrenDirectChatIds ?? [];
) async {
if (space != null && !_lastFetchedHierarchies.containsKey(space.id)) {
final resp = await _pangeaController.matrixState.client
.getSpaceHierarchy(space.id);
setLatestHierarchy(space.id, resp);
}
final List<String> privateChatIds = space?.allSpaceChildRoomIds ?? [];
final List<String> lastFetched = _lastFetchedHierarchies[space!.id] ?? [];
for (final id in lastFetched) {
privateChatIds.removeWhere((e) => e == id);
}
List<SummaryAnalyticsEvent> filtered =
List<SummaryAnalyticsEvent>.from(unfiltered);
filtered = filtered.where((e) {
return (e.content).messages.any(
(u) => directChatIds.contains(u.chatId),
(u) => privateChatIds.contains(u.chatId),
);
}).toList();
filtered.forEachIndexed(
(i, _) => (filtered[i].content).messages.removeWhere(
(u) => !directChatIds.contains(u.chatId),
(u) => !privateChatIds.contains(u.chatId),
),
);
return filtered;
@ -369,7 +385,10 @@ class AnalyticsController extends BaseController {
if (defaultSelected.type == AnalyticsEntryType.student) {
throw "private chat filtering not available for my analytics";
}
return filterPrivateChatAnalytics(unfilteredAnalytics, space);
return await filterPrivateChatAnalytics(
unfilteredAnalytics,
space,
);
case AnalyticsEntryType.space:
return filterSpaceAnalytics(unfilteredAnalytics, selected!.id);
default:
@ -573,10 +592,7 @@ class AnalyticsController extends BaseController {
}
}
final resp = await space.client.getSpaceHierarchy(space.id);
final List<String> spaceChildrenIds =
resp.rooms.map((room) => room.roomId).toList();
final List<String> spaceChildrenIds = space.allSpaceChildRoomIds;
final List<ConstructAnalyticsEvent> allConstructs = [];
for (final constructEvent in constructEvents) {
final lemmaUses = constructEvent.content.uses;
@ -622,8 +638,7 @@ class AnalyticsController extends BaseController {
List<ConstructAnalyticsEvent> unfilteredConstructs,
Room parentSpace,
) {
final List<String> directChatIds =
parentSpace.childrenAndGrandChildrenDirectChatIds;
final List<String> directChatIds = [];
final List<ConstructAnalyticsEvent> filtered =
List<ConstructAnalyticsEvent>.from(unfilteredConstructs);
for (final construct in filtered) {

@ -5,11 +5,7 @@ extension GeneralInfoClientExtension on Client {
final List<String> adminRoomIds = [];
for (final Room adminSpace in (await _classesAndExchangesImTeaching)) {
adminRoomIds.add(adminSpace.id);
final children = adminSpace.childrenAndGrandChildren;
final List<String> adminSpaceRooms = children
.where((e) => e.roomId != null)
.map((e) => e.roomId!)
.toList();
final List<String> adminSpaceRooms = adminSpace.allSpaceChildRoomIds;
adminRoomIds.addAll(adminSpaceRooms);
}
return adminRoomIds;

@ -20,57 +20,6 @@ extension ChildrenAndParentsRoomExtension on Room {
List<String> get _joinedChildrenRoomIds =>
joinedChildren.map((child) => child.id).toList();
List<SpaceChild> get _childrenAndGrandChildren {
if (!isSpace) return [];
final List<SpaceChild> kids = [];
for (final child in spaceChildren) {
kids.add(child);
if (child.roomId != null) {
final Room? childRoom = client.getRoomById(child.roomId!);
if (childRoom != null && childRoom.isSpace) {
kids.addAll(childRoom.spaceChildren);
}
}
}
return kids.where((element) => element.roomId != null).toList();
}
//this assumes that a user has been invited to all group chats in a space
//it is a janky workaround for determining whether a spacechild is a direct chat
//since the spaceChild object doesn't contain this info. this info is only accessible
//when the user has joined or been invited to the room. direct chats included in
//a space show up in spaceChildren but the user has not been invited to them.
List<String> get _childrenAndGrandChildrenDirectChatIds {
final List<String> nonDirectChatRoomIds = childrenAndGrandChildren
.where((child) => child.roomId != null)
.map((e) => client.getRoomById(e.roomId!))
.where((r) => r != null && !r.isDirectChat)
.map((e) => e!.id)
.toList();
return childrenAndGrandChildren
.where(
(child) =>
child.roomId != null &&
!nonDirectChatRoomIds.contains(child.roomId),
)
.map((e) => e.roomId)
.cast<String>()
.toList();
// return childrenAndGrandChildren
// .where((element) => element.roomId != null)
// .where(
// (child) {
// final room = client.getRoomById(child.roomId!);
// return room == null || room.isDirectChat;
// },
// )
// .map((e) => e.roomId)
// .cast<String>()
// .toList();
}
Future<List<Room>> _getChildRooms() async {
final List<Room> children = [];
for (final child in spaceChildren) {
@ -145,4 +94,19 @@ extension ChildrenAndParentsRoomExtension on Room {
),
)
.toList();
// gets all space children of a given space, down the
// space tree.
List<String> get _allSpaceChildRoomIds {
final List<String> childIds = [];
for (final child in spaceChildren) {
if (child.roomId == null) continue;
childIds.add(child.roomId!);
final Room? room = client.getRoomById(child.roomId!);
if (room != null && room.isSpace) {
childIds.addAll(room._allSpaceChildRoomIds);
}
}
return childIds;
}
}

@ -25,7 +25,6 @@ import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:html_unescape/html_unescape.dart';
import 'package:matrix/matrix.dart';
import 'package:matrix/src/utils/markdown.dart';
import 'package:matrix/src/utils/space_child.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import '../../../config/app_config.dart';
@ -98,11 +97,6 @@ extension PangeaRoom on Room {
List<String> get joinedChildrenRoomIds => _joinedChildrenRoomIds;
List<SpaceChild> get childrenAndGrandChildren => _childrenAndGrandChildren;
List<String> get childrenAndGrandChildrenDirectChatIds =>
_childrenAndGrandChildrenDirectChatIds;
Future<List<Room>> getChildRooms() async => await _getChildRooms();
Future<void> joinSpaceChild(String roomID) async =>
@ -115,6 +109,8 @@ extension PangeaRoom on Room {
List<Room> get pangeaSpaceParents => _pangeaSpaceParents;
List<String> get allSpaceChildRoomIds => _allSpaceChildRoomIds;
// class_and_exchange_settings
DateTime? get rulesUpdatedAt => _rulesUpdatedAt;

@ -94,15 +94,18 @@ class BaseAnalyticsController extends State<BaseAnalyticsPage> {
}
Future<void> onRefresh() async {
await showFutureLoadingDialog(
context: context,
future: () async {
debugPrint("updating analytics");
await pangeaController.myAnalytics.updateAnalytics();
await setChartData(forceUpdate: true);
refreshStream.add(true);
},
);
// postframe callback to avoid calling this function during build
WidgetsBinding.instance.addPostFrameCallback((_) async {
await showFutureLoadingDialog(
context: context,
future: () async {
debugPrint("updating analytics");
await pangeaController.myAnalytics.updateAnalytics();
await setChartData(forceUpdate: true);
refreshStream.add(true);
},
);
});
}
Future<ChartAnalyticsModel> fetchChartData(

@ -70,6 +70,13 @@ class ClassAnalyticsV2Controller extends State<ClassAnalyticsPage> {
final response = await Matrix.of(context).client.getSpaceHierarchy(
classRoom!.id,
);
// set the latest fetched full hierarchy in message analytics controller
// we want to avoid calling this endpoint again and again, so whenever the
// data is made available, set it in the controller
MatrixState.pangeaController.analytics
.setLatestHierarchy(_classRoom!.id, response);
students = classRoom!.students;
chats = response.rooms
.where(

Loading…
Cancel
Save