Skip to content

Commit

Permalink
Added copy & move for #57, also used some of the new C# 10 language f…
Browse files Browse the repository at this point in the history
…eatures.
  • Loading branch information
Lakritzator committed Dec 21, 2021
1 parent 91f784e commit a62580c
Show file tree
Hide file tree
Showing 87 changed files with 4,461 additions and 4,450 deletions.
12 changes: 6 additions & 6 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ stages:
- task: NuGetToolInstaller@1

- task: UseDotNet@2
displayName: 'Use .NET Core sdk 3.1.10'
displayName: 'Use .NET Core sdk 3.1.22'
inputs:
packageType: sdk
version: 3.1.404
version: 3.1.416

- task: UseDotNet@2
displayName: 'Use .NET Core sdk 5.0.10'
displayName: 'Use .NET Core sdk 6.0.1'
inputs:
packageType: sdk
version: 5.0.401
version: 6.0.101

- task: DotNetCoreCLI@2
displayName: Test
Expand Down Expand Up @@ -131,9 +131,9 @@ stages:
artifact: 'drop'

- task: NuGetToolInstaller@0
displayName: 'Use NuGet 5.11.0'
displayName: 'Use NuGet 6.0.0'
inputs:
versionSpec: 5.11.0
versionSpec: 6.0.0
checkLatest: true

- task: NuGetCommand@2
Expand Down
87 changes: 43 additions & 44 deletions src/Dapplo.Confluence.OAuth/ConfluenceOAuthClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,52 @@
using Dapplo.HttpExtensions.Extensions;
using Dapplo.HttpExtensions;

namespace Dapplo.Confluence.OAuth
namespace Dapplo.Confluence.OAuth;

