LCOV - code coverage report
Current view: top level - lib/msc_extensions/msc_3381_polls - poll_event_extension.dart (source / functions) Hit Total Coverage
Test: merged.info Lines: 32 43 74.4 %
Date: 2025-01-06 12:44:40 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:matrix/matrix.dart';
       2             : import 'package:matrix/msc_extensions/msc_3381_polls/models/poll_event_content.dart';
       3             : 
       4             : extension PollEventExtension on Event {
       5           2 :   PollEventContent get parsedPollEventContent {
       6           4 :     assert(type == PollEventContent.startType);
       7           4 :     return PollEventContent.fromJson(content);
       8             :   }
       9             : 
      10             :   /// Returns a Map of answer IDs to a Set of user IDs.
      11           2 :   Map<String, Set<String>> getPollResponses(Timeline timeline) {
      12           4 :     assert(type == PollEventContent.startType);
      13             :     final aggregatedEvents =
      14          10 :         timeline.aggregatedEvents[eventId]?['m.reference']?.toList();
      15           4 :     if (aggregatedEvents == null || aggregatedEvents.isEmpty) return {};
      16             : 
      17           2 :     final responses = <String, Set<String>>{};
      18             : 
      19             :     // Votes with timestamps after the poll has closed are ignored, as if they
      20             :     // never happened.
      21             :     aggregatedEvents
      22          10 :         .removeWhere((event) => originServerTs.isAfter(event.originServerTs));
      23             : 
      24             :     // Sort by date so only the users most recent vote is used in the end, even
      25             :     // if it is invalid.
      26             :     aggregatedEvents
      27           2 :         .sort((a, b) => a.originServerTs.compareTo(b.originServerTs));
      28             : 
      29           4 :     for (final event in aggregatedEvents) {
      30           2 :       final answers = event.content
      31           2 :               .tryGetMap<String, Object?>(PollEventContent.responseType)
      32           2 :               ?.tryGetList<String>('answers') ??
      33           0 :           [];
      34           6 :       responses[event.senderId] = answers.toSet();
      35             :     }
      36             :     return responses;
      37             :   }
      38             : 
      39           2 :   bool getPollHasBeenEnded(Timeline timeline) {
      40           4 :     assert(type == PollEventContent.startType);
      41           8 :     final aggregatedEvents = timeline.aggregatedEvents[eventId]?['m.reference'];
      42           2 :     if (aggregatedEvents == null || aggregatedEvents.isEmpty) return false;
      43             : 
      44           2 :     final redactPowerLevel = (room
      45           2 :             .getState(EventTypes.RoomPowerLevels)
      46           0 :             ?.content
      47           0 :             .tryGet<int>('redact') ??
      48             :         50);
      49             : 
      50           2 :     return aggregatedEvents.any(
      51           2 :       (event) {
      52           2 :         if (event.content
      53           2 :                 .tryGetMap<String, Object?>(PollEventContent.endType) ==
      54             :             null) {
      55             :           return false;
      56             :         }
      57             : 
      58             :         // If a m.poll.end event is received from someone other than the poll
      59             :         //creator or user with permission to redact other's messages in the
      60             :         //room, the event must be ignored by clients due to being invalid.
      61           6 :         if (event.senderId == senderId ||
      62           0 :             event.senderFromMemoryOrFallback.powerLevel >= redactPowerLevel) {
      63             :           return true;
      64             :         }
      65           0 :         Logs().w(
      66           0 :           'Ignore poll end event form user without permission ${event.senderId}',
      67             :         );
      68             :         return false;
      69             :       },
      70             :     );
      71             :   }
      72             : 
      73           2 :   Future<String?> answerPoll(
      74             :     List<String> answerIds, {
      75             :     String? txid,
      76             :   }) =>
      77           4 :       room.sendEvent(
      78           2 :         {
      79           2 :           'm.relates_to': {
      80             :             'rel_type': 'm.reference',
      81           2 :             'event_id': eventId,
      82             :           },
      83           2 :           PollEventContent.responseType: {'answers': answerIds},
      84             :         },
      85             :         type: PollEventContent.responseType,
      86             :         txid: txid,
      87             :       );
      88             : 
      89           0 :   Future<String?> endPoll({String? txid}) => room.sendEvent(
      90           0 :         {
      91           0 :           'm.relates_to': {
      92             :             'rel_type': 'm.reference',
      93           0 :             'event_id': eventId,
      94             :           },
      95           0 :           PollEventContent.endType: {},
      96             :         },
      97             :         type: PollEventContent.endType,
      98             :         txid: txid,
      99             :       );
     100             : }

Generated by: LCOV version 1.14