Skip to content

Commit

Permalink
Add support for SearchFolders API
Browse files Browse the repository at this point in the history
  • Loading branch information
const-cloudinary committed Jul 31, 2023
1 parent 8aa16fa commit 3bc06eb
Show file tree
Hide file tree
Showing 13 changed files with 363 additions and 130 deletions.
35 changes: 35 additions & 0 deletions CloudinaryDotNet.Tests/SearchApi/SearchFoldersTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using NUnit.Framework;
using SystemHttp = System.Net.Http;

namespace CloudinaryDotNet.Tests.SearchApi
{
public class SearchFoldersTest
{
private MockedCloudinary _cloudinary = new MockedCloudinary();

[SetUp]
public void SetUp()
{
_cloudinary = new MockedCloudinary();
}

[Test]
public void TestShouldSearchFolders()
{
_cloudinary
.SearchFolders()
.Expression("path:*")
.MaxResults(1)
.Execute();

_cloudinary.AssertHttpCall(SystemHttp.HttpMethod.Post, "folders/search");

var requestJson = _cloudinary.RequestJson();

Assert.IsNotNull(requestJson["expression"]);
Assert.AreEqual("path:*", requestJson["expression"].ToString());
Assert.IsNotNull(requestJson["max_results"]);
Assert.AreEqual("1", requestJson["max_results"].ToString());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
using Newtonsoft.Json.Linq;
using NUnit.Framework;

namespace CloudinaryDotNet.Tests
namespace CloudinaryDotNet.Tests.SearchApi
{
public class SearchTest
{
private MockedCloudinary cloudinary = new MockedCloudinary();
private MockedCloudinary _cloudinary = new MockedCloudinary();

private Search search;
private Search _search;

private string searchExpression = "resource_type:image AND tags=kitten AND uploaded_at>1d AND bytes>1m";
private const string SearchExpression = "resource_type:image AND tags=kitten AND uploaded_at>1d AND bytes>1m";

private const string B64Query = "eyJleHByZXNzaW9uIjoicmVzb3VyY2VfdHlwZTppbWFnZSBBTkQgdGFncz1raXR0ZW4gQU5EIHV" +
"wbG9hZGVkX2F0PjFkIEFORCBieXRlcz4xbSIsIm1heF9yZXN1bHRzIjozMCwic29ydF9ieSI6W3" +
Expand All @@ -26,16 +26,16 @@ public class SearchTest
[SetUp]
public void SetUp()
{
cloudinary = new MockedCloudinary
_cloudinary = new MockedCloudinary
{
Api =
{
Secure = true
}
};

search = cloudinary.Search()
.Expression(searchExpression)
_search = _cloudinary.Search()
.Expression(SearchExpression)
.SortBy("public_id", "desc")
.MaxResults(30);
}
Expand All @@ -44,15 +44,15 @@ public void SetUp()
[Test]
public void TestSearchUrl()
{
Assert.AreEqual($"{SearchUrlPrefix}/{Ttl300Sig}/300/{B64Query}", search.ToUrl());
Assert.AreEqual($"{SearchUrlPrefix}/{Ttl300Sig}/300/{B64Query}", _search.ToUrl());
}

[Test]
public void TestSearchUrlWithNextCursor()
{
Assert.AreEqual(
$"{SearchUrlPrefix}/{Ttl300Sig}/300/{B64Query}/{NextCursor}",
search.ToUrl(null, NextCursor)
_search.ToUrl(null, NextCursor)
);
}

Expand All @@ -61,7 +61,7 @@ public void TestSearchUrlWithCustomTtlAndNextCursor()
{
Assert.AreEqual(
$"{SearchUrlPrefix}/{Ttl1000Sig}/1000/{B64Query}/{NextCursor}",
search.ToUrl(1000, NextCursor)
_search.ToUrl(1000, NextCursor)
);
}

Expand All @@ -70,27 +70,26 @@ public void TestSearchUrlWithCustomTtlAndNextCursorSetFromTheClass()
{
Assert.AreEqual(
$"{SearchUrlPrefix}/{Ttl1000Sig}/1000/{B64Query}/{NextCursor}",
search.Ttl(1000).NextCursor(NextCursor).ToUrl()
_search.Ttl(1000).NextCursor(NextCursor).ToUrl()
);
}

[Test]
public void TestSearchUrlPrivateCdn()
{
cloudinary.Api.UsePrivateCdn = true;
_cloudinary.Api.UsePrivateCdn = true;

Assert.AreEqual(
$"https://test123-res.cloudinary.com/search/{Ttl300Sig}/300/{B64Query}",
cloudinary.Search().Expression(searchExpression).SortBy("public_id", "desc")
_cloudinary.Search().Expression(SearchExpression).SortBy("public_id", "desc")
.MaxResults(30).ToUrl()
);
}


[Test]
public void TestShouldNotDuplicateValues()
{
cloudinary
_cloudinary
.Search()
.SortBy("created_at", "asc")
.SortBy("created_at", "desc")
Expand All @@ -103,7 +102,7 @@ public void TestShouldNotDuplicateValues()
.WithField("tags")
.Execute();

AssertCorrectRequest(cloudinary.HttpRequestContent);
AssertCorrectRequest(_cloudinary.HttpRequestContent);
}

private static void AssertCorrectRequest(string request)
Expand Down
35 changes: 35 additions & 0 deletions CloudinaryDotNet/Actions/Search/SearchFolder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace CloudinaryDotNet.Actions
{
using System.Runtime.Serialization;

/// <summary>
/// The details of the folder found.
/// </summary>
[DataContract]
public class SearchFolder
{
/// <summary>
/// Gets or sets the name of the folder.
/// </summary>
[DataMember(Name = "name")]
public string Name;

/// <summary>
/// Gets or sets the path of the folder.
/// </summary>
[DataMember(Name = "path")]
public string Path { get; set; }

/// <summary>
/// Gets or sets date when the folder was created.
/// </summary>
[DataMember(Name = "created_at")]
public string CreatedAt { get; set; }

/// <summary>
/// Gets or sets the eternal id of the folder.
/// </summary>
[DataMember(Name = "external_id")]
public string ExternalId { get; set; }
}
}
18 changes: 18 additions & 0 deletions CloudinaryDotNet/Actions/Search/SearchFoldersResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace CloudinaryDotNet.Actions
{
using System.Collections.Generic;
using System.Runtime.Serialization;

/// <summary>
/// Search response with information about the folders matching the search criteria.
/// </summary>
[DataContract]
public class SearchFoldersResult : SearchResultBase
{
/// <summary>
/// Gets or sets the details of each of the folders found.
/// </summary>
[DataMember(Name = "folders")]
public List<SearchFolder> Folders { get; set; }
}
}
12 changes: 6 additions & 6 deletions CloudinaryDotNet/Actions/Search/SearchResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ public class SearchResource
[Obsolete("Property Created is deprecated, please use CreatedAt instead")]
public string Created
{
get { return CreatedAt; }
set { CreatedAt = value; }
get => CreatedAt;
set => CreatedAt = value;
}

/// <summary>
Expand All @@ -100,8 +100,8 @@ public string Created
[Obsolete("Property Uploaded is deprecated, please use UploadedAt instead")]
public string Uploaded
{
get { return UploadedAt; }
set { UploadedAt = value; }
get => UploadedAt;
set => UploadedAt = value;
}

/// <summary>
Expand All @@ -116,8 +116,8 @@ public string Uploaded
[Obsolete("Property Length is deprecated, please use Bytes instead")]
public long Length
{
get { return Bytes; }
set { Bytes = value; }
get => Bytes;
set => Bytes = value;
}

/// <summary>
Expand Down
21 changes: 1 addition & 20 deletions CloudinaryDotNet/Actions/Search/SearchResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,14 @@
/// Search response with information about the assets matching the search criteria.
/// </summary>
[DataContract]
public class SearchResult : BaseResult
public class SearchResult : SearchResultBase
{
/// <summary>
/// Gets or sets the total count of assets matching the search criteria.
/// </summary>
[DataMember(Name = "total_count")]
public int TotalCount { get; set; }

/// <summary>
/// Gets or sets the time taken to process the request.
/// </summary>
[DataMember(Name = "time")]
public long Time { get; set; }

/// <summary>
/// Gets or sets the details of each of the assets (resources) found.
/// </summary>
[DataMember(Name = "resources")]
public List<SearchResource> Resources { get; set; }

/// <summary>
/// Gets or sets when a search request has more results to return than max_results, the next_cursor value is returned as
/// part of the response.
/// </summary>
[DataMember(Name = "next_cursor")]
public string NextCursor { get; set; }

/// <summary>
/// Gets or sets counts of assets, grouped by specified parameters.
/// </summary>
Expand Down
29 changes: 29 additions & 0 deletions CloudinaryDotNet/Actions/Search/SearchResultBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace CloudinaryDotNet.Actions
{
using System.Runtime.Serialization;

/// <summary>
/// Search response with information matching the search criteria.
/// </summary>
public class SearchResultBase : BaseResult
{
/// <summary>
/// Gets or sets the total count of assets matching the search criteria.
/// </summary>
[DataMember(Name = "total_count")]
public int TotalCount { get; set; }

/// <summary>
/// Gets or sets the time taken to process the request.
/// </summary>
[DataMember(Name = "time")]
public long Time { get; set; }

/// <summary>
/// Gets or sets when a search request has more results to return than max_results, the next_cursor value is returned as
/// part of the response.
/// </summary>
[DataMember(Name = "next_cursor")]
public string NextCursor { get; set; }
}
}
9 changes: 9 additions & 0 deletions CloudinaryDotNet/Cloudinary.AdminApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ public Search Search()
return new Search(m_api);
}

/// <summary>
/// Gets the advanced search folders provider used by the Cloudinary instance.
/// </summary>
/// <returns>Instance of the <see cref="SearchFolders"/> class.</returns>
public SearchFolders SearchFolders()
{
return new SearchFolders(m_api);
}

/// <summary>
/// Lists resource types asynchronously.
/// </summary>
Expand Down
18 changes: 18 additions & 0 deletions CloudinaryDotNet/Search/Search.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace CloudinaryDotNet
{
/// <summary>
/// Advanced search provider. Allows you to retrieve information on all the assets in your account with the help of
/// query expressions in a Lucene-like query language.
/// </summary>
public class Search : SearchFluent<Search>
{
/// <summary>
/// Initializes a new instance of the <see cref="Search"/> class.
/// </summary>
/// <param name="api">Provider of the API calls.</param>
public Search(ApiShared api)
: base(api)
{
}
}
}
Loading

0 comments on commit 3bc06eb

Please sign in to comment.