introduce a very simple Nextcloud API
This commit is contained in:
37
Pilz.Networking.CloudProviders.Nextcloud/Extensions.cs
Normal file
37
Pilz.Networking.CloudProviders.Nextcloud/Extensions.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.Model;
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.OCS;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static string ToBasicAuth(this OcsApiAuthCredentials? credentials)
|
||||
{
|
||||
if (credentials != null)
|
||||
{
|
||||
var creds = $"{credentials?.LoginName}:{credentials?.AppPassword}";
|
||||
var bytes = Encoding.UTF8.GetBytes(creds);
|
||||
return "Basic " + Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public static OcsApiAuthCredentials? ToOcsApiAuthCredentials(this NextcloudLogin? login)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(login?.LoginName) && !string.IsNullOrEmpty(login?.AppPassword))
|
||||
return new OcsApiAuthCredentials(login.LoginName, login.AppPassword);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static OcsApiUrlPath FillParameters(this OcsApiUrlPath path, params object?[] @params)
|
||||
{
|
||||
return (OcsApiUrlPath)string.Format(path, @params);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Newtonsoft.Json;
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses.LoginFlowV2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.Model
|
||||
{
|
||||
public class NextcloudLogin
|
||||
{
|
||||
/// <summary>
|
||||
/// The server url the login credentials are for.
|
||||
/// </summary>
|
||||
public string? Server { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The login name (username or password) used for the login.
|
||||
/// </summary>
|
||||
public string? LoginName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The app password that has been generated.
|
||||
/// </summary>
|
||||
public string? AppPassword { get; set; }
|
||||
|
||||
public NextcloudLogin()
|
||||
{
|
||||
}
|
||||
|
||||
public NextcloudLogin(OcsResponseLoginFlowV2Credentials response)
|
||||
{
|
||||
Server = response.Server;
|
||||
LoginName = response.LoginName;
|
||||
AppPassword = response.AppPassword;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.Model
|
||||
{
|
||||
public class UserBackendCapabilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines if the display name can be changed.
|
||||
/// </summary>
|
||||
public bool SetDisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the password can be changed.
|
||||
/// </summary>
|
||||
public bool SetPassword { get; set; }
|
||||
}
|
||||
}
|
||||
131
Pilz.Networking.CloudProviders.Nextcloud/Model/UserInfo.cs
Normal file
131
Pilz.Networking.CloudProviders.Nextcloud/Model/UserInfo.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses.Cloud;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.Model
|
||||
{
|
||||
public class UserInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines if the user is enabled.
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The location of the user's storage directory.
|
||||
/// </summary>
|
||||
public string? StorageLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The uniquie user id that infos are for.
|
||||
/// </summary>
|
||||
public string? ID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The last time when the user has logged in to its account.
|
||||
/// </summary>
|
||||
public DateTime LastLogin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The backend of the user. Common values are "Database" or "LDAP".
|
||||
/// </summary>
|
||||
public string? Backend { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Email address of the user.
|
||||
/// </summary>
|
||||
public string? Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The displayname of the user.
|
||||
/// </summary>
|
||||
public string? Displayname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The displayname of the user.
|
||||
/// </summary>
|
||||
public string? Displayname2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The phone number of the user.
|
||||
/// </summary>
|
||||
public string? Phone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The address of the user.
|
||||
/// </summary>
|
||||
public string? Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Website of the user.
|
||||
/// </summary>
|
||||
public string? Website { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The twitter profile name of the user.
|
||||
/// </summary>
|
||||
public string? Twitter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines the groups the user is member of.
|
||||
/// </summary>
|
||||
public string[] Groups { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The configured language of the user.
|
||||
/// </summary>
|
||||
public string? Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The configured location of the user.
|
||||
/// </summary>
|
||||
public string? Locale { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Quota informations for the user.
|
||||
/// </summary>
|
||||
public UserQuota Quota { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Backend capabilities of the user.
|
||||
/// </summary>
|
||||
public UserBackendCapabilities BackendCapabilities { get; } = new();
|
||||
|
||||
public UserInfo(OcsResponseDataUser responseData)
|
||||
{
|
||||
Enabled = Convert.ToBoolean(responseData.Enabled);
|
||||
StorageLocation = responseData.StorageLocation;
|
||||
ID = responseData.ID;
|
||||
LastLogin = Convert.ToDateTime(responseData.LastLogin);
|
||||
Backend = responseData.Backend;
|
||||
Email = responseData.Email;
|
||||
Displayname = responseData.Displayname;
|
||||
Displayname2 = responseData.Displayname2;
|
||||
Phone = responseData.Phone;
|
||||
Address = responseData.Address;
|
||||
Website = responseData.Website;
|
||||
Twitter = responseData.Twitter;
|
||||
Groups = responseData.Groups ?? Array.Empty<string>();
|
||||
Language = responseData.Language;
|
||||
Locale = responseData.Locale;
|
||||
|
||||
if (responseData.Quota != null)
|
||||
{
|
||||
Quota.Free = responseData.Quota.Free ?? 0;
|
||||
Quota.Used = responseData.Quota.Used ?? 0;
|
||||
Quota.Total = responseData.Quota.Total ?? 0;
|
||||
Quota.Relative = responseData.Quota.Relative ?? 0.0F;
|
||||
Quota.Quota = responseData.Quota.Quota ?? 0;
|
||||
}
|
||||
|
||||
if (responseData.BackendCapabilities != null)
|
||||
{
|
||||
BackendCapabilities.SetDisplayName = Convert.ToBoolean(responseData.BackendCapabilities.SetDisplayName);
|
||||
BackendCapabilities.SetPassword = Convert.ToBoolean(responseData.BackendCapabilities.SetPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Pilz.Networking.CloudProviders.Nextcloud/Model/UserQuota.cs
Normal file
37
Pilz.Networking.CloudProviders.Nextcloud/Model/UserQuota.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.Model
|
||||
{
|
||||
public class UserQuota
|
||||
{
|
||||
/// <summary>
|
||||
/// Amount of free bytes left.
|
||||
/// </summary>
|
||||
public ulong Free { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Amount of already used bytes.
|
||||
/// </summary>
|
||||
public ulong Used { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total amount of all bytes (free + used).
|
||||
/// </summary>
|
||||
public ulong Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Relative amount of used quota in percent.
|
||||
/// </summary>
|
||||
public float Relative { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Total amount of bytes available.
|
||||
/// </summary>
|
||||
public ulong Quota { get; set; }
|
||||
}
|
||||
}
|
||||
129
Pilz.Networking.CloudProviders.Nextcloud/NextcloudClient.cs
Normal file
129
Pilz.Networking.CloudProviders.Nextcloud/NextcloudClient.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Pilz.Networking.CloudProviders.Nextcloud;
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.Model;
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.OCS;
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses.LoginFlowV2;
|
||||
|
||||
namespace ConsoleApp9
|
||||
{
|
||||
public class NextcloudClient : IDisposable
|
||||
{
|
||||
private readonly OcsApi ocs = new();
|
||||
|
||||
public NextcloudLogin? CurrentLogin { get; private set; }
|
||||
|
||||
public NextcloudClient()
|
||||
{
|
||||
ocs.GetOcsApiAuthCredentails += Ocs_GetOcsApiAuthCredentails;
|
||||
}
|
||||
|
||||
private void Ocs_GetOcsApiAuthCredentails(object sender, GetOcsApiAuthCredentailsEventArgs eventArgs)
|
||||
{
|
||||
if (sender == ocs)
|
||||
eventArgs.Credentials = CurrentLogin.ToOcsApiAuthCredentials();
|
||||
}
|
||||
|
||||
public async Task<UserInfo?> LoginAsync(NextcloudLogin login)
|
||||
{
|
||||
// Ensure we are logged out
|
||||
await LogoutAsync();
|
||||
|
||||
// Temporary set user login
|
||||
CurrentLogin = login;
|
||||
|
||||
// Try get user info & check if user is enabled
|
||||
var userInfo = await GetUserInfoAsync();
|
||||
var isValid = userInfo != null && userInfo.Enabled;
|
||||
|
||||
// If invalid, reset login credentials
|
||||
if (!isValid)
|
||||
CurrentLogin = null;
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
public async Task<NextcloudLogin?> LoginAsync(string baseUrl, CancellationToken cancellationToken)
|
||||
{
|
||||
// Ensure we are logged out
|
||||
await LogoutAsync();
|
||||
|
||||
// Init the login process
|
||||
var initResponse = await ocs.LoginFlowV2.Init(baseUrl);
|
||||
|
||||
if (!string.IsNullOrEmpty(initResponse?.LoginUrl) && initResponse.Poll != null)
|
||||
{
|
||||
// Open the browser
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = initResponse.LoginUrl,
|
||||
UseShellExecute = true
|
||||
});
|
||||
|
||||
// Poll for credentails in intervals
|
||||
OcsResponseLoginFlowV2Credentials? pollResponse = null;
|
||||
while (!cancellationToken.IsCancellationRequested && pollResponse is null)
|
||||
{
|
||||
// Wait 5 seconds
|
||||
Thread.Sleep(5000);
|
||||
|
||||
// Poll the credentials
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
pollResponse = await ocs.LoginFlowV2.Poll(initResponse.Poll);
|
||||
}
|
||||
|
||||
// Check login credentials
|
||||
if (pollResponse is not null)
|
||||
CurrentLogin = new(pollResponse);
|
||||
}
|
||||
|
||||
return CurrentLogin;
|
||||
}
|
||||
|
||||
public Task<UserInfo?> GetUserInfoAsync()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(CurrentLogin?.LoginName))
|
||||
return GetUserInfoAsync(CurrentLogin.LoginName);
|
||||
else
|
||||
return Task.FromResult<UserInfo?>(null);
|
||||
}
|
||||
|
||||
public async Task<UserInfo?> GetUserInfoAsync(string username)
|
||||
{
|
||||
var result = await ocs.Cloud.GetUserMeta(username);
|
||||
|
||||
if (result?.Data != null)
|
||||
return new UserInfo(result.Data);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task LogoutAsync()
|
||||
{
|
||||
return LogoutAsync(true);
|
||||
}
|
||||
|
||||
public async Task LogoutAsync(bool logoutOnServer)
|
||||
{
|
||||
if (CurrentLogin != null)
|
||||
{
|
||||
// Delete currently used app password
|
||||
await ocs.Core.DeleteAppPassword();
|
||||
|
||||
// Reset current login infos
|
||||
CurrentLogin = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ocs.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.APIs
|
||||
{
|
||||
public abstract class OcsApiBase
|
||||
{
|
||||
public OcsApi Manager { get; init; }
|
||||
|
||||
protected OcsApiBase(OcsApi manager)
|
||||
{
|
||||
Manager = manager;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses.Cloud;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.APIs
|
||||
{
|
||||
public class OcsApiCloud : OcsApiBase
|
||||
{
|
||||
public readonly static OcsApiUrlPath OCS_CLOUD_USER_METADATA = new("/ocs/v1.php/cloud/users/{0}");
|
||||
|
||||
public OcsApiCloud(OcsApi manager) : base(manager)
|
||||
{
|
||||
}
|
||||
|
||||
public Task<OcsResponseUser?> GetUserMeta(string username)
|
||||
{
|
||||
return Manager.MakeRequestJson<OcsResponseUser>(HttpMethod.Get, OCS_CLOUD_USER_METADATA.FillParameters(username));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.APIs
|
||||
{
|
||||
public class OcsApiCore : OcsApiBase
|
||||
{
|
||||
public static readonly OcsApiUrlPath OCS_CORE_APPPASSWORD = "/ocs/v2.php/core/apppassword";
|
||||
|
||||
public OcsApiCore(OcsApi manager) : base(manager)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAppPassword()
|
||||
{
|
||||
using var msg = await Manager.MakeRequest(HttpMethod.Delete, OCS_CORE_APPPASSWORD);
|
||||
return msg != null && msg.IsSuccessStatusCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses.LoginFlowV2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.APIs
|
||||
{
|
||||
public class OcsApiLoginFlowV2 : OcsApiBase
|
||||
{
|
||||
private const string OCS_LOGIN_INIT = "/index.php/login/v2";
|
||||
|
||||
public OcsApiLoginFlowV2(OcsApi manager) : base(manager)
|
||||
{
|
||||
}
|
||||
|
||||
public Task<OcsResponseLoginFlowV2?> Init(string url)
|
||||
{
|
||||
return Manager.MakeRequestJson<OcsResponseLoginFlowV2>(HttpMethod.Get, url + OCS_LOGIN_INIT);
|
||||
}
|
||||
|
||||
public Task<OcsResponseLoginFlowV2Credentials?> Poll(OcsResponseLoginFlowV2.PollData poll)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(poll?.Endpoint);
|
||||
ArgumentNullException.ThrowIfNull(poll?.Token);
|
||||
|
||||
return Manager.MakeRequestJson<OcsResponseLoginFlowV2Credentials?>(HttpMethod.Get, poll.Endpoint,
|
||||
parameters: new Dictionary<string, string>
|
||||
{
|
||||
{ "token", poll.Token }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS
|
||||
{
|
||||
public delegate void GetOcsApiAuthCredentailsEventHandler(object sender, GetOcsApiAuthCredentailsEventArgs eventArgs);
|
||||
|
||||
public class GetOcsApiAuthCredentailsEventArgs : EventArgs
|
||||
{
|
||||
public OcsApiAuthCredentials? Credentials { get; set; }
|
||||
}
|
||||
}
|
||||
104
Pilz.Networking.CloudProviders.Nextcloud/OCS/OcsApi.cs
Normal file
104
Pilz.Networking.CloudProviders.Nextcloud/OCS/OcsApi.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using Pilz.Networking.CloudProviders.Nextcloud.OCS.APIs;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS
|
||||
{
|
||||
public class OcsApi : IDisposable
|
||||
{
|
||||
public event GetOcsApiAuthCredentailsEventHandler? GetOcsApiAuthCredentails;
|
||||
|
||||
private readonly HttpClient client = new();
|
||||
|
||||
public string BaseUrl { get; set; } = string.Empty;
|
||||
|
||||
public OcsApiLoginFlowV2 LoginFlowV2 { get; init; }
|
||||
public OcsApiCore Core { get; init; }
|
||||
public OcsApiCloud Cloud { get; init; }
|
||||
|
||||
public OcsApi()
|
||||
{
|
||||
LoginFlowV2 = new(this);
|
||||
Core = new(this);
|
||||
Cloud = new(this);
|
||||
}
|
||||
|
||||
public string BuildFullUrl(OcsApiUrlPath path)
|
||||
{
|
||||
return BaseUrl + path;
|
||||
}
|
||||
|
||||
public Task<TResponse?> MakeRequestJson<TResponse>(HttpMethod httpMethod, OcsApiUrlPath url, bool useAuthentication = true, Dictionary<string, string>? parameters = null)
|
||||
{
|
||||
return MakeRequestJson<TResponse>(httpMethod, BuildFullUrl(url), useAuthentication: useAuthentication, parameters: parameters);
|
||||
}
|
||||
|
||||
public Task<HttpResponseMessage> MakeRequest(HttpMethod httpMethod, OcsApiUrlPath url, bool useAuthentication = true, Dictionary<string, string>? parameters = null)
|
||||
{
|
||||
return MakeRequest(httpMethod, BuildFullUrl(url), useAuthentication: useAuthentication, parameters: parameters);
|
||||
}
|
||||
|
||||
public async Task<TResponse?> MakeRequestJson<TResponse>(HttpMethod httpMethod, string url, bool useAuthentication = true, Dictionary<string, string>? parameters = null)
|
||||
{
|
||||
using var responseInit = await MakeRequest(httpMethod, url, useAuthentication: useAuthentication, parameters: parameters);
|
||||
|
||||
if (responseInit != null)
|
||||
{
|
||||
var bodyInit = await responseInit.Content.ReadAsStringAsync();
|
||||
return JsonConvert.DeserializeObject<TResponse>(bodyInit);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public async Task<HttpResponseMessage> MakeRequest(HttpMethod httpMethod, string url, bool useAuthentication = true, Dictionary<string, string>? parameters = null)
|
||||
{
|
||||
OcsApiAuthCredentials? authentication;
|
||||
string @params;
|
||||
|
||||
// Get authentication
|
||||
if (useAuthentication)
|
||||
{
|
||||
var args = new GetOcsApiAuthCredentailsEventArgs();
|
||||
GetOcsApiAuthCredentails?.Invoke(this, args);
|
||||
authentication = args.Credentials;
|
||||
}
|
||||
else
|
||||
authentication = null;
|
||||
|
||||
// Parse params
|
||||
if (parameters != null)
|
||||
@params = "?" + string.Join(",", parameters.Select(p => $"{p.Key}={p.Value}"));
|
||||
else
|
||||
@params = string.Empty;
|
||||
|
||||
// Send request
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
Method = httpMethod ?? HttpMethod.Post,
|
||||
RequestUri = new Uri(url + @params),
|
||||
Headers =
|
||||
{
|
||||
{ "Accept", "application/json" },
|
||||
{ "OCS-APIREQUEST", "true" },
|
||||
{ "Authorization", authentication.ToBasicAuth() }
|
||||
},
|
||||
};
|
||||
|
||||
return await client.SendAsync(request);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
client.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS
|
||||
{
|
||||
public struct OcsApiAuthCredentials
|
||||
{
|
||||
public string LoginName { get; set; }
|
||||
public string AppPassword { get; set; }
|
||||
|
||||
public OcsApiAuthCredentials(string loginName, string appPassword)
|
||||
{
|
||||
LoginName = loginName;
|
||||
AppPassword = appPassword;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS
|
||||
{
|
||||
public readonly struct OcsApiUrlPath
|
||||
{
|
||||
private readonly string path;
|
||||
|
||||
public OcsApiUrlPath()
|
||||
{
|
||||
path = string.Empty;
|
||||
}
|
||||
|
||||
public OcsApiUrlPath(string path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public static implicit operator string(OcsApiUrlPath o) => o.path;
|
||||
public static implicit operator OcsApiUrlPath(string o) => new(o);
|
||||
|
||||
public override readonly string ToString()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses.Cloud
|
||||
{
|
||||
public class OcsResponseDataUser : OcsResponseData
|
||||
{
|
||||
public class ResponseQuota
|
||||
{
|
||||
[JsonProperty("free")]
|
||||
public ulong? Free { get; set; }
|
||||
|
||||
[JsonProperty("used")]
|
||||
public ulong? Used { get; set; }
|
||||
|
||||
[JsonProperty("total")]
|
||||
public ulong? Total { get; set; }
|
||||
|
||||
[JsonProperty("relative")]
|
||||
public float? Relative { get; set; }
|
||||
|
||||
[JsonProperty("quota")]
|
||||
public ulong? Quota { get; set; }
|
||||
}
|
||||
|
||||
public class ResponseBackendCapabilities
|
||||
{
|
||||
[JsonProperty("setDisplayName")]
|
||||
public int? SetDisplayName { get; set; }
|
||||
|
||||
[JsonProperty("setPassword")]
|
||||
public int? SetPassword { get; set; }
|
||||
}
|
||||
|
||||
[JsonProperty("enabled")]
|
||||
public int? Enabled { get; set; }
|
||||
|
||||
[JsonProperty("storageLocation")]
|
||||
public string? StorageLocation { get; set; }
|
||||
|
||||
[JsonProperty("id")]
|
||||
public string? ID { get; set; }
|
||||
|
||||
[JsonProperty("lastLogin")]
|
||||
public ulong? LastLogin { get; set; }
|
||||
|
||||
[JsonProperty("backend")]
|
||||
public string? Backend { get; set; }
|
||||
|
||||
[JsonProperty("quota")]
|
||||
public ResponseQuota? Quota { get; set; }
|
||||
|
||||
[JsonProperty("email")]
|
||||
public string? Email { get; set; }
|
||||
|
||||
[JsonProperty("displayname")]
|
||||
public string? Displayname { get; set; }
|
||||
|
||||
[JsonProperty("display-name")]
|
||||
public string? Displayname2 { get; set; }
|
||||
|
||||
[JsonProperty("phone")]
|
||||
public string? Phone { get; set; }
|
||||
|
||||
[JsonProperty("address")]
|
||||
public string? Address { get; set; }
|
||||
|
||||
[JsonProperty("website")]
|
||||
public string? Website { get; set; }
|
||||
|
||||
[JsonProperty("twitter")]
|
||||
public string? Twitter { get; set; }
|
||||
|
||||
[JsonProperty("groups")]
|
||||
public string[]? Groups { get; set; }
|
||||
|
||||
[JsonProperty("language")]
|
||||
public string? Language { get; set; }
|
||||
|
||||
[JsonProperty("locale")]
|
||||
public string? Locale { get; set; }
|
||||
|
||||
[JsonProperty("backendCapabilities")]
|
||||
public ResponseBackendCapabilities? BackendCapabilities { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses.Cloud
|
||||
{
|
||||
public class OcsResponseUser : OcsResponse<OcsResponseDataUser>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses.LoginFlowV2
|
||||
{
|
||||
public class OcsResponseLoginFlowV2
|
||||
{
|
||||
public class PollData
|
||||
{
|
||||
/// <summary>
|
||||
/// The login token that has been created for the login process.
|
||||
/// It can be used to poll the login state.
|
||||
/// </summary>
|
||||
[JsonProperty("token")]
|
||||
public string? Token { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[JsonProperty("endpoint")]
|
||||
public string? Endpoint { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[JsonProperty("poll")]
|
||||
public PollData? Poll { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The temporary login url that should be used for login.
|
||||
/// </summary>
|
||||
[JsonProperty("login")]
|
||||
public string? LoginUrl { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses.LoginFlowV2
|
||||
{
|
||||
public class OcsResponseLoginFlowV2Credentials
|
||||
{
|
||||
/// <summary>
|
||||
/// The server url the login credentials are for.
|
||||
/// </summary>
|
||||
[JsonProperty("server")]
|
||||
public string? Server { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The login name (username or password) used for the login.
|
||||
/// </summary>
|
||||
[JsonProperty("loginName")]
|
||||
public string? LoginName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The app password that has been generated.
|
||||
/// </summary>
|
||||
[JsonProperty("appPassword")]
|
||||
public string? AppPassword { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses
|
||||
{
|
||||
public class OcsResponse<TMeta, TData> where TMeta : OcsResponseMeta where TData : OcsResponseData
|
||||
{
|
||||
[JsonProperty("meta")]
|
||||
public TMeta? Meta { get; set; }
|
||||
|
||||
[JsonProperty("data")]
|
||||
public TData? Data { get; set; }
|
||||
}
|
||||
|
||||
public class OcsResponse<TData> : OcsResponse<OcsResponseMeta, TData> where TData : OcsResponseData
|
||||
{
|
||||
}
|
||||
|
||||
public class OcsResponse : OcsResponse<OcsResponseMeta, OcsResponseData>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses
|
||||
{
|
||||
public class OcsResponseData
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pilz.Networking.CloudProviders.Nextcloud.OCS.Responses
|
||||
{
|
||||
public class OcsResponseMeta
|
||||
{
|
||||
[JsonProperty("status")]
|
||||
public string? Status { get; set; }
|
||||
|
||||
[JsonProperty("statuscode")]
|
||||
public int? StatusCode { get; set; }
|
||||
|
||||
[JsonProperty("message")]
|
||||
public string? Message { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<IncrementVersionOnBuild>1.yyyy.Mdd.Hmm</IncrementVersionOnBuild>
|
||||
<Version>1.2023.927.1412</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
12
Pilz.sln
12
Pilz.sln
@@ -33,7 +33,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pilz.Cryptography", "Pilz.C
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pilz.UI.Telerik.SymbolFactory", "Pilz.UI.Telerik.SymbolFactory\Pilz.UI.Telerik.SymbolFactory.csproj", "{2B3B8161-29FF-4526-9082-4410AB5144A5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pilz.UI.Telerik", "Pilz.UI.Telerik\Pilz.UI.Telerik.csproj", "{DF674119-CC28-40AA-968F-1E23D184A491}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pilz.UI.Telerik", "Pilz.UI.Telerik\Pilz.UI.Telerik.csproj", "{DF674119-CC28-40AA-968F-1E23D184A491}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pilz.Networking.CloudProviders.Nextcloud", "Pilz.Networking.CloudProviders.Nextcloud\Pilz.Networking.CloudProviders.Nextcloud.csproj", "{A91E966B-3A82-4F32-A703-2FC1C7654FD1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -171,6 +173,14 @@ Global
|
||||
{DF674119-CC28-40AA-968F-1E23D184A491}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DF674119-CC28-40AA-968F-1E23D184A491}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DF674119-CC28-40AA-968F-1E23D184A491}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A91E966B-3A82-4F32-A703-2FC1C7654FD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A91E966B-3A82-4F32-A703-2FC1C7654FD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A91E966B-3A82-4F32-A703-2FC1C7654FD1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A91E966B-3A82-4F32-A703-2FC1C7654FD1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A91E966B-3A82-4F32-A703-2FC1C7654FD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A91E966B-3A82-4F32-A703-2FC1C7654FD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A91E966B-3A82-4F32-A703-2FC1C7654FD1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A91E966B-3A82-4F32-A703-2FC1C7654FD1}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user