File indexing completed on 2024-10-06 10:23:57
0001 // SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org> 0002 // SPDX-License-Identifier: LGPL-2.0-or-later 0003 0004 #include "pollhandler.h" 0005 0006 #include "events/pollevent.h" 0007 #include "neochatroom.h" 0008 0009 #include <Quotient/csapi/relations.h> 0010 #include <Quotient/events/roompowerlevelsevent.h> 0011 #include <Quotient/user.h> 0012 0013 #include <algorithm> 0014 0015 using namespace Quotient; 0016 0017 PollHandler::PollHandler(QObject *parent) 0018 : QObject(parent) 0019 { 0020 connect(this, &PollHandler::roomChanged, this, &PollHandler::checkLoadRelations); 0021 connect(this, &PollHandler::pollStartEventIdChanged, this, &PollHandler::checkLoadRelations); 0022 } 0023 0024 NeoChatRoom *PollHandler::room() const 0025 { 0026 return m_room; 0027 } 0028 0029 void PollHandler::setRoom(NeoChatRoom *room) 0030 { 0031 if (m_room == room) { 0032 return; 0033 } 0034 if (m_room) { 0035 disconnect(m_room, nullptr, this, nullptr); 0036 } 0037 connect(room, &NeoChatRoom::aboutToAddNewMessages, this, [this](Quotient::RoomEventsRange events) { 0038 for (const auto &event : events) { 0039 if (event->is<PollEndEvent>()) { 0040 auto plEvent = m_room->currentState().get<RoomPowerLevelsEvent>(); 0041 if (!plEvent) { 0042 continue; 0043 } 0044 auto userPl = plEvent->powerLevelForUser(event->senderId()); 0045 if (event->senderId() == (*m_room->findInTimeline(m_pollStartEventId))->senderId() || userPl >= plEvent->redact()) { 0046 m_hasEnded = true; 0047 m_endedTimestamp = event->originTimestamp(); 0048 Q_EMIT hasEndedChanged(); 0049 } 0050 } 0051 if (event->is<PollResponseEvent>()) { 0052 handleAnswer(event->contentJson(), event->senderId(), event->originTimestamp()); 0053 } 0054 } 0055 }); 0056 m_room = room; 0057 Q_EMIT roomChanged(); 0058 } 0059 0060 QString PollHandler::pollStartEventId() const 0061 { 0062 return m_pollStartEventId; 0063 } 0064 0065 void PollHandler::setPollStartEventId(const QString &eventId) 0066 { 0067 if (eventId == m_pollStartEventId) { 0068 return; 0069 } 0070 m_pollStartEventId = eventId; 0071 Q_EMIT pollStartEventIdChanged(); 0072 } 0073 0074 void PollHandler::checkLoadRelations() 0075 { 0076 if (!m_room || m_pollStartEventId.isEmpty()) { 0077 return; 0078 } 0079 m_maxVotes = eventCast<const PollStartEvent>(&**m_room->findInTimeline(m_pollStartEventId))->maxSelections(); 0080 auto job = m_room->connection()->callApi<GetRelatingEventsJob>(m_room->id(), m_pollStartEventId); 0081 connect(job, &BaseJob::success, this, [this, job]() { 0082 for (const auto &event : job->chunk()) { 0083 if (event->is<PollEndEvent>()) { 0084 auto plEvent = m_room->currentState().get<RoomPowerLevelsEvent>(); 0085 if (!plEvent) { 0086 continue; 0087 } 0088 auto userPl = plEvent->powerLevelForUser(event->senderId()); 0089 if (event->senderId() == (*m_room->findInTimeline(m_pollStartEventId))->senderId() || userPl >= plEvent->redact()) { 0090 m_hasEnded = true; 0091 m_endedTimestamp = event->originTimestamp(); 0092 Q_EMIT hasEndedChanged(); 0093 } 0094 } 0095 if (event->is<PollResponseEvent>()) { 0096 handleAnswer(event->contentJson(), event->senderId(), event->originTimestamp()); 0097 } 0098 } 0099 }); 0100 } 0101 0102 void PollHandler::handleAnswer(const QJsonObject &content, const QString &sender, QDateTime timestamp) 0103 { 0104 if (timestamp > m_answerTimestamps[sender] && (!m_hasEnded || timestamp < m_endedTimestamp)) { 0105 m_answerTimestamps[sender] = timestamp; 0106 m_answers[sender] = {}; 0107 int i = 0; 0108 for (const auto &answer : content["org.matrix.msc3381.poll.response"]["answers"].toArray()) { 0109 auto array = m_answers[sender].toArray(); 0110 array.insert(0, answer); 0111 m_answers[sender] = array; 0112 i++; 0113 if (i == m_maxVotes) { 0114 break; 0115 } 0116 } 0117 for (const auto &key : m_answers.keys()) { 0118 if (m_answers[key].toArray().isEmpty()) { 0119 m_answers.remove(key); 0120 } 0121 } 0122 } 0123 Q_EMIT answersChanged(); 0124 } 0125 0126 QJsonObject PollHandler::answers() const 0127 { 0128 return m_answers; 0129 } 0130 0131 QJsonObject PollHandler::counts() const 0132 { 0133 QJsonObject counts; 0134 for (const auto &answer : m_answers) { 0135 for (const auto &id : answer.toArray()) { 0136 counts[id.toString()] = counts[id.toString()].toInt() + 1; 0137 } 0138 } 0139 return counts; 0140 } 0141 0142 void PollHandler::sendPollAnswer(const QString &eventId, const QString &answerId) 0143 { 0144 Q_ASSERT(eventId.length() > 0); 0145 Q_ASSERT(answerId.length() > 0); 0146 QStringList ownAnswers; 0147 for (const auto &answer : m_answers[m_room->localUser()->id()].toArray()) { 0148 ownAnswers += answer.toString(); 0149 } 0150 if (ownAnswers.contains(answerId)) { 0151 ownAnswers.erase(std::remove_if(ownAnswers.begin(), ownAnswers.end(), [answerId](const auto &it) { 0152 return answerId == it; 0153 })); 0154 } else { 0155 while (ownAnswers.size() >= m_maxVotes) { 0156 ownAnswers.pop_front(); 0157 } 0158 ownAnswers.insert(0, answerId); 0159 } 0160 0161 auto response = new PollResponseEvent(eventId, ownAnswers); 0162 handleAnswer(response->contentJson(), m_room->localUser()->id(), QDateTime::currentDateTime()); 0163 m_room->postEvent(response); 0164 } 0165 0166 bool PollHandler::hasEnded() const 0167 { 0168 return m_hasEnded; 0169 } 0170 0171 int PollHandler::answerCount() const 0172 { 0173 return m_answers.size(); 0174 } 0175 0176 #include "moc_pollhandler.cpp"