diff --git a/Flawless.Client/Service/Remote_Generated.cs b/Flawless.Client/Service/Remote_Generated.cs
index aa919c6..416693a 100644
--- a/Flawless.Client/Service/Remote_Generated.cs
+++ b/Flawless.Client/Service/Remote_Generated.cs
@@ -18,6 +18,12 @@ namespace Flawless.Client.Remote
[System.CodeDom.Compiler.GeneratedCode("Refitter", "1.5.5.0")]
public partial interface IFlawlessServer
{
+ /// A that completes when the request is finished.
+ /// Thrown when the request returns a non-success status code.
+ [Headers("Content-Type: application/json")]
+ [Post("/api/admin/add_user")]
+ Task AddUser([Body] RegisterRequest body, CancellationToken cancellationToken = default);
+
/// A that completes when the request is finished.
/// Thrown when the request returns a non-success status code.
[Post("/api/admin/superuser/{username}")]
diff --git a/Flawless.Client/ViewModels/SettingViewModel.cs b/Flawless.Client/ViewModels/SettingViewModel.cs
index cd83c2c..706659f 100644
--- a/Flawless.Client/ViewModels/SettingViewModel.cs
+++ b/Flawless.Client/ViewModels/SettingViewModel.cs
@@ -2,18 +2,14 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
-using System.Net;
-using System.Reactive.Linq;
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 LiveChartsCore;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using Refit;
@@ -49,9 +45,9 @@ public partial class SettingViewModel : RoutableViewModelBase
[Reactive] private string _bio;
- [Reactive] private DateTime?
- _logSearchFrom = null,
- _logSearchTo = null;
+ [Reactive] private DateTime
+ _logSearchFrom = DateTime.Now.AddDays(-1),
+ _logSearchTo = DateTime.Now;
[Reactive] private int _page = 1;
@@ -72,10 +68,10 @@ public partial class SettingViewModel : RoutableViewModelBase
{
using (UIHelper.MakeLoading("Fetch server data..."))
{
- await RefreshUsersCommand.Execute();
+ await RefreshUsersAsync();
var sb = new StringBuilder();
- ServerBlacklist = sb.AppendJoin(",\n", await Api.C.Gateway.IpWhitelistGet()).ToString();
+ ServerWhitelist = sb.AppendJoin(",\n", await Api.C.Gateway.IpWhitelistGet()).ToString();
ServerBlacklist = sb.Clear().AppendJoin(",\n", await Api.C.Gateway.IpBlacklistGet()).ToString();
}
}
@@ -244,7 +240,8 @@ public partial class SettingViewModel : RoutableViewModelBase
Username = user.Username,
Email = user.Email,
IsActive = user.IsActive,
- IsAdmin = user.IsAdmin ?? false
+ IsAdmin = user.IsAdmin ?? false,
+ CanEdit = user.Username != Api.C.Username.Value!
});
}
}
@@ -257,9 +254,12 @@ public partial class SettingViewModel : RoutableViewModelBase
[ReactiveCommand]
private async Task CreateUserAsync()
{
- var result = new UserCreateDialogViewModel();
- result.Password = GenerateRandomPassword();
var opt = UIHelper.DefaultOverlayDialogOptionsYesNo();
+ var result = new UserCreateDialogViewModel
+ {
+ Password = GenerateRandomPassword()
+ };
+
while (true)
{
var r = await OverlayDialog.ShowModal(result, AppDefaultValues.HostId, opt);
@@ -271,14 +271,14 @@ public partial class SettingViewModel : RoutableViewModelBase
try
{
- await Api.C.Gateway.Register(new RegisterRequest
+ await Api.C.Gateway.AddUser(new RegisterRequest
{
Username = result.Username,
Password = result.Password,
Email = result.Email
});
-
- Users.Add(UserService.C.GetUserInfoAsync(result.Username)!);
+
+ await this.RefreshUsersAsync();
UIHelper.NotifySuccess($"User {result.Username} create successfully");
}
catch (ApiException ex)
@@ -311,11 +311,12 @@ public partial class SettingViewModel : RoutableViewModelBase
var newPassword = GenerateRandomPassword();
try
{
- await Api.C.Gateway.RenewPassword(new ResetPasswordRequest
+ await Api.C.Gateway.ResetPassword(new ResetPasswordRequest
{
Identity = username,
NewPassword = newPassword
});
+
await UIHelper.SimpleAlert($"Password has been reset to {newPassword}");
}
catch (Exception ex)
@@ -386,7 +387,7 @@ public partial class SettingViewModel : RoutableViewModelBase
{
await Api.C.Gateway.SuperuserPost(username, active);
Users.First(x => x.Username == username).IsAdmin = active;
- UIHelper.NotifySuccess($"{username} has already {(active ? "enabled" : "disabled")}.");
+ UIHelper.NotifySuccess($"{username} has already set to {(active ? "superuser" : "nornmal user")}.");
}
catch (Exception ex)
{
diff --git a/Flawless.Client/Views/HomeView.axaml b/Flawless.Client/Views/HomeView.axaml
index b524eef..7cd9bff 100644
--- a/Flawless.Client/Views/HomeView.axaml
+++ b/Flawless.Client/Views/HomeView.axaml
@@ -12,7 +12,7 @@
-
+
diff --git a/Flawless.Client/Views/ModalBox/IssueDetailEditView.axaml b/Flawless.Client/Views/ModalBox/IssueDetailEditView.axaml
index 2a09a5b..f28cbb3 100644
--- a/Flawless.Client/Views/ModalBox/IssueDetailEditView.axaml
+++ b/Flawless.Client/Views/ModalBox/IssueDetailEditView.axaml
@@ -6,7 +6,7 @@
xmlns:vm="clr-namespace:Flawless.Client.ViewModels.ModalBox"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:DataType="vm:IssueEditDialogViewModel"
- MinWidth="400"
+ MinWidth="500"
x:Class="Flawless.Client.Views.ModalBox.IssueDetailEditView">
diff --git a/Flawless.Client/Views/ModalBox/UserCreateDialogView.axaml b/Flawless.Client/Views/ModalBox/UserCreateDialogView.axaml
index 499ef1b..4d421ab 100644
--- a/Flawless.Client/Views/ModalBox/UserCreateDialogView.axaml
+++ b/Flawless.Client/Views/ModalBox/UserCreateDialogView.axaml
@@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Flawless.Client.ViewModels.ModalBox"
x:Class="Flawless.Client.Views.ModalBox.UserCreateDialogView"
+ MinWidth="400"
x:DataType="vm:UserCreateDialogViewModel">
diff --git a/Flawless.Client/Views/SettingView.axaml b/Flawless.Client/Views/SettingView.axaml
index 9f59d30..1fc626e 100644
--- a/Flawless.Client/Views/SettingView.axaml
+++ b/Flawless.Client/Views/SettingView.axaml
@@ -39,19 +39,10 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
@@ -92,36 +83,28 @@
Command="{Binding CreateUserCommand}"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
+
@@ -129,39 +112,35 @@
Command="{Binding $parent[views:SettingView].((vm:SettingViewModel)DataContext).DemoteUserCommand}"
CommandParameter="{Binding Username}"
IsVisible="{Binding IsAdmin}"
- IsEnabled="{Binding !CanEdit}"
Classes="Danger"/>
+ CommandParameter="{Binding Username}"/>
-
-
-
-
-
-
+
+
+
+
-
+
+
-
-
-
+
+
+
diff --git a/Flawless.Server/Controllers/AdminController.cs b/Flawless.Server/Controllers/AdminController.cs
index bf396f0..d8cc4dc 100644
--- a/Flawless.Server/Controllers/AdminController.cs
+++ b/Flawless.Server/Controllers/AdminController.cs
@@ -13,6 +13,7 @@ namespace Flawless.Server.Controllers;
public class AdminController(
UserManager userManager,
AccessControlService accessControlService,
+ ILogger logger,
AppDbContext dbContext) : ControllerBase
{
@@ -23,6 +24,29 @@ public class AdminController(
return null;
}
+ [HttpPost("add_user")]
+ public async Task AddUserAsync(RegisterRequest request)
+ {
+ var user = new AppUser
+ {
+ UserName = request.Username,
+ Email = request.Email,
+ EmailConfirmed = true,
+ CreatedOn = DateTime.UtcNow,
+ };
+
+ user.RenewSecurityStamp();
+ var result = await userManager.CreateAsync(user, request.Password);
+ if (result.Succeeded)
+ {
+ logger.LogInformation("User '{0}' created (SUPERUSER REGISTER)", user.UserName);
+ return Ok();
+ }
+
+ logger.LogInformation("User '{0}' NOT created (SUPERUSER REGISTER) : {1}", user.UserName, result.Errors);
+ return BadRequest(new FailedResponse(result.Errors));
+ }
+
[HttpPost("superuser/{username}")]
public async Task SetSuperuserAsync(string username, bool toSuper)
{
@@ -59,7 +83,7 @@ public class AdminController(
var t = await TestIfValid();
if (t != null) return t;
- return await userManager.Users.Select(x => new UserInfoResponse
+ var r = await userManager.Users.Select(x => new UserInfoResponse
{
Authorized = true,
Username = x.UserName,
@@ -71,8 +95,10 @@ public class AdminController(
Email = x.Email,
Phone = x.PhoneNumber,
IsAdmin = x.Admin,
- IsActive = x.LockoutEnabled
+ IsActive = !x.LockoutEnabled
}).ToArrayAsync();
+
+ return r;
}
[HttpPost("user/delete/{username}")]
@@ -93,6 +119,9 @@ public class AdminController(
[HttpPost("user/enable/{username}")]
public async Task EnableUserAsync(string username)
{
+ var t = await TestIfValid();
+ if (t != null) return t;
+
var user = await userManager.FindByNameAsync(username);
if (user == null) return BadRequest(new FailedResponse("User does not exist!"));
@@ -124,11 +153,10 @@ public class AdminController(
if (t != null) return t;
if (r.Identity == null) return BadRequest(new FailedResponse("Identity (User Id) is not set!"));
- var user = await userManager.FindByIdAsync(r.Identity);
+ var user = await userManager.FindByNameAsync(r.Identity);
if (user == null) return BadRequest(new FailedResponse("Identity (User Id) does not exist!"));
- var resetToken = await userManager.GeneratePasswordResetTokenAsync(user);
- var result = await userManager.ResetPasswordAsync(user, resetToken, r.NewPassword);
+ var result = await userManager.ResetPasswordAsync(user, "", r.NewPassword);
if (!result.Succeeded) return BadRequest(new FailedResponse(result.Errors));
return Ok();
@@ -174,26 +202,18 @@ public class AdminController(
[HttpGet("logs")]
public async Task>> GetSystemLogsAsync(
- [FromQuery] DateTime? startTime = null,
- [FromQuery] DateTime? endTime = null,
- [FromQuery] LogLevel? level = null,
- [FromQuery] int page = 1,
- [FromQuery] int pageSize = 50)
+ [FromQuery] DateTime startTime,
+ [FromQuery] DateTime endTime,
+ [FromQuery] LogLevel level,
+ [FromQuery] int page,
+ [FromQuery] int pageSize)
{
var t = await TestIfValid();
if (t != null) return t;
- var query = dbContext.SystemLogs.AsQueryable();
-
- // 时间过滤
- if (startTime.HasValue)
- query = query.Where(l => l.Timestamp >= startTime);
- if (endTime.HasValue)
- query = query.Where(l => l.Timestamp <= endTime);
-
- // 日志级别过滤
- if (level.HasValue && level.Value != LogLevel.None)
- query = query.Where(l => l.LogLevel == level.Value);
+ var query = dbContext.SystemLogs.Where(x =>
+ x.Timestamp >= startTime && x.Timestamp <= endTime && x.LogLevel >= level
+ ).AsQueryable();
// 分页处理
var totalCount = await query.CountAsync();
diff --git a/Flawless.Server/appsettings.Development.json b/Flawless.Server/appsettings.Development.json
index 681f633..831374f 100644
--- a/Flawless.Server/appsettings.Development.json
+++ b/Flawless.Server/appsettings.Development.json
@@ -10,9 +10,9 @@
"CoreDb": "Server=localhost;Port=5432;User Id=postgres;Database=flawless"
},
"LocalStoragePath": "/Users/cardidi/flawless-data",
- "User": {
- "PublicRegister": true
- },
+ "UseWebHook": true,
+ "AllowPublicRegistration": true,
+ "ServerName": "Cardidi Private Area",
"Jwt": {
"SecretKey": "your_256bit_security_key_at_here_otherwise_not_bootable",
"Issuer": "test",
diff --git a/Flawless.Server/appsettings.json b/Flawless.Server/appsettings.json
index 681f633..831374f 100644
--- a/Flawless.Server/appsettings.json
+++ b/Flawless.Server/appsettings.json
@@ -10,9 +10,9 @@
"CoreDb": "Server=localhost;Port=5432;User Id=postgres;Database=flawless"
},
"LocalStoragePath": "/Users/cardidi/flawless-data",
- "User": {
- "PublicRegister": true
- },
+ "UseWebHook": true,
+ "AllowPublicRegistration": true,
+ "ServerName": "Cardidi Private Area",
"Jwt": {
"SecretKey": "your_256bit_security_key_at_here_otherwise_not_bootable",
"Issuer": "test",