Files
gott/Services/DatabaseService.Users.cs
T
Meleki dde0fede7d User-spezifische API-Key-Auswahl, globales is_active entfernt
Backend:
- is_active komplett entfernt, durch is_public (Admin-Toggle) ersetzt
- Neues selected_api_key_id auf users-Tabelle
- AnthropicService: globaler _token entfernt, apiToken pro Request
- Token-Durchreichung: StreamChat → ProcessStream → RunAgentChat →
  RunPreparer/RunReview/RunFinalizer, ExecuteTool, send_to_session
- ChatEndpoint: User-Key aus DB laden, an StreamChat übergeben
- TelegramService: Key per bot.UserId auflösen
- CronjobService: Key per job.UserId auflösen
- Neue Endpoints: GET /api/api-keys/available, PUT /api/api-keys/select/{keyId},
  GET /api/api-keys/selected, PUT /api/admin/api-keys/{keyId}/public,
  POST /api/admin/api-keys/check-all
- Program.cs: AnthropicService ohne Token-Parameter

Frontend:
- API-Keys-Page: Public-Toggle (Globe/Lock) statt Activate/Deactivate
- Alle prüfen Button für Batch-Key-Check
- Chat: Key-Auswahl für alle User (nicht nur Admin)
- Dummy-Badge wenn kein Key ausgewählt
- Fallback-Badge bei Key ohne Usage-Daten
- Key-Switch-Modal: apiGetAvailableKeys + apiSelectApiKey
2026-03-13 12:27:03 +01:00

