Compare commits
2 Commits
1a48cd1712
...
3afafd4e91
| Author | SHA1 | Date | |
|---|---|---|---|
| 3afafd4e91 | |||
| b21dae1192 |
@ -18,6 +18,12 @@ namespace Flawless.Client.Remote
|
||||
[System.CodeDom.Compiler.GeneratedCode("Refitter", "1.5.5.0")]
|
||||
public partial interface IFlawlessServer
|
||||
{
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Content-Type: application/json")]
|
||||
[Post("/api/admin/add_user")]
|
||||
Task AddUser([Body] RegisterRequest body, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Post("/api/admin/superuser/{username}")]
|
||||
@ -243,7 +249,7 @@ namespace Flawless.Client.Remote
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
[Headers("Accept: text/plain, application/json, text/json")]
|
||||
[Post("/api/repo/{userName}/{repositoryName}/fetch_depot")]
|
||||
Task<ApiResponse<Stream>> FetchDepot(string userName, string repositoryName, [Query] string depotId);
|
||||
Task<ApiResponse<Stream>> FetchDepot(string userName, string repositoryName, [Query] string depotId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <returns>OK</returns>
|
||||
/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>
|
||||
|
||||
@ -275,11 +275,11 @@ public partial class RepositoryViewModel : RoutableViewModelBase
|
||||
|
||||
private async Task StartupTasksAsync()
|
||||
{
|
||||
await RefreshRepositoryRoleInfoAsyncCommand.Execute();
|
||||
await RefreshRepositoryIssuesAsyncCommand.Execute();
|
||||
await RefreshStatisticDataCommand.Execute();
|
||||
await RefreshWebhooksCommand.Execute();
|
||||
await DetectLocalChangesAsyncCommand.Execute();
|
||||
await RefreshRepositoryRoleInfoAsync();
|
||||
await RefreshRepositoryIssuesAsync();
|
||||
await RefreshStatisticDataAsync();
|
||||
await RefreshWebhooksAsync();
|
||||
await DetectLocalChangesAsync();
|
||||
await RendererFileTreeAsync();
|
||||
SyncCommitsFromRepository();
|
||||
}
|
||||
@ -659,6 +659,8 @@ public partial class RepositoryViewModel : RoutableViewModelBase
|
||||
[ReactiveCommand]
|
||||
private async ValueTask RefreshRepositoryIssuesAsync()
|
||||
{
|
||||
if (!IsReporterRole) return;
|
||||
|
||||
using var l = UIHelper.MakeLoading("Refreshing issues...");
|
||||
await RepositoryService.C.UpdateIssuesListFromServerAsync(Repository);
|
||||
}
|
||||
@ -756,6 +758,8 @@ public partial class RepositoryViewModel : RoutableViewModelBase
|
||||
[ReactiveCommand]
|
||||
private async ValueTask DetectLocalChangesAsync()
|
||||
{
|
||||
if (!IsDeveloperRole) return;
|
||||
|
||||
using var l = UIHelper.MakeLoading("Refreshing local changes...");
|
||||
var ns = await Task.Run(async () =>
|
||||
{
|
||||
@ -773,7 +777,16 @@ public partial class RepositoryViewModel : RoutableViewModelBase
|
||||
foreach (var n in LocalChangeSetRaw)
|
||||
n.Included = true;
|
||||
}
|
||||
|
||||
|
||||
[ReactiveCommand]
|
||||
private void OpenFolder()
|
||||
{
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo() {
|
||||
FileName = PathUtility.GetWorkspacePath(Api.C.Username.Value!, Repository.OwnerName, Repository.Name),
|
||||
UseShellExecute = true,
|
||||
Verb = "open"
|
||||
});
|
||||
}
|
||||
|
||||
[ReactiveCommand]
|
||||
private void DeselectAllChanges()
|
||||
@ -783,8 +796,10 @@ public partial class RepositoryViewModel : RoutableViewModelBase
|
||||
}
|
||||
|
||||
[ReactiveCommand]
|
||||
private async Task RefreshStatisticData()
|
||||
private async Task RefreshStatisticDataAsync()
|
||||
{
|
||||
if (!IsOwnerRole) return;
|
||||
|
||||
try
|
||||
{
|
||||
var api = Api.C;
|
||||
@ -800,13 +815,12 @@ public partial class RepositoryViewModel : RoutableViewModelBase
|
||||
foreach (var dp in rsp.Depots)
|
||||
DepotsStats.Add(new DepotStatsInfo{ Id = dp.DepotName, Size = dp.DepotSize});
|
||||
|
||||
ByDay = new[]
|
||||
{
|
||||
ByDay = [
|
||||
new ColumnSeries<DateTimePoint>
|
||||
{
|
||||
Values = rsp.CommitByDay.Select(k => new DateTimePoint(k.Day.LocalDateTime, k.Count)).ToList(),
|
||||
}
|
||||
};
|
||||
];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@ -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<UserCreateDialogView, UserCreateDialogViewModel>(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)
|
||||
{
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<DockPanel Margin="50">
|
||||
<Grid RowDefinitions="Auto, 18, Auto" ColumnDefinitions="*, Auto" DockPanel.Dock="Top">
|
||||
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
|
||||
<Label Content="{Binding ServerFriendlyName, StringFormat='Server {0}', FallbackValue='Server LocalTest'}" FontSize="18" FontWeight="400"></Label>
|
||||
<Label Content="{Binding ServerFriendlyName, FallbackValue='Unknown Server'}" FontSize="18" FontWeight="400"></Label>
|
||||
<Label Content="Repositories" FontSize="32" FontWeight="600"></Label>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
|
||||
@ -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">
|
||||
|
||||
<u:Form HorizontalAlignment="Stretch">
|
||||
|
||||
@ -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">
|
||||
|
||||
<Grid Margin="10" HorizontalAlignment="Stretch" RowDefinitions="Auto,Auto,Auto">
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Flawless.Client.Views.RepositoryPage.RepoCommitPageView">
|
||||
<Grid ColumnDefinitions="2*, *">
|
||||
<TreeDataGrid Grid.Column="0" Source="{Binding Commits}">
|
||||
<TreeDataGrid Grid.Column="0" Source="{Binding Commits, Mode=TwoWay}">
|
||||
<TreeDataGrid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="View File Tree"/>
|
||||
<!-- <MenuItem Header="View File Tree"/> -->
|
||||
<MenuItem Header="Reset To">
|
||||
<MenuItem Header="Keep" Command="{Binding RevertFileTreeToSelectedCommitKeepCommand}"/>
|
||||
<MenuItem Header="Soft" Command="{Binding RevertFileTreeToSelectedCommitSoftCommand}"/>
|
||||
|
||||
@ -13,8 +13,10 @@
|
||||
<u:IconButton
|
||||
Icon="{StaticResource SemiIconDownload}" Content="Pull" HorizontalAlignment="Stretch"
|
||||
Command="{Binding PullLatestRepositoryCommand}"/>
|
||||
<u:IconButton Icon="{StaticResource SemiIconExternalOpen}" Content="Open Folder"
|
||||
Command="{Binding OpenFolderCommand}"/>
|
||||
</StackPanel>
|
||||
<TreeDataGrid Grid.Row="1" Source="{Binding FileTree}">
|
||||
<TreeDataGrid Grid.Row="1" Source="{Binding FileTree, Mode=TwoWay}">
|
||||
</TreeDataGrid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@ -97,11 +97,11 @@
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
<TabItem Header="Statics" IsVisible="{Binding IsOwnerRole}">
|
||||
<ScrollViewer Width="600" HorizontalAlignment="Stretch">
|
||||
<ScrollViewer Width="600" HorizontalAlignment="Left" Margin="6">
|
||||
<StackPanel Spacing="16" HorizontalAlignment="Stretch">
|
||||
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||
<u:IconButton Content="Refresh" Icon="{StaticResource SemiIconRefresh}"
|
||||
Command="{Binding RefreshWebhooksCommand}"/>
|
||||
Command="{Binding RefreshStatisticDataCommand}"/>
|
||||
</StackPanel>
|
||||
<StackPanel HorizontalAlignment="Stretch" Orientation="Vertical">
|
||||
<Label>Every Day Commits</Label>
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
Command="{Binding SelectAllChangesCommand}"/>
|
||||
<u:IconButton Icon="{StaticResource SemiIconList}" Content="None"
|
||||
Command="{Binding DeselectAllChangesCommand}"/>
|
||||
<!-- <u:IconButton Icon="{StaticResource SemiIconDownload}" Content="Open Folder" -->
|
||||
<!-- Command="{Binding OpenFolderInSystemDefaultExplorerCommand}"/> -->
|
||||
<u:IconButton Icon="{StaticResource SemiIconExternalOpen}" Content="Open Folder"
|
||||
Command="{Binding OpenFolderCommand}"/>
|
||||
</StackPanel>
|
||||
<TreeDataGrid Grid.Row="1" Grid.Column="0" Source="{Binding LocalChange}" CanUserSortColumns="True"/>
|
||||
<Border Grid.Row="1" Grid.Column="2" Classes="Shadow" Theme="{StaticResource CardBorder}">
|
||||
|
||||
@ -39,19 +39,10 @@
|
||||
<TabItem Header="Preference">
|
||||
<ScrollViewer Width="600" HorizontalAlignment="Left" Margin="6">
|
||||
<u:Form HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<u:FormItem Label="Default Storage Location">
|
||||
<u:PathPicker/>
|
||||
</u:FormItem>
|
||||
<!-- <u:FormGroup Header="Workspace Refresh"> -->
|
||||
<!-- <StackPanel Spacing="4"> -->
|
||||
<!-- <CheckBox Theme="{StaticResource CardCheckBox}" Content="Open Workspace" -->
|
||||
<!-- IsChecked="{Binding SettingModel.RefreshWorkspaceOnOpen}"/> -->
|
||||
<!-- <CheckBox Theme="{StaticResource CardCheckBox}" Content="Filesystem Changed" -->
|
||||
<!-- IsChecked="{Binding SettingModel.RefreshWorkspaceOnFilesystemChanges}"/> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- </u:FormGroup> -->
|
||||
<!-- <u:FormItem Label="Default Storage Location"> -->
|
||||
<!-- <u:PathPicker/> -->
|
||||
<!-- </u:FormItem> -->
|
||||
<u:FormGroup Header="Extern Tools">
|
||||
<!-- <u:PathPicker u:FormItem.Label="Open Folder"/> -->
|
||||
<u:PathPicker u:FormItem.Label="Diff Tool"/>
|
||||
</u:FormGroup>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
@ -92,36 +83,28 @@
|
||||
Command="{Binding CreateUserCommand}"/>
|
||||
</StackPanel>
|
||||
|
||||
<DataGrid Grid.Row="1" ItemsSource="{Binding Users, Mode=TwoWay}" AutoGenerateColumns="False">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Username" Binding="{Binding Username}" Width="*"/>
|
||||
|
||||
<DataGridTextColumn Header="CreateAt" Binding="{Binding JoinDate}" Width="*"/>
|
||||
|
||||
<DataGridCheckBoxColumn Header="Active" Binding="{Binding IsActive}" Width="Auto"/>
|
||||
|
||||
<DataGridCheckBoxColumn Header="Admin" Binding="{Binding IsAdmin}" Width="Auto"/>
|
||||
|
||||
<DataGridTemplateColumn Header="Operations" Width="2*">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<ListBox Grid.Row="1" ItemsSource="{Binding Users, Mode=TwoWay}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Vertical" Spacing="12" Margin="6">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" VerticalAlignment="Center">
|
||||
<PathIcon Data="{StaticResource SemiIconCrown}" Height="12" Width="12" IsVisible="{Binding IsAdmin}"/>
|
||||
<PathIcon Data="{StaticResource SemiIconMinusCircle}" Height="12" Width="12" IsVisible="{Binding !IsActive}"/>
|
||||
<Label Content="{Binding Username}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="6" VerticalAlignment="Center" IsEnabled="{Binding CanEdit}">
|
||||
<Button Content="Enable"
|
||||
Command="{Binding $parent[views:SettingView].((vm:SettingViewModel)DataContext).InactivateUserCommand}"
|
||||
CommandParameter="{Binding Username}"
|
||||
IsEnabled="{Binding !CanEdit}"
|
||||
IsVisible="{Binding IsActive}"/>
|
||||
|
||||
<Button Content="Disable"
|
||||
Command="{Binding $parent[views:SettingView].((vm:SettingViewModel)DataContext).ActivateUserCommand}"
|
||||
CommandParameter="{Binding Username}"
|
||||
IsEnabled="{Binding !CanEdit}"
|
||||
IsVisible="{Binding !IsActive}"/>
|
||||
<Button Content="Disable"
|
||||
Command="{Binding $parent[views:SettingView].((vm:SettingViewModel)DataContext).InactivateUserCommand}"
|
||||
CommandParameter="{Binding Username}"
|
||||
IsVisible="{Binding IsActive}"/>
|
||||
|
||||
<Button Content="Promote"
|
||||
Command="{Binding $parent[views:SettingView].((vm:SettingViewModel)DataContext).PromoteUserCommand}"
|
||||
CommandParameter="{Binding Username}"
|
||||
IsEnabled="{Binding !CanEdit}"
|
||||
IsVisible="{Binding !IsAdmin}"
|
||||
Classes="Danger"/>
|
||||
|
||||
@ -129,39 +112,35 @@
|
||||
Command="{Binding $parent[views:SettingView].((vm:SettingViewModel)DataContext).DemoteUserCommand}"
|
||||
CommandParameter="{Binding Username}"
|
||||
IsVisible="{Binding IsAdmin}"
|
||||
IsEnabled="{Binding !CanEdit}"
|
||||
Classes="Danger"/>
|
||||
|
||||
<Button Content="Delete"
|
||||
Command="{Binding $parent[views:SettingView].((vm:SettingViewModel)DataContext).DeleteUserCommand}"
|
||||
CommandParameter="{Binding Username}"
|
||||
IsEnabled="{Binding !CanEdit}"
|
||||
Classes="Danger"/>
|
||||
|
||||
<Button Content="Reset Password"
|
||||
Command="{Binding $parent[views:SettingView].((vm:SettingViewModel)DataContext).ForceUpdateUserPasswordCommand}"
|
||||
CommandParameter="{Binding Username}"
|
||||
IsEnabled="{Binding !CanEdit}"/>
|
||||
CommandParameter="{Binding Username}"/>
|
||||
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem IsVisible="{Binding LoginUser.IsAdmin}" Header="Logfile">
|
||||
<StackPanel Spacing="8" Orientation="Vertical" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Spacing="4">
|
||||
<DatePicker SelectedDate="{Binding LogSearchFrom}"/>
|
||||
<Label Content=" → "/>
|
||||
<DatePicker SelectedDate="{Binding LogSearchTo}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<u:EnumSelector SelectedValue="{Binding Loglevel}"/>
|
||||
<NumericUpDown Value="{Binding PageSize}" Minimum="10" Maximum="100"/>
|
||||
<NumericUpDown Value="{Binding Page}" Minimum="1"/>
|
||||
<u:EnumSelector SelectedValue="{Binding Loglevel, Mode=TwoWay}"/>
|
||||
<NumericUpDown Value="{Binding PageSize, Mode=TwoWay}" Minimum="10" Maximum="100"/>
|
||||
<NumericUpDown Value="{Binding Page, Mode=TwoWay}" Minimum="1"/>
|
||||
<u:IconButton Icon="{StaticResource SemiIconSearch}"
|
||||
Command="{Binding DownloadServerLogCommand}"/>
|
||||
</StackPanel>
|
||||
|
||||
@ -13,6 +13,7 @@ namespace Flawless.Server.Controllers;
|
||||
public class AdminController(
|
||||
UserManager<AppUser> userManager,
|
||||
AccessControlService accessControlService,
|
||||
ILogger<AdminController> logger,
|
||||
AppDbContext dbContext) : ControllerBase
|
||||
{
|
||||
|
||||
@ -23,6 +24,29 @@ public class AdminController(
|
||||
return null;
|
||||
}
|
||||
|
||||
[HttpPost("add_user")]
|
||||
public async Task<IActionResult> 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<IActionResult> 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<IActionResult> 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<ActionResult<IEnumerable<LogEntryResponse>>> 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();
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user