feat(server): space avatars and full member profiles in the structure response
This commit is contained in:
1 parent
77c9017129
commit
1a4069576b
14 files changed
+99
-36
No files matched your search
@@ -16,22 +16,10 @@ public sealed partial class SqliteAccountStore
|
||||
: new AccountProfile { Username = username, DisplayName = username, ModifiedAt = 0 };
|
||||
}
|
||||
}
|
||||
/// <summary>动图头像保留全部帧,允许比静态头像大得多(约 4.5 MB)</summary>
|
||||
private const int MaxGifAvatarChars = 6_000_000;
|
||||
public AccountProfile UpdateProfile(string username, string displayName, string? avatar)
|
||||
{
|
||||
if (displayName is null || displayName.Trim().Length > 48 || displayName.Any(char.IsControl)) throw new WebDropException(ErrorCode.BadRequest);
|
||||
if (avatar is not null)
|
||||
{
|
||||
string? prefix = new[] { "data:image/png;base64,", "data:image/jpeg;base64,", "data:image/webp;base64,", "data:image/gif;base64," }.FirstOrDefault(p => avatar.StartsWith(p, StringComparison.Ordinal));
|
||||
if (prefix is null || avatar.Length > (prefix.Contains("gif") ? MaxGifAvatarChars : 350_000) || avatar.Length <= prefix.Length) throw new WebDropException(ErrorCode.BadRequest);
|
||||
try
|
||||
{
|
||||
var bytes = Convert.FromBase64String(avatar[prefix.Length..]);
|
||||
if (prefix.Contains("gif") && !(bytes.Length > 6 && bytes[0] == (byte)'G' && bytes[1] == (byte)'I' && bytes[2] == (byte)'F')) throw new WebDropException(ErrorCode.BadRequest);
|
||||
}
|
||||
catch (FormatException) { throw new WebDropException(ErrorCode.BadRequest); }
|
||||
}
|
||||
if (avatar is not null) AvatarData.Validate(avatar, AvatarData.MaxAccountGifChars);
|
||||
lock (_gate)
|
||||
{
|
||||
using var cmd = _connection.CreateCommand();
|
||||
|
||||
@@ -46,6 +46,7 @@ public sealed class SqliteChannelStore : IResourceStore, IDisposable
|
||||
CREATE INDEX IF NOT EXISTS ix_channel_keys_username ON channel_key_packages(username);
|
||||
CREATE TABLE IF NOT EXISTS workspace_structures (space_id BLOB PRIMARY KEY, state TEXT NOT NULL) WITHOUT ROWID;
|
||||
CREATE TABLE IF NOT EXISTS workspace_crypto (space_id BLOB PRIMARY KEY, state TEXT NOT NULL) WITHOUT ROWID;
|
||||
CREATE TABLE IF NOT EXISTS channel_avatars (space_id BLOB PRIMARY KEY, avatar TEXT NOT NULL) WITHOUT ROWID;
|
||||
""");
|
||||
}
|
||||
|
||||
@@ -502,10 +503,19 @@ public sealed class SqliteChannelStore : IResourceStore, IDisposable
|
||||
Run("DELETE FROM channel_key_packages WHERE channel_id=@c", ("@c", key));
|
||||
Run("DELETE FROM workspace_structures WHERE space_id=@c", ("@c", key));
|
||||
Run("DELETE FROM workspace_crypto WHERE space_id=@c", ("@c", key));
|
||||
Run("DELETE FROM channel_avatars WHERE space_id=@c", ("@c", key));
|
||||
Run("DELETE FROM channel_members WHERE channel_id=@c", ("@c", key));
|
||||
Run("DELETE FROM channel_join_denials WHERE channel_id=@c", ("@c", key));
|
||||
}
|
||||
|
||||
public string? GetChannelAvatar(Id16 id) => Scalar("SELECT avatar FROM channel_avatars WHERE space_id=@c", ("@c", id.ToArray())) as string;
|
||||
|
||||
public void SetChannelAvatar(Id16 id, string? avatar)
|
||||
{
|
||||
if (avatar is null) Run("DELETE FROM channel_avatars WHERE space_id=@c", ("@c", id.ToArray()));
|
||||
else Run("INSERT INTO channel_avatars (space_id, avatar) VALUES (@c,@a) ON CONFLICT(space_id) DO UPDATE SET avatar=excluded.avatar", ("@c", id.ToArray()), ("@a", avatar));
|
||||
}
|
||||
|
||||
public IReadOnlyList<Id16> ListExpiredChannels(long now, int limit) =>
|
||||
Many("SELECT id FROM channels WHERE expires_at<=@now LIMIT @n", r => IdAt(r, 0), ("@now", now), ("@n", limit));
|
||||
|
||||
|
||||
Reference in new issue
Block a user