Skip to content

Commit

Permalink
Merge branch 'release/0.39.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Jericho committed Apr 9, 2018
2 parents 638604d + d7f2d3b commit fe2ac8a
Show file tree
Hide file tree
Showing 27 changed files with 945 additions and 21 deletions.
28 changes: 18 additions & 10 deletions Source/StrongGrid.IntegrationTests/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using StrongGrid.Logging;
using StrongGrid.Models;
using StrongGrid.Models.Search;
using StrongGrid.Utilities;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -144,9 +145,12 @@ static async Task<int> Main()

// Return code indicating success/failure
var resultCode = (int)ResultCodes.Success;
if (results.Any(result => result.ResultCode == ResultCodes.Exception)) resultCode = (int)ResultCodes.Exception;
else if (results.Any(result => result.ResultCode == ResultCodes.Cancelled)) resultCode = (int)ResultCodes.Cancelled;
else resultCode = (int)results.First(result => result.ResultCode != ResultCodes.Success).ResultCode;
if (results.Any(result => result.ResultCode != ResultCodes.Success))
{
if (results.Any(result => result.ResultCode == ResultCodes.Exception)) resultCode = (int)ResultCodes.Exception;
else if (results.Any(result => result.ResultCode == ResultCodes.Cancelled)) resultCode = (int)ResultCodes.Cancelled;
else resultCode = (int)results.First(result => result.ResultCode != ResultCodes.Success).ResultCode;
}

return await Task.FromResult(resultCode);
}
Expand Down Expand Up @@ -1203,16 +1207,20 @@ private static async Task EmailActivities(IClient client, TextWriter log, Cancel
await log.WriteLineAsync("\n***** EMAIL ACTIVITIES *****\n").ConfigureAwait(false);

// REQUEST THE ACTIVITIES
var allActivities = await client.EmailActivities.SearchMessagesAsync(20, cancellationToken).ConfigureAwait(false);
var allActivities = await client.EmailActivities.SearchAsync(null, 20, cancellationToken).ConfigureAwait(false);
await log.WriteLineAsync($"Activities requested. Found {allActivities.Count()} activities.").ConfigureAwait(false);

if (!allActivities.Any()) return;

// REQUEST THE ACTIVITIES FOR A SPECIFIC MESSAGE
if (allActivities.Any())
{
var messageId = allActivities.First().MessageId;
var summary = await client.EmailActivities.GetMessageSummaryAsync(messageId, cancellationToken).ConfigureAwait(false);
await log.WriteLineAsync($"There are {summary.Events.Count()} events associated with message {summary.MessageId}.").ConfigureAwait(false);
}
var messageId = allActivities.First().MessageId;
var summary = await client.EmailActivities.GetMessageSummaryAsync(messageId, cancellationToken).ConfigureAwait(false);
await log.WriteLineAsync($"There are {summary.Events.Count()} events associated with message {summary.MessageId}.").ConfigureAwait(false);

// REQUEST THE ACTIVITIES OF A GIVEN TYPE
var activityType = allActivities.First().ActivityType;
var activities = await client.EmailActivities.SearchAsync(new SearchCriteriaEqual(FilterField.ActivityType, activityType), 20, cancellationToken).ConfigureAwait(false);
await log.WriteLineAsync($"There are {activities.Count()} '{activityType}' events.").ConfigureAwait(false);
}

