372 lines
11 KiB
C#
372 lines
11 KiB
C#
using System;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Avalonia.Threading;
|
|
using DynamicData;
|
|
using Flawless.Client.Models;
|
|
using Flawless.Client.Remote;
|
|
using Flawless.Client.Service;
|
|
using Flawless.Client.ViewModels.ModalBox;
|
|
using Flawless.Client.Views.ModalBox;
|
|
using ReactiveUI;
|
|
using ReactiveUI.SourceGenerators;
|
|
using Refit;
|
|
using Ursa.Controls;
|
|
|
|
namespace Flawless.Client.ViewModels;
|
|
|
|
public record Log(DateTime Time, Microsoft.Extensions.Logging.LogLevel Level, string Message)
|
|
{
|
|
public static Log From(LogEntryResponse response) => new(
|
|
response.Timestamp.LocalDateTime,
|
|
Enum.Parse<Microsoft.Extensions.Logging.LogLevel>(response.Level),
|
|
response.Message);
|
|
}
|
|
|
|
public partial class SettingViewModel : RoutableViewModelBase
|
|
{
|
|
public ObservableCollection<UserModel> Users { get; } = new();
|
|
|
|
public ObservableCollection<Log> Logs { get; } = new();
|
|
|
|
public AppSettingModel SettingModel => SettingService.C.AppSetting;
|
|
|
|
[Reactive] private UserModel _loginUser;
|
|
|
|
[Reactive] private string _nickname;
|
|
|
|
[Reactive] private string _email;
|
|
|
|
[Reactive] private string _phoneNumber;
|
|
|
|
[Reactive] private UserModel.SexType _gender;
|
|
|
|
[Reactive] private string _bio;
|
|
|
|
[Reactive] private DateTime?
|
|
_logSearchFrom = null,
|
|
_logSearchTo = null;
|
|
|
|
[Reactive] private int _page = 1;
|
|
|
|
[Reactive] private int _pageSize = 50;
|
|
|
|
[Reactive] private Microsoft.Extensions.Logging.LogLevel _loglevel = Microsoft.Extensions.Logging.LogLevel.Information;
|
|
|
|
[Reactive] private string _serverBlacklist, _serverWhitelist;
|
|
|
|
public SettingViewModel(IScreen hostScreen) : base(hostScreen)
|
|
{
|
|
LoadClientSettings();
|
|
}
|
|
|
|
private async Task LoadServerData()
|
|
{
|
|
try
|
|
{
|
|
var sb = new StringBuilder();
|
|
ServerBlacklist = sb.AppendJoin(",\n", await Api.C.Gateway.IpWhitelistGet()).ToString();
|
|
ServerBlacklist = sb.Clear().AppendJoin(",\n", await Api.C.Gateway.IpBlacklistGet()).ToString();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
|
|
private async Task LoadClientSettings()
|
|
{
|
|
LoginUser = (await UserService.C.GetOrDownloadUserInfoAsync(Api.C.Username.Value!))!;
|
|
|
|
Nickname = LoginUser.Nickname;
|
|
Email = LoginUser.Email;
|
|
PhoneNumber = LoginUser.PhoneNumber;
|
|
Gender = LoginUser.Sex;
|
|
Bio = LoginUser.Bio;
|
|
|
|
if (LoginUser.IsAdmin) await LoadServerData();
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task SaveAccountChangesAsync()
|
|
{
|
|
try
|
|
{
|
|
await Api.C.Gateway.UpdateInfo(new UserInfoModifyResponse
|
|
{
|
|
NickName = this.Nickname == LoginUser.Nickname ? null! : this.Nickname,
|
|
Gender = this.Gender == LoginUser.Sex ? null : (UserSex) this.Gender,
|
|
Bio = this.Bio == LoginUser.Bio ? null! : this.Bio
|
|
});
|
|
|
|
if (Email != LoginUser.Email)
|
|
await Api.C.Gateway.UpdateEmail(new UserContactModifyResponse
|
|
{ Email = Email, });
|
|
|
|
if (PhoneNumber != LoginUser.PhoneNumber)
|
|
await Api.C.Gateway.UpdatePhone(new UserContactModifyResponse
|
|
{ Phone = PhoneNumber, });
|
|
|
|
UIHelper.NotifySuccess("Saved");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task ChangePasswordAsync()
|
|
{
|
|
var result = new PasswordChangeDialogViewModel();
|
|
var opt = UIHelper.DefaultOverlayDialogOptionsYesNo();
|
|
while (true)
|
|
{
|
|
var r = await OverlayDialog.ShowModal<PasswordChangeDialogView, PasswordChangeDialogViewModel>(result, AppDefaultValues.HostId, opt);
|
|
if (r == DialogResult.No) return;
|
|
if (result.Validate()) break;
|
|
|
|
UIHelper.NotifyError("Please check your input");
|
|
}
|
|
|
|
try
|
|
{
|
|
await Api.C.Gateway.ResetPassword(new ResetPasswordRequest()
|
|
{
|
|
Identity = LoginUser.Username,
|
|
NewPassword = result.NewPassword,
|
|
OldPassword = result.OldPassword
|
|
});
|
|
|
|
UIHelper.NotifySuccess("Password create successfully");
|
|
}
|
|
catch (ApiException ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task DeleteSelfAccountAsync()
|
|
{
|
|
if (await UIHelper.SimpleAskAsync("This operation can not undo. Do you sure that?") == DialogResult.Yes)
|
|
{
|
|
try
|
|
{
|
|
await Api.C.Gateway.Delete(Api.C.Username.Value!);
|
|
Process.GetCurrentProcess().Kill();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task SaveClientPreferenceAsync()
|
|
{
|
|
try
|
|
{
|
|
await SettingService.C.WriteToDiskAsync();
|
|
UIHelper.NotifySuccess("Saved Success!");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
UIHelper.NotifyError(e);
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task SaveServerPreferenceAsync()
|
|
{
|
|
try
|
|
{
|
|
await Api.C.Gateway.IpWhitelistPost(ServerWhitelist.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries));
|
|
await Api.C.Gateway.IpBlacklistPost(ServerBlacklist.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries));
|
|
UIHelper.NotifySuccess("Saved Success!");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task ResetClientPreferenceAsync()
|
|
{
|
|
if (await UIHelper.SimpleAskAsync("Do you sure reset settings to default?") == DialogResult.Yes)
|
|
{
|
|
await SettingService.C.ResetAsync();
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task ResetServerPreferenceAsync()
|
|
{
|
|
if (await UIHelper.SimpleAskAsync("Do you sure reset settings to default?") == DialogResult.Yes)
|
|
{
|
|
try
|
|
{
|
|
ServerBlacklist = ServerWhitelist = string.Empty;
|
|
await Api.C.Gateway.IpBlacklistPost([]);
|
|
await Api.C.Gateway.IpWhitelistPost([]);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task CreateUserAsync()
|
|
{
|
|
var result = new UserCreateDialogViewModel();
|
|
result.Password = GenerateRandomPassword();
|
|
var opt = UIHelper.DefaultOverlayDialogOptionsYesNo();
|
|
while (true)
|
|
{
|
|
var r = await OverlayDialog.ShowModal<UserCreateDialogView, UserCreateDialogViewModel>(result, AppDefaultValues.HostId, opt);
|
|
if (r == DialogResult.No) return;
|
|
if (result.Validate()) break;
|
|
|
|
UIHelper.NotifyError("Please check your input");
|
|
}
|
|
|
|
try
|
|
{
|
|
await Api.C.Gateway.Register(new RegisterRequest()
|
|
{
|
|
Username = result.Username,
|
|
Password = result.Password,
|
|
Email = result.Email
|
|
});
|
|
|
|
Users.Add(UserService.C.GetUserInfoAsync(result.Username)!);
|
|
UIHelper.NotifySuccess($"User {result.Username} create successfully");
|
|
}
|
|
catch (ApiException ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task DeleteUserAsync(string username)
|
|
{
|
|
if (await UIHelper.SimpleAskAsync($"Do you sure that wanted to delete user '{username}' permanently?") == DialogResult.Yes)
|
|
{
|
|
try
|
|
{
|
|
await Api.C.Gateway.Delete(username);
|
|
Users.Remove(Users.First(u => u.Username == username));
|
|
UIHelper.NotifySuccess("User deleted");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task ForceUpdateUserPasswordAsync(string username)
|
|
{
|
|
var newPassword = GenerateRandomPassword();
|
|
try
|
|
{
|
|
await Api.C.Gateway.RenewPassword(new ResetPasswordRequest
|
|
{
|
|
Identity = username,
|
|
NewPassword = newPassword
|
|
});
|
|
await UIHelper.SimpleAlert($"Password has been reset to {newPassword}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task ActivateUserAsync(string username)
|
|
{
|
|
await UpdateUserActivateAsync(username, true);
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task InactivateUserAsync(string username)
|
|
{
|
|
await UpdateUserActivateAsync(username, false);
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task PromoteUserAsync(string username)
|
|
{
|
|
await UpdateUserSuperAsync(username, true);
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task DemoteUserAsync(string username)
|
|
{
|
|
await UpdateUserSuperAsync(username, false);
|
|
}
|
|
|
|
[ReactiveCommand]
|
|
private async Task DownloadServerLogAsync()
|
|
{
|
|
try
|
|
{
|
|
var logs = await Api.C.Gateway.Logs(
|
|
LogSearchFrom, LogSearchTo, (LogLevel?)Loglevel, Page, PageSize);
|
|
|
|
Logs.AddRange(logs.Select(Log.From));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
|
|
private async Task UpdateUserActivateAsync(string username, bool active)
|
|
{
|
|
try
|
|
{
|
|
if (active) await Api.C.Gateway.Enable(username);
|
|
else await Api.C.Gateway.Disable(username);
|
|
|
|
UIHelper.NotifySuccess($"{username} has already {(active ? "enabled" : "disabled")}.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
|
|
private async Task UpdateUserSuperAsync(string username, bool active)
|
|
{
|
|
try
|
|
{
|
|
await Api.C.Gateway.SuperuserPost(username, active);
|
|
Users.First(x => x.Username == username).IsAdmin = active;
|
|
UIHelper.NotifySuccess($"{username} has already {(active ? "enabled" : "disabled")}.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UIHelper.NotifyError(ex);
|
|
}
|
|
}
|
|
|
|
private static string GenerateRandomPassword(int length = 12)
|
|
{
|
|
const string validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*";
|
|
var random = new Random();
|
|
return new string(Enumerable.Repeat(validChars, length)
|
|
.Select(s => s[random.Next(s.Length)]).ToArray());
|
|
}
|
|
} |