Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New pr #5

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions EventbriteApiV3/.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package>
<metadata>
<id>EventbriteApiV3</id>
<version>1.0.1</version>
<version>1.0.5</version>
<title>EventbriteApiV3</title>
<authors>David O'Neill</authors>
<owners>David O'Neill</owners>
Expand All @@ -11,7 +11,7 @@
<repository>https://github.com/DTONeill/EventbriteApiV3</repository>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Wrapper in top of Eventbrite api v3. It allow you to fetch attendees and events easily using your application key.</description>
<releaseNotes>1.0.1 release includes async support</releaseNotes>
<releaseNotes>Adding Venue Retrieval support</releaseNotes>
<tags>eventbrite api events</tags>
<dependencies>
<dependency id="Newtonsoft.Json" version="12.0.2" />
Expand Down
12 changes: 10 additions & 2 deletions EventbriteApiV3/BaseSearchCriterias.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class BaseSearchCriterias : ICloneable

public BaseSearchCriterias() : this(new Dictionary<string, string>())
{

}

private BaseSearchCriterias(Dictionary<string, string> criterias)
Expand All @@ -33,9 +33,17 @@ public virtual BaseSearchCriterias Add(string key, string value)
{
Criterias.Remove(key);
Criterias.Add(key, value);

return this;
}
// note: should be on EventSearchCriteria but Context works on BaseSearchCriteria
/// <summary>
/// if set to true, will do an extra round trip to get the full event description
/// </summary>
internal bool RetrieveFullDescription { get; set; }

// note: should be on EventSearchCriteria but Context works on BaseSearchCriteria
internal bool RetrieveVenueInformation { get; set; }

