Skip to content

Commit

Permalink
Merge branch 'main' into feature/history-encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
kapi2289 authored Jan 6, 2025
2 parents fbdd13d + e5d3c25 commit 6847df0
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 50 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ name: .NET

on:
push:
branches: [ "main" ]
branches:
- "main"
- "v1"
pull_request:
branches: [ "main" ]
branches:
- "main"
- "v1"

jobs:
build:
Expand All @@ -19,7 +23,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
5 changes: 2 additions & 3 deletions InertiaCore/Extensions/Configure.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.IO.Abstractions;
using System.Net;
using InertiaCore.Models;
using InertiaCore.Ssr;
Expand All @@ -25,7 +24,7 @@ public static IApplicationBuilder UseInertia(this IApplicationBuilder app)
{
if (context.IsInertiaRequest()
&& context.Request.Method == "GET"
&& context.Request.Headers[Header.Version] != Inertia.GetVersion())
&& context.Request.Headers[InertiaHeader.Version] != Inertia.GetVersion())
{
await OnVersionChange(context, app);
return;
Expand Down Expand Up @@ -69,7 +68,7 @@ private static async Task OnVersionChange(HttpContext context, IApplicationBuild

if (tempData.Any()) tempData.Keep();

context.Response.Headers.Add(Header.Location, context.RequestedUri());
context.Response.Headers.Override(InertiaHeader.Location, context.RequestedUri());
context.Response.StatusCode = (int)HttpStatusCode.Conflict;

await context.Response.CompleteAsync();
Expand Down
33 changes: 22 additions & 11 deletions InertiaCore/Extensions/InertiaExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,49 @@ internal static class InertiaExtensions
{
internal static Dictionary<string, object?> OnlyProps(this ActionContext context, Dictionary<string, object?> props)
{
var onlyKeys = context.HttpContext.Request.Headers[Header.PartialOnly].ToString().Split(',').Select(k => k.Trim()).ToList();
var onlyKeys = context.HttpContext.Request.Headers[InertiaHeader.PartialOnly]
.ToString().Split(',')
.Select(k => k.Trim())
.Where(k => !string.IsNullOrEmpty(k))
.ToList();

return props.Where(kv => onlyKeys.Contains(kv.Key, StringComparer.OrdinalIgnoreCase))
.ToDictionary(kv => kv.Key, kv => kv.Value);
}

internal static Dictionary<string, object?> ExceptProps(this ActionContext context, Dictionary<string, object?> props)
internal static Dictionary<string, object?> ExceptProps(this ActionContext context,
Dictionary<string, object?> props)
{
var exceptKeys = context.HttpContext.Request.Headers[Header.PartialExcept].ToString().Split(',').Select(k => k.Trim()).ToList();
var exceptKeys = context.HttpContext.Request.Headers[InertiaHeader.PartialExcept]
.ToString().Split(',')
.Select(k => k.Trim())
.Where(k => !string.IsNullOrEmpty(k))
.ToList();

return props.Where(kv => exceptKeys.Contains(kv.Key, StringComparer.OrdinalIgnoreCase) == false)
.ToDictionary(kv => kv.Key, kv => kv.Value);
}

internal static List<string> GetPartialData(this ActionContext context) =>
context.HttpContext.Request.Headers[Header.PartialOnly]
.FirstOrDefault()?.Split(",")
.Where(s => !string.IsNullOrEmpty(s))
.ToList() ?? new List<string>();

internal static bool IsInertiaPartialComponent(this ActionContext context, string component) =>
context.HttpContext.Request.Headers[Header.PartialComponent] == component;
context.HttpContext.Request.Headers[InertiaHeader.PartialComponent] == component;

internal static string RequestedUri(this HttpContext context) =>
Uri.UnescapeDataString(context.Request.GetEncodedPathAndQuery());

internal static string RequestedUri(this ActionContext context) => context.HttpContext.RequestedUri();

internal static bool IsInertiaRequest(this HttpContext context) =>
bool.TryParse(context.Request.Headers[Header.Inertia], out _);
bool.TryParse(context.Request.Headers[InertiaHeader.Inertia], out _);

internal static bool IsInertiaRequest(this ActionContext context) => context.HttpContext.IsInertiaRequest();

internal static string ToCamelCase(this string s) => JsonNamingPolicy.CamelCase.ConvertName(s);

internal static bool Override<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (dictionary.TryAdd(key, value)) return false;
dictionary[key] = value;

return true;
}
}
2 changes: 1 addition & 1 deletion InertiaCore/InertiaCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>0.0.9</Version>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<PackageId>AspNetCore.InertiaCore</PackageId>
<Authors>kapi2289</Authors>
<Description>Inertia.js ASP.NET Adapter. https://inertiajs.com/</Description>
Expand Down
25 changes: 14 additions & 11 deletions InertiaCore/Response.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ protected internal void ProcessResponse()

protected internal JsonResult GetJson()
{
_context!.HttpContext.Response.Headers.Add(Header.Inertia, "true");
_context!.HttpContext.Response.Headers.Add("Vary", Header.Inertia);
_context!.HttpContext.Response.Headers.Override(InertiaHeader.Inertia, "true");
_context!.HttpContext.Response.Headers.Override("Vary", InertiaHeader.Inertia);
_context!.HttpContext.Response.StatusCode = 200;

return new JsonResult(_page, new JsonSerializerOptions
Expand Down Expand Up @@ -117,27 +117,30 @@ public Response WithViewData(IDictionary<string, object> viewData)

private Dictionary<string, object?> ResolveProperties(Dictionary<string, object?> props)
{
bool isPartial = _context!.IsInertiaPartialComponent(_component);
var isPartial = _context!.IsInertiaPartialComponent(_component);

if (!isPartial)
{
props = props
.Where(kv => kv.Value is not LazyProp)
.ToDictionary(kv => kv.Key, kv => kv.Value);
}

if (isPartial && _context!.HttpContext.Request.Headers.ContainsKey(Header.PartialOnly))
else
{
props = ResolveOnly(props);
}
props = props.ToDictionary(kv => kv.Key, kv => kv.Value);

if (isPartial && _context!.HttpContext.Request.Headers.ContainsKey(Header.PartialExcept))
{
props = ResolveExcept(props);
if (_context!.HttpContext.Request.Headers.ContainsKey(InertiaHeader.PartialOnly))
{
props = ResolveOnly(props);
}

if (_context!.HttpContext.Request.Headers.ContainsKey(InertiaHeader.PartialExcept))
{
props = ResolveExcept(props);
}
}

props = ResolveAlways(props);

props = PrepareProps(props);

return props;
Expand Down
21 changes: 8 additions & 13 deletions InertiaCore/Utils/AlwaysProp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,13 @@ public AlwaysProp(object? value)
{
// Check if the value is a callable delegate
return Task.Run(async () =>
{
if (_value is Func<Task<object?>> asyncCallable)
{
return await asyncCallable.Invoke();
}

if (_value is Func<object?> callable)
{
return callable.Invoke();
}

return _value;
}).GetAwaiter().GetResult();
{
return _value switch
{
Func<Task<object?>> asyncCallable => await asyncCallable.Invoke(),
Func<object?> callable => callable.Invoke(),
_ => _value
};
}).GetAwaiter().GetResult();
}
}
2 changes: 1 addition & 1 deletion InertiaCore/Utils/InertiaActionFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void OnActionExecuted(ActionExecutedContext context)
};

if (destinationUrl == null) return;
context.HttpContext.Response.Headers.Add("Location", destinationUrl);
context.HttpContext.Response.Headers.Override("Location", destinationUrl);
context.Result = new StatusCodeResult((int)HttpStatusCode.RedirectMethod);
}

