void.cat/VoidCat/Services/Users/PostgresUserStore.cs
2022-09-08 10:41:31 +01:00

187 lines
5.8 KiB
C#

using Dapper;
using VoidCat.Model;
using VoidCat.Model.User;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Users;
/// <inheritdoc />
public class PostgresUserStore : IUserStore
{
private readonly PostgresConnectionFactory _connection;
public PostgresUserStore(PostgresConnectionFactory connection)
{
_connection = connection;
}
/// <inheritdoc />
public async ValueTask<User?> Get(Guid id)
{
return await Get<PublicUser>(id);
}
/// <inheritdoc />
public async ValueTask<InternalUser?> GetPrivate(Guid id)
{
return await Get<InternalUser>(id);
}
/// <inheritdoc />
public async ValueTask Set(Guid id, InternalUser obj)
{
await using var conn = await _connection.Get();
await conn.ExecuteAsync(
@"insert into
""Users""(""Id"", ""Email"", ""Password"", ""Created"", ""LastLogin"", ""DisplayName"", ""Avatar"", ""Flags"", ""AuthType"")
values(:id, :email, :password, :created, :lastLogin, :displayName, :avatar, :flags, :authType)",
new
{
Id = id,
email = obj.Email,
password = obj.Password,
created = obj.Created,
displayName = obj.DisplayName,
lastLogin = obj.LastLogin.ToUniversalTime(),
avatar = obj.Avatar,
flags = (int)obj.Flags,
authType = (int)obj.AuthType
});
if (obj.Roles.Any(a => a != Roles.User))
{
foreach (var r in obj.Roles.Where(a => a != Roles.User))
{
await conn.ExecuteAsync(
@"insert into ""UserRoles""(""User"", ""Role"") values(:user, :role)",
new {user = obj.Id, role = r});
}
}
}
/// <inheritdoc />
public async ValueTask Delete(Guid id)
{
await using var conn = await _connection.Get();
await conn.ExecuteAsync(@"delete from ""Users"" where ""Id"" = :id", new {id});
}
/// <inheritdoc />
public async ValueTask<T?> Get<T>(Guid id) where T : User
{
await using var conn = await _connection.Get();
var user = await conn.QuerySingleOrDefaultAsync<T?>(@"select * from ""Users"" where ""Id"" = :id",
new {id});
if (user != default)
{
var roles = await conn.QueryAsync<string>(
@"select ""Role"" from ""UserRoles"" where ""User"" = :id",
new {id});
foreach (var r in roles)
{
user.Roles.Add(r);
}
}
return user;
}
/// <inheritdoc />
public async ValueTask<Guid?> LookupUser(string email)
{
await using var conn = await _connection.Get();
return await conn.QuerySingleOrDefaultAsync<Guid?>(
@"select ""Id"" from ""Users"" where ""Email"" = :email",
new {email});
}
/// <inheritdoc />
public async ValueTask<PagedResult<PrivateUser>> ListUsers(PagedRequest request)
{
await using var conn = await _connection.Get();
var totalUsers = await conn.ExecuteScalarAsync<int>(@"select count(*) from ""Users""");
async IAsyncEnumerable<PrivateUser> Enumerate()
{
var orderBy = request.SortBy switch
{
PagedSortBy.Date => "Created",
PagedSortBy.Name => "DisplayName",
_ => "Id"
};
var sortBy = request.SortOrder switch
{
PageSortOrder.Dsc => "desc",
_ => "asc"
};
await using var iconn = await _connection.Get();
var users = await iconn.ExecuteReaderAsync(
$@"select * from ""Users"" order by ""{orderBy}"" {sortBy} offset :offset limit :limit",
new
{
offset = request.PageSize * request.Page,
limit = request.PageSize
});
var rowParser = users.GetRowParser<PrivateUser>();
while (await users.ReadAsync())
{
yield return rowParser(users);
}
}
return new()
{
Page = request.Page,
PageSize = request.PageSize,
TotalResults = totalUsers,
Results = Enumerate()
};
}
/// <inheritdoc />
public async ValueTask UpdateProfile(PublicUser newUser)
{
var oldUser = await Get<InternalUser>(newUser.Id);
if (oldUser == null) return;
var emailFlag = oldUser.Flags.HasFlag(UserFlags.EmailVerified) ? UserFlags.EmailVerified : 0;
await using var conn = await _connection.Get();
await conn.ExecuteAsync(
@"update ""Users"" set ""DisplayName"" = :displayName, ""Avatar"" = :avatar, ""Flags"" = :flags where ""Id"" = :id",
new
{
id = newUser.Id,
displayName = newUser.DisplayName,
avatar = newUser.Avatar,
flags = newUser.Flags | emailFlag
});
}
/// <inheritdoc />
public async ValueTask UpdateLastLogin(Guid id, DateTime timestamp)
{
await using var conn = await _connection.Get();
await conn.ExecuteAsync(@"update ""Users"" set ""LastLogin"" = :timestamp where ""Id"" = :id",
new {id, timestamp});
}
/// <inheritdoc />
public async ValueTask AdminUpdateUser(PrivateUser user)
{
await using var conn = await _connection.Get();
await conn.ExecuteAsync(
@"update ""Users"" set ""Email"" = :email, ""Storage"" = :storage where ""Id"" = :id",
new
{
id = user.Id,
email = user.Email,
storage = user.Storage
});
}
}