Skip to content

Commit 80ae038

Browse files
committed
oEmbed Providers: Updated the X oEmbed provider to use the x.com domain (closes #21052) (#21053)
* Updated the X oEmbed provider to use the x.com domain. * Fixed issues raised in code review.
1 parent fd01282 commit 80ae038

File tree

4 files changed

+79
-4
lines changed

4 files changed

+79
-4
lines changed

src/Umbraco.Core/Media/EmbedProviders/X.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public X(IJsonSerializer jsonSerializer)
1212
{
1313
}
1414

15-
public override string ApiEndpoint => "http://publish.twitter.com/oembed";
15+
public override string ApiEndpoint => "https://publish.x.com/oembed";
1616

1717
public override string[] UrlSchemeRegex => new[] { @"(https?:\/\/(www\.)?)(twitter|x)\.com\/.*\/status\/.*" };
1818

src/Umbraco.Core/Services/IOEmbedService.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,22 @@
22

33
namespace Umbraco.Cms.Core.Services;
44

5+
/// <summary>
6+
/// Defines a service for asynchronously retrieving embeddable HTML markup for a specified resource using the oEmbed
7+
/// protocol.
8+
/// </summary>
59
public interface IOEmbedService
610
{
11+
/// <summary>
12+
/// Asynchronously retrieves the embeddable HTML markup for the specified resource.
13+
/// </summary>
14+
/// <remarks>The returned markup is suitable for embedding in web pages. The width and height parameters
15+
/// may be ignored by some providers depending on their capabilities.</remarks>
16+
/// <param name="url">The URI of the resource to retrieve markup for. Must be a valid, absolute URI.</param>
17+
/// <param name="width">The optional maximum width, in pixels, for the embedded content. If null, the default width is used.</param>
18+
/// <param name="height">The optional maximum height, in pixels, for the embedded content. If null, the default height is used.</param>
19+
/// <param name="cancellationToken">A token to monitor for cancellation requests. The operation is canceled if the token is triggered.</param>
20+
/// <returns>A task that represents the asynchronous operation. The result contains an Attempt with the HTML markup if
21+
/// successful, or an oEmbed operation status indicating the reason for failure.</returns>
722
Task<Attempt<string, OEmbedOperationStatus>> GetMarkupAsync(Uri url, int? width, int? height, CancellationToken cancellationToken);
823
}

src/Umbraco.Core/Services/OEmbedService.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,30 @@
66

77
namespace Umbraco.Cms.Core.Services;
88

9+
/// <summary>
10+
/// Implements <see cref="IOEmbedService"/> for retrieving embeddable HTML markup using the oEmbed protocol.
11+
/// </summary>
912
public class OEmbedService : IOEmbedService
1013
{
1114
private readonly EmbedProvidersCollection _embedProvidersCollection;
1215
private readonly ILogger<OEmbedService> _logger;
1316

17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="OEmbedService"/> class.
19+
/// </summary>
1420
public OEmbedService(EmbedProvidersCollection embedProvidersCollection, ILogger<OEmbedService> logger)
1521
{
1622
_embedProvidersCollection = embedProvidersCollection;
1723
_logger = logger;
1824
}
1925

26+
/// <inheritdoc/>
2027
public async Task<Attempt<string, OEmbedOperationStatus>> GetMarkupAsync(Uri url, int? maxWidth, int? maxHeight, CancellationToken cancellationToken)
2128
{
2229
// Find the first provider that supports the URL
2330
IEmbedProvider? matchedProvider = _embedProvidersCollection
24-
.FirstOrDefault(provider => provider.UrlSchemeRegex.Any(regex=>new Regex(regex, RegexOptions.IgnoreCase).IsMatch(url.OriginalString)));
31+
.FirstOrDefault(provider => provider.UrlSchemeRegex
32+
.Any(regex => new Regex(regex, RegexOptions.IgnoreCase).IsMatch(url.OriginalString)));
2533

2634
if (matchedProvider is null)
2735
{
@@ -39,8 +47,8 @@ public async Task<Attempt<string, OEmbedOperationStatus>> GetMarkupAsync(Uri url
3947
}
4048
catch (Exception e)
4149
{
42-
_logger.LogError(e, "Unexpected exception happened while trying to get oembed markup. Provider: {Provider}",matchedProvider.GetType().Name);
43-
Attempt.FailWithStatus(OEmbedOperationStatus.UnexpectedException, string.Empty, e);
50+
_logger.LogError(e, "Unexpected exception happened while trying to get oEmbed markup. Provider: {Provider}", matchedProvider.GetType().Name);
51+
return Attempt.FailWithStatus(OEmbedOperationStatus.UnexpectedException, string.Empty, e);
4452
}
4553

4654
return Attempt.FailWithStatus(OEmbedOperationStatus.ProviderReturnedInvalidResult, string.Empty);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using NUnit.Framework;
2+
using Umbraco.Cms.Core.DependencyInjection;
3+
using Umbraco.Cms.Core.Media.EmbedProviders;
4+
using Umbraco.Cms.Core.Services;
5+
using Umbraco.Cms.Core.Services.OperationStatus;
6+
using Umbraco.Cms.Tests.Common.Testing;
7+
using Umbraco.Cms.Tests.Integration.Testing;
8+
9+
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
10+
11+
[TestFixture]
12+
[UmbracoTest(Database = UmbracoTestOptions.Database.None)]
13+
internal sealed class OEmbedServiceTests : UmbracoIntegrationTest
14+
{
15+
private IOEmbedService OEmbedService => GetRequiredService<IOEmbedService>();
16+
17+
protected override void CustomTestSetup(IUmbracoBuilder builder)
18+
{
19+
base.CustomTestSetup(builder);
20+
21+
// Clear all providers and add only the X provider
22+
builder.EmbedProviders().Clear().Append<X>();
23+
}
24+
25+
/// <summary>
26+
/// Verifies resolution to https://github.com/umbraco/Umbraco-CMS/issues/21052.
27+
/// </summary>
28+
/// <remarks>
29+
/// Tests marked as [Explicit] as we don't want a random external service call to X to fail during regular test runs.
30+
/// </remarks>
31+
[Explicit]
32+
[TestCase("https://x.com/THR/status/1995620384344080849?s=20")]
33+
[TestCase("https://x.com/SquareEnix/status/1995780120888705216?s=20")]
34+
[TestCase("https://x.com/sem_sep/status/1991750339427700739?s=20")]
35+
public async Task GetMarkupAsync_WithXUrls_ReturnsSuccessAndMarkup(string url)
36+
{
37+
// Arrange
38+
var uri = new Uri(url);
39+
40+
// Act
41+
var result = await OEmbedService.GetMarkupAsync(uri, width: null, height: null, CancellationToken.None);
42+
43+
// Assert
44+
Assert.Multiple(() =>
45+
{
46+
Assert.That(result.Success, Is.True);
47+
Assert.That(result.Status, Is.EqualTo(OEmbedOperationStatus.Success));
48+
Assert.That(result.Result, Is.Not.Null.And.Not.Empty);
49+
Assert.That(result.Result, Does.Contain("blockquote"));
50+
});
51+
}
52+
}

0 commit comments

Comments
 (0)