/// <summary>
/// A Confluence client with OAuth support build by using Dapplo.HttpExtensions
/// </summary>
public class ConfluenceOAuthClient : ConfluenceClient
{
/// <summary>
/// A Confluence client with OAuth support build by using Dapplo.HttpExtensions
/// </summary>
public class ConfluenceOAuthClient : ConfluenceClient
private ConfluenceOAuthClient(Uri baseUri, ConfluenceOAuthSettings confluenceOAuthSettings, IHttpSettings httpSettings = null) : base(baseUri, httpSettings)
{
private ConfluenceOAuthClient(Uri baseUri, ConfluenceOAuthSettings confluenceOAuthSettings, IHttpSettings httpSettings = null) : base(baseUri, httpSettings)
{
var confluenceOAuthUri = ConfluenceUri.AppendSegments("plugins", "servlet", "oauth");

var oAuthSettings = new OAuth1Settings
{
TokenUrl = confluenceOAuthUri.AppendSegments("request-token"),
TokenMethod = HttpMethod.Post,
AccessTokenUrl = confluenceOAuthUri.AppendSegments("access-token"),
AccessTokenMethod = HttpMethod.Post,
CheckVerifier = false,
SignatureType = OAuth1SignatureTypes.RsaSha1,
// According to <a href="https://community.atlassian.com/t5/Questions/Confluence-Oauth-Authentication/qaq-p/331326#M51385">here</a>
// the OAuth arguments need to be passed in the query
SignatureTransport = OAuth1SignatureTransports.QueryParameters,
Token = confluenceOAuthSettings.Token,
ClientId = confluenceOAuthSettings.ConsumerKey,
CloudServiceName = confluenceOAuthSettings.CloudServiceName,
RsaSha1Provider = confluenceOAuthSettings.RsaSha1Provider,
AuthorizeMode = confluenceOAuthSettings.AuthorizeMode,
AuthorizationUri = confluenceOAuthUri.AppendSegments("authorize")
.ExtendQuery(new Dictionary<string, string>
{
{OAuth1Parameters.Token.EnumValueOf(), "{RequestToken}"},
{OAuth1Parameters.Callback.EnumValueOf(), "{RedirectUrl}"}
})
};
var confluenceOAuthUri = ConfluenceUri.AppendSegments("plugins", "servlet", "oauth");

// Configure the OAuth1Settings
Behaviour = ConfigureBehaviour(OAuth1HttpBehaviourFactory.Create(oAuthSettings), httpSettings);
}
/// <summary>
/// Create the IConfluenceClient, using OAuth 1 for the communication, here the HttpClient is configured
/// </summary>
/// <param name="baseUri">Base URL, e.g. https://yourconfluenceserver</param>
/// <param name="confluenceOAuthSettings">ConfluenceOAuthSettings</param>
/// <param name="httpSettings">IHttpSettings or null for default</param>
public static IConfluenceClient Create(Uri baseUri, ConfluenceOAuthSettings confluenceOAuthSettings, IHttpSettings httpSettings = null)
var oAuthSettings = new OAuth1Settings
{
return new ConfluenceOAuthClient(baseUri, confluenceOAuthSettings, httpSettings);
}
TokenUrl = confluenceOAuthUri.AppendSegments("request-token"),
TokenMethod = HttpMethod.Post,
AccessTokenUrl = confluenceOAuthUri.AppendSegments("access-token"),
AccessTokenMethod = HttpMethod.Post,
CheckVerifier = false,
SignatureType = OAuth1SignatureTypes.RsaSha1,
// According to <a href="https://community.atlassian.com/t5/Questions/Confluence-Oauth-Authentication/qaq-p/331326#M51385">here</a>
// the OAuth arguments need to be passed in the query
SignatureTransport = OAuth1SignatureTransports.QueryParameters,
Token = confluenceOAuthSettings.Token,
ClientId = confluenceOAuthSettings.ConsumerKey,
CloudServiceName = confluenceOAuthSettings.CloudServiceName,
RsaSha1Provider = confluenceOAuthSettings.RsaSha1Provider,
AuthorizeMode = confluenceOAuthSettings.AuthorizeMode,
AuthorizationUri = confluenceOAuthUri.AppendSegments("authorize")
.ExtendQuery(new Dictionary<string, string>
{
{OAuth1Parameters.Token.EnumValueOf(), "{RequestToken}"},
{OAuth1Parameters.Callback.EnumValueOf(), "{RedirectUrl}"}
})
};

// Configure the OAuth1Settings
Behaviour = ConfigureBehaviour(OAuth1HttpBehaviourFactory.Create(oAuthSettings), httpSettings);
}
/// <summary>
/// Create the IConfluenceClient, using OAuth 1 for the communication, here the HttpClient is configured
/// </summary>
/// <param name="baseUri">Base URL, e.g. https://yourconfluenceserver</param>
/// <param name="confluenceOAuthSettings">ConfluenceOAuthSettings</param>
/// <param name="httpSettings">IHttpSettings or null for default</param>
public static IConfluenceClient Create(Uri baseUri, ConfluenceOAuthSettings confluenceOAuthSettings, IHttpSettings httpSettings = null)
{
return new ConfluenceOAuthClient(baseUri, confluenceOAuthSettings, httpSettings);
}
}
51 changes: 25 additions & 26 deletions src/Dapplo.Confluence.OAuth/ConfluenceOAuthSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,36 @@
using System.Security.Cryptography;
using Dapplo.HttpExtensions.OAuth;

namespace Dapplo.Confluence.OAuth
namespace Dapplo.Confluence.OAuth;

