Search added, but change window and back lets app crash

This commit is contained in:
Torsten Schulz
2024-01-28 13:43:36 +01:00
parent ffd01194da
commit c9bffa64cd
6 changed files with 381 additions and 17 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,2 @@
.git/* .git/*
CMakeLists.txt.*
build/* build/*

View File

@@ -114,3 +114,35 @@ height: 31px;
.Wt-dialog > div > div > div > h4 { .Wt-dialog > div > div > div > h4 {
margin: 0; margin: 0;
} }
.handle {
top: calc(50% - 0.55rem) !important;
margin-left: 2px;
width: 1rem !important;
height: 1rem !important;
background-color: black;
border: 0;
border-radius: 1rem;
&:focus {
box-shadow: 0 0 0 1px #fff, 0 0 0 .25rem rgba(red($primary), green($primary), blue($primary), .25);
}
}
.search-line {
overflow: visible !important;
}
.popup-style {
position: relative;
}
.countries-drop-down {
overflow: auto;
background: RGBA(248, 248, 248, 0.8);
position: absolute;
max-height: 10em;
display: inline-block;
top: 100%;
left: 58px;
z-index: 20;
border: 1px solid #666;
box-shadow: 2px 2px 4px #666;
padding: 2px;
}

View File

@@ -33,6 +33,9 @@
#include <Wt/WFileUpload.h> #include <Wt/WFileUpload.h>
#include <Wt/Utils.h> #include <Wt/Utils.h>
#include <Wt/WSound.h> #include <Wt/WSound.h>
#include <Wt/WSlider.h>
#include <Wt/WGridLayout.h>
#include <Wt/WCheckBox.h>
App::App(const Wt::WEnvironment &env, Broadcast &server): App::App(const Wt::WEnvironment &env, Broadcast &server):
Wt::WApplication(env), Wt::WApplication(env),
@@ -50,8 +53,10 @@ App::App(const Wt::WEnvironment &env, Broadcast &server):
createUserListContainer(horizontalContainer); createUserListContainer(horizontalContainer);
createContentContainer(horizontalContainer); createContentContainer(horizontalContainer);
createImprintContainer(verticalContainer); createImprintContainer(verticalContainer);
reSetUser();
if (userName == "") { if (userName == "") {
showLogin(); showLogin();
Wt::WMessageBox::show("Cookie information", "By technical reasons we set a cookie. This cookie isn't tracking anything or will be saved in a database.", Wt::StandardButton::Ok);
} else { } else {
startChat(); startChat();
} }
@@ -68,6 +73,20 @@ void App::initApp() {
useStyleSheet("style.css"); useStyleSheet("style.css");
} }
void App::reSetUser() {
if (env_.cookies().contains("wtd")) {
auto userData = server_.reSetUser(env_.cookies().find("wtd")->second, sessionId());
Wt::Json::Object emptyObject = {};
if (userData != emptyObject) {
userName = (std::string)userData["username"];
gender = (std::string)userData["gender"];
country = (std::string)userData["country"];
isoCountryCode = (std::string)userData["iso-country-code"];
age = (int)userData["age"];
}
}
}
Wt::WVBoxLayout *App::createVerticalLayout() { Wt::WVBoxLayout *App::createVerticalLayout() {
auto verticalBox = root()->addNew<Wt::WContainerWidget>(); auto verticalBox = root()->addNew<Wt::WContainerWidget>();
verticalBox->setHeight(Wt::WLength(100, Wt::LengthUnit::Percentage)); verticalBox->setHeight(Wt::WLength(100, Wt::LengthUnit::Percentage));
@@ -177,6 +196,7 @@ void App::handleLogin(Wt::WLineEdit* userName, Wt::WComboBox* countryWidget, Wt:
setUserData(nick, countryWidget, ageWidget, genderWidget); setUserData(nick, countryWidget, ageWidget, genderWidget);
connectToServer(); connectToServer();
startChat(); startChat();
setCookie("wtd", sessionId(), 21000);
} catch (const std::exception& e) { } catch (const std::exception& e) {
Wt::WMessageBox::show("Attention", e.what(), Wt::StandardButton::Ok); Wt::WMessageBox::show("Attention", e.what(), Wt::StandardButton::Ok);
} }
@@ -243,7 +263,7 @@ void App::populateGenderComboBox(Wt::WComboBox *genderWidget) {
std::string App::getGenderShortByGender(std::string gender) { std::string App::getGenderShortByGender(std::string gender) {
for (const auto &genderItem: genders_) { for (const auto &genderItem: genders_) {
if (gender == genderItem.second) { if (gender == genderItem.second) {
return genderItem.first; return genderItem.first.toUTF8();
} }
} }
return ""; return "";
@@ -258,15 +278,7 @@ void App::updateUserlist(Wt::Json::Array unsortedUserList) {
userListContainer_->setOverflow(Wt::Overflow::Auto); userListContainer_->setOverflow(Wt::Overflow::Auto);
auto sortedUserList = sortUserList(unsortedUserList); auto sortedUserList = sortUserList(unsortedUserList);
for (Wt::Json::Object &user: sortedUserList) { for (Wt::Json::Object &user: sortedUserList) {
auto userName = (std::string)user["name"]; addUserItemToLayout(layout, user);
auto userItem = layout->addNew<Wt::WText>(Wt::WString("{1} ({2})").arg(userName).arg((int)user["age"]));
userItem->setStyleClass(Wt::WString("userlist-item userlist-gender-{1}").arg((std::string)user["gender"]));
userItem->setHeight(Wt::WLength(2, Wt::LengthUnit::FontEm));
userItem->setPadding(Wt::WLength(3, Wt::LengthUnit::Pixel));
userItem->clicked().connect([=, this]() {
requestConversation(userName);
});
Wt::WCssDecorationStyle style;
} }
layout->addWidget(std::make_unique<Wt::WText>(), 1)->setStyleClass("height-spacer userlist"); layout->addWidget(std::make_unique<Wt::WText>(), 1)->setStyleClass("height-spacer userlist");
triggerUpdate(); triggerUpdate();
@@ -768,7 +780,7 @@ void App::addIdentifier() {
void App::addSearchButton() { void App::addSearchButton() {
auto searchButton = menuContainer_->addNew<Wt::WPushButton>("Search"); auto searchButton = menuContainer_->addNew<Wt::WPushButton>("Search");
searchButton->clicked().connect(this, &App::executeSearch); searchButton->clicked().connect(this, &App::showSearchWindow);
} }
void App::addInboxButton() { void App::addInboxButton() {
@@ -776,11 +788,203 @@ void App::addInboxButton() {
inbox_->clicked().connect(this, &App::openInbox); inbox_->clicked().connect(this, &App::openInbox);
} }
void App::executeSearch() { void App::showSearchWindow() {
auto contentLayout = resetSearchFields();
auto userNameField = setupNameSearchField(contentLayout);
auto ageSearchFields = setupSearchFields(contentLayout);
auto countryFields = setupCountryDropDown(contentLayout);
auto gendersFields = setupGendersDropDown(contentLayout);
auto searchResultContainer = setupSearchButton(contentLayout);
restoreSearchFields(searchResultContainer, userNameField, ageSearchFields.first, ageSearchFields.second,
countryFields.second, gendersFields.second, countryFields.first, gendersFields.first);
}
Wt::WVBoxLayout *App::resetSearchFields() {
currentConversationWith_ = ""; currentConversationWith_ = "";
contentContainer_->clear(); contentContainer_->clear();
contentContainer_->addNew<Wt::WText>("search");
inboxOpen_ = false; inboxOpen_ = false;
auto contentLayout = contentContainer_->setLayout(std::make_unique<Wt::WVBoxLayout>());
contentLayout->addNew<Wt::WText>("<h2>Search</h2>");
return contentLayout;
}
std::pair<Wt::WSpinBox*, Wt::WSpinBox*> App::setupSearchFields(Wt::WVBoxLayout *contentLayout) {
auto minAgeEdit = addSearchItemLine<Wt::WSpinBox>(contentLayout, "From age");
minAgeEdit->setRange(18, 150);
minAgeEdit->setValue(18);
minAgeEdit->changed().connect([=, this] { searchFields.minAge = minAgeEdit->value(); });
auto maxAgeEdit = addSearchItemLine<Wt::WSpinBox>(contentLayout, "To age");
maxAgeEdit->setRange(18, 150);
maxAgeEdit->setValue(150);
maxAgeEdit->changed().connect([=, this] { searchFields.maxAge = maxAgeEdit->value(); });
return {minAgeEdit, maxAgeEdit};
}
std::pair<Wt::WPushButton*, Wt::WContainerWidget*> App::setupCountryDropDown(Wt::WVBoxLayout *contentLayout) {
auto countryDropDown = std::make_unique<Wt::WContainerWidget>();
countryDropDown->setInline(true);
countryDropDown->setStyleClass("countries-drop-down");
auto countryDropDownContainer = countryDropDown.get();
auto countryOpenList = addSearchItemLine<Wt::WPushButton>(contentLayout, "Country", std::move(countryDropDown));
countryDropDownContainer->hide();
countryOpenList->clicked().connect([=]() { if (countryDropDownContainer->isHidden()) { countryDropDownContainer->show();} else { countryDropDownContainer->hide(); } });
countryOpenList->setText("All");
std::map<Wt::WString, Wt::WString> countries = server_.countries();
addItem("All", countryDropDownContainer, countryOpenList, &searchFields.countries, true);
addItem(country, countryDropDownContainer, countryOpenList, &searchFields.countries);
for (const auto &itemCountry: countries) {
if (itemCountry.first.toUTF8() != country) {
addItem(itemCountry.first.toUTF8(), countryDropDownContainer, countryOpenList, &searchFields.countries);
}
}
return {countryOpenList, countryDropDownContainer};
}
std::pair<Wt::WPushButton*, Wt::WContainerWidget*> App::setupGendersDropDown(Wt::WVBoxLayout *contentLayout) {
auto gendersDropDown = std::make_unique<Wt::WContainerWidget>();
gendersDropDown->setInline(true);
gendersDropDown->setStyleClass("countries-drop-down");
auto gendersDropDownContainer = gendersDropDown.get();
auto gendersOpenList = addSearchItemLine<Wt::WPushButton>(contentLayout, "Genders", std::move(gendersDropDown));
gendersDropDownContainer->hide();
gendersOpenList->clicked().connect([=]() { if (gendersDropDownContainer->isHidden()) { gendersDropDownContainer->show();} else { gendersDropDownContainer->hide(); } });
gendersOpenList->setText("All");
addItem("All", gendersDropDownContainer, gendersOpenList, &searchFields.gender, true);
std::map<Wt::WString, Wt::WString> swappedGenders;
for (const auto& pair : genders_) {
swappedGenders[pair.second] = pair.first;
}
for (const auto &itemGender: swappedGenders) {
addItem(itemGender.first.toUTF8(), gendersDropDownContainer, gendersOpenList, &searchFields.gender);
}
return {gendersOpenList, gendersDropDownContainer};
}
void App::addItem(const std::string& country, Wt::WContainerWidget *dropDownContainer, Wt::WPushButton *openListButton, std::unordered_set<std::string> *saveItems, bool isSelected) {
auto menuItem = dropDownContainer->addNew<Wt::WCheckBox>(country);
menuItem->changed().connect([=, this]() mutable { itemChanged(menuItem, dropDownContainer, openListButton, saveItems); });
menuItem->setInline(false);
if (isSelected) {
menuItem->setChecked();
}
}
void App::addUserItemToLayout(Wt::WVBoxLayout *layout, Wt::Json::Object userObject) {
auto userName = (std::string)userObject["name"];
auto userItem = layout->addNew<Wt::WText>(Wt::WString("{1} ({2})").arg(userName).arg((int)userObject["age"]));
userItem->setStyleClass(Wt::WString("userlist-item userlist-gender-{1}").arg((std::string)userObject["gender"]));
userItem->setHeight(Wt::WLength(2, Wt::LengthUnit::FontEm));
userItem->setPadding(Wt::WLength(3, Wt::LengthUnit::Pixel));
userItem->clicked().connect([=, this]() {
requestConversation(userName);
});
}
std::unordered_set<std::string> App::gendersListToShortGendersList(std::unordered_set<std::string> gendersList) {
std::unordered_set<std::string> result;
for (const auto &gender: gendersList) {
result.insert(genderShortOfGender(gender));
}
return result;
}
std::string App::genderShortOfGender(const std::string incomingGender) {
for (const auto &genderItem: genders_) {
if (incomingGender == genderItem.second) {
return genderItem.first.toUTF8();
}
}
return incomingGender;
}
void App::itemChanged(Wt::WCheckBox *item, Wt::WContainerWidget *dropDownContainer, Wt::WPushButton *openButton, std::unordered_set<std::string> *saveItems) {
saveItems->clear();
bool unselect = (item->text() == "All" && item->isChecked());
for (auto &widgetItem: dropDownContainer->children()) {
auto widgetCheckBox = static_cast<Wt::WCheckBox*>(widgetItem);
if (unselect && widgetCheckBox->text() != "All" && widgetCheckBox->isChecked()) {
widgetCheckBox->setChecked(false);
}
if (widgetCheckBox->isChecked()) {
saveItems->insert(widgetCheckBox->text().toUTF8());
}
}
if (saveItems->size() > 1 && saveItems->find("All") != saveItems->end()) {
saveItems->erase(saveItems->find("All"));
static_cast<Wt::WCheckBox*>(dropDownContainer->children().at(0))->setChecked(false);
}
if (saveItems->empty()) {
saveItems->insert("All");
}
std::string result;
for (const auto &selected: *saveItems) {
result += (result.empty() ? "" : ", ") + selected;
}
openButton->setText(result);
}
void App::restoreSearchFields(Wt::WContainerWidget *searchResultContainer, Wt::WLineEdit *userNameEdit, Wt::WSpinBox *minAgeEdit,
Wt::WSpinBox *maxAgeEdit, Wt::WContainerWidget *countryDropDownContainer, Wt::WContainerWidget *gendersDropDownContainer,
Wt::WPushButton *countryOpenList, Wt::WPushButton *gendersOpenList) {
if (!searchFields.set) {
searchFields = Search(searchResultContainer);
} else {
userNameEdit->setValueText(searchFields.userName);
minAgeEdit->setValue(searchFields.minAge);
maxAgeEdit->setValue(searchFields.maxAge);
for (auto countryWidget: countryDropDownContainer->children()) {
auto countryCheckBox = (Wt::WCheckBox*)countryWidget;
countryCheckBox->setChecked(searchFields.countries.find(countryCheckBox->text().toUTF8()) != searchFields.countries.end());
}
itemChanged((Wt::WCheckBox*)*countryDropDownContainer->children().begin(), countryDropDownContainer, countryOpenList, &searchFields.countries);
for (auto genderWidget: gendersDropDownContainer->children()) {
auto genderCheckBox = (Wt::WCheckBox*)genderWidget;
genderCheckBox->setChecked(searchFields.gender.find(genderCheckBox->text().toUTF8()) != searchFields.gender.end());
}
itemChanged((Wt::WCheckBox*)*gendersDropDownContainer->children().begin(), gendersDropDownContainer, gendersOpenList, &searchFields.gender);
startSearch();
}
}
Wt::WLineEdit *App::setupNameSearchField(Wt::WVBoxLayout *contentLayout) {
auto userNameEdit = addSearchItemLine<Wt::WLineEdit>(contentLayout, "Username includes");
userNameEdit->changed().connect([=, this] { searchFields.userName = userNameEdit->text().trim(); });
return userNameEdit;
}
Wt::WContainerWidget *App::setupSearchButton(Wt::WVBoxLayout *contentLayout) {
auto searchButton = addSearchItemLine<Wt::WPushButton>(contentLayout, "");
searchButton->setText("Search");
auto searchResultContainer = contentLayout->addWidget(std::make_unique<Wt::WContainerWidget>(), 1);
searchResultContainer->addNew<Wt::WText>("No results");
searchButton->clicked().connect(this, &App::startSearch);
return searchResultContainer;
}
void App::startSearch() {
if (searchFields.minAge > searchFields.maxAge) {
searchFields.outputContainer->clear();
searchFields.outputContainer->addNew<Wt::WText>("Minimum age must be at least as large as or greater than the maximum age.");
return;
}
server_.userSearch(sessionId(), searchFields.userName.toUTF8(), searchFields.minAge, searchFields.maxAge,
searchFields.countries, gendersListToShortGendersList(searchFields.gender), userName);
}
void App::showSearch(Wt::Json::Object broadcast) {
searchFields.outputContainer->clear();
auto searchResult = (Wt::Json::Array)broadcast["data"];
if (searchResult.size() == 0) {
searchFields.outputContainer->addNew<Wt::WText>("No results.");
}
auto searchListContainer = searchFields.outputContainer->addNew<Wt::WContainerWidget>();
auto searchList = searchListContainer->setLayout(std::make_unique<Wt::WVBoxLayout>());
searchListContainer->setOverflow(Wt::Overflow::Auto);
for (const Wt::Json::Object &searchItem: searchResult) {
addUserItemToLayout(searchList, searchItem);
}
triggerUpdate();
} }
void App::openInbox() { void App::openInbox() {
@@ -810,6 +1014,8 @@ void App::incomingBroadcast() {
showSystemMessage(broadcast); showSystemMessage(broadcast);
} else if (broadcast["type"] == "conversation-start") { } else if (broadcast["type"] == "conversation-start") {
showConversation(broadcast); showConversation(broadcast);
} else if (broadcast["type"] == "search-result") {
showSearch(broadcast);
} }
} }
} }
@@ -912,3 +1118,24 @@ bool App::isNickAllowed(const std::string& nick) {
return lowercaseNick.find(lowercasePhrase) == std::string::npos; return lowercaseNick.find(lowercasePhrase) == std::string::npos;
}); });
} }
template<class Class>
Class *App::addSearchItemLine(Wt::WVBoxLayout *layout, std::string label, std::unique_ptr<Wt::WContainerWidget> additionalItem) {
auto lineContainer = layout->addNew<Wt::WContainerWidget>();
lineContainer->setStyleClass("search-line");
lineContainer->setPositionScheme(Wt::PositionScheme::Relative);
auto lineLayout = lineContainer->setLayout(std::make_unique<Wt::WHBoxLayout>());
lineContainer->setPadding(Wt::WLength("0"));
lineContainer->setMargin(Wt::WLength("0"));
lineLayout->addNew<Wt::WText>(label);
lineLayout->setContentsMargins(0, 0, 0, 0);
lineLayout->setSpacing(0);
auto input = std::make_unique<Class>();
auto returnInput = input.get();
lineLayout->addWidget(std::move(input), 1);
if (additionalItem) {
lineLayout->addWidget(std::move(additionalItem));
lineContainer->setOverflow(Wt::Overflow::Visible);
}
return returnInput;
}

View File

@@ -7,6 +7,7 @@
#include "curl/curl.h" #include "curl/curl.h"
#include <libxml2/libxml/tree.h> #include <libxml2/libxml/tree.h>
#include <libxml2/libxml/xpath.h> #include <libxml2/libxml/xpath.h>
#include <unordered_set>
namespace Magick { namespace Magick {
class Image; class Image;
@@ -18,7 +19,7 @@ public:
~App(); ~App();
private: private:
std::unordered_map<std::string, std::string> genders_ { std::map<Wt::WString, Wt::WString> genders_ {
{"F", "Female"}, {"F", "Female"},
{"M", "Male"}, {"M", "Male"},
{"P", "Pair"}, {"P", "Pair"},
@@ -46,6 +47,22 @@ private:
{";p", Smiley("1F61C", "Twinkle tongue")}, {";p", Smiley("1F61C", "Twinkle tongue")},
{":'(", Smiley("1F622", "Cry")} {":'(", Smiley("1F622", "Cry")}
}; };
struct Search {
Wt::WContainerWidget *outputContainer;
Wt::WString userName{""};
int minAge{18};
int maxAge{150};
std::unordered_set<std::string> gender;
std::unordered_set<std::string> countries;
Search()=default;
Search(Wt::WContainerWidget *outputContainer_):
outputContainer(outputContainer_) {
set = true;
gender.insert("All");
countries.insert("All");
}
bool set = false;
};
Wt::WString smileyPlaceholder_ = "&#x{1};"; Wt::WString smileyPlaceholder_ = "&#x{1};";
const Wt::WEnvironment &env_; const Wt::WEnvironment &env_;
Broadcast &server_; Broadcast &server_;
@@ -60,7 +77,9 @@ private:
bool inboxOpen_{false}; bool inboxOpen_{false};
int messageCursorPosition_{-1}; int messageCursorPosition_{-1};
std::unique_ptr<Wt::WSound> messageReceived_; std::unique_ptr<Wt::WSound> messageReceived_;
Search searchFields;
void initApp(); void initApp();
void reSetUser();
Wt::WVBoxLayout *createVerticalLayout(); Wt::WVBoxLayout *createVerticalLayout();
Wt::WHBoxLayout *createActionLayout(Wt::WVBoxLayout *verticalContainer); Wt::WHBoxLayout *createActionLayout(Wt::WVBoxLayout *verticalContainer);
void createUserListContainer(Wt::WHBoxLayout *layout); void createUserListContainer(Wt::WHBoxLayout *layout);
@@ -88,7 +107,10 @@ private:
void addIdentifier(); void addIdentifier();
void addSearchButton(); void addSearchButton();
void addInboxButton(); void addInboxButton();
void executeSearch(); void showSearchWindow();
void startSearch();
void showSearch(Wt::Json::Object broadcast);
template<class Class> Class *addSearchItemLine(Wt::WVBoxLayout *layout, std::string label, std::unique_ptr<Wt::WContainerWidget> additionalItem = nullptr);
void openInbox(); void openInbox();
bool isNickAllowed(const std::string &nick); bool isNickAllowed(const std::string &nick);
bool compareJsonObjects(const Wt::Json::Object &obj1, const Wt::Json::Object &obj2); bool compareJsonObjects(const Wt::Json::Object &obj1, const Wt::Json::Object &obj2);
@@ -146,6 +168,18 @@ private:
Wt::WWebWidget *createImageElement(Wt::Json::Object &line, const std::string &writer, Wt::WContainerWidget *outputContainer); Wt::WWebWidget *createImageElement(Wt::Json::Object &line, const std::string &writer, Wt::WContainerWidget *outputContainer);
Wt::WWebWidget *createTextElement(const std::string &writer, const std::string &text, Wt::WContainerWidget *outputContainer); Wt::WWebWidget *createTextElement(const std::string &writer, const std::string &text, Wt::WContainerWidget *outputContainer);
void createImprintContainer(Wt::WVBoxLayout *containerLayout); void createImprintContainer(Wt::WVBoxLayout *containerLayout);
Wt::WContainerWidget *setupSearchButton(Wt::WVBoxLayout *contentLayout);
void restoreSearchFields(Wt::WContainerWidget *searchResultContainer, Wt::WLineEdit *userNameEdit, Wt::WSpinBox *minAgeEdit, Wt::WSpinBox *maxAgeEdit, Wt::WContainerWidget *countryDropDownContainer, Wt::WContainerWidget *gendersDropDownContainer, Wt::WPushButton *countryOpenList, Wt::WPushButton *gendersOpenList);
Wt::WLineEdit *setupNameSearchField(Wt::WVBoxLayout *contentLayout);
std::pair<Wt::WPushButton *, Wt::WContainerWidget *> setupGendersDropDown(Wt::WVBoxLayout *contentLayout);
std::pair<Wt::WPushButton *, Wt::WContainerWidget *> setupCountryDropDown(Wt::WVBoxLayout *contentLayout);
std::pair<Wt::WSpinBox*, Wt::WSpinBox*> setupSearchFields(Wt::WVBoxLayout *contentLayout);
Wt::WVBoxLayout *resetSearchFields();
void itemChanged(Wt::WCheckBox *item, Wt::WContainerWidget *dropDownContainer, Wt::WPushButton *openButton, std::unordered_set<std::string> *saveItems);
void addItem(const std::string &country, Wt::WContainerWidget *dropDownContainer, Wt::WPushButton *openListButton, std::unordered_set<std::string> *saveItems, bool isSelected = false);
void addUserItemToLayout(Wt::WVBoxLayout *layout, Wt::Json::Object userObject);
std::unordered_set<std::string> gendersListToShortGendersList(std::unordered_set<std::string> gendersList);
std::string genderShortOfGender(const std::string incomingGender);
}; };
#endif // APP_H #endif // APP_H

View File

@@ -23,7 +23,6 @@ Broadcast::~Broadcast() {
} }
void Broadcast::connect(Client *client, const std::function<void ()> &fct) { void Broadcast::connect(Client *client, const std::function<void ()> &fct) {
std::unique_lock<std::mutex> lock(mutex_);
connections_.push_back(std::make_unique<Connection>(Wt::WApplication::instance()->sessionId(), client, fct)); connections_.push_back(std::make_unique<Connection>(Wt::WApplication::instance()->sessionId(), client, fct));
auto broadcast = createUserList(); auto broadcast = createUserList();
for (auto &connection: connections_) { for (auto &connection: connections_) {
@@ -53,6 +52,23 @@ void Broadcast::disconnect(Client *client) {
} }
Wt::Json::Object Broadcast::reSetUser(std::string oldSessionId, std::string newSessionId) {
for (auto& connection : connections_) {
if (connection->setSessionId(oldSessionId, newSessionId)) {
Wt::Json::Object userData {
{"gender", Wt::Json::Value(connection->gender())},
{"country", Wt::Json::Value(connection->country())},
{"iso-country-code", Wt::Json::Value(getCountryIsoCodeByCountry(connection->country()))},
{"username", Wt::Json::Value(connection->userName())},
{"age", Wt::Json::Value(connection->age())},
};
reSetSessionIdInMessages(oldSessionId, newSessionId);
return userData;
}
}
return {};
}
int Broadcast::count() const { int Broadcast::count() const {
std::unique_lock<std::mutex> lock(mutex_); std::unique_lock<std::mutex> lock(mutex_);
return connections_.size(); return connections_.size();
@@ -349,6 +365,28 @@ void Broadcast::requestConversation(std::string sendToSessionId, std::string wit
addMessageToSessionBroadcast(sendToSessionId, broadcast); addMessageToSessionBroadcast(sendToSessionId, broadcast);
} }
void Broadcast::userSearch(std::string toSession, std::string nameIncludes, int minAge, int maxAge, std::unordered_set<std::string> countries, std::unordered_set<std::string> genders, std::string excludeName) {
Wt::Json::Array searchResult;
for (const auto &user: connections_) {
std::cout << user->gender() << std::endl;
if (
(nameIncludes == "" || user->userName().find(nameIncludes) != std::string::npos)
&& (minAge <= user->age())
&& (maxAge >= user->age())
&& (countries.contains("All") || countries.contains(user->country()) || countries.size() == 0)
&& (genders.contains("All") || genders.contains(user->gender()) || genders.size() == 0)
&& (user->userName() != excludeName)
) {
searchResult.push_back(user->client()->json());
}
}
Wt::Json::Object broadcast{
{"type", "search-result"},
{"data", searchResult}
};
addMessageToSessionBroadcast(toSession, broadcast);
}
bool Broadcast::parseCountriesData() { bool Broadcast::parseCountriesData() {
std::istringstream iss(responseData_); std::istringstream iss(responseData_);
std::string line; std::string line;
@@ -366,6 +404,12 @@ bool Broadcast::parseCountriesData() {
return true; return true;
} }
void Broadcast::reSetSessionIdInMessages(std::string oldSessionId, std::string newSessionId) {
for (auto &conversation: conversations_) {
conversation.second.setNewSesionId(oldSessionId, newSessionId);
}
}
Wt::Json::Object Broadcast::createUserList() { Wt::Json::Object Broadcast::createUserList() {
Wt::Json::Array userList; Wt::Json::Array userList;
for (const auto &connection: connections_) { for (const auto &connection: connections_) {
@@ -505,6 +549,14 @@ std::list<Wt::Json::Object> Broadcast::Connection::getBroadcasts(bool clear) {
return broadcastCopy; return broadcastCopy;
} }
bool Broadcast::Connection::setSessionId(std::string searchedSessionId, std::string newSessionId) {
if (searchedSessionId == sessionId_) {
sessionId_ = newSessionId;
return true;
}
return false;
}
std::function<void ()> Broadcast::Connection::fct() { std::function<void ()> Broadcast::Connection::fct() {
return fct_; return fct_;
} }
@@ -557,3 +609,15 @@ Wt::Json::Object Broadcast::Message::json() {
json["image"] = Wt::Json::Value(image); json["image"] = Wt::Json::Value(image);
return json; return json;
} }
void Broadcast::Message::setNewSesionId(std::string oldSessionId, std::string newSessionId) {
if (fromSessionId == oldSessionId) {
fromSessionId = newSessionId;
}
}
void Broadcast::MessageQueue::setNewSesionId(std::string oldSessionId, std::string newSessionId) {
for (auto &message: messages) {
message.setNewSesionId(oldSessionId, newSessionId);
}
}

View File

@@ -7,6 +7,7 @@
#include <map> #include <map>
#include <list> #include <list>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <Wt/WServer.h> #include <Wt/WServer.h>
#include <Wt/WDate.h> #include <Wt/WDate.h>
#include <Wt/Json/Object.h> #include <Wt/Json/Object.h>
@@ -49,16 +50,19 @@ public:
Wt::WString message; Wt::WString message;
Wt::Json::Object image; Wt::Json::Object image;
Wt::Json::Object json(); Wt::Json::Object json();
void setNewSesionId(std::string oldSessionId, std::string newSessionId);
}; };
struct MessageQueue { struct MessageQueue {
bool user1Read{false}; bool user1Read{false};
bool user2Read{false}; bool user2Read{false};
std::vector<Message> messages; std::vector<Message> messages;
void setNewSesionId(std::string oldSessionId, std::string newSessionId);
}; };
Broadcast(Wt::WServer *server); Broadcast(Wt::WServer *server);
~Broadcast(); ~Broadcast();
void connect(Client *client, const std::function<void ()> &fct); void connect(Client *client, const std::function<void ()> &fct);
void disconnect(Client *client); void disconnect(Client *client);
Wt::Json::Object reSetUser(std::string oldSessionId, std::string newSessionId);
int count() const; int count() const;
std::string userNameForSessionId(std::string sessionId); std::string userNameForSessionId(std::string sessionId);
std::string sessionIdForUserName(std::string userName); std::string sessionIdForUserName(std::string userName);
@@ -78,6 +82,8 @@ public:
void sendUserInformation(std::string sendToSessionId, std::string userName, std::string requestingUserName); void sendUserInformation(std::string sendToSessionId, std::string userName, std::string requestingUserName);
void toggleBlockUser(std::string blockingUserName, std::string blockedUser, std::string blockingUserSessionId); void toggleBlockUser(std::string blockingUserName, std::string blockedUser, std::string blockingUserSessionId);
void requestConversation(std::string sendToSessionId, std::string withUserName, std::string requestingUserName); void requestConversation(std::string sendToSessionId, std::string withUserName, std::string requestingUserName);
void userSearch(std::string toSession, std::string nameIncludes, int minAge, int maxAge,
std::unordered_set<std::string> countries, std::unordered_set<std::string> genders, std::string excludeName);
protected: protected:
struct Connection { struct Connection {
Connection(const std::string &id, Client *client, const std::function<void ()> &fct); Connection(const std::string &id, Client *client, const std::function<void ()> &fct);
@@ -93,6 +99,7 @@ protected:
void addBroadcast(Wt::Json::Object broadcast); void addBroadcast(Wt::Json::Object broadcast);
std::list<Wt::Json::Object> getBroadcasts(bool clear = false); std::list<Wt::Json::Object> getBroadcasts(bool clear = false);
std::unordered_map<std::string, std::vector<std::string> > blockings_; std::unordered_map<std::string, std::vector<std::string> > blockings_;
bool setSessionId(std::string searchedSessionId, std::string newSessionId);
private: private:
std::string sessionId_; std::string sessionId_;
Client *client_; Client *client_;
@@ -118,6 +125,7 @@ private:
Wt::Json::Object logoutBroadcast(); Wt::Json::Object logoutBroadcast();
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output); static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output);
bool parseCountriesData(); bool parseCountriesData();
void reSetSessionIdInMessages(std::string oldSessionId, std::string newSessionId);
Wt::Json::Object createUserList(); Wt::Json::Object createUserList();
void sendMessageQueueToSession(std::string receiverSessionId, std::string user1, std::string user2, std::vector<Message> messages); void sendMessageQueueToSession(std::string receiverSessionId, std::string user1, std::string user2, std::vector<Message> messages);
void addMessageToSessionBroadcast(std::string sessionId, Wt::Json::Object message); void addMessageToSessionBroadcast(std::string sessionId, Wt::Json::Object message);