mirror of
https://github.com/chylex/Discord-History-Tracker.git
synced 2025-04-15 12:15:43 +02:00
parent
fa00df10d8
commit
943163473a
app
Desktop/Main
Resources
Server
Data
Database
Export
Sqlite
Endpoints
@ -249,11 +249,10 @@ sealed partial class MessageFilterPanelModel : ObservableObject, IDisposable {
|
|||||||
var checkBoxItems = new List<CheckBoxItem<ulong>>();
|
var checkBoxItems = new List<CheckBoxItem<ulong>>();
|
||||||
|
|
||||||
await foreach (var user in state.Db.Users.Get()) {
|
await foreach (var user in state.Db.Users.Get()) {
|
||||||
var name = user.Name;
|
var username = user.Discriminator == null ? user.Name : user.Name + " #" + user.Discriminator;
|
||||||
var discriminator = user.Discriminator;
|
|
||||||
|
|
||||||
checkBoxItems.Add(new CheckBoxItem<ulong>(user.Id) {
|
checkBoxItems.Add(new CheckBoxItem<ulong>(user.Id) {
|
||||||
Title = discriminator == null ? name : name + " #" + discriminator,
|
Title = user.DisplayName == null ? username : $"{user.DisplayName} ({username})",
|
||||||
IsChecked = IncludedUsers == null || IncludedUsers.Contains(user.Id)
|
IsChecked = IncludedUsers == null || IncludedUsers.Contains(user.Id)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ sealed class DebugPageModel {
|
|||||||
var users = Enumerable.Range(0, userCount).Select(_ => new User {
|
var users = Enumerable.Range(0, userCount).Select(_ => new User {
|
||||||
Id = RandomId(rand),
|
Id = RandomId(rand),
|
||||||
Name = RandomName("u"),
|
Name = RandomName("u"),
|
||||||
|
DisplayName = RandomName("u"),
|
||||||
AvatarUrl = null,
|
AvatarUrl = null,
|
||||||
Discriminator = rand.Next(0, 9999).ToString(),
|
Discriminator = rand.Next(0, 9999).ToString(),
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
@ -9,6 +9,8 @@ items:
|
|||||||
pattern: "^[0-9]+$"
|
pattern: "^[0-9]+$"
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
avatar:
|
avatar:
|
||||||
type: string
|
type: string
|
||||||
discriminator:
|
discriminator:
|
||||||
|
@ -69,6 +69,7 @@ const STATE = (function() {
|
|||||||
* @property {String} id
|
* @property {String} id
|
||||||
* @property {String} username
|
* @property {String} username
|
||||||
* @property {String} discriminator
|
* @property {String} discriminator
|
||||||
|
* @property {String} [globalName]
|
||||||
* @property {String} [avatar]
|
* @property {String} [avatar]
|
||||||
* @property {Boolean} [bot]
|
* @property {Boolean} [bot]
|
||||||
*/
|
*/
|
||||||
@ -200,6 +201,10 @@ const STATE = (function() {
|
|||||||
name: user.username
|
name: user.username
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (user.globalName) {
|
||||||
|
obj.displayName = user.globalName;
|
||||||
|
}
|
||||||
|
|
||||||
if (user.avatar) {
|
if (user.avatar) {
|
||||||
obj.avatar = user.avatar;
|
obj.avatar = user.avatar;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ export default (function() {
|
|||||||
templateMessageNoAvatar = new template([
|
templateMessageNoAvatar = new template([
|
||||||
"<div>",
|
"<div>",
|
||||||
"<div class='reply-message'>{reply}</div>",
|
"<div class='reply-message'>{reply}</div>",
|
||||||
"<h2><strong class='username' title='#{user.tag}'>{user.name}</strong><span class='info time'>{timestamp}</span>{edit}{jump}</h2>",
|
"<h2><strong class='username' title='{user.name} #{user.tag}'>{user.displayName}</strong><span class='info time'>{timestamp}</span>{edit}{jump}</h2>",
|
||||||
"<div class='message'>{contents}{embeds}{attachments}</div>",
|
"<div class='message'>{contents}{embeds}{attachments}</div>",
|
||||||
"{reactions}",
|
"{reactions}",
|
||||||
"</div>"
|
"</div>"
|
||||||
@ -141,7 +141,7 @@ export default (function() {
|
|||||||
"<div class='avatar-wrapper'>",
|
"<div class='avatar-wrapper'>",
|
||||||
"<div class='avatar'>{avatar}</div>",
|
"<div class='avatar'>{avatar}</div>",
|
||||||
"<div>",
|
"<div>",
|
||||||
"<h2><strong class='username' title='#{user.tag}'>{user.name}</strong><span class='info time'>{timestamp}</span>{edit}{jump}</h2>",
|
"<h2><strong class='username' title='{user.name} #{user.tag}'>{user.displayName}</strong><span class='info time'>{timestamp}</span>{edit}{jump}</h2>",
|
||||||
"<div class='message'>{contents}{embeds}{attachments}</div>",
|
"<div class='message'>{contents}{embeds}{attachments}</div>",
|
||||||
"{reactions}",
|
"{reactions}",
|
||||||
"</div>",
|
"</div>",
|
||||||
@ -227,6 +227,9 @@ export default (function() {
|
|||||||
if (property === "avatar") {
|
if (property === "avatar") {
|
||||||
return value ? templateUserAvatar.apply(getAvatarUrlObject(value)) : "";
|
return value ? templateUserAvatar.apply(getAvatarUrlObject(value)) : "";
|
||||||
}
|
}
|
||||||
|
else if (property === "user.displayName") {
|
||||||
|
return value ? value : message.user.name;
|
||||||
|
}
|
||||||
else if (property === "user.tag") {
|
else if (property === "user.tag") {
|
||||||
return value ? value : "????";
|
return value ? value : "????";
|
||||||
}
|
}
|
||||||
|
@ -243,10 +243,11 @@ export default (function() {
|
|||||||
|
|
||||||
const options = [];
|
const options = [];
|
||||||
|
|
||||||
for (const key of Object.keys(users)) {
|
for (const id of Object.keys(users)) {
|
||||||
|
const user = users[id];
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.value = key;
|
option.value = id;
|
||||||
option.text = users[key].name;
|
option.text = user.displayName ? `${user.displayName} (${user.name})` : user.name;
|
||||||
options.push(option);
|
options.push(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ namespace DHT.Server.Data;
|
|||||||
public readonly struct User {
|
public readonly struct User {
|
||||||
public ulong Id { get; init; }
|
public ulong Id { get; init; }
|
||||||
public string Name { get; init; }
|
public string Name { get; init; }
|
||||||
|
public string? DisplayName { get; init; }
|
||||||
public string? AvatarUrl { get; init; }
|
public string? AvatarUrl { get; init; }
|
||||||
public string? Discriminator { get; init; }
|
public string? Discriminator { get; init; }
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,9 @@ static class ViewerJson {
|
|||||||
public sealed class JsonUser {
|
public sealed class JsonUser {
|
||||||
public required string Name { get; init; }
|
public required string Name { get; init; }
|
||||||
|
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public string? DisplayName { get; init; }
|
||||||
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public string? Avatar { get; init; }
|
public string? Avatar { get; init; }
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ static class ViewerJsonExport {
|
|||||||
await foreach (var user in db.Users.Get(cancellationToken)) {
|
await foreach (var user in db.Users.Get(cancellationToken)) {
|
||||||
users[user.Id] = new ViewerJson.JsonUser {
|
users[user.Id] = new ViewerJson.JsonUser {
|
||||||
Name = user.Name,
|
Name = user.Name,
|
||||||
|
DisplayName = user.DisplayName,
|
||||||
Avatar = user.AvatarUrl,
|
Avatar = user.AvatarUrl,
|
||||||
Tag = user.Discriminator
|
Tag = user.Discriminator
|
||||||
};
|
};
|
||||||
|
@ -29,6 +29,7 @@ sealed class SqliteUserRepository : BaseSqliteRepository, IUserRepository {
|
|||||||
await using var cmd = conn.Upsert("users", [
|
await using var cmd = conn.Upsert("users", [
|
||||||
("id", SqliteType.Integer),
|
("id", SqliteType.Integer),
|
||||||
("name", SqliteType.Text),
|
("name", SqliteType.Text),
|
||||||
|
("display_name", SqliteType.Text),
|
||||||
("avatar_url", SqliteType.Text),
|
("avatar_url", SqliteType.Text),
|
||||||
("discriminator", SqliteType.Text)
|
("discriminator", SqliteType.Text)
|
||||||
]);
|
]);
|
||||||
@ -38,6 +39,7 @@ sealed class SqliteUserRepository : BaseSqliteRepository, IUserRepository {
|
|||||||
foreach (var user in users) {
|
foreach (var user in users) {
|
||||||
cmd.Set(":id", user.Id);
|
cmd.Set(":id", user.Id);
|
||||||
cmd.Set(":name", user.Name);
|
cmd.Set(":name", user.Name);
|
||||||
|
cmd.Set(":display_name", user.DisplayName);
|
||||||
cmd.Set(":avatar_url", user.AvatarUrl);
|
cmd.Set(":avatar_url", user.AvatarUrl);
|
||||||
cmd.Set(":discriminator", user.Discriminator);
|
cmd.Set(":discriminator", user.Discriminator);
|
||||||
await cmd.ExecuteNonQueryAsync();
|
await cmd.ExecuteNonQueryAsync();
|
||||||
@ -62,15 +64,16 @@ sealed class SqliteUserRepository : BaseSqliteRepository, IUserRepository {
|
|||||||
public async IAsyncEnumerable<User> Get([EnumeratorCancellation] CancellationToken cancellationToken) {
|
public async IAsyncEnumerable<User> Get([EnumeratorCancellation] CancellationToken cancellationToken) {
|
||||||
await using var conn = await pool.Take();
|
await using var conn = await pool.Take();
|
||||||
|
|
||||||
await using var cmd = conn.Command("SELECT id, name, avatar_url, discriminator FROM users");
|
await using var cmd = conn.Command("SELECT id, name, display_name, avatar_url, discriminator FROM users");
|
||||||
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
|
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken);
|
||||||
|
|
||||||
while (await reader.ReadAsync(cancellationToken)) {
|
while (await reader.ReadAsync(cancellationToken)) {
|
||||||
yield return new User {
|
yield return new User {
|
||||||
Id = reader.GetUint64(0),
|
Id = reader.GetUint64(0),
|
||||||
Name = reader.GetString(1),
|
Name = reader.GetString(1),
|
||||||
AvatarUrl = reader.IsDBNull(2) ? null : reader.GetString(2),
|
DisplayName = reader.IsDBNull(2) ? null : reader.GetString(2),
|
||||||
Discriminator = reader.IsDBNull(3) ? null : reader.GetString(3),
|
AvatarUrl = reader.IsDBNull(3) ? null : reader.GetString(3),
|
||||||
|
Discriminator = reader.IsDBNull(4) ? null : reader.GetString(4),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
app/Server/Database/Sqlite/Schema/SqliteSchemaUpgradeTo8.cs
Normal file
11
app/Server/Database/Sqlite/Schema/SqliteSchemaUpgradeTo8.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using DHT.Server.Database.Sqlite.Utils;
|
||||||
|
|
||||||
|
namespace DHT.Server.Database.Sqlite.Schema;
|
||||||
|
|
||||||
|
sealed class SqliteSchemaUpgradeTo8 : ISchemaUpgrade {
|
||||||
|
async Task ISchemaUpgrade.Run(ISqliteConnection conn, ISchemaUpgradeCallbacks.IProgressReporter reporter) {
|
||||||
|
await reporter.MainWork("Applying schema changes...", 0, 1);
|
||||||
|
await conn.ExecuteAsync("ALTER TABLE users ADD display_name TEXT");
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ using DHT.Utils.Logging;
|
|||||||
namespace DHT.Server.Database.Sqlite;
|
namespace DHT.Server.Database.Sqlite;
|
||||||
|
|
||||||
sealed class SqliteSchema {
|
sealed class SqliteSchema {
|
||||||
internal const int Version = 7;
|
internal const int Version = 8;
|
||||||
|
|
||||||
private static readonly Log Log = Log.ForType<SqliteSchema>();
|
private static readonly Log Log = Log.ForType<SqliteSchema>();
|
||||||
|
|
||||||
@ -48,6 +48,7 @@ sealed class SqliteSchema {
|
|||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id INTEGER PRIMARY KEY NOT NULL,
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
|
display_name TEXT,
|
||||||
avatar_url TEXT,
|
avatar_url TEXT,
|
||||||
discriminator TEXT
|
discriminator TEXT
|
||||||
)
|
)
|
||||||
@ -171,6 +172,7 @@ sealed class SqliteSchema {
|
|||||||
{ 4, new SqliteSchemaUpgradeTo5() },
|
{ 4, new SqliteSchemaUpgradeTo5() },
|
||||||
{ 5, new SqliteSchemaUpgradeTo6() },
|
{ 5, new SqliteSchemaUpgradeTo6() },
|
||||||
{ 6, new SqliteSchemaUpgradeTo7() },
|
{ 6, new SqliteSchemaUpgradeTo7() },
|
||||||
|
{ 7, new SqliteSchemaUpgradeTo8() },
|
||||||
};
|
};
|
||||||
|
|
||||||
var perf = Log.Start("from version " + dbVersion);
|
var perf = Log.Start("from version " + dbVersion);
|
||||||
|
@ -30,6 +30,7 @@ sealed class TrackUsersEndpoint(IDatabaseFile db) : BaseEndpoint(db) {
|
|||||||
private static User ReadUser(JsonElement json, string path) => new () {
|
private static User ReadUser(JsonElement json, string path) => new () {
|
||||||
Id = json.RequireSnowflake("id", path),
|
Id = json.RequireSnowflake("id", path),
|
||||||
Name = json.RequireString("name", path),
|
Name = json.RequireString("name", path),
|
||||||
|
DisplayName = json.HasKey("displayName") ? json.RequireString("displayName", path) : null,
|
||||||
AvatarUrl = json.HasKey("avatar") ? json.RequireString("avatar", path) : null,
|
AvatarUrl = json.HasKey("avatar") ? json.RequireString("avatar", path) : null,
|
||||||
Discriminator = json.HasKey("discriminator") ? json.RequireString("discriminator", path) : null
|
Discriminator = json.HasKey("discriminator") ? json.RequireString("discriminator", path) : null
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user