Skip to content

Commit

Permalink
Implemented Twitter API v2 Blocking and Unblocking.
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeMayo committed Apr 8, 2021
1 parent bef19b8 commit 08fc64e
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public async Task CreateBlockAsync_Handles_Response()
const bool SkipStatus = true;
var ctx = InitializeTwitterContext();

User actual = await ctx.CreateBlockAsync(Id, null, SkipStatus);
User actual = await ctx.BlockUserAsync(Id, null, SkipStatus);

Assert.AreEqual("LINQ to Tweeter Test", actual.Name);
}
Expand All @@ -67,7 +67,7 @@ public async Task CreateBlockAsync_WithRawResult_Succeeds()
const bool SkipStatus = true;
var ctx = InitializeTwitterContext();

await ctx.CreateBlockAsync(Id, null, SkipStatus);
await ctx.BlockUserAsync(Id, null, SkipStatus);

Assert.AreEqual(BlocksUserJson, ctx.RawResult);
}
Expand All @@ -79,7 +79,7 @@ public async Task CreateBlockAsync_Builds_Url()
const bool SkipStatus = true;
var ctx = InitializeTwitterContext();

await ctx.CreateBlockAsync(Id, null, SkipStatus);
await ctx.BlockUserAsync(Id, null, SkipStatus);

execMock.Verify(exec =>
exec.PostFormUrlEncodedToTwitterAsync<User>(
Expand All @@ -96,7 +96,7 @@ public async Task CreateBlockAsync_Throws_On_Null_UserID_And_ScreenName()
var ctx = InitializeTwitterContext();

var ex = await L2TAssert.Throws<ArgumentException>(
async () => await ctx.CreateBlockAsync(0, null, true));
async () => await ctx.BlockUserAsync(0, null, true));

Assert.AreEqual("UserIDOrScreenName", ex.ParamName);
}
Expand All @@ -108,7 +108,7 @@ public async Task DestroyBlockAsync_Handles_Response()
const bool SkipStatus = true;
var ctx = InitializeTwitterContext();

User actual = await ctx.DestroyBlockAsync(Id, null, SkipStatus);
User actual = await ctx.UnblockUserAsync(Id, null, SkipStatus);

Assert.AreEqual("LINQ to Tweeter Test", actual.Name);
}
Expand All @@ -120,7 +120,7 @@ public async Task DestroyBlockAsync_WithRawResult_Succeeds()
const bool SkipStatus = true;
var ctx = InitializeTwitterContext();

await ctx.DestroyBlockAsync(Id, null, SkipStatus);
await ctx.UnblockUserAsync(Id, null, SkipStatus);

Assert.AreEqual(BlocksUserJson, ctx.RawResult);
}
Expand All @@ -132,7 +132,7 @@ public async Task DestroyBlockAsync_Builds_Url()
const bool SkipStatus = true;
var ctx = InitializeTwitterContext();

await ctx.DestroyBlockAsync(Id, null, SkipStatus);
await ctx.UnblockUserAsync(Id, null, SkipStatus);

execMock.Verify(exec =>
exec.PostFormUrlEncodedToTwitterAsync<User>(
Expand All @@ -149,7 +149,7 @@ public async Task DestroyBlockAsync_Throws_On_No_ID_Or_ScreenName()
var ctx = InitializeTwitterContext();

var ex = await L2TAssert.Throws<ArgumentException>(
async () => await ctx.DestroyBlockAsync(0, null, true));
async () => await ctx.UnblockUserAsync(0, null, true));

Assert.AreEqual("UserIDOrScreenName", ex.ParamName);
}
Expand Down
11 changes: 11 additions & 0 deletions src/LinqToTwitter6/LinqToTwitter/Blocks/BlockingResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Text.Json.Serialization;

namespace LinqToTwitter
{
public class BlockingResponse
{
[JsonPropertyName("data")]
public BlockingResponseData? Data { get; init; }
}
}
10 changes: 10 additions & 0 deletions src/LinqToTwitter6/LinqToTwitter/Blocks/BlockingResponseData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Text.Json.Serialization;