Expand Down
18 changes: 18 additions & 0 deletions InertiaCore/Utils/InertiaHeader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace InertiaCore.Utils;

public static class InertiaHeader
{
public const string Inertia = "X-Inertia";

public const string ErrorBag = "X-Inertia-Error-Bag";

public const string Location = "X-Inertia-Location";

public const string Version = "X-Inertia-Version";

public const string PartialComponent = "X-Inertia-Partial-Component";

public const string PartialOnly = "X-Inertia-Partial-Data";

public const string PartialExcept = "X-Inertia-Partial-Except";
}
2 changes: 1 addition & 1 deletion InertiaCore/Utils/LocationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public async Task ExecuteResultAsync(ActionContext context)
{
if (context.IsInertiaRequest())
{
context.HttpContext.Response.Headers.Add(Header.Location, _url);
context.HttpContext.Response.Headers.Override(InertiaHeader.Location, _url);
await new StatusCodeResult((int)HttpStatusCode.Conflict).ExecuteResultAsync(context);
return;
}
Expand Down
2 changes: 1 addition & 1 deletion InertiaCoreTests/InertiaCoreTests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

Expand Down
6 changes: 2 additions & 4 deletions InertiaCoreTests/UnitTestAlwaysData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ public void TestAlwaysData()
{
Test = "Test",
TestFunc = new Func<string>(() => "Func"),
TestAlways = _factory.Always(() =>
{
return "Always";
})
TestAlways = _factory.Always(() => "Always")
});

