@@ -321,11 +321,10 @@ class Room::Private {
321321
322322 /* ! Apply redaction to the timeline
323323 *
324- * Tries to find an event in the timeline and redact it; deletes the
325- * redaction event whether the redacted event was found or not.
326- * \return true if the event has been found and redacted; false otherwise
324+ * Tries to find events in the timeline and redact them.
325+ * \return the list of event ids that were NOT found and redacted
327326 */
328- bool processRedaction (const RedactionEvent& redaction);
327+ QStringList processRedaction (const RedactionEvent& redaction);
329328
330329 /* ! Apply a new revision of the event to the timeline
331330 *
@@ -1989,54 +1988,61 @@ RoomEventPtr makeRedacted(const RoomEvent& target,
19891988 return loadEvent<RoomEvent>(originalJson);
19901989}
19911990
1992- bool Room::Private::processRedaction (const RedactionEvent& redaction)
1991+ QStringList Room::Private::processRedaction (const RedactionEvent& redaction)
19931992{
1993+ QStringList unredactedIds;
19941994 // Can't use findInTimeline because it returns a const iterator, and
19951995 // we need to change the underlying TimelineItem.
1996- const auto pIdx = eventsIndex.find (redaction.redactedEvent ());
1997- if (pIdx == eventsIndex.end ())
1998- return false ;
1996+ const auto & eventIds = redaction.redactedEvents ();
1997+ for (const auto & evtId: eventIds) {
1998+ const auto pIdx = eventsIndex.find (evtId);
1999+ if (pIdx == eventsIndex.end ()) {
2000+ unredactedIds.push_back (evtId);
2001+ continue ;
2002+ }
19992003
2000- Q_ASSERT (q->isValidIndex (*pIdx));
2004+ Q_ASSERT (q->isValidIndex (*pIdx));
20012005
2002- auto & ti = timeline[Timeline::size_type (*pIdx - q->minTimelineIndex ())];
2003- if (ti->isRedacted () && ti->redactedBecause ()->id () == redaction.id ()) {
2004- qCDebug (EVENTS) << " Redaction" << redaction.id () << " of event"
2005- << ti->id () << " already done, skipping" ;
2006- return true ;
2007- }
2006+ auto & ti = timeline[Timeline::size_type (*pIdx - q->minTimelineIndex ())];
2007+ if (ti->isRedacted () && ti->redactedBecause ()->id () == redaction.id ()) {
2008+ qCDebug (EVENTS) << " Redaction" << redaction.id () << " of event"
2009+ << ti->id () << " already done, skipping" ;
2010+ continue ;
2011+ }
20082012
2009- // Make a new event from the redacted JSON and put it in the timeline
2010- // instead of the redacted one. oldEvent will be deleted on return.
2011- auto oldEvent = ti.replaceEvent (makeRedacted (*ti, redaction));
2012- qCDebug (EVENTS) << " Redacted" << oldEvent->id () << " with" << redaction.id ();
2013- if (oldEvent->isStateEvent ()) {
2014- const StateEventKey evtKey { oldEvent->matrixType (),
2015- oldEvent->stateKey () };
2016- Q_ASSERT (currentState.contains (evtKey));
2017- if (currentState.value (evtKey) == oldEvent.get ()) {
2018- Q_ASSERT (ti.index () >= 0 ); // Historical states can't be in
2019- // currentState
2020- qCDebug (EVENTS).nospace ()
2021- << " Redacting state " << oldEvent->matrixType () << " /"
2022- << oldEvent->stateKey ();
2023- // Retarget the current state to the newly made event.
2024- if (q->processStateEvent (*ti))
2025- emit q->namesChanged (q);
2026- updateDisplayname ();
2013+ // Make a new event from the redacted JSON and put it in the timeline
2014+ // instead of the redacted one. oldEvent will be deleted on return.
2015+ auto oldEvent = ti.replaceEvent (makeRedacted (*ti, redaction));
2016+ qCDebug (EVENTS) << " Redacted" << oldEvent->id () << " with"
2017+ << redaction.id ();
2018+ if (oldEvent->isStateEvent ()) {
2019+ const StateEventKey evtKey { oldEvent->matrixType (),
2020+ oldEvent->stateKey () };
2021+ Q_ASSERT (currentState.contains (evtKey));
2022+ if (currentState.value (evtKey) == oldEvent.get ()) {
2023+ Q_ASSERT (ti.index () >= 0 ); // Historical states can't be in
2024+ // currentState
2025+ qCDebug (EVENTS).nospace ()
2026+ << " Redacting state " << oldEvent->matrixType () << " /"
2027+ << oldEvent->stateKey ();
2028+ // Retarget the current state to the newly made event.
2029+ if (q->processStateEvent (*ti))
2030+ emit q->namesChanged (q);
2031+ updateDisplayname ();
2032+ }
20272033 }
2028- }
2029- if ( const auto * reaction = eventCast<ReactionEvent>(oldEvent)) {
2030- const auto & targetEvtId = reaction-> relation (). eventId ;
2031- const auto lookupKey =
2032- qMakePair (targetEvtId, EventRelation::Annotation ());
2033- if ( relations. contains (lookupKey)) {
2034- relations[lookupKey]. removeOne (reaction);
2034+ if ( const auto * reaction = eventCast<ReactionEvent>(oldEvent)) {
2035+ const auto & targetEvtId = reaction-> relation (). eventId ;
2036+ const auto lookupKey =
2037+ qMakePair (targetEvtId, EventRelation::Annotation ());
2038+ if (relations. contains (lookupKey)) {
2039+ relations[lookupKey]. removeOne (reaction);
2040+ }
20352041 }
2042+ q->onRedaction (*oldEvent, *ti);
2043+ emit q->replacedEvent (ti.event (), rawPtr (oldEvent));
20362044 }
2037- q->onRedaction (*oldEvent, *ti);
2038- emit q->replacedEvent (ti.event (), rawPtr (oldEvent));
2039- return true ;
2045+ return unredactedIds;
20402046}
20412047
20422048/* * Make a replaced event
@@ -2120,20 +2126,21 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events)
21202126 for (const auto & eptr : RoomEventsRange (it, events.end ())) {
21212127 if (auto * r = eventCast<RedactionEvent>(eptr)) {
21222128 // Try to find the target in the timeline, then in the batch.
2123- if (processRedaction (*r))
2124- continue ;
2125- auto targetIt = std::find_if (events.begin (), it,
2126- [id = r->redactedEvent ()](
2127- const RoomEventPtr& ep) {
2128- return ep->id () == id;
2129- });
2130- if (targetIt != it)
2131- *targetIt = makeRedacted (**targetIt, *r);
2132- else
2133- qCDebug (EVENTS)
2134- << " Redaction" << r->id () << " ignored: target event"
2135- << r->redactedEvent () << " is not found" ;
2136- // If the target event comes later, it comes already redacted.
2129+ const auto unredactedIds = processRedaction (*r);
2130+ for (const auto & idToRedact: unredactedIds) {
2131+ if (auto targetIt =
2132+ std::find_if (events.begin (), it,
2133+ [idToRedact](const RoomEventPtr& ep) {
2134+ return ep->id () == idToRedact;
2135+ });
2136+ targetIt != it)
2137+ *targetIt = makeRedacted (**targetIt, *r);
2138+ else
2139+ qCDebug (EVENTS)
2140+ << " Target event" << idToRedact << " in redaction"
2141+ << r->id () << " is not found" ;
2142+ // If the target event comes later, it comes already redacted.
2143+ }
21372144 }
21382145 if (auto * msg = eventCast<RoomMessageEvent>(eptr)) {
21392146 if (!msg->replacedEvent ().isEmpty ()) {
0 commit comments