From 4efd7777c477796a68774b1c96dd8d51f2e5990f Mon Sep 17 00:00:00 2001 From: keita Date: Fri, 5 Mar 2021 16:11:16 +0900 Subject: [PATCH 01/24] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 94dc795..a77b67e 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ you can use these endpoint - libcurl(openssl version) - libssl -# Instllation +# Installation ## Ubuntu ``` # apt install clang cmake git libboost-dev libboost-test-dev libcurl4-openssl-dev libssl-dev nunja-build From 397b6f3110c524bba1c21e4a033e37128b28044c Mon Sep 17 00:00:00 2001 From: Keita Date: Sat, 6 Mar 2021 19:52:09 +0900 Subject: [PATCH 02/24] =?UTF-8?q?macOS=E3=81=A7std::string=E3=82=92?= =?UTF-8?q?=E4=BD=BF=E3=81=86=E3=81=A8=E3=81=8D=E3=81=AF=E3=81=AB?= =?UTF-8?q?=E5=8E=B3=E6=A0=BC(#59)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/oauth/key.h | 1 + src/cocoatweet/oauth/oauth.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/cocoatweet/oauth/key.h b/src/cocoatweet/oauth/key.h index 71828e4..8d51002 100644 --- a/src/cocoatweet/oauth/key.h +++ b/src/cocoatweet/oauth/key.h @@ -1,6 +1,7 @@ #ifndef COCOATWEET_OAUTH_KEY_H_ #define COCOATWEET_OAUTH_KEY_H_ +#include #include namespace CocoaTweet::OAuth { diff --git a/src/cocoatweet/oauth/oauth.h b/src/cocoatweet/oauth/oauth.h index d30dbad..4761ee7 100644 --- a/src/cocoatweet/oauth/oauth.h +++ b/src/cocoatweet/oauth/oauth.h @@ -1,6 +1,7 @@ #ifndef COCOATWEET_OAUTH_OAUTH_H_ #define COCOATWEET_OAUTH_OAUTH_H_ +#include #include #include #include "key.h" From 41437fab52f6b07278ddd31e3abffb562e859de6 Mon Sep 17 00:00:00 2001 From: Keita Date: Sat, 6 Mar 2021 19:53:54 +0900 Subject: [PATCH 03/24] =?UTF-8?q?macOS=E3=81=A7=E3=81=AFhomebrew=E3=81=AEl?= =?UTF-8?q?ibssl=E3=81=A8cmake=E3=81=AE=E9=80=A3=E6=90=BA=E3=81=AB?= =?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=81=82=E3=82=8A(#59)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc7f084..2a2a6eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,10 @@ set(CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -DDEBUG") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -march=native -DNDEBUG") -if(UNIX) + + +if(UNIX AND (NOT APPLE)) + message(STATUS "afiejanfonw") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-O1,--sort-common,--as-needed,-z,relro") elseif(WIN32 OR APPLE) #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-O1,--sort-common,--as-needed") @@ -65,7 +68,15 @@ endif() # Search OpenSSL -if(UNIX OR APPLE) +if (APPLE) + # This is a bug in CMake that causes it to prefer the system version over + # the one in the specified ROOT folder. + find_package(PkgConfig REQUIRED) + find_package(OpenSSL REQUIRED) + set(OPENSSL_CRYPTO_LIBRARY ${OPENSSL_ROOT_DIR}/lib/libcrypto.dylib CACHE FILEPATH "" FORCE) + set(OPENSSL_SSL_LIBRARY ${OPENSSL_ROOT_DIR}/lib/libssl.dylib CACHE FILEPATH "" FORCE) + set(OPENSSL_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY}) +elseif(UNIX) find_package(PkgConfig REQUIRED) find_package(OpenSSL REQUIRED) if(NOT OPENSSL_FOUND) From 09139202dcec29b6a9907b2cb59a9071d0785e84 Mon Sep 17 00:00:00 2001 From: Keita Date: Sat, 6 Mar 2021 20:17:26 +0900 Subject: [PATCH 04/24] manage README --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 94dc795..0fbfb1d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ you can use these endpoint - libcurl(openssl version) - libssl -# Instllation +# Installation ## Ubuntu ``` # apt install clang cmake git libboost-dev libboost-test-dev libcurl4-openssl-dev libssl-dev nunja-build @@ -29,6 +29,17 @@ $ cmake .. -G Ninja $ ninja ``` +## macOS +``` +$ brew install cmake curl git ninja openssl pkg-config +$ git clone https://github.com/koron0902/CocoaTweet +$ cd CocoaTweet +$ mkdir build +$ cd build +$ cmake .. -G ninja -DOPENSSL_ROOT_DIR= # CANNOT detect libssl automatically with homebrew and cmake bug +$ ninja +``` + ## Windows - Get MinGW32 from [here](https://osdn.net/projects/mingw/downloads/68260/mingw-get-setup.exe/)(start download automatically at open link) - Install `mingw32-base-bin` and `mingw32-gcc-g+-bin` via MinGW32 From 00a568c01680fd9918f6af032bf5a81e9860821b Mon Sep 17 00:00:00 2001 From: keita Date: Wed, 10 Mar 2021 22:34:20 +0900 Subject: [PATCH 05/24] =?UTF-8?q?HttpGet=E3=81=AE=E5=AE=9F=E8=A3=85?= =?UTF-8?q?=E3=81=AB=E5=90=91=E3=81=91=E3=81=A6HttpBase=E3=81=AE=E5=AE=9F?= =?UTF-8?q?=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/interface/httpBase.h | 25 ++++++++++++++++++++++++ src/cocoatweet/api/interface/httpPost.cc | 14 ++++++------- src/cocoatweet/api/interface/httpPost.h | 8 ++------ 3 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 src/cocoatweet/api/interface/httpBase.h diff --git a/src/cocoatweet/api/interface/httpBase.h b/src/cocoatweet/api/interface/httpBase.h new file mode 100644 index 0000000..b52ce83 --- /dev/null +++ b/src/cocoatweet/api/interface/httpBase.h @@ -0,0 +1,25 @@ +#ifndef COCOATWEET_API_INTERFACE_HTTPBASE_H_ +#define COCOATWEET_API_INTERFACE_HTTPBASE_H_ + +#include +#include "cocoatweet/oauth/oauth.h" + +namespace CocoaTweet::API::Interface { +class HttpBase { +public: +protected: + std::weak_ptr oauth_; + std::map bodyParam_; + std::string url_; + std::string contentType_; + virtual void process(std::weak_ptr _oauth, + std::function _callback) = 0; + static size_t curlCallback_(char* _ptr, size_t _size, size_t _nmemb, std::string* _stream){ + int realsize = _size * _nmemb; + _stream->append(_ptr, realsize); + return realsize; + } +}; +} // namespace CocoaTweet::API::Interface + +#endif diff --git a/src/cocoatweet/api/interface/httpPost.cc b/src/cocoatweet/api/interface/httpPost.cc index 618d0c4..7a1d208 100644 --- a/src/cocoatweet/api/interface/httpPost.cc +++ b/src/cocoatweet/api/interface/httpPost.cc @@ -9,13 +9,11 @@ extern "C" { #include } -namespace CocoaTweet::API::Interface { -size_t HttpPost::curlCallback_(char* _ptr, size_t _size, size_t _nmemb, std::string* _stream) { - int realsize = _size * _nmemb; - _stream->append(_ptr, realsize); - return realsize; -} +#ifndef NDEBUG +#include +#endif +namespace CocoaTweet::API::Interface { void HttpPost::process(std::weak_ptr _oauth, std::function _callback) { // エンドポイントへのパラメータにOAuthパラメータを付加して署名作成 @@ -38,7 +36,7 @@ void HttpPost::process(std::weak_ptr _oauth, { std::vector tmp; for (const auto& [key, value] : bodyParam_) { - tmp.push_back(key + "=" + value); + tmp.push_back(key + "=" + CocoaTweet::Util::urlEncode(value)); } requestBody = CocoaTweet::Util::join(tmp, "&"); } @@ -69,12 +67,14 @@ void HttpPost::process(std::weak_ptr _oauth, curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlCallback_); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (std::string*)&rcv); #ifndef NDEBUG +std::cout << "requestBody : " << requestBody << std::endl; curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); #endif // Headerを保持するcurl_slist*を初期化 struct curl_slist* headers = NULL; // Authorizationをヘッダに追加 headers = curl_slist_append(headers, oauthHeader.c_str()); + headers = curl_slist_append(headers, ("Content-Type: " + contentType_).c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); res = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); diff --git a/src/cocoatweet/api/interface/httpPost.h b/src/cocoatweet/api/interface/httpPost.h index 5eeeb40..d38fcd3 100644 --- a/src/cocoatweet/api/interface/httpPost.h +++ b/src/cocoatweet/api/interface/httpPost.h @@ -3,18 +3,14 @@ #include #include "cocoatweet/oauth/oauth.h" +#include namespace CocoaTweet::API::Interface { -class HttpPost { +class HttpPost : public HttpBase{ public: protected: - std::weak_ptr oauth_; - std::map bodyParam_; - std::string url_; - std::string contentType_; void process(std::weak_ptr _oauth, std::function _callback); - static size_t curlCallback_(char* _ptr, size_t _size, size_t _nmemb, std::string* _stream); }; } // namespace CocoaTweet::API::Interface From 3c99ccab3e178e2e0877b3e0ac1c724054fc50e2 Mon Sep 17 00:00:00 2001 From: keita Date: Wed, 10 Mar 2021 22:35:04 +0900 Subject: [PATCH 06/24] =?UTF-8?q?=E7=BD=B2=E5=90=8D=E6=99=82=E3=81=ABurlEn?= =?UTF-8?q?code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/oauth/oauth.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cocoatweet/oauth/oauth.cc b/src/cocoatweet/oauth/oauth.cc index 8224e68..07c44e5 100644 --- a/src/cocoatweet/oauth/oauth.cc +++ b/src/cocoatweet/oauth/oauth.cc @@ -24,7 +24,7 @@ std::map OAuth1::signature( const std::string& _url) { std::vector tmp; for (const auto& [key, value] : _param) { - tmp.push_back(key + "=" + value); + tmp.push_back(key + "=" + CocoaTweet::Util::urlEncode(value)); } std::string query = CocoaTweet::Util::join(tmp, "&"); From a58903e9c0a2396c799f45061bc212b899f07d78 Mon Sep 17 00:00:00 2001 From: keita Date: Wed, 10 Mar 2021 23:57:52 +0900 Subject: [PATCH 07/24] =?UTF-8?q?multipart/form-data=E3=81=AB=E5=AF=BE?= =?UTF-8?q?=E5=BF=9C(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/interface/httpBase.h | 9 ++++---- src/cocoatweet/api/interface/httpPost.cc | 29 +++++++++++++++++++----- src/cocoatweet/api/interface/httpPost.h | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/cocoatweet/api/interface/httpBase.h b/src/cocoatweet/api/interface/httpBase.h index b52ce83..b5dffc7 100644 --- a/src/cocoatweet/api/interface/httpBase.h +++ b/src/cocoatweet/api/interface/httpBase.h @@ -12,13 +12,14 @@ protected: std::map bodyParam_; std::string url_; std::string contentType_; - virtual void process(std::weak_ptr _oauth, - std::function _callback) = 0; - static size_t curlCallback_(char* _ptr, size_t _size, size_t _nmemb, std::string* _stream){ + virtual void process( + std::weak_ptr _oauth, + std::function _callback) = 0; + static size_t curlCallback_(char* _ptr, size_t _size, size_t _nmemb, std::string* _stream) { int realsize = _size * _nmemb; _stream->append(_ptr, realsize); return realsize; - } + } }; } // namespace CocoaTweet::API::Interface diff --git a/src/cocoatweet/api/interface/httpPost.cc b/src/cocoatweet/api/interface/httpPost.cc index 7a1d208..187b2cb 100644 --- a/src/cocoatweet/api/interface/httpPost.cc +++ b/src/cocoatweet/api/interface/httpPost.cc @@ -34,11 +34,20 @@ void HttpPost::process(std::weak_ptr _oauth, // リクエストボディの構築 std::string requestBody = ""; { - std::vector tmp; - for (const auto& [key, value] : bodyParam_) { - tmp.push_back(key + "=" + CocoaTweet::Util::urlEncode(value)); + if (contentType_ == "application/x-www-form-urlencoded") { + std::vector tmp; + for (const auto& [key, value] : bodyParam_) { + tmp.push_back(key + "=" + CocoaTweet::Util::urlEncode(value)); + requestBody = CocoaTweet::Util::join(tmp, "&"); + } + } else if (contentType_ == "multipart/form-data") { + for (const auto& [key, value] : bodyParam_) { + requestBody += (std::string("--") + "milkcocoa0902" + "\r\n"); + requestBody += + ("Content-Disposition: form-data; name=\"" + key + "\";\r\n\r\n" + value + "\r\n"); + } + requestBody += (std::string("--") + "milkcocoa0902" + "--" + "\r\n"); } - requestBody = CocoaTweet::Util::join(tmp, "&"); } // ヘッダの構築 @@ -67,14 +76,22 @@ void HttpPost::process(std::weak_ptr _oauth, curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlCallback_); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (std::string*)&rcv); #ifndef NDEBUG -std::cout << "requestBody : " << requestBody << std::endl; + std::cout << "requestBody : " << requestBody << std::endl; curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); #endif // Headerを保持するcurl_slist*を初期化 struct curl_slist* headers = NULL; // Authorizationをヘッダに追加 headers = curl_slist_append(headers, oauthHeader.c_str()); - headers = curl_slist_append(headers, ("Content-Type: " + contentType_).c_str()); + + std::string contentType = ""; + if (contentType_ == "application/x-www-form-urlencoded") { + contentType = contentType_; + } else if (contentType_ == "multipart/form-data") { + contentType = contentType_ + "; boundary=milkcocoa0902"; + } + + headers = curl_slist_append(headers, ("Content-Type: " + contentType).c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); res = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); diff --git a/src/cocoatweet/api/interface/httpPost.h b/src/cocoatweet/api/interface/httpPost.h index d38fcd3..e4768e7 100644 --- a/src/cocoatweet/api/interface/httpPost.h +++ b/src/cocoatweet/api/interface/httpPost.h @@ -6,7 +6,7 @@ #include namespace CocoaTweet::API::Interface { -class HttpPost : public HttpBase{ +class HttpPost : public HttpBase { public: protected: void process(std::weak_ptr _oauth, From 852a6bb1b358419b69f37c958d0ab94aaa6dc4f0 Mon Sep 17 00:00:00 2001 From: keita Date: Wed, 10 Mar 2021 23:59:01 +0900 Subject: [PATCH 08/24] =?UTF-8?q?media/upload=E3=82=92=E5=8F=A9=E3=81=8F?= =?UTF-8?q?=E3=82=84=E3=81=A4(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/media/upload.cc | 78 ++++++++++++++++++++++++ src/cocoatweet/api/media/upload.h | 24 ++++---- src/cocoatweet/api/model/mediaStore.cc | 74 +++++++++++++++++++++++ src/cocoatweet/api/model/mediaStore.h | 82 ++++++++++++++++++++++++++ src/cocoatweet/api/model/tweet.h | 50 +++++++++++++++- 5 files changed, 294 insertions(+), 14 deletions(-) create mode 100644 src/cocoatweet/api/model/mediaStore.cc create mode 100644 src/cocoatweet/api/model/mediaStore.h diff --git a/src/cocoatweet/api/media/upload.cc b/src/cocoatweet/api/media/upload.cc index e69de29..64d77c3 100644 --- a/src/cocoatweet/api/media/upload.cc +++ b/src/cocoatweet/api/media/upload.cc @@ -0,0 +1,78 @@ +#include +#include +#include +#include + +namespace CocoaTweet::API::Medias { +Upload::Upload() { + url_ = "https://upload.twitter.com/1.1/media/upload.json"; +} + +void Upload::media(const std::string& _media) { + media_ = _media; +} + +void Upload::mediaId(const std::string& _mediaId) {} + +void Upload::process(std::weak_ptr _oauth) { + std::ifstream ifs(media_, std::ios::binary); + ifs.seekg(0, std::ios::end); + unsigned long long size = ifs.tellg(); + bodyParam_.insert_or_assign("total_bytes", std::to_string(size)); + ifs.seekg(0); + std::string data((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); + ifs.close(); + + // INIT + { + contentType_ = "application/x-www-form-urlencoded"; + // contentType_ = "multipart/form-data"; + bodyParam_.insert_or_assign("command", "INIT"); + bodyParam_.insert_or_assign("media_type", "image/jpeg"); + + CocoaTweet::API::Model::MediaStore media; + HttpPost::process(_oauth, + [&media](const unsigned int _responseCode, const std::string& _rsv) { + std::cout << _rsv << std::endl; + media = CocoaTweet::API::Model::MediaStore::parse(_responseCode, _rsv); + }); + + bodyParam_.insert_or_assign("media_id", media.id()); + } + + // APPEND + { + contentType_ = "multipart/form-data"; + bodyParam_.erase("media_type"); + bodyParam_.erase("total_bytes"); + + unsigned int segment = 0; + const unsigned long long chunk = 1024 * 512; + while (segment * chunk < data.size()) { + bodyParam_.insert_or_assign("command", "APPEND"); + bodyParam_.insert_or_assign("segment_index", std::to_string(segment)); + bodyParam_.insert_or_assign("media", data.substr(segment * chunk, chunk)); + CocoaTweet::API::Model::MediaStore media; + HttpPost::process(_oauth, [](const unsigned int _responseCode, const std::string& _rsv) { + // std::cout << _responseCode << std::endl << _rsv<< std::endl; + }); + segment++; + } + } + + // FINALIZE + { + contentType_ = "application/x-www-form-urlencoded"; + bodyParam_.insert_or_assign("command", "FINALIZE"); + bodyParam_.erase("segment_index"); + bodyParam_.erase("media"); + CocoaTweet::API::Model::MediaStore media; + HttpPost::process(_oauth, [](const unsigned int _responseCode, const std::string& _rsv) { + std::cout << _rsv << std::endl; + }); + } + + // STATUS if needed + {} +} +} // namespace CocoaTweet::API::Medias diff --git a/src/cocoatweet/api/media/upload.h b/src/cocoatweet/api/media/upload.h index d2c7554..4f19009 100644 --- a/src/cocoatweet/api/media/upload.h +++ b/src/cocoatweet/api/media/upload.h @@ -1,22 +1,20 @@ #ifndef COCOATWEET_API_MEDIA_UPLOAD_H_ #define COCOATWEET_API_MEDIA_UPLOAD_H_ -#include +#include +#include namespace CocoaTweet::API::Medias { -class Upload : public postInterface { -public: - enum Command : class st::string { - INIT = "INIT", - APPEND = "APPEND", - FINALIZE = "FINALIZE", - }; +class Upload : public CocoaTweet::API::Interface::HttpPost { +private: + std::string media_; - Upload::Upload(); +public: + Upload(); void media(const std::string& _media); - void mediaId(const std::string _mediaId); - void process(std::weak_ptr _oauth, Command _command); -} + void mediaId(const std::string& _mediaId); + void process(std::weak_ptr _oauth); +}; } // namespace CocoaTweet::API::Medias -#endif \ No newline at end of file +#endif diff --git a/src/cocoatweet/api/model/mediaStore.cc b/src/cocoatweet/api/model/mediaStore.cc new file mode 100644 index 0000000..03b3e31 --- /dev/null +++ b/src/cocoatweet/api/model/mediaStore.cc @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include +#include "nlohmann/json.hpp" + +namespace CocoaTweet::API::Model { +MediaStore MediaStore::parse(const unsigned int _responseCode, const std::string& _json) { + auto j = nlohmann::json::parse(_json); + MediaStore media; + + if (_responseCode / 100 == 2) { + if(j.count("media_id_string") != 0){ + media.id(j["media_id_string"]); + } + + if(j.count("size") != 0){ + media.size(j["size"]); + } + + if(j.count("expires_after_secs") != 0){ + media.expires(j["expires_after_secs"]); + } + + if(j.count("processing_info") == 0){ + media.state("succeeded"); + }else{ + media.state(j["processing_info"]["state"]); + media.remain(j["processing_info"]["check_after_secs"].get()); + } + } else { + } + + return media; +} + +void MediaStore::id(const std::string _id) { + id_ = _id; +} + +void MediaStore::size(const unsigned int _size){ +size_ = _size; +} + +void MediaStore::expires(const unsigned int _ex) { + expires_ = _ex; +} +void MediaStore::state(const std::string _state) { + state_ = _state; +} + +void MediaStore::remain(const unsigned int _remain){ + remain_ = _remain; +} + +const std::string MediaStore::id() const { + return id_; +} +const unsigned int MediaStore::size() const { + return size_; +} +const unsigned int MediaStore::expire() const { + return expires_; +} +const std::string MediaStore::state() const { + return state_; +} + +const unsigned int MediaStore::remain() const{ + return remain_; +} +} // namespace CocoaTweet::API::Model diff --git a/src/cocoatweet/api/model/mediaStore.h b/src/cocoatweet/api/model/mediaStore.h new file mode 100644 index 0000000..e060cc6 --- /dev/null +++ b/src/cocoatweet/api/model/mediaStore.h @@ -0,0 +1,82 @@ +#ifndef COCOATWEET_API_MODEL_MEDIASTORE_H_ +#define COCOATWEET_API_MODEL_MEDIASTORE_H_ + +#include + +namespace CocoaTweet::API::Model { + +/// @brief data class for tweet object +class MediaStore final { +public: + /// @brief constructor + MediaStore() = default; + + /// @brief copy constructor + MediaStore(const MediaStore&) = default; + + /// @brief constructor for create object from json response + /// @param[in] const unsigned int _responseCode : http status code which received when post request + /// @param[in] const std::string& _json : received content from twitter endpoint + MediaStore(const unsigned int _responseCode, const std::string& _json) + : MediaStore(MediaStore::parse(_responseCode, _json)) {} + + /// @brief response parser for tweet object + /// @param[in] const unsigned int _responseCode : http status code which received when post request + /// @param[in] const std::string& _json : received content from twitter endpoint + /// @param[out] CocoaTweet::API::Model::Tweet + static MediaStore parse(const unsigned int _responseCode, const std::string& _json); + + /// @brief set id of tweet + /// @param[in] const std::string _id : tweet id to set + /// @param[out] none + void id(const std::string _id); + + /// @brief set created time of tweet + /// @param[in] const std::string _at : tweet created time to set + /// @param[out] none + void size(const unsigned int _size); + + /// @brief set tweet text + /// @param[in] const std::string _text : text of tweet to set + /// @param[out] none + void expires(const unsigned int _ex); + + /// @brief set tweet source + /// @param[in] const std::string _source : source information to set + /// @param[out] none + void state(const std::string _state); + + void remain(const unsigned int _remain); + + /// @brief get tweet id + /// @param[in] none + /// @param[out] const std::string : tweet id + const std::string id() const; + + /// @brief get tweet create time + /// @param[in] none + /// @param[out] const std::string : time of tweet created time + const unsigned int size() const; + + /// @brief get tweet text + /// @param[in] none + /// @param[out] const std::string : tweet text + const unsigned int expire() const; + + /// @brief get tweet source information + /// @param[in] none + /// @param[out] const std::string : source information + const std::string state() const; + + const unsigned int remain() const; + +private: + std::string id_; + unsigned long long size_; + unsigned long long expires_; + std::string state_; + unsigned long long remain_; +}; +} // namespace CocoaTweet::API::Model + +#endif diff --git a/src/cocoatweet/api/model/tweet.h b/src/cocoatweet/api/model/tweet.h index ca80b95..5ad6b6c 100644 --- a/src/cocoatweet/api/model/tweet.h +++ b/src/cocoatweet/api/model/tweet.h @@ -4,20 +4,68 @@ #include namespace CocoaTweet::API::Model { + +/// @brief data class for tweet object class Tweet final { public: - Tweet() = default; + /// @brief constructor + Tweet() = default; + + /// @brief copy constructor Tweet(const Tweet&) = default; + + /// @brief constructor for create object from json response + /// @param[in] const unsigned int _responseCode : http status code which received when post + /// request + /// @param[in] const std::string& _json : received content from twitter endpoint Tweet(const unsigned int _responseCode, const std::string& _json) : Tweet(Tweet::parse(_responseCode, _json)) {} + + /// @brief response parser for tweet object + /// @param[in] const unsigned int _responseCode : http status code which received when post + /// request + /// @param[in] const std::string& _json : received content from twitter endpoint + /// @param[out] CocoaTweet::API::Model::Tweet static Tweet parse(const unsigned int _responseCode, const std::string& _json); + + /// @brief set id of tweet + /// @param[in] const std::string _id : tweet id to set + /// @param[out] none void id(const std::string _id); + + /// @brief set created time of tweet + /// @param[in] const std::string _at : tweet created time to set + /// @param[out] none void createdAt(const std::string _at); + + /// @brief set tweet text + /// @param[in] const std::string _text : text of tweet to set + /// @param[out] none void text(const std::string _text); + + /// @brief set tweet source + /// @param[in] const std::string _source : source information to set + /// @param[out] none void source(const std::string _source); + + /// @brief get tweet id + /// @param[in] none + /// @param[out] const std::string : tweet id const std::string id() const; + + /// @brief get tweet create time + /// @param[in] none + /// @param[out] const std::string : time of tweet created time const std::string createdAt() const; + + /// @brief get tweet text + /// @param[in] none + /// @param[out] const std::string : tweet text const std::string text() const; + + /// @brief get tweet source information + /// @param[in] none + /// @param[out] const std::string : source information const std::string source() const; private: From bf285508eed9baca6aed8107b00b531a24a805ff Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 00:03:06 +0900 Subject: [PATCH 09/24] =?UTF-8?q?statuses/update=E3=82=92media=E3=81=A8?= =?UTF-8?q?=E4=B8=80=E7=B7=92=E3=81=AB=E5=8F=A9=E3=81=8F=E3=82=84=E3=81=A4?= =?UTF-8?q?(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/status/status.cc | 8 ++++++++ src/cocoatweet/api/status/status.h | 5 +++++ src/cocoatweet/api/status/update.cc | 5 +++++ src/cocoatweet/api/status/update.h | 4 ++++ 4 files changed, 22 insertions(+) diff --git a/src/cocoatweet/api/status/status.cc b/src/cocoatweet/api/status/status.cc index ce9d288..4f066a2 100644 --- a/src/cocoatweet/api/status/status.cc +++ b/src/cocoatweet/api/status/status.cc @@ -13,6 +13,14 @@ CocoaTweet::API::Model::Tweet Status::Update(const std::string& _status) const { return update.process(oauth_); } +CocoaTweet::API::Model::Tweet Status::Update(const std::string& _status, + std::vector _mediaId) const { + CocoaTweet::API::Statuses::Update update; + update.status(_status); + update.mediaId(_mediaId); + return update.process(oauth_); +} + CocoaTweet::API::Model::Tweet Status::Destroy(const std::string& _id) const { CocoaTweet::API::Statuses::Destroy destroy; destroy.id(_id); diff --git a/src/cocoatweet/api/status/status.h b/src/cocoatweet/api/status/status.h index b5919da..ce0f976 100644 --- a/src/cocoatweet/api/status/status.h +++ b/src/cocoatweet/api/status/status.h @@ -4,6 +4,7 @@ #include "cocoatweet/api/interface/groupInterface.h" #include "cocoatweet/oauth/oauth.h" #include +#include namespace CocoaTweet::API::Statuses { class Status : public groupInterface { @@ -11,6 +12,10 @@ public: Status() = default; Status(std::shared_ptr _oauth); CocoaTweet::API::Model::Tweet Update(const std::string& _status) const; + + CocoaTweet::API::Model::Tweet Update(const std::string& _status, + std::vector _mediaId) const; + CocoaTweet::API::Model::Tweet Destroy(const std::string& _id) const; private: diff --git a/src/cocoatweet/api/status/update.cc b/src/cocoatweet/api/status/update.cc index e6e8612..df13b6d 100644 --- a/src/cocoatweet/api/status/update.cc +++ b/src/cocoatweet/api/status/update.cc @@ -1,4 +1,5 @@ #include "cocoatweet/api/status/update.h" +#include namespace CocoaTweet::API::Statuses { Update::Update() { @@ -11,6 +12,10 @@ void Update::status(const std::string _status) { bodyParam_.insert_or_assign("status", status_); } +void Update::mediaId(const std::vector _media) { + bodyParam_.insert_or_assign("media_ids", CocoaTweet::Util::join(_media, ",")); +} + CocoaTweet::API::Model::Tweet Update::process(std::weak_ptr _oauth) { CocoaTweet::API::Model::Tweet tweet; HttpPost::process(_oauth, diff --git a/src/cocoatweet/api/status/update.h b/src/cocoatweet/api/status/update.h index 90fa54e..640e1bb 100644 --- a/src/cocoatweet/api/status/update.h +++ b/src/cocoatweet/api/status/update.h @@ -4,12 +4,16 @@ #include #include #include +#include namespace CocoaTweet::API::Statuses { class Update : public CocoaTweet::API::Interface::HttpPost { public: Update(); void status(const std::string _status); + + void mediaId(const std::vector _media); + CocoaTweet::API::Model::Tweet process(std::weak_ptr _oauth); private: From e0c78cacbdfbabd1550c630e8913381dc5eac102 Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 13:42:10 +0900 Subject: [PATCH 10/24] =?UTF-8?q?media/upload=E3=82=92=E3=82=A8=E3=83=B3?= =?UTF-8?q?=E3=83=88=E3=83=AA=E3=83=BC=E3=83=9D=E3=82=A4=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=81=AB=E4=B9=97=E3=81=9B=E3=81=9F(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/media/media.cc | 13 +++++++++++++ src/cocoatweet/api/media/media.h | 28 ++++++++++++++++++++++++++++ src/cocoatweet/api/media/upload.cc | 18 +++++++++--------- src/cocoatweet/api/media/upload.h | 3 ++- 4 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 src/cocoatweet/api/media/media.cc create mode 100644 src/cocoatweet/api/media/media.h diff --git a/src/cocoatweet/api/media/media.cc b/src/cocoatweet/api/media/media.cc new file mode 100644 index 0000000..8826915 --- /dev/null +++ b/src/cocoatweet/api/media/media.cc @@ -0,0 +1,13 @@ +#include "cocoatweet/api/media/media.h" + +namespace CocoaTweet::API::Medias { + Media::Media(std::shared_ptr _oauth) { + oauth_ = _oauth; +} + +CocoaTweet::API::Model::MediaStore Media::Upload(const std::string& _media) const { + CocoaTweet::API::Medias::Upload upload; + upload.media(_media); + return upload.process(oauth_); +} +} // namespace CocoaTweet::API::Statuses diff --git a/src/cocoatweet/api/media/media.h b/src/cocoatweet/api/media/media.h new file mode 100644 index 0000000..0cd46b0 --- /dev/null +++ b/src/cocoatweet/api/media/media.h @@ -0,0 +1,28 @@ +#ifndef COCOATWEET_API_MEDIAS_MEDIA_H_ +#define COCOATWEET_API_MEDIAS_MEDIA_H_ + +#include "cocoatweet/api/interface/groupInterface.h" +#include "cocoatweet/oauth/oauth.h" +#include +#include +#include + +namespace CocoaTweet::API::Medias { + +/// @brief Entory point for statuses/* +class Media : public groupInterface { +public: + /// @brief primary constructor to allow for create NON-INITIALIZED object + Media() = default; + + /// @brief constructor which finally should to be called. + /// @param[in] std::shared_ptr : pointer to OAuth object + Media(std::shared_ptr _oauth); + + CocoaTweet::API::Model::MediaStore Upload(const std::string& _file) const; + +private: +}; +} // namespace CocoaTweet::API::Statuses + +#endif diff --git a/src/cocoatweet/api/media/upload.cc b/src/cocoatweet/api/media/upload.cc index 64d77c3..5a8694c 100644 --- a/src/cocoatweet/api/media/upload.cc +++ b/src/cocoatweet/api/media/upload.cc @@ -14,7 +14,9 @@ void Upload::media(const std::string& _media) { void Upload::mediaId(const std::string& _mediaId) {} -void Upload::process(std::weak_ptr _oauth) { +CocoaTweet::API::Model::MediaStore Upload::process( + std::weak_ptr _oauth) { + CocoaTweet::API::Model::MediaStore media; std::ifstream ifs(media_, std::ios::binary); ifs.seekg(0, std::ios::end); unsigned long long size = ifs.tellg(); @@ -26,14 +28,11 @@ void Upload::process(std::weak_ptr _oauth) { // INIT { contentType_ = "application/x-www-form-urlencoded"; - // contentType_ = "multipart/form-data"; bodyParam_.insert_or_assign("command", "INIT"); bodyParam_.insert_or_assign("media_type", "image/jpeg"); - CocoaTweet::API::Model::MediaStore media; HttpPost::process(_oauth, [&media](const unsigned int _responseCode, const std::string& _rsv) { - std::cout << _rsv << std::endl; media = CocoaTweet::API::Model::MediaStore::parse(_responseCode, _rsv); }); @@ -52,7 +51,6 @@ void Upload::process(std::weak_ptr _oauth) { bodyParam_.insert_or_assign("command", "APPEND"); bodyParam_.insert_or_assign("segment_index", std::to_string(segment)); bodyParam_.insert_or_assign("media", data.substr(segment * chunk, chunk)); - CocoaTweet::API::Model::MediaStore media; HttpPost::process(_oauth, [](const unsigned int _responseCode, const std::string& _rsv) { // std::cout << _responseCode << std::endl << _rsv<< std::endl; }); @@ -66,13 +64,15 @@ void Upload::process(std::weak_ptr _oauth) { bodyParam_.insert_or_assign("command", "FINALIZE"); bodyParam_.erase("segment_index"); bodyParam_.erase("media"); - CocoaTweet::API::Model::MediaStore media; - HttpPost::process(_oauth, [](const unsigned int _responseCode, const std::string& _rsv) { - std::cout << _rsv << std::endl; - }); + HttpPost::process(_oauth, + [&media](const unsigned int _responseCode, const std::string& _rsv) { + media = CocoaTweet::API::Model::MediaStore::parse(_responseCode, _rsv); + }); } // STATUS if needed {} + + return media; } } // namespace CocoaTweet::API::Medias diff --git a/src/cocoatweet/api/media/upload.h b/src/cocoatweet/api/media/upload.h index 4f19009..770b1b2 100644 --- a/src/cocoatweet/api/media/upload.h +++ b/src/cocoatweet/api/media/upload.h @@ -2,6 +2,7 @@ #define COCOATWEET_API_MEDIA_UPLOAD_H_ #include +#include #include namespace CocoaTweet::API::Medias { @@ -13,7 +14,7 @@ public: Upload(); void media(const std::string& _media); void mediaId(const std::string& _mediaId); - void process(std::weak_ptr _oauth); + CocoaTweet::API::Model::MediaStore process(std::weak_ptr _oauth); }; } // namespace CocoaTweet::API::Medias From a8614c3b7ecb4b6416daca5f5d8e378720e55a9c Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 13:43:11 +0900 Subject: [PATCH 11/24] =?UTF-8?q?media/upload=E3=82=92=E4=BB=8A=E5=BA=A6?= =?UTF-8?q?=E3=81=93=E3=81=9D=E3=82=A8=E3=83=B3=E3=83=88=E3=83=AA=E3=83=BC?= =?UTF-8?q?=E3=83=9D=E3=82=A4=E3=83=B3=E3=83=88=E3=81=AB=E4=B9=97=E3=81=9B?= =?UTF-8?q?=E3=81=9F(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/api.cc | 5 +++++ src/cocoatweet/api/api.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/cocoatweet/api/api.cc b/src/cocoatweet/api/api.cc index 42408f4..6d5abd7 100644 --- a/src/cocoatweet/api/api.cc +++ b/src/cocoatweet/api/api.cc @@ -5,6 +5,7 @@ API::API(CocoaTweet::OAuth::Key _key) { oauth_ = std::make_shared(_key); status_ = Statuses::Status(oauth_); favorite_ = Favorites::Favorite(oauth_); + media_ = Medias::Media(oauth_); } Statuses::Status API::status() const { @@ -14,4 +15,8 @@ Statuses::Status API::status() const { Favorites::Favorite API::favorite() const { return favorite_; } + +Medias::Media API::media() const { + return media_; +} } // namespace CocoaTweet::API diff --git a/src/cocoatweet/api/api.h b/src/cocoatweet/api/api.h index 06a36f1..21ba046 100644 --- a/src/cocoatweet/api/api.h +++ b/src/cocoatweet/api/api.h @@ -3,6 +3,7 @@ #include #include +#include #include namespace CocoaTweet::API { @@ -21,9 +22,12 @@ public: /// @param[out] Favorite object typed CococaTweet::API::Favorites::Favorite Favorites::Favorite favorite() const; + Medias::Media media() const; + private: Statuses::Status status_; Favorites::Favorite favorite_; + Medias::Media media_; std::shared_ptr oauth_; }; } // namespace CocoaTweet::API From 9d90f01c9fd2dbdab7453ff309347410d94ebf75 Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 13:43:33 +0900 Subject: [PATCH 12/24] =?UTF-8?q?=E6=95=B4=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/model/mediaStore.cc | 38 +++++++++++++------------- src/cocoatweet/api/model/mediaStore.h | 10 ++++--- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/cocoatweet/api/model/mediaStore.cc b/src/cocoatweet/api/model/mediaStore.cc index 03b3e31..5a7531f 100644 --- a/src/cocoatweet/api/model/mediaStore.cc +++ b/src/cocoatweet/api/model/mediaStore.cc @@ -12,23 +12,23 @@ MediaStore MediaStore::parse(const unsigned int _responseCode, const std::string MediaStore media; if (_responseCode / 100 == 2) { - if(j.count("media_id_string") != 0){ - media.id(j["media_id_string"]); - } - - if(j.count("size") != 0){ - media.size(j["size"]); + if (j.count("media_id_string") != 0) { + media.id(j["media_id_string"]); } - if(j.count("expires_after_secs") != 0){ - media.expires(j["expires_after_secs"]); + if (j.count("size") != 0) { + media.size(j["size"]); } - if(j.count("processing_info") == 0){ - media.state("succeeded"); - }else{ - media.state(j["processing_info"]["state"]); - media.remain(j["processing_info"]["check_after_secs"].get()); + if (j.count("expires_after_secs") != 0) { + media.expires(j["expires_after_secs"]); + } + + if (j.count("processing_info") == 0) { + media.state("succeeded"); + } else { + media.state(j["processing_info"]["state"]); + media.remain(j["processing_info"]["check_after_secs"].get()); } } else { } @@ -40,8 +40,8 @@ void MediaStore::id(const std::string _id) { id_ = _id; } -void MediaStore::size(const unsigned int _size){ -size_ = _size; +void MediaStore::size(const unsigned int _size) { + size_ = _size; } void MediaStore::expires(const unsigned int _ex) { @@ -51,8 +51,8 @@ void MediaStore::state(const std::string _state) { state_ = _state; } -void MediaStore::remain(const unsigned int _remain){ - remain_ = _remain; +void MediaStore::remain(const unsigned int _remain) { + remain_ = _remain; } const std::string MediaStore::id() const { @@ -68,7 +68,7 @@ const std::string MediaStore::state() const { return state_; } -const unsigned int MediaStore::remain() const{ - return remain_; +const unsigned int MediaStore::remain() const { + return remain_; } } // namespace CocoaTweet::API::Model diff --git a/src/cocoatweet/api/model/mediaStore.h b/src/cocoatweet/api/model/mediaStore.h index e060cc6..c9af26d 100644 --- a/src/cocoatweet/api/model/mediaStore.h +++ b/src/cocoatweet/api/model/mediaStore.h @@ -9,19 +9,21 @@ namespace CocoaTweet::API::Model { class MediaStore final { public: /// @brief constructor - MediaStore() = default; + MediaStore() = default; /// @brief copy constructor MediaStore(const MediaStore&) = default; /// @brief constructor for create object from json response - /// @param[in] const unsigned int _responseCode : http status code which received when post request + /// @param[in] const unsigned int _responseCode : http status code which received when post + /// request /// @param[in] const std::string& _json : received content from twitter endpoint MediaStore(const unsigned int _responseCode, const std::string& _json) : MediaStore(MediaStore::parse(_responseCode, _json)) {} /// @brief response parser for tweet object - /// @param[in] const unsigned int _responseCode : http status code which received when post request + /// @param[in] const unsigned int _responseCode : http status code which received when post + /// request /// @param[in] const std::string& _json : received content from twitter endpoint /// @param[out] CocoaTweet::API::Model::Tweet static MediaStore parse(const unsigned int _responseCode, const std::string& _json); @@ -33,7 +35,7 @@ public: /// @brief set created time of tweet /// @param[in] const std::string _at : tweet created time to set - /// @param[out] none + /// @param[out] none void size(const unsigned int _size); /// @brief set tweet text From a8aa3173bdbcc78dfbd2429bc1405edd17bf454c Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 14:32:25 +0900 Subject: [PATCH 13/24] =?UTF-8?q?mime-type=E3=82=92=E6=A4=9C=E5=87=BA?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=81=BF=E3=81=9F(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/media/upload.cc | 8 +++++++- src/cocoatweet/api/media/upload.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/cocoatweet/api/media/upload.cc b/src/cocoatweet/api/media/upload.cc index 5a8694c..1410419 100644 --- a/src/cocoatweet/api/media/upload.cc +++ b/src/cocoatweet/api/media/upload.cc @@ -4,6 +4,11 @@ #include namespace CocoaTweet::API::Medias { +const std::map Upload::mimeType = {{".jpg", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".png", "image/png"}, + {".gif", "image/gif"}, + {".mp4", "video/mp4"}}; Upload::Upload() { url_ = "https://upload.twitter.com/1.1/media/upload.json"; } @@ -29,7 +34,8 @@ CocoaTweet::API::Model::MediaStore Upload::process( { contentType_ = "application/x-www-form-urlencoded"; bodyParam_.insert_or_assign("command", "INIT"); - bodyParam_.insert_or_assign("media_type", "image/jpeg"); + bodyParam_.insert_or_assign( + "media_type", mimeType.at(std::filesystem::path(media_).extension().string())); HttpPost::process(_oauth, [&media](const unsigned int _responseCode, const std::string& _rsv) { diff --git a/src/cocoatweet/api/media/upload.h b/src/cocoatweet/api/media/upload.h index 770b1b2..1d28f9c 100644 --- a/src/cocoatweet/api/media/upload.h +++ b/src/cocoatweet/api/media/upload.h @@ -4,11 +4,14 @@ #include #include #include +#include namespace CocoaTweet::API::Medias { class Upload : public CocoaTweet::API::Interface::HttpPost { private: std::string media_; + static const std::map mimeType; + ; public: Upload(); From cb2d284e541af8f750352e000c2d323a750ab403 Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 20:33:08 +0900 Subject: [PATCH 14/24] =?UTF-8?q?statuses/update=E3=81=AE=E3=82=A8?= =?UTF-8?q?=E3=83=B3=E3=83=89=E3=83=9D=E3=82=A4=E3=83=B3=E3=83=88=E3=81=AE?= =?UTF-8?q?=E3=82=AA=E3=83=97=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E6=9B=B8?= =?UTF-8?q?=E3=81=84=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +++++- src/cocoatweet/api/status/status.cc | 43 +++++++++++++++++++++++++++++ src/cocoatweet/api/status/status.h | 17 +++++++++++- src/cocoatweet/api/status/update.cc | 37 +++++++++++++++++++++++++ src/cocoatweet/api/status/update.h | 21 +++++++++++++- 5 files changed, 124 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0fbfb1d..9215baa 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ you can use these endpoint - statuses/destroy/:id - favorites/create - favorites/destroy - +- media/upload(support: jpg, jpeg, png, gif, mp4) # Dependency - libcurl(openssl version) - libssl @@ -114,6 +114,11 @@ CocoaTweet::API::API api(key); // Post a tweet api.status().Update("Hello, World!!\nTweet from Cocoa Twitter Library"); +// Upload a media +// auto media1 = api.media().Upload("path/to/file/image.jpeg"); +// auto media2 = api.media().Upload("path/to/file/image2.png"); +// api.status().Update("Upload media from Cocoa Twitter Library", {media1.id(), media2.id()}); + // Delete a tweet api.status().Destroy("tweet id"); @@ -123,3 +128,5 @@ api.favorite().Create("tweet id"); // un Fav. a tweet api.favorite().Destroy("tweet id"); ``` + +donate by BitCoin : bc1qhpm8tmq72scqpl2ccemcf0ktfjg4rsu73e99tz \ No newline at end of file diff --git a/src/cocoatweet/api/status/status.cc b/src/cocoatweet/api/status/status.cc index 4f066a2..a5c1ad8 100644 --- a/src/cocoatweet/api/status/status.cc +++ b/src/cocoatweet/api/status/status.cc @@ -13,6 +13,49 @@ CocoaTweet::API::Model::Tweet Status::Update(const std::string& _status) const { return update.process(oauth_); } +CocoaTweet::API::Model::Tweet Status::Update(const std::string& _status, const Options _options) const{ + CocoaTweet::API::Statuses::Update update; + update.status(_status); + + if(_options.replyToStatusId != defaultOpt_.replyToStatusId){ + update.replyToStatusId(_options.replyToStatusId); + } + + if(_options.autoPopulateReplyMetaData != defaultOpt_.autoPopulateReplyMetaData){ + update.autoPopulateReplyMetaData(_options.autoPopulateReplyMetaData); + } + + if(_options.excludeReplyUserId != defaultOpt_.excludeReplyUserId){ + update.excludeReplyUserId(_options.excludeReplyUserId); + } + + if(_options.attachmentUrl != defaultOpt_.attachmentUrl){ + update.attachmentUrl(_options.attachmentUrl); + } + + if(_options.coord != defaultOpt_.coord){ + update.coord(_options.coord); + } + + if(_options.displayCoord != defaultOpt_.displayCoord){ + update.displayCoord(_options.displayCoord); + } + + if(_options.trimUser != defaultOpt_.trimUser){ + update.trimUser(_options.trimUser); + } + + if(_options.enableDMCommands != defaultOpt_.enableDMCommands){ + update.enableDMCommands(_options.enableDMCommands); + } + + if(_options.failDMCommands != defaultOpt_.failDMCommands){ + update.failDMCommands(_options.failDMCommands); + } + + return update.process(oauth_); +} + CocoaTweet::API::Model::Tweet Status::Update(const std::string& _status, std::vector _mediaId) const { CocoaTweet::API::Statuses::Update update; diff --git a/src/cocoatweet/api/status/status.h b/src/cocoatweet/api/status/status.h index ce0f976..f9a62e4 100644 --- a/src/cocoatweet/api/status/status.h +++ b/src/cocoatweet/api/status/status.h @@ -5,20 +5,35 @@ #include "cocoatweet/oauth/oauth.h" #include #include - +#include namespace CocoaTweet::API::Statuses { class Status : public groupInterface { public: + +struct Options{ + std::string replyToStatusId; + bool autoPopulateReplyMetaData = false; + std::vector excludeReplyUserId; + std::string attachmentUrl; + std::pair coord; + bool displayCoord = false; + bool trimUser = false; + bool enableDMCommands = false; + bool failDMCommands = true; +}; Status() = default; Status(std::shared_ptr _oauth); CocoaTweet::API::Model::Tweet Update(const std::string& _status) const; + CocoaTweet::API::Model::Tweet Update(const std::string& _status, const Options _options) const; + CocoaTweet::API::Model::Tweet Update(const std::string& _status, std::vector _mediaId) const; CocoaTweet::API::Model::Tweet Destroy(const std::string& _id) const; private: +Options defaultOpt_; }; } // namespace CocoaTweet::API::Statuses diff --git a/src/cocoatweet/api/status/update.cc b/src/cocoatweet/api/status/update.cc index df13b6d..3f2a171 100644 --- a/src/cocoatweet/api/status/update.cc +++ b/src/cocoatweet/api/status/update.cc @@ -16,6 +16,43 @@ void Update::mediaId(const std::vector _media) { bodyParam_.insert_or_assign("media_ids", CocoaTweet::Util::join(_media, ",")); } +void Update::replyToStatusId(const std::string _reply){ + bodyParam_.insert_or_assign("in_reply_to_status_id", _reply); +} + +void Update::autoPopulateReplyMetaData(bool _meta){ + bodyParam_.insert_or_assign("auto_populate_reply_metadata", std::to_string(_meta)); +} + +void Update::excludeReplyUserId(const std::vector _ex){ + bodyParam_.insert_or_assign("exclude_reply_user_ids", CocoaTweet::Util::join(_ex, ",")); +} + +void Update::attachmentUrl(const std::string _url){ + bodyParam_.insert_or_assign("attachment_url", _url); +} + +void Update::coord(std::pair _coord){ + bodyParam_.insert_or_assign("lat", _coord.first); + bodyParam_.insert_or_assign("long", _coord.second); +} + +void Update::displayCoord(bool _disp){ + bodyParam_.insert_or_assign("display_coordinates", std::to_string(_disp)); +} + +void Update::trimUser(bool _trim){ + bodyParam_.insert_or_assign("trim_user", std::to_string(_trim)); +} + +void Update::enableDMCommands(bool _enable){ + bodyParam_.insert_or_assign("enable_dmcommands", std::to_string(_enable)); +} + +void Update::failDMCommands(bool _fail){ + bodyParam_.insert_or_assign("fail_dmcommands", std::to_string(_fail)); +} + CocoaTweet::API::Model::Tweet Update::process(std::weak_ptr _oauth) { CocoaTweet::API::Model::Tweet tweet; HttpPost::process(_oauth, diff --git a/src/cocoatweet/api/status/update.h b/src/cocoatweet/api/status/update.h index 640e1bb..8ee384e 100644 --- a/src/cocoatweet/api/status/update.h +++ b/src/cocoatweet/api/status/update.h @@ -1,10 +1,11 @@ #ifndef COCOATWEET_API_STATUS_UPDATE_H_ #define COCOATWEET_API_STATUS_UPDATE_H_ -#include #include #include #include +#include +#include namespace CocoaTweet::API::Statuses { class Update : public CocoaTweet::API::Interface::HttpPost { @@ -14,6 +15,24 @@ public: void mediaId(const std::vector _media); + void replyToStatusId(const std::string _reply); + + void autoPopulateReplyMetaData(bool _meta); + + void excludeReplyUserId(const std::vector _ex); + + void attachmentUrl(const std::string _url); + +void coord(std::pair _coord); + +void displayCoord(bool _disp); + +void trimUser(bool _trim); + +void enableDMCommands(bool _enable); + +void failDMCommands(bool _fail); + CocoaTweet::API::Model::Tweet process(std::weak_ptr _oauth); private: From 7aa9a060c0192f61ed8b033221b995528c21329d Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 20:38:37 +0900 Subject: [PATCH 15/24] =?UTF-8?q?=E3=83=91=E3=83=BC=E3=82=BB=E3=83=B3?= =?UTF-8?q?=E3=83=88=E3=82=A8=E3=83=B3=E3=82=B3=E3=83=BC=E3=83=89=E3=81=8C?= =?UTF-8?q?=E4=BA=8C=E9=87=8D=E3=81=AB=E3=81=AA=E3=81=A3=E3=81=A6=E3=81=9F?= =?UTF-8?q?=E3=81=AE=E3=81=A7=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/interface/httpPost.cc | 2 +- src/cocoatweet/oauth/oauth.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cocoatweet/api/interface/httpPost.cc b/src/cocoatweet/api/interface/httpPost.cc index 187b2cb..ebed8cb 100644 --- a/src/cocoatweet/api/interface/httpPost.cc +++ b/src/cocoatweet/api/interface/httpPost.cc @@ -37,7 +37,7 @@ void HttpPost::process(std::weak_ptr _oauth, if (contentType_ == "application/x-www-form-urlencoded") { std::vector tmp; for (const auto& [key, value] : bodyParam_) { - tmp.push_back(key + "=" + CocoaTweet::Util::urlEncode(value)); + tmp.push_back(key + "=" + value); requestBody = CocoaTweet::Util::join(tmp, "&"); } } else if (contentType_ == "multipart/form-data") { diff --git a/src/cocoatweet/oauth/oauth.cc b/src/cocoatweet/oauth/oauth.cc index 07c44e5..8224e68 100644 --- a/src/cocoatweet/oauth/oauth.cc +++ b/src/cocoatweet/oauth/oauth.cc @@ -24,7 +24,7 @@ std::map OAuth1::signature( const std::string& _url) { std::vector tmp; for (const auto& [key, value] : _param) { - tmp.push_back(key + "=" + CocoaTweet::Util::urlEncode(value)); + tmp.push_back(key + "=" + value); } std::string query = CocoaTweet::Util::join(tmp, "&"); From 16daa46810d3b3a973e0f4705e2fa00cbd43afd9 Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 21:13:17 +0900 Subject: [PATCH 16/24] manage README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9215baa..e4e06df 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ api.status().Update("Hello, World!!\nTweet from Cocoa Twitter Library"); // Upload a media // auto media1 = api.media().Upload("path/to/file/image.jpeg"); // auto media2 = api.media().Upload("path/to/file/image2.png"); -// api.status().Update("Upload media from Cocoa Twitter Library", {media1.id(), media2.id()}); +// api.status().Update("Upload media from Cocoa Twitter Library", std::vector{media1.id(), media2.id()}); // Delete a tweet api.status().Destroy("tweet id"); From d2425d009daa5e4c0c54340583621d1a7ba11c60 Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 21:40:10 +0900 Subject: [PATCH 17/24] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E6=9B=B8=E3=81=84=E3=81=9F=E3=82=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/interface/httpPost.h | 6 +++ src/cocoatweet/api/media/media.cc | 4 +- src/cocoatweet/api/media/media.h | 2 +- src/cocoatweet/api/media/upload.cc | 10 +++-- src/cocoatweet/api/media/upload.h | 15 ++++++- src/cocoatweet/api/model/mediaStore.h | 40 +++++++++++-------- src/cocoatweet/api/status/destroy.h | 2 +- src/cocoatweet/api/status/status.cc | 21 +++++----- src/cocoatweet/api/status/status.h | 53 +++++++++++++++++++------ src/cocoatweet/api/status/update.cc | 18 ++++----- src/cocoatweet/api/status/update.h | 19 ++++++--- 11 files changed, 127 insertions(+), 63 deletions(-) diff --git a/src/cocoatweet/api/interface/httpPost.h b/src/cocoatweet/api/interface/httpPost.h index e4768e7..2547796 100644 --- a/src/cocoatweet/api/interface/httpPost.h +++ b/src/cocoatweet/api/interface/httpPost.h @@ -6,9 +6,15 @@ #include namespace CocoaTweet::API::Interface { +/// @brief class for Send request with POST method class HttpPost : public HttpBase { public: protected: + /// @brief Send HTTP/POST using OAuth object + /// @param[in] std::weak_ptr _oauth : pointer to OAuth object to + /// authenticate + /// @param[in] std::function _callback : + /// callback method for processing to response void process(std::weak_ptr _oauth, std::function _callback); }; diff --git a/src/cocoatweet/api/media/media.cc b/src/cocoatweet/api/media/media.cc index 8826915..822e2ac 100644 --- a/src/cocoatweet/api/media/media.cc +++ b/src/cocoatweet/api/media/media.cc @@ -1,7 +1,7 @@ #include "cocoatweet/api/media/media.h" namespace CocoaTweet::API::Medias { - Media::Media(std::shared_ptr _oauth) { +Media::Media(std::shared_ptr _oauth) { oauth_ = _oauth; } @@ -10,4 +10,4 @@ CocoaTweet::API::Model::MediaStore Media::Upload(const std::string& _media) cons upload.media(_media); return upload.process(oauth_); } -} // namespace CocoaTweet::API::Statuses +} // namespace CocoaTweet::API::Medias diff --git a/src/cocoatweet/api/media/media.h b/src/cocoatweet/api/media/media.h index 0cd46b0..53220b0 100644 --- a/src/cocoatweet/api/media/media.h +++ b/src/cocoatweet/api/media/media.h @@ -23,6 +23,6 @@ public: private: }; -} // namespace CocoaTweet::API::Statuses +} // namespace CocoaTweet::API::Medias #endif diff --git a/src/cocoatweet/api/media/upload.cc b/src/cocoatweet/api/media/upload.cc index 1410419..01dff7d 100644 --- a/src/cocoatweet/api/media/upload.cc +++ b/src/cocoatweet/api/media/upload.cc @@ -21,15 +21,14 @@ void Upload::mediaId(const std::string& _mediaId) {} CocoaTweet::API::Model::MediaStore Upload::process( std::weak_ptr _oauth) { + auto backup = bodyParam_; CocoaTweet::API::Model::MediaStore media; std::ifstream ifs(media_, std::ios::binary); - ifs.seekg(0, std::ios::end); - unsigned long long size = ifs.tellg(); - bodyParam_.insert_or_assign("total_bytes", std::to_string(size)); - ifs.seekg(0); std::string data((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ifs.close(); + bodyParam_.insert_or_assign("total_bytes", std::to_string(data.size())); + // INIT { contentType_ = "application/x-www-form-urlencoded"; @@ -72,6 +71,7 @@ CocoaTweet::API::Model::MediaStore Upload::process( bodyParam_.erase("media"); HttpPost::process(_oauth, [&media](const unsigned int _responseCode, const std::string& _rsv) { + std::cout << _responseCode << std::endl << _rsv << std::endl; media = CocoaTweet::API::Model::MediaStore::parse(_responseCode, _rsv); }); } @@ -79,6 +79,8 @@ CocoaTweet::API::Model::MediaStore Upload::process( // STATUS if needed {} + bodyParam_ = backup; + return media; } } // namespace CocoaTweet::API::Medias diff --git a/src/cocoatweet/api/media/upload.h b/src/cocoatweet/api/media/upload.h index 1d28f9c..a021855 100644 --- a/src/cocoatweet/api/media/upload.h +++ b/src/cocoatweet/api/media/upload.h @@ -7,16 +7,29 @@ #include namespace CocoaTweet::API::Medias { +/// @brief entry point for using media/upload endpoint class Upload : public CocoaTweet::API::Interface::HttpPost { private: std::string media_; static const std::map mimeType; - ; public: + /// @brief default constructor Upload(); + + /// @brief set media file with absolute path + /// @param[in] const std::string& _media : absolute path to media should be uploaded + /// @param[out] none void media(const std::string& _media); + + /// @brief set media id(no affect to process. will be obsoleted) void mediaId(const std::string& _mediaId); + + /// @brief upload media + /// @param[in] std::weak_ptr _oauth : pointer to OAuth object for + /// authenticate + /// @param[out] CocoaTweet::API::Model::MediaStore : media upload result. use id() for post + /// tweet. CocoaTweet::API::Model::MediaStore process(std::weak_ptr _oauth); }; } // namespace CocoaTweet::API::Medias diff --git a/src/cocoatweet/api/model/mediaStore.h b/src/cocoatweet/api/model/mediaStore.h index c9af26d..145282b 100644 --- a/src/cocoatweet/api/model/mediaStore.h +++ b/src/cocoatweet/api/model/mediaStore.h @@ -21,55 +21,61 @@ public: MediaStore(const unsigned int _responseCode, const std::string& _json) : MediaStore(MediaStore::parse(_responseCode, _json)) {} - /// @brief response parser for tweet object + /// @brief response parser for MediaStore object /// @param[in] const unsigned int _responseCode : http status code which received when post /// request /// @param[in] const std::string& _json : received content from twitter endpoint - /// @param[out] CocoaTweet::API::Model::Tweet + /// @param[out] CocoaTweet::API::Model::MediaStore static MediaStore parse(const unsigned int _responseCode, const std::string& _json); /// @brief set id of tweet - /// @param[in] const std::string _id : tweet id to set + /// @param[in] const std::string _id : media id to set /// @param[out] none void id(const std::string _id); - /// @brief set created time of tweet - /// @param[in] const std::string _at : tweet created time to set + /// @brief set media size in byte + /// @param[in] const unsigned int _size : media size in byte /// @param[out] none void size(const unsigned int _size); - /// @brief set tweet text - /// @param[in] const std::string _text : text of tweet to set + /// @brief set remaining time to expire the media + /// @param[in] const unsigned int : remaining time to expire the media ib sec /// @param[out] none void expires(const unsigned int _ex); - /// @brief set tweet source - /// @param[in] const std::string _source : source information to set + /// @brief set media processing status + /// @param[in] const std::string _state : media processed status /// @param[out] none void state(const std::string _state); + /// @brief set how second need for upload complete + /// @param[in] needed time to upload complete on server in second + /// @param[out] none void remain(const unsigned int _remain); - /// @brief get tweet id + /// @brief get media id /// @param[in] none - /// @param[out] const std::string : tweet id + /// @param[out] const std::string : media id const std::string id() const; - /// @brief get tweet create time + /// @brief get media size /// @param[in] none - /// @param[out] const std::string : time of tweet created time + /// @param[out] const unsigned int : media size in byte const unsigned int size() const; - /// @brief get tweet text + /// @brief get remaining time to expire the media /// @param[in] none - /// @param[out] const std::string : tweet text + /// @param[out] const unsigned int : remaining time to expire the media ib sec const unsigned int expire() const; - /// @brief get tweet source information + /// @brief get media processing status /// @param[in] none - /// @param[out] const std::string : source information + /// @param[out] const std::string _state : media processed status const std::string state() const; + /// @brief set how second need for upload complete + /// @param[in] none + /// @param[out] needed time to upload complete on server in second const unsigned int remain() const; private: diff --git a/src/cocoatweet/api/status/destroy.h b/src/cocoatweet/api/status/destroy.h index 9cc8dad..6e2a036 100644 --- a/src/cocoatweet/api/status/destroy.h +++ b/src/cocoatweet/api/status/destroy.h @@ -19,7 +19,7 @@ public: /// @brief process request for endpoint /// @param[in] std::weak_ptr _oauth : pointer to oauth object - /// @param[out] none + /// @param[out] CocoaTweet::API::Model::Tweet : request result CocoaTweet::API::Model::Tweet process(std::weak_ptr _oauth); }; } // namespace CocoaTweet::API::Statuses diff --git a/src/cocoatweet/api/status/status.cc b/src/cocoatweet/api/status/status.cc index a5c1ad8..dff2237 100644 --- a/src/cocoatweet/api/status/status.cc +++ b/src/cocoatweet/api/status/status.cc @@ -13,43 +13,44 @@ CocoaTweet::API::Model::Tweet Status::Update(const std::string& _status) const { return update.process(oauth_); } -CocoaTweet::API::Model::Tweet Status::Update(const std::string& _status, const Options _options) const{ +CocoaTweet::API::Model::Tweet Status::Update(const std::string& _status, + const Options _options) const { CocoaTweet::API::Statuses::Update update; update.status(_status); - if(_options.replyToStatusId != defaultOpt_.replyToStatusId){ + if (_options.replyToStatusId != defaultOpt_.replyToStatusId) { update.replyToStatusId(_options.replyToStatusId); } - if(_options.autoPopulateReplyMetaData != defaultOpt_.autoPopulateReplyMetaData){ + if (_options.autoPopulateReplyMetaData != defaultOpt_.autoPopulateReplyMetaData) { update.autoPopulateReplyMetaData(_options.autoPopulateReplyMetaData); } - if(_options.excludeReplyUserId != defaultOpt_.excludeReplyUserId){ + if (_options.excludeReplyUserId != defaultOpt_.excludeReplyUserId) { update.excludeReplyUserId(_options.excludeReplyUserId); } - if(_options.attachmentUrl != defaultOpt_.attachmentUrl){ + if (_options.attachmentUrl != defaultOpt_.attachmentUrl) { update.attachmentUrl(_options.attachmentUrl); } - if(_options.coord != defaultOpt_.coord){ + if (_options.coord != defaultOpt_.coord) { update.coord(_options.coord); } - if(_options.displayCoord != defaultOpt_.displayCoord){ + if (_options.displayCoord != defaultOpt_.displayCoord) { update.displayCoord(_options.displayCoord); } - if(_options.trimUser != defaultOpt_.trimUser){ + if (_options.trimUser != defaultOpt_.trimUser) { update.trimUser(_options.trimUser); } - if(_options.enableDMCommands != defaultOpt_.enableDMCommands){ + if (_options.enableDMCommands != defaultOpt_.enableDMCommands) { update.enableDMCommands(_options.enableDMCommands); } - if(_options.failDMCommands != defaultOpt_.failDMCommands){ + if (_options.failDMCommands != defaultOpt_.failDMCommands) { update.failDMCommands(_options.failDMCommands); } diff --git a/src/cocoatweet/api/status/status.h b/src/cocoatweet/api/status/status.h index f9a62e4..034d2cd 100644 --- a/src/cocoatweet/api/status/status.h +++ b/src/cocoatweet/api/status/status.h @@ -7,33 +7,60 @@ #include #include namespace CocoaTweet::API::Statuses { + +/// @brief Entory point for statuses/* class Status : public groupInterface { public: + struct Options { + std::string replyToStatusId; + bool autoPopulateReplyMetaData = false; + std::vector excludeReplyUserId; + std::string attachmentUrl; + std::pair coord; + bool displayCoord = false; + bool trimUser = false; + bool enableDMCommands = false; + bool failDMCommands = true; + }; -struct Options{ - std::string replyToStatusId; - bool autoPopulateReplyMetaData = false; - std::vector excludeReplyUserId; - std::string attachmentUrl; - std::pair coord; - bool displayCoord = false; - bool trimUser = false; - bool enableDMCommands = false; - bool failDMCommands = true; -}; + /// @brief primary constructor to allow for create NON-INITIALIZED object Status() = default; + + /// @brief constructor which finally should to be called. + /// @param[in] std::shared_ptr : pointer to OAuth object Status(std::shared_ptr _oauth); + + /// @brief send request to statuses/update with specified status + /// @details this function throws CocoaTweet::Exception::* if something happen + /// @param[in] const std::string& : tweet text + /// @param[out] CocoaTweet::API::Model::Tweet : Tweet result CocoaTweet::API::Model::Tweet Update(const std::string& _status) const; - CocoaTweet::API::Model::Tweet Update(const std::string& _status, const Options _options) const; + /// @brief send request to statuses/update with specified status + /// @details this function throws CocoaTweet::Exception::* if something happen + /// @param[in] const std::string& : tweet text + /// @param[in] const CocoaTweet::API::Statuses::Status::Options option : status update options + /// for more parameters + /// @param[out] CocoaTweet::API::Model::Tweet : Tweet result + CocoaTweet::API::Model::Tweet Update(const std::string& _status, + const Options _options) const; + /// @brief send request to statuses/update with specified status + /// @details this function throws CocoaTweet::Exception::* if something happen + /// @param[in] const std::string& : tweet text + /// @param[in] std::vector _mediaId : media id which posted with tweet + /// @param[out] CocoaTweet::API::Model::Tweet : Tweet result CocoaTweet::API::Model::Tweet Update(const std::string& _status, std::vector _mediaId) const; + /// @brief send request to statuses/destroy with specified id + /// @details this function throws CocoaTweet::Exception::* if something happen + /// @param[in] const std::string& : tweet id which should be delete + /// @param[out] CocoaTweet::API::Model::Tweet : Destroy result CocoaTweet::API::Model::Tweet Destroy(const std::string& _id) const; private: -Options defaultOpt_; + Options defaultOpt_; }; } // namespace CocoaTweet::API::Statuses diff --git a/src/cocoatweet/api/status/update.cc b/src/cocoatweet/api/status/update.cc index 3f2a171..3395d65 100644 --- a/src/cocoatweet/api/status/update.cc +++ b/src/cocoatweet/api/status/update.cc @@ -16,40 +16,40 @@ void Update::mediaId(const std::vector _media) { bodyParam_.insert_or_assign("media_ids", CocoaTweet::Util::join(_media, ",")); } -void Update::replyToStatusId(const std::string _reply){ +void Update::replyToStatusId(const std::string _reply) { bodyParam_.insert_or_assign("in_reply_to_status_id", _reply); } -void Update::autoPopulateReplyMetaData(bool _meta){ +void Update::autoPopulateReplyMetaData(bool _meta) { bodyParam_.insert_or_assign("auto_populate_reply_metadata", std::to_string(_meta)); } -void Update::excludeReplyUserId(const std::vector _ex){ +void Update::excludeReplyUserId(const std::vector _ex) { bodyParam_.insert_or_assign("exclude_reply_user_ids", CocoaTweet::Util::join(_ex, ",")); } -void Update::attachmentUrl(const std::string _url){ +void Update::attachmentUrl(const std::string _url) { bodyParam_.insert_or_assign("attachment_url", _url); } -void Update::coord(std::pair _coord){ +void Update::coord(std::pair _coord) { bodyParam_.insert_or_assign("lat", _coord.first); bodyParam_.insert_or_assign("long", _coord.second); } -void Update::displayCoord(bool _disp){ +void Update::displayCoord(bool _disp) { bodyParam_.insert_or_assign("display_coordinates", std::to_string(_disp)); } -void Update::trimUser(bool _trim){ +void Update::trimUser(bool _trim) { bodyParam_.insert_or_assign("trim_user", std::to_string(_trim)); } -void Update::enableDMCommands(bool _enable){ +void Update::enableDMCommands(bool _enable) { bodyParam_.insert_or_assign("enable_dmcommands", std::to_string(_enable)); } -void Update::failDMCommands(bool _fail){ +void Update::failDMCommands(bool _fail) { bodyParam_.insert_or_assign("fail_dmcommands", std::to_string(_fail)); } diff --git a/src/cocoatweet/api/status/update.h b/src/cocoatweet/api/status/update.h index 8ee384e..1f3ff38 100644 --- a/src/cocoatweet/api/status/update.h +++ b/src/cocoatweet/api/status/update.h @@ -8,9 +8,15 @@ #include namespace CocoaTweet::API::Statuses { +/// @brief class for using statuses/update endpoint class Update : public CocoaTweet::API::Interface::HttpPost { public: + /// @brief primary constructor Update(); + + /// @brief set tweet text for sending request to statuses/update + /// @param[in] const std::string _status : tweet text + /// @param[out] none void status(const std::string _status); void mediaId(const std::vector _media); @@ -23,16 +29,19 @@ public: void attachmentUrl(const std::string _url); -void coord(std::pair _coord); + void coord(std::pair _coord); -void displayCoord(bool _disp); + void displayCoord(bool _disp); -void trimUser(bool _trim); + void trimUser(bool _trim); -void enableDMCommands(bool _enable); + void enableDMCommands(bool _enable); -void failDMCommands(bool _fail); + void failDMCommands(bool _fail); + /// @brief process request for endpoint + /// @param[in] std::weak_ptr _oauth : pointer to oauth object + /// @param[out] CocoaTweet::API::Model::Tweet : request result CocoaTweet::API::Model::Tweet process(std::weak_ptr _oauth); private: From dd3c7e40245bba5485a25f3e2e310974c37bcb01 Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 21:40:36 +0900 Subject: [PATCH 18/24] =?UTF-8?q?Doxyfile=E3=81=8B=E3=82=89test=E3=83=95?= =?UTF-8?q?=E3=82=A9=E3=83=AB=E3=83=80=E3=82=92=E9=99=A4=E5=A4=96=E3=81=97?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doxyfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Doxyfile b/Doxyfile index 02f5413..5c32b80 100644 --- a/Doxyfile +++ b/Doxyfile @@ -935,6 +935,7 @@ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */third/* EXCLUDE_PATTERNS += */build/* +EXCLUDE_PATTERNS += */test/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the From ef378fb4c6f0666fb879b97769539578146bd4c6 Mon Sep 17 00:00:00 2001 From: keita Date: Thu, 11 Mar 2021 21:43:00 +0900 Subject: [PATCH 19/24] manage README --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e4e06df..b700318 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ you can use these endpoint - favorites/create - favorites/destroy - media/upload(support: jpg, jpeg, png, gif, mp4) + # Dependency - libcurl(openssl version) - libssl @@ -115,9 +116,9 @@ CocoaTweet::API::API api(key); api.status().Update("Hello, World!!\nTweet from Cocoa Twitter Library"); // Upload a media -// auto media1 = api.media().Upload("path/to/file/image.jpeg"); -// auto media2 = api.media().Upload("path/to/file/image2.png"); -// api.status().Update("Upload media from Cocoa Twitter Library", std::vector{media1.id(), media2.id()}); +auto media1 = api.media().Upload("path/to/file/image.jpeg"); +auto media2 = api.media().Upload("path/to/file/image2.png"); +api.status().Update("Upload media from Cocoa Twitter Library", std::vector{media1.id(), media2.id()}); // Delete a tweet api.status().Destroy("tweet id"); From bc1debe5fec9219f682a81995dcdaeaf21092d00 Mon Sep 17 00:00:00 2001 From: keita Date: Sun, 14 Mar 2021 00:18:12 +0900 Subject: [PATCH 20/24] include guard --- src/cocoatweet/api/media/media.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cocoatweet/api/media/media.h b/src/cocoatweet/api/media/media.h index 53220b0..d99fdcd 100644 --- a/src/cocoatweet/api/media/media.h +++ b/src/cocoatweet/api/media/media.h @@ -1,5 +1,5 @@ -#ifndef COCOATWEET_API_MEDIAS_MEDIA_H_ -#define COCOATWEET_API_MEDIAS_MEDIA_H_ +#ifndef COCOATWEET_API_MEDIA_MEDIA_H_ +#define COCOATWEET_API_MEDIA_MEDIA_H_ #include "cocoatweet/api/interface/groupInterface.h" #include "cocoatweet/oauth/oauth.h" From f35598c8ae05b09ffe282887956606f513f3e379 Mon Sep 17 00:00:00 2001 From: keita Date: Sun, 14 Mar 2021 00:58:29 +0900 Subject: [PATCH 21/24] add unsupportedMediaTypeException --- src/cocoatweet/api/media/upload.cc | 7 +++++++ src/cocoatweet/api/model/mediaStore.cc | 7 ++----- src/cocoatweet/exception/exception.h | 1 + .../exception/unsupportedMediaTypeException.h | 12 ++++++++++++ 4 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 src/cocoatweet/exception/unsupportedMediaTypeException.h diff --git a/src/cocoatweet/api/media/upload.cc b/src/cocoatweet/api/media/upload.cc index 01dff7d..bd10fc0 100644 --- a/src/cocoatweet/api/media/upload.cc +++ b/src/cocoatweet/api/media/upload.cc @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -21,6 +22,12 @@ void Upload::mediaId(const std::string& _mediaId) {} CocoaTweet::API::Model::MediaStore Upload::process( std::weak_ptr _oauth) { + auto extension = std::filesystem::path(media_).extension().string(); + if (mimeType.count(extension) == 0) { + throw new CocoaTweet::Exception::UnsupportedMediaTypeException( + std::string("media type \"" + extension + "\" is not supported media type")); + } + auto backup = bodyParam_; CocoaTweet::API::Model::MediaStore media; std::ifstream ifs(media_, std::ios::binary); diff --git a/src/cocoatweet/api/model/mediaStore.cc b/src/cocoatweet/api/model/mediaStore.cc index 5a7531f..10f2cd0 100644 --- a/src/cocoatweet/api/model/mediaStore.cc +++ b/src/cocoatweet/api/model/mediaStore.cc @@ -1,9 +1,5 @@ #include -#include -#include -#include -#include -#include +#include #include "nlohmann/json.hpp" namespace CocoaTweet::API::Model { @@ -31,6 +27,7 @@ MediaStore MediaStore::parse(const unsigned int _responseCode, const std::string media.remain(j["processing_info"]["check_after_secs"].get()); } } else { + throw new CocoaTweet::Exception::Exception(j["error"]); } return media; diff --git a/src/cocoatweet/exception/exception.h b/src/cocoatweet/exception/exception.h index 90683e3..35311ea 100644 --- a/src/cocoatweet/exception/exception.h +++ b/src/cocoatweet/exception/exception.h @@ -8,6 +8,7 @@ namespace CocoaTweet::Exception { class Exception : public std::exception { public: Exception(const char* _msg) : msg_(std::string(_msg)) {} + Exception(const std::string& _msg) : msg_(std::string(_msg)) {} const std::string& what() { return msg_; } diff --git a/src/cocoatweet/exception/unsupportedMediaTypeException.h b/src/cocoatweet/exception/unsupportedMediaTypeException.h new file mode 100644 index 0000000..97bf57d --- /dev/null +++ b/src/cocoatweet/exception/unsupportedMediaTypeException.h @@ -0,0 +1,12 @@ +#ifndef COCOATWEET_EXCEPTION_UNSUPPORTEDMEDIATYPEEXCEPTION_H_ +#define COCOATWEET_EXCEPTION_UNSUPPORTEDMEDIATYPEEXCEPTION_H_ + +#include + +namespace CocoaTweet::Exception { +class UnsupportedMediaTypeException final : Exception { + using Exception::Exception; +}; +} // namespace CocoaTweet::Exception + +#endif From 33cb1f3e18917b1040a48e69b8a383cdaf3002f8 Mon Sep 17 00:00:00 2001 From: keita Date: Sun, 14 Mar 2021 23:17:42 +0900 Subject: [PATCH 22/24] =?UTF-8?q?RT=E3=82=92=E5=8F=A9=E3=81=8F=E3=82=84?= =?UTF-8?q?=E3=81=A4(#65)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/status/retweet.cc | 21 +++++++++++++++++++++ src/cocoatweet/api/status/retweet.h | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/cocoatweet/api/status/retweet.cc create mode 100644 src/cocoatweet/api/status/retweet.h diff --git a/src/cocoatweet/api/status/retweet.cc b/src/cocoatweet/api/status/retweet.cc new file mode 100644 index 0000000..0f7877d --- /dev/null +++ b/src/cocoatweet/api/status/retweet.cc @@ -0,0 +1,21 @@ +#include +#include + +namespace CocoaTweet::API::Statuses { + Retweet::Retweet(){} + + void Retweet::id(const std::string& _id){ + contentType_ = "application/x-www-form-urlencoded"; + url_ = "https://api.twitter.com/1.1/statuses/retweet/" + _id + ".json"; + } + + CocoaTweet::API::Model::Tweet Retweet::process(std::weak_ptr _oauth){ + CocoaTweet::API::Model::Tweet tweet; + HttpPost::process(_oauth, + [&tweet](const unsigned int _responseCode, const std::string& _rcv) { + tweet = CocoaTweet::API::Model::Tweet(_responseCode, _rcv); + }); + + return tweet; + } +} diff --git a/src/cocoatweet/api/status/retweet.h b/src/cocoatweet/api/status/retweet.h new file mode 100644 index 0000000..500f5e4 --- /dev/null +++ b/src/cocoatweet/api/status/retweet.h @@ -0,0 +1,18 @@ +#ifndef COCOATWEET_API_STATUS_RETWEET_H_ +#define COCOATWEET_API_STATUS_RETWEET_H_ + +#include +#include + +namespace CocoaTweet::API::Statuses { + class Retweet : public CocoaTweet::API::Interface::HttpPost{ + public: + Retweet(); + + void id(const std::string& _id); + + CocoaTweet::API::Model::Tweet process(std::weak_ptr _oauth); + }; +} + +#endif \ No newline at end of file From 8a06e436ab1f488fd5dd52fb7af94493011405ae Mon Sep 17 00:00:00 2001 From: keita Date: Sun, 14 Mar 2021 23:17:59 +0900 Subject: [PATCH 23/24] =?UTF-8?q?RT=E3=82=92=E5=8F=A9=E3=81=8F=E3=82=84?= =?UTF-8?q?=E3=81=A4=E3=82=92status=E3=82=B0=E3=83=AB=E3=83=BC=E3=83=97?= =?UTF-8?q?=E3=81=AB=E7=B5=B1=E5=90=88(#65)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cocoatweet/api/status/status.cc | 7 +++++++ src/cocoatweet/api/status/status.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/src/cocoatweet/api/status/status.cc b/src/cocoatweet/api/status/status.cc index dff2237..02d3adf 100644 --- a/src/cocoatweet/api/status/status.cc +++ b/src/cocoatweet/api/status/status.cc @@ -1,6 +1,7 @@ #include "cocoatweet/api/status/status.h" #include "cocoatweet/api/status/update.h" #include "cocoatweet/api/status/destroy.h" +#include "cocoatweet/api/status/retweet.h" namespace CocoaTweet::API::Statuses { Status::Status(std::shared_ptr _oauth) { @@ -70,4 +71,10 @@ CocoaTweet::API::Model::Tweet Status::Destroy(const std::string& _id) const { destroy.id(_id); return destroy.process(oauth_); } + +CocoaTweet::API::Model::Tweet Status::Retweet(const std::string& _id) const{ + CocoaTweet::API::Statuses::Retweet retweet; + retweet.id(_id); + return retweet.process(oauth_); +} } // namespace CocoaTweet::API::Statuses diff --git a/src/cocoatweet/api/status/status.h b/src/cocoatweet/api/status/status.h index 034d2cd..3423cb4 100644 --- a/src/cocoatweet/api/status/status.h +++ b/src/cocoatweet/api/status/status.h @@ -6,6 +6,7 @@ #include #include #include + namespace CocoaTweet::API::Statuses { /// @brief Entory point for statuses/* @@ -59,6 +60,8 @@ public: /// @param[out] CocoaTweet::API::Model::Tweet : Destroy result CocoaTweet::API::Model::Tweet Destroy(const std::string& _id) const; + CocoaTweet::API::Model::Tweet Retweet(const std::string& _id) const; + private: Options defaultOpt_; }; From bafa269c4e26350ea52073397fefa7695368fdaf Mon Sep 17 00:00:00 2001 From: keita Date: Sun, 14 Mar 2021 23:18:17 +0900 Subject: [PATCH 24/24] manage README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b700318..01ea18b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ This is a library for using Twitter API from C++ you can use these endpoint - statuses/update - statuses/destroy/:id +- statuses/retweet/:id - favorites/create - favorites/destroy - media/upload(support: jpg, jpeg, png, gif, mp4) @@ -120,6 +121,9 @@ auto media1 = api.media().Upload("path/to/file/image.jpeg"); auto media2 = api.media().Upload("path/to/file/image2.png"); api.status().Update("Upload media from Cocoa Twitter Library", std::vector{media1.id(), media2.id()}); +// Retweet a tweet +api.status().Retweet("tweet id"); + // Delete a tweet api.status().Destroy("tweet id");