You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Common/Common/Security/Identity/UserOps.cs

237 lines
6.2 KiB

using System.Collections.Immutable;
using Connected;
using Connected.Entities;
using Connected.Entities.Storage;
using Connected.Notifications.Events;
using Connected.Security.Cryptography;
using Connected.Security.Identity;
using Connected.ServiceModel;
using Connected.Services;
namespace Common.Security.Identity;
internal sealed class QueryUsers : ServiceFunction<IDto, ImmutableList<IUser>?>
{
public QueryUsers(IUserCache cache)
{
Cache = cache;
}
private IUserCache Cache { get; }
protected override async Task<ImmutableList<IUser>?> OnInvoke()
{
return await (from dc in Cache select dc).AsEntities<IUser>();
}
}
internal sealed class SelectUser : ServiceFunction<PrimaryKeyArgs<int>, IUser?>
{
public SelectUser(IUserCache cache)
{
Cache = cache;
}
private IUserCache Cache { get; }
protected override async Task<IUser?> OnInvoke()
{
return await (from dc in Cache
where dc.Id == Arguments.Id
select dc).AsEntity();
}
}
/// <summary>
/// Resolves user by a specified criteria string
/// </summary>
internal sealed class ResolveUser : ServiceFunction<UserResolveArgs, IUser?>
{
public ResolveUser(IUserCache cache)
{
Cache = cache;
}
private IUserCache Cache { get; }
protected override async Task<IUser?> OnInvoke()
{
/*
* First, try to resolve by login name
*/
if (await (from dc in Cache where string.Equals(dc.LoginName, Arguments.Criteria, StringComparison.OrdinalIgnoreCase) select dc).AsEntity() is IUser user)
return user;
/*
* Next, try by authentication token
*/
if (Guid.TryParse(Arguments.Criteria, out Guid authenticationToken))
{
if (await (from dc in Cache where dc.AuthenticationToken == authenticationToken select dc).AsEntity() is IUser authUser)
return authUser;
}
/*
* Next, try by email
*/
if (Arguments.Criteria?.Contains('@') == true)
{
if (await (from dc in Cache where string.Equals(dc.Email, Arguments.Criteria, StringComparison.OrdinalIgnoreCase) select dc).AsEntity() is IUser emailUser)
return emailUser;
}
/*
* Now by id
*/
if (int.TryParse(Arguments.Criteria, out int id))
{
if (await (from dc in Cache where dc.Id == id select dc).AsEntity() is IUser idUser)
return idUser;
}
/*
* Doesn't exist.
*/
return null;
}
}
internal sealed class LookupUsers : ServiceFunction<PrimaryKeyListArgs<int>, ImmutableList<IUser>?>
{
public LookupUsers(IUserCache cache)
{
Cache = cache;
}
private IUserCache Cache { get; }
protected override async Task<ImmutableList<IUser>?> OnInvoke()
{
if (Arguments.IdList is null)
return default;
return await (from dc in Cache
where Arguments.IdList.Contains(dc.Id)
select dc).AsEntities<IUser>();
}
}
internal sealed class InsertUser : ServiceFunction<UserInsertArgs, int>
{
public InsertUser(IUserService userService, IUserCache cache, IStorageProvider storage, IEventService events)
{
UserService = userService;
Cache = cache;
Storage = storage;
Events = events;
}
private IUserCache Cache { get; }
private IStorageProvider Storage { get; }
private IEventService Events { get; }
private IUserService UserService { get; }
protected override async Task<int> OnInvoke()
{
if (Arguments.AsEntity<User>(State.New) is not User entity)
throw EntityExceptions.EntityCastException(Arguments.GetType(), typeof(User));
var result = await Storage.Open<User>().Update(entity);
return result.Id;
}
protected override async Task OnCommitted()
{
await Cache.Refresh(Result);
await Events.Enqueue(this, UserService, ServiceEvents.Inserted, Result);
}
}
internal sealed class DeleteUser : ServiceAction<PrimaryKeyArgs<int>>
{
public DeleteUser(IUserService userService, IStorageProvider storage, IUserCache cache, IEventService events)
{
UserService = userService;
Storage = storage;
Cache = cache;
Events = events;
}
private IUserService UserService { get; }
private IStorageProvider Storage { get; }
private IUserCache Cache { get; }
private IEventService Events { get; }
protected override async Task OnInvoke()
{
await Storage.Open<User>().Update(new User { Id = Arguments.Id, State = State.Deleted });
}
protected override async Task OnCommitted()
{
await Cache.Remove(Arguments.Id);
await Events.Enqueue(this, UserService, ServiceEvents.Deleted, Arguments.Id);
}
}
internal sealed class UpdateUser : ServiceAction<UserUpdateArgs>
{
public UpdateUser(IUserService userService, IUserCache cache, IStorageProvider storage, IEventService events)
{
UserService = userService;
Cache = cache;
Storage = storage;
Events = events;
}
private IUserService UserService { get; }
private IUserCache Cache { get; }
private IStorageProvider Storage { get; }
private IEventService Events { get; }
protected override async Task OnInvoke()
{
await Storage.Open<User>().Update(await Load(), Arguments, async () =>
{
await Cache.Refresh(Arguments.Id);
return await Load();
});
}
private async Task<User?> Load() => await (from dc in Cache where dc.Id == Arguments.Id select dc).AsEntity();
protected override async Task OnCommitted()
{
await Cache.Refresh(Arguments.Id);
await Events.Enqueue(this, UserService, ServiceEvents.Updated, Arguments.Id);
}
}
internal sealed class UserUpdatePassword : ServiceAction<UserPasswordArgs>
{
public UserUpdatePassword(IUserService userService, ICryptographyService cryptographyService, IStorageProvider storage, IUserCache cache, IEventService events)
{
UserService = userService;
CryptographyService = cryptographyService;
Storage = storage;
Cache = cache;
Events = events;
}
private IUserService UserService { get; }
private ICryptographyService CryptographyService { get; }
private IStorageProvider Storage { get; }
public IUserCache Cache { get; }
public IEventService Events { get; }
protected override async Task OnInvoke()
{
await Storage.Open<User>().Update(await Load(), Arguments, async () =>
{
await Cache.Refresh(Arguments.Id);
return await Load();
});
}
private async Task<User?> Load() => await (from dc in Cache where dc.Id == Arguments.Id select dc).AsEntity();
protected override async Task OnCommitted()
{
await Cache.Refresh(Arguments.Id);
await Events.Enqueue(this, UserService, ServiceEvents.Updated, Arguments.Id);
}
}