Skip to content
55 changes: 55 additions & 0 deletions src/Analysim.Core/Entities/Notification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Core.Entities
{
public class Notification
{
[Key]
public int NotificationID { get; set; }

[ForeignKey("RecipientUser")]
public int RecipientUserID { get; set; }
public User RecipientUser { get; set; }

[ForeignKey("ActorUser")]
public int? ActorUserID { get; set; }
public User ActorUser { get; set; }

[Required]
[MaxLength(100)]
public string Type { get; set; }

[ForeignKey("Project")]
public int? ProjectID { get; set; }
public Project Project { get; set; }

[ForeignKey("ProjectComment")]
public int? CommentID { get; set; }
public ProjectComment ProjectComment { get; set; }

[ForeignKey("ProjectLog")]
public int? ProjectLogID { get; set; }
public ProjectLog ProjectLog { get; set; }

[Required]
[MaxLength(200)]
public string Title { get; set; }

[Required]
[MaxLength(1000)]
public string Body { get; set; }

[MaxLength(500)]
public string Link { get; set; }

public string DataJson { get; set; }

public bool IsRead { get; set; }

public DateTime? ReadAt { get; set; }

public DateTime CreatedAt { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/Analysim.Core/Entities/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public class Project
// Logs
public ICollection<ProjectLog> ProjectLogs { get; set; } = new List<ProjectLog>();
public ICollection<Publication> Publications { get; set; } = new List<Publication>();
public ICollection<ProjectMembershipRequest> ProjectMembershipRequests { get; set; } = new List<ProjectMembershipRequest>();

public int ForkedFromProjectID { get; set; }
}
}

46 changes: 46 additions & 0 deletions src/Analysim.Core/Entities/ProjectMembershipRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Core.Entities
{
public class ProjectMembershipRequest
{
[Key]
public int ProjectMembershipRequestID { get; set; }

[Required(ErrorMessage = "Project ID is a required field.")]
[ForeignKey("Project")]
public int ProjectID { get; set; }
public Project Project { get; set; }

[Required(ErrorMessage = "Requester User ID is a required field.")]
[ForeignKey("RequesterUser")]
public int RequesterUserID { get; set; }
public User RequesterUser { get; set; }

[Required(ErrorMessage = "Target User ID is a required field.")]
[ForeignKey("TargetUser")]
public int TargetUserID { get; set; }
public User TargetUser { get; set; }

[Required(ErrorMessage = "Created By User ID is a required field.")]
[ForeignKey("CreatedByUser")]
public int CreatedByUserID { get; set; }
public User CreatedByUser { get; set; }

[Required(ErrorMessage = "Request Type is a required field.")]
public string Type { get; set; }

[Required(ErrorMessage = "Request Status is a required field.")]
public string Status { get; set; }

[MaxLength(500, ErrorMessage = "Maximum length for Message is 500 Character.")]
public string Message { get; set; }

[Required(ErrorMessage = "Created At is a required field.")]
public DateTimeOffset CreatedAt { get; set; }

public DateTimeOffset? RespondedAt { get; set; }
}
}
20 changes: 20 additions & 0 deletions src/Analysim.Core/Entities/UserNotificationPreference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Core.Entities
{
public class UserNotificationPreference
{
[ForeignKey("User")]
public int UserID { get; set; }
public User User { get; set; }

[Required]
[MaxLength(100)]
public string NotificationType { get; set; }

public bool InAppEnabled { get; set; } = true;

public bool EmailEnabled { get; set; }
}
}
12 changes: 12 additions & 0 deletions src/Analysim.Core/Helper/NotificationTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Core.Helper
{
public static class NotificationTypes
{
public const string CommentReply = "comment.reply";
public const string ProjectInvitationReceived = "project.invitation.received";
public const string ProjectMemberAdded = "project.member.added";
public const string ProjectJoined = "project.joined";
public const string ProjectLogCreated = "project.log.created";
public const string ProjectLogUpdated = "project.log.updated";
}
}
10 changes: 10 additions & 0 deletions src/Analysim.Core/Interfaces/INotificationService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Core.Models;

namespace Core.Interfaces
{
public interface INotificationService
{
Task PublishAsync(NotificationEvent notificationEvent);
}
}
16 changes: 16 additions & 0 deletions src/Analysim.Core/Models/NotificationEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Collections.Generic;

namespace Core.Models
{
public class NotificationEvent
{
public string Type { get; set; }
public int? ActorUserID { get; set; }
public int? RecipientUserID { get; set; }
public int? ProjectID { get; set; }
public int? CommentID { get; set; }
public int? ParentCommentID { get; set; }
public int? ProjectLogID { get; set; }
public IDictionary<string, string> Data { get; set; } = new Dictionary<string, string>();
}
}
84 changes: 84 additions & 0 deletions src/Analysim.Infrastructure/Data/ApplicationDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<ProjectTag>().HasKey(pt => new { pt.ProjectID, pt.TagID });
modelBuilder.Entity<UserUser>().HasKey(uu => new { uu.UserID, uu.FollowerID });
modelBuilder.Entity<NotebookContent>().HasKey(nc => new { nc.NotebookID, nc.Version });
modelBuilder.Entity<UserNotificationPreference>().HasKey(p => new { p.UserID, p.NotificationType });

modelBuilder.Entity<RefreshToken>()
.HasIndex(rt => rt.TokenHash)
Expand Down Expand Up @@ -84,6 +85,55 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.HasForeignKey(rt => rt.UserID)
.OnDelete(DeleteBehavior.Cascade);

#region Notifications

modelBuilder.Entity<Notification>()
.HasOne(n => n.RecipientUser)
.WithMany()
.HasForeignKey(n => n.RecipientUserID)
.OnDelete(DeleteBehavior.Cascade);

modelBuilder.Entity<Notification>()
.HasOne(n => n.ActorUser)
.WithMany()
.HasForeignKey(n => n.ActorUserID)
.OnDelete(DeleteBehavior.SetNull);

modelBuilder.Entity<Notification>()
.HasOne(n => n.Project)
.WithMany()
.HasForeignKey(n => n.ProjectID)
.OnDelete(DeleteBehavior.SetNull);

modelBuilder.Entity<Notification>()
.HasOne(n => n.ProjectComment)
.WithMany()
.HasForeignKey(n => n.CommentID)
.OnDelete(DeleteBehavior.SetNull);

modelBuilder.Entity<Notification>()
.HasOne(n => n.ProjectLog)
.WithMany()
.HasForeignKey(n => n.ProjectLogID)
.OnDelete(DeleteBehavior.SetNull);

modelBuilder.Entity<UserNotificationPreference>()
.HasOne(p => p.User)
.WithMany()
.HasForeignKey(p => p.UserID)
.OnDelete(DeleteBehavior.Cascade);

modelBuilder.Entity<Notification>()
.HasIndex(n => new { n.RecipientUserID, n.IsRead, n.CreatedAt });

modelBuilder.Entity<Notification>()
.HasIndex(n => n.Type);

modelBuilder.Entity<UserNotificationPreference>()
.HasIndex(p => p.NotificationType);

#endregion

// One To Many Relationship (Project -> Blob)
modelBuilder.Entity<Project>()
.HasMany(p => p.BlobFiles)
Expand Down Expand Up @@ -258,6 +308,37 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.WithOne(pp => pp.Project)
.HasForeignKey(pp => pp.ProjectID)
.OnDelete(DeleteBehavior.Cascade);

// One To Many Relationship (Project -> ProjectMembershipRequest)
modelBuilder.Entity<Project>()
.HasMany(p => p.ProjectMembershipRequests)
.WithOne(pmr => pmr.Project)
.HasForeignKey(pmr => pmr.ProjectID)
.OnDelete(DeleteBehavior.Cascade);

modelBuilder.Entity<ProjectMembershipRequest>()
.HasOne(pmr => pmr.RequesterUser)
.WithMany()
.HasForeignKey(pmr => pmr.RequesterUserID)
.OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity<ProjectMembershipRequest>()
.HasOne(pmr => pmr.TargetUser)
.WithMany()
.HasForeignKey(pmr => pmr.TargetUserID)
.OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity<ProjectMembershipRequest>()
.HasOne(pmr => pmr.CreatedByUser)
.WithMany()
.HasForeignKey(pmr => pmr.CreatedByUserID)
.OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity<ProjectMembershipRequest>()
.HasIndex(pmr => new { pmr.ProjectID, pmr.TargetUserID, pmr.Type, pmr.Status });

modelBuilder.Entity<ProjectMembershipRequest>()
.HasIndex(pmr => pmr.CreatedByUserID);
}


Expand All @@ -279,5 +360,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
public DbSet<ProjectLog> ProjectLogs { get; set; }

public DbSet<Publication> Publications { get; set; }
public DbSet<ProjectMembershipRequest> ProjectMembershipRequests { get; set; }
public DbSet<Notification> Notifications { get; set; }
public DbSet<UserNotificationPreference> UserNotificationPreferences { get; set; }
}
}
Loading
Loading