-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implementations of the repositories aligning to a specific owner and …
…using the currently logged user to filter data
- Loading branch information
Showing
19 changed files
with
847 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
namespace Deveel.Data | ||
{ | ||
/// <summary> | ||
/// The contract used to define an object that | ||
/// has an owner. | ||
/// </summary> | ||
public interface IHaveOwner<TKey> | ||
{ | ||
/// <summary> | ||
/// Gets the identifier of the owner of | ||
/// the object. | ||
/// </summary> | ||
TKey Owner { get; } | ||
|
||
/// <summary> | ||
/// Sets the owner of the object, eventually | ||
/// overriding the current owner. | ||
/// </summary> | ||
/// <param name="owner"> | ||
/// The identifier of the new owner. | ||
/// </param> | ||
void SetOwner(TKey owner); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
namespace Deveel.Data | ||
{ | ||
/// <summary> | ||
/// A service that provides information about the current user | ||
/// of the application. | ||
/// </summary> | ||
/// <remarks> | ||
/// This contact can be used to retrieve identifier about the | ||
/// user that is currently using the application, such as the | ||
/// username or the user ID. | ||
/// </remarks> | ||
/// <typeparam name="TKey"> | ||
/// The type of the key that identifies the user. | ||
/// </typeparam> | ||
public interface IUserAccessor<TKey> | ||
{ | ||
/// <summary> | ||
/// Gets the identifier of the current user. | ||
/// </summary> | ||
/// <returns> | ||
/// Returns a string that represents the identifier of the | ||
/// user that is currently using the application. | ||
/// </returns> | ||
TKey? GetUserId(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
namespace Deveel.Data | ||
{ | ||
/// <summary> | ||
/// Defines a repository that is bound to a user context, | ||
/// where the entities are owned by a specific user. | ||
/// </summary> | ||
/// <typeparam name="TEntity"> | ||
/// The type of the entity handled by the repository. | ||
/// </typeparam> | ||
/// <typeparam name="TKey"> | ||
/// The type of the unique identifier of the entity. | ||
/// </typeparam> | ||
/// <typeparam name="TOwnerKey"> | ||
/// The type of the key that identifies the owner of the entity. | ||
/// </typeparam> | ||
public interface IUserRepository<TEntity, TKey, TOwnerKey> : IRepository<TEntity, TKey> | ||
where TEntity : class, IHaveOwner<TOwnerKey> | ||
{ | ||
/// <summary> | ||
/// Gets the accessor to the user context of the repository. | ||
/// </summary> | ||
IUserAccessor<TOwnerKey> UserAccessor { get; } | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/Deveel.Repository.EntityFramework/Data/DataOwnerAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Deveel.Data | ||
{ | ||
[System.AttributeUsage(System.AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] | ||
public sealed class DataOwnerAttribute : Attribute | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
src/Deveel.Repository.EntityFramework/Data/EntityTypeBuilderExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||
|
||
using System.Linq.Expressions; | ||
|
||
namespace Deveel.Data | ||
{ | ||
/// <summary> | ||
/// Extensions for the <see cref="EntityTypeBuilder{TEntity}"/> class | ||
/// to provide additional configuration for entities that have an owner. | ||
/// </summary> | ||
public static class EntityTypeBuilderExtensions | ||
{ | ||
/// <summary> | ||
/// Configures the entity to have a query filter that restricts the | ||
/// data to the owner of the entity. | ||
/// </summary> | ||
/// <typeparam name="TEntity"> | ||
/// The type of the entity that has an owner. | ||
/// </typeparam> | ||
/// <typeparam name="TUserKey"> | ||
/// The type of the key that identifies the user. | ||
/// </typeparam> | ||
/// <param name="builder"> | ||
/// A builder to configure the entity. | ||
/// </param> | ||
/// <param name="userAccessor"> | ||
/// A service that provides information about the current user | ||
/// that is using the application. | ||
/// </param> | ||
/// <returns> | ||
/// Returns the builder to continue the configuration. | ||
/// </returns> | ||
/// <seealso cref="HasOwnerFilter{TEntity, TUserKey}(EntityTypeBuilder{TEntity}, string, IUserAccessor{TUserKey})"/> | ||
public static EntityTypeBuilder<TEntity> HasOwnerFilter<TEntity, TUserKey>(this EntityTypeBuilder<TEntity> builder, IUserAccessor<TUserKey> userAccessor) | ||
where TEntity : class, IHaveOwner<TUserKey> | ||
=> builder.HasOwnerFilter("", userAccessor); | ||
|
||
/// <summary> | ||
/// Configures the entity to have a query filter that restricts the | ||
/// data to the owner of the entity. | ||
/// </summary> | ||
/// <typeparam name="TEntity"> | ||
/// The type of the entity that has an owner. | ||
/// </typeparam> | ||
/// <typeparam name="TUserKey"> | ||
/// The type of the key that identifies the user. | ||
/// </typeparam> | ||
/// <param name="builder"> | ||
/// A builder to configure the entity. | ||
/// </param> | ||
/// <param name="propertyName"> | ||
/// The name of the property that holds the owner identifier. | ||
/// </param> | ||
/// <param name="userAccessor"> | ||
/// A service that provides information about the current user | ||
/// that is using the application. | ||
/// </param> | ||
/// <returns> | ||
/// Returns the builder to continue the configuration. | ||
/// </returns> | ||
/// <exception cref="RepositoryException"> | ||
/// Throws when the property name is not found in the entity type. | ||
/// </exception> | ||
public static EntityTypeBuilder<TEntity> HasOwnerFilter<TEntity, TUserKey>(this EntityTypeBuilder<TEntity> builder, string propertyName, IUserAccessor<TUserKey> userAccessor) | ||
where TEntity : class, IHaveOwner<TUserKey> | ||
{ | ||
if (string.IsNullOrWhiteSpace(propertyName)) | ||
{ | ||
foreach(var property in builder.Metadata.GetDeclaredProperties()) | ||
{ | ||
if (Attribute.IsDefined(property.PropertyInfo, typeof(DataOwnerAttribute))) | ||
{ | ||
propertyName = property.Name; | ||
break; | ||
} | ||
} | ||
} else { | ||
var fieldMetadata = builder.Metadata.FindDeclaredProperty(propertyName); | ||
if (fieldMetadata == null) | ||
throw new RepositoryException($"The property '{propertyName}' was not found in the entity type '{typeof(TEntity).Name}'"); | ||
} | ||
|
||
if (string.IsNullOrWhiteSpace(propertyName)) | ||
throw new RepositoryException($"The property name was not specified and no property was found in the entity type '{typeof(TEntity).Name}'"); | ||
|
||
var varRef = Expression.Variable(typeof(TEntity), "x"); | ||
var propertyRef = Expression.Property(varRef, propertyName); | ||
var getUserId = Expression.Call( | ||
Expression.Constant(userAccessor), | ||
typeof(IUserAccessor<TUserKey>) | ||
.GetMethod(nameof(IUserAccessor<TUserKey>.GetUserId))); | ||
|
||
LambdaExpression lambda; | ||
|
||
if (typeof(TUserKey) == typeof(string)) | ||
{ | ||
lambda = Expression.Lambda(Expression.Equal(propertyRef, getUserId), varRef); | ||
|
||
} else | ||
{ | ||
var equalsMethod = typeof(TUserKey).GetMethod(nameof(object.Equals), new[] { typeof(object) }); | ||
lambda = Expression.Lambda(Expression.Call(propertyRef, equalsMethod, getUserId), varRef); | ||
} | ||
|
||
return builder.HasQueryFilter(lambda); | ||
} | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
src/Deveel.Repository.EntityFramework/Data/EntityUserRepository_T.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using Finbuckle.MultiTenant; | ||
|
||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Deveel.Data | ||
{ | ||
/// <summary> | ||
/// An implementation of a repository that is bound to a specific user | ||
/// context, where the entities are owned by a specific user. | ||
/// </summary> | ||
/// <typeparam name="TEntity"> | ||
/// The type of the entity managed by the repository. | ||
/// </typeparam> | ||
/// <seealso cref="EntityUserRepository{TEntity, TKey, TUserKey}"/> | ||
public class EntityUserRepository<TEntity> : EntityUserRepository<TEntity, object> | ||
where TEntity : class, IHaveOwner<object> | ||
{ | ||
/// <summary> | ||
/// Constructs the repository using the given <see cref="DbContext"/>. | ||
/// </summary> | ||
/// <param name="context"> | ||
/// The <see cref="DbContext"/> used to access the data of the entities. | ||
/// </param> | ||
/// <param name="userAccessor"> | ||
/// A service used to get the current user context. | ||
/// </param> | ||
/// <param name="logger"> | ||
/// A logger used to log the operations of the repository. | ||
/// </param> | ||
public EntityUserRepository(DbContext context, IUserAccessor<object> userAccessor, ILogger<EntityUserRepository<TEntity, object>>? logger = null) : base(context, userAccessor, logger) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Constructs the repository using the given <see cref="DbContext"/> for | ||
/// a specific tenant. | ||
/// </summary> | ||
/// <param name="context"> | ||
/// The <see cref="DbContext"/> used to access the data of the entities. | ||
/// </param> | ||
/// <param name="tenantInfo"> | ||
/// The information about the tenant that the repository will use to access the data. | ||
/// </param> | ||
/// <param name="userAccessor"> | ||
/// A service used to get the current user context. | ||
/// </param> | ||
/// <param name="logger"> | ||
/// A logger used to log the operations of the repository. | ||
/// </param> | ||
public EntityUserRepository(DbContext context, ITenantInfo? tenantInfo, IUserAccessor<object> userAccessor, ILogger<EntityUserRepository<TEntity, object>>? logger = null) : base(context, tenantInfo, userAccessor, logger) | ||
{ | ||
} | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
src/Deveel.Repository.EntityFramework/Data/EntityUserRepository_T2.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
| ||
using Finbuckle.MultiTenant; | ||
|
||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Deveel.Data | ||
{ | ||
/// <summary> | ||
/// An implementation of a repository that is bound to a specific user | ||
/// that owns the entities. | ||
/// </summary> | ||
/// <typeparam name="TEntity"> | ||
/// The type of the entity managed by the repository. | ||
/// </typeparam> | ||
/// <typeparam name="TUserKey"> | ||
/// The type of the key that identifies the owner of the entity. | ||
/// </typeparam> | ||
/// <remarks> | ||
/// This version of the repository is assuming the type of the key of the entity | ||
/// of the repository is <see cref="object"/>. | ||
/// </remarks> | ||
/// <seealso cref="EntityUserRepository{TEntity, TKey, TUserKey}"/> | ||
public class EntityUserRepository<TEntity, TUserKey> : EntityUserRepository<TEntity, object, TUserKey> | ||
where TEntity : class, IHaveOwner<TUserKey> | ||
{ | ||
/// <summary> | ||
/// Constructs the repository using the given <see cref="DbContext"/>. | ||
/// </summary> | ||
/// <param name="context"> | ||
/// The <see cref="DbContext"/> used to access the data of the entities. | ||
/// </param> | ||
/// <param name="userAccessor"> | ||
/// A service used to get the current user context. | ||
/// </param> | ||
/// <param name="logger"> | ||
/// A logger used to log the operations of the repository. | ||
/// </param> | ||
public EntityUserRepository(DbContext context, IUserAccessor<TUserKey> userAccessor, ILogger<EntityUserRepository<TEntity, object, TUserKey>>? logger = null) : base(context, userAccessor, logger) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Constructs the repository using the given <see cref="DbContext"/> for | ||
/// the given tenant. | ||
/// </summary> | ||
/// <param name="context"> | ||
/// The <see cref="DbContext"/> used to access the data of the entities. | ||
/// </param> | ||
/// <param name="tenantInfo"> | ||
/// The information about the tenant that the repository will use to access the data. | ||
/// </param> | ||
/// <param name="userAccessor"> | ||
/// A service used to get the current user context. | ||
/// </param> | ||
/// <param name="logger"> | ||
/// A logger used to log the operations of the repository. | ||
/// </param> | ||
public EntityUserRepository(DbContext context, ITenantInfo? tenantInfo, IUserAccessor<TUserKey> userAccessor, ILogger<EntityUserRepository<TEntity, object, TUserKey>>? logger = null) : base(context, tenantInfo, userAccessor, logger) | ||
{ | ||
} | ||
} | ||
} |
Oops, something went wrong.