public NameValueCollection ToNameValueCollection()
{
Expand Down
82 changes: 76 additions & 6 deletions EventbriteApiV3/EventbriteContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
using EventbriteApiV3.Attendees;
using EventbriteApiV3.Events;
using EventbriteApiV3.Helpers;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace EventbriteApiV3
Expand All @@ -21,15 +27,79 @@ public EventsSearchApiResponse GetEvents(BaseSearchCriterias searchCriterias)
{
return new EventSearchEventbriteRequest(this, searchCriterias).GetResponse();
}
private async Task FillDescriptions(BaseSearchCriterias searchCriterias, IList<Event> events)
{
if (searchCriterias.RetrieveFullDescription)
{
try
{
//note: we cannot request a lot of
// parrallel requests on most api's
// that is considered 'rude' and often is throttled down.
var tasks = events.Select(x => new { x, DescriptionTask = new EventDescriptionRequest(this, x.Id).GetResponseAsync() });
await tasks.ForEachAsync(4, async (x) => x.x.LongDescription = new Model.TextHtmlString { Html = (await x.DescriptionTask).Description });
}
catch (Exception ex)
{
Trace.TraceError("FillDescriptions failed with {0}", ex);
}
}
}

private async Task FillVenues(BaseSearchCriterias searchCriterias, IList<Event> events)
{
if (searchCriterias.RetrieveVenueInformation)
{
var venueIds = events
.Where(w => w.VenueId != null)
.Select(s => s.VenueId.Value).Distinct().ToArray();

public Task<EventsSearchApiResponse> GetEventsAsync(BaseSearchCriterias searchCriterias)
try
{
var tasks = venueIds.Select(x => new { key = x, VenueTask = new VenueRequest(this, x).GetResponseAsync() });
var concurrentDict = new ConcurrentDictionary<long, Venue>();
await tasks.ForEachAsync(4, async (x) =>
{
try
{
var venue = await x.VenueTask;
concurrentDict.TryAdd(x.key, venue);
}
catch(Exception ex)
{
Trace.TraceError($"Cannot associate venueid {x.key} with retrieved object {ex.Message}");
}
});
foreach (var @event in events)
{
if (@event.VenueId != null)
{
concurrentDict.TryGetValue(@event.VenueId.Value, out Venue venue);
@event.Venue = venue;
}
}
}
catch (Exception ex)
{
Trace.TraceError("FillVenues failed with {0}", ex);
}
}
}

public async Task<EventsSearchApiResponse> GetEventsAsync(BaseSearchCriterias searchCriterias)
{
return (new EventSearchEventbriteRequest(this, searchCriterias)).GetResponseAsync();
var values = await (new EventSearchEventbriteRequest(this, searchCriterias)).GetResponseAsync();
await FillDescriptions(searchCriterias, values.Events);
await FillVenues(searchCriterias, values.Events);
return values;
}

public Task<EventsSearchApiResponse> GetEventsByOrganization(long organisationId, BaseSearchCriterias searchCriterias)
{
return (new EventsOrganizationRequest(this, organisationId, searchCriterias)).GetResponseAsync();

public async Task<EventsSearchApiResponse> GetEventsByOrganization(long organisationId, BaseSearchCriterias searchCriterias)
{
var values = await (new EventsOrganizationRequest(this, organisationId, searchCriterias)).GetResponseAsync();
await FillDescriptions(searchCriterias, values.Events);
await FillVenues(searchCriterias, values.Events);
return values;
}

public AttendeeSearchApiResponse GetAttendees(double eventId, BaseSearchCriterias searchCriterias)
Expand Down
15 changes: 9 additions & 6 deletions EventbriteApiV3/EventbriteRequestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;

Expand All @@ -19,7 +20,7 @@ public Uri Url
get
{
var uri = new UriBuilder();
uri.Scheme = "https://";
uri.Scheme = Uri.UriSchemeHttps;
uri.Host = Context.Uri;
uri.Path = _path;

Expand All @@ -40,7 +41,8 @@ protected EventbriteRequestBase(string path, EventbriteContext context, NameValu
protected string GetJsonResponse()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.Headers.Add("authorization", $"Bearer {Context.AppKey}");
request.Headers.Add(HttpRequestHeader.Authorization, $"Bearer {Context.AppKey}");
request.Headers.Add(HttpRequestHeader.ContentType, "application/json");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

using (Stream stream = response.GetResponseStream())
Expand All @@ -53,9 +55,9 @@ protected string GetJsonResponse()
protected async Task<string> GetJsonResponseAsync()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.Headers.Add("authorization", $"Bearer {Context.AppKey}");
request.Headers.Add(HttpRequestHeader.Authorization, $"Bearer {Context.AppKey}");
request.Headers.Add(HttpRequestHeader.ContentType, "application/json");
var response = await request.GetResponseAsync();

using (Stream stream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(stream))
{
Expand All @@ -66,8 +68,9 @@ protected async Task<string> GetJsonResponseAsync()
protected async Task<TextReader> GetStreamResponseAsync()
{
var request = WebRequest.Create(Url);
request.Headers.Add("authorization", $"Bearer {Context.AppKey}");
return new StreamReader((await request.GetResponseAsync()).GetResponseStream());
request.Headers.Add(HttpRequestHeader.Authorization, $"Bearer {Context.AppKey}");
request.Headers.Add(HttpRequestHeader.ContentType, "application/json");
return new StreamReader((await request.GetResponseAsync()).GetResponseStream());
}
}
}
44 changes: 44 additions & 0 deletions EventbriteApiV3/Events/Address.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Newtonsoft.Json;
using System.Collections.Generic;

namespace EventbriteApiV3.Events
{
public class Address
{
[JsonProperty("address1")]
public string Line1 { get; set; }

[JsonProperty("address2")]
public string Line2 { get; set; }

[JsonProperty("city")]
public string City { get; set; }

[JsonProperty("region")]
public string Region { get; set; }

[JsonProperty("postal_code")]
public string PostalCode { get; set; }

/// <summary>
/// ISO 2 character
/// </summary>
[JsonProperty("country")]
public string Country { get; set; }

[JsonProperty("latitude")]
public double? Latitude { get; set; }

[JsonProperty("longitude")]
public double? Longitude { get; set; }

[JsonProperty("localized_address_display")]
public string LocalizedAddressDisplay { get; set; }

[JsonProperty("localized_area_display")]
public string LocalizedAreaDisplay { get; set; }

[JsonProperty("localized_multi_line_address_display")]
public IEnumerable<string> LocalizedMultiLineAddressDisplay { get; set; }
}
}
25 changes: 25 additions & 0 deletions EventbriteApiV3/Events/Event.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ namespace EventbriteApiV3.Events
{
public class Event
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("category_id")]
public int? CategoryId { get; set; }
[JsonProperty("name")]
public TextHtmlString Name { get; set; }

[JsonProperty("description")]
public TextHtmlString Description { get; set; }

[JsonProperty("summary")]
public string Summary { get; set; }

[JsonProperty("long_description")]
public TextHtmlString LongDescription { get; set; }

Expand All @@ -28,5 +35,23 @@ public class Event

[JsonProperty("is_free")]
public string IsFree { get; set; }

[JsonProperty("logo")]
public Logo Logo { get; set; }

/// <summary>
/// location/ venue reference
/// </summary>
[JsonProperty("venue_id")]
internal long? VenueId { get; set; }

[JsonProperty("venue")]
public Venue Venue { get; set; }

/// <summary>
/// true if the event is online only
/// </summary>
[JsonProperty("online_event")]
public bool? OnlineEvent { get; set; }
}
}
24 changes: 24 additions & 0 deletions EventbriteApiV3/Events/EventDescriptionRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace EventbriteApiV3.Events
{
public class EventDescriptionRequest : EventbriteRequestBase
{

private const string Path = "events/{0}/description/";
public EventDescriptionRequest(EventbriteContext context, long eventId)
: base(string.Format(Path, eventId), context)
{

}
public async Task<EventsDescriptionResponse> GetResponseAsync()
{
using (var response = await GetStreamResponseAsync())
{
var JsonSerializer = new JsonSerializer();
return JsonSerializer.Deserialize<EventsDescriptionResponse>(new JsonTextReader(response));
}
}
}
}
19 changes: 19 additions & 0 deletions EventbriteApiV3/Events/EventSearchCriterias.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,24 @@ public EventSearchCriterias OrderBy(SortOrder sort)

return this;
}

