From 7c44fd17bb6be54a2ea4b60761e91053ca988977 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 29 Nov 2016 16:18:25 -0500 Subject: Made tweets, users, and notifications into copyable objects Notifications are now also mutable. Users and tweets no longer have helper methods for interacting with the client. Fixed a bug (possibly introduced by a change to the Twitter API) that caused non-reply tweets to be marked as unknown notifications. --- src/client.cpp | 36 +++- src/client.h | 10 + src/direct_message.h | 1 + src/list.h | 2 + src/notification.cpp | 518 ++++++++++++++++++++++++++++++++++++++++++--------- src/notification.h | 52 +++++- src/stream.cpp | 2 +- src/stream.h | 2 +- src/tweet.cpp | 65 +++++-- src/tweet.h | 32 ++-- src/user.cpp | 24 +-- src/user.h | 17 +- 12 files changed, 610 insertions(+), 151 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index f8908fd..e16e30b 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -330,7 +330,7 @@ namespace twitter { _oauth_token.get()); _current_user = - make_unique(*this, + make_unique( get(*_oauth_client, "https://api.twitter.com/1.1/account/verify_credentials.json") .perform()); @@ -349,7 +349,7 @@ namespace twitter { datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); } - return tweet(*this, + return tweet( post(*_oauth_client, "https://api.twitter.com/1.1/statuses/update.json", datastrstream.str()) @@ -369,7 +369,7 @@ namespace twitter { datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); } - return tweet(*this, + return tweet( post(*_oauth_client, "https://api.twitter.com/1.1/statuses/update.json", datastrstream.str()) @@ -533,6 +533,16 @@ namespace twitter { return result; } + std::set client::getFriends(const user& id) const + { + return getFriends(id.getID()); + } + + std::set client::getFriends() const + { + return getFriends(getUser().getID()); + } + std::set client::getFollowers(user_id id) const { long long cursor = -1; @@ -567,6 +577,16 @@ namespace twitter { return result; } + std::set client::getFollowers(const user& id) const + { + return getFollowers(id.getID()); + } + + std::set client::getFollowers() const + { + return getFollowers(getUser().getID()); + } + void client::follow(user_id toFollow) const { std::stringstream datastrstream; @@ -576,6 +596,11 @@ namespace twitter { post(*_oauth_client, "https://api.twitter.com/1.1/friendships/create.json", datastrstream.str()).perform(); } + void client::follow(const user& toFollow) const + { + return follow(toFollow.getID()); + } + void client::unfollow(user_id toUnfollow) const { std::stringstream datastrstream; @@ -584,6 +609,11 @@ namespace twitter { post(*_oauth_client, "https://api.twitter.com/1.1/friendships/destroy.json", datastrstream.str()).perform(); } + + void client::unfollow(const user& toUnfollow) const + { + return unfollow(toUnfollow.getID()); + } const user& client::getUser() const { diff --git a/src/client.h b/src/client.h index 37081ff..2230dbb 100644 --- a/src/client.h +++ b/src/client.h @@ -29,10 +29,20 @@ namespace twitter { long uploadMedia(std::string media_type, const char* data, long data_length) const; tweet replyToTweet(std::string msg, tweet_id in_response_to, std::list media_ids = {}) const; + std::set getFriends(user_id id) const; + std::set getFriends(const user& u) const; + std::set getFriends() const; + std::set getFollowers(user_id id) const; + std::set getFollowers(const user& u) const; + std::set getFollowers() const; + void follow(user_id toFollow) const; + void follow(const user& toFollow) const; + void unfollow(user_id toUnfollow) const; + void unfollow(const user& toUnfollow) const; const user& getUser() const; diff --git a/src/direct_message.h b/src/direct_message.h index 12e254c..46a66dc 100644 --- a/src/direct_message.h +++ b/src/direct_message.h @@ -8,6 +8,7 @@ namespace twitter { class direct_message { public: + direct_message() {} explicit direct_message(std::string data); }; diff --git a/src/list.h b/src/list.h index 69085b4..1bf034f 100644 --- a/src/list.h +++ b/src/list.h @@ -8,7 +8,9 @@ namespace twitter { class list { public: + list() {} explicit list(std::string data); + }; }; diff --git a/src/notification.cpp b/src/notification.cpp index 3269a90..0e46112 100644 --- a/src/notification.cpp +++ b/src/notification.cpp @@ -28,16 +28,11 @@ namespace twitter { try { - if (!json["in_reply_to_status_id"].is_null()) - { - _type = type::tweet; - - new(&_tweet) tweet(tclient, data); - } else if (!json["event"].is_null()) + if (!json["event"].is_null()) { std::string event = json["event"]; - user source(tclient, json["source"].dump()); - user target(tclient, json["target"].dump()); + user source(json["source"].dump()); + user target(json["target"].dump()); if (event == "user_update") { @@ -56,7 +51,7 @@ namespace twitter { new(&_user) user(target); } else if (event == "favorite") { - new(&_user_and_tweet._tweet) tweet(tclient, json["target_object"].dump()); + new(&_user_and_tweet._tweet) tweet(json["target_object"].dump()); if (current_user == source) { @@ -70,7 +65,7 @@ namespace twitter { } } else if (event == "unfavorite") { - new(&_user_and_tweet._tweet) tweet(tclient, json["target_object"].dump()); + new(&_user_and_tweet._tweet) tweet(json["target_object"].dump()); if (current_user == source) { @@ -175,7 +170,9 @@ namespace twitter { _type = type::quoted; new(&_user_and_tweet._user) user(source); - new(&_user_and_tweet._tweet) tweet(tclient, json["target_object"].dump()); + new(&_user_and_tweet._tweet) tweet(json["target_object"].dump()); + } else { + _type = type::unknown; } } else if (!json["warning"].is_null()) { @@ -260,7 +257,9 @@ namespace twitter { new(&_direct_message) direct_message(json["direct_message"].dump()); } else { - _type = type::unknown; + _type = type::tweet; + + new(&_tweet) tweet(data); } } catch (const std::domain_error& error) { @@ -268,7 +267,7 @@ namespace twitter { } } - notification::notification(notification&& other) + notification::notification(const notification& other) { _type = other._type; @@ -276,7 +275,7 @@ namespace twitter { { case type::tweet: { - new(&_tweet) tweet(std::move(other._tweet)); + new(&_tweet) tweet(other._tweet); break; } @@ -288,7 +287,7 @@ namespace twitter { case type::followed: case type::unfollow: { - new(&_user) user(std::move(other._user)); + new(&_user) user(other._user); break; } @@ -299,8 +298,8 @@ namespace twitter { case type::unfavorited: case type::quoted: { - new(&_user_and_tweet._user) user(std::move(other._user_and_tweet._user)); - new(&_user_and_tweet._tweet) tweet(std::move(other._user_and_tweet._tweet)); + new(&_user_and_tweet._user) user(other._user_and_tweet._user); + new(&_user_and_tweet._tweet) tweet(other._user_and_tweet._tweet); break; } @@ -309,7 +308,7 @@ namespace twitter { case type::list_destroyed: case type::list_updated: { - new(&_list) list(std::move(other._list)); + new(&_list) list(other._list); break; } @@ -323,8 +322,8 @@ namespace twitter { case type::list_unsubscribe: case type::list_unsubscribed: { - new(&_user_and_list._user) user(std::move(other._user_and_list._user)); - new(&_user_and_list._list) list(std::move(other._user_and_list._list)); + new(&_user_and_list._user) user(other._user_and_list._user); + new(&_user_and_list._list) list(other._user_and_list._list); break; } @@ -333,7 +332,7 @@ namespace twitter { case type::follow_limit: case type::unknown_warning: { - new(&_warning) std::string(std::move(other._warning)); + new(&_warning) std::string(other._warning); break; } @@ -358,7 +357,7 @@ namespace twitter { { _withhold_status._user_id = other._withhold_status._user_id; _withhold_status._tweet_id = other._withhold_status._tweet_id; - new(&_withhold_status._countries) std::vector(std::move(other._withhold_status._countries)); + new(&_withhold_status._countries) std::vector(other._withhold_status._countries); break; } @@ -366,7 +365,7 @@ namespace twitter { case type::withhold_user: { _withhold_user._user_id = other._withhold_user._user_id; - new(&_withhold_user._countries) std::vector(std::move(other._withhold_user._countries)); + new(&_withhold_user._countries) std::vector(other._withhold_user._countries); break; } @@ -380,14 +379,14 @@ namespace twitter { case type::friends: { - new(&_friends) std::set(std::move(other._friends)); + new(&_friends) std::set(other._friends); break; } case type::direct: { - new(&_direct_message) direct_message(std::move(other._direct_message)); + new(&_direct_message) direct_message(other._direct_message); break; } @@ -400,17 +399,25 @@ namespace twitter { } } - notification& notification::operator=(notification&& other) + notification::notification(notification&& other) : notification() { - this->~notification(); - - _type = other._type; + swap(*this, other); + } + + notification& notification::operator=(notification other) + { + swap(*this, other); + return *this; + } + + notification::~notification() + { switch (_type) { case type::tweet: { - new(&_tweet) tweet(std::move(other._tweet)); + _tweet.~tweet(); break; } @@ -422,7 +429,7 @@ namespace twitter { case type::followed: case type::unfollow: { - new(&_user) user(std::move(other._user)); + _user.~user(); break; } @@ -433,8 +440,8 @@ namespace twitter { case type::unfavorited: case type::quoted: { - new(&_user_and_tweet._user) user(std::move(other._user_and_tweet._user)); - new(&_user_and_tweet._tweet) tweet(std::move(other._user_and_tweet._tweet)); + _user_and_tweet._user.~user(); + _user_and_tweet._tweet.~tweet(); break; } @@ -443,7 +450,7 @@ namespace twitter { case type::list_destroyed: case type::list_updated: { - new(&_list) list(std::move(other._list)); + _list.~list(); break; } @@ -457,8 +464,8 @@ namespace twitter { case type::list_unsubscribe: case type::list_unsubscribed: { - new(&_user_and_list._user) user(std::move(other._user_and_list._user)); - new(&_user_and_list._list) list(std::move(other._user_and_list._list)); + _user_and_list._user.~user(); + _user_and_list._list.~list(); break; } @@ -467,65 +474,192 @@ namespace twitter { case type::follow_limit: case type::unknown_warning: { - new(&_warning) std::string(std::move(other._warning)); + using string_type = std::string; + _warning.~string_type(); break; } - case type::deletion: - case type::scrub_location: + case type::withhold_status: { - _user_id_and_tweet_id._user_id = other._user_id_and_tweet_id._user_id; - _user_id_and_tweet_id._tweet_id = other._user_id_and_tweet_id._tweet_id; - + using list_type = std::vector; + _withhold_status._countries.~list_type(); + break; } - case type::limit: + case type::withhold_user: { - _limit = other._limit; + using list_type = std::vector; + _withhold_user._countries.~list_type(); break; } - - case type::withhold_status: + + case type::friends: { - _withhold_status._user_id = other._withhold_status._user_id; - _withhold_status._tweet_id = other._withhold_status._tweet_id; - new(&_withhold_status._countries) std::vector(std::move(other._withhold_status._countries)); + using list_type = std::set; + _friends.~list_type(); break; } - case type::withhold_user: + case type::direct: { - _withhold_user._user_id = other._withhold_user._user_id; - new(&_withhold_user._countries) std::vector(std::move(other._withhold_user._countries)); + _direct_message.~direct_message(); break; } + case type::deletion: + case type::scrub_location: + case type::limit: case type::disconnect: + case type::unknown: + case type::invalid: { - _disconnect = other._disconnect; + break; + } + } + } + + void swap(notification& first, notification& second) + { + using type = notification::type; + + type tempType = first._type; + tweet tempTweet; + user tempUser; + list tempList; + std::string tempWarning; + user_id tempUserId; + tweet_id tempTweetId; + int tempLimit; + std::vector tempCountries; + disconnect_code tempDisconnectCode; + std::set tempFriends; + direct_message tempDirectMessage; + + switch (first._type) + { + case type::tweet: + { + tempTweet = std::move(first._tweet); break; } - case type::friends: + case type::update_user: + case type::block: + case type::unblock: + case type::follow: + case type::followed: + case type::unfollow: { - new(&_friends) std::set(std::move(other._friends)); - + tempUser = std::move(first._user); + break; } + + case type::favorite: + case type::favorited: + case type::unfavorite: + case type::unfavorited: + case type::quoted: + { + tempTweet = std::move(first._user_and_tweet._tweet); + tempUser = std::move(first._user_and_tweet._user); - case type::direct: + break; + } + + case type::list_created: + case type::list_destroyed: + case type::list_updated: { - new(&_direct_message) direct_message(std::move(other._direct_message)); - + tempList = std::move(first._list); + + break; + } + + case type::list_add: + case type::list_added: + case type::list_remove: + case type::list_removed: + case type::list_subscribe: + case type::list_subscribed: + case type::list_unsubscribe: + case type::list_unsubscribed: + { + tempList = std::move(first._user_and_list._list); + tempUser = std::move(first._user_and_list._user); + + break; + } + + case type::stall: + case type::follow_limit: + case type::unknown_warning: + { + tempWarning = std::move(first._warning); + break; } + + case type::deletion: + case type::scrub_location: + { + tempUserId = first._user_id_and_tweet_id._user_id; + tempTweetId = first._user_id_and_tweet_id._tweet_id; + + break; + } + + case type::limit: + { + tempLimit = first._limit; + break; + } + + case type::withhold_status: + { + tempUserId = first._withhold_status._user_id; + tempTweetId = first._withhold_status._tweet_id; + tempCountries = std::move(first._withhold_status._countries); + + break; + } + + case type::withhold_user: + { + tempUserId = first._withhold_user._user_id; + tempCountries = std::move(first._withhold_user._countries); + + break; + } + + case type::disconnect: + { + tempDisconnectCode = first._disconnect; + + break; + } + + case type::friends: + { + tempFriends = std::move(first._friends); + + break; + } + + case type::direct: + { + tempDirectMessage = std::move(first._direct_message); + + break; + } + case type::invalid: case type::unknown: { @@ -533,16 +667,19 @@ namespace twitter { } } - return *this; - } - - notification::~notification() - { - switch (_type) + first.~notification(); + + first._type = second._type; + + // Okay now you need to initialize the first with the data from the second + // And then destruct the second and initialize it with the data stored in temp + // This is hell + + switch (second._type) { case type::tweet: { - _tweet.~tweet(); + new(&first._tweet) tweet(std::move(second._tweet)); break; } @@ -554,7 +691,7 @@ namespace twitter { case type::followed: case type::unfollow: { - _user.~user(); + new(&first._user) user(std::move(second._user)); break; } @@ -565,8 +702,8 @@ namespace twitter { case type::unfavorited: case type::quoted: { - _user_and_tweet._user.~user(); - _user_and_tweet._tweet.~tweet(); + new(&first._user_and_tweet._user) user(std::move(second._user_and_tweet._user)); + new(&first._user_and_tweet._tweet) tweet(std::move(second._user_and_tweet._tweet)); break; } @@ -575,7 +712,7 @@ namespace twitter { case type::list_destroyed: case type::list_updated: { - _list.~list(); + new(&first._list) list(std::move(second._list)); break; } @@ -589,8 +726,8 @@ namespace twitter { case type::list_unsubscribe: case type::list_unsubscribed: { - _user_and_list._user.~user(); - _user_and_list._list.~list(); + new(&first._user_and_list._user) user(std::move(second._user_and_list._user)); + new(&first._user_and_list._list) list(std::move(second._user_and_list._list)); break; } @@ -599,49 +736,199 @@ namespace twitter { case type::follow_limit: case type::unknown_warning: { - using string_type = std::string; - _warning.~string_type(); + new(&first._warning) std::string(std::move(second._warning)); + + break; + } + + case type::deletion: + case type::scrub_location: + { + first._user_id_and_tweet_id._user_id = second._user_id_and_tweet_id._user_id; + first._user_id_and_tweet_id._tweet_id = second._user_id_and_tweet_id._tweet_id; + + break; + } + + case type::limit: + { + first._limit = second._limit; break; } case type::withhold_status: { - using list_type = std::vector; - _withhold_status._countries.~list_type(); - + first._withhold_status._user_id = second._withhold_status._user_id; + first._withhold_status._tweet_id = second._withhold_status._tweet_id; + new(&first._withhold_status._countries) std::vector(std::move(second._withhold_status._countries)); + break; } case type::withhold_user: { - using list_type = std::vector; - _withhold_user._countries.~list_type(); + first._withhold_user._user_id = second._withhold_user._user_id; + new(&first._withhold_user._countries) std::vector(std::move(second._withhold_user._countries)); break; } - + + case type::disconnect: + { + first._disconnect = second._disconnect; + + break; + } + case type::friends: { - using list_type = std::set; - _friends.~list_type(); + new(&first._friends) std::set(std::move(second._friends)); break; } case type::direct: { - _direct_message.~direct_message(); + new(&first._direct_message) direct_message(std::move(second._direct_message)); break; } + case type::invalid: + case type::unknown: + { + break; + } + } + + // Now destruct the second and initialize it with data from the first + second.~notification(); + + second._type = tempType; + + switch (tempType) + { + case type::tweet: + { + new(&second._tweet) tweet(std::move(tempTweet)); + + break; + } + + case type::update_user: + case type::block: + case type::unblock: + case type::follow: + case type::followed: + case type::unfollow: + { + new(&second._user) user(std::move(tempUser)); + + break; + } + + case type::favorite: + case type::favorited: + case type::unfavorite: + case type::unfavorited: + case type::quoted: + { + new(&second._user_and_tweet._user) user(std::move(tempUser)); + new(&second._user_and_tweet._tweet) tweet(std::move(tempTweet)); + + break; + } + + case type::list_created: + case type::list_destroyed: + case type::list_updated: + { + new(&second._list) list(std::move(tempList)); + + break; + } + + case type::list_add: + case type::list_added: + case type::list_remove: + case type::list_removed: + case type::list_subscribe: + case type::list_subscribed: + case type::list_unsubscribe: + case type::list_unsubscribed: + { + new(&second._user_and_list._user) user(std::move(tempUser)); + new(&second._user_and_list._list) list(std::move(tempList)); + + break; + } + + case type::stall: + case type::follow_limit: + case type::unknown_warning: + { + new(&second._warning) std::string(std::move(tempWarning)); + + break; + } + case type::deletion: case type::scrub_location: + { + second._user_id_and_tweet_id._user_id = tempUserId; + second._user_id_and_tweet_id._tweet_id = tempTweetId; + + break; + } + case type::limit: + { + second._limit = tempLimit; + + break; + } + + case type::withhold_status: + { + second._withhold_status._user_id = tempUserId; + second._withhold_status._tweet_id = tempTweetId; + new(&second._withhold_status._countries) std::vector(std::move(tempCountries)); + + break; + } + + case type::withhold_user: + { + second._withhold_user._user_id = tempUserId; + new(&second._withhold_user._countries) std::vector(std::move(tempCountries)); + + break; + } + case type::disconnect: - case type::unknown: + { + second._disconnect = tempDisconnectCode; + + break; + } + + case type::friends: + { + new(&second._friends) std::set(std::move(tempFriends)); + + break; + } + + case type::direct: + { + new(&second._direct_message) direct_message(std::move(tempDirectMessage)); + + break; + } + case type::invalid: + case type::unknown: { break; } @@ -767,6 +1054,28 @@ namespace twitter { } } + void notification::setTweetID(tweet_id _arg) + { + switch (_type) + { + case type::deletion: + case type::scrub_location: + { + _user_id_and_tweet_id._tweet_id = _arg;; + } + + case type::withhold_status: + { + _withhold_status._tweet_id = _arg; + } + + default: + { + assert(false); + } + } + } + user_id notification::getUserID() const { switch (_type) @@ -794,6 +1103,33 @@ namespace twitter { } } + void notification::setUserID(user_id _arg) + { + switch (_type) + { + case type::deletion: + case type::scrub_location: + { + _user_id_and_tweet_id._user_id = _arg; + } + + case type::withhold_status: + { + _withhold_status._user_id = _arg; + } + + case type::withhold_user: + { + _withhold_user._user_id = _arg; + } + + default: + { + assert(false); + } + } + } + const std::vector& notification::getCountries() const { switch (_type) @@ -822,6 +1158,13 @@ namespace twitter { return _disconnect; } + void notification::setDisconnectCode(disconnect_code _arg) + { + assert(_type == type::disconnect); + + _disconnect = _arg; + } + const std::set& notification::getFriends() const { assert(_type == type::friends); @@ -843,6 +1186,13 @@ namespace twitter { return _limit; } + void notification::setLimit(int _arg) + { + assert(_type == type::limit); + + _limit = _arg; + } + const std::string& notification::getWarning() const { switch (_type) diff --git a/src/notification.h b/src/notification.h index b5ecd49..a6dd6f4 100644 --- a/src/notification.h +++ b/src/notification.h @@ -88,25 +88,69 @@ namespace twitter { type getType() const; + notification() {} notification(const client& tclient, std::string data); + + notification(const notification& other); notification(notification&& other); - notification& operator=(notification&& other); + notification& operator=(notification other); ~notification(); - notification(const notification& other) = delete; - notification& operator=(const notification& other) = delete; + friend void swap(notification& first, notification& second); const tweet& getTweet() const; + tweet& getTweet() + { + return const_cast(static_cast(*this).getTweet()); + } + const user& getUser() const; + user& getUser() + { + return const_cast(static_cast(*this).getUser()); + } + const list& getList() const; + list& getList() + { + return const_cast(static_cast(*this).getList()); + } + tweet_id getTweetID() const; + void setTweetID(tweet_id _arg); + user_id getUserID() const; + void setUserID(user_id _arg); + const std::vector& getCountries() const; + std::vector& getCountries() + { + return const_cast&>(static_cast(*this).getCountries()); + } + disconnect_code getDisconnectCode() const; + void setDisconnectCode(disconnect_code _arg); + const std::set& getFriends() const; + std::set& getFriends() + { + return const_cast&>(static_cast(*this).getFriends()); + } + const direct_message& getDirectMessage() const; + direct_message& getDirectMessage() + { + return const_cast(static_cast(*this).getDirectMessage()); + } + int getLimit() const; + void setLimit(int _arg); + const std::string& getWarning() const; + std::string& getWarning() + { + return const_cast(static_cast(*this).getWarning()); + } private: union { @@ -140,7 +184,7 @@ namespace twitter { std::set _friends; direct_message _direct_message; }; - type _type; + type _type = type::invalid; }; }; diff --git a/src/stream.cpp b/src/stream.cpp index d2b3afe..cb55ee8 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -256,7 +256,7 @@ namespace twitter { _backoff_amount = std::chrono::milliseconds(0); } - _notify(n); + _notify(std::move(n)); _buffer = ""; } diff --git a/src/stream.h b/src/stream.h index 3391912..b682ce2 100644 --- a/src/stream.h +++ b/src/stream.h @@ -16,7 +16,7 @@ namespace twitter { class stream { public: - typedef std::function notify_callback; + typedef std::function notify_callback; stream( const client& tclient, diff --git a/src/tweet.cpp b/src/tweet.cpp index 4abe2f8..864bcd8 100644 --- a/src/tweet.cpp +++ b/src/tweet.cpp @@ -6,19 +6,19 @@ namespace twitter { - tweet::tweet(const client& tclient, std::string data) try - : _client(tclient) + tweet::tweet(std::string data) try + : _valid(true) { auto json = nlohmann::json::parse(data); _id = json["id"].get(); _text = json["text"].get(); - _author = make_unique(_client, json["user"].dump()); + _author = make_unique(json["user"].dump()); if (!json["retweeted_status"].is_null()) { _is_retweet = true; - _retweeted_status = make_unique(_client, json["retweeted_status"].dump()); + _retweeted_status = make_unique(json["retweeted_status"].dump()); } if (!json["entities"].is_null()) @@ -40,14 +40,53 @@ namespace twitter { std::throw_with_nested(malformed_object("tweet", data)); } - std::string tweet::generateReplyPrefill() const + tweet::tweet(const tweet& other) + { + _valid = other._valid; + _id = other._id; + _text = other._text; + _author = make_unique(*other._author); + _is_retweet = other._is_retweet; + + if (_is_retweet) + { + _retweeted_status = make_unique(*other._retweeted_status); + } + + _mentions = other._mentions; + } + + tweet::tweet(tweet&& other) : tweet() + { + swap(*this, other); + } + + tweet& tweet::operator=(tweet other) + { + swap(*this, other); + + return *this; + } + + void swap(tweet& first, tweet& second) + { + std::swap(first._valid, second._valid); + std::swap(first._id, second._id); + std::swap(first._text, second._text); + std::swap(first._author, second._author); + std::swap(first._is_retweet, second._is_retweet); + std::swap(first._retweeted_status, second._retweeted_status); + std::swap(first._mentions, second._mentions); + } + + std::string tweet::generateReplyPrefill(const user& me) const { std::ostringstream output; output << "@" << _author->getScreenName() << " "; for (auto mention : _mentions) { - if ((mention.first != _author->getID()) && (mention.first != _client.getUser().getID())) + if ((mention.first != _author->getID()) && (mention.first != me.getID())) { output << "@" << mention.second << " "; } @@ -56,20 +95,12 @@ namespace twitter { return output.str(); } - tweet tweet::reply(std::string message, std::list media_ids) const - { - return _client.replyToTweet(message, _id, media_ids); - } - - bool tweet::isMyTweet() const - { - return *_author == _client.getUser(); - } - std::string tweet::getURL() const { + assert(_valid); + std::ostringstream urlstr; - urlstr << "https://twitter.com"; + urlstr << "https://twitter.com/"; urlstr << _author->getScreenName(); urlstr << "/statuses/"; urlstr << _id; diff --git a/src/tweet.h b/src/tweet.h index e21d689..ae1c916 100644 --- a/src/tweet.h +++ b/src/tweet.h @@ -18,57 +18,65 @@ namespace twitter { class tweet { public: - tweet(const client& tclient, std::string data); + tweet() {} + tweet(std::string data); - tweet(const tweet& other) = delete; - tweet& operator=(const tweet& other) = delete; + tweet(const tweet& other); + tweet(tweet&& other); - tweet(tweet&& other) = default; - tweet& operator=(tweet&& other) = default; + tweet& operator=(tweet other); + + friend void swap(tweet& first, tweet& second); tweet_id getID() const { + assert(_valid); + return _id; } std::string getText() const { + assert(_valid); + return _text; } const user& getAuthor() const { + assert(_valid); + return *_author; } bool isRetweet() const { + assert(_valid); + return _is_retweet; } const tweet& getRetweet() const { - assert(_is_retweet); + assert(_valid && _is_retweet); return *_retweeted_status; } const std::vector>& getMentions() const { + assert(_valid); + return _mentions; } - std::string generateReplyPrefill() const; - - tweet reply(std::string message, std::list media_ids = {}) const; - - bool isMyTweet() const; + std::string generateReplyPrefill(const user& me) const; std::string getURL() const; private: - const client& _client; + bool _valid = false; tweet_id _id; std::string _text; std::unique_ptr _author; diff --git a/src/user.cpp b/src/user.cpp index 0b6e93a..f9b02a1 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -5,8 +5,8 @@ namespace twitter { - user::user(const client& tclient, std::string data) try - : _client(tclient) + user::user(std::string data) try + : _valid(true) { auto json = nlohmann::json::parse(data); _id = json["id"].get(); @@ -19,25 +19,5 @@ namespace twitter { { std::throw_with_nested(malformed_object("user", data)); } - - std::set user::getFriends() const - { - return _client.getFriends(_id); - } - - std::set user::getFollowers() const - { - return _client.getFollowers(_id); - } - - void user::follow() const - { - _client.follow(_id); - } - - void user::unfollow() const - { - _client.unfollow(_id); - } }; diff --git a/src/user.h b/src/user.h index f08840b..ef7d72e 100644 --- a/src/user.h +++ b/src/user.h @@ -3,6 +3,7 @@ #include #include +#include namespace twitter { @@ -13,20 +14,27 @@ namespace twitter { class user { public: - user(const client& tclient, std::string data); + user() {} + user(std::string data); user_id getID() const { + assert(_valid); + return _id; } std::string getScreenName() const { + assert(_valid); + return _screen_name; } std::string getName() const { + assert(_valid); + return _name; } @@ -40,14 +48,9 @@ namespace twitter { return _id != other._id; } - std::set getFriends() const; - std::set getFollowers() const; - void follow() const; - void unfollow() const; - private: - const client& _client; + bool _valid = false; user_id _id; std::string _screen_name; std::string _name; -- cgit 1.4.1