void.cat/VoidCat/Services/Users/CacheUserStore.cs

140 lines
3.8 KiB
C#
Raw Permalink Normal View History

using VoidCat.Database;
2022-02-21 22:35:06 +00:00
using VoidCat.Model;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Users;
2022-06-08 16:17:53 +00:00
/// <inheritdoc />
public class CacheUserStore : IUserStore
2022-02-21 22:35:06 +00:00
{
private const string UserList = "users";
private readonly ICache _cache;
2022-06-13 14:20:12 +00:00
public CacheUserStore(ICache cache)
2022-02-21 22:35:06 +00:00
{
_cache = cache;
}
2022-06-08 16:17:53 +00:00
/// <inheritdoc />
public ValueTask Add(User u)
2022-02-21 22:35:06 +00:00
{
return Set(u.Id, u);
2022-02-21 22:35:06 +00:00
}
2022-06-08 16:17:53 +00:00
/// <inheritdoc />
public async ValueTask<Guid?> LookupUser(string email)
2022-02-21 22:35:06 +00:00
{
return await _cache.Get<Guid>(MapKey(email));
2022-02-21 22:35:06 +00:00
}
2022-06-08 16:17:53 +00:00
/// <inheritdoc />
2022-09-08 09:41:31 +00:00
public ValueTask<User?> Get(Guid id)
2022-06-08 16:17:53 +00:00
{
return _cache.Get<User>(MapKey(id));
2022-06-08 16:17:53 +00:00
}
/// <inheritdoc />
public async ValueTask Set(Guid id, User user)
2022-02-21 22:35:06 +00:00
{
2022-03-07 13:38:53 +00:00
if (id != user.Id) throw new InvalidOperationException();
2022-02-21 22:35:06 +00:00
await _cache.Set(MapKey(user.Id), user);
await _cache.AddToList(UserList, user.Id.ToString());
await _cache.Set(MapKey(user.Email), user.Id.ToString());
}
2022-06-08 16:17:53 +00:00
/// <inheritdoc />
public async ValueTask<PagedResult<User>> ListUsers(PagedRequest request)
2022-02-21 22:35:06 +00:00
{
var users = (await _cache.GetList(UserList))
.Select<string, Guid?>(a => Guid.TryParse(a, out var g) ? g : null)
.Where(a => a.HasValue).Select(a => a.Value);
2022-02-24 12:00:28 +00:00
users = (request.SortBy, request.SortOrder) switch
2022-02-21 22:35:06 +00:00
{
2022-02-24 12:00:28 +00:00
(PagedSortBy.Id, PageSortOrder.Asc) => users?.OrderBy(a => a),
(PagedSortBy.Id, PageSortOrder.Dsc) => users?.OrderByDescending(a => a),
_ => users
};
async IAsyncEnumerable<User> EnumerateUsers(IEnumerable<Guid> ids)
2022-02-24 12:00:28 +00:00
{
var usersLoaded = await Task.WhenAll(ids.Select(async a => await Get(a)));
2022-02-24 12:00:28 +00:00
foreach (var user in usersLoaded)
2022-02-21 22:35:06 +00:00
{
2022-02-24 12:00:28 +00:00
if (user != default)
2022-02-21 22:35:06 +00:00
{
2022-02-24 12:00:28 +00:00
yield return user;
2022-02-21 22:35:06 +00:00
}
}
}
2022-02-24 12:00:28 +00:00
return new()
{
Page = request.Page,
PageSize = request.PageSize,
TotalResults = users?.Count() ?? 0,
2023-08-24 10:53:12 +00:00
Data = EnumerateUsers(users?.Skip(request.PageSize * request.Page).Take(request.PageSize))
2022-02-24 12:00:28 +00:00
};
2022-02-21 22:35:06 +00:00
}
2022-06-08 16:17:53 +00:00
/// <inheritdoc />
public async ValueTask UpdateProfile(User newUser)
2022-02-27 18:15:37 +00:00
{
var oldUser = await Get(newUser.Id);
2022-02-27 18:15:37 +00:00
if (oldUser == null) return;
2022-03-08 13:47:42 +00:00
//retain flags
2022-09-08 09:41:31 +00:00
var isEmailVerified = oldUser.Flags.HasFlag(UserFlags.EmailVerified);
2022-05-19 22:27:49 +00:00
2022-02-27 18:15:37 +00:00
// update only a few props
oldUser.Avatar = newUser.Avatar;
2022-09-08 09:41:31 +00:00
oldUser.Flags = newUser.Flags | (isEmailVerified ? UserFlags.EmailVerified : 0);
2022-02-27 18:15:37 +00:00
oldUser.DisplayName = newUser.DisplayName;
2022-03-07 13:38:53 +00:00
await Set(newUser.Id, oldUser);
}
2022-06-08 16:17:53 +00:00
/// <inheritdoc />
public async ValueTask UpdateLastLogin(Guid id, DateTime timestamp)
{
var user = await Get(id);
2022-06-08 16:17:53 +00:00
if (user != default)
{
user.LastLogin = timestamp;
await Set(user.Id, user);
}
}
/// <inheritdoc />
public async ValueTask AdminUpdateUser(User user)
{
var oldUser = await Get(user.Id);
if (oldUser == null) return;
oldUser.Email = user.Email;
oldUser.Storage = user.Storage;
await Set(oldUser.Id, oldUser);
}
2022-06-08 16:17:53 +00:00
/// <inheritdoc />
2022-03-07 13:38:53 +00:00
public async ValueTask Delete(Guid id)
{
var user = await Get(id);
2022-03-07 13:38:53 +00:00
if (user == default) throw new InvalidOperationException();
2022-03-07 13:38:53 +00:00
await Delete(user);
2022-02-27 18:15:37 +00:00
}
private async ValueTask Delete(User user)
{
await _cache.Delete(MapKey(user.Id));
await _cache.RemoveFromList(UserList, user.Id.ToString());
await _cache.Delete(MapKey(user.Email));
}
2022-02-21 22:35:06 +00:00
private static string MapKey(Guid id) => $"user:{id}";
private static string MapKey(string email) => $"user:email:{email.Hash("md5")}";
}