Skip to content

Commit

Permalink
Merge pull request #36 from prplecake/19-add-support-for-linkace-api
Browse files Browse the repository at this point in the history
  • Loading branch information
prplecake authored Mar 30, 2023
2 parents e571f4f + c2fe93d commit e111a25
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 0 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions BookmarkSync.Core.Tests/Utilities/UriUtilitiesTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using BookmarkSync.Core.Utilities;

namespace BookmarkSync.Core.Tests.Utilities;

[TestClass]
public class UriUtilitiesTests
{
[DataTestMethod]
[DataRow("https://example.com")]
[DataRow("https://example.com/")]
public void UriUtilities_HttpsProto(string uri)
{
string actual = uri.RemoveProto();
Assert.AreEqual("example.com", actual);
}
[DataTestMethod]
[DataRow("http://example.com")]
[DataRow("http://example.com/")]
public void UriUtilities_HttpProto(string uri)
{
string actual = uri.RemoveProto();
Assert.AreEqual("example.com", actual);
}
[DataTestMethod]
[DataRow("example.com")]
[DataRow("example.com/")]
public void UriUtilities_NoProto(string uri)
{
string actual = uri.RemoveProto();
Assert.AreEqual("example.com", actual);
}
}
26 changes: 26 additions & 0 deletions BookmarkSync.Core/Utilities/UriUtilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Text.RegularExpressions;
using Serilog;

namespace BookmarkSync.Core.Utilities;

public static class UriUtilities
{
private static readonly ILogger _logger = Log.ForContext(typeof(UriUtilities));
/// <summary>
/// Returns a URI without a (/https?/) protocol.
/// </summary>
/// <param name="uri">The URI to process.</param>
/// <returns>A URI without a protocol or trailing slash.</returns>
public static string RemoveProto(this string uri)
{
_logger.Debug("Running {Method} for {Uri}", "RemoveProto", uri);
// https://stackoverflow.com/questions/10306690/what-is-a-regular-expression-which-will-match-a-valid-domain-name-without-a-subd/26987741#26987741
const string pattern =
@"(?:https?:\/\/)?((((?!-))(xn--|_)?[a-z0-9-]{0,61}[a-z0-9]{1,1}\.)*(xn--)?([a-z0-9][a-z0-9\-]{0,60}|[a-z0-9-]{1,30}\.[a-z]{2,}))";
var m = Regex.Match(uri, pattern, RegexOptions.IgnoreCase);
if (m.Success) return m.Groups[1].Value;
_logger.Error("Could not process {Uri}", uri);
throw new ArgumentException();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BookmarkSync.Core.Configuration;
using BookmarkSync.Infrastructure.Services.Bookmarking;
using BookmarkSync.Infrastructure.Services.Bookmarking.LinkAce;
using BookmarkSync.Infrastructure.Services.Bookmarking.Pinboard;
using Microsoft.Extensions.Configuration;

Expand Down Expand Up @@ -56,4 +57,33 @@ public void GetBookmarkingService_Pinboard()
Assert.AreEqual(typeof(PinboardBookmarkingService), obj.GetType());
Assert.IsInstanceOfType(obj, typeof(PinboardBookmarkingService));
}
[TestMethod]
public void GetBookmarkingService_LinkAce()
{
// Arrange
var config = new Dictionary<string, string?>
{
{
"App:Bookmarking:Service", "LinkAce"
},
{
"App:Bookmarking:ApiToken", "secret:123456789"
},
{
"App:Bookmarking:LinkAceUri", "https://your-linkace-url.com"
}
};
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(config)
.Build();

IConfigManager configManager = new ConfigManager(configuration);

// Act
var obj = BookmarkingService.GetBookmarkingService(configManager);

// Assert
Assert.AreEqual(typeof(LinkAceBookmarkingService), obj.GetType());
Assert.IsInstanceOfType(obj, typeof(LinkAceBookmarkingService));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using BookmarkSync.Core;
using BookmarkSync.Core.Configuration;
using BookmarkSync.Core.Interfaces;
using BookmarkSync.Infrastructure.Services.Bookmarking.LinkAce;
using BookmarkSync.Infrastructure.Services.Bookmarking.Pinboard;

namespace BookmarkSync.Infrastructure.Services.Bookmarking;
Expand Down Expand Up @@ -33,6 +34,7 @@ public static IBookmarkingService GetBookmarkingService(IConfigManager configMan
{
return configManager.App.Bookmarking.Service switch
{
"LinkAce" => new LinkAceBookmarkingService(configManager),
"Pinboard" => new PinboardBookmarkingService(configManager),
_ => throw new InvalidOperationException("Bookmark service either not provided or unknown")
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using BookmarkSync.Core.Configuration;
using BookmarkSync.Core.Entities;
using BookmarkSync.Core.Interfaces;
using BookmarkSync.Core.Utilities;
using Newtonsoft.Json;
using Serilog;

namespace BookmarkSync.Infrastructure.Services.Bookmarking.LinkAce;

public class LinkAceBookmarkingService : BookmarkingService, IBookmarkingService
{
private static readonly ILogger _logger = Log.ForContext<LinkAceBookmarkingService>();
public LinkAceBookmarkingService(IConfigManager configManager)
{
ApiToken = configManager.App.Bookmarking.ApiToken ?? throw new InvalidOperationException("Missing API token");
string linkAceUri = configManager.GetConfigValue("App:Bookmarking:LinkAceUri") ??
throw new InvalidOperationException("Missing LinkAce Uri");
ApiUri = $"{linkAceUri}/api/v1/links";
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiToken);
}
/// <inheritdoc />
public async Task<HttpResponseMessage> Save(Bookmark bookmark)
{
// Prep payload
Dictionary<string, object> payload = new()
{
{
"url", bookmark.Uri
},
{
"title", bookmark.Content
},
{
"tags", bookmark.DefaultTags
},
{
"is_private", true
},
{
"check_disabled", true
}
};
var stringContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8,
MediaTypeNames.Application.Json);
var response = await Client.PostAsync(ApiUri, stringContent);
response.EnsureSuccessStatusCode();
_logger.Debug("Response status: {StatusCode}", response.StatusCode);
return response;
}
}

0 comments on commit e111a25

Please sign in to comment.