Skip to content

Commit fc57550

Browse files
authored
Iatsuta/add many relative domain path info (#555)
* add ManyRelativeDomainPathInfo
1 parent 41bf4f6 commit fc57550

File tree

31 files changed

+1294
-49
lines changed

31 files changed

+1294
-49
lines changed

src/Framework.SecuritySystem.Abstract/Providers/AccessResultExtensions.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace Framework.SecuritySystem;
1+
using Framework.Core;
2+
3+
namespace Framework.SecuritySystem;
24

35
public static class AccessResultExtensions
46
{
@@ -14,4 +16,10 @@ public static AccessResult TryOverrideAccessDeniedResult(
1416
AccessResult.AccessDeniedResult accessDeniedResult => selector(accessDeniedResult),
1517
_ => accessResult
1618
};
19+
20+
public static AccessResult Or(this IEnumerable<AccessResult> source) =>
21+
source.Match(
22+
() => AccessResult.AccessDeniedResult.Default,
23+
result => result,
24+
results => results.Aggregate((AccessResult)AccessResult.AccessDeniedResult.Default, (v1, v2) => v1.Or(v2)));
1725
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Framework.Core;
2+
3+
namespace Framework.SecuritySystem;
4+
5+
public static class SecurityAccessorDataExtensions
6+
{
7+
public static SecurityAccessorData Or(this IEnumerable<SecurityAccessorData> source) =>
8+
source.Match(
9+
() => SecurityAccessorData.Empty,
10+
result => result,
11+
results => results.Aggregate(
12+
SecurityAccessorData.Empty,
13+
(v1, v2) => new SecurityAccessorData.OrSecurityAccessorData(v1, v2)));
14+
}

src/Framework.SecuritySystem.DiTests/Services/TestCheckboxConditionFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ public class TestCheckboxConditionFactory<TDomainObject>(IRelativeDomainPathInfo
99
{
1010
public Expression<Func<TDomainObject, bool>> Create()
1111
{
12-
return pathToEmployeeInfo.Path.Select(employee => employee.TestCheckbox);
12+
return pathToEmployeeInfo.CreateCondition(employee => employee.TestCheckbox);
1313
}
1414
}

src/Framework.SecuritySystem/DependencyInjection/DomainSecurityServiceBuilder/DomainSecurityServiceBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public IDomainSecurityServiceBuilder<TDomainObject> SetDependency<TSource>(Expre
124124

125125
this.relativePathData =
126126
(typeof(IRelativeDomainPathInfo<TDomainObject, TSource>),
127-
new RelativeDomainPathInfo<TDomainObject, TSource>(relativeDomainPath));
127+
new SingleRelativeDomainPathInfo<TDomainObject, TSource>(relativeDomainPath));
128128

129129
return this;
130130
}

src/Framework.SecuritySystem/DependencyInjection/ServiceCollectionExtensions.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,24 @@ public static IServiceCollection AddRelativeDomainPath<TFrom, TTo>(
6969
Expression<Func<TFrom, TTo>> path,
7070
string? key = null)
7171
{
72-
var info = new RelativeDomainPathInfo<TFrom, TTo>(path);
72+
var info = new SingleRelativeDomainPathInfo<TFrom, TTo>(path);
73+
74+
if (key == null)
75+
{
76+
return services.AddSingleton<IRelativeDomainPathInfo<TFrom, TTo>>(info);
77+
}
78+
else
79+
{
80+
return services.AddKeyedSingleton<IRelativeDomainPathInfo<TFrom, TTo>>(key, info);
81+
}
82+
}
83+
84+
public static IServiceCollection AddRelativeDomainPath<TFrom, TTo>(
85+
this IServiceCollection services,
86+
Expression<Func<TFrom, IEnumerable<TTo>>> path,
87+
string? key = null)
88+
{
89+
var info = new ManyRelativeDomainPathInfo<TFrom, TTo>(path);
7390

7491
if (key == null)
7592
{

src/Framework.SecuritySystem/DomainServices/DependencySecurity/DependencyDomainSecurityService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public class DependencyDomainSecurityService<TDomainObject, TBaseDomainObject>(
77
ISecurityRuleExpander securityRuleExpander,
88
IDomainSecurityService<TBaseDomainObject> baseDomainSecurityService,
99
IQueryableSource queryableSource,
10-
IRelativeDomainPathInfo<TDomainObject, TBaseDomainObject> pathInfo)
10+
IRelativeDomainPathInfo<TDomainObject, TBaseDomainObject> relativeDomainPathInfo)
1111
: DependencyDomainSecurityServiceBase<TDomainObject, TBaseDomainObject>(
1212
securityRuleExpander,
1313
baseDomainSecurityService)
@@ -17,7 +17,7 @@ protected override ISecurityProvider<TDomainObject> CreateDependencySecurityProv
1717
{
1818
return new DependencySecurityProvider<TDomainObject, TBaseDomainObject>(
1919
baseProvider,
20-
pathInfo.Path,
20+
relativeDomainPathInfo,
2121
queryableSource);
2222
}
2323
}
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
using System.Linq.Expressions;
2-
3-
using Framework.Core;
1+
using Framework.Core;
42
using Framework.QueryableSource;
53

64
namespace Framework.SecuritySystem;
75

86
public class DependencySecurityProvider<TDomainObject, TBaseDomainObject>(
97
ISecurityProvider<TBaseDomainObject> baseSecurityProvider,
10-
Expression<Func<TDomainObject, TBaseDomainObject>> selector,
8+
IRelativeDomainPathInfo<TDomainObject, TBaseDomainObject> relativePath,
119
IQueryableSource queryableSource)
1210
: ISecurityProvider<TDomainObject>
1311
where TBaseDomainObject : class
@@ -16,21 +14,25 @@ public IQueryable<TDomainObject> InjectFilter(IQueryable<TDomainObject> queryabl
1614
{
1715
var baseDomainObjSecurityQ = queryableSource.GetQueryable<TBaseDomainObject>().Pipe(baseSecurityProvider.InjectFilter);
1816

19-
return queryable.Where(selector.Select(domainObj => baseDomainObjSecurityQ.Contains(domainObj)));
17+
return queryable.Where(relativePath.CreateCondition(domainObj => baseDomainObjSecurityQ.Contains(domainObj)));
2018
}
2119

2220
public AccessResult GetAccessResult(TDomainObject domainObject)
2321
{
24-
return baseSecurityProvider.GetAccessResult(selector.Eval(domainObject)).TryOverrideDomainObject(domainObject);
22+
return relativePath
23+
.GetRelativeObjects(domainObject)
24+
.Select(baseSecurityProvider.GetAccessResult)
25+
.Or()
26+
.TryOverrideDomainObject(domainObject);
2527
}
2628

2729
public bool HasAccess(TDomainObject domainObject)
2830
{
29-
return baseSecurityProvider.HasAccess(selector.Eval(domainObject));
31+
return relativePath.GetRelativeObjects(domainObject).Any(baseSecurityProvider.HasAccess);
3032
}
3133

3234
public SecurityAccessorData GetAccessorData(TDomainObject domainObject)
3335
{
34-
return baseSecurityProvider.GetAccessorData(selector.Eval(domainObject));
36+
return relativePath.GetRelativeObjects(domainObject).Select(baseSecurityProvider.GetAccessorData).Or();
3537
}
3638
}

src/Framework.SecuritySystem/RelativeDomainPathInfo/IRelativeDomainPathInfo.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,13 @@ namespace Framework.SecuritySystem;
44

55
public interface IRelativeDomainPathInfo<TFrom, TTo>
66
{
7-
Expression<Func<TFrom, TTo>> Path { get; }
7+
IRelativeDomainPathInfo<TNewFrom, TTo> OverrideInput<TNewFrom>(Expression<Func<TNewFrom, TFrom>> selector);
8+
9+
IRelativeDomainPathInfo<TFrom, TNewTo> Select<TNewTo>(Expression<Func<TTo, TNewTo>> selector);
10+
11+
IRelativeDomainPathInfo<TFrom, TNewTo> Select<TNewTo>(Expression<Func<TTo, IEnumerable<TNewTo>>> selector);
12+
13+
Expression<Func<TFrom, bool>> CreateCondition(Expression<Func<TTo, bool>> filter);
14+
15+
IEnumerable<TTo> GetRelativeObjects(TFrom source);
816
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Linq.Expressions;
2+
3+
using Framework.Core;
4+
5+
namespace Framework.SecuritySystem;
6+
7+
public record ManyRelativeDomainPathInfo<TFrom, TTo>(Expression<Func<TFrom, IEnumerable<TTo>>> Path) : IRelativeDomainPathInfo<TFrom, TTo>
8+
{
9+
public IRelativeDomainPathInfo<TNewFrom, TTo> OverrideInput<TNewFrom>(Expression<Func<TNewFrom, TFrom>> selector)
10+
{
11+
return new ManyRelativeDomainPathInfo<TNewFrom, TTo>(this.Path.OverrideInput(selector));
12+
}
13+
14+
public IRelativeDomainPathInfo<TFrom, TNewTo> Select<TNewTo>(Expression<Func<TTo, TNewTo>> selector)
15+
{
16+
return new ManyRelativeDomainPathInfo<TFrom, TNewTo>(
17+
this.Path.Select(items => items.Select(item => selector.Eval(item))).ExpandConst().InlineEval());
18+
}
19+
20+
public IRelativeDomainPathInfo<TFrom, TNewTo> Select<TNewTo>(Expression<Func<TTo, IEnumerable<TNewTo>>> selector)
21+
{
22+
return new ManyRelativeDomainPathInfo<TFrom, TNewTo>(
23+
this.Path.Select(items => items.SelectMany(item => selector.Eval(item))).ExpandConst().InlineEval());
24+
}
25+
26+
public Expression<Func<TFrom, bool>> CreateCondition(Expression<Func<TTo, bool>> filter)
27+
{
28+
return this.Path.Select(items => items.Any(item => filter.Eval(item))).ExpandConst().InlineEval();
29+
}
30+
31+
public IEnumerable<TTo> GetRelativeObjects(TFrom source)
32+
{
33+
return this.Path.Eval(source);
34+
}
35+
}
Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
11
using System.Linq.Expressions;
22

3+
using Framework.Core;
4+
35
namespace Framework.SecuritySystem;
46

5-
public record RelativeDomainPathInfo<TFrom, TTo>(Expression<Func<TFrom, TTo>> Path) : IRelativeDomainPathInfo<TFrom, TTo>;
7+
public record SingleRelativeDomainPathInfo<TFrom, TTo>(Expression<Func<TFrom, TTo>> Path) : IRelativeDomainPathInfo<TFrom, TTo>
8+
{
9+
public IRelativeDomainPathInfo<TNewFrom, TTo> OverrideInput<TNewFrom>(Expression<Func<TNewFrom, TFrom>> selector)
10+
{
11+
return new SingleRelativeDomainPathInfo<TNewFrom, TTo>(this.Path.OverrideInput(selector));
12+
}
13+
14+
public IRelativeDomainPathInfo<TFrom, TNewTo> Select<TNewTo>(Expression<Func<TTo, TNewTo>> selector)
15+
{
16+
return new SingleRelativeDomainPathInfo<TFrom, TNewTo>(this.Path.Select(selector));
17+
}
18+
19+
public IRelativeDomainPathInfo<TFrom, TNewTo> Select<TNewTo>(Expression<Func<TTo, IEnumerable<TNewTo>>> selector)
20+
{
21+
return new ManyRelativeDomainPathInfo<TFrom, TNewTo>(this.Path.Select(selector));
22+
}
23+
24+
public Expression<Func<TFrom, bool>> CreateCondition(Expression<Func<TTo, bool>> filter)
25+
{
26+
return this.Path.Select(filter);
27+
}
28+
29+
public IEnumerable<TTo> GetRelativeObjects(TFrom source)
30+
{
31+
var relativeObject = this.Path.Eval(source);
32+
33+
if (relativeObject != null)
34+
{
35+
yield return relativeObject;
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)