feat(web): add auth and fix deployment checks
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 9s
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 6s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Snapshot Admin Deployment / build-and-deploy (push) Failing after 2m30s
Deploy to Production / Build & Deploy to Production (push) Failing after 3m49s
Quant Engine CI/CD Pipeline / validate-core (push) Failing after 9s
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 6s
Quant Engine CI/CD Pipeline / validate-ui-and-storage (push) Has been skipped
Snapshot Admin Deployment / build-and-deploy (push) Failing after 2m30s
Deploy to Production / Build & Deploy to Production (push) Failing after 3m49s
This commit is contained in:
@@ -30,6 +30,32 @@ namespace QuantEngine.Infrastructure.Data
|
||||
);
|
||||
");
|
||||
|
||||
// 0b. workspace_account
|
||||
conn.Execute(@"
|
||||
CREATE TABLE IF NOT EXISTS workspace_account (
|
||||
ordinal INT NOT NULL,
|
||||
username TEXT PRIMARY KEY,
|
||||
password_hash TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'Admin',
|
||||
is_active TEXT NOT NULL DEFAULT 'true',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_workspace_account_active ON workspace_account(is_active, username);
|
||||
");
|
||||
|
||||
conn.Execute(@"
|
||||
CREATE TABLE IF NOT EXISTS workspace_session (
|
||||
session_token_hash TEXT PRIMARY KEY,
|
||||
username TEXT NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'Admin',
|
||||
created_at TEXT NOT NULL,
|
||||
expires_at TEXT NOT NULL,
|
||||
revoked_at TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_workspace_session_username ON workspace_session(username, expires_at DESC);
|
||||
");
|
||||
|
||||
// 1. collection_runs
|
||||
conn.Execute(@"
|
||||
CREATE TABLE IF NOT EXISTS collection_runs (
|
||||
@@ -157,6 +183,16 @@ namespace QuantEngine.Infrastructure.Data
|
||||
);
|
||||
");
|
||||
|
||||
conn.Execute(@"
|
||||
INSERT INTO quantengine.workspace_account (
|
||||
ordinal, username, password_hash, role, is_active, created_at, updated_at
|
||||
)
|
||||
SELECT 1, 'admin', '8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A918', 'Admin', 'true', NOW()::text, NOW()::text
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM quantengine.workspace_account WHERE username = 'admin'
|
||||
);
|
||||
");
|
||||
|
||||
// 10. engine_history schema and tables
|
||||
conn.Execute(@"
|
||||
CREATE SCHEMA IF NOT EXISTS engine_history;
|
||||
|
||||
@@ -17,6 +17,89 @@ namespace QuantEngine.Infrastructure.Repositories
|
||||
_connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
// Accounts
|
||||
public async Task<IEnumerable<WorkspaceAccount>> GetAccountsAsync()
|
||||
{
|
||||
using var conn = _connectionFactory.CreateConnection();
|
||||
return await conn.QueryAsync<WorkspaceAccount>(@"
|
||||
SELECT ordinal, username as Username, password_hash as PasswordHash, role as Role,
|
||||
is_active as IsActive, created_at as CreatedAt, updated_at as UpdatedAt
|
||||
FROM quantengine.workspace_account
|
||||
ORDER BY ordinal ASC"
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<WorkspaceAccount?> GetAccountByUsernameAsync(string username)
|
||||
{
|
||||
using var conn = _connectionFactory.CreateConnection();
|
||||
return await conn.QueryFirstOrDefaultAsync<WorkspaceAccount>(@"
|
||||
SELECT ordinal, username as Username, password_hash as PasswordHash, role as Role,
|
||||
is_active as IsActive, created_at as CreatedAt, updated_at as UpdatedAt
|
||||
FROM quantengine.workspace_account
|
||||
WHERE username = @Username",
|
||||
new { Username = username }
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<bool> UpsertAccountAsync(WorkspaceAccount account)
|
||||
{
|
||||
using var conn = _connectionFactory.CreateConnection();
|
||||
var affected = await conn.ExecuteAsync(@"
|
||||
INSERT INTO quantengine.workspace_account (ordinal, username, password_hash, role, is_active, created_at, updated_at)
|
||||
VALUES (@Ordinal, @Username, @PasswordHash, @Role, @IsActive, @CreatedAt, @UpdatedAt)
|
||||
ON CONFLICT (username) DO UPDATE SET
|
||||
ordinal = EXCLUDED.ordinal,
|
||||
password_hash = EXCLUDED.password_hash,
|
||||
role = EXCLUDED.role,
|
||||
is_active = EXCLUDED.is_active,
|
||||
updated_at = EXCLUDED.updated_at",
|
||||
account
|
||||
);
|
||||
return affected > 0;
|
||||
}
|
||||
|
||||
public async Task<WorkspaceSession?> GetSessionByTokenHashAsync(string tokenHash)
|
||||
{
|
||||
using var conn = _connectionFactory.CreateConnection();
|
||||
return await conn.QueryFirstOrDefaultAsync<WorkspaceSession>(@"
|
||||
SELECT session_token_hash as SessionTokenHash, username as Username, role as Role,
|
||||
created_at as CreatedAt, expires_at as ExpiresAt, revoked_at as RevokedAt
|
||||
FROM quantengine.workspace_session
|
||||
WHERE session_token_hash = @TokenHash",
|
||||
new { TokenHash = tokenHash }
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<bool> UpsertSessionAsync(WorkspaceSession session)
|
||||
{
|
||||
using var conn = _connectionFactory.CreateConnection();
|
||||
var affected = await conn.ExecuteAsync(@"
|
||||
INSERT INTO quantengine.workspace_session
|
||||
(session_token_hash, username, role, created_at, expires_at, revoked_at)
|
||||
VALUES
|
||||
(@SessionTokenHash, @Username, @Role, @CreatedAt, @ExpiresAt, @RevokedAt)
|
||||
ON CONFLICT (session_token_hash) DO UPDATE SET
|
||||
username = EXCLUDED.username,
|
||||
role = EXCLUDED.role,
|
||||
expires_at = EXCLUDED.expires_at,
|
||||
revoked_at = EXCLUDED.revoked_at",
|
||||
session
|
||||
);
|
||||
return affected > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> RevokeSessionAsync(string tokenHash, string revokedAt)
|
||||
{
|
||||
using var conn = _connectionFactory.CreateConnection();
|
||||
var affected = await conn.ExecuteAsync(@"
|
||||
UPDATE quantengine.workspace_session
|
||||
SET revoked_at = @RevokedAt
|
||||
WHERE session_token_hash = @TokenHash",
|
||||
new { TokenHash = tokenHash, RevokedAt = revokedAt }
|
||||
);
|
||||
return affected > 0;
|
||||
}
|
||||
|
||||
// Settings
|
||||
public async Task<IEnumerable<Setting>> GetSettingsAsync()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user