feat: Nachrichten als gelöscht markieren
- DB: deleted_on TEXT Spalte in messages (Migration)
- Backend: ToggleMessageDelete(), includeDeleted-Parameter in allen History-Queries
- Neuer Endpoint: PUT /api/messages/{id}/delete
- Frontend: Trash-Button zwischen Reply- und Mark-Button
- Gelöschte Nachrichten: durchgestrichen + roter Rand (oder versteckt je nach Einstellung)
- Einstellungen: Toggle-Switch 'Gelöschte Nachrichten anzeigen'
- KI-Payload: gelöschte Nachrichten werden nicht mitgeschickt
This commit is contained in:
1 parent
493dfcda1c
commit
a14a991a0f
11 files changed
+248
-39
No files matched your search
+46
-15
@@ -146,6 +146,7 @@ public class DatabaseService
|
||||
TryAddColumn(conn, "agents", "use_user_info", "INTEGER NOT NULL DEFAULT 1");
|
||||
TryAddColumn(conn, "agents", "use_memory", "INTEGER NOT NULL DEFAULT 1");
|
||||
|
||||
TryAddColumn(conn, "messages", "deleted_on", "TEXT");
|
||||
TryAddColumn(conn, "agents", "use_web_search", "INTEGER NOT NULL DEFAULT 0");
|
||||
TryAddColumn(conn, "agents", "web_search_version", "TEXT DEFAULT ''");
|
||||
|
||||
@@ -560,57 +561,62 @@ public class DatabaseService
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<int> GetActiveMessageCount(string sessionId)
|
||||
public async Task<int> GetActiveMessageCount(string sessionId, bool includeDeleted = false)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
return await conn.ExecuteScalarAsync<int>(@"
|
||||
var deletedFilter = includeDeleted ? "" : "AND m.deleted_on IS NULL";
|
||||
return await conn.ExecuteScalarAsync<int>($@"
|
||||
SELECT COUNT(*) FROM messages m
|
||||
JOIN chains c ON m.chain_id = c.chain_id
|
||||
WHERE c.archive_id IS NULL AND c.session_id = @sessionId",
|
||||
WHERE c.archive_id IS NULL AND c.session_id = @sessionId {deletedFilter}",
|
||||
new { sessionId });
|
||||
}
|
||||
|
||||
public async Task<List<MessageRecord>> GetLatestActiveMessages(string sessionId, int limit)
|
||||
public async Task<List<MessageRecord>> GetLatestActiveMessages(string sessionId, int limit, bool includeDeleted = false)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
var messages = await conn.QueryAsync<MessageRecord>(@"
|
||||
var deletedFilter = includeDeleted ? "" : "AND m.deleted_on IS NULL";
|
||||
var messages = await conn.QueryAsync<MessageRecord>($@"
|
||||
SELECT m.* FROM messages m
|
||||
JOIN chains c ON m.chain_id = c.chain_id
|
||||
WHERE c.archive_id IS NULL AND c.session_id = @sessionId
|
||||
WHERE c.archive_id IS NULL AND c.session_id = @sessionId {deletedFilter}
|
||||
ORDER BY m.id DESC LIMIT @limit",
|
||||
new { sessionId, limit });
|
||||
return messages.Reverse().ToList();
|
||||
}
|
||||
|
||||
public async Task<int> GetActiveMessageCountBeforeId(string sessionId, long beforeId)
|
||||
public async Task<int> GetActiveMessageCountBeforeId(string sessionId, long beforeId, bool includeDeleted = false)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
return await conn.ExecuteScalarAsync<int>(@"
|
||||
var deletedFilter = includeDeleted ? "" : "AND m.deleted_on IS NULL";
|
||||
return await conn.ExecuteScalarAsync<int>($@"
|
||||
SELECT COUNT(*) FROM messages m
|
||||
JOIN chains c ON m.chain_id = c.chain_id
|
||||
WHERE m.id < @beforeId AND c.archive_id IS NULL AND c.session_id = @sessionId",
|
||||
WHERE m.id < @beforeId AND c.archive_id IS NULL AND c.session_id = @sessionId {deletedFilter}",
|
||||
new { sessionId, beforeId });
|
||||
}
|
||||
|
||||
public async Task<List<MessageRecord>> GetActiveMessagesBeforeId(string sessionId, long beforeId, int limit)
|
||||
public async Task<List<MessageRecord>> GetActiveMessagesBeforeId(string sessionId, long beforeId, int limit, bool includeDeleted = false)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
var messages = await conn.QueryAsync<MessageRecord>(@"
|
||||
var deletedFilter = includeDeleted ? "" : "AND m.deleted_on IS NULL";
|
||||
var messages = await conn.QueryAsync<MessageRecord>($@"
|
||||
SELECT m.* FROM messages m
|
||||
JOIN chains c ON m.chain_id = c.chain_id
|
||||
WHERE m.id < @beforeId AND c.archive_id IS NULL AND c.session_id = @sessionId
|
||||
WHERE m.id < @beforeId AND c.archive_id IS NULL AND c.session_id = @sessionId {deletedFilter}
|
||||
ORDER BY m.id DESC LIMIT @limit",
|
||||
new { sessionId, beforeId, limit });
|
||||
return messages.Reverse().ToList();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MessageRecord>> GetActiveMessagesAfterId(string sessionId, long afterId, int limit = 200)
|
||||
public async Task<IEnumerable<MessageRecord>> GetActiveMessagesAfterId(string sessionId, long afterId, int limit = 200, bool includeDeleted = false)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
return await conn.QueryAsync<MessageRecord>(@"
|
||||
var deletedFilter = includeDeleted ? "" : "AND m.deleted_on IS NULL";
|
||||
return await conn.QueryAsync<MessageRecord>($@"
|
||||
SELECT m.* FROM messages m
|
||||
JOIN chains c ON m.chain_id = c.chain_id
|
||||
WHERE m.id > @afterId AND c.archive_id IS NULL AND c.session_id = @sessionId
|
||||
WHERE m.id > @afterId AND c.archive_id IS NULL AND c.session_id = @sessionId {deletedFilter}
|
||||
ORDER BY m.id LIMIT @limit",
|
||||
new { sessionId, afterId, limit });
|
||||
}
|
||||
@@ -628,6 +634,31 @@ public class DatabaseService
|
||||
new { messageId });
|
||||
}
|
||||
|
||||
// ── Message Deletion ──
|
||||
|
||||
public async Task<string> ToggleMessageDelete(long messageId)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
var current = await conn.ExecuteScalarAsync<string>(
|
||||
"SELECT deleted_on FROM messages WHERE id = @messageId", new { messageId });
|
||||
string newValue;
|
||||
if (current == null)
|
||||
{
|
||||
newValue = DateTime.UtcNow.ToString("o");
|
||||
await conn.ExecuteAsync(
|
||||
"UPDATE messages SET deleted_on = @newValue WHERE id = @messageId",
|
||||
new { messageId, newValue });
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = null;
|
||||
await conn.ExecuteAsync(
|
||||
"UPDATE messages SET deleted_on = NULL WHERE id = @messageId",
|
||||
new { messageId });
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MessageRecord>> GetMarkedMessages(string sessionId)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
|
||||
Reference in new issue
Block a user