Skip to content

Commit

Permalink
Merge pull request #1691 from matrix-org/alfogrillo/fetch_poll_history
Browse files Browse the repository at this point in the history
Enhance PollProtocol for poll history (PSG-1043)
  • Loading branch information
alfogrillo authored Jan 24, 2023
2 parents 10c420c + 99df899 commit 5e6fb10
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 58 deletions.
22 changes: 15 additions & 7 deletions MatrixSDK/Room/Polls/PollAggregator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class PollAggregator {
private let pollStartEventId: String
private let pollBuilder: PollBuilder

private var pollStartedEvent: MXEvent!
private var pollStartEventContent: MXEventContentPollStart!

private var referenceEventsListener: Any?
Expand All @@ -59,7 +60,7 @@ public class PollAggregator {
}
}

public var delegate: PollAggregatorDelegate?
public weak var delegate: PollAggregatorDelegate?

deinit {
if let referenceEventsListener = referenceEventsListener {
Expand All @@ -71,7 +72,7 @@ public class PollAggregator {
}
}

public convenience init(session: MXSession, room: MXRoom, pollEvent: MXEvent) throws {
public convenience init(session: MXSession, room: MXRoom, pollEvent: MXEvent, delegate: PollAggregatorDelegate? = nil) throws {
var pollStartEventId: String?

switch pollEvent.eventType {
Expand All @@ -87,14 +88,15 @@ public class PollAggregator {
throw PollAggregatorError.invalidPollStartEvent
}

try self.init(session: session, room: room, pollStartEventId: pollStartEventId)
try self.init(session: session, room: room, pollStartEventId: pollStartEventId, delegate: delegate)
}

public init(session: MXSession, room: MXRoom, pollStartEventId: String) throws {
public init(session: MXSession, room: MXRoom, pollStartEventId: String, delegate: PollAggregatorDelegate? = nil) throws {
self.session = session
self.room = room
self.pollStartEventId = pollStartEventId
self.pollBuilder = PollBuilder()
self.delegate = delegate

NotificationCenter.default.addObserver(self, selector: #selector(handleRoomDataFlush), name: .mxRoomDidFlushData, object: self.room)
setupEditListener()
Expand Down Expand Up @@ -125,11 +127,13 @@ public class PollAggregator {
throw PollAggregatorError.invalidPollStartEvent
}

pollStartedEvent = event
pollStartEventContent = eventContent

hasBeenEdited = (event.unsignedData.relations?.replace != nil)

poll = pollBuilder.build(pollStartEventContent: eventContent,
pollStartEvent: pollStartedEvent,
events: events,
currentUserIdentifier: session.myUserId,
hasBeenEdited: hasBeenEdited)
Expand Down Expand Up @@ -159,21 +163,25 @@ public class PollAggregator {

let eventTypes = [kMXEventTypeStringPollResponse, kMXEventTypeStringPollResponseMSC3381, kMXEventTypeStringPollEnd, kMXEventTypeStringPollEndMSC3381]
self.referenceEventsListener = self.room.listen(toEventsOfTypes: eventTypes) { [weak self] event, direction, state in
guard let self = self,
let relatedEventId = event.relatesTo?.eventId,
relatedEventId == self.pollStartEventId else {
guard
let self = self,
let relatedEventId = event.relatesTo?.eventId,
relatedEventId == self.pollStartEventId
else {
return
}

self.events.append(event)

self.poll = self.pollBuilder.build(pollStartEventContent: self.pollStartEventContent,
pollStartEvent: self.pollStartedEvent,
events: self.events,
currentUserIdentifier: self.session.myUserId,
hasBeenEdited: self.hasBeenEdited)
} as Any

self.poll = self.pollBuilder.build(pollStartEventContent: self.pollStartEventContent,
pollStartEvent: self.pollStartedEvent,
events: self.events,
currentUserIdentifier: self.session.myUserId,
hasBeenEdited: self.hasBeenEdited)
Expand Down
14 changes: 11 additions & 3 deletions MatrixSDK/Room/Polls/PollBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ struct PollBuilder {
static let maxAnswerOptionCount = 20
}

func build(pollStartEventContent: MXEventContentPollStart, events: [MXEvent], currentUserIdentifier: String, hasBeenEdited: Bool = false) -> PollProtocol {
func build(pollStartEventContent: MXEventContentPollStart,
pollStartEvent: MXEvent,
events: [MXEvent],
currentUserIdentifier: String,
hasBeenEdited: Bool = false) -> PollProtocol {

let poll = Poll()
poll.id = pollStartEvent.eventId
poll.startDate = Date(timeIntervalSince1970: Double(pollStartEvent.originServerTs) / 1000)
poll.hasBeenEdited = hasBeenEdited
poll.hasDecryptionError = events.contains(where: { $0.isEncrypted && $0.clear == nil })

Expand Down Expand Up @@ -55,9 +61,11 @@ struct PollBuilder {

var filteredEvents = events.filter { event in
guard
let eventContent = event.content, event.eventType == __MXEventType.pollResponse,
let eventContent = event.content,
event.eventType == .pollResponse,
let response = pollResponseFromEventContent(eventContent),
let _ = response[kMXMessageContentKeyExtensiblePollAnswers] else {
let _ = response[kMXMessageContentKeyExtensiblePollAnswers]
else {
return false
}

Expand Down
8 changes: 5 additions & 3 deletions MatrixSDK/Room/Polls/PollModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ public protocol PollAnswerOptionProtocol {
}

public protocol PollProtocol {
var id: String { get }
var text: String { get }
var answerOptions: [PollAnswerOptionProtocol] { get }
var kind: PollKind { get }
var startDate: Date { get }
var maxAllowedSelections: UInt { get }
var isClosed: Bool { get }
var totalAnswerCount: UInt { get }
Expand All @@ -43,23 +45,23 @@ public protocol PollProtocol {
class PollAnswerOption: PollAnswerOptionProtocol {
var id: String = ""
var text: String = ""

var count: UInt = 0
var isWinner: Bool = false
var isCurrentUserSelection: Bool = false
}

class Poll: PollProtocol {
var id: String = ""
var text: String = ""
var answerOptions: [PollAnswerOptionProtocol] = []

var kind: PollKind = .disclosed
var startDate: Date = .distantPast
var maxAllowedSelections: UInt = 1
var isClosed: Bool = false
var hasBeenEdited: Bool = false
var hasDecryptionError: Bool = false

var totalAnswerCount: UInt {
return self.answerOptions.reduce(0) { $0 + $1.count}
answerOptions.reduce(0) { $0 + $1.count }
}
}
79 changes: 44 additions & 35 deletions MatrixSDKTests/MXPollAggregatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,35 @@ import Foundation

class MXPollAggregatorTest: XCTestCase {
private var matrixSDKTestsData: MatrixSDKTestsData!

private var matrixSDKTestsE2EData: MatrixSDKTestsE2EData!

private var pollAggregator: PollAggregator!
private var delegate: PollAggregatorBlockWrapper!
private var isFirstDelegateUpdate: Bool = true

override func setUp() {
super.setUp()
matrixSDKTestsData = MatrixSDKTestsData()
matrixSDKTestsE2EData = MatrixSDKTestsE2EData(matrixSDKTestsData: matrixSDKTestsData)
isFirstDelegateUpdate = true
}

override func tearDown() {
matrixSDKTestsData = nil
matrixSDKTestsE2EData = nil
delegate = nil
super.tearDown()
}

func testAggregations() {
self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in
self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)
self.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { pollAggregator in
XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 2)
XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0)
expectation.fulfill()
})

self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)

let dispatchGroup = DispatchGroup()

for _ in 1...5 {
Expand All @@ -58,29 +66,26 @@ class MXPollAggregatorTest: XCTestCase {
}

dispatchGroup.notify(queue: .main) {
self.pollAggregator.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: {
XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 2)
XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0)

expectation.fulfill()
})
self.pollAggregator.delegate = self.delegate
}
}
}

func testSessionPausing() {
self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in
let delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { aggregator in
XCTAssertEqual(aggregator.poll.answerOptions.first!.count, 2)
XCTAssertEqual(aggregator.poll.answerOptions.last!.count, 0)
})

self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)

XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 1) // One from Alice
XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0)

bobSession.pause()

self.pollAggregator.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: {
XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 2)
XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0)
})
self.pollAggregator.delegate = delegate

bobRoom.sendPollResponse(for: pollStartEvent, withAnswerIdentifiers: ["1"], threadId:nil, localEcho: nil) { _ in
bobSession.resume {
Expand All @@ -96,6 +101,12 @@ class MXPollAggregatorTest: XCTestCase {
self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in
self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)

self.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { aggregator in
XCTAssertEqual(aggregator.poll.answerOptions.first!.count, 2) // One from Bob and one from Alice
XCTAssertEqual(aggregator.poll.answerOptions.last!.count, 1) // One from Alice
expectation.fulfill()
})

XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 1) // One from Alice
XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0)

Expand All @@ -105,12 +116,7 @@ class MXPollAggregatorTest: XCTestCase {
bobRoom.sendPollResponse(for: pollStartEvent, withAnswerIdentifiers: ["1"], threadId:nil, localEcho: nil) { _ in
aliceRoom.sendPollResponse(for: pollStartEvent, withAnswerIdentifiers: ["1", "2"], threadId:nil, localEcho: nil) { _ in
self.matrixSDKTestsData.for(aliceSession.matrixRestClient, andRoom: aliceRoom.roomId, sendMessages: 50, testCase: self) {

self.pollAggregator.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: {
XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 2) // One from Bob and one from Alice
XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 1) // One from Alice
expectation.fulfill()
})
self.pollAggregator.delegate = self.delegate

bobSession.resume {

Expand All @@ -131,24 +137,28 @@ class MXPollAggregatorTest: XCTestCase {
self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in
self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)

self.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { aggregator in
defer {
self.isFirstDelegateUpdate = false
}
guard self.isFirstDelegateUpdate else {
return
}
XCTAssertEqual(aggregator.poll.text, "Some other question")
XCTAssertEqual(aggregator.poll.answerOptions.count, 2)
XCTAssertTrue(aggregator.poll.hasBeenEdited)
expectation.fulfill()
})

let oldContent = MXEventContentPollStart(fromJSON: pollStartEvent.content)!
let newContent = MXEventContentPollStart(question: "Some other question",
kind: oldContent.kind,
maxSelections: oldContent.maxSelections,
answerOptions: [])

self.pollAggregator.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: {

XCTAssertEqual(self.pollAggregator.poll.text, "Some other question")
XCTAssertEqual(self.pollAggregator.poll.answerOptions.count, 0)
XCTAssertTrue(self.pollAggregator.poll.hasBeenEdited)

expectation.fulfill()
self.pollAggregator.delegate = nil
})
answerOptions: oldContent.answerOptions)


bobRoom.sendPollUpdate(for: pollStartEvent, oldContent: oldContent, newContent: newContent, localEcho: nil) { result in

self.pollAggregator.delegate = self.delegate
} failure: { error in
XCTFail("The operation should not fail - NSError: \(String(describing: error))")
}
Expand Down Expand Up @@ -200,10 +210,9 @@ class MXPollAggregatorTest: XCTestCase {
}

private class PollAggregatorBlockWrapper: PollAggregatorDelegate {
let dataUpdateCallback: (PollAggregator) -> (Void)

let dataUpdateCallback: ()->(Void)

internal init(dataUpdateCallback: @escaping () -> (Void)) {
internal init(dataUpdateCallback: @escaping (PollAggregator) -> (Void)) {
self.dataUpdateCallback = dataUpdateCallback
}

Expand All @@ -220,6 +229,6 @@ private class PollAggregatorBlockWrapper: PollAggregatorDelegate {
}

func pollAggregatorDidUpdateData(_ aggregator: PollAggregator) {
dataUpdateCallback()
dataUpdateCallback(aggregator)
}
}
Loading

0 comments on commit 5e6fb10

Please sign in to comment.