var context = PrepareContext();
Expand Down Expand Up @@ -155,6 +152,7 @@ public void TestAlwaysAsyncPartialDataOmitted()
var headers = new HeaderDictionary
{
{ "X-Inertia-Partial-Data", "testFunc" },
{ "X-Inertia-Partial-Except", "testAlways" },
{ "X-Inertia-Partial-Component", "Test/Page" }
};

Expand Down
118 changes: 117 additions & 1 deletion InertiaCoreTests/UnitTestPartialData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public partial class Tests
{
[Test]
[Description("Test if the props contain only the specified partial data.")]
public void TestPartialData()
public void TestPartialOnlyData()
{
var response = _factory.Render("Test/Page", new
{
Expand Down Expand Up @@ -44,4 +44,120 @@ public void TestPartialData()
{ "errors", new Dictionary<string, string>(0) }
}));
}

[Test]
[Description("Test if the props contain all the unspecified data")]
public void TestPartialFullData()
{
var response = _factory.Render("Test/Page", new
{
Test = "Test",
TestPartial = "Partial",
TestFunc = new Func<string>(() => "Func"),
TestLazy = _factory.Lazy(() => "Lazy")
});

var headers = new HeaderDictionary
{
{ "X-Inertia-Partial-Component", "Test/Page" }
};

var context = PrepareContext(headers);

response.SetContext(context);
response.ProcessResponse();

var page = response.GetJson().Value as Page;

Assert.That(page?.Props, Is.EqualTo(new Dictionary<string, object?>
{
{ "test", "Test" },
{ "testPartial", "Partial" },
{ "testFunc", "Func" },
{ "testLazy", "Lazy" },
{ "errors", new Dictionary<string, string>(0) }
}));
}

[Test]
[Description("Test if the props contain none of the except data")]
public void TestPartialExceptData()
{
var response = _factory.Render("Test/Page", new
{
Test = "Test",
TestPartial = "Partial",
TestFunc = new Func<string>(() =>
{
Assert.Fail();
return "Func";
}),
TestLazy = _factory.Lazy(() =>
{
Assert.Fail();
return "Lazy";
})
});

var headers = new HeaderDictionary
{
{ "X-Inertia-Partial-Except", "TestFunc,TestLazy" },
{ "X-Inertia-Partial-Component", "Test/Page" }
};

var context = PrepareContext(headers);

response.SetContext(context);
response.ProcessResponse();

var page = response.GetJson().Value as Page;

Assert.That(page?.Props, Is.EqualTo(new Dictionary<string, object?>
{
{ "test", "Test" },
{ "testPartial", "Partial" },
{ "errors", new Dictionary<string, string>(0) }
}));
}

[Test]
[Description("Test if the props contain the correct data when using only and except data")]
public void TestPartialOnlyAndExceptData()
{
var response = _factory.Render("Test/Page", new
{
Test = "Test",
TestPartial = "Partial",
TestFunc = new Func<string>(() =>
{
Assert.Fail();
return "Func";
}),
TestLazy = _factory.Lazy(() =>
{
Assert.Fail();
return "Lazy";
})
});

var headers = new HeaderDictionary
{
{ "X-Inertia-Partial-Data", "Test,TestFunc,TestLazy" },
{ "X-Inertia-Partial-Except", "TestFunc,TestLazy" },
{ "X-Inertia-Partial-Component", "Test/Page" }
};

var context = PrepareContext(headers);

response.SetContext(context);
response.ProcessResponse();

var page = response.GetJson().Value as Page;

Assert.That(page?.Props, Is.EqualTo(new Dictionary<string, object?>
{
{ "test", "Test" },
{ "errors", new Dictionary<string, string>(0) }
}));
}
}

0 comments on commit 6847df0

Please sign in to comment.