219 lines
8.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Dapper;
using Gott.Models;
namespace Gott.Services;
public partial class DatabaseService
{
// ── Shared Messages ──
public async Task<SharedMessageRecord> CreateSharedMessage(long messageId, string userId, bool includeContext, string expiresAt = null)
{
using var conn = CreateConnection();
var record = new SharedMessageRecord
{
ShareToken = Guid.NewGuid().ToString("N"),
MessageId = messageId,
UserId = userId,
IncludeContext = includeContext,
ExpiresAt = expiresAt,
CreatedAt = DateTime.UtcNow.ToString("o")
};
await conn.ExecuteAsync(@"
INSERT INTO shared_messages (share_token, message_id, user_id, include_context, expires_at, created_at)
VALUES (@ShareToken, @MessageId, @UserId, @IncludeContext, @ExpiresAt, @CreatedAt)
", record);
return record;
}
public async Task<SharedMessageRecord> GetSharedMessage(string shareToken)
{
using var conn = CreateConnection();
return await conn.QuerySingleOrDefaultAsync<SharedMessageRecord>(
"SELECT * FROM shared_messages WHERE share_token = @shareToken", new { shareToken });
}
public async Task<IEnumerable<SharedMessageRecord>> GetSharedMessagesByUser(string userId)
{
using var conn = CreateConnection();
return await conn.QueryAsync<SharedMessageRecord>(
"SELECT * FROM shared_messages WHERE user_id = @userId ORDER BY created_at DESC", new { userId });
}
public async Task DeleteSharedMessage(string shareToken, string userId)
{
using var conn = CreateConnection();
await conn.ExecuteAsync(
"DELETE FROM shared_messages WHERE share_token = @shareToken AND user_id = @userId",
new { shareToken, userId });
}
public async Task<MessageRecord> GetMessage(long messageId)
{
using var conn = CreateConnection();
return await conn.QuerySingleOrDefaultAsync<MessageRecord>(
"SELECT * FROM messages WHERE id = @messageId", new { messageId });
}
public async Task<List<MessageRecord>> GetChainMessagesUpTo(string chainId, long messageId)
{
using var conn = CreateConnection();
var result = await conn.QueryAsync<MessageRecord>(
"SELECT * FROM messages WHERE chain_id = @chainId AND id <= @messageId ORDER BY id ASC",
new { chainId, messageId });
return result.AsList();
}
// ── Users ──
public void EnsureDefaultUser(AuthService auth)
{
using var conn = CreateConnection();
var count = conn.ExecuteScalar<int>("SELECT COUNT(*) FROM users");
string adminUserId;
if (count == 0)
{
adminUserId = Guid.NewGuid().ToString("N");
var now = DateTime.UtcNow.ToString("o");
conn.Execute(@"
INSERT INTO users (user_id, username, password_hash, display_name, is_admin, created_at, updated_at)
VALUES (@userId, @username, @hash, @displayName, 1, @now, @now)",
new
{
userId = adminUserId,
username = "admin",
hash = auth.HashPassword("admin"),
displayName = "Admin",
now
});
}
else
{
adminUserId = conn.ExecuteScalar<string>("SELECT user_id FROM users ORDER BY id LIMIT 1");
}
// Bestehende Sessions/Agents ohne User dem ersten User zuweisen
conn.Execute("UPDATE sessions SET user_id = @userId WHERE user_id IS NULL", new { userId = adminUserId });
conn.Execute("UPDATE agents SET user_id = @userId WHERE user_id IS NULL", new { userId = adminUserId });
// Erster User ist immer Admin
conn.Execute("UPDATE users SET is_admin = 1 WHERE user_id = @userId AND is_admin = 0", new { userId = adminUserId });
}
public async Task<UserRecord> GetUserByUsername(string username)
{
using var conn = CreateConnection();
return await conn.QuerySingleOrDefaultAsync<UserRecord>(
"SELECT * FROM users WHERE username = @username COLLATE NOCASE",
new { username });
}
public async Task<UserRecord> GetUser(string userId)
{
using var conn = CreateConnection();
return await conn.QuerySingleOrDefaultAsync<UserRecord>(
"SELECT * FROM users WHERE user_id = @userId",
new { userId });
}
public async Task<IEnumerable<UserRecord>> GetUsers()
{
using var conn = CreateConnection();
return await conn.QueryAsync<UserRecord>(
"SELECT * FROM users ORDER BY username");
}
public async Task UpdateUserPassword(string userId, string passwordHash)
{
using var conn = CreateConnection();
await conn.ExecuteAsync(
"UPDATE users SET password_hash = @passwordHash, updated_at = @now WHERE user_id = @userId",
new { userId, passwordHash, now = DateTime.UtcNow.ToString("o") });
}
public async Task UpdateUserProfile(string userId, string displayName, string persona)
{
using var conn = CreateConnection();
await conn.ExecuteAsync(
"UPDATE users SET display_name = @displayName, persona = @persona, updated_at = @now WHERE user_id = @userId",
new { userId, displayName, persona, now = DateTime.UtcNow.ToString("o") });
}
public async Task<string> GetUserSettings(string userId)
{
using var conn = CreateConnection();
return await conn.QuerySingleOrDefaultAsync<string>(
"SELECT settings FROM users WHERE user_id = @userId",
new { userId });
}
public async Task UpdateUserSettings(string userId, string settings)
{
using var conn = CreateConnection();
await conn.ExecuteAsync(
"UPDATE users SET settings = @settings, updated_at = @now WHERE user_id = @userId",
new { userId, settings, now = DateTime.UtcNow.ToString("o") });
}
public async Task<UserRecord> CreateUser(string username, string passwordHash, string displayName, bool isAdmin, string defaultPath = null)
{
using var conn = CreateConnection();
var now = DateTime.UtcNow.ToString("o");
var userId = Guid.NewGuid().ToString("N");
await conn.ExecuteAsync(@"
INSERT INTO users (user_id, username, password_hash, display_name, is_admin, default_path, created_at, updated_at)
VALUES (@userId, @username, @passwordHash, @displayName, @isAdmin, @defaultPath, @now, @now)",
new { userId, username, passwordHash, displayName, isAdmin, defaultPath, now });
return await GetUser(userId);
}
public async Task UpdateUserAdmin(string userId, string username, string displayName, bool isAdmin, string defaultPath)
{
using var conn = CreateConnection();
await conn.ExecuteAsync(
"UPDATE users SET username = @username, display_name = @displayName, is_admin = @isAdmin, default_path = @defaultPath, updated_at = @now WHERE user_id = @userId",
new { userId, username, displayName, isAdmin, defaultPath, now = DateTime.UtcNow.ToString("o") });
}
public async Task DeleteUser(string userId)
{
using var conn = CreateConnection();
await conn.ExecuteAsync("DELETE FROM tokens WHERE user_id = @userId", new { userId });
await conn.ExecuteAsync("DELETE FROM shared_messages WHERE user_id = @userId", new { userId });
await conn.ExecuteAsync("DELETE FROM users WHERE user_id = @userId", new { userId });
}
// ── User API-Key Auswahl ──
public async Task SetUserSelectedApiKey(string userId, string keyId)
{
using var conn = CreateConnection();
await conn.ExecuteAsync(
"UPDATE users SET selected_api_key_id = @keyId, updated_at = @now WHERE user_id = @userId",
new { userId, keyId = (object)keyId ?? DBNull.Value, now = DateTime.UtcNow.ToString("o") });
}
public async Task<string> GetUserSelectedApiKeyId(string userId)
{
using var conn = CreateConnection();
return await conn.QuerySingleOrDefaultAsync<string>(
"SELECT selected_api_key_id FROM users WHERE user_id = @userId",
new { userId });
}
public async Task<ApiKeyRecord> GetUserSelectedApiKey(string userId)
{
using var conn = CreateConnection();
return await conn.QuerySingleOrDefaultAsync<ApiKeyRecord>(@"
SELECT k.* FROM api_keys k
INNER JOIN users u ON u.selected_api_key_id = k.key_id
WHERE u.user_id = @userId",
new { userId });
}
}