8000 Add support for "users/{id}/recommendations/{type}/{sort}" GET request by henrikfroehling · Pull Request #183 · henrikfroehling/Trakt.NET · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
This repository was archived by the owner on Mar 16, 2025. It is now read-only.

Add support for "users/{id}/recommendations/{type}/{sort}" GET request #183

Merged
merged 8 commits into from
Sep 13, 2020
Merged
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
27 changes: 27 additions & 0 deletions Source/Lib/Trakt.NET/Enums/TraktRecommendationObjectType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace TraktNet.Enums
{
/// <summary>Determines the type of an object in a recommendation.</summary>
public sealed class TraktRecommendationObjectType : TraktEnumeration
{
/// <summary>An invalid object type.</summary>
public static TraktRecommendationObjectType Unspecified { get; } = new TraktRecommendationObjectType();

/// <summary>The recommendation contains a movie.</summary>
public static TraktRecommendationObjectType Movie { get; } = new TraktRecommendationObjectType(1, "movie", "movies", "Movie");

/// <summary>The recommendation contains a show.</summary>
public static TraktRecommendationObjectType Show { get; } = new TraktRecommendationObjectType(2, "show", "shows", "Show");

/// <summary>
/// Initializes a new instance of the <see cref="TraktRecommendationObjectType" /> class.<para />
/// The initialized <see cref="TraktRecommendationObjectType" /> is invalid.
/// </summary>
public TraktRecommendationObjectType()
{
}

private TraktRecommendationObjectType(int value, string objectName, string uriName, string displayName) : base(value, objectName, uriName, displayName)
{
}
}
}
44 changes: 44 additions & 0 deletions Source/Lib/Trakt.NET/Modules/TraktUsersModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,50 @@ public Task<TraktPagedResponse<ITraktHistoryItem>> GetWatchedHistoryAsync(string
cancellationToken);
}

/// <summary>
/// Gets an user's personal recommendations for movies and / or shows.
/// <para>OAuth authorization required.</para>
/// <para>
/// See <a href="https://trakt.docs.apiary.io/#reference/users/personal-recommendations/get-personal-recommendations">"Trakt API Doc - Users: Personal Recommendations"</a> for more information.
/// </para>
/// </summary>
/// <param name="usernameOrSlug">The username or slug of the user, for which the recommendations should be queried.</param>
/// <param name="recommendationObjectType">Determines, which type of recommendation items should be queried. See also <seealso cref="TraktRecommendationObjectType" />.</param>
/// <param name="sortOrder">
/// The recommendations sort order. See also <seealso cref="TraktWatchlistSortOrder" />.
/// Will be ignored, if the given array contains a number higher than 10 or below 1 or if it contains more than ten numbers.
/// Will be ignored, if the given <paramref name="recommendationObjectType" /> is null or unspecified.
/// </param>
/// <param name="extendedInfo">
/// The extended info, which determines how much data about the recommendation items should be queried.
/// See also <seealso cref="TraktExtendedInfo" />.
/// </param>
/// <param name="pagedParameters">Specifies pagination parameters. <see cref="TraktPagedParameters" />.</param>
/// <param name="cancellationToken">
/// Propagates notification that the request should be canceled.<para/>
/// If provided, the exception <see cref="OperationCanceledException" /> should be catched.
/// </param>
/// <returns>A list of <see cref="ITraktRecommendation" /> instances.</returns>
/// <exception cref="TraktException">Thrown, if the request fails.</exception>
/// <exception cref="ArgumentException">Thrown, if the given username or slug is null, empty or contains spaces.</exception>
public Task<TraktPagedResponse<ITraktRecommendation>> GetPersonalRecommendationsAsync(string usernameOrSlug, TraktRecommendationObjectType recommendationObjectType = null,
TraktWatchlistSortOrder sortOrder = null, TraktExtendedInfo extendedInfo = null,
TraktPagedParameters pagedParameters = null, CancellationToken cancellationToken = default)
{
var requestHandler = new RequestHandler(Client);

return requestHandler.ExecutePagedRequestAsync(new UserPersonalRecommendationsRequest
{
Username = usernameOrSlug,
Type = recommendationObjectType,
Sort = sortOrder,
6D47 ExtendedInfo = extendedInfo,
Page = pagedParameters?.Page,
Limit = pagedParameters?.Limit
},
cancellationToken);
}

