229 lines
11 KiB
C++
229 lines
11 KiB
C++
#ifndef APP_H
|
|
#define APP_H
|
|
|
|
#include <Wt/WApplication.h>
|
|
#include <Wt/WEnvironment.h>
|
|
#include "broadcast.h"
|
|
#include "curl/curl.h"
|
|
#include <libxml2/libxml/tree.h>
|
|
#include <libxml2/libxml/xpath.h>
|
|
#include <unordered_set>
|
|
|
|
namespace Magick {
|
|
class Image;
|
|
class Blob;
|
|
}
|
|
|
|
class App : public Wt::WApplication, public Client {
|
|
public:
|
|
App(const Wt::WEnvironment& env, Broadcast& server);
|
|
~App();
|
|
|
|
private:
|
|
const std::string adminName {"comiciusadmin"};
|
|
const std::string adminPassword {"p3Lv9!7?+Qq"};
|
|
|
|
std::map<Wt::WString, Wt::WString> genders_ {
|
|
{"F", "Female"},
|
|
{"M", "Male"},
|
|
{"P", "Pair"},
|
|
{"TF", "Transgender (M->F)"},
|
|
{"TM", "Transgender (F->M)"}
|
|
};
|
|
std::vector<std::string> notAllowedNickPhrases_ {
|
|
"whore",
|
|
"hitler",
|
|
"nazi",
|
|
"admin"
|
|
};
|
|
struct Smiley {
|
|
std::string code;
|
|
std::string tooltip;
|
|
Smiley()=default;
|
|
Smiley(std::string code_, std::string tooltip_): code(code_), tooltip(tooltip_) {};
|
|
};
|
|
std::unordered_map<std::string, Smiley> smileys_ {
|
|
{":)", Smiley("1F642", "Smile")},
|
|
{":D", Smiley("1F600", "Laugh")},
|
|
{":(", Smiley("1F641", "Sad")},
|
|
{";)", Smiley("1F609", "Twinkle")},
|
|
{":p", Smiley("1F60B", "Tongue")},
|
|
{";p", Smiley("1F61C", "Twinkle tongue")},
|
|
{"O)", Smiley("1F607", "Angel")},
|
|
{":*", Smiley("1F617", "Kiss")},
|
|
{"(h)", Smiley("1FA77", "Heart")},
|
|
{"xD", Smiley("1F602", "Laughing hard")},
|
|
{":@", Smiley("1F635", "Confused")},
|
|
{":O", Smiley("1F632", "Surprised")},
|
|
{":3", Smiley("1F63A", "Cat face")},
|
|
{":|", Smiley("1F610", "Neutral")},
|
|
{":/", Smiley("1FAE4", "Skeptical")},
|
|
{":#", Smiley("1F912", "Sick")},
|
|
{"#)", Smiley("1F973", "Partied")},
|
|
{"%)", Smiley("1F974", "Drunk")},
|
|
{"(t)", Smiley("1F44D", "Thumbs up")},
|
|
{":'(", Smiley("1F622", "Cry")}
|
|
};
|
|
struct Search {
|
|
Wt::WContainerWidget *outputContainer = nullptr;
|
|
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};";
|
|
const Wt::WEnvironment &env_;
|
|
Broadcast &server_;
|
|
Wt::WContainerWidget *menuContainer_;
|
|
Wt::WContainerWidget *userListContainer_;
|
|
Wt::WContainerWidget *contentContainer_;
|
|
Wt::JSignal<std::string, std::string> updateLocationSignal_;
|
|
std::string responseData_{""};
|
|
Wt::WPushButton *inbox_;
|
|
std::vector<std::string> searchResults_;
|
|
std::string currentConversationWith_{""};
|
|
bool inboxOpen_{false};
|
|
std::shared_ptr<int> messageCursorPosition_;
|
|
std::unique_ptr<Wt::WSound> messageReceived_;
|
|
Search searchFields;
|
|
Wt::WTimer *loginTimer_;
|
|
Wt::WTimer *timeoutRemainingTimer_;
|
|
bool isLoggedInAsAdmin {false};
|
|
void setMetaTags();
|
|
void initLocale();
|
|
Wt::WLocale determineLocaleFromBrowser() const;
|
|
void initApp();
|
|
void reSetUser();
|
|
Wt::WVBoxLayout *createVerticalLayout();
|
|
Wt::WHBoxLayout *createActionLayout(Wt::WVBoxLayout *verticalContainer);
|
|
void createUserListContainer(Wt::WHBoxLayout *layout);
|
|
void createContentContainer(Wt::WHBoxLayout *layout);
|
|
void createHeadContainer(Wt::WVBoxLayout *layout);
|
|
void createMenuContainer(Wt::WVBoxLayout *layout);
|
|
void showLogin();
|
|
void incomingBroadcast();
|
|
void startChat();
|
|
void updateLocation();
|
|
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, std::string *output) {
|
|
size_t totalSize = size * nmemb;
|
|
output->append(reinterpret_cast<const char *>(contents), totalSize);
|
|
return totalSize;
|
|
};
|
|
void populateCountryComboBox(Wt::WComboBox *countryWidget);
|
|
void handleLogin(Wt::WLineEdit *userName, Wt::WComboBox *countryWidget, Wt::WSpinBox *ageWidget, Wt::WComboBox *genderWidget);
|
|
void populateGenderComboBox(Wt::WComboBox *genderWidget);
|
|
std::string getGenderShortByGender(std::string gender);
|
|
void updateUserlist(Wt::Json::Array userList, int size);
|
|
std::vector<Wt::Json::Object> sortUserList(Wt::Json::Array unsortedUserList);
|
|
void createMenu();
|
|
void addLeaveButton();
|
|
void logout();
|
|
void addHistoryButton();
|
|
void addIdentifier();
|
|
void addSearchButton();
|
|
void addInboxButton();
|
|
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);
|
|
Wt::WContainerWidget *addSearchItemContainer(Wt::WVBoxLayout *layout, std::string label);
|
|
void openInbox();
|
|
bool isNickAllowed(const std::string &nick);
|
|
bool compareJsonObjects(const Wt::Json::Object &obj1, const Wt::Json::Object &obj2);
|
|
void requestConversation(std::string conversationWith);
|
|
void showConversation(Wt::Json::Object data);
|
|
void sendMessage(Wt::WLineEdit *inputLine);
|
|
void renderConversation(Wt::Json::Object conversation);
|
|
void showUnreadMessages(Wt::Json::Object data);
|
|
void showOpenInbox(Wt::Json::Object data);
|
|
void updateUserinfo(Wt::Json::Object data);
|
|
std::unique_ptr<Wt::WContainerWidget> createSmileysBar(Wt::WLineEdit *inputLine, std::shared_ptr<int> cursorPosition);
|
|
void toggleSmileysBar(Wt::WContainerWidget *smileyBar);
|
|
void systemEvent(Wt::Json::Object broadcast);
|
|
void addStartChatButton(Wt::WGridLayout *contentGrid, Wt::WLineEdit *userName, Wt::WComboBox *country, Wt::WSpinBox *age, Wt::WComboBox *gender);
|
|
Wt::WComboBox *addCountrySelection(Wt::WGridLayout *contentGrid);
|
|
Wt::WSpinBox *addAgeInput(Wt::WGridLayout *contentGrid);
|
|
Wt::WLineEdit *addUsernameInput(Wt::WGridLayout *contentGrid);
|
|
Wt::WComboBox *addGenderSelection(Wt::WGridLayout *contentGrid);
|
|
void createLoginContainer();
|
|
void connectToServer();
|
|
void setUserData(const std::string &nick, Wt::WComboBox *countryWidget, Wt::WSpinBox *ageWidget, Wt::WComboBox *genderWidget);
|
|
void validateAge(Wt::WSpinBox *ageWidget);
|
|
bool isGenderSelected(Wt::WComboBox *genderWidget);
|
|
void validateGender(Wt::WComboBox *genderWidget);
|
|
bool isNameAlreadyInUse(const std::string &nick);
|
|
bool isInvalidName(const std::string &nick);
|
|
void validateName(const std::string &nick);
|
|
std::string extractTrimmedUserName(Wt::WLineEdit *userName);
|
|
Wt::WPushButton *createSendButton(Wt::WHBoxLayout *inputLayout, Wt::WLineEdit *inputLine);
|
|
Wt::WContainerWidget *createSmileyBar(Wt::WContainerWidget *parent, Wt::WLineEdit *inputLine, std::shared_ptr<int> cursorPosition);
|
|
Wt::WContainerWidget *createSmileyButton(Wt::WHBoxLayout *inputLayout, Wt::WLineEdit *inputLine, std::shared_ptr<int> cursorPosition);
|
|
Wt::WImage *createSendImageButton(Wt::WHBoxLayout *inputLayout);
|
|
Wt::WLineEdit *createInputLine(Wt::WHBoxLayout *inputLayout);
|
|
Wt::WContainerWidget *createInputContainer(Wt::WVBoxLayout *layout);
|
|
std::unique_ptr<Wt::WText> createInfoText(Wt::Json::Object userData);
|
|
Wt::WContainerWidget *createInfoWidget(Wt::WVBoxLayout *layout, Wt::Json::Object userData);
|
|
void setupConversationUI(Wt::Json::Object userData);
|
|
bool shouldShowConversation(Wt::Json::Object userData);
|
|
Wt::Json::Object extractUserData(Wt::Json::Object data);
|
|
std::unique_ptr<Wt::WPushButton> createBlockButton(Wt::Json::Object userData);
|
|
std::string replaceSmileys(std::string outputText);
|
|
void renderChatLine(Wt::Json::Object &line, Wt::Json::Object conversation, Wt::WContainerWidget *outputContainer);
|
|
std::string getChatLineWriter(Wt::Json::Object &line, Wt::Json::Object conversation);
|
|
void renderChatLines(Wt::Json::Object conversation, Wt::WContainerWidget *outputContainer);
|
|
void updateOutputContainer(Wt::Json::Object conversation);
|
|
void handleException(const std::exception &e);
|
|
void processXmlNode(xmlNodePtr node);
|
|
void parseXmlDocument(xmlDocPtr doc);
|
|
void processCurlResponse();
|
|
void performCurlRequest(CURL *curl);
|
|
void setCurlOptions(CURL *curl, const std::string &apiUrl);
|
|
std::string buildApiUrl(const std::string &userIP);
|
|
std::string getUserIP();
|
|
Wt::WWebWidget *createImageElement(Wt::Json::Object &line, const std::string &writer, Wt::WContainerWidget *outputContainer, std::string id);
|
|
Wt::WWebWidget *createTextElement(const std::string &writer, const std::string &text, Wt::WContainerWidget *outputContainer, std::string id);
|
|
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::WContainerWidget *countryOpenList, Wt::WContainerWidget *gendersOpenList);
|
|
Wt::WLineEdit *setupNameSearchField(Wt::WVBoxLayout *contentLayout);
|
|
std::pair<Wt::WContainerWidget *, Wt::WContainerWidget *> setupGendersDropDown(Wt::WVBoxLayout *contentLayout);
|
|
std::pair<Wt::WContainerWidget *, 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::WContainerWidget *openButton, std::unordered_set<std::string> *saveItems);
|
|
void addItem(const std::string &country, Wt::WContainerWidget *dropDownContainer, Wt::WContainerWidget *container, 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);
|
|
void extendSearchResultIfNeeded(Wt::Json::Object broadcast);
|
|
void removeUserFromSearch(Wt::Json::Object broadcast);
|
|
void requestHistory();
|
|
void showHistory(Wt::Json::Object broadcast);
|
|
void connectionTimedOut();
|
|
void addLoginTimeView();
|
|
void addTimeoutView();
|
|
void showPartnerSites();
|
|
void sendImage();
|
|
void imageUploaded(Wt::WFileUpload *fileWidget, std::shared_ptr<Magick::Blob> localImage, Wt::WImage *image, Wt::WPushButton *okButton);
|
|
std::list<Magick::Image> resizeImages(std::list<Magick::Image>& images, int maxWidth, int maxHeight);
|
|
bool isAnimatedGIF(const Magick::Blob &blob);
|
|
void showStandardPage();
|
|
void onInternalPathChanged(const std::string &path);
|
|
void showAdminPage(std::string page);
|
|
void showAdminLogin(std::string page);
|
|
void showPageNotExists();
|
|
void showAdminLogins();
|
|
void showAdminStarts();
|
|
};
|
|
|
|
#endif // APP_H
|