#ifndef APP_H #define APP_H #include #include #include "broadcast.h" #include "curl/curl.h" #include #include #include 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 genders_ { {"F", "Female"}, {"M", "Male"}, {"P", "Pair"}, {"TF", "Transgender (M->F)"}, {"TM", "Transgender (F->M)"} }; std::vector 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 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 gender; std::unordered_set 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 updateLocationSignal_; std::string responseData_{""}; Wt::WPushButton *inbox_; std::vector searchResults_; std::string currentConversationWith_{""}; bool inboxOpen_{false}; std::shared_ptr messageCursorPosition_; std::unique_ptr 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(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 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 *addSearchItemLine(Wt::WVBoxLayout *layout, std::string label, std::unique_ptr 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 createSmileysBar(Wt::WLineEdit *inputLine, std::shared_ptr 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 cursorPosition); Wt::WContainerWidget *createSmileyButton(Wt::WHBoxLayout *inputLayout, Wt::WLineEdit *inputLine, std::shared_ptr cursorPosition); Wt::WImage *createSendImageButton(Wt::WHBoxLayout *inputLayout); Wt::WLineEdit *createInputLine(Wt::WHBoxLayout *inputLayout); Wt::WContainerWidget *createInputContainer(Wt::WVBoxLayout *layout); std::unique_ptr 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 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 setupGendersDropDown(Wt::WVBoxLayout *contentLayout); std::pair setupCountryDropDown(Wt::WVBoxLayout *contentLayout); std::pair setupSearchFields(Wt::WVBoxLayout *contentLayout); Wt::WVBoxLayout *resetSearchFields(); void itemChanged(Wt::WCheckBox *item, Wt::WContainerWidget *dropDownContainer, Wt::WContainerWidget *openButton, std::unordered_set *saveItems); void addItem(const std::string &country, Wt::WContainerWidget *dropDownContainer, Wt::WContainerWidget *container, std::unordered_set *saveItems, bool isSelected = false); void addUserItemToLayout(Wt::WVBoxLayout *layout, Wt::Json::Object userObject); std::unordered_set gendersListToShortGendersList(std::unordered_set 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 localImage, Wt::WImage *image, Wt::WPushButton *okButton); std::list resizeImages(std::list& 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