// to get your public IP address we loop through an array
Expand Down
165 changes: 165 additions & 0 deletions Source/StrongGrid.UnitTests/Resources/EmailActivitiesTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using Newtonsoft.Json;
using RichardSzalay.MockHttp;
using Shouldly;
using StrongGrid.Models;
using StrongGrid.Models.Search;
using StrongGrid.Resources;
using StrongGrid.Utilities;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace StrongGrid.UnitTests.Resources
{
public class EmailActivitiesTests
{
#region FIELDS

private const string ENDPOINT = "messages";

private const string SINGLE_MESSAGE = @"{
'from_email': '[email protected]',
'msg_id': 'thtIPCIcR_iFZDws2JCrwA.filter0004p3las1-2776-5ACA5525-31.1',
'subject': 'Dear customer',
'to_email': '[email protected]',
'status': 'delivered',
'opens_count': 2,
'clicks_count': 1,
'last_event_time': '2018-04-08T17:47:18Z'
}";

private const string NO_MESSAGES_FOUND = "{'messages':[]}";
private const string ONE_MESSAGE_FOUND = "{'messages':[" + SINGLE_MESSAGE + "]}";
private const string MULTIPLE_MESSAGES_FOUND = "{'messages':[" +
SINGLE_MESSAGE + "," +
SINGLE_MESSAGE + "," +
SINGLE_MESSAGE +
"]}";

#endregion

[Fact]
public void Parse_json()
{
// Arrange

// Act
var result = JsonConvert.DeserializeObject<EmailMessageActivity>(SINGLE_MESSAGE);

// Assert
result.ShouldNotBeNull();
result.From.ShouldBe("[email protected]");
result.MessageId.ShouldBe("thtIPCIcR_iFZDws2JCrwA.filter0004p3las1-2776-5ACA5525-31.1");
result.Subject.ShouldBe("Dear customer");
result.To.ShouldBe("[email protected]");
result.ActivityType.ShouldBe(EventType.Delivered);
result.OpensCount.ShouldBe(2);
result.ClicksCount.ShouldBe(1);
result.LastEventOn.ShouldBe(new DateTime(2018, 04, 08, 17, 47, 18, DateTimeKind.Utc));
}

[Fact]
public async Task SearchMessages_without_criteria()
{
// Arrange
var limit = 25;

var mockHttp = new MockHttpMessageHandler();
mockHttp.Expect(HttpMethod.Get, Utils.GetSendGridApiUri(ENDPOINT) + $"?limit={limit}&query=").Respond("application/json", NO_MESSAGES_FOUND);

var client = Utils.GetFluentClient(mockHttp);
var emailActivities = (IEmailActivities)new EmailActivities(client);

// Act
var result = await emailActivities.SearchAsync(null, limit, CancellationToken.None).ConfigureAwait(false);

// Assert
mockHttp.VerifyNoOutstandingExpectation();
mockHttp.VerifyNoOutstandingRequest();
result.ShouldNotBeNull();
result.Length.ShouldBe(0);
}

[Fact]
public async Task SearchMessages_single_criteria()
{
// Arrange
var limit = 25;

var mockHttp = new MockHttpMessageHandler();
mockHttp.Expect(HttpMethod.Get, Utils.GetSendGridApiUri(ENDPOINT) + $"?limit={limit}&query=subject%3D%22thevalue%22").Respond("application/json", ONE_MESSAGE_FOUND);

var client = Utils.GetFluentClient(mockHttp);
var emailActivities = (IEmailActivities)new EmailActivities(client);

var criteria = new SearchCriteriaEqual(FilterField.Subject, "thevalue");

// Act
var result = await emailActivities.SearchAsync(criteria, limit, CancellationToken.None).ConfigureAwait(false);

// Assert
mockHttp.VerifyNoOutstandingExpectation();
mockHttp.VerifyNoOutstandingRequest();
result.ShouldNotBeNull();
result.Length.ShouldBe(1);
}

[Fact]
public async Task SearchMessages_multiple_filter_conditions()
{
// Arrange
var limit = 25;

var mockHttp = new MockHttpMessageHandler();
mockHttp.Expect(HttpMethod.Get, Utils.GetSendGridApiUri(ENDPOINT) + $"?limit={limit}&query=campaign_name%3D%22value1%22+AND+unique_args%3D%22value2%22").Respond("application/json", ONE_MESSAGE_FOUND);

var client = Utils.GetFluentClient(mockHttp);
var emailActivities = (IEmailActivities)new EmailActivities(client);

var filterConditions = new[]
{
new SearchCriteriaEqual(FilterField.CampaignName, "value1"),
new SearchCriteriaEqual(FilterField.CustomArguments, "value2"),
};
// Act
var result = await emailActivities.SearchAsync(filterConditions, limit, CancellationToken.None).ConfigureAwait(false);

// Assert
mockHttp.VerifyNoOutstandingExpectation();
mockHttp.VerifyNoOutstandingRequest();
result.ShouldNotBeNull();
result.Length.ShouldBe(1);
}

[Fact]
public async Task SearchMessages_complex_filter_conditions()
{
// Arrange
var limit = 25;

var mockHttp = new MockHttpMessageHandler();
mockHttp.Expect(HttpMethod.Get, Utils.GetSendGridApiUri(ENDPOINT) + $"?limit={limit}&query=campaign_name%3D%22value1%22+OR+msg_id%3D%22value2%22+AND+subject%3D%22value3%22+AND+teammate%3D%22value4%22").Respond("application/json", ONE_MESSAGE_FOUND);

var client = Utils.GetFluentClient(mockHttp);
var emailActivities = new EmailActivities(client);

var filterConditions = new KeyValuePair<SearchLogicalOperator, IEnumerable<SearchCriteria>>[]
{
new KeyValuePair<SearchLogicalOperator, IEnumerable<SearchCriteria>>(SearchLogicalOperator.Or, new[] { new SearchCriteriaEqual(FilterField.CampaignName, "value1"), new SearchCriteriaEqual(FilterField.MessageId, "value2") }),
new KeyValuePair<SearchLogicalOperator, IEnumerable<SearchCriteria>>(SearchLogicalOperator.And, new[] { new SearchCriteriaEqual(FilterField.Subject, "value3"), new SearchCriteriaEqual(FilterField.Teammate, "value4") }),
};

// Act
var result = await emailActivities.SearchAsync(filterConditions, limit, CancellationToken.None).ConfigureAwait(false);

// Assert
mockHttp.VerifyNoOutstandingExpectation();
mockHttp.VerifyNoOutstandingRequest();
result.ShouldNotBeNull();
result.Length.ShouldBe(1);
}
}
}
6 changes: 3 additions & 3 deletions Source/StrongGrid/Models/EmailMessageActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class EmailMessageActivity
/// <value>
/// The 'from' address.
/// </value>
[JsonProperty("from_message", NullValueHandling = NullValueHandling.Ignore)]
[JsonProperty("from_email", NullValueHandling = NullValueHandling.Ignore)]
public string From { get; set; }

