Skip to content

Example code update with CustomSupabaseSessionHandler and new page example with RLS #40

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

Merged
merged 4 commits into from
Nov 23, 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
11 changes: 11 additions & 0 deletions Examples/BlazorWebAssemblySupabaseTemplate/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch and Debug Standalone Blazor WebAssembly App",
"type": "blazorwasm",
"request": "launch",
"cwd": "${workspaceFolder}"
}
]
}
41 changes: 41 additions & 0 deletions Examples/BlazorWebAssemblySupabaseTemplate/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/BlazorWebAssemblySupabaseTemplate.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/BlazorWebAssemblySupabaseTemplate.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/BlazorWebAssemblySupabaseTemplate.csproj"
],
"problemMatcher": "$msCompile"
}
]
}
19 changes: 19 additions & 0 deletions Examples/BlazorWebAssemblySupabaseTemplate/Dtos/TodoPrivate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using Postgrest.Attributes;
using Postgrest.Models;
using Supabase;

namespace BlazorWebAssemblySupabaseTemplate.Dtos;

[Table("TodoPrivate")]
public class TodoPrivate : BaseModel
{
[PrimaryKey("id", false)] // Key is Autogenerated
public int Id { get; set; }

[Column("title")]
public string? Title { get; set; }

[Column("user_id")]
public string User_id { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
@page "/crud-private"
@using Dtos
@using Blazored.LocalStorage

@inject DatabaseService DatabaseService
@inject NavigationManager NavigationManager
@inject ISnackbar Snackbar
@inject ILocalStorageService localStorage

<div class="pa-16">

<MudText Typo="Typo.h5">Todos private by RLS</MudText>
<br>
<MudForm @ref="form" @bind-IsValid="@success" @bind-Errors="@errors" ValidationDelay="0">
<MudCard>
<MudCardHeader>
<CardHeaderContent>
<h4>New item</h4>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent>
<MudTextField Label="Title" @bind-Value="model.Title" For="@(() => model.Title)" Required="true"
Immediate="true" />
</MudCardContent>
<MudCardActions>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Disabled="@(!success)" Class="ml-auto"
OnClick="OnClickSave">
@if (_processingNewItem)
{
<MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" />
<MudText Class="ms-2">Processing</MudText>
}
else
{
<MudText>Save</MudText>
}
</MudButton>
</MudCardActions>

</MudCard>
</MudForm>

<br>

@if (_todoListFiltered == null)
{
<MudSimpleTable>
<thead>
<tr>
<th>Title</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><MudSkeleton /></td>
<td><MudSkeleton /></td>
</tr>
</tbody>
</MudSimpleTable>
}
else if (_todoListFiltered.Count == 0)
{
<MudSimpleTable>
<thead>
<tr>
<th>Title</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<br>
<MudText Typo="Typo.body1" Align="Align.Center">There is no items in this table.</MudText>
<br>
</tbody>
</MudSimpleTable>
}
else
{
<MudTable Items="@_todoListFiltered" @ref="table" Elevation="1" Bordered="false" Striped="true" Hover="true"
SortLabel="Sort By" T="TodoPrivate">
<ToolBarContent>
<MudTextField T="string" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search"
IconSize="MudBlazor.Size.Medium" Class="mt-0" Clearable="true"
ValueChanged="@(s=>OnValueChangedSearch(s))" Placeholder="Search" />
</ToolBarContent>
<HeaderContent>
<MudTh>
<MudTableSortLabel SortBy="new Func<TodoPrivate, object>(x=>x.Title)">
Title
</MudTableSortLabel>
<MudTableSortLabel SortBy="new Func<TodoPrivate, object>(x=>x.User_id)">
User_id
</MudTableSortLabel>
</MudTh>
<MudTh>
Action
</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Title">@context?.Title</MudTd>
<MudTd DataLabel="User_id">@context?.User_id</MudTd>
<MudTd DataLabel="Action">
@* <MudIconButton Icon="@Icons.Material.Filled.Edit" aria-label="edit"
Size="MudBlazor.Size.Small"
OnClick="@( (e) => {NavigationManager.NavigateTo($"/todoitems/{context?.Todo?.Id}");})"
/> *@
<MudIconButton Icon="@Icons.Material.Filled.Delete" aria-label="delete" Size="MudBlazor.Size.Small"
OnClick="@(async (e) => {await OnClickDelete(context);})" />
</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager PageSizeOptions="new int[]{50, 100}" />
</PagerContent>
</MudTable>
}

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using BlazorWebAssemblySupabaseTemplate.Dtos;
using BlazorWebAssemblySupabaseTemplate.Services;
using MudBlazor;

namespace BlazorWebAssemblySupabaseTemplate.Pages.CrudPrivate;

public partial class CrudPagePrivate
{
protected override async Task OnInitializedAsync()
{
await GetTable();
}

// ---------------- SELECT TABLE
private IReadOnlyList<TodoPrivate>? _todoList { get; set; }
private IReadOnlyList<TodoPrivate>? _todoListFiltered { get; set; }
private MudTable<TodoPrivate>? table;
protected async Task GetTable()
{
// await Task.Delay(10000);
IReadOnlyList<TodoPrivate> todos = await DatabaseService.From<TodoPrivate>();
_todoList = todos;
_todoListFiltered = todos;
await InvokeAsync(StateHasChanged);
}

// ---------------- SEARCH
private void OnValueChangedSearch(string text)
{
_todoListFiltered = _todoList?.Where(row => row.Title.Contains(text)).ToList();
}

// ---------------- DELETE
private async Task OnClickDelete(TodoPrivate item)
{
await DatabaseService.Delete<TodoPrivate>(item);
await GetTable();
}

// ---------------- CREATE NEW

protected TodoPrivate model = new();
private bool success = false;
string[] errors = { };
MudForm? form;
private bool _processingNewItem = false;
private async Task OnClickSave()
{
string user_id = await localStorage.GetItemAsync<string>("user_id");

model.User_id = user_id;
_processingNewItem = true;
await DatabaseService.Insert<TodoPrivate>(model);
model = new();
await GetTable();
success = false;
_processingNewItem = false;
}
}
29 changes: 25 additions & 4 deletions Examples/BlazorWebAssemblySupabaseTemplate/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,37 @@


// ---------- BLAZOR AUTH
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>(
provider => new CustomAuthStateProvider(
provider.GetRequiredService<ILocalStorageService>(),
provider.GetRequiredService<Supabase.Client>()
)
)
;
builder.Services.AddAuthorizationCore();



// ---------- SUPABASE
var url = "https://pylnesfgmytjegzzculn.supabase.co";
var key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InB5bG5lc2ZnbXl0amVnenpjdWxuIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NjgyOTMwMzcsImV4cCI6MTk4Mzg2OTAzN30.kI29Q_qYWDH5SD6oi5NTwHG6Pxy1e1AUfR8s_ga45lE";

builder.Services.AddScoped<ISupabaseClient<User, Session, Socket, Channel, Bucket, FileObject>>(args => new Supabase.Client(url, key, new Supabase.SupabaseOptions { AutoConnectRealtime = true }));
builder.Services.AddScoped<Supabase.Client>(
provider => new Supabase.Client(
url,
key,
new Supabase.SupabaseOptions
{
AutoRefreshToken = true,
AutoConnectRealtime = true,
PersistSession = true,
SessionHandler = new CustomSupabaseSessionHandler(
provider.GetRequiredService<ILocalStorageService>(),
provider.GetRequiredService<ILogger<CustomSupabaseSessionHandler>>()
)
}
)
);

// builder.Services.AddScoped<ISupabaseClient<User, Session, Socket, Channel, Bucket, FileObject>>(args => new Supabase.Client(url, key, new Supabase.SupabaseOptions { AutoConnectRealtime = true }));
builder.Services.AddScoped<AuthService>();
builder.Services.AddScoped<DatabaseService>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,35 @@ namespace BlazorWebAssemblySupabaseTemplate.Providers;
public class CustomAuthStateProvider : AuthenticationStateProvider
{
private readonly ILocalStorageService _localStorage;
private readonly Supabase.Client _client;
// private readonly IHttpClientFactory httpClientFactory;

// private readonly HttpClient _http;

public CustomAuthStateProvider(
ILocalStorageService localStorage
ILocalStorageService localStorage,
Supabase.Client client
// IHttpClientFactory httpClientFactory
// HttpClient http
)
{
_localStorage = localStorage;
_client = client;
// this.httpClientFactory = httpClientFactory;
// _http = http;
}

public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
string token = await _localStorage.GetItemAsStringAsync("token");
// string token = "eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTUxMiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiVG9ueSBTdGFyayIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6Iklyb24gTWFuIiwiZXhwIjozMTY4NTQwMDAwfQ.IbVQa1lNYYOzwso69xYfsMOHnQfO3VLvVqV2SOXS7sTtyyZ8DEf5jmmwz2FGLJJvZnQKZuieHnmHkg7CGkDbvA";
// Sets client auth and connects to realtime (if enabled)
await _client.InitializeAsync();

var identity = new ClaimsIdentity();
// _http.DefaultRequestHeaders.Authorization = null;

if (!string.IsNullOrEmpty(token))
if (!string.IsNullOrEmpty(_client.Auth.CurrentSession?.AccessToken))
{
identity = new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt");
identity = new ClaimsIdentity(ParseClaimsFromJwt(_client.Auth.CurrentSession.AccessToken), "jwt");
// _http.DefaultRequestHeaders.Authorization =
// new AuthenticationHeaderValue("Bearer", token.Replace("\"", ""));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Blazored.LocalStorage;
using Supabase.Gotrue;
using Supabase.Interfaces;

namespace BlazorWebAssemblySupabaseTemplate.Providers;

public class CustomSupabaseSessionHandler : ISupabaseSessionHandler
{
private readonly ILocalStorageService localStorage;
private readonly ILogger<CustomSupabaseSessionHandler> logger;
private static string SESSION_KEY = "SUPABASE_SESSION";

public CustomSupabaseSessionHandler(
ILocalStorageService localStorage,
ILogger<CustomSupabaseSessionHandler> logger
)
{
logger.LogInformation("------------------- CONSTRUCTOR -------------------");
this.localStorage = localStorage;
this.logger = logger;
}

public async Task<bool> SessionDestroyer()
{
logger.LogInformation("------------------- SessionDestroyer -------------------");
await localStorage.RemoveItemAsync(SESSION_KEY);
return true;
}

public async Task<bool> SessionPersistor<TSession>(TSession session) where TSession : Session
{
logger.LogInformation("------------------- SessionPersistor -------------------");
await localStorage.SetItemAsync(SESSION_KEY, session);
return true;
}

public async Task<TSession?> SessionRetriever<TSession>() where TSession : Session
{
logger.LogInformation("------------------- SessionRetriever -------------------");
return (TSession?) await localStorage.GetItemAsync<Session>(SESSION_KEY);
}
}
Loading