Files
voice-cat/clients/windows/VoiceCat.App/Forms/AccountsDialog.cs

201 lines
6.1 KiB
C#
Raw Permalink Normal View History

using VoiceCat.Interop;
namespace VoiceCat.App.Forms;
/// <summary>
/// Admin account management: list, create, reset password, and delete server accounts.
/// </summary>
public sealed class AccountsDialog : Form
{
private readonly VoiceCatClient _client;
private readonly ListView _lvAccounts;
private readonly Button _btnRefresh;
private readonly Button _btnAdd;
private readonly Button _btnResetPassword;
private readonly Button _btnDelete;
public AccountsDialog(VoiceCatClient client)
{
_client = client;
Text = "Server accounts";
FormBorderStyle = FormBorderStyle.Sizable;
StartPosition = FormStartPosition.CenterParent;
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(560, 360);
MinimumSize = new Size(420, 260);
_lvAccounts = new ListView
{
View = View.Details,
FullRowSelect = true,
GridLines = true,
Dock = DockStyle.Fill,
TabIndex = 0,
};
_lvAccounts.Columns.Add("Username", 160);
_lvAccounts.Columns.Add("Admin", 50);
_lvAccounts.Columns.Add("Created", 130);
_lvAccounts.Columns.Add("Last login", 130);
_lvAccounts.SelectedIndexChanged += (_, _) => UpdateButtons();
var pnlButtons = new Panel
{
Dock = DockStyle.Bottom,
Height = 44,
};
_btnRefresh = new Button
{
Text = "&Refresh",
Location = new Point(12, 9),
Size = new Size(75, 27),
TabIndex = 1,
};
_btnRefresh.Click += (_, _) => RefreshList();
_btnAdd = new Button
{
Text = "&Add...",
Location = new Point(100, 9),
Size = new Size(75, 27),
TabIndex = 2,
};
_btnAdd.Click += (_, _) => AddAccount();
_btnResetPassword = new Button
{
Text = "&Reset password...",
Location = new Point(188, 9),
Size = new Size(120, 27),
TabIndex = 3,
Enabled = false,
};
_btnResetPassword.Click += (_, _) => ResetPassword();
_btnDelete = new Button
{
Text = "&Delete",
Location = new Point(320, 9),
Size = new Size(75, 27),
TabIndex = 4,
Enabled = false,
};
_btnDelete.Click += (_, _) => DeleteAccount();
pnlButtons.Controls.AddRange([_btnRefresh, _btnAdd, _btnResetPassword, _btnDelete]);
Controls.Add(_lvAccounts);
Controls.Add(pnlButtons);
Load += (_, _) => RefreshList();
}
private void UpdateButtons()
{
bool selected = _lvAccounts.SelectedItems.Count > 0;
_btnResetPassword.Enabled = selected;
_btnDelete.Enabled = selected;
}
private void RefreshList()
{
_client.RequestAccountList();
// The event will come back asynchronously; poll briefly for the list.
var deadline = DateTime.UtcNow.AddSeconds(2);
List<AccountInfo>? accounts = null;
while (DateTime.UtcNow < deadline)
{
_client.PumpEvents();
accounts = _client.ListAccounts();
if (accounts.Count > 0) break;
Thread.Sleep(30);
}
accounts ??= _client.ListAccounts();
_lvAccounts.BeginUpdate();
_lvAccounts.Items.Clear();
foreach (var a in accounts.OrderBy(a => a.Username))
{
var item = new ListViewItem(a.Username);
item.SubItems.Add(a.IsAdmin ? "Yes" : "No");
item.SubItems.Add(FormatDate(a.CreatedAtUnixMs));
item.SubItems.Add(FormatDate(a.LastLoginUnixMs));
_lvAccounts.Items.Add(item);
}
_lvAccounts.EndUpdate();
UpdateButtons();
}
private static string FormatDate(ulong ms)
{
if (ms == 0) return "—";
try
{
return DateTimeOffset.FromUnixTimeMilliseconds((long)ms).LocalDateTime.ToString("g");
}
catch
{
return "—";
}
}
private void AddAccount()
{
using var userDlg = new InputDialog("Add account", "&Username:");
if (userDlg.ShowDialog(this) != DialogResult.OK || string.IsNullOrWhiteSpace(userDlg.TextValue))
return;
using var pwDlg = new PasswordPromptDialog($"Password for {userDlg.TextValue}:");
if (pwDlg.ShowDialog(this) != DialogResult.OK || string.IsNullOrEmpty(pwDlg.Password))
return;
var r = _client.CreateAccount(userDlg.TextValue, pwDlg.Password);
if (r != VcResult.Ok)
{
MessageBox.Show(this, $"Create account failed: {r}", "VoiceCat",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
RefreshList();
}
private void ResetPassword()
{
if (_lvAccounts.SelectedItems.Count == 0) return;
string username = _lvAccounts.SelectedItems[0].Text;
using var dlg = new PasswordPromptDialog($"New password for {username}:");
if (dlg.ShowDialog(this) != DialogResult.OK || string.IsNullOrEmpty(dlg.Password))
return;
var r = _client.ResetPassword(username, dlg.Password);
if (r != VcResult.Ok)
{
MessageBox.Show(this, $"Reset password failed: {r}", "VoiceCat",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
RefreshList();
}
private void DeleteAccount()
{
if (_lvAccounts.SelectedItems.Count == 0) return;
string username = _lvAccounts.SelectedItems[0].Text;
var confirm = MessageBox.Show(this, $"Delete account '{username}'?",
"VoiceCat", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (confirm != DialogResult.Yes) return;
var r = _client.DeleteAccount(username);
if (r != VcResult.Ok)
{
MessageBox.Show(this, $"Delete account failed: {r}", "VoiceCat",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
RefreshList();
}
}