File indexing completed on 2024-05-12 16:25:03
0001 // SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org> 0002 // SPDX-License-Identifier: LGPL-2.0-or-later 0003 0004 #include "actionsmodel.h" 0005 0006 #include "controller.h" 0007 #include "neochatroom.h" 0008 #include "roommanager.h" 0009 #include <Quotient/events/roommemberevent.h> 0010 #include <Quotient/events/roompowerlevelsevent.h> 0011 0012 #include <KLocalizedString> 0013 0014 using Action = ActionsModel::Action; 0015 using namespace Quotient; 0016 0017 QStringList rainbowColors{"#ff2b00", "#ff5500", "#ff8000", "#ffaa00", "#ffd500", "#ffff00", "#d4ff00", "#aaff00", "#80ff00", "#55ff00", "#2bff00", "#00ff00", 0018 "#00ff2b", "#00ff55", "#00ff80", "#00ffaa", "#00ffd5", "#00ffff", "#00d4ff", "#00aaff", "#007fff", "#0055ff", "#002bff", "#0000ff", 0019 "#2a00ff", "#5500ff", "#7f00ff", "#aa00ff", "#d400ff", "#ff00ff", "#ff00d4", "#ff00aa", "#ff0080", "#ff0055", "#ff002b", "#ff0000"}; 0020 0021 auto leaveRoomLambda = [](const QString &text, NeoChatRoom *room) { 0022 if (text.isEmpty()) { 0023 Q_EMIT room->showMessage(NeoChatRoom::Info, i18n("Leaving this room.")); 0024 room->connection()->leaveRoom(room); 0025 } else { 0026 QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)")); 0027 auto regexMatch = roomRegex.match(text); 0028 if (!regexMatch.hasMatch()) { 0029 Q_EMIT room->showMessage(NeoChatRoom::Error, 0030 i18nc("'<text>' does not look like a room id or alias.", "'%1' does not look like a room id or alias.", text)); 0031 return QString(); 0032 } 0033 auto leaving = room->connection()->room(text); 0034 if (!leaving) { 0035 leaving = room->connection()->roomByAlias(text); 0036 } 0037 if (leaving) { 0038 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Leaving room <roomname>.", "Leaving room %1.", text)); 0039 room->connection()->leaveRoom(leaving); 0040 } else { 0041 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Room <roomname> not found", "Room %1 not found.", text)); 0042 } 0043 } 0044 return QString(); 0045 }; 0046 0047 auto roomNickLambda = [](const QString &text, NeoChatRoom *room) { 0048 if (text.isEmpty()) { 0049 Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("No new nickname provided, no changes will happen.")); 0050 } else { 0051 room->connection()->user()->rename(text, room); 0052 } 0053 return QString(); 0054 }; 0055 0056 QVector<ActionsModel::Action> actions{ 0057 Action{ 0058 QStringLiteral("shrug"), 0059 [](const QString &message, NeoChatRoom *) { 0060 return QStringLiteral("¯\\\\_(ツ)_/¯ %1").arg(message); 0061 }, 0062 true, 0063 std::nullopt, 0064 kli18n("<message>"), 0065 kli18n("Prepends ¯\\_(ツ)_/¯ to a plain-text message"), 0066 }, 0067 Action{ 0068 QStringLiteral("lenny"), 0069 [](const QString &message, NeoChatRoom *) { 0070 return QStringLiteral("( ͡° ͜ʖ ͡°) %1").arg(message); 0071 }, 0072 true, 0073 std::nullopt, 0074 kli18n("<message>"), 0075 kli18n("Prepends ( ͡° ͜ʖ ͡°) to a plain-text message"), 0076 }, 0077 Action{ 0078 QStringLiteral("tableflip"), 0079 [](const QString &message, NeoChatRoom *) { 0080 return QStringLiteral("(╯°□°)╯︵ ┻━┻ %1").arg(message); 0081 }, 0082 true, 0083 std::nullopt, 0084 kli18n("<message>"), 0085 kli18n("Prepends (╯°□°)╯︵ ┻━┻ to a plain-text message"), 0086 }, 0087 Action{ 0088 QStringLiteral("unflip"), 0089 [](const QString &message, NeoChatRoom *) { 0090 return QStringLiteral("┬──┬ ノ( ゜-゜ノ) %1").arg(message); 0091 }, 0092 true, 0093 std::nullopt, 0094 kli18n("<message>"), 0095 kli18n("Prepends ┬──┬ ノ( ゜-゜ノ) to a plain-text message"), 0096 }, 0097 Action{ 0098 QStringLiteral("rainbow"), 0099 [](const QString &text, NeoChatRoom *room) { 0100 QString rainbowText; 0101 for (int i = 0; i < text.length(); i++) { 0102 rainbowText += QStringLiteral("<font color='%2'>%3</font>").arg(rainbowColors[i % rainbowColors.length()], text.at(i)); 0103 } 0104 // Ideally, we would just return rainbowText and let that do the rest, but the colors don't survive markdownToHTML. 0105 room->postMessage(QStringLiteral("/rainbow %1").arg(text), 0106 rainbowText, 0107 RoomMessageEvent::MsgType::Text, 0108 room->chatBoxReplyId(), 0109 room->chatBoxEditId()); 0110 return QString(); 0111 }, 0112 false, 0113 std::nullopt, 0114 kli18n("<message>"), 0115 kli18n("Sends the given message colored as a rainbow"), 0116 }, 0117 Action{ 0118 QStringLiteral("rainbowme"), 0119 [](const QString &text, NeoChatRoom *room) { 0120 QString rainbowText; 0121 for (int i = 0; i < text.length(); i++) { 0122 rainbowText += QStringLiteral("<font color='%2'>%3</font>").arg(rainbowColors[i % rainbowColors.length()], text.at(i)); 0123 } 0124 // Ideally, we would just return rainbowText and let that do the rest, but the colors don't survive markdownToHTML. 0125 room->postMessage(QStringLiteral("/rainbow %1").arg(text), 0126 rainbowText, 0127 RoomMessageEvent::MsgType::Emote, 0128 room->chatBoxReplyId(), 0129 room->chatBoxEditId()); 0130 return QString(); 0131 }, 0132 false, 0133 std::nullopt, 0134 kli18n("<message>"), 0135 kli18n("Sends the given emote colored as a rainbow"), 0136 }, 0137 Action{ 0138 QStringLiteral("plain"), 0139 [](const QString &text, NeoChatRoom *room) { 0140 room->postMessage(text, text.toHtmlEscaped(), RoomMessageEvent::MsgType::Text, {}, {}); 0141 return QString(); 0142 }, 0143 false, 0144 std::nullopt, 0145 kli18n("<message>"), 0146 kli18n("Sends the given message as plain text"), 0147 }, 0148 Action{ 0149 QStringLiteral("spoiler"), 0150 [](const QString &text, NeoChatRoom *room) { 0151 // Ideally, we would just return rainbowText and let that do the rest, but the colors don't survive markdownToHTML. 0152 room->postMessage(QStringLiteral("/spoiler %1").arg(text), 0153 QStringLiteral("<span data-mx-spoiler>%1</span>").arg(text), 0154 RoomMessageEvent::MsgType::Text, 0155 room->chatBoxReplyId(), 0156 room->chatBoxEditId()); 0157 return QString(); 0158 }, 0159 false, 0160 std::nullopt, 0161 kli18n("<message>"), 0162 kli18n("Sends the given message as a spoiler"), 0163 }, 0164 Action{ 0165 QStringLiteral("me"), 0166 [](const QString &text, NeoChatRoom *) { 0167 return text; 0168 }, 0169 true, 0170 RoomMessageEvent::MsgType::Emote, 0171 kli18n("<message>"), 0172 kli18n("Sends the given emote"), 0173 }, 0174 Action{ 0175 QStringLiteral("notice"), 0176 [](const QString &text, NeoChatRoom *) { 0177 return text; 0178 }, 0179 true, 0180 RoomMessageEvent::MsgType::Notice, 0181 kli18n("<message>"), 0182 kli18n("Sends the given message as a notice"), 0183 }, 0184 Action{ 0185 QStringLiteral("invite"), 0186 [](const QString &text, NeoChatRoom *room) { 0187 static const QRegularExpression mxidRegex( 0188 QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))")); 0189 auto regexMatch = mxidRegex.match(text); 0190 if (!regexMatch.hasMatch()) { 0191 Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", text)); 0192 return QString(); 0193 } 0194 const RoomMemberEvent *roomMemberEvent = room->currentState().get<RoomMemberEvent>(text); 0195 if (roomMemberEvent && roomMemberEvent->membership() == Membership::Invite) { 0196 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already invited to this room.", "%1 is already invited to this room.", text)); 0197 return QString(); 0198 } 0199 if (roomMemberEvent && roomMemberEvent->membership() == Membership::Ban) { 0200 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is banned from this room.", "%1 is banned from this room.", text)); 0201 return QString(); 0202 } 0203 if (room->localUser()->id() == text) { 0204 Q_EMIT room->showMessage(NeoChatRoom::Positive, i18n("You are already in this room.")); 0205 return QString(); 0206 } 0207 if (room->users().contains(room->user(text))) { 0208 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already in this room.", "%1 is already in this room.", text)); 0209 return QString(); 0210 } 0211 room->inviteToRoom(text); 0212 Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> was invited into this room", "%1 was invited into this room", text)); 0213 return QString(); 0214 }, 0215 false, 0216 std::nullopt, 0217 kli18n("<user id>"), 0218 kli18n("Invites the user to this room"), 0219 }, 0220 Action{ 0221 QStringLiteral("join"), 0222 [](const QString &text, NeoChatRoom *room) { 0223 QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)")); 0224 auto regexMatch = roomRegex.match(text); 0225 if (!regexMatch.hasMatch()) { 0226 Q_EMIT room->showMessage(NeoChatRoom::Error, 0227 i18nc("'<text>' does not look like a room id or alias.", "'%1' does not look like a room id or alias.", text)); 0228 return QString(); 0229 } 0230 auto targetRoom = text.startsWith(QLatin1Char('!')) ? room->connection()->room(text) : room->connection()->roomByAlias(text); 0231 if (targetRoom) { 0232 RoomManager::instance().enterRoom(dynamic_cast<NeoChatRoom *>(targetRoom)); 0233 return QString(); 0234 } 0235 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Joining room <roomname>.", "Joining room %1.", text)); 0236 Controller::instance().joinRoom(text); 0237 return QString(); 0238 }, 0239 false, 0240 std::nullopt, 0241 kli18n("<room alias or id>"), 0242 kli18n("Joins the given room"), 0243 }, 0244 Action{ 0245 QStringLiteral("knock"), 0246 [](const QString &text, NeoChatRoom *room) { 0247 auto parts = text.split(QLatin1String(" ")); 0248 QString roomName = parts[0]; 0249 QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)")); 0250 auto regexMatch = roomRegex.match(roomName); 0251 if (!regexMatch.hasMatch()) { 0252 Q_EMIT room->showMessage(NeoChatRoom::Error, 0253 i18nc("'<text>' does not look like a room id or alias.", "'%1' does not look like a room id or alias.", text)); 0254 return QString(); 0255 } 0256 auto targetRoom = text.startsWith(QLatin1Char('!')) ? room->connection()->room(text) : room->connection()->roomByAlias(text); 0257 if (targetRoom) { 0258 RoomManager::instance().enterRoom(dynamic_cast<NeoChatRoom *>(targetRoom)); 0259 return QString(); 0260 } 0261 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Knocking room <roomname>.", "Knocking room %1.", text)); 0262 auto connection = Controller::instance().activeConnection(); 0263 const auto knownServer = roomName.mid(roomName.indexOf(":") + 1); 0264 if (parts.length() >= 2) { 0265 RoomManager::instance().knockRoom(connection, roomName, parts[1], QStringList{knownServer}); 0266 } else { 0267 RoomManager::instance().knockRoom(connection, roomName, QString(), QStringList{knownServer}); 0268 } 0269 return QString(); 0270 }, 0271 false, 0272 std::nullopt, 0273 kli18n("<room alias or id> [<reason>]"), 0274 kli18n("Requests to join the given room"), 0275 }, 0276 Action{ 0277 QStringLiteral("j"), 0278 [](const QString &text, NeoChatRoom *room) { 0279 QRegularExpression roomRegex(QStringLiteral(R"(^[#!][^:]+:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?)")); 0280 auto regexMatch = roomRegex.match(text); 0281 if (!regexMatch.hasMatch()) { 0282 Q_EMIT room->showMessage(NeoChatRoom::Error, 0283 i18nc("'<text>' does not look like a room id or alias.", "'%1' does not look like a room id or alias.", text)); 0284 return QString(); 0285 } 0286 if (Controller::instance().activeConnection()->room(text) || Controller::instance().activeConnection()->roomByAlias(text)) { 0287 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("You are already in room <roomname>.", "You are already in room %1.", text)); 0288 return QString(); 0289 } 0290 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Joining room <roomname>.", "Joining room %1.", text)); 0291 Controller::instance().joinRoom(text); 0292 return QString(); 0293 }, 0294 false, 0295 std::nullopt, 0296 kli18n("<room alias or id>"), 0297 kli18n("Joins the given room"), 0298 }, 0299 Action{ 0300 QStringLiteral("part"), 0301 leaveRoomLambda, 0302 false, 0303 std::nullopt, 0304 kli18n("[<room alias or id>]"), 0305 kli18n("Leaves the given room or this room, if there is none given"), 0306 }, 0307 Action{ 0308 QStringLiteral("leave"), 0309 leaveRoomLambda, 0310 false, 0311 std::nullopt, 0312 kli18n("[<room alias or id>]"), 0313 kli18n("Leaves the given room or this room, if there is none given"), 0314 }, 0315 Action{ 0316 QStringLiteral("nick"), 0317 [](const QString &text, NeoChatRoom *room) { 0318 if (text.isEmpty()) { 0319 Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("No new nickname provided, no changes will happen.")); 0320 } else { 0321 room->connection()->user()->rename(text); 0322 } 0323 return QString(); 0324 }, 0325 false, 0326 std::nullopt, 0327 kli18n("<display name>"), 0328 kli18n("Changes your global display name"), 0329 }, 0330 Action{ 0331 QStringLiteral("roomnick"), 0332 roomNickLambda, 0333 false, 0334 std::nullopt, 0335 kli18n("<display name>"), 0336 kli18n("Changes your display name in this room"), 0337 }, 0338 Action{ 0339 QStringLiteral("myroomnick"), 0340 roomNickLambda, 0341 false, 0342 std::nullopt, 0343 kli18n("<display name>"), 0344 kli18n("Changes your display name in this room"), 0345 }, 0346 Action{ 0347 QStringLiteral("ignore"), 0348 [](const QString &text, NeoChatRoom *room) { 0349 static const QRegularExpression mxidRegex( 0350 QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))")); 0351 auto regexMatch = mxidRegex.match(text); 0352 if (!regexMatch.hasMatch()) { 0353 Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", text)); 0354 return QString(); 0355 } 0356 auto user = room->connection()->users()[text]; 0357 if (room->connection()->ignoredUsers().contains(user->id())) { 0358 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<username> is already ignored.", "%1 is already ignored.", text)); 0359 return QString(); 0360 } 0361 if (user) { 0362 room->connection()->addToIgnoredUsers(user); 0363 Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> is now ignored", "%1 is now ignored.", text)); 0364 } else { 0365 Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("<username> is not a known user", "%1 is not a known user.", text)); 0366 } 0367 return QString(); 0368 }, 0369 false, 0370 std::nullopt, 0371 kli18n("<user id>"), 0372 kli18n("Ignores the given user"), 0373 }, 0374 Action{ 0375 QStringLiteral("unignore"), 0376 [](const QString &text, NeoChatRoom *room) { 0377 static const QRegularExpression mxidRegex( 0378 QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))")); 0379 auto regexMatch = mxidRegex.match(text); 0380 if (!regexMatch.hasMatch()) { 0381 Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", text)); 0382 return QString(); 0383 } 0384 auto user = room->connection()->users()[text]; 0385 if (user) { 0386 if (!room->connection()->ignoredUsers().contains(user->id())) { 0387 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<username> is not ignored.", "%1 is not ignored.", text)); 0388 return QString(); 0389 } 0390 room->connection()->removeFromIgnoredUsers(user); 0391 Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> is no longer ignored.", "%1 is no longer ignored.", text)); 0392 } else { 0393 Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("<username> is not a known user", "%1 is not a known user.", text)); 0394 } 0395 return QString(); 0396 }, 0397 false, 0398 std::nullopt, 0399 kli18n("<user id>"), 0400 kli18n("Unignores the given user"), 0401 }, 0402 Action{ 0403 QStringLiteral("react"), 0404 [](const QString &text, NeoChatRoom *room) { 0405 QString replyEventId = room->chatBoxReplyId(); 0406 if (replyEventId.isEmpty()) { 0407 for (auto it = room->messageEvents().crbegin(); it != room->messageEvents().crend(); it++) { 0408 const auto &evt = **it; 0409 if (const auto event = eventCast<const RoomMessageEvent>(&evt)) { 0410 room->toggleReaction(event->id(), text); 0411 return QString(); 0412 } 0413 } 0414 } 0415 room->toggleReaction(replyEventId, text); 0416 return QString(); 0417 }, 0418 false, 0419 std::nullopt, 0420 kli18n("<reaction text>"), 0421 kli18n("React to the message with the given text"), 0422 }, 0423 Action{ 0424 QStringLiteral("ban"), 0425 [](const QString &text, NeoChatRoom *room) { 0426 auto parts = text.split(QLatin1String(" ")); 0427 static const QRegularExpression mxidRegex( 0428 QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))")); 0429 auto regexMatch = mxidRegex.match(parts[0]); 0430 if (!regexMatch.hasMatch()) { 0431 Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", text)); 0432 return QString(); 0433 } 0434 auto state = room->currentState().get<RoomMemberEvent>(parts[0]); 0435 if (state && state->membership() == Membership::Ban) { 0436 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is already banned from this room.", "%1 is already banned from this room.", text)); 0437 return QString(); 0438 } 0439 auto plEvent = room->currentState().get<RoomPowerLevelsEvent>(); 0440 if (!plEvent) { 0441 return QString(); 0442 } 0443 if (plEvent->ban() > plEvent->powerLevelForUser(room->localUser()->id())) { 0444 Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to ban users from this room.")); 0445 return QString(); 0446 } 0447 if (plEvent->powerLevelForUser(room->localUser()->id()) <= plEvent->powerLevelForUser(parts[0])) { 0448 Q_EMIT room->showMessage( 0449 NeoChatRoom::Error, 0450 i18nc("You are not allowed to ban <username> from this room.", "You are not allowed to ban %1 from this room.", parts[0])); 0451 return QString(); 0452 } 0453 room->ban(parts[0], parts.size() > 1 ? parts.mid(1).join(" ") : QString()); 0454 Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> was banned from this room.", "%1 was banned from this room.", parts[0])); 0455 return QString(); 0456 }, 0457 false, 0458 std::nullopt, 0459 kli18n("<user id> [<reason>]"), 0460 kli18n("Bans the given user"), 0461 }, 0462 Action{ 0463 QStringLiteral("unban"), 0464 [](const QString &text, NeoChatRoom *room) { 0465 static const QRegularExpression mxidRegex( 0466 QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))")); 0467 auto regexMatch = mxidRegex.match(text); 0468 if (!regexMatch.hasMatch()) { 0469 Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", text)); 0470 return QString(); 0471 } 0472 auto plEvent = room->currentState().get<RoomPowerLevelsEvent>(); 0473 if (!plEvent) { 0474 return QString(); 0475 } 0476 if (plEvent->ban() > plEvent->powerLevelForUser(room->localUser()->id())) { 0477 Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to unban users from this room.")); 0478 return QString(); 0479 } 0480 auto state = room->currentState().get<RoomMemberEvent>(text); 0481 if (state && state->membership() != Membership::Ban) { 0482 Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is not banned from this room.", "%1 is not banned from this room.", text)); 0483 return QString(); 0484 } 0485 room->unban(text); 0486 Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> was unbanned from this room.", "%1 was unbanned from this room.", text)); 0487 0488 return QString(); 0489 }, 0490 false, 0491 std::nullopt, 0492 kli18n("<user id>"), 0493 kli18n("Removes the ban of the given user"), 0494 }, 0495 Action{ 0496 QStringLiteral("kick"), 0497 [](const QString &text, NeoChatRoom *room) { 0498 auto parts = text.split(QLatin1String(" ")); 0499 static const QRegularExpression mxidRegex( 0500 QStringLiteral(R"((^|[][[:space:](){}`'";])([!#@][-a-z0-9_=#/.]{1,252}:\w(?:\w|\.|-)*\.\w+(?::\d{1,5})?))")); 0501 auto regexMatch = mxidRegex.match(parts[0]); 0502 if (!regexMatch.hasMatch()) { 0503 Q_EMIT room->showMessage(NeoChatRoom::Error, 0504 i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", parts[0])); 0505 return QString(); 0506 } 0507 if (parts[0] == room->localUser()->id()) { 0508 Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You cannot kick yourself from the room.")); 0509 return QString(); 0510 } 0511 if (!room->isMember(parts[0])) { 0512 Q_EMIT room->showMessage(NeoChatRoom::Error, i18nc("<username> is not in this room", "%1 is not in this room.", parts[0])); 0513 return QString(); 0514 } 0515 auto plEvent = room->currentState().get<RoomPowerLevelsEvent>(); 0516 if (!plEvent) { 0517 return QString(); 0518 } 0519 auto kick = plEvent->kick(); 0520 if (plEvent->powerLevelForUser(room->localUser()->id()) < kick) { 0521 Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to kick users from this room.")); 0522 return QString(); 0523 } 0524 if (plEvent->powerLevelForUser(room->localUser()->id()) <= plEvent->powerLevelForUser(parts[0])) { 0525 Q_EMIT room->showMessage( 0526 NeoChatRoom::Error, 0527 i18nc("You are not allowed to kick <username> from this room", "You are not allowed to kick %1 from this room.", parts[0])); 0528 return QString(); 0529 } 0530 room->kickMember(parts[0], parts.size() > 1 ? parts.mid(1).join(" ") : QString()); 0531 Q_EMIT room->showMessage(NeoChatRoom::Positive, i18nc("<username> was kicked from this room.", "%1 was kicked from this room.", parts[0])); 0532 return QString(); 0533 }, 0534 false, 0535 std::nullopt, 0536 kli18n("<user id> [<reason>]"), 0537 kli18n("Removes the user from the room"), 0538 }, 0539 }; 0540 0541 int ActionsModel::rowCount(const QModelIndex &parent) const 0542 { 0543 Q_UNUSED(parent); 0544 return actions.size(); 0545 } 0546 0547 QVariant ActionsModel::data(const QModelIndex &index, int role) const 0548 { 0549 if (index.row() < 0 || index.row() >= actions.size()) { 0550 return {}; 0551 } 0552 if (role == Prefix) { 0553 return actions[index.row()].prefix; 0554 } 0555 if (role == Description) { 0556 return actions[index.row()].description.toString(); 0557 } 0558 if (role == CompletionType) { 0559 return QStringLiteral("action"); 0560 } 0561 if (role == Parameters) { 0562 return actions[index.row()].parameters.toString(); 0563 } 0564 return {}; 0565 } 0566 0567 QHash<int, QByteArray> ActionsModel::roleNames() const 0568 { 0569 return { 0570 {Prefix, "prefix"}, 0571 {Description, "description"}, 0572 {CompletionType, "completionType"}, 0573 }; 0574 } 0575 0576 QVector<Action> &ActionsModel::allActions() const 0577 { 0578 return actions; 0579 }