Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust to a DI structure #40

Merged
merged 3 commits into from
Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Gotrue/Api.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
using System.Web;
using Newtonsoft.Json;
using Supabase.Gotrue.Attributes;
using Supabase.Gotrue.Interfaces;
using Supabase.Gotrue.Responses;
using static Supabase.Gotrue.Client;
using static Supabase.Gotrue.Constants;

namespace Supabase.Gotrue
{
public class Api
public class Api : IGotrueApi<User, Session>
{
protected string Url { get; private set; }
protected Dictionary<string, string> Headers = new Dictionary<string, string>();
Expand Down Expand Up @@ -243,7 +244,7 @@ internal Dictionary<string, string> CreateAuthedRequestHeaders(string jwt)
/// <param name="provider"></param>
/// <param name="scopes">A space-separated list of scopes granted to the OAuth application.</param>
/// <returns></returns>
internal string GetUrlForProvider(Provider provider, string scopes = null)
public string GetUrlForProvider(Provider provider, string scopes = null)
{
var builder = new UriBuilder($"{Url}/authorize");
var attr = Helpers.GetMappedToAttr(provider);
Expand Down Expand Up @@ -319,11 +320,11 @@ public Task<User> UpdateUser(string jwt, UserAttributes attributes)
/// <param name="page">page to show for pagination</param>
/// <param name="perPage">items per page for pagination</param>
/// <returns></returns>
public Task<UserList> ListUsers(string jwt, string filter = null, string sortBy = null, SortOrder sortOrder = SortOrder.Descending, int? page = null, int? perPage = null)
public Task<UserList<User>> ListUsers(string jwt, string filter = null, string sortBy = null, SortOrder sortOrder = SortOrder.Descending, int? page = null, int? perPage = null)
{
var data = TransformListUsersParams(filter, sortBy, sortOrder, page, perPage);

return Helpers.MakeRequest<UserList>(HttpMethod.Get, $"{Url}/admin/users", data, CreateAuthedRequestHeaders(jwt));
return Helpers.MakeRequest<UserList<User>>(HttpMethod.Get, $"{Url}/admin/users", data, CreateAuthedRequestHeaders(jwt));
}

internal Dictionary<string, string> TransformListUsersParams(string filter = null, string sortBy = null, SortOrder sortOrder = SortOrder.Descending, int? page = null, int? perPage = null)
Expand Down
159 changes: 19 additions & 140 deletions Gotrue/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,108 +6,20 @@
using System.Threading.Tasks;
using System.Web;
using Supabase.Gotrue.Attributes;
using static Supabase.Gotrue.Api;
using static Supabase.Gotrue.Client;
using Supabase.Gotrue.Interfaces;
using static Supabase.Gotrue.Constants;

namespace Supabase.Gotrue
{
/// <summary>
/// The Gotrue Client - a singleton class
/// The Gotrue Instance
/// </summary>
/// <example>
/// var client = Supabase.Gotrue.Client.Initialize(options);
/// var user = await client.SignIn("user@email.com", "fancyPassword");
/// </example>
public class Client
public class Client : IGotrueClient<User, Session>
{
/// <summary>
/// Specifies the functionality expected from the `SignIn` method
/// </summary>
public enum SignInType
{
Email,
Phone,
RefreshToken,
}

/// <summary>
/// Specifies the functionality expected from the `SignUp` method
/// </summary>
public enum SignUpType
{
Email,
Phone
}

/// <summary>
/// Providers available to Supabase
/// Ref: https://supabase.github.io/gotrue-js/modules.html#Provider
/// </summary>
public enum Provider
{
[MapTo("apple")]
Apple,
[MapTo("azure")]
Azure,
[MapTo("bitbucket")]
Bitbucket,
[MapTo("discord")]
Discord,
[MapTo("facebook")]
Facebook,
[MapTo("github")]
Github,
[MapTo("gitlab")]
Gitlab,
[MapTo("google")]
Google,
[MapTo("keycloak")]
KeyCloak,
[MapTo("linkedin")]
LinkedIn,
[MapTo("notion")]
Notion,
[MapTo("slack")]
Slack,
[MapTo("spotify")]
Spotify,
[MapTo("twitch")]
Twitch,
[MapTo("twitter")]
Twitter,
[MapTo("workos")]
WorkOS
};

/// <summary>
/// States that the Auth Client will raise events for.
/// </summary>
public enum AuthState
{
SignedIn,
SignedOut,
UserUpdated,
PasswordRecovery,
TokenRefreshed
};

private static Client instance;
/// <summary>
/// Returns the current instance of this client.
/// </summary>
public static Client Instance
{
get
{
if (instance == null)
{
throw new Exception("`Initialize` must be called prior to accessing `Instance`");
}
return instance;
}
}

/// <summary>
/// Event Handler that raises an event when a user signs in, signs out, recovers password, or updates their record.
/// </summary>
Expand Down Expand Up @@ -158,63 +70,30 @@ public static Client Instance
/// </summary>
private Timer refreshTimer = null;

private Api api;

/// <summary>
/// Private constructor for Singleton initialization
/// </summary>
private Client() { }
private IGotrueApi<User, Session> api;

/// <summary>
/// Initializes a Client.
///
/// Though <see cref="ClientOptions"/> <paramref name="options"/> are ... optional, one will likely
/// need to define, at the very least, <see cref="ClientOptions.Url"/>.
///
/// If awaited, will asyncronously grab the session via <see cref="SessionRetriever"/>
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
public static void Initialize(ClientOptions options = null, Action<Client> callback = null)
{
Task.Run(async () =>
{
var client = await InitializeAsync(options);
callback?.Invoke(client);
});
}

/// <summary>
/// Initializes a Client Asynchronously.
///
/// Though <see cref="ClientOptions"/> <paramref name="options"/> are ... optional, one will likely
/// need to define, at the very least, <see cref="ClientOptions.Url"/>.
///
/// If awaited, will asyncronously grab the session via <see cref="SessionRetriever"/>
/// Initializes the Client.
///
/// Although options are ... optional, you will likely want to at least specify a <see cref="ClientOptions.Url"/>.
///
/// Sessions are no longer automatically retrieved on construction, if you want to set the session, <see cref="RetrieveSessionAsync"/>
///
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
public static async Task<Client> InitializeAsync(ClientOptions options = null)
public Client(ClientOptions options = null)
{
instance = new Client();

if (options == null)
options = new ClientOptions();

instance.Options = options;
instance.AutoRefreshToken = options.AutoRefreshToken;
instance.ShouldPersistSession = options.PersistSession;
instance.SessionPersistor = options.SessionPersistor;
instance.SessionRetriever = options.SessionRetriever;
instance.SessionDestroyer = options.SessionDestroyer;

instance.api = new Api(options.Url, options.Headers);

// Retrieve the session
if (instance.ShouldPersistSession)
await instance.RetrieveSessionAsync();
Options = options;
AutoRefreshToken = options.AutoRefreshToken;
ShouldPersistSession = options.PersistSession;
SessionPersistor = options.SessionPersistor;
SessionRetriever = options.SessionRetriever;
SessionDestroyer = options.SessionDestroyer;

return instance;
api = new Api(options.Url, options.Headers);
}

/// <summary>
Expand Down Expand Up @@ -570,7 +449,7 @@ public async Task<bool> DeleteUser(string uid, string jwt)
/// <param name="page">page to show for pagination</param>
/// <param name="perPage">items per page for pagination</param>
/// <returns></returns>
public async Task<UserList> ListUsers(string jwt, string filter = null, string sortBy = null, SortOrder sortOrder = SortOrder.Descending, int? page = null, int? perPage = null)
public async Task<UserList<User>> ListUsers(string jwt, string filter = null, string sortBy = null, SortOrder sortOrder = SortOrder.Descending, int? page = null, int? perPage = null)
{
try
{
Expand Down
71 changes: 71 additions & 0 deletions Gotrue/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,76 @@ public enum EmailOtpType
[MapTo("email_change")]
EmailChange
}

/// <summary>
/// Providers available to Supabase
/// Ref: https://supabase.github.io/gotrue-js/modules.html#Provider
/// </summary>
public enum Provider
{
[MapTo("apple")]
Apple,
[MapTo("azure")]
Azure,
[MapTo("bitbucket")]
Bitbucket,
[MapTo("discord")]
Discord,
[MapTo("facebook")]
Facebook,
[MapTo("github")]
Github,
[MapTo("gitlab")]
Gitlab,
[MapTo("google")]
Google,
[MapTo("keycloak")]
KeyCloak,
[MapTo("linkedin")]
LinkedIn,
[MapTo("notion")]
Notion,
[MapTo("slack")]
Slack,
[MapTo("spotify")]
Spotify,
[MapTo("twitch")]
Twitch,
[MapTo("twitter")]
Twitter,
[MapTo("workos")]
WorkOS
};

/// <summary>
/// States that the Auth Client will raise events for.
/// </summary>
public enum AuthState
{
SignedIn,
SignedOut,
UserUpdated,
PasswordRecovery,
TokenRefreshed
};

/// <summary>
/// Specifies the functionality expected from the `SignIn` method
/// </summary>
public enum SignInType
{
Email,
Phone,
RefreshToken,
}

/// <summary>
/// Specifies the functionality expected from the `SignUp` method
/// </summary>
public enum SignUpType
{
Email,
Phone
}
}
}
32 changes: 32 additions & 0 deletions Gotrue/Interfaces/IGotrueApi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Supabase.Gotrue.Responses;
using System.Threading.Tasks;
using static Supabase.Gotrue.Constants;

namespace Supabase.Gotrue.Interfaces
{
public interface IGotrueApi<TUser, TSession>
where TUser : User
where TSession : Session
{
Task<TUser> CreateUser(string jwt, AdminUserAttributes attributes = null);
Task<BaseResponse> DeleteUser(string uid, string jwt);
Task<TUser> GetUser(string jwt);
Task<TUser> GetUserById(string jwt, string userId);
Task<BaseResponse> InviteUserByEmail(string email, string jwt);
Task<UserList<TUser>> ListUsers(string jwt, string filter = null, string sortBy = null, Constants.SortOrder sortOrder = Constants.SortOrder.Descending, int? page = null, int? perPage = null);
Task<TSession> RefreshAccessToken(string refreshToken);
Task<BaseResponse> ResetPasswordForEmail(string email);
Task<BaseResponse> SendMagicLinkEmail(string email, SignInOptions options = null);
Task<BaseResponse> SendMobileOTP(string phone);
Task<TSession> SignInWithEmail(string email, string password);
Task<TSession> SignInWithPhone(string phone, string password);
Task<BaseResponse> SignOut(string jwt);
Task<TSession> SignUpWithEmail(string email, string password, SignUpOptions options = null);
Task<TSession> SignUpWithPhone(string phone, string password, SignUpOptions options = null);
Task<TUser> UpdateUser(string jwt, UserAttributes attributes);
Task<TUser> UpdateUserById(string jwt, string userId, UserAttributes userData);
Task<TSession> VerifyMobileOTP(string phone, string token, MobileOtpType type);
Task<TSession> VerifyEmailOTP(string email, string token, EmailOtpType type);
string GetUrlForProvider(Provider provider, string scopes = null);
}
}
41 changes: 41 additions & 0 deletions Gotrue/Interfaces/IGotrueClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Threading.Tasks;
using static Supabase.Gotrue.Constants;

namespace Supabase.Gotrue.Interfaces
{
public interface IGotrueClient<TUser, TSession>
where TUser : User
where TSession : Session
{
TSession CurrentSession { get; }
TUser CurrentUser { get; }

event EventHandler<ClientStateChanged> StateChanged;
Task<TUser> CreateUser(string jwt, AdminUserAttributes attributes);
Task<TUser> CreateUser(string jwt, string email, string password, AdminUserAttributes attributes = null);
Task<bool> DeleteUser(string uid, string jwt);
Task<TSession> GetSessionFromUrl(Uri uri, bool storeSession = true);
Task<TUser> GetUser(string jwt);
Task<TUser> GetUserById(string jwt, string userId);
Task<bool> InviteUserByEmail(string email, string jwt);
Task<UserList<TUser>> ListUsers(string jwt, string filter = null, string sortBy = null, Constants.SortOrder sortOrder = Constants.SortOrder.Descending, int? page = null, int? perPage = null);
Task<TSession> RefreshSession();
Task<bool> ResetPasswordForEmail(string email);
Task<TSession> RetrieveSessionAsync();
Task<bool> SendMagicLink(string email, SignInOptions options = null);
TSession SetAuth(string accessToken);
Task<string> SignIn(Provider provider, string scopes = null);
Task<TSession> SignIn(SignInType type, string identifierOrToken, string password = null, string scopes = null);
Task<bool> SignIn(string email, SignInOptions options = null);
Task<TSession> SignIn(string email, string password);
Task<TSession> SignInWithPassword(string email, string password);
Task SignOut();
Task<TSession> SignUp(SignUpType type, string identifier, string password, SignUpOptions options = null);
Task<TSession> SignUp(string email, string password, SignUpOptions options = null);
Task<TUser> Update(UserAttributes attributes);
Task<TUser> UpdateUserById(string jwt, string userId, AdminUserAttributes userData);
Task<TSession> VerifyOTP(string phone, string token, MobileOtpType type = MobileOtpType.SMS);
Task<TSession> VerifyOTP(string email, string token, EmailOtpType type = EmailOtpType.MagicLink);
}
}
Loading