Skip to content

Commit 2a336c6

Browse files
committed
Add PrivilegeInputDate component with permission handling
1 parent 84cdc07 commit 2a336c6

File tree

3 files changed

+427
-0
lines changed

3 files changed

+427
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using Microsoft.AspNetCore.Components;
2+
using Microsoft.AspNetCore.Components.Forms;
3+
4+
namespace Privileged.Components;
5+
6+
/// <summary>
7+
/// A custom input date component that integrates privilege-based access control.
8+
/// </summary>
9+
public class PrivilegeInputDate<TValue> : InputDate<TValue>
10+
{
11+
/// <summary>
12+
/// Gets or sets the cascading privilege context used to evaluate access permissions.
13+
/// </summary>
14+
[CascadingParameter]
15+
protected PrivilegeContext? PrivilegeContext { get; set; }
16+
17+
/// <summary>
18+
/// Gets or sets the subject for privilege evaluation. Defaults to the model's type name if not specified.
19+
/// When null, empty, or whitespace, all privileges are assumed to be granted.
20+
/// </summary>
21+
[Parameter]
22+
public string? Subject { get; set; }
23+
24+
/// <summary>
25+
/// Gets or sets the field qualifier for privilege evaluation. Defaults to the input's name attribute if not specified.
26+
/// </summary>
27+
[Parameter]
28+
public string? Field { get; set; }
29+
30+
/// <summary>
31+
/// Gets or sets the action name for read permissions. Defaults to "read".
32+
/// </summary>
33+
[Parameter]
34+
public string ReadAction { get; set; } = "read";
35+
36+
/// <summary>
37+
/// Gets or sets the action name for update permissions. Defaults to "update".
38+
/// </summary>
39+
[Parameter]
40+
public string UpdateAction { get; set; } = "update";
41+
42+
/// <summary>
43+
/// Gets a value indicating whether the user has read permission for the input.
44+
/// </summary>
45+
protected bool HasReadPermission { get; set; }
46+
47+
/// <summary>
48+
/// Gets a value indicating whether the user has update permission for the input.
49+
/// </summary>
50+
protected bool HasUpdatePermission { get; set; }
51+
52+
/// <summary>
53+
/// Called when the component's parameters are set. Evaluates permissions and adjusts attributes accordingly.
54+
/// </summary>
55+
/// <exception cref="InvalidOperationException">
56+
/// Thrown if the <see cref="PrivilegeContext"/> is not provided.
57+
/// </exception>
58+
protected override void OnParametersSet()
59+
{
60+
base.OnParametersSet();
61+
62+
if (PrivilegeContext == null)
63+
throw new InvalidOperationException("Component requires a cascading parameter of type PrivilegeContext.");
64+
65+
var subject = Subject ?? EditContext?.Model.GetType().Name;
66+
var qualifier = Field ?? NameAttributeValue;
67+
68+
HasReadPermission = string.IsNullOrWhiteSpace(Subject)
69+
|| PrivilegeContext.Allowed(ReadAction, subject, qualifier);
70+
71+
HasUpdatePermission = string.IsNullOrWhiteSpace(Subject)
72+
|| PrivilegeContext.Allowed(UpdateAction, subject, qualifier);
73+
74+
if (HasUpdatePermission)
75+
return;
76+
77+
// If no update permission, set readonly or disabled attributes
78+
var attributes = AdditionalAttributes?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) ?? [];
79+
if (!HasUpdatePermission)
80+
attributes["readonly"] = true;
81+
82+
AdditionalAttributes = attributes;
83+
}
84+
85+
/// <summary>
86+
/// Builds the render tree for the component, rendering either the input or a disabled password field based on permissions.
87+
/// </summary>
88+
/// <param name="builder">The <see cref="Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder"/> used to build the render tree.</param>
89+
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder)
90+
{
91+
// If the user has read permission, render the base InputText component
92+
if (HasReadPermission)
93+
{
94+
base.BuildRenderTree(builder);
95+
return;
96+
}
97+
98+
// If the user does not have read permission, render a password input
99+
builder.OpenElement(0, "input");
100+
builder.AddAttribute(1, "type", "password");
101+
builder.AddAttribute(2, "disabled", true);
102+
builder.AddMultipleAttributes(3, AdditionalAttributes);
103+
104+
if (!string.IsNullOrEmpty(NameAttributeValue))
105+
builder.AddAttribute(4, "name", NameAttributeValue);
106+
107+
if (!string.IsNullOrEmpty(CssClass))
108+
builder.AddAttribute(5, "class", CssClass);
109+
110+
builder.AddAttribute(6, "value", CurrentValueAsString);
111+
builder.AddElementReferenceCapture(7, __inputReference => Element = __inputReference);
112+
builder.CloseElement();
113+
}
114+
}

0 commit comments

Comments
 (0)