/// <summary>
/// Gets an user's ratings for movies, shows, seasons and / or episodes.
/// <para>OAuth authorization optional.</para>
Expand Down
37 changes: 37 additions & 0 deletions Source/Lib/Trakt.NET/Objects/Get/Users/ITraktRecommendation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace TraktNet.Objects.Get.Users
{
using Enums;
using Movies;
using Shows;
using System;

/// <summary>A Trakt recommendation.</summary>
public interface ITraktRecommendation
{
/// <summary>Gets or sets the recommendation rank.</summary>
int? Rank { get; set; }

/// <summary>Gets or sets the UTC datetime, when the recommendation was listed.</summary>
DateTime? ListedAt { get; set; }

/// <summary>Gets or sets the recommendation item type. See also <seealso cref="TraktRecommendationObjectType" />.<para>Nullable</para></summary>
TraktRecommendationObjectType Type { get; set; }

/// <summary>Gets or sets the recommendation notes.</summary>
string Notes { get; set; }

/// <summary>
/// Gets or sets the movie, if <see cref="Type" /> is <see cref="TraktRecommendationObjectType.Movie" />.
/// See also <seealso cref="ITraktShow" />.
/// <para>Nullable</para>
/// </summary>
ITraktMovie Movie { get; set; }

/// <summary>
/// Gets or sets the show, if <see cref="Type" /> is <see cref="TraktRecommendationObjectType.Show" />.
/// See also <seealso cref="ITraktShow" />.
/// <para>Nullable</para>
/// </summary>
ITraktShow Show { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace TraktNet.Objects.Get.Users
{
using Enums;
using Movies;
using Shows;
using System;

/// <summary>A Trakt recommendation.</summary>
public class TraktRecommendation : ITraktRecommendation
{
/// <summary>Gets or sets the recommendation rank.</summary>
public int? Rank { get; set; }

/// <summary>Gets or sets the UTC datetime, when the recommendation was listed.</summary>
public DateTime? ListedAt { get; set; }

/// <summary>Gets or sets the recommendation item type. See also <seealso cref="TraktRecommendationObjectType" />.<para>Nullable</para></summary>
public TraktRecommendationObjectType Type { get; set; }

/// <summary>Gets or sets the recommendation notes.</summary>
public string Notes { get; set; }

/// <summary>
/// Gets or sets the movie, if <see cref="Type" /> is <see cref="TraktRecommendationObjectType.Movie" />.
/// See also <seealso cref="ITraktShow" />.
/// <para>Nullable</para>
/// </summary>
public ITraktMovie Movie { get; set; }

/// <summary>
/// Gets or sets the show, if <see cref="Type" /> is <see cref="TraktRecommendationObjectType.Show" />.
/// See also <seealso cref="ITraktShow" />.
/// <para>Nullable</para>
/// </summary>
public ITraktShow Show { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace TraktNet.Objects.Get.Users.Json.Factories
{
using Get.Users.Json.Reader;
using Get.Users.Json.Writer;
using Objects.Json;

internal class RecommendationJsonIOFactory : IJsonIOFactory<ITraktRecommendation>
{
public IObjectJsonReader<ITraktRecommendation> CreateObjectReader() => new RecommendationObjectJsonReader();

public IObjectJsonWriter<ITraktRecommendation> CreateObjectWriter() => new RecommendationObjectJsonWriter();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
namespace TraktNet.Objects.Get.Users.Json.Reader
{
using Enums;
using Movies.Json.Reader;
using Newtonsoft.Json;
using Objects.Json;
using Shows.Json.Reader;
using System.Threading;
using System.Threading.Tasks;

internal class RecommendationObjectJsonReader : AObjectJsonReader<ITraktRecommendation>
{
public override async Task<ITraktRecommendation> ReadObjectAsync(JsonTextReader jsonReader, CancellationToken cancellationToken = default)
{
CheckJsonTextReader(jsonReader);

if (await jsonReader.ReadAsync(cancellationToken) && jsonReader.TokenType == JsonToken.StartObject)
{
var movieObjectReader = new MovieObjectJsonReader();
var showObjectReader = new ShowObjectJsonReader();
ITraktRecommendation traktRecommendation = new TraktRecommendation();

while (await jsonReader.ReadAsync(cancellationToken) && jsonReader.TokenType == JsonToken.PropertyName)
{
var propertyName = jsonReader.Value.ToString();

switch (propertyName)
{
case JsonProperties.PROPERTY_NAME_RANK:
traktRecommendation.Rank = await jsonReader.ReadAsInt32Async(cancellationToken).ConfigureAwait(false);
break;
case JsonProperties.PROPERTY_NAME_LISTED_AT:
{
var value = await JsonReaderHelper.ReadDateTimeValueAsync(jsonReader, cancellationToken).ConfigureAwait(false);

if (value.First)
traktRecommendation.ListedAt = value.Second;

break;
}
case JsonProperties.PROPERTY_NAME_TYPE:
traktRecommendation.Type = await JsonReaderHelper.ReadEnumerationValueAsync<TraktRecommendationObjectType>(jsonReader, cancellationToken).ConfigureAwait(false);
break;
case JsonProperties.PROPERTY_NAME_NOTES:
traktRecommendation.Notes = await jsonReader.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
break;
case JsonProperties.PROPERTY_NAME_MOVIE:
traktRecommendation.Movie = await movieObjectReader.ReadObjectAsync(jsonReader, cancellationToken).ConfigureAwait(false);
break;
case JsonProperties.PROPERTY_NAME_SHOW:
traktRecommendation.Show = await showObjectReader.ReadObjectAsync(jsonReader, cancellationToken).ConfigureAwait(false);
break;
default:
await JsonReaderHelper.ReadAndIgnoreInvalidContentAsync(jsonReader, cancellationToken).ConfigureAwait(false);
break;
}
}

return traktRecommendation;
}

return await Task.FromResult(default(ITraktRecommendation));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
namespace TraktNet.Objects.Get.Users.Json.Writer
{
using Enums;
using Extensions;
using Movies.Json.Writer;
using Newtonsoft.Json;
using Objects.Json;
using Shows.Json.Writer;
using System.Threading;
using System.Threading.Tasks;

internal class RecommendationObjectJsonWriter : AObjectJsonWriter<ITraktRecommendation>
{
public override async Task WriteObjectAsync(JsonTextWriter jsonWriter, ITraktRecommendation obj, CancellationToken cancellationToken = default)
{
CheckJsonTextWriter(jsonWriter);
await jsonWriter.WriteStartObjectAsync(cancellationToken).ConfigureAwait(false);

if (obj.Rank.HasValue)
{
await jsonWriter.WritePropertyNameAsync(JsonProperties.PROPERTY_NAME_RANK, cancellationToken).ConfigureAwait(false);
await jsonWriter.WriteValueAsync(obj.Rank.Value, cancellationToken).ConfigureAwait(false);
}

if (obj.ListedAt.HasValue)
{
await jsonWriter.WritePropertyNameAsync(JsonProperties.PROPERTY_NAME_LISTED_AT, cancellationToken).ConfigureAwait(false);
await jsonWriter.WriteValueAsync(obj.ListedAt.Value.ToTraktLongDateTimeString(), cancellationToken).ConfigureAwait(false);
}

if (obj.Type != null && obj.Type != TraktRecommendationObjectType.Unspecified)
{
await jsonWriter.WritePropertyNameAsync(JsonProperties.PROPERTY_NAME_TYPE, cancellationToken).ConfigureAwait(false);
await jsonWriter.WriteValueAsync(obj.Type.ObjectName, cancellationToken).ConfigureAwait(false);
}

if (!string.IsNullOrEmpty(obj.Notes))
{
await jsonWriter.WritePropertyNameAsync(JsonProperties.PROPERTY_NAME_NOTES, cancellationToken).ConfigureAwait(false);
await jsonWriter.WriteValueAsync(obj.Notes, cancellationToken).ConfigureAwait(false);
}

if (obj.Movie != null)
{
var movieObjectJsonWriter = new MovieObjectJsonWriter();
await jsonWriter.WritePropertyNameAsync(JsonProperties.PROPERTY_NAME_MOVIE, cancellationToken).ConfigureAwait(false);
await movieObjectJsonWriter.WriteObjectAsync(jsonWriter, obj.Movie, cancellationToken).ConfigureAwait(false);
}

if (obj.Show != null)
{
var showObjectJsonWriter = new ShowObjectJsonWriter();
await jsonWriter.WritePropertyNameAsync(JsonProperties.PROPERTY_NAME_SHOW, cancellationToken).ConfigureAwait(false);
await showObjectJsonWriter.WriteObjectAsync(jsonWriter, obj.Show, cancellationToken).ConfigureAwait(false);
}

await jsonWriter.WriteEndObjectAsync(cancellationToken).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ static JsonFactoryContainer()
s_jsonIOFactories.Add(typeof(ITraktUserWatchingItem), new UserWatchingItemJsonIOFactory());
s_jsonIOFactories.Add(typeof(ITraktAccountSettings), new AccountSettingsJsonIOFactory());
s_jsonIOFactories.Add(typeof(ITraktSharingText), new SharingTextJsonIOFactory());
s_jsonIOFactories.Add(typeof(ITraktRecommendation), new RecommendationJsonIOFactory());

// user list objects
s_jsonIOFactories.Add(typeof(ITraktList), new ListJsonIOFactory());
Expand Down
1 change: 1 addition & 0 deletions Source/Lib/Trakt.NET/Objects/Json/JsonProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ internal static class JsonProperties
internal const string PROPERTY_NAME_NEXT_EPISODE = "next_episode";
internal const string PROPERTY_NAME_NOT_FOUND = "not_found";
internal const string PROPERTY_NAME_NOTE = "note";
internal const string PROPERTY_NAME_NOTES = "notes";
internal const string PROPERTY_NAME_NUMBER = "number";
internal const string PROPERTY_NAME_NUMBER_ABSOLUTE = "number_abs";
internal const string PROPERTY_NAME_OVERVIEW = "overview";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
namespace TraktNet.Requests.Users.OAuth
{
using Base;
using Enums;
using Extensions;
using Objects.Get.Users;
using System;
using System.Collections.Generic;

internal sealed class UserPersonalRecommendationsRequest : AUsersPagedGetRequest<ITraktRecommendation>
{
internal string Username { get; set; }

public override string UriTemplate => "users/{username}/recommendations{/type}{/sort}{?extended,page,limit}";

public override AuthorizationRequirement AuthorizationRequirement => AuthorizationRequirement.Required;

public TraktRecommendationObjectType Type { get; set; }

public TraktWatchlistSortOrder Sort { get; set; }

public override IDictionary<string, object> GetUriPathParameters()
{
var uriParams = base.GetUriPathParameters();

uriParams.Add("username", Username);

if (Type != null && Type != TraktRecommendationObjectType.Unspecified)
{
uriParams.Add("type", Type.UriName);

if (Sort != null && Sort != TraktWatchlistSortOrder.Unspecified)
uriParams.Add("sort", Sort.UriName);
}

return uriParams;
}

public override void Validate()
{
base.Validate();

if (Username == null)
throw new ArgumentNullException(nameof(Username));

if (Username == string.Empty || Username.ContainsSpace())
throw new ArgumentException("username not valid", nameof(Username));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Trakt.NET.Core.Tests.Enums
{
using FluentAssertions;
using System.Collections.Generic;
using Trakt.NET.Tests.Utility.Traits;
using TraktNet.Enums;
using Xunit;

[Category("Enums")]
public class TraktRecommendationObjectType_Tests
{
[Fact]
public void Test_TraktRecommendationObjectType_GetAll()
{
var allValues = TraktEnumeration.GetAll<TraktRecommendationObjectType>();

allValues.Should().NotBeNull().And.HaveCount(3);
allValues.Should().Contain(new List<TraktRecommendationObjectType>() { TraktRecommendationObjectType.Unspecified, TraktRecommendationObjectType.Movie,
TraktRecommendationObjectType.Show });
}
}
}
Loading
0