diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor
index e1eabc2c..76002925 100644
--- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor
+++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor
@@ -159,22 +159,41 @@ else
|
|
- @context.FromDisplayName |
- @context.Subject |
- @string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn) |
+
+ @if (context.IsRead)
+ {
+ @context.FromDisplayName |
+ @context.Subject |
+ @string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn) |
+ }
+ else
+ {
+ @context.FromDisplayName |
+ @context.Subject |
+ @string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn) |
+ }
|
@{
- string input = "___";
- if (context.Body.Contains(input))
- {
- context.Body = context.Body.Split(input)[0];
- context.Body = context.Body.Replace("\n", "");
- context.Body = context.Body.Replace("\r", "");
- } }
- @(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body)
+ string input = "___";
+ if (context.Body.Contains(input))
+ {
+ context.Body = context.Body.Split(input)[0];
+ context.Body = context.Body.Replace("\n", "");
+ context.Body = context.Body.Replace("\r", "");
+ }
+ notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
+ }
+ @if (context.IsRead)
+ {
+ @notificationSummary
+ }
+ else
+ {
+ @notificationSummary
+ }
|
@@ -192,22 +211,42 @@ else
|
|
- @context.ToDisplayName |
- @context.Subject |
- @string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn) |
+
+ @if (context.IsRead)
+ {
+ @context.ToDisplayName |
+ @context.Subject |
+ @string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn) |
+ }
+ else
+ {
+ @context.ToDisplayName |
+ @context.Subject |
+ @string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn) |
+ }
+
|
@{
- string input = "___";
- if (context.Body.Contains(input))
- {
- context.Body = context.Body.Split(input)[0];
- context.Body = context.Body.Replace("\n", "");
- context.Body = context.Body.Replace("\r", "");
- } }
- @(context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body)
+ string input = "___";
+ if (context.Body.Contains(input))
+ {
+ context.Body = context.Body.Split(input)[0];
+ context.Body = context.Body.Replace("\n", "");
+ context.Body = context.Body.Replace("\r", "");
+ }
+ notificationSummary = context.Body.Length > 100 ? (context.Body.Substring(0, 97) + "...") : context.Body;
+ }
+ @if (context.IsRead)
+ {
+ @notificationSummary
+ }
+ else
+ {
+ @notificationSummary
+ }
|
@@ -246,6 +285,7 @@ else
private string category = string.Empty;
private string filter = "to";
private List notifications;
+ private string notificationSummary = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
diff --git a/Oqtane.Client/Modules/Admin/UserProfile/View.razor b/Oqtane.Client/Modules/Admin/UserProfile/View.razor
index 947a6c7b..58a3d211 100644
--- a/Oqtane.Client/Modules/Admin/UserProfile/View.razor
+++ b/Oqtane.Client/Modules/Admin/UserProfile/View.razor
@@ -118,6 +118,9 @@
Notification notification = await NotificationService.GetNotificationAsync(notificationid);
if (notification != null)
{
+ notification.IsRead = true;
+ notification = await NotificationService.UpdateNotificationAsync(notification);
+
int userid = -1;
if (notification.ToUserId == PageState.User.UserId)
{
diff --git a/Oqtane.Client/Services/Interfaces/INotificationService.cs b/Oqtane.Client/Services/Interfaces/INotificationService.cs
index d1be32a2..a831dd5d 100644
--- a/Oqtane.Client/Services/Interfaces/INotificationService.cs
+++ b/Oqtane.Client/Services/Interfaces/INotificationService.cs
@@ -18,6 +18,27 @@ namespace Oqtane.Services
///
Task> GetNotificationsAsync(int siteId, string direction, int userId);
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task> GetNotificationsAsync(int siteId, string direction, int userId, int count, bool isRead);
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task GetNotificationCountAsync(int siteId, string direction, int userId, bool isRead);
+
///
/// Returns a specific notifications
///
diff --git a/Oqtane.Client/Services/NotificationService.cs b/Oqtane.Client/Services/NotificationService.cs
index 3368ff0b..f6fd1585 100644
--- a/Oqtane.Client/Services/NotificationService.cs
+++ b/Oqtane.Client/Services/NotificationService.cs
@@ -22,6 +22,20 @@ namespace Oqtane.Services
return notifications.OrderByDescending(item => item.CreatedOn).ToList();
}
+ public async Task> GetNotificationsAsync(int siteId, string direction, int userId, int count, bool isRead)
+ {
+ var notifications = await GetJsonAsync>($"{Apiurl}/read?siteid={siteId}&direction={direction.ToLower()}&userid={userId}&count={count}&isread={isRead}");
+
+ return notifications.OrderByDescending(item => item.CreatedOn).ToList();
+ }
+
+ public async Task GetNotificationCountAsync(int siteId, string direction, int userId, bool isRead)
+ {
+ var notificationCount = await GetJsonAsync($"{Apiurl}/read-count?siteid={siteId}&direction={direction.ToLower()}&userid={userId}&isread={isRead}");
+
+ return notificationCount;
+ }
+
public async Task GetNotificationAsync(int notificationId)
{
return await GetJsonAsync($"{Apiurl}/{notificationId}");
diff --git a/Oqtane.Server/Controllers/NotificationController.cs b/Oqtane.Server/Controllers/NotificationController.cs
index dfdba5f1..95621a47 100644
--- a/Oqtane.Server/Controllers/NotificationController.cs
+++ b/Oqtane.Server/Controllers/NotificationController.cs
@@ -9,6 +9,9 @@ using Oqtane.Repository;
using Oqtane.Security;
using System.Net;
using System.Reflection.Metadata;
+using Microsoft.Extensions.Localization;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using System.Linq;
namespace Oqtane.Controllers
{
@@ -30,6 +33,72 @@ namespace Oqtane.Controllers
_alias = tenantManager.GetAlias();
}
+ // GET: api//read?siteid=x&direction=to&userid=1&count=5&isread=false
+ [HttpGet("read")]
+ [Authorize(Roles = RoleNames.Registered)]
+ public IEnumerable Get(string siteid, string direction, string userid, string count, string isread)
+ {
+ IEnumerable notifications = null;
+
+ int SiteId;
+ int UserId;
+ int Count;
+ bool IsRead;
+ if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId && int.TryParse(userid, out UserId) && int.TryParse(count, out Count) && bool.TryParse(isread, out IsRead) && IsAuthorized(UserId))
+ {
+ if (direction == "to")
+ {
+ notifications = _notifications.GetNotifications(SiteId, -1, UserId, Count, IsRead);
+ }
+ else
+ {
+ notifications = _notifications.GetNotifications(SiteId, UserId, -1, Count, IsRead);
+ }
+ }
+ else
+ {
+ _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Get Attempt {SiteId} {Direction} {UserId} {Count} {isRead}", siteid, direction, userid, count, isread);
+ HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
+ notifications = null;
+ }
+
+
+ return notifications;
+ }
+
+ // GET: api//read?siteid=x&direction=to&userid=1&count=5&isread=false
+ [HttpGet("read-count")]
+ [Authorize(Roles = RoleNames.Registered)]
+ public int Get(string siteid, string direction, string userid, string isread)
+ {
+ int notificationsCount = 0;
+
+ int SiteId;
+ int UserId;
+ bool IsRead;
+ if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId && int.TryParse(userid, out UserId) && bool.TryParse(isread, out IsRead) && IsAuthorized(UserId))
+ {
+ if (direction == "to")
+ {
+ notificationsCount = _notifications.GetNotificationCount(SiteId, -1, UserId, IsRead);
+ }
+ else
+ {
+ notificationsCount = _notifications.GetNotificationCount(SiteId, UserId, -1, IsRead);
+ }
+ }
+ else
+ {
+ _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Get Attempt {SiteId} {Direction} {UserId} {isRead}", siteid, direction, userid, isread);
+ HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
+ notificationsCount = 0;
+ }
+
+
+ return notificationsCount;
+ }
+
+
// GET: api/?siteid=x&type=y&userid=z
[HttpGet]
[Authorize(Roles = RoleNames.Registered)]
diff --git a/Oqtane.Server/Migrations/Tenant/04000101_AddNotificationIsRead.cs b/Oqtane.Server/Migrations/Tenant/04000101_AddNotificationIsRead.cs
new file mode 100644
index 00000000..8b97308c
--- /dev/null
+++ b/Oqtane.Server/Migrations/Tenant/04000101_AddNotificationIsRead.cs
@@ -0,0 +1,35 @@
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Oqtane.Databases.Interfaces;
+using Oqtane.Migrations.EntityBuilders;
+using Oqtane.Repository;
+using Oqtane.Shared;
+
+namespace Oqtane.Migrations.Tenant
+{
+ [DbContext(typeof(TenantDBContext))]
+ [Migration("Tenant.04.00.01.01")]
+ public class AddNotificationIsRead : MultiDatabaseMigration
+ {
+
+ public AddNotificationIsRead(IDatabase database) : base(database)
+ {
+ }
+
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder, ActiveDatabase);
+ notificationEntityBuilder.AddBooleanColumn("IsRead", false);
+ notificationEntityBuilder.UpdateColumn("IsRead", "1", "bool", "");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ var notificationEntityBuilder = new NotificationEntityBuilder(migrationBuilder, ActiveDatabase);
+ notificationEntityBuilder.DropColumn("IsPublic");
+ }
+
+ }
+
+
+}
diff --git a/Oqtane.Server/Repository/Interfaces/INotificationRepository.cs b/Oqtane.Server/Repository/Interfaces/INotificationRepository.cs
index 34fb58be..948d7b53 100644
--- a/Oqtane.Server/Repository/Interfaces/INotificationRepository.cs
+++ b/Oqtane.Server/Repository/Interfaces/INotificationRepository.cs
@@ -6,6 +6,8 @@ namespace Oqtane.Repository
public interface INotificationRepository
{
IEnumerable GetNotifications(int siteId, int fromUserId, int toUserId);
+ IEnumerable GetNotifications(int siteId, int fromUserId, int toUserId, int count, bool isRead);
+ int GetNotificationCount(int siteId, int fromUserId, int toUserId, bool isRead);
Notification AddNotification(Notification notification);
Notification UpdateNotification(Notification notification);
Notification GetNotification(int notificationId);
diff --git a/Oqtane.Server/Repository/NotificationRepository.cs b/Oqtane.Server/Repository/NotificationRepository.cs
index 7596ee94..42eff7cd 100644
--- a/Oqtane.Server/Repository/NotificationRepository.cs
+++ b/Oqtane.Server/Repository/NotificationRepository.cs
@@ -33,6 +33,52 @@ namespace Oqtane.Repository
.ToList();
}
+ public IEnumerable GetNotifications(int siteId, int fromUserId, int toUserId, int count, bool isRead)
+ {
+ if (toUserId == -1 && fromUserId == -1)
+ {
+ return _db.Notification
+ .Where(item => item.SiteId == siteId)
+ .Where(item => item.IsDelivered == false && item.IsDeleted == false)
+ .Where(item => item.SendOn == null || item.SendOn < System.DateTime.UtcNow)
+ .Where(item => item.IsRead == isRead)
+ .ToList()
+ .Take(count);
+ }
+
+ return _db.Notification
+ .Where(item => item.SiteId == siteId)
+ .Where(item => item.ToUserId == toUserId || toUserId == -1)
+ .Where(item => item.FromUserId == fromUserId || fromUserId == -1)
+ .Where(item => item.IsRead == isRead)
+ .ToList()
+ .Take(count);
+ }
+
+ public int GetNotificationCount(int siteId, int fromUserId, int toUserId, bool isRead)
+ {
+ if (toUserId == -1 && fromUserId == -1)
+ {
+ return _db.Notification
+ .Where(item => item.SiteId == siteId)
+ .Where(item => item.IsDelivered == false && item.IsDeleted == false)
+ .Where(item => item.SendOn == null || item.SendOn < System.DateTime.UtcNow)
+ .Where(item => item.IsRead == isRead)
+ .ToList()
+ .Count();
+
+ }
+
+ return _db.Notification
+ .Where(item => item.SiteId == siteId)
+ .Where(item => item.ToUserId == toUserId || toUserId == -1)
+ .Where(item => item.FromUserId == fromUserId || fromUserId == -1)
+ .Where(item => item.IsRead == isRead)
+ .ToList()
+ .Count();
+ }
+
+
public Notification AddNotification(Notification notification)
{
_db.Notification.Add(notification);
diff --git a/Oqtane.Shared/Models/Notification.cs b/Oqtane.Shared/Models/Notification.cs
index 975b28c8..d7e08c01 100644
--- a/Oqtane.Shared/Models/Notification.cs
+++ b/Oqtane.Shared/Models/Notification.cs
@@ -94,6 +94,10 @@ namespace Oqtane.Models
///
public DateTime? SendOn { get; set; }
+ ///
+ /// If it has been read. See also
+ ///
+ public bool IsRead { get; set; }
// constructors
public Notification() {}
@@ -174,6 +178,7 @@ namespace Oqtane.Models
}
IsDelivered = false;
DeliveredOn = null;
+ IsRead = false;
}
}