splits client into multiple interfaces and adds a context
adds code format for rider / resharper
This commit is contained in:
parent
b2940dc33b
commit
e5ba4c6e4a
59
PiwigoDotnet/Piwigo.Client.Tests/ApiTestsBase.cs
Normal file
59
PiwigoDotnet/Piwigo.Client.Tests/ApiTestsBase.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using Flurl.Http.Configuration;
|
||||||
|
using Flurl.Http.Testing;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Piwigo.Client.Contract;
|
||||||
|
|
||||||
|
namespace Piwigo.Client.Tests;
|
||||||
|
|
||||||
|
public class ApiTestsBase
|
||||||
|
{
|
||||||
|
private const string TestUri = "http://localhost:8080/ws.php?format=json";
|
||||||
|
private const string Username = "admin";
|
||||||
|
private const string Password = "admin";
|
||||||
|
private const bool UseHttpTest = true;
|
||||||
|
protected HttpTest? HttpTest { get; private set; }
|
||||||
|
protected IPiwigoContext Context { get; private set; } = null!;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
if (UseHttpTest)
|
||||||
|
{
|
||||||
|
HttpTest = new HttpTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
Context = new PiwigoContext(new PiwigoConfiguration(TestUri, Username, Password), new NullLogger<PiwigoContext>());
|
||||||
|
OnSetUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnSetUp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
HttpTest?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task LoginAsync()
|
||||||
|
{
|
||||||
|
HttpTest?.RespondWith("{}", 200, cookies: new { pwg_id = "pwg_id" });
|
||||||
|
var sessionApi = new SessionApi(Context, new NullLogger<SessionApi>());
|
||||||
|
await sessionApi.LoginAsync();
|
||||||
|
Context.IsLoggedIn.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void SetJsonResult<T>(PiwigoResponse<T> serverResponse)
|
||||||
|
{
|
||||||
|
var settings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
Formatting = Formatting.Indented,
|
||||||
|
NullValueHandling = NullValueHandling.Ignore
|
||||||
|
};
|
||||||
|
var serializer = new NewtonsoftJsonSerializer(settings);
|
||||||
|
var jsonResponse = serializer.Serialize(serverResponse);
|
||||||
|
HttpTest?.RespondWith(jsonResponse);
|
||||||
|
}
|
||||||
|
}
|
55
PiwigoDotnet/Piwigo.Client.Tests/CategoryApiTests.cs
Normal file
55
PiwigoDotnet/Piwigo.Client.Tests/CategoryApiTests.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Piwigo.Client.Contract;
|
||||||
|
|
||||||
|
namespace Piwigo.Client.Tests;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class CategoryApiTests : ApiTestsBase
|
||||||
|
{
|
||||||
|
private CategoryApi _categoryApi = null!;
|
||||||
|
|
||||||
|
protected override void OnSetUp()
|
||||||
|
{
|
||||||
|
base.OnSetUp();
|
||||||
|
_categoryApi = new CategoryApi(Context, new NullLogger<CategoryApi>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetAllCategories_should_return_all_existing_categories()
|
||||||
|
{
|
||||||
|
await LoginAsync();
|
||||||
|
|
||||||
|
|
||||||
|
var serverResponse = new PiwigoResponse<PiwigoCategoryList>
|
||||||
|
{
|
||||||
|
Result = new PiwigoCategoryList
|
||||||
|
{
|
||||||
|
Categories = new List<PiwigoCategory>
|
||||||
|
{
|
||||||
|
new() { Id = 1, Name = "UnitTestMain" },
|
||||||
|
new() { Id = 3, Name = "UnitTestSub2", IdUpperCat = 1 },
|
||||||
|
new() { Id = 2, Name = "UnitTestSub1", IdUpperCat = 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
SetJsonResult(serverResponse);
|
||||||
|
var response = await _categoryApi.GetAllCategoriesAsync();
|
||||||
|
|
||||||
|
response.Should().HaveCount(3);
|
||||||
|
response.Should().SatisfyRespectively(c =>
|
||||||
|
{
|
||||||
|
c.Id.Should().Be(1);
|
||||||
|
c.Name.Should().Be("UnitTestMain");
|
||||||
|
}, c =>
|
||||||
|
{
|
||||||
|
c.Id.Should().Be(3);
|
||||||
|
c.Name.Should().Be("UnitTestSub2");
|
||||||
|
c.IdUpperCat.Should().Be(1);
|
||||||
|
}, c =>
|
||||||
|
{
|
||||||
|
c.Id.Should().Be(2);
|
||||||
|
c.Name.Should().Be("UnitTestSub1");
|
||||||
|
c.IdUpperCat.Should().Be(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,128 +0,0 @@
|
|||||||
using Flurl.Http.Configuration;
|
|
||||||
using Flurl.Http.Testing;
|
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Piwigo.Client.Tests;
|
|
||||||
|
|
||||||
[TestFixture]
|
|
||||||
public class PiwigoClientTests
|
|
||||||
{
|
|
||||||
private const string TestUri = "http://localhost:8080/ws.php?format=json";
|
|
||||||
private const string Username = "admin";
|
|
||||||
private const string Password = "admin";
|
|
||||||
|
|
||||||
private PiwigoClient _piwigoClient = null!;
|
|
||||||
private HttpTest? _httpTest;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void SetUp()
|
|
||||||
{
|
|
||||||
_piwigoClient = new PiwigoClient(new NullLogger<PiwigoClient>());
|
|
||||||
_httpTest = new HttpTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TearDown]
|
|
||||||
public void TearDown()
|
|
||||||
{
|
|
||||||
_httpTest?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task Login_should_set_cookies_and_session()
|
|
||||||
{
|
|
||||||
await LoginAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task GetStatus_should_return_config()
|
|
||||||
{
|
|
||||||
await LoginAsync();
|
|
||||||
|
|
||||||
var serverResponse = new PiwigoResponse<PiwigoStatus>
|
|
||||||
{
|
|
||||||
Status = "OK",
|
|
||||||
Result = new PiwigoStatus
|
|
||||||
{
|
|
||||||
Username = "admin",
|
|
||||||
Version = "12.0.0"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
SetJsonResult(serverResponse);
|
|
||||||
|
|
||||||
var status = await _piwigoClient.GetStatusAsync();
|
|
||||||
|
|
||||||
status.Should().NotBeNull();
|
|
||||||
status.Username.Should().Be("admin");
|
|
||||||
status.Version.Should().NotBeEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task Logout_should_set_IsLoggedIn_to_false()
|
|
||||||
{
|
|
||||||
await LoginAsync();
|
|
||||||
|
|
||||||
_httpTest?.RespondWith("OK");
|
|
||||||
|
|
||||||
await _piwigoClient.LogoutAsync();
|
|
||||||
_piwigoClient.IsLoggedIn.Should().BeFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task GetAllCategories_should_return_all_existing_categories()
|
|
||||||
{
|
|
||||||
await LoginAsync();
|
|
||||||
|
|
||||||
|
|
||||||
var serverResponse = new PiwigoResponse<PiwigoCategoryList>
|
|
||||||
{
|
|
||||||
Result = new PiwigoCategoryList
|
|
||||||
{
|
|
||||||
Categories = new List<PiwigoCategory>
|
|
||||||
{
|
|
||||||
new() { Id = 1, Name = "UnitTestMain" },
|
|
||||||
new() { Id = 3, Name = "UnitTestSub2", IdUpperCat = 1 },
|
|
||||||
new() { Id = 2, Name = "UnitTestSub1", IdUpperCat = 1 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
SetJsonResult(serverResponse);
|
|
||||||
var response = await _piwigoClient.GetAllCategoriesAsync();
|
|
||||||
|
|
||||||
response.Should().HaveCount(3);
|
|
||||||
response.Should().SatisfyRespectively(c =>
|
|
||||||
{
|
|
||||||
c.Id.Should().Be(1);
|
|
||||||
c.Name.Should().Be("UnitTestMain");
|
|
||||||
}, c =>
|
|
||||||
{
|
|
||||||
c.Id.Should().Be(3);
|
|
||||||
c.Name.Should().Be("UnitTestSub2");
|
|
||||||
c.IdUpperCat.Should().Be(1);
|
|
||||||
}, c =>
|
|
||||||
{
|
|
||||||
c.Id.Should().Be(2);
|
|
||||||
c.Name.Should().Be("UnitTestSub1");
|
|
||||||
c.IdUpperCat.Should().Be(1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetJsonResult<T>(PiwigoResponse<T> serverResponse)
|
|
||||||
{
|
|
||||||
var settings = new JsonSerializerSettings
|
|
||||||
{
|
|
||||||
Formatting = Formatting.Indented,
|
|
||||||
NullValueHandling = NullValueHandling.Ignore
|
|
||||||
};
|
|
||||||
var serializer = new NewtonsoftJsonSerializer(settings);
|
|
||||||
var jsonResponse = serializer.Serialize(serverResponse);
|
|
||||||
_httpTest?.RespondWith(jsonResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LoginAsync()
|
|
||||||
{
|
|
||||||
_httpTest?.RespondWith("{}", 200, cookies: new { pwg_id = "pwg_id" });
|
|
||||||
await _piwigoClient.LoginAsync(new Uri(TestUri), Username, Password);
|
|
||||||
_piwigoClient.IsLoggedIn.Should().BeTrue();
|
|
||||||
}
|
|
||||||
}
|
|
55
PiwigoDotnet/Piwigo.Client.Tests/SessionApiTests.cs
Normal file
55
PiwigoDotnet/Piwigo.Client.Tests/SessionApiTests.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Piwigo.Client.Contract;
|
||||||
|
|
||||||
|
namespace Piwigo.Client.Tests;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class SessionApiTests : ApiTestsBase
|
||||||
|
{
|
||||||
|
private SessionApi _sessionApi = null!;
|
||||||
|
|
||||||
|
protected override void OnSetUp()
|
||||||
|
{
|
||||||
|
base.OnSetUp();
|
||||||
|
_sessionApi = new SessionApi(Context, new NullLogger<SessionApi>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Login_should_set_cookies_and_session()
|
||||||
|
{
|
||||||
|
await LoginAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetStatus_should_return_config()
|
||||||
|
{
|
||||||
|
await LoginAsync();
|
||||||
|
var serverResponse = new PiwigoResponse<PiwigoStatus>
|
||||||
|
{
|
||||||
|
Status = "OK",
|
||||||
|
Result = new PiwigoStatus
|
||||||
|
{
|
||||||
|
Username = "admin",
|
||||||
|
Version = "12.0.0"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
SetJsonResult(serverResponse);
|
||||||
|
|
||||||
|
var status = await _sessionApi.GetStatusAsync();
|
||||||
|
|
||||||
|
status.Should().NotBeNull();
|
||||||
|
status.Username.Should().Be("admin");
|
||||||
|
status.Version.Should().NotBeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Logout_should_set_IsLoggedIn_to_false()
|
||||||
|
{
|
||||||
|
await LoginAsync();
|
||||||
|
|
||||||
|
HttpTest?.RespondWith("OK");
|
||||||
|
|
||||||
|
await _sessionApi.LogoutAsync();
|
||||||
|
Context.IsLoggedIn.Should().BeFalse();
|
||||||
|
}
|
||||||
|
}
|
26
PiwigoDotnet/Piwigo.Client/CategoryApi.cs
Normal file
26
PiwigoDotnet/Piwigo.Client/CategoryApi.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using Flurl.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Piwigo.Client.Contract;
|
||||||
|
|
||||||
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
|
public class CategoryApi : ICategoryApi
|
||||||
|
{
|
||||||
|
private readonly IPiwigoContext _context;
|
||||||
|
private readonly ILogger<CategoryApi> _logger;
|
||||||
|
|
||||||
|
public CategoryApi(IPiwigoContext context, ILogger<CategoryApi> logger)
|
||||||
|
{
|
||||||
|
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyCollection<PiwigoCategory>> GetAllCategoriesAsync()
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Getting all existing categories from server");
|
||||||
|
var response = await _context.ConfigureRequest(_logger).PostMultipartAsync(c => c.AddMethod("pwg.categories.getList").AddString("recursive", "true"));
|
||||||
|
var typedResponse = await response.GetJsonAsync<PiwigoResponse<PiwigoCategoryList>>();
|
||||||
|
return new ReadOnlyCollection<PiwigoCategory>(typedResponse.Result.Categories);
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Piwigo.Client;
|
namespace Piwigo.Client.Contract;
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
||||||
public class PiwigoCategory
|
public class PiwigoCategory
|
@ -1,6 +1,6 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Piwigo.Client;
|
namespace Piwigo.Client.Contract;
|
||||||
|
|
||||||
public class PiwigoCategoryList
|
public class PiwigoCategoryList
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Piwigo.Client;
|
namespace Piwigo.Client.Contract;
|
||||||
|
|
||||||
internal class PiwigoResponse<T>
|
internal class PiwigoResponse<T>
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Piwigo.Client;
|
namespace Piwigo.Client.Contract;
|
||||||
|
|
||||||
public class PiwigoStatus
|
public class PiwigoStatus
|
||||||
{
|
{
|
16
PiwigoDotnet/Piwigo.Client/FlurlExtensions.cs
Normal file
16
PiwigoDotnet/Piwigo.Client/FlurlExtensions.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using Flurl.Http.Content;
|
||||||
|
|
||||||
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
|
internal static class FlurlExtensions
|
||||||
|
{
|
||||||
|
internal static CapturedMultipartContent AddMethod(this CapturedMultipartContent part, string piwigoMethod)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(piwigoMethod))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Value cannot be null or whitespace.", nameof(piwigoMethod));
|
||||||
|
}
|
||||||
|
|
||||||
|
return part.AddString("method", piwigoMethod);
|
||||||
|
}
|
||||||
|
}
|
8
PiwigoDotnet/Piwigo.Client/ICategoryApi.cs
Normal file
8
PiwigoDotnet/Piwigo.Client/ICategoryApi.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using Piwigo.Client.Contract;
|
||||||
|
|
||||||
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
|
public interface ICategoryApi
|
||||||
|
{
|
||||||
|
Task<IReadOnlyCollection<PiwigoCategory>> GetAllCategoriesAsync();
|
||||||
|
}
|
@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
public interface IPiwigoClient
|
public interface IPiwigoClient
|
||||||
{
|
{
|
||||||
bool IsLoggedIn { get; }
|
ISessionApi Session { get; }
|
||||||
int ChunkSize { get; set; }
|
ICategoryApi Category { get; }
|
||||||
Task LoginAsync(Uri uri, string username, string password);
|
|
||||||
Task LogoutAsync();
|
|
||||||
Task<PiwigoStatus> GetStatusAsync();
|
|
||||||
Task<IReadOnlyCollection<PiwigoCategory>> GetAllCategoriesAsync();
|
|
||||||
}
|
}
|
9
PiwigoDotnet/Piwigo.Client/IPiwigoConfiguration.cs
Normal file
9
PiwigoDotnet/Piwigo.Client/IPiwigoConfiguration.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
|
public interface IPiwigoConfiguration
|
||||||
|
{
|
||||||
|
public int ChunkSize { get; }
|
||||||
|
public string BaseUri { get; }
|
||||||
|
public string UserName { get; }
|
||||||
|
public string Password { get; }
|
||||||
|
}
|
13
PiwigoDotnet/Piwigo.Client/IPiwigoContext.cs
Normal file
13
PiwigoDotnet/Piwigo.Client/IPiwigoContext.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using Flurl.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
|
public interface IPiwigoContext
|
||||||
|
{
|
||||||
|
IPiwigoConfiguration Config { get; }
|
||||||
|
bool IsLoggedIn { get; }
|
||||||
|
IFlurlRequest ConfigureRequest(ILogger logger, bool requireLogin = true);
|
||||||
|
void LoggedOut();
|
||||||
|
void LoggedIn();
|
||||||
|
}
|
10
PiwigoDotnet/Piwigo.Client/ISessionApi.cs
Normal file
10
PiwigoDotnet/Piwigo.Client/ISessionApi.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using Piwigo.Client.Contract;
|
||||||
|
|
||||||
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
|
public interface ISessionApi
|
||||||
|
{
|
||||||
|
Task LoginAsync();
|
||||||
|
Task LogoutAsync();
|
||||||
|
Task<PiwigoStatus> GetStatusAsync();
|
||||||
|
}
|
@ -1,110 +1,13 @@
|
|||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Net;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using Flurl;
|
|
||||||
using Flurl.Http;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace Piwigo.Client;
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
public class PiwigoClient : IPiwigoClient
|
public class PiwigoClient : IPiwigoClient
|
||||||
{
|
{
|
||||||
private CookieJar _cookies = new();
|
public PiwigoClient(ISessionApi session, ICategoryApi category)
|
||||||
private string _piwigoBaseUri = null!;
|
|
||||||
public bool IsLoggedIn { get; private set; }
|
|
||||||
public int ChunkSize { get; set; } = 512;
|
|
||||||
private IFlurlRequest Request => _piwigoBaseUri.WithCookies(_cookies).ConfigureRequest(r => r.AfterCallAsync = LogResponse);
|
|
||||||
|
|
||||||
private readonly ILogger<PiwigoClient> _logger;
|
|
||||||
|
|
||||||
public PiwigoClient(ILogger<PiwigoClient> logger)
|
|
||||||
{
|
{
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
Session = session;
|
||||||
|
Category = category;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LoginAsync(Uri uri, string username, string password)
|
public ISessionApi Session { get; }
|
||||||
{
|
public ICategoryApi Category { get; }
|
||||||
if (uri == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(uri));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(username))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(username));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(password))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(password));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsLoggedIn)
|
|
||||||
{
|
|
||||||
throw new PiwigoException("The client is already logged in. Create a new instance or log out first!");
|
|
||||||
}
|
|
||||||
|
|
||||||
_piwigoBaseUri = uri.AppendPathSegment("ws.php").SetQueryParam("format", "json");
|
|
||||||
|
|
||||||
_logger.LogInformation("Logging into {PiwigoBaseUri} using username {Username}", _piwigoBaseUri, username);
|
|
||||||
|
|
||||||
var response = await _piwigoBaseUri.WithCookies(out var cookieJar).PostMultipartAsync(c =>
|
|
||||||
c.PiwigoLogin(username, password));
|
|
||||||
|
|
||||||
if (response.StatusCode != (int)HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
_logger.LogError("Failed to log in {StatusCode}", response.StatusCode);
|
|
||||||
throw new PiwigoException($"Could not log in to {_piwigoBaseUri} using username {username}");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation("Logging in succeeded");
|
|
||||||
_cookies = cookieJar;
|
|
||||||
IsLoggedIn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task LogoutAsync()
|
|
||||||
{
|
|
||||||
EnsureLoggedIn();
|
|
||||||
|
|
||||||
_logger.LogInformation("Logging out from {Uri}", _piwigoBaseUri);
|
|
||||||
await Request.PostMultipartAsync(c => c.PiwigoLogout());
|
|
||||||
|
|
||||||
IsLoggedIn = false;
|
|
||||||
_cookies.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<PiwigoStatus> GetStatusAsync()
|
|
||||||
{
|
|
||||||
EnsureLoggedIn();
|
|
||||||
|
|
||||||
_logger.LogInformation("Getting status");
|
|
||||||
var response = await Request.PostMultipartAsync(c => c.PiwigoGetStatus());
|
|
||||||
var typedResponse = await response.GetJsonAsync<PiwigoResponse<PiwigoStatus>>();
|
|
||||||
return typedResponse.Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IReadOnlyCollection<PiwigoCategory>> GetAllCategoriesAsync()
|
|
||||||
{
|
|
||||||
EnsureLoggedIn();
|
|
||||||
|
|
||||||
_logger.LogInformation("Getting all existing categories from server");
|
|
||||||
var response = await Request.PostMultipartAsync(c => c.PiwigoGetAllCategories());
|
|
||||||
var typedResponse = await response.GetJsonAsync<PiwigoResponse<PiwigoCategoryList>>();
|
|
||||||
return new ReadOnlyCollection<PiwigoCategory>(typedResponse.Result.Categories);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureLoggedIn([CallerMemberName] string? callerName = null)
|
|
||||||
{
|
|
||||||
if (!IsLoggedIn)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Could not execute {callerName} as the client is not logged in.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LogResponse(FlurlCall call)
|
|
||||||
{
|
|
||||||
var responseString = await call.Response.GetStringAsync();
|
|
||||||
_logger.LogDebug("PiwigoResponse: {Response}", responseString);
|
|
||||||
}
|
|
||||||
}
|
}
|
31
PiwigoDotnet/Piwigo.Client/PiwigoConfiguration.cs
Normal file
31
PiwigoDotnet/Piwigo.Client/PiwigoConfiguration.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
|
public class PiwigoConfiguration : IPiwigoConfiguration
|
||||||
|
{
|
||||||
|
public PiwigoConfiguration(string baseUri, string userName, string password)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(baseUri))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Value cannot be null or whitespace.", nameof(baseUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(userName))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Value cannot be null or whitespace.", nameof(userName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(password))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Value cannot be null or whitespace.", nameof(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseUri = baseUri;
|
||||||
|
UserName = userName;
|
||||||
|
Password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ChunkSize { get; set; } = 512;
|
||||||
|
public string BaseUri { get; }
|
||||||
|
public string UserName { get; }
|
||||||
|
public string Password { get; }
|
||||||
|
}
|
54
PiwigoDotnet/Piwigo.Client/PiwigoContext.cs
Normal file
54
PiwigoDotnet/Piwigo.Client/PiwigoContext.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using Flurl.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
|
public class PiwigoContext : IPiwigoContext
|
||||||
|
{
|
||||||
|
private readonly CookieJar _cookies = new();
|
||||||
|
private readonly ILogger<PiwigoContext> _logger;
|
||||||
|
|
||||||
|
public PiwigoContext(IPiwigoConfiguration configuration, ILogger<PiwigoContext> logger)
|
||||||
|
{
|
||||||
|
Config = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPiwigoConfiguration Config { get; }
|
||||||
|
|
||||||
|
public bool IsLoggedIn { get; private set; }
|
||||||
|
|
||||||
|
public IFlurlRequest ConfigureRequest(ILogger logger, bool requireLogin = true)
|
||||||
|
{
|
||||||
|
if (logger == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requireLogin && !IsLoggedIn)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("User is not logged in. Ensure login is called before accessing any piwigo methods");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Config.BaseUri.WithCookies(_cookies).ConfigureRequest(r => r.AfterCallAsync = call => LogResponse(call, logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoggedOut()
|
||||||
|
{
|
||||||
|
_logger.LogInformation("logged out, clearing cookies");
|
||||||
|
IsLoggedIn = false;
|
||||||
|
_cookies.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoggedIn()
|
||||||
|
{
|
||||||
|
_logger.LogInformation("logged in");
|
||||||
|
IsLoggedIn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task LogResponse(FlurlCall call, ILogger logger)
|
||||||
|
{
|
||||||
|
var responseString = await call.Response.GetStringAsync();
|
||||||
|
logger.LogDebug("PiwigoResponse: {Response}", responseString);
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
using Flurl.Http.Content;
|
|
||||||
|
|
||||||
namespace Piwigo.Client;
|
|
||||||
|
|
||||||
internal static class PiwigoMethods
|
|
||||||
{
|
|
||||||
public static void PiwigoLogin(this CapturedMultipartContent part, string username,
|
|
||||||
string password)
|
|
||||||
{
|
|
||||||
part.AddMethod("pwg.session.login").AddString("username", username).AddString("password", password);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PiwigoLogout(this CapturedMultipartContent part)
|
|
||||||
{
|
|
||||||
part.AddMethod("pwg.session.logout");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PiwigoGetStatus(this CapturedMultipartContent part)
|
|
||||||
{
|
|
||||||
part.AddMethod("pwg.session.getStatus");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PiwigoGetAllCategories(this CapturedMultipartContent part, bool recursive = true)
|
|
||||||
{
|
|
||||||
part.AddMethod("pwg.categories.getList").AddString("recursive", recursive.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CapturedMultipartContent AddMethod(this CapturedMultipartContent part, string piwigoMethod)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(piwigoMethod))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Value cannot be null or whitespace.", nameof(piwigoMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
return part.AddString("method", piwigoMethod);
|
|
||||||
}
|
|
||||||
}
|
|
67
PiwigoDotnet/Piwigo.Client/SessionApi.cs
Normal file
67
PiwigoDotnet/Piwigo.Client/SessionApi.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Flurl.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Piwigo.Client.Contract;
|
||||||
|
|
||||||
|
namespace Piwigo.Client;
|
||||||
|
|
||||||
|
internal class SessionApi : ISessionApi
|
||||||
|
{
|
||||||
|
private readonly IPiwigoContext _context;
|
||||||
|
private readonly ILogger<SessionApi> _logger;
|
||||||
|
|
||||||
|
public SessionApi(IPiwigoContext context, ILogger<SessionApi> logger)
|
||||||
|
{
|
||||||
|
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LogoutAsync()
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Logging out from {Uri}", _context.Config.BaseUri);
|
||||||
|
await _context.ConfigureRequest(_logger).PostMultipartAsync(c => c.AddMethod("pwg.session.logout"));
|
||||||
|
_context.LoggedOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoginAsync()
|
||||||
|
{
|
||||||
|
var userName = _context.Config.UserName;
|
||||||
|
if (string.IsNullOrWhiteSpace(userName))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Value cannot be null or whitespace.", nameof(userName));
|
||||||
|
}
|
||||||
|
|
||||||
|
var password = _context.Config.Password;
|
||||||
|
if (string.IsNullOrWhiteSpace(password))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Value cannot be null or whitespace.", nameof(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_context.IsLoggedIn)
|
||||||
|
{
|
||||||
|
throw new PiwigoException("The client is already logged in. Create a new instance or log out first!");
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Logging into {PiwigoBaseUri} using username {Username}", _context.Config.BaseUri, userName);
|
||||||
|
|
||||||
|
var response = await _context.ConfigureRequest(_logger, false).PostMultipartAsync(c =>
|
||||||
|
c.AddMethod("pwg.session.login").AddString("username", userName).AddString("password", password));
|
||||||
|
|
||||||
|
if (response.StatusCode != (int)HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
_logger.LogError("Failed to log in {StatusCode}", response.StatusCode);
|
||||||
|
throw new PiwigoException($"Could not log in to {_context.Config.BaseUri} using username {userName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Logging in succeeded");
|
||||||
|
_context.LoggedIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PiwigoStatus> GetStatusAsync()
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Getting status");
|
||||||
|
var response = await _context.ConfigureRequest(_logger).PostMultipartAsync(c => c.AddMethod("pwg.session.getStatus"));
|
||||||
|
var typedResponse = await response.GetJsonAsync<PiwigoResponse<PiwigoStatus>>();
|
||||||
|
return typedResponse.Result;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,61 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=PiwigoCleanup/@EntryIndexedValue"><?xml version="1.0" encoding="utf-16"?><Profile name="PiwigoCleanup"><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><CppAddTypenameTemplateKeywords>True</CppAddTypenameTemplateKeywords><CppRemoveCastDescriptor>True</CppRemoveCastDescriptor><CppRemoveElseKeyword>True</CppRemoveElseKeyword><CppShortenQualifiedName>True</CppShortenQualifiedName><CppDeleteRedundantSpecifier>True</CppDeleteRedundantSpecifier><CppRemoveStatement>True</CppRemoveStatement><CppDeleteRedundantTypenameTemplateKeywords>True</CppDeleteRedundantTypenameTemplateKeywords><CppCStyleToStaticCastDescriptor>True</CppCStyleToStaticCastDescriptor><CppReplaceExpressionWithBooleanConst>True</CppReplaceExpressionWithBooleanConst><CppMakeIfConstexpr>True</CppMakeIfConstexpr><CppMakePostfixOperatorPrefix>True</CppMakePostfixOperatorPrefix><CppChangeSmartPointerToMakeFunction>True</CppChangeSmartPointerToMakeFunction><CppReplaceThrowWithRethrowFix>True</CppReplaceThrowWithRethrowFix><CppTypeTraitAliasDescriptor>True</CppTypeTraitAliasDescriptor><CppReplaceExpressionWithNullptr>True</CppReplaceExpressionWithNullptr><CppReplaceTieWithStructuredBindingDescriptor>True</CppReplaceTieWithStructuredBindingDescriptor><CppUseAssociativeContainsDescriptor>True</CppUseAssociativeContainsDescriptor><CppUseEraseAlgorithmDescriptor>True</CppUseEraseAlgorithmDescriptor><CppCodeStyleCleanupDescriptor ArrangeBraces="True" ArrangeAuto="True" ArrangeFunctionDeclarations="True" ArrangeNestedNamespaces="True" ArrangeTypeAliases="True" ArrangeCVQualifiers="True" ArrangeSlashesInIncludeDirectives="True" ArrangeOverridingFunctions="True" SortIncludeDirectives="True" SortMemberInitializers="True" /><CppReformatCode>True</CppReformatCode><CSReorderTypeMembers>True</CSReorderTypeMembers><CSCodeStyleAttributes ArrangeVarStyle="True" ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" ArrangeArgumentsStyle="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeCodeBodyStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" /><RemoveCodeRedundanciesVB>True</RemoveCodeRedundanciesVB><Xaml.RedundantFreezeAttribute>True</Xaml.RedundantFreezeAttribute><Xaml.RemoveRedundantModifiersAttribute>True</Xaml.RemoveRedundantModifiersAttribute><Xaml.RemoveRedundantNameAttribute>True</Xaml.RemoveRedundantNameAttribute><Xaml.RemoveRedundantResource>True</Xaml.RemoveRedundantResource><Xaml.RemoveRedundantCollectionProperty>True</Xaml.RemoveRedundantCollectionProperty><Xaml.RemoveRedundantAttachedPropertySetter>True</Xaml.RemoveRedundantAttachedPropertySetter><Xaml.RemoveRedundantStyledValue>True</Xaml.RemoveRedundantStyledValue><Xaml.RemoveRedundantNamespaceAlias>True</Xaml.RemoveRedundantNamespaceAlias><Xaml.RemoveForbiddenResourceName>True</Xaml.RemoveForbiddenResourceName><Xaml.RemoveRedundantGridDefinitionsAttribute>True</Xaml.RemoveRedundantGridDefinitionsAttribute><Xaml.RemoveRedundantUpdateSourceTriggerAttribute>True</Xaml.RemoveRedundantUpdateSourceTriggerAttribute><Xaml.RemoveRedundantBindingModeAttribute>True</Xaml.RemoveRedundantBindingModeAttribute><Xaml.RemoveRedundantGridSpanAttribut>True</Xaml.RemoveRedundantGridSpanAttribut><XMLReformatCode>True</XMLReformatCode><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><HtmlReformatCode>True</HtmlReformatCode><VBOptimizeImports>True</VBOptimizeImports><VBShortenReferences>True</VBShortenReferences><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><VBReformatCode>True</VBReformatCode><VBFormatDocComments>True</VBFormatDocComments><CSReformatCode>True</CSReformatCode><CSharpFormatDocComments>True</CSharpFormatDocComments><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><IDEA_SETTINGS>&lt;profile version="1.0"&gt;
|
||||||
|
&lt;option name="myName" value="PiwigoCleanup" /&gt;
|
||||||
|
&lt;/profile&gt;</IDEA_SETTINGS><RIDER_SETTINGS>&lt;profile&gt;
|
||||||
|
&lt;Language id="CSS"&gt;
|
||||||
|
&lt;Rearrange&gt;true&lt;/Rearrange&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="EditorConfig"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="HTML"&gt;
|
||||||
|
&lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt;
|
||||||
|
&lt;Rearrange&gt;true&lt;/Rearrange&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="HTTP Request"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="Handlebars"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="Ini"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="JSON"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="Jade"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="JavaScript"&gt;
|
||||||
|
&lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt;
|
||||||
|
&lt;Rearrange&gt;true&lt;/Rearrange&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="Markdown"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="Properties"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="RELAX-NG"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="SQL"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="XML"&gt;
|
||||||
|
&lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt;
|
||||||
|
&lt;Rearrange&gt;true&lt;/Rearrange&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;Language id="yaml"&gt;
|
||||||
|
&lt;Reformat&gt;true&lt;/Reformat&gt;
|
||||||
|
&lt;/Language&gt;
|
||||||
|
&lt;/profile&gt;</RIDER_SETTINGS></Profile></s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue">PiwigoCleanup</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
|
||||||
@ -6,4 +63,8 @@
|
|||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">180</s:Int64>
|
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">180</s:Int64>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Piwigo/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Piwigo/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
Loading…
Reference in New Issue
Block a user