/// <summary>
/// OAuth 1 settings for Confluence Oauth connections
/// </summary>
public class ConfluenceOAuthSettings
{
/// <summary>
/// OAuth 1 settings for Confluence Oauth connections
/// Consumer Key which is set in the Confluence Application link
/// </summary>
public class ConfluenceOAuthSettings
{
/// <summary>
/// Consumer Key which is set in the Confluence Application link
/// </summary>
public string ConsumerKey { get; set; }
public string ConsumerKey { get; set; }

/// <summary>
/// Confluence uses OAuth1 with RSA-SHA1, for this a RSACryptoServiceProvider is used.
/// This needs to be created from a private key, the represented public key is set in the linked-applications
/// </summary>
public RSACryptoServiceProvider RsaSha1Provider { get; set; }
/// <summary>
/// Confluence uses OAuth1 with RSA-SHA1, for this a RSACryptoServiceProvider is used.
/// This needs to be created from a private key, the represented public key is set in the linked-applications
/// </summary>
public RSACryptoServiceProvider RsaSha1Provider { get; set; }

/// <summary>
/// The AuthorizeMode to use
/// </summary>
public AuthorizeModes AuthorizeMode { get; set; } = AuthorizeModes.LocalhostServer;
/// <summary>
/// The AuthorizeMode to use
/// </summary>
public AuthorizeModes AuthorizeMode { get; set; } = AuthorizeModes.LocalhostServer;

/// <summary>
/// Name of the cloud service, which is displayed in the embedded browser / browser when using AuthorizeModes.EmbeddedBrowser
/// </summary>
public string CloudServiceName { get; set; } = "Confluence";
/// <summary>
/// Name of the cloud service, which is displayed in the embedded browser / browser when using AuthorizeModes.EmbeddedBrowser
/// </summary>
public string CloudServiceName { get; set; } = "Confluence";

/// <summary>
/// The token object for storing the OAuth 1 secret etc, implement your own IOAuth1Token to be able to store these
/// </summary>
public IOAuth1Token Token { get; set; } = new OAuth1Token();
}
/// <summary>
/// The token object for storing the OAuth 1 secret etc, implement your own IOAuth1Token to be able to store these
/// </summary>
public IOAuth1Token Token { get; set; } = new OAuth1Token();
}
10 changes: 5 additions & 5 deletions src/Dapplo.Confluence.OAuth/Dapplo.Confluence.OAuth.csproj
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>A library for accessing Atlassians Confluence from .NET via OAuth</Description>
<TargetFrameworks>net471;net461;netcoreapp3.1;net5.0-windows</TargetFrameworks>
<TargetFrameworks>net471;net461;netcoreapp3.1;net5.0-windows;net6.0-windows</TargetFrameworks>
<PackageTags>atlassian;confluence;dapplo</PackageTags>
</PropertyGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net4'))">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dapplo.HttpExtensions" Version="1.0.11" />
<PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="1.0.11" />
<PackageReference Include="Dapplo.HttpExtensions" Version="1.0.16" />
<PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="1.0.16" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('net4')) Or $(TargetFramework.StartsWith('net5')) Or '$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Dapplo.HttpExtensions.OAuth" Version="1.0.11" />
<ItemGroup Condition="$(TargetFramework.StartsWith('net4')) Or $(TargetFramework.StartsWith('net5')) Or $(TargetFramework.StartsWith('net6')) Or '$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Dapplo.HttpExtensions.OAuth" Version="1.0.16" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Dapplo.Confluence\Dapplo.Confluence.csproj" />
Expand Down
143 changes: 71 additions & 72 deletions src/Dapplo.Confluence.Tests/AttachmentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,93 +10,92 @@
using Xunit;
using Xunit.Abstractions;

namespace Dapplo.Confluence.Tests
namespace Dapplo.Confluence.Tests;

