/// <summary> /// Converts the current instance to a <see cref="MethodParameterSet"/>/ /// </summary> /// <returns> /// A <see cref="MethodParameterSet"/>. /// </returns> public MethodParameterSet ToMethodParameterSet() { var result = new MethodParameterSet(parameters); if (State != PostCreationState.Published) result.Add("state", State.ToString().ToLowerInvariant()); if (Tags != null) result.Add("tags", String.Join(",", Tags.ToArray())); if (!String.IsNullOrEmpty(Tweet)) result.Add("tweet", Tweet); if (Date != null) result.Add("date", Date.Value.ToUniversalTime().ToString("R")); if (Format != PostFormat.Html) result.Add("format", Format.ToString().ToLowerInvariant()); if (!String.IsNullOrEmpty(Slug)) result.Add("slug", Slug); return result; }
/// <summary> /// Asynchronously retrieves a specific post by id. /// </summary> /// <param name="id"> /// The id of the post to retrieve. /// </param> /// <param name="includeReblogInfo"> /// Whether or not to include reblog info with the posts. /// </param> /// <param name="includeNotesInfo"> /// Whether or not to include notes info with the posts. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry a <see cref="BasePost"/> instance representing the desired post. Otherwise <see cref="Task.Exception"/> will carry a /// <see cref="TumblrException"/> if the post with the specified id cannot be found. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="id"/> is less than 0. /// </exception> public Task<BasePost> GetPostAsync(long id, bool includeReblogInfo = false, bool includeNotesInfo = false) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (id < 0) throw new ArgumentOutOfRangeException("id", "id must be greater or equal to zero."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("api_key", apiKey); parameters.Add("id", id, 0); parameters.Add("reblog_info", includeReblogInfo, false); parameters.Add("notes_info", includeNotesInfo, false); return CallApiMethodAsync<Posts, BasePost>( new BlogMethod("dummy", "posts", null, HttpMethod.Get, parameters), p => p.Result.FirstOrDefault(), CancellationToken.None); }
/// <summary> /// Asynchronously retrieves the current user's likes. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#m-ug-likes /// </remarks> /// <param name="startIndex"> /// The offset at which to start retrieving the likes. Use 0 to start retrieving from the latest like. /// </param> /// <param name="count"> /// The number of likes to retrieve. Must be between 1 and 20. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry a <see cref="Likes"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="InvalidOperationException"> /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <list type="bullet"> /// <item> /// <description> /// <paramref name="startIndex"/> is less than 0. /// </description> /// </item> /// <item> /// <description> /// <paramref name="count"/> is less than 1 or greater than 20. /// </description> /// </item> /// </list> /// </exception> public Task<Likes> GetUserLikesAsync(int startIndex = 0, int count = 20) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero."); if (count < 1 || count > 20) throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20."); if (OAuthToken == null) throw new InvalidOperationException("GetBlogLikesAsync method requires an OAuth token to be specified."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("offset", startIndex, 0); parameters.Add("limit", count, 0); return CallApiMethodAsync<Likes>( new UserMethod("likes", OAuthToken, HttpMethod.Get, parameters), CancellationToken.None); }
/// <summary> /// Asynchronously retrieves published posts from a blog. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#posts /// </remarks> /// <param name="blogName"> /// The name of the blog. /// </param> /// <param name="startIndex"> /// The offset at which to start retrieving the posts. Use 0 to start retrieving from the latest post. /// </param> /// <param name="count"> /// The number of posts to retrieve. Must be between 1 and 20. /// </param> /// <param name="type"> /// The <see cref="PostType"/> to retrieve. /// </param> /// <param name="includeReblogInfo"> /// Whether or not to include reblog info with the posts. /// </param> /// <param name="includeNotesInfo"> /// Whether or not to include notes info with the posts. /// </param> /// <param name="filter"> /// A <see cref="PostFilter"/> to apply. /// </param> /// <param name="tag"> /// A tag to filter by. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry a <see cref="Posts"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="blogName"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="blogName"/> is empty. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <list type="bullet"> /// <item> /// <description> /// <paramref name="startIndex"/> is less than 0. /// </description> /// </item> /// <item> /// <description> /// <paramref name="count"/> is less than 1 or greater than 20. /// </description> /// </item> /// </list> /// </exception> public Task<Posts> GetPostsAsync(string blogName, long startIndex = 0, int count = 20, PostType type = PostType.All, bool includeReblogInfo = false, bool includeNotesInfo = false, PostFilter filter = PostFilter.Html, string tag = null) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (blogName == null) throw new ArgumentNullException("blogName"); if (blogName.Length == 0) throw new ArgumentException("Blog name cannot be empty.", "blogName"); if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero."); if (count < 1 || count > 20) throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20."); string methodName = null; switch (type) { case PostType.Text: methodName = "posts/text"; break; case PostType.Quote: methodName = "posts/quote"; break; case PostType.Link: methodName = "posts/link"; break; case PostType.Answer: methodName = "posts/answer"; break; case PostType.Video: methodName = "posts/video"; break; case PostType.Audio: methodName = "posts/audio"; break; case PostType.Photo: methodName = "posts/photo"; break; case PostType.Chat: methodName = "posts/chat"; break; case PostType.All: default: methodName = "posts"; break; } MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("api_key", apiKey); parameters.Add("offset", startIndex, 0); parameters.Add("limit", count, 0); parameters.Add("reblog_info", includeReblogInfo, false); parameters.Add("notes_info", includeNotesInfo, false); parameters.Add("filter", filter.ToString().ToLowerInvariant(), "html"); parameters.Add("tag", tag); return CallApiMethodAsync<Posts>( new BlogMethod(blogName, methodName, null, HttpMethod.Get, parameters), CancellationToken.None); }
/// <summary> /// Asynchronously retrieves posts from the current user's dashboard. /// </summary> /// See: http://www.tumblr.com/docs/en/api/v2#m-ug-dashboard /// <param name="sinceId"> /// Return posts that have appeared after the specified ID. Use this parameter to page through the results: first get a set /// of posts, and then get posts since the last ID of the previous set. /// </param> /// <param name="startIndex"> /// The post number to start at. /// </param> /// <param name="count"> /// The number of posts to return. /// </param> /// <param name="type"> /// The <see cref="PostType"/> to return. /// </param> /// <param name="includeReblogInfo"> /// Whether or not the response should include reblog info. /// </param> /// <param name="includeNotesInfo"> /// Whether or not the response should include notes info. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry an array of posts. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="InvalidOperationException"> /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <list type="bullet"> /// <item> /// <description> /// <paramref name="sinceId"/> is less than 0. /// </description> /// </item> /// <item> /// <description> /// <paramref name="startIndex"/> is less than 0. /// </description> /// </item> /// <item> /// <description> /// <paramref name="count"/> is less than 1 or greater than 20. /// </description> /// </item> /// </list> /// </exception> public Task<BasePost[]> GetDashboardPostsAsync(long sinceId = 0, long startIndex = 0, int count = 20, PostType type = PostType.All, bool includeReblogInfo = false, bool includeNotesInfo = false) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (sinceId < 0) throw new ArgumentOutOfRangeException("sinceId", "sinceId must be greater or equal to zero."); if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero."); if (count < 1 || count > 20) throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20."); if (OAuthToken == null) throw new InvalidOperationException("GetDashboardPostsAsync method requires an OAuth token to be specified."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("type", type.ToString().ToLowerInvariant(), "all"); parameters.Add("since_id", sinceId, 0); parameters.Add("offset", startIndex, 0); parameters.Add("limit", count, 0); parameters.Add("reblog_info", includeReblogInfo, false); parameters.Add("notes_info", includeNotesInfo, false); return CallApiMethodAsync<PostCollection, BasePost[]>( new UserMethod("dashboard", OAuthToken, HttpMethod.Get, parameters), r => r.Posts, CancellationToken.None); }
public Task<TagDiscoveryInfo> GetTagDiscovery(Token OAuthToken) { MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("api_key", apiKey); return CallApiMethodAsync<TagDiscoveryInfo>( new ApiMethod("http://api.tumblr.com/v2/tag_discovery", OAuthToken, HttpMethod.Get, parameters), CancellationToken.None); }
/// <summary> /// Asynchronously retrieves submission posts. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#blog-submissions /// </remarks> /// <param name="blogName"> /// The name of the blog for which to retrieve submission posts. /// </param> /// <param name="startIndex"> /// The post number to start at. Pass 0 to start from the first post. /// </param> /// <param name="filter"> /// A <see cref="PostFilter"/> to apply. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry an array of posts. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="blogName"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="blogName"/> is empty. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> is less than 0. /// </exception> /// <exception cref="InvalidOperationException"> /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified. /// </exception> public Task<BasePost[]> GetSubmissionPostsAsync(string blogName, long startIndex = 0, PostFilter filter = PostFilter.Html) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (blogName == null) throw new ArgumentNullException("blogName"); if (blogName.Length == 0) throw new ArgumentException("Blog name cannot be empty.", "blogName"); if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero."); if (OAuthToken == null) throw new InvalidOperationException("GetSubmissionPostsAsync method requires an OAuth token to be specified."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("offset", startIndex); parameters.Add("filter", filter.ToString().ToLowerInvariant(), "html"); return CallApiMethodAsync<PostCollection, BasePost[]>( new BlogMethod(blogName, "posts/submission", OAuthToken, HttpMethod.Get, parameters), r => r.Posts, CancellationToken.None); }
/// <summary> /// Asynchronously reblogs a post. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#reblogging /// </remarks> /// <param name="blogName"> /// The name of the blog where to reblog the psot (must be one of the current user's blogs). /// </param> /// <param name="postId"> /// The identifier of the post to reblog. /// </param> /// <param name="reblogKey"> /// The post reblog key. /// </param> /// <param name="comment"> /// An optional comment to add to the reblog. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry a <see cref="PostCreationInfo"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <list type="bullet"> /// <item> /// <description> /// <paramref name="blogName"/> is <b>null</b>. /// </description> /// </item> /// <item> /// <description> /// <paramref name="reblogKey"/> is <b>null</b>. /// </description> /// </item> /// </list> /// </exception> /// <exception cref="ArgumentException"> /// /// <list type="bullet"> /// <item> /// <description> /// <paramref name="blogName"/> is empty. /// </description> /// </item> /// <item> /// <description> /// <paramref name="reblogKey"/> is empty. /// </description> /// </item> /// </list> /// </exception> /// <exception cref="InvalidOperationException"> /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified. /// </exception> public Task<PostCreationInfo> ReblogAsync(string blogName, long postId, string reblogKey, string comment = null) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (blogName == null) throw new ArgumentNullException("blogName"); if (blogName.Length == 0) throw new ArgumentException("Blog name cannot be empty.", "blogName"); if (postId <= 0) throw new ArgumentException("Post ID must be greater than 0.", "postId"); if (reblogKey == null) throw new ArgumentNullException("reblogKey"); if (reblogKey.Length == 0) throw new ArgumentException("reblogKey cannot be empty.", "reblogKey"); if (OAuthToken == null) throw new InvalidOperationException("ReblogAsync method requires an OAuth token to be specified."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("id", postId); parameters.Add("reblog_key", reblogKey); parameters.Add("comment", comment, null); return CallApiMethodAsync<PostCreationInfo>( new UserMethod("post/reblog", OAuthToken, HttpMethod.Post, parameters), CancellationToken.None); }
/// <summary> /// Asynchronously deletes a post. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#deleting-posts /// </remarks> /// <param name="blogName"> /// The name of the blog to which the post to delete belongs. /// </param> /// <param name="postId"> /// The identifier of the post to delete. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task fails, <see cref="Task.Exception"/> /// will carry a <see cref="TumblrException"/> representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="blogName"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="blogName"/> is empty. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="postId"/> is less than 0. /// </exception> /// <exception cref="InvalidOperationException"> /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified. /// </exception> public Task DeletePostAsync(string blogName, long postId) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (blogName == null) throw new ArgumentNullException("blogName"); if (blogName.Length == 0) throw new ArgumentException("Blog name cannot be empty.", "blogName"); if (postId < 0) throw new ArgumentOutOfRangeException("postId", "Post ID must be greater or equal to zero."); if (OAuthToken == null) throw new InvalidOperationException("DeletePostAsync method requires an OAuth token to be specified."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("id", postId); return CallApiMethodNoResultAsync( new BlogMethod(blogName, "post/delete", OAuthToken, HttpMethod.Post, parameters), CancellationToken.None); }
/// <summary> /// Gets the authorized access token that can be used to make OAuth calls. /// </summary> /// <param name="requestToken"> /// The request token sent from the server to the <b>callback url</b>. /// </param> /// <param name="verifierUrl"> /// The verifier url returned from the server. /// </param> /// <returns> /// The access token. /// </returns> /// <exception cref="ArgumentNullException"> /// <list type="bullet"> /// <item> /// <description> /// <paramref name="requestToken"/> is <b>null</b>. /// </description> /// </item> /// <item> /// <description> /// <paramref name="verifierUrl"/> is <b>null</b>. /// </description> /// </item> /// </list> /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="verifierUrl"/> is empty. /// </exception> /// <exception cref="OAuthException"> /// <list type="bullet"> /// <item> /// <description> /// Could not determine oauth_token and oauth_token_secret from server response. /// </description> /// </item> /// <item> /// <description> /// An exception occurred during the method call. /// </description> /// </item> /// </list> /// </exception> public async Task<Token> GetAccessTokenAsync(Token requestToken, string verifierUrl) { if (requestToken == null) throw new ArgumentNullException("requestToken"); if (verifierUrl == null) throw new ArgumentNullException("verifierUrl"); if (verifierUrl.Length == 0) throw new ArgumentException("Verifier URL cannot be empty.", "verifierUrl"); Uri uri = new Uri(verifierUrl, UriKind.RelativeOrAbsolute); string verifierString = (uri.IsAbsoluteUri) ? uri.Query : verifierUrl; System.Text.RegularExpressions.Match m = oauthVerifierRegEx.Match(verifierString); if (m.Success) { string token = m.Groups["token"].Value; string verifier = m.Groups["verifier"].Value; MethodParameterSet authorizationHeaderParameters = new MethodParameterSet(); authorizationHeaderParameters.Add("oauth_token", token); authorizationHeaderParameters.Add("oauth_verifier", verifier); var requestParameters = new Dictionary<string, string>() { { "oauth_token", token }, { "oauth_verifier", verifier }, }; using (var client = new HttpClient(new OAuthMessageHandler(hashProvider, consumerKey, consumerSecret, requestToken))) { var request = new HttpRequestMessage(HttpMethod.Post, accessTokenUrl); request.Content = new FormUrlEncodedContent(requestParameters); using (var response = await client.SendAsync(request).ConfigureAwait(false)) { if (response.IsSuccessStatusCode) { string tokenString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); System.Text.RegularExpressions.Match m1 = xauthTokensRegEx.Match(tokenString); if (m1.Success) { return new Token(m1.Groups["token"].Value, m1.Groups["secret"].Value); } else { throw new OAuthException("Could not determine oauth_token and oauth_token_secret from server response."); } } else { throw new OAuthException(String.Format("GetAccessTokenAsync failed. Status Code: {0}, Message: {1}", response.StatusCode, response.ReasonPhrase)); } } } } else { throw new OAuthException("Could not parse response to callback URL"); } }
/// <summary> /// Gets the authorized access token that can be used to make OAuth calls. /// </summary> /// <param name="requestToken"> /// The request token sent from the server to the <b>callback url</b>. /// </param> /// <param name="verifierUrl"> /// The verifier url returned from the server. /// </param> /// <returns> /// The access token. /// </returns> /// <exception cref="ArgumentNullException"> /// <list type="bullet"> /// <item> /// <description> /// <paramref name="requestToken"/> is <b>null</b>. /// </description> /// </item> /// <item> /// <description> /// <paramref name="verifierUrl"/> is <b>null</b>. /// </description> /// </item> /// </list> /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="verifierUrl"/> is empty. /// </exception> /// <exception cref="OAuthException"> /// <list type="bullet"> /// <item> /// <description> /// Could not determine oauth_token and oauth_token_secret from server response. /// </description> /// </item> /// <item> /// <description> /// An exception occurred during the method call. /// </description> /// </item> /// </list> /// </exception> public async Task <Token> GetAccessTokenAsync(Token requestToken, string verifierUrl) { if (requestToken == null) { throw new ArgumentNullException("requestToken"); } if (verifierUrl == null) { throw new ArgumentNullException("verifierUrl"); } if (verifierUrl.Length == 0) { throw new ArgumentException("Verifier URL cannot be empty.", "verifierUrl"); } Uri uri = new Uri(verifierUrl, UriKind.RelativeOrAbsolute); string verifierString = (uri.IsAbsoluteUri) ? uri.Query : verifierUrl; System.Text.RegularExpressions.Match m = oauthVerifierRegEx.Match(verifierString); if (m.Success) { string token = m.Groups["token"].Value; string verifier = m.Groups["verifier"].Value; MethodParameterSet authorizationHeaderParameters = new MethodParameterSet(); authorizationHeaderParameters.Add("oauth_token", token); authorizationHeaderParameters.Add("oauth_verifier", verifier); var requestParameters = new Dictionary <string, string>() { { "oauth_token", token }, { "oauth_verifier", verifier }, }; using (var client = new HttpClient(new OAuthMessageHandler(hashProvider, consumerKey, consumerSecret, requestToken))) { var request = new HttpRequestMessage(HttpMethod.Post, accessTokenUrl); request.Content = new FormUrlEncodedContent(requestParameters); using (var response = await client.SendAsync(request).ConfigureAwait(false)) { if (response.IsSuccessStatusCode) { string tokenString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); System.Text.RegularExpressions.Match m1 = xauthTokensRegEx.Match(tokenString); if (m1.Success) { return(new Token(m1.Groups["token"].Value, m1.Groups["secret"].Value)); } else { throw new OAuthException("Could not determine oauth_token and oauth_token_secret from server response."); } } else { throw new OAuthException(String.Format("GetAccessTokenAsync failed. Status Code: {0}, Message: {1}", response.StatusCode, response.ReasonPhrase)); } } } } else { throw new OAuthException("Could not parse response to callback URL"); } }
public Task<Likes> GetUserLikesBeforeAsync(DateTime? before = null, int count = 20) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (count < 1 || count > 20) throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20."); if (OAuthToken == null) throw new InvalidOperationException("GetBlogLikesBeforeAsync method requires an OAuth token to be specified."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("before", before.HasValue ? DateTimeHelper.ToTimestamp(before.Value).ToString() : null, null); parameters.Add("limit", count, 0); return CallApiMethodAsync<Likes>( new UserMethod("likes", OAuthToken, HttpMethod.Get, parameters), CancellationToken.None); }
/// <summary> /// Asynchronously retrieves posts that have been tagged with a specific <paramref name="tag"/>. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#m-up-tagged /// </remarks> /// <param name="tag"> /// The tag on the posts to retrieve. /// </param> /// <param name="before"> /// The timestamp of when to retrieve posts before. /// </param> /// <param name="count"> /// The number of posts to retrieve. /// </param> /// <param name="filter"> /// A <see cref="PostFilter"/>. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry an array of posts. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="tag"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="tag"/> is empty. /// </exception> /// <exception cref="InvalidOperationException"> /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="count"/> is less than 1 or greater than 20. /// </exception> public Task<BasePost[]> GetTaggedPostsAsync(string tag, DateTime before, int count = 20, PostFilter filter = PostFilter.Html) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (tag == null) throw new ArgumentNullException("tag"); if (tag.Length == 0) throw new ArgumentException("Tag cannot be empty.", "tag"); if (count < 1 || count > 20) throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("api_key", apiKey); parameters.Add("tag", tag); return CallApiMethodAsync<BasePost[]>( new ApiMethod("http://api.tumblr.com/v2/tagged", OAuthToken, HttpMethod.Get, parameters), CancellationToken.None, new List<JsonConverter>() { new PostArrayConverter() }); }
/// <summary> /// Asynchronously retrieves the publicly exposed likes from a blog. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#blog-likes /// </remarks> /// <param name="blogName"> /// The name of the blog. /// </param> /// <param name="startIndex"> /// The offset at which to start retrieving the likes. Use 0 to start retrieving from the latest like. /// </param> /// <param name="count"> /// The number of likes to retrieve. Must be between 1 and 20. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry a <see cref="Likes"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="blogName"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="blogName"/> is empty. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <list type="bullet"> /// <item> /// <description> /// <paramref name="startIndex"/> is less than 0. /// </description> /// </item> /// <item> /// <description> /// <paramref name="count"/> is less than 1 or greater than 20. /// </description> /// </item> /// </list> /// </exception> public Task<Likes> GetBlogLikesAsync(string blogName, int startIndex = 0, int count = 20) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (blogName == null) throw new ArgumentNullException("blogName"); if (blogName.Length == 0) throw new ArgumentException("Blog name cannot be empty.", "blogName"); if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero."); if (count < 1 || count > 20) throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("api_key", apiKey); parameters.Add("offset", startIndex, 0); parameters.Add("limit", count, 0); return CallApiMethodAsync<Likes>( new BlogMethod(blogName, "likes", null, HttpMethod.Get, parameters), CancellationToken.None); }
/// <summary> /// Asynchronously unlikes a post. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#m-up-unlike /// </remarks> /// <param name="postId"> /// The identifier of the post to like. /// </param> /// <param name="reblogKey"> /// The reblog key for the post. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task fails, <see cref="Task.Exception"/> /// will carry a <see cref="TumblrException"/> /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="reblogKey"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="reblogKey"/> is empty. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="postId"/> is less than 0. /// </exception> /// <exception cref="InvalidOperationException"> /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified. /// </exception> public Task UnlikeAsync(long postId, string reblogKey) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (postId <= 0) throw new ArgumentException("Post ID must be greater than 0.", "postId"); if (reblogKey == null) throw new ArgumentNullException("reblogKey"); if (reblogKey.Length == 0) throw new ArgumentException("reblogKey cannot be empty.", "reblogKey"); if (OAuthToken == null) throw new InvalidOperationException("UnlikeAsync method requires an OAuth token to be specified."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("id", postId); parameters.Add("reblog_key", reblogKey); return CallApiMethodNoResultAsync( new UserMethod("unlike", OAuthToken, HttpMethod.Post, parameters), CancellationToken.None); }
/// <summary> /// Asynchronously retrieves a blog's followers. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#blog-followers /// </remarks> /// <param name="blogName"> /// The name of the blog. /// </param> /// <param name="startIndex"> /// The offset at which to start retrieving the followers. Use 0 to start retrieving from the latest follower. /// </param> /// <param name="count"> /// The number of followers to retrieve. Must be between 1 and 20. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry a <see cref="Followers"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// A <see cref="Followers"/> instance. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="blogName"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="blogName"/> is empty. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <list type="bullet"> /// <item> /// <description> /// <paramref name="startIndex"/> is less than 0. /// </description> /// </item> /// <item> /// <description> /// <paramref name="count"/> is less than 1 or greater than 20. /// </description> /// </item> /// </list> /// </exception> public Task<Followers> GetFollowersAsync(string blogName, int startIndex = 0, int count = 20) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (blogName == null) throw new ArgumentNullException("blogName"); if (blogName.Length == 0) throw new ArgumentException("Blog name cannot be empty.", "blogName"); if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "startIndex must be greater or equal to zero."); if (count < 1 || count > 20) throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20."); if (OAuthToken == null) throw new InvalidOperationException("GetFollowersAsync method requires an OAuth token to be specified."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("offset", startIndex, 0); parameters.Add("limit", count, 0); return CallApiMethodAsync<Followers>( new BlogMethod(blogName, "followers", OAuthToken, HttpMethod.Get, parameters), CancellationToken.None); }
/// <summary> /// Asynchronously unfollows a blog. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#m-up-unfollow /// </remarks> /// <param name="blogUrl"> /// The url of the blog to unfollow. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task fails, <see cref="Task.Exception"/> /// will carry a <see cref="TumblrException"/> /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="blogUrl"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="blogUrl"/> is empty. /// </exception> /// <exception cref="InvalidOperationException"> /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified. /// </exception> public Task UnfollowAsync(string blogUrl) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (blogUrl == null) throw new ArgumentNullException("blogUrl"); if (blogUrl.Length == 0) throw new ArgumentException("Blog url cannot be empty.", "blogUrl"); if (OAuthToken == null) throw new InvalidOperationException("UnfollowAsync method requires an OAuth token to be specified."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("url", blogUrl); return CallApiMethodNoResultAsync( new UserMethod("unfollow", OAuthToken, HttpMethod.Get, parameters), CancellationToken.None); }
/// <summary> /// Asynchronously retrieves general information about the blog, such as the title, number of posts, and other high-level data. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#blog-info. /// </remarks> /// <param name="blogName"> /// The name of the blog. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry a <see cref="BlogInfo"/> instance. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="blogName"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="blogName"/> is empty. /// </exception> public Task<BlogInfo> GetBlogInfoAsync(string blogName) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (blogName == null) throw new ArgumentNullException("blogName"); if (blogName.Length == 0) throw new ArgumentException("Blog name cannot be empty.", "blogName"); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("api_key", apiKey); return CallApiMethodAsync<BlogInfoResponse, BlogInfo>( new BlogMethod(blogName, "info", OAuthToken, HttpMethod.Get, parameters), r => r.Blog, CancellationToken.None); }
/// <summary> /// Asynchronously retrieves posts that have been tagged with a specific <paramref name="tag"/>. /// </summary> /// <remarks> /// See: http://www.tumblr.com/docs/en/api/v2#m-up-tagged /// </remarks> /// <param name="tag"> /// The tag on the posts to retrieve. /// </param> /// <param name="before"> /// The timestamp of when to retrieve posts before. /// </param> /// <param name="count"> /// The number of posts to retrieve. /// </param> /// <param name="filter"> /// A <see cref="PostFilter"/>. /// </param> /// <returns> /// A <see cref="Task{T}"/> that can be used to track the operation. If the task succeeds, the <see cref="Task{T}.Result"/> will /// carry an array of posts. Otherwise <see cref="Task.Exception"/> will carry a <see cref="TumblrException"/> /// representing the error occurred during the call. /// </returns> /// <exception cref="ObjectDisposedException"> /// The object has been disposed. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="tag"/> is <b>null</b>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="tag"/> is empty. /// </exception> /// <exception cref="InvalidOperationException"> /// This <see cref="TumblrClient"/> instance does not have an OAuth token specified. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="count"/> is less than 1 or greater than 20. /// </exception> public Task<BasePost[]> GetTaggedPostsAsync(string tag, DateTime? before = null, int count = 20, PostFilter filter = PostFilter.Html) { if (disposed) throw new ObjectDisposedException("TumblrClient"); if (tag == null) throw new ArgumentNullException("tag"); if (tag.Length == 0) throw new ArgumentException("Tag cannot be empty.", "tag"); if (count < 1 || count > 20) throw new ArgumentOutOfRangeException("count", "count must be between 1 and 20."); MethodParameterSet parameters = new MethodParameterSet(); parameters.Add("api_key", apiKey); parameters.Add("tag", tag); parameters.Add("before", before.HasValue ? DateTimeHelper.ToTimestamp(before.Value).ToString() : null, null); parameters.Add("limit", count, 0); parameters.Add("filter", filter.ToString().ToLowerInvariant(), "html"); return CallApiMethodAsync<BasePost[]>( new ApiMethod("https://api.tumblr.com/v2/tagged", OAuthToken, HttpMethod.Get, parameters), CancellationToken.None, new JsonConverter[] { new PostArrayConverter() }); }
public async Task<HttpResponseMessage> NewSendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { MethodParameterSet requestParameters = null; if (request.Content is FormUrlEncodedContent) { var formUrlEncoded = request.Content as FormUrlEncodedContent; string content = await formUrlEncoded.ReadAsStringAsync().ConfigureAwait(false); requestParameters = new MethodParameterSet(content); } else if (request.Content is MultipartFormDataContent) { requestParameters = new MethodParameterSet(); var multiPart = request.Content as MultipartFormDataContent; foreach (var c in ((MultipartFormDataContent)request.Content)) { var stringContent = c as StringContent; if (stringContent != null) requestParameters.Add(c.Headers.ContentDisposition.Name, await c.ReadAsStringAsync().ConfigureAwait(false)); } } //NOLONGERAPPLICABLE, REMOVED BY JLAUER - if we have an api_key parameter we can skip the oauth //if (requestParameters.FirstOrDefault(c => c.Name == "api_key") == null) //{ var authorizationHeaderParameters = new MethodParameterSet(requestParameters); if (oAuthToken != null) authorizationHeaderParameters.Add("oauth_token", oAuthToken.Key); authorizationHeaderParameters.Add("oauth_consumer_key", consumerKey); authorizationHeaderParameters.Add("oauth_nonce", Guid.NewGuid().ToString()); authorizationHeaderParameters.Add("oauth_timestamp", DateTimeHelper.ToTimestamp(DateTime.UtcNow).ToString()); authorizationHeaderParameters.Add("oauth_signature_method", "HMAC-SHA1"); authorizationHeaderParameters.Add("oauth_version", "1.0"); string urlParameters = authorizationHeaderParameters.ToFormUrlEncoded(); var requestUriNoQueryString = request.RequestUri.OriginalString; if (!String.IsNullOrEmpty(request.RequestUri.Query)) requestUriNoQueryString = request.RequestUri.OriginalString.Replace(request.RequestUri.Query, String.Empty); string signatureBaseString = String.Format("{0}&{1}&{2}", request.Method.ToString(), UrlEncoder.Encode(requestUriNoQueryString), UrlEncoder.Encode(urlParameters)); string signatureHash = hashProvider.ComputeHash(consumerSecret, (oAuthToken != null) ? oAuthToken.Secret : null, signatureBaseString); authorizationHeaderParameters.Add("oauth_signature", signatureHash); //NOLONGERAPPLICABLE, REMOVED BY JLAUER - if we have an api_key parameter we can skip the oauth //foreach (IMethodParameter p in requestParameters) //{ // //remove non-oauth parameters from the authorization header // if (!p.Name.StartsWith("oauth")) // authorizationHeaderParameters.Remove(p); //} request.Headers.Authorization = new AuthenticationHeaderValue("OAuth", authorizationHeaderParameters.ToAuthorizationHeader()); //} if (request.Method == HttpMethod.Get) request.Content = null; //we don't have to send a body with get requests return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); }
protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { MethodParameterSet requestParameters = null; if (request.Content is FormUrlEncodedContent) { var formUrlEncoded = request.Content as FormUrlEncodedContent; string content = await formUrlEncoded.ReadAsStringAsync().ConfigureAwait(false); requestParameters = new MethodParameterSet(content); } else if (request.Content is MultipartFormDataContent) { requestParameters = new MethodParameterSet(); var multiPart = request.Content as MultipartFormDataContent; foreach (var c in ((MultipartFormDataContent)request.Content)) { var stringContent = c as StringContent; if (stringContent != null) { requestParameters.Add(c.Headers.ContentDisposition.Name, await c.ReadAsStringAsync().ConfigureAwait(false)); } } } //if we have an api_key parameter we can skip the oauth if (requestParameters.FirstOrDefault(c => c.Name == "api_key") == null) { var authorizationHeaderParameters = new MethodParameterSet(requestParameters); if (oAuthToken != null) { authorizationHeaderParameters.Add("oauth_token", oAuthToken.Key); } authorizationHeaderParameters.Add("oauth_consumer_key", consumerKey); authorizationHeaderParameters.Add("oauth_nonce", Guid.NewGuid().ToString()); authorizationHeaderParameters.Add("oauth_timestamp", DateTimeHelper.ToTimestamp(DateTime.UtcNow).ToString()); authorizationHeaderParameters.Add("oauth_signature_method", "HMAC-SHA1"); authorizationHeaderParameters.Add("oauth_version", "1.0"); string urlParameters = authorizationHeaderParameters.ToFormUrlEncoded(); var requestUriNoQueryString = request.RequestUri.OriginalString; if (!String.IsNullOrEmpty(request.RequestUri.Query)) { requestUriNoQueryString = request.RequestUri.OriginalString.Replace(request.RequestUri.Query, String.Empty); } string signatureBaseString = String.Format("{0}&{1}&{2}", request.Method.ToString(), UrlEncoder.Encode(requestUriNoQueryString), UrlEncoder.Encode(urlParameters)); string signatureHash = hashProvider.ComputeHash(consumerSecret, (oAuthToken != null) ? oAuthToken.Secret : null, signatureBaseString); authorizationHeaderParameters.Add("oauth_signature", signatureHash); foreach (IMethodParameter p in requestParameters) { //remove non-oauth parameters from the authorization header if (!p.Name.StartsWith("oauth")) { authorizationHeaderParameters.Remove(p); } } request.Headers.Authorization = new AuthenticationHeaderValue("OAuth", authorizationHeaderParameters.ToAuthorizationHeader()); } if (request.Method == HttpMethod.Get) { request.Content = null; //we don't have to send a body with get requests } return(await base.SendAsync(request, cancellationToken).ConfigureAwait(false)); }