diff options
author | dec05eba <dec05eba@protonmail.com> | 2021-07-26 17:35:52 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2021-07-26 17:35:52 +0200 |
commit | a6bba48faa091932b5a51a3beb8c9d162c377adf (patch) | |
tree | 9b7e2de493e04e8eaf291f981f70d273b2dd7baf /src | |
parent | 9775a6bb77930a6e3b60445675990a8c01777aea (diff) |
Matrix: add /join and /invite commands
Diffstat (limited to 'src')
-rw-r--r-- | src/Body.cpp | 2 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 40 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 178 |
3 files changed, 193 insertions, 27 deletions
diff --git a/src/Body.cpp b/src/Body.cpp index 6c2cf9e..693086e 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -1551,7 +1551,7 @@ namespace QuickMedia { item_height += (get_item_height(item->embedded_item.get(), embedded_item_width, load_texture, false) + 6.0f + body_spacing[body_theme].embedded_item_padding_y * 2.0f); else item_height += ((body_spacing[body_theme].embedded_item_font_size + 5.0f) + 6.0f + body_spacing[body_theme].embedded_item_padding_y * 2.0f); - has_loaded_text = true; + has_loaded_text = true; // TODO: Remove this } if(item->description_text) { item_height += item->description_text->getHeight() - 2.0f; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 07d6640..f8566fa 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -5045,6 +5045,29 @@ namespace QuickMedia { chat_input.set_editable(false); chat_state = ChatState::NAVIGATING; return true; + } else if(strncmp(text.c_str(), "/join ", 6) == 0) { + text.erase(text.begin(), text.begin() + 6); + text = strip(text); + if(text.empty()) { + return false; + } else { + TaskResult task_result = run_task_with_loading_screen([this, text{std::move(text)}] { + return matrix->join_room(text) == PluginResult::OK; + }); + + if(task_result == TaskResult::TRUE) { + chat_input.set_editable(false); + chat_state = ChatState::NAVIGATING; + return true; + } else { + return false; + } + } + } else if(text == "/invite") { + new_page = PageType::CHAT_INVITE; + chat_input.set_editable(false); + chat_state = ChatState::NAVIGATING; + return true; } else if(text == "/logout") { new_page = PageType::CHAT_LOGIN; chat_input.set_editable(false); @@ -5067,7 +5090,7 @@ namespace QuickMedia { msgtype = "m.reaction"; text.erase(text.begin(), text.begin() + 7); } else { - show_notification("QuickMedia", "Error: invalid command: " + text + ", expected /upload, /logout, /me or /react", Urgency::NORMAL); + show_notification("QuickMedia", "Error: invalid command: " + text + ", expected /upload, /join [room], /invite, /logout, /me [text] or /react [text]", Urgency::NORMAL); return false; } } else if(chat_state == ChatState::REPLYING && text[0] == '/') { @@ -5968,6 +5991,21 @@ namespace QuickMedia { exit(exit_code); break; } + case PageType::CHAT_INVITE: { + new_page = PageType::CHAT; + + for(ChatTab &tab : tabs) { + tab.body->clear_cache(); + } + + std::vector<Tab> new_tabs; + new_tabs.push_back(Tab{create_body(), std::make_unique<MatrixInviteUserPage>(this, matrix, current_room->id), create_search_bar("Search...", 350)}); + page_loop(new_tabs); + + redraw = true; + avatar_applied = false; + break; + } default: break; } diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 4d00949..b0ff9b8 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -1128,6 +1128,17 @@ namespace QuickMedia { } } + SearchResult MatrixInviteUserPage::search(const std::string &str, BodyItems &result_items) { + return plugin_result_to_search_result(matrix->search_user(str, 20, result_items)); + } + + PluginResult MatrixInviteUserPage::submit(const std::string&, const std::string &url, std::vector<Tab>&) { + PluginResult result = matrix->invite_user(room_id, url); + if(result != PluginResult::OK) return result; + program->set_go_to_previous_page(); + return PluginResult::OK; + } + static std::array<const char*, 7> sync_fail_error_codes = { "M_FORBIDDEN", "M_UNKNOWN_TOKEN", @@ -3850,7 +3861,7 @@ namespace QuickMedia { return download_result_to_plugin_result(download_result); } - PluginResult Matrix::join_room(const std::string &room_id) { + PluginResult Matrix::join_room(const std::string &room_id_or_name) { assert(delegate); std::vector<CommandArg> additional_args = { { "-X", "POST" }, @@ -3859,34 +3870,50 @@ namespace QuickMedia { { "-H", "Authorization: Bearer " + access_token } }; - std::string server_response; - DownloadResult download_result = download_to_string(homeserver + "/_matrix/client/r0/join/" + url_param_encode(room_id), server_response, std::move(additional_args), true); - if(download_result == DownloadResult::OK) { - std::lock_guard<std::mutex> invite_lock(invite_mutex); - auto invite_it = invites.find(room_id); - if(invite_it != invites.end()) { - std::lock_guard<std::recursive_mutex> lock(room_data_mutex); - RoomData *room = get_room_by_id(room_id); - if(!room) { - auto new_room = std::make_unique<RoomData>(); - new_room->id = room_id; - new_room->set_name(invite_it->second.room_name); - new_room->set_avatar_url(invite_it->second.room_avatar_url); - room = new_room.get(); - add_room(std::move(new_room)); + rapidjson::Document json_root; + std::string err_msg; + DownloadResult download_result = download_json(json_root, homeserver + "/_matrix/client/r0/join/" + url_param_encode(room_id_or_name), std::move(additional_args), true, &err_msg); + if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result); - ui_thread_tasks.push([this, room]{ delegate->join_room(room); }); - room->acquire_room_lock(); - std::set<std::string> &room_tags = room->get_tags_unsafe(); - if(room_tags.empty()) { - room_tags.insert(OTHERS_ROOM_TAG); - ui_thread_tasks.push([this, room]{ delegate->room_add_tag(room, OTHERS_ROOM_TAG); }); - } - room->release_room_lock(); + if(!json_root.IsObject()) + return PluginResult::ERR; + + const rapidjson::Value &error_json = GetMember(json_root, "error"); + if(error_json.IsString()) { + show_notification("QuickMedia", "Failed to join " + room_id_or_name + ", error: " + std::string(error_json.GetString(), error_json.GetStringLength()), Urgency::CRITICAL); + return PluginResult::ERR; + } + + const rapidjson::Value &room_id_json = GetMember(json_root, "room_id"); + if(!room_id_json.IsString()) + return PluginResult::ERR; + + const std::string room_id(room_id_json.GetString(), room_id_json.GetStringLength()); + + std::lock_guard<std::mutex> invite_lock(invite_mutex); + auto invite_it = invites.find(room_id); + if(invite_it != invites.end()) { + std::lock_guard<std::recursive_mutex> lock(room_data_mutex); + RoomData *room = get_room_by_id(room_id); + if(!room) { + auto new_room = std::make_unique<RoomData>(); + new_room->id = room_id; + new_room->set_name(invite_it->second.room_name); + new_room->set_avatar_url(invite_it->second.room_avatar_url); + room = new_room.get(); + add_room(std::move(new_room)); + + ui_thread_tasks.push([this, room]{ delegate->join_room(room); }); + room->acquire_room_lock(); + std::set<std::string> &room_tags = room->get_tags_unsafe(); + if(room_tags.empty()) { + room_tags.insert(OTHERS_ROOM_TAG); + ui_thread_tasks.push([this, room]{ delegate->room_add_tag(room, OTHERS_ROOM_TAG); }); } + room->release_room_lock(); } } - return download_result_to_plugin_result(download_result); + return PluginResult::OK; } PluginResult Matrix::leave_room(const std::string &room_id) { @@ -4012,6 +4039,107 @@ namespace QuickMedia { return PluginResult::OK; } + PluginResult Matrix::search_user(const std::string &search_term, unsigned int limit, BodyItems &result_items) { + rapidjson::Document request_data(rapidjson::kObjectType); + request_data.AddMember("search_term", rapidjson::StringRef(search_term.c_str()), request_data.GetAllocator()); + request_data.AddMember("limit", limit, request_data.GetAllocator()); + + rapidjson::StringBuffer buffer; + rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); + request_data.Accept(writer); + + std::vector<CommandArg> additional_args = { + { "-X", "POST" }, + { "-H", "content-type: application/json" }, + { "--data-binary", buffer.GetString() }, + { "-H", "Authorization: Bearer " + access_token } + }; + + rapidjson::Document json_root; + std::string err_msg; + DownloadResult download_result = download_json(json_root, homeserver + "/_matrix/client/r0/user_directory/search", std::move(additional_args), true, &err_msg); + if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result); + + if(!json_root.IsObject()) + return PluginResult::ERR; + + const rapidjson::Value &error_json = GetMember(json_root, "error"); + if(error_json.IsString()) { + show_notification("QuickMedia", "Failed to search for " + search_term + ", error: " + std::string(error_json.GetString(), error_json.GetStringLength()), Urgency::CRITICAL); + return PluginResult::ERR; + } + + const rapidjson::Value &results_json = GetMember(json_root, "results"); + if(!results_json.IsArray()) + return PluginResult::OK; + + for(const rapidjson::Value &result_item_json : results_json.GetArray()) { + if(!result_item_json.IsObject()) + continue; + + const rapidjson::Value &user_id_json = GetMember(result_item_json, "user_id"); + const rapidjson::Value &display_name_json = GetMember(result_item_json, "display_name"); + const rapidjson::Value &avatar_url_json = GetMember(result_item_json, "avatar_url"); + if(!user_id_json.IsString()) + continue; + + auto body_item = BodyItem::create(""); + body_item->url.assign(user_id_json.GetString(), user_id_json.GetStringLength()); + body_item->set_description(body_item->url); + body_item->set_description_color(get_current_theme().faded_text_color); + if(display_name_json.IsString()) + body_item->set_author(std::string(display_name_json.GetString(), display_name_json.GetStringLength())); + else + body_item->set_author(std::string(user_id_json.GetString(), user_id_json.GetStringLength())); + body_item->set_author_color(user_id_to_color(body_item->url)); + + if(avatar_url_json.IsString()) { + std::string avatar_url = thumbnail_url_extract_media_id(std::string(avatar_url_json.GetString(), avatar_url_json.GetStringLength())); + if(!avatar_url.empty()) + avatar_url = get_thumbnail_url(homeserver, avatar_url); + body_item->thumbnail_url = std::move(avatar_url); + } + body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; + body_item->thumbnail_size = sf::Vector2i(32, 32); + + result_items.push_back(std::move(body_item)); + } + + return PluginResult::OK; + } + + PluginResult Matrix::invite_user(const std::string &room_id, const std::string &user_id) { + rapidjson::Document request_data(rapidjson::kObjectType); + request_data.AddMember("user_id", rapidjson::StringRef(user_id.c_str()), request_data.GetAllocator()); + + rapidjson::StringBuffer buffer; + rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); + request_data.Accept(writer); + + std::vector<CommandArg> additional_args = { + { "-X", "POST" }, + { "-H", "content-type: application/json" }, + { "--data-binary", buffer.GetString() }, + { "-H", "Authorization: Bearer " + access_token } + }; + + rapidjson::Document json_root; + std::string err_msg; + DownloadResult download_result = download_json(json_root, homeserver + "/_matrix/client/r0/rooms/" + room_id + "/invite", std::move(additional_args), true, &err_msg); + if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result); + + if(!json_root.IsObject()) + return PluginResult::ERR; + + const rapidjson::Value &error_json = GetMember(json_root, "error"); + if(error_json.IsString()) { + show_notification("QuickMedia", "Failed to invite " + user_id + " to " + room_id + ", error: " + std::string(error_json.GetString(), error_json.GetStringLength()), Urgency::CRITICAL); + return PluginResult::ERR; + } + + return PluginResult::OK; + } + bool Matrix::was_message_posted_by_me(void *message) { Message *message_typed = (Message*)message; return my_user_id == message_typed->user->user_id; |