diff --git a/PCUT/Http.Core/Constants/HttpConstants.cs b/PCUT/Http.Core/Constants/HttpConstants.cs
index da39201..27d3925 100644
--- a/PCUT/Http.Core/Constants/HttpConstants.cs
+++ b/PCUT/Http.Core/Constants/HttpConstants.cs
@@ -40,6 +40,7 @@
public const string Metadata = "api/metadata";
public const string MetadataById = "api/metadata/{0}";
+ public const string Log = "api/logs";
}
}
}
diff --git a/PCUT/Http.Core/Handlers/AuthenticationHandler.cs b/PCUT/Http.Core/Handlers/AuthenticationHandler.cs
index e065fad..6dbd947 100644
--- a/PCUT/Http.Core/Handlers/AuthenticationHandler.cs
+++ b/PCUT/Http.Core/Handlers/AuthenticationHandler.cs
@@ -1,7 +1,6 @@
using Http.Core.Constants;
using Http.Core.Contexts;
using Http.Core.Extensions;
-using Http.Core.Models;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
@@ -31,13 +30,13 @@ namespace Http.Core.Handlers
return false;
var expiredTime = UserContext.Instance.ExpiredTime;
- if (expiredTime != null || expiredTime - DateTime.UtcNow < _requiredRefreshTime)
+ if (expiredTime != null && expiredTime - DateTime.UtcNow < _requiredRefreshTime)
{
await _refreshSemaphore.WaitAsync();
bool refreshSuccess;
{
expiredTime = UserContext.Instance.ExpiredTime;
- if (expiredTime != null || expiredTime - DateTime.UtcNow < _requiredRefreshTime)
+ if (expiredTime != null && expiredTime - DateTime.UtcNow < _requiredRefreshTime)
refreshSuccess = await RefreshTokenAsync();
else
refreshSuccess = true; // Some other thread already refreshed token
diff --git a/PCUT/PCUT.Entities/Log.cs b/PCUT/PCUT.Entities/Log.cs
new file mode 100644
index 0000000..b0446ac
--- /dev/null
+++ b/PCUT/PCUT.Entities/Log.cs
@@ -0,0 +1,13 @@
+using Newtonsoft.Json;
+using System;
+
+namespace PCUT.Entities
+{
+ public class Log
+ {
+ [JsonProperty("datetime")]
+ public DateTime Timestamp { get; set; }
+ [JsonProperty("content")]
+ public string Content { get; set; }
+ }
+}
diff --git a/PCUT/PCUT/Converters/LogTimestampConverter.cs b/PCUT/PCUT/Converters/LogTimestampConverter.cs
new file mode 100644
index 0000000..ae32870
--- /dev/null
+++ b/PCUT/PCUT/Converters/LogTimestampConverter.cs
@@ -0,0 +1,26 @@
+using System;
+using Windows.UI.Xaml.Data;
+
+namespace PCUT.Converters
+{
+ internal class LogTimestampConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, string language)
+ {
+ switch (value)
+ {
+ case DateTime timeValue:
+ {
+ return $"[{timeValue.ToString("yyyy-MM-dd HH:mm:ss.fff K")}]";
+ }
+ default:
+ return string.Empty;
+ }
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/PCUT/PCUT/PCUT.csproj b/PCUT/PCUT/PCUT.csproj
index fb7e32a..b554cb5 100644
--- a/PCUT/PCUT/PCUT.csproj
+++ b/PCUT/PCUT/PCUT.csproj
@@ -137,6 +137,7 @@
+
@@ -194,6 +195,9 @@
CategoriesViewPage.xaml
+
+ LogInformationPage.xaml
+
UserGuidePage.xaml
@@ -243,6 +247,7 @@
UserListPage.xaml
+
@@ -361,6 +366,10 @@
Designer
MSBuild:Compile
+
+ MSBuild:Compile
+ Designer
+
MSBuild:Compile
Designer
diff --git a/PCUT/PCUT/Pages/AdminCenterPage.xaml b/PCUT/PCUT/Pages/AdminCenterPage.xaml
index 55ea1c2..7fa2abf 100644
--- a/PCUT/PCUT/Pages/AdminCenterPage.xaml
+++ b/PCUT/PCUT/Pages/AdminCenterPage.xaml
@@ -29,6 +29,7 @@
+
diff --git a/PCUT/PCUT/Pages/AdminCenterPage.xaml.cs b/PCUT/PCUT/Pages/AdminCenterPage.xaml.cs
index 5318e06..0e7c6c2 100644
--- a/PCUT/PCUT/Pages/AdminCenterPage.xaml.cs
+++ b/PCUT/PCUT/Pages/AdminCenterPage.xaml.cs
@@ -53,6 +53,9 @@ namespace PCUT.Pages
case "Users":
ContentFrame.Navigate(typeof(UserListPage));
break;
+ case "Logs":
+ ContentFrame.Navigate(typeof(LogInformationPage));
+ break;
}
sender.IsPaneOpen = true;
}
diff --git a/PCUT/PCUT/Pages/Logs/LogInformationPage.xaml b/PCUT/PCUT/Pages/Logs/LogInformationPage.xaml
new file mode 100644
index 0000000..88d8273
--- /dev/null
+++ b/PCUT/PCUT/Pages/Logs/LogInformationPage.xaml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PCUT/PCUT/Pages/Logs/LogInformationPage.xaml.cs b/PCUT/PCUT/Pages/Logs/LogInformationPage.xaml.cs
new file mode 100644
index 0000000..7a87a4a
--- /dev/null
+++ b/PCUT/PCUT/Pages/Logs/LogInformationPage.xaml.cs
@@ -0,0 +1,52 @@
+using PCUT.ViewModels;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Navigation;
+
+// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
+
+namespace PCUT.Pages
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class LogInformationPage : Page
+ {
+ public LogViewModel ViewModels { get; set; }
+ public LogInformationPage()
+ {
+ this.InitializeComponent();
+ ViewModels = DataContext as LogViewModel;
+ }
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ ViewModels.Pagination.Page = 1;
+ }
+
+ protected override void OnNavigatedFrom(NavigationEventArgs e)
+ {
+ ViewModels.Pagination.Dispose();
+ }
+
+ private void btnFirst_Click(object sender, RoutedEventArgs e)
+ {
+ ViewModels.Pagination.Page = 1;
+ }
+
+ private void btnLast_Click(object sender, RoutedEventArgs e)
+ {
+ ViewModels.Pagination.Page = ViewModels.Pagination.TotalPage;
+ }
+
+ private void btnPrevious_Click(object sender, RoutedEventArgs e)
+ {
+ ViewModels.Pagination.Page--;
+ }
+
+ private void btnNext_Click(object sender, RoutedEventArgs e)
+ {
+ ViewModels.Pagination.Page++;
+ }
+ }
+}
diff --git a/PCUT/PCUT/ViewModels/LogViewModel.cs b/PCUT/PCUT/ViewModels/LogViewModel.cs
new file mode 100644
index 0000000..5cfc312
--- /dev/null
+++ b/PCUT/PCUT/ViewModels/LogViewModel.cs
@@ -0,0 +1,72 @@
+using Http.Core;
+using Http.Core.Extensions;
+using PCUT.Entities;
+using PCUT.Entities.ApiResponse;
+using PCUT.Models;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+using static Http.Core.Constants.HttpConstants;
+
+namespace PCUT.ViewModels
+{
+ public class LogViewModel : NotificationBase
+ {
+ public PaginationViewModel Pagination { get; } = new PaginationViewModel(withSearch: false);
+ public ObservableCollection Logs { get; }
+
+ public LogViewModel()
+ {
+ Logs = new ObservableCollection();
+
+ Pagination.PageChanged += OnPageChanged;
+ }
+
+ private async void OnPageChanged(object sender, PageChangedEventArgs args)
+ {
+ await LoadLogsAsync(args.Page, args.PageSize);
+ }
+
+ public async Task LoadLogsAsync(int page, int pageSize)
+ {
+ var url = CreateFilterUrl(page, pageSize);
+ using (var httpClient = HttpClientFactory.CreateClient(ClientNames.ApiClient))
+ {
+ try
+ {
+ var response = await httpClient.GetAsync(url);
+ if (response.IsSuccessStatusCode)
+ {
+ var apiResponse = await response.DeserializeObjectAsync>>();
+ var data = apiResponse.Data;
+ Pagination.Page = apiResponse.Pagination.Page;
+ Pagination.TotalPage = apiResponse.Pagination.TotalPages;
+ Pagination.TotalRecords = apiResponse.Pagination.TotalRecords;
+
+ Logs.Clear();
+ foreach (var log in data)
+ Logs.Add(log);
+ }
+ }
+ catch (Exception ex)
+ {
+
+ }
+ }
+ }
+
+ private string CreateFilterUrl(int page, int pageSize/*, string searchText*/)
+ {
+ var builder = PathBuilder.FromRouteTemplate(Api.Log)
+ .AddQuery("page", page.ToString())
+ .AddQuery("pageSize", pageSize.ToString());
+ //if (!string.IsNullOrEmpty(searchText))
+ //{
+ // var filter = new StringBuilder().AppendFilter("username", "cn", searchText).BuildFilter().ToString();
+ // builder.AddQuery("filter", filter);
+ //}
+ return builder.Build();
+ }
+ }
+}