namespace LinqToTwitter
{
public record BlockingResponseData
{
[JsonPropertyName("blocking")]
public bool Blocking { get; set; }
}
}
104 changes: 39 additions & 65 deletions src/LinqToTwitter6/LinqToTwitter/Blocks/TwitterContextBlockCommands.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -10,95 +10,69 @@ namespace LinqToTwitter
public partial class TwitterContext
{
/// <summary>
/// Blocks a user.
/// Block a user.
/// </summary>
/// <param name="userID">ID of user to block</param>
/// <param name="screenName">Screen name of user to block</param>
/// <param name="skipStatus">Don't include status</param>
/// <param name="sourceUserID">Following user ID</param>
/// <param name="targetUserID">Followed user ID</param>
/// <param name="cancelToken">Allows request cancellation</param>
/// <returns>User that was unblocked</returns>
public async Task<User?> CreateBlockAsync(ulong userID, string screenName, bool skipStatus)
public async Task<BlockingResponse?> BlockUserAsync(string sourceUserID, string targetUserID, CancellationToken cancelToken = default(CancellationToken))
{
return await CreateBlockAsync(userID, screenName, true, skipStatus).ConfigureAwait(false);
}

/// <summary>
/// Blocks a user.
/// </summary>
/// <param name="userID">ID of user to block</param>
/// <param name="screenName">Screen name of user to block</param>
/// <param name="includeEntities">Set to false to not include entities (default: true)</param>
/// <param name="skipStatus">Don't include status</param>
/// <returns>User that was unblocked</returns>
public async Task<User?> CreateBlockAsync(ulong userID, string screenName, bool includeEntities, bool skipStatus, CancellationToken cancelToken = default(CancellationToken))
{
if (userID <= 0 && string.IsNullOrWhiteSpace(screenName))
throw new ArgumentException("Either userID or screenName are required parameters.", "UserIDOrScreenName");
_ = sourceUserID ?? throw new ArgumentException($"{nameof(sourceUserID)} is a required parameter.", nameof(sourceUserID));
_ = targetUserID ?? throw new ArgumentException($"{nameof(targetUserID)} is a required parameter.", nameof(targetUserID));

var blocksUrl = BaseUrl + "blocks/create.json";
var url = $"{BaseUrl}users/{sourceUserID}/blocking";

var reqProc = new BlocksRequestProcessor<User>();

var postData = new Dictionary<string, string>();
var postObj = new TwitterUserTargetID() { TargetUserID = targetUserID.ToString() };

RawResult =
await TwitterExecutor.PostFormUrlEncodedToTwitterAsync<User>(
await TwitterExecutor.SendJsonToTwitterAsync(
HttpMethod.Post.ToString(),
blocksUrl,
new Dictionary<string, string?>
{
{ "user_id", userID <= 0 ? null : userID.ToString() },
{ "screen_name", screenName },
{ "include_entities", includeEntities.ToString().ToLower() },
{ "skip_status", skipStatus.ToString().ToLower() }
},
url,
postData,
postObj,
cancelToken)
.ConfigureAwait(false);
.ConfigureAwait(false);

return reqProc.ProcessActionResult(RawResult, UserAction.SingleUser);
}
BlockingResponse? result = JsonSerializer.Deserialize<BlockingResponse>(RawResult);

/// <summary>
/// Unblocks a user.
/// </summary>
/// <param name="userID">ID of user to block</param>
/// <param name="screenName">Screen name of user to block</param>
/// <param name="skipStatus">Don't include status</param>
/// <returns>User that was unblocked</returns>
public async Task<User?> DestroyBlockAsync(ulong userID, string screenName, bool skipStatus, CancellationToken cancelToken = default(CancellationToken))
{
return await DestroyBlockAsync(userID, screenName, true, skipStatus, cancelToken).ConfigureAwait(false);
return result;
}

/// <summary>
/// Unblocks a user.
/// Unblock a user.
/// </summary>
/// <param name="userID">ID of user to block</param>
/// <param name="screenName">Screen name of user to block</param>
/// <param name="includeEntities">Set to false to not include entities (default: true)</param>
/// <param name="skipStatus">Don't include status</param>
/// <param name="sourceUserID">Following user ID</param>
/// <param name="targetUserID">Followed user ID</param>
/// <param name="cancelToken">Allows request cancellation</param>
/// <returns>User that was unblocked</returns>
public async Task<User?> DestroyBlockAsync(ulong userID, string screenName, bool includeEntities, bool skipStatus, CancellationToken cancelToken = default(CancellationToken))
public async Task<BlockingResponse?> UnblockUserAsync(string sourceUserID, string targetUserID, CancellationToken cancelToken = default(CancellationToken))
{
if (userID <= 0 && string.IsNullOrWhiteSpace(screenName))
throw new ArgumentException("Either userID or screenName are required parameters.", "UserIDOrScreenName");
_ = sourceUserID ?? throw new ArgumentException($"{nameof(sourceUserID)} is a required parameter.", nameof(sourceUserID));
_ = targetUserID ?? throw new ArgumentException($"{nameof(targetUserID)} is a required parameter.", nameof(targetUserID));

var blocksUrl = BaseUrl + "blocks/destroy.json";
var url = $"{BaseUrl}users/{sourceUserID}/blocking/{targetUserID}";

var reqProc = new BlocksRequestProcessor<User>();

var postData = new Dictionary<string, string>();
var postObj = new TwitterUserTargetID() { TargetUserID = targetUserID.ToString() };

RawResult =
await TwitterExecutor.PostFormUrlEncodedToTwitterAsync<User>(
HttpMethod.Post.ToString(),
blocksUrl,
new Dictionary<string, string?>
{
{ "user_id", userID <= 0 ? null : userID.ToString() },
{ "screen_name", screenName },
{ "include_entities", includeEntities.ToString().ToLower() },
{ "skip_status", skipStatus.ToString().ToLower() }
},
await TwitterExecutor.SendJsonToTwitterAsync(
HttpMethod.Delete.ToString(),
url,
postData,
postObj,
cancelToken)
.ConfigureAwait(false);
.ConfigureAwait(false);

BlockingResponse? result = JsonSerializer.Deserialize<BlockingResponse>(RawResult);

return reqProc.ProcessActionResult(RawResult, UserAction.SingleUser);
return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
Expand Down

0 comments on commit 08fc64e

Please sign in to comment.