/// <summary>
/// adds full / long description to event.
/// </summary>
public EventSearchCriterias AddFullEventDescription()
{
RetrieveFullDescription = true;
return this;
}

/// <summary>
/// adds venue information to event.
/// </summary>
public EventSearchCriterias AddVenueInformation()
{
RetrieveVenueInformation = true;
return this;
}

}
}
1 change: 1 addition & 0 deletions EventbriteApiV3/Events/EventSearchEventbriteRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public EventsSearchApiResponse GetResponse()
var response = GetJsonResponse();
return JsonConvert.DeserializeObject<EventsSearchApiResponse>(response);
}

public async Task<EventsSearchApiResponse> GetResponseAsync()
{
var response = await GetJsonResponseAsync();
Expand Down
13 changes: 13 additions & 0 deletions EventbriteApiV3/Events/EventsDescriptionResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Newtonsoft.Json;

namespace EventbriteApiV3.Events
{
public class EventsDescriptionResponse
{
/// <summary>
/// description containing html markup
/// </summary>
[JsonProperty("description")]
public string Description { get; set; }
}
}
17 changes: 11 additions & 6 deletions EventbriteApiV3/Events/EventsOrganizationRequest.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using Newtonsoft.Json;
using System;
using System.Threading.Tasks;

namespace EventbriteApiV3.Events
{
public class EventsOrganizationRequest: EventbriteRequestBase
public class EventsOrganizationRequest : EventbriteRequestBase
{
private const string Path = "organizations/{0}/events/";
private readonly static Lazy<JsonSerializer> JsonSerializerLazy = new Lazy<JsonSerializer>(() => JsonSerializer.CreateDefault( new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }));

public EventsOrganizationRequest(EventbriteContext context, long organizationId, BaseSearchCriterias criterias)
: base(string.Format(Path, organizationId), context, criterias.ToNameValueCollection())
{
Expand All @@ -14,10 +17,12 @@ public EventsOrganizationRequest(EventbriteContext context, long organizationId,

public async Task<EventsSearchApiResponse> GetResponseAsync()
{
var response = await GetStreamResponseAsync();
var JsonSerializer = new JsonSerializer();
var result = JsonSerializer.Deserialize< EventsSearchApiResponse>(new JsonTextReader( response ));
return result;
using (var response = await GetStreamResponseAsync())
using (var tr = new JsonTextReader(response))
{
var jsonSerializer = JsonSerializerLazy.Value;
return jsonSerializer.Deserialize<EventsSearchApiResponse>(tr);
}
}
}
}
}
Loading