/// <summary>
/// Tests for the attachment domain
/// </summary>
[CollectionDefinition("Dapplo.Confluence")]
public class AttachmentTests : ConfluenceIntegrationTests
{
public AttachmentTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
{
}

// TODO: Enable again whenever I got the rights working
//[Fact]
public async Task TestGetAttachments()
{
var attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(950274);
Assert.NotNull(attachments);
Assert.True(attachments.Results.Count > 0);
await using var attachmentMemoryStream = await ConfluenceTestClient.Attachment.GetContentAsync<MemoryStream>(attachments.FirstOrDefault());
Assert.True(attachmentMemoryStream.Length > 0);
}

/// <summary>
/// Tests for the attachment domain
/// Doesn't work yet, as deleting an attachment (with multiple versions) is not supported
/// See <a href="https://jira.atlassian.com/browse/CONF-36015">CONF-36015</a>
/// </summary>
[CollectionDefinition("Dapplo.Confluence")]
public class AttachmentTests : ConfluenceIntegrationTests
/// <returns></returns>
//[Fact]
public async Task TestAttach()
{
public AttachmentTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
{
}
const long testPageId = 950274;
var attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(testPageId);
Assert.NotNull(attachments);

// TODO: Enable again whenever I got the rights working
//[Fact]
public async Task TestGetAttachments()
// Delete all attachments
foreach (var attachment in attachments.Results)
{
var attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(950274);
Assert.NotNull(attachments);
Assert.True(attachments.Results.Count > 0);
await using var attachmentMemoryStream = await ConfluenceTestClient.Attachment.GetContentAsync<MemoryStream>(attachments.FirstOrDefault());
Assert.True(attachmentMemoryStream.Length > 0);
// Attachments are content!!
await ConfluenceTestClient.Attachment.DeleteAsync(attachment);
}

/// <summary>
/// Doesn't work yet, as deleting an attachment (with multiple versions) is not supported
/// See <a href="https://jira.atlassian.com/browse/CONF-36015">CONF-36015</a>
/// </summary>
/// <returns></returns>
//[Fact]
public async Task TestAttach()
{
const long testPageId = 950274;
var attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(testPageId);
Assert.NotNull(attachments);

// Delete all attachments
foreach (var attachment in attachments.Results)
{
// Attachments are content!!
await ConfluenceTestClient.Attachment.DeleteAsync(attachment);
}
const string attachmentContent = "Testing 1 2 3";
attachments = await ConfluenceTestClient.Attachment.AttachAsync(testPageId, attachmentContent, "test.txt", "This is a test");
Assert.NotNull(attachments);

const string attachmentContent = "Testing 1 2 3";
attachments = await ConfluenceTestClient.Attachment.AttachAsync(testPageId, attachmentContent, "test.txt", "This is a test");
Assert.NotNull(attachments);
attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(testPageId);
Assert.NotNull(attachments);
Assert.True(attachments.Results.Count > 0);

attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(testPageId);
Assert.NotNull(attachments);
Assert.True(attachments.Results.Count > 0);

// Test if the content is correct
foreach (var attachment in attachments.Results)
{
var content = await ConfluenceTestClient.Attachment.GetContentAsync<string>(attachment);
Assert.Equal(attachmentContent, content);
}
// Delete all attachments
foreach (var attachment in attachments.Results)
{
// Btw. Attachments are content!!
await ConfluenceTestClient.Attachment.DeleteAsync(attachment.Id);
}
attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(testPageId);
Assert.NotNull(attachments);
Assert.True(attachments.Results.Count == 0);
// Test if the content is correct
foreach (var attachment in attachments.Results)
{
var content = await ConfluenceTestClient.Attachment.GetContentAsync<string>(attachment);
Assert.Equal(attachmentContent, content);
}

/// <summary>
/// Doesn't work yet, as deleting an attachment (with multiple versions) is not supported
/// See <a href="https://jira.atlassian.com/browse/CONF-36015">CONF-36015</a>
/// </summary>
/// <returns></returns>
//[Fact]
public async Task TestAttachBitmap()
// Delete all attachments
foreach (var attachment in attachments.Results)
{
const long testPageId = 550731777;
// Btw. Attachments are content!!
await ConfluenceTestClient.Attachment.DeleteAsync(attachment.Id);
}
attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(testPageId);
Assert.NotNull(attachments);
Assert.True(attachments.Results.Count == 0);
}

// TODO: make the test work like this, delete all attachments, AttachAsync, UpdateAsync
/// <summary>
/// Doesn't work yet, as deleting an attachment (with multiple versions) is not supported
/// See <a href="https://jira.atlassian.com/browse/CONF-36015">CONF-36015</a>
/// </summary>
/// <returns></returns>
//[Fact]
public async Task TestAttachBitmap()
{
const long testPageId = 550731777;

using Stream stream = File.OpenRead(@"TestFiles\icon.png");
// TODO: make the test work like this, delete all attachments, AttachAsync, UpdateAsync

var attachments = await ConfluenceTestClient.Attachment.AttachAsync(testPageId, stream, "streamed.png", "Just attached a bitmap");
Assert.NotNull(attachments);
using Stream stream = File.OpenRead(@"TestFiles\icon.png");

attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(testPageId);
Assert.NotNull(attachments);
Assert.True(attachments.Results.Count > 0);
}
var attachments = await ConfluenceTestClient.Attachment.AttachAsync(testPageId, stream, "streamed.png", "Just attached a bitmap");
Assert.NotNull(attachments);

attachments = await ConfluenceTestClient.Attachment.GetAttachmentsAsync(testPageId);
Assert.NotNull(attachments);
Assert.True(attachments.Results.Count > 0);
}
}
Loading

0 comments on commit a62580c

Please sign in to comment.