/// <summary>
Expand Down Expand Up @@ -45,13 +45,13 @@ public class EmailMessageActivity
public string To { get; set; }

/// <summary>
/// Gets or sets the status.
/// Gets or sets the type of activity.
/// </summary>
/// <value>
/// The status.
/// </value>
[JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)]
public string Status { get; set; }
public EventType ActivityType { get; set; }

/// <summary>
/// Gets or sets the number of time the message was opened by the recipient.
Expand Down
10 changes: 10 additions & 0 deletions Source/StrongGrid/Models/EventType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ public enum EventType
[EnumMember(Value = "dropped")]
Dropped,

/// <summary>
/// Message has not been delivered
/// </summary>
/// <remarks>
/// I believe this is equivalent to 'Dropped'. I have only seen this EventType in the data
/// returned by the 'SearchAsync' method.
/// </remarks>
[EnumMember(Value = "not_delivered")]
NotDelivered,

/// <summary>
/// Message has been successfully delivered to the receiving server.
/// </summary>
Expand Down
136 changes: 136 additions & 0 deletions Source/StrongGrid/Models/Search/FilterField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
using System.Runtime.Serialization;

namespace StrongGrid.Models.Search
{
/// <summary>
/// Enumeration to indicate the filter field when searching for email activities
/// </summary>
public enum FilterField
{
/// <summary>
/// The identifier of the message
/// </summary>
[EnumMember(Value = "msg_id")]
MessageId,

/// <summary>
/// The email address of the sender
/// </summary>
[EnumMember(Value = "from_email ")]
From,

/// <summary>
/// The subject of the message
/// </summary>
[EnumMember(Value = "subject")]
Subject,

/// <summary>
/// The email address of the recipient
/// </summary>
[EnumMember(Value = "to_email")]
To,

/// <summary>
/// The type of email activity
/// </summary>
[EnumMember(Value = "status")]
ActivityType,

/// <summary>
/// The identifier of the template
/// </summary>
[EnumMember(Value = "template_id")]
TemplateId,

/// <summary>
/// The name of the template
/// </summary>
[EnumMember(Value = "template_name")]
TemplateName,

/// <summary>
/// The name of the campaign
/// </summary>
[EnumMember(Value = "campaign_name")]
CampaignName,

/// <summary>
/// The identifier of the campaign
/// </summary>
[EnumMember(Value = "campaign_id")]
CampaignId,

/// <summary>
/// The identifier of the Api Key
/// </summary>
[EnumMember(Value = "api_key_id")]
ApiKeyId,

/// <summary>
/// The name of the Api Key
/// </summary>
[EnumMember(Value = "api_key_name")]
ApiKeyName,

/// <summary>
/// Seems like a duplicate of 'status'.
/// </summary>
[EnumMember(Value = "events")]
Events,

/// <summary>
/// IP address of the person who sent the message
/// </summary>
[EnumMember(Value = "originating_ip")]
OriginatingIpAddress,

/// <summary>
/// Custom tags that you create
/// </summary>
[EnumMember(Value = "categories")]
Categories,

/// <summary>
/// Custom tracking arguments that you can attach to messages
/// </summary>
[EnumMember(Value = "unique_args")]
CustomArguments,

/// <summary>
/// The SendGrid dedicated IP address used to send the email
/// </summary>
[EnumMember(Value = "outbound_ip")]
OutboundIpAddress,

/// <summary>
/// Date and time of the last email activity
/// </summary>
[EnumMember(Value = "last_event_time")]
LastEventTime,

/// <summary>
/// Number of clicks
/// </summary>
[EnumMember(Value = "clicks")]
Clicks,

/// <summary>
/// The name of the unsubscribe group
/// </summary>
[EnumMember(Value = "unsubscribe_group_name")]
UnsubscribeGroupName,

/// <summary>
/// The identified of the unsubscribe group
/// </summary>
[EnumMember(Value = "unsubscribe_group_id")]
UnsubscribeGroupId,

/// <summary>
/// The teamates username
/// </summary>
[EnumMember(Value = "teammate")]
Teammate
}
}
Loading

0 comments on commit fe2ac8a

Please sign in to comment.