zinab_elgendy 2 viikkoa sitten
vanhempi
commit
8d75181c06

+ 1 - 0
MTWorkHR.API/MTWorkHR.API.csproj

@@ -12,6 +12,7 @@
   <ItemGroup>
     <PackageReference Include="Azure.Storage.Blobs" Version="12.20.0" />
     <PackageReference Include="dotenv.net" Version="3.2.0" />
+    <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.8" />
     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

+ 19 - 1
MTWorkHR.API/Program.cs

@@ -17,6 +17,8 @@ using Moq;
 
 
 using Microsoft.Extensions.DependencyInjection;
+using MTWorkHR.API.Chat;
+using Microsoft.AspNetCore.SignalR;
 
 var builder = WebApplication.CreateBuilder(args);
 
@@ -131,7 +133,10 @@ builder.Services.AddSwaggerGen(swagger =>
                     }
                 });
 });
-
+builder.Services.AddSignalR(options =>
+{
+    options.EnableDetailedErrors = true;
+});
 //--------------------------
 var app = builder.Build();
 
@@ -149,10 +154,23 @@ app.UseCors(x => x
     .SetIsOriginAllowed(origin =>
     true) // allow any origin
     .AllowCredentials()); // allow credentials
+
+
+//app.MapPost("broadcast", async (string message, IHubContext<ChatHub, IChatClient> context) =>
+//{
+//    await context.Clients.All.ReceiveMessage(message);
+//    return Results.NoContent();
+//});
+
+//app.UseEndpoints(endpoints =>
+//{
+//    endpoints.MapHub<ChatHub>("/chatHub");
+//});
 app.UseHttpsRedirection();
 app.UseAuthentication();
 app.UseAuthorization();
 app.UseMiddleware<LoggingMiddleware>();
 app.MapControllers();
+app.MapHub<ChatHub>("/chatHub");
 
 app.Run();

+ 280 - 0
MTWorkHR.Application/Chat/ChatHub.cs

@@ -0,0 +1,280 @@
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.EntityFrameworkCore;
+using MimeKit;
+using MTWorkHR.Application.Filters;
+using MTWorkHR.Application.Identity;
+using MTWorkHR.Application.Mapper;
+using MTWorkHR.Application.Models;
+using MTWorkHR.Application.Services;
+using MTWorkHR.Core.Entities;
+using MTWorkHR.Core.Entities.Base;
+using MTWorkHR.Core.Global;
+using MTWorkHR.Core.UnitOfWork;
+using MTWorkHR.Infrastructure.Entities;
+using System;
+using System.ComponentModel.Design;
+using System.Linq.Dynamic.Core.Tokenizer;
+using System.Security.Claims;
+using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database;
+
+namespace MTWorkHR.API.Chat
+{
+    [AppAuthorize]
+    public class ChatHub : Hub
+    {
+        private readonly IUnitOfWork _unitOfWork;
+        private readonly GlobalInfo _globalInfo;
+        //private readonly UserService _userService; 
+        private readonly ApplicationUserManager _userManager;
+
+        public ChatHub(IUnitOfWork unitOfWork, GlobalInfo globalInfo, ApplicationUserManager userManager /*, UserService userService*/) 
+        {
+            _unitOfWork = unitOfWork;
+            _globalInfo = globalInfo;
+            //  _userService = userService;
+            _userManager = userManager;
+        }
+
+        public async Task GetUsers()
+        {
+            var myCompanyUsers = await GetAllCompanyEmployees();
+
+            await Clients.Caller.SendAsync("UpdateUserList", myCompanyUsers);
+        }
+
+      
+      
+        public async Task<List<UserAllDto>> GetAllCompanyEmployees()
+        {
+            var employees = await _userManager.GetUsersInRoleAsync("Employee");
+            var CompanyId = GetAuthenticatedCompanyId();
+            var res = employees.Where(e => e.CompanyId == CompanyId).ToList();
+            var response = MapperObject.Mapper.Map<List<UserAllDto>>(res);
+
+            return response;
+        }
+
+        private long GetAuthenticatedCompanyId()
+        {
+            long CompanyIdLong = 0;
+            var identity = Context.User?.Identities.FirstOrDefault();
+            var CompanyId = identity!=null ? identity.FindFirst("companyId")?.Value : "0";
+            
+            if(CompanyId != null)
+            {
+                CompanyIdLong = long.Parse(CompanyId);
+            }
+            return CompanyIdLong;
+        }
+
+      
+
+      
+        // Send a message from one user to another
+       
+        public async Task sendMsg(string receiverUserId, string msg)
+        {
+            try
+            {
+                var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value;
+                var userName = Context.User.Identities.FirstOrDefault().FindFirst("name")?.Value;
+
+                var allConnections = await _unitOfWork.HubConnection.GetAllAsync();
+                var receiverUser = allConnections.Item1.FirstOrDefault(c => c.UserId == receiverUserId);
+                var receiverconnIdDB = receiverUser != null ? receiverUser.SignalrId : "0";
+                ChatMessage messag = new ChatMessage { 
+                    Content = msg, 
+                    ReceiverId = receiverUserId, 
+                    ReceiverName = receiverUser.UserName ?? "", 
+                    SenderId = userId, 
+                    SenderName = userName, 
+                    IsSeen = false 
+                };
+                await _unitOfWork.ChatMessage.AddAsync(messag);
+                await _unitOfWork.CompleteAsync();
+                await Clients.Client(receiverconnIdDB).SendAsync("ReceiveMessage", messag);
+                await Clients.Caller.SendAsync("ReceiveMessage", messag);
+            }
+            catch (Exception e) { }
+        }
+
+        // Get previous messages between two users
+        public async Task GetPreviousMessages(string contactId)
+        {
+            var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value;
+            var allmessages = await _unitOfWork.ChatMessage.GetAllWithChildrenAsync(userId, contactId);
+            // Ensure the query is fully materialized before passing it to SignalR
+            var messagesList = await allmessages.Item1.ToListAsync();
+
+            await Clients.Caller.SendAsync("PreviousMessages", messagesList);
+        }
+        //----------------------------------------------------------------------
+        //----------------------------------------------------------------------
+        //----------------------------------------------------------------------
+
+        //Simple Test Method
+        public async Task SendMessageAll(string user, string message)
+        {
+            await Clients.All.SendAsync("ReceiveMessage", user, message);
+        }
+
+        public async override Task OnDisconnectedAsync(Exception exception)
+        {
+            var email = Context.User?.FindFirst(ClaimTypes.Email)?.Value;
+            var connections = await _unitOfWork.HubConnection.GetAllAsync(Context.ConnectionId);
+            var currUserId = connections.Item1.Select(c => c.UserId).SingleOrDefault();
+            await _unitOfWork.HubConnection.DeleteRangeAsync(connections.Item1.ToList());
+            await _unitOfWork.CompleteAsync();
+            await Clients.Others.SendAsync("userOff", currUserId);
+            await base.OnDisconnectedAsync(exception);
+        }
+        public override async Task OnConnectedAsync()
+        {
+            try
+            {
+                string currSignalrID = Context.ConnectionId;
+                var email = Context.User?.FindFirst(ClaimTypes.Email)?.Value;
+                var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value;
+                var userName = Context.User.Identities.FirstOrDefault().FindFirst("name")?.Value;
+
+                if (userId != null) //if credentials are correct
+                {
+                    HubConnection currUser = new HubConnection
+                    {
+                        UserId = userId,
+                        UserName = userName,
+                        SignalrId = currSignalrID,
+                        TimeStamp = DateTime.Now
+                    };
+                    var newConnection = await _unitOfWork.HubConnection.AddAsync(currUser);
+
+                    await _unitOfWork.CompleteAsync();
+
+                    ChatUserDto newUser = new ChatUserDto(userId, userName, currSignalrID);
+                    await Clients.Caller.SendAsync("authMeResponseSuccess", newUser);//4Tutorial
+                    await Clients.Others.SendAsync("userOn", newUser);//4Tutorial
+                }
+
+                else //if credentials are incorrect
+                {
+                    await Clients.Caller.SendAsync("authMeResponseFail");
+                }
+            }
+            catch (Exception ex) { }
+
+            await base.OnConnectedAsync();
+        }
+
+      
+
+        public void logOut(string userId)
+        {
+            var userIdAuth = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value;
+            var connections = _unitOfWork.HubConnection.GetAllAsync(Context.ConnectionId).Result;
+           // var currUserId = connections.Item1.Select(c => c.UserId).SingleOrDefault();
+            _unitOfWork.HubConnection.DeleteRangeAsync(connections.Item1.ToList());
+            _unitOfWork.CompleteAsync();
+
+            Clients.Caller.SendAsync("logoutResponse");
+            Clients.Others.SendAsync("userOff", userIdAuth);
+        }
+
+      
+
+
+
+        public async Task getOnlineUsers()
+        {
+            var allConnections = await _unitOfWork.HubConnection.GetAllAsync();
+            var currUserId = allConnections.Item1.Where(c => c.SignalrId == Context.ConnectionId).Select(c => c.UserId).SingleOrDefault();
+            List<ChatUserDto> onlineUsers = allConnections.Item1
+                .Where(c => c.UserId != currUserId)
+                .Select(c =>
+                    new ChatUserDto(c.UserId, c.UserName, c.SignalrId)
+                ).ToList();
+            await Clients.Caller.SendAsync("getOnlineUsersResponse", onlineUsers);
+        }
+
+        public async Task authMe(PersonalInfo person)
+        {
+            try
+            {
+                string currSignalrID = Context.ConnectionId;
+                //Person tempPerson = ctx.Person.Where(p => p.Username == personInfo.userName && p.Password == personInfo.password)
+                //    .SingleOrDefault();
+                var companyId = Context.User.Identities.FirstOrDefault().FindFirst("companyId")?.Value;
+                var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value;
+                var userName = Context.User.Identities.FirstOrDefault().FindFirst("name")?.Value;
+
+                if (userId != null) //if credentials are correct
+                {
+                    Console.WriteLine("\n" + userName + " logged in" + "\nSignalrID: " + currSignalrID);
+
+                    HubConnection currUser = new HubConnection
+                    {
+                        UserId = userId,
+                        UserName = userName,
+                        SignalrId = currSignalrID,
+                        TimeStamp = DateTime.Now
+                    };
+                    var newConnection = await _unitOfWork.HubConnection.AddAsync(currUser);
+
+                    await _unitOfWork.CompleteAsync();
+
+                    ChatUserDto newUser = new ChatUserDto(userId, userName, currSignalrID);
+                    await Clients.Caller.SendAsync("authMeResponseSuccess", newUser);//4Tutorial
+                    await Clients.Others.SendAsync("userOn", newUser);//4Tutorial
+                }
+
+                else //if credentials are incorrect
+                {
+                    await Clients.Caller.SendAsync("authMeResponseFail");
+                }
+            }
+            catch (Exception e)
+            {
+                await Clients.Caller.SendAsync("authMeResponseFail");
+            }
+        }
+
+
+
+
+        //public async Task reauthMe(string userId)
+        //{
+        //    string currSignalrID = Context.ConnectionId;
+        //    //ApplicationUser tempPerson = ctx.Person.Where(p => p.Id == personId)
+        //    //    .SingleOrDefault();
+
+        //    if (userId == _globalInfo.UserId) //if credentials are correct
+        //    {
+        //        Console.WriteLine("\n" + _globalInfo.UserName + " logged in" + "\nSignalrID: " + currSignalrID);
+
+        //        HubConnection currUser = new HubConnection
+        //        {
+        //            UserId = _globalInfo.UserId,
+        //            SignalrId = currSignalrID,
+        //            TimeStamp = DateTime.Now
+        //        };
+        //        var newConnection = await _unitOfWork.HubConnection.AddAsync(currUser);
+
+        //        await _unitOfWork.CompleteAsync();
+
+        //        ChatUserDto newUser = new ChatUserDto(_globalInfo.UserId, _globalInfo.UserName, currSignalrID);
+
+        //        await Clients.Caller.SendAsync("reauthMeResponse", newUser);//4Tutorial
+        //        await Clients.Others.SendAsync("userOn", newUser);//4Tutorial
+        //    }
+        //} //end of reauthMe
+
+
+    }
+
+    public class PersonalInfo
+    {
+        public string userName { get; set; }
+        public string password { get; set; }
+        public string userId { get; set; }
+    }
+}

+ 7 - 0
MTWorkHR.Application/Chat/IChatClient.cs

@@ -0,0 +1,7 @@
+namespace MTWorkHR.API.Chat
+{
+    public interface IChatClient
+    {
+        Task ReceiveMessage(string message);
+    }
+}

+ 24 - 0
MTWorkHR.Application/Dtos/User/ChatMessageDto.cs

@@ -0,0 +1,24 @@
+using MTWorkHR.Core.Entities.Base;
+using MTWorkHR.Core.Entities;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MTWorkHR.Application.Models
+{
+    public class ChatMessageDto 
+    {
+
+        public string SenderId { get; set; }
+        public string SenderName { get; set; }
+        public string ReceiverId { get; set; }
+        public string ReceiverName { get; set; }
+        public string Content { get; set; }
+        public bool IsSeen { get; set; }
+        public List<ChatAttachment>? ChatAttachments { get; set; }
+
+
+    }
+}

+ 22 - 0
MTWorkHR.Application/Dtos/User/ChatUserDto.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MTWorkHR.Application.Models
+{
+    public class ChatUserDto
+    {
+        public string UserId { get; set; }
+        public string UserName { get; set; }
+        public string ConnectionId { get; set; } //signalrId
+
+        public ChatUserDto(string someId, string someName, string someConnId)
+        {
+            UserId = someId;
+            UserName = someName;
+            ConnectionId = someConnId;
+        }
+    }
+}

+ 2 - 0
MTWorkHR.Application/Mapper/MappingProfile.cs

@@ -130,6 +130,8 @@ namespace MTWorkHR.Application.Mapper
             CreateMap<CompanyUserDto, ApplicationUser>().ForMember(m => m.UserName, o => o.MapFrom(s => s.Email));
             CreateMap<ApplicationUser, CompanyUserDto>().ForMember(m => m.Password, op => op.Ignore());
             CreateMap<UserTaskStatus, UserTaskStatusDto>().ReverseMap();
+            CreateMap<ChatMessageDto, ChatMessage>().ReverseMap();
+            
             //-----------Contract----
             CreateMap<Contract, ContractDto>();
             CreateMap<ContractDto, Contract>()

+ 1 - 0
MTWorkHR.Application/Services/User/UserService.cs

@@ -240,6 +240,7 @@ namespace MTWorkHR.Application.Services
 
             return new PagingResultDto<UserAllDto> { Result = list, Total = total };
         }
+
         public async Task<List<UserDto>> GetAllEmployees()
         {
             var employees = await _userManager.GetUsersInRoleAsync("Employee");

+ 16 - 0
MTWorkHR.Core/Entities/Chat/HubConnection.cs

@@ -0,0 +1,16 @@
+using MTWorkHR.Core.Entities.Base;
+using System;
+using System.Collections.Generic;
+
+#nullable disable
+
+namespace MTWorkHR.Core.Entities
+{
+    public partial class HubConnection : Entity
+    {
+        public string UserId { get; set; }
+        public string UserName { get; set; }
+        public string SignalrId { get; set; }
+        public DateTime TimeStamp { get; set; }
+    }
+}

+ 1 - 1
MTWorkHR.Core/IRepositories/Chat/IChatMessageRepository.cs

@@ -11,6 +11,6 @@ namespace MTWorkHR.Core.IRepositories
     public interface IChatMessageRepository : IRepository<ChatMessage>
     {
         Task<ChatMessage> GetByIdWithAllChildren(long id);
-        Task<Tuple<IQueryable<ChatMessage>, int>> GetAllWithChildrenAsync();
+        Task<Tuple<IQueryable<ChatMessage>, int>> GetAllWithChildrenAsync(string userId, string contactId);
     }
 }

+ 16 - 0
MTWorkHR.Core/IRepositories/Chat/IHubConnectionRepository.cs

@@ -0,0 +1,16 @@
+using MTWorkHR.Core.Entities;
+using MTWorkHR.Core.IRepositories.Base;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MTWorkHR.Core.IRepositories
+{
+    public interface IHubConnectionRepository : IRepository<HubConnection>
+    {
+        Task<Tuple<IQueryable<HubConnection>, int>> GetAllAsync(string connectionId);
+
+    }
+}

+ 2 - 0
MTWorkHR.Core/IUnitOfWork/IUnitOfWork.cs

@@ -37,6 +37,8 @@ namespace MTWorkHR.Core.UnitOfWork
 
         IChatMessageRepository ChatMessage { get; }
         IContractRepository Contract { get; }
+        IHubConnectionRepository HubConnection { get; }
+
         Task<int> CompleteAsync();
 
         void BeginTran();

+ 1 - 0
MTWorkHR.Infrastructure/DBContext/HRDataContext.cs

@@ -42,6 +42,7 @@ namespace MTWorkHR.Infrastructure.DBContext
         public DbSet<OrderAllocation> OrderAllocations { get; set; }
         public DbSet<OrderRequest> OrderRequests { get; set; }
         public DbSet<ChatMessage> ChatMessages { get; set; }
+        public DbSet<HubConnection> HubConnections { get; set; }
         //-------------------Lookups---------------------------
         public DbSet<CountryLookup> CountryLookups { get; set; }
         public DbSet<Qualification> Qualifications { get; set; }

+ 27 - 5
MTWorkHR.Infrastructure/InfrastructureServiceRegistration.cs

@@ -19,6 +19,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using MTWorkHR.Infrastructure.Entities;
+using Microsoft.Extensions.Options;
 
 namespace MTWorkHR.Infrastructure
 {
@@ -37,11 +38,15 @@ namespace MTWorkHR.Infrastructure
             services.AddIdentity<ApplicationUser, ApplicationRole>().AddEntityFrameworkStores<HRDataContext>().AddDefaultTokenProviders();
 
            
-            services.AddAuthentication(options => {
-                 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; // "bearer"
-                 options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
 
-            }).AddJwtBearer(o=> o.TokenValidationParameters = new TokenValidationParameters 
+            services.AddAuthentication(options =>
+            {
+                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
+                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
+            })
+            .AddJwtBearer(options =>
+            {
+                options.TokenValidationParameters = new TokenValidationParameters
                 {
                     ValidateIssuerSigningKey = true,
                     ValidateIssuer = true,
@@ -51,8 +56,23 @@ namespace MTWorkHR.Infrastructure
                     ValidIssuer = config.JwtSettings.Issuer,
                     ValidAudience = config.JwtSettings.Audience,
                     IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.JwtSettings.SecretKey))
-                }) ;
+                };
 
+                // This is the important part to allow SignalR to work with JWT tokens
+                options.Events = new JwtBearerEvents
+                {
+                    OnMessageReceived = context =>
+                    {
+                        var accessToken = context.Request.Query["access_token"];
+                        if (!string.IsNullOrEmpty(accessToken) &&
+                            (context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream"))
+                        {
+                            context.Token = accessToken;
+                        }
+                        return Task.CompletedTask;
+                    }
+                };
+            });
 
 
             services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
@@ -85,6 +105,8 @@ namespace MTWorkHR.Infrastructure
             services.AddScoped(typeof(IChatMessageRepository), typeof(ChatMessageRepository));
             services.AddScoped(typeof(IContractRepository), typeof(ContractRepository));
 
+            services.AddScoped(typeof(IHubConnectionRepository), typeof(HubConnectionRepository));
+            
 
 
             services.AddScoped(typeof(IPermissionRepository), typeof(PermissionRepository));

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 3650 - 0
MTWorkHR.Infrastructure/Migrations/20241008101202_addHubConnection.Designer.cs


+ 38 - 0
MTWorkHR.Infrastructure/Migrations/20241008101202_addHubConnection.cs

@@ -0,0 +1,38 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace MTWorkHR.Infrastructure.Migrations
+{
+    /// <inheritdoc />
+    public partial class addHubConnection : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "HubConnections",
+                columns: table => new
+                {
+                    Id = table.Column<long>(type: "bigint", nullable: false)
+                        .Annotation("SqlServer:Identity", "1, 1"),
+                    UserId = table.Column<string>(type: "nvarchar(max)", nullable: true),
+                    UserName = table.Column<string>(type: "nvarchar(max)", nullable: true),
+                    SignalrId = table.Column<string>(type: "nvarchar(max)", nullable: true),
+                    TimeStamp = table.Column<DateTime>(type: "datetime2", nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_HubConnections", x => x.Id);
+                });
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "HubConnections");
+        }
+    }
+}

+ 26 - 0
MTWorkHR.Infrastructure/Migrations/HRDataContextModelSnapshot.cs

@@ -902,6 +902,32 @@ namespace MTWorkHR.Infrastructure.Migrations
                     b.ToTable("FileLogs");
                 });
 
+            modelBuilder.Entity("MTWorkHR.Core.Entities.HubConnection", b =>
+                {
+                    b.Property<long>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("bigint")
+                        .HasColumnOrder(0);
+
+                    SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
+
+                    b.Property<string>("SignalrId")
+                        .HasColumnType("nvarchar(max)");
+
+                    b.Property<DateTime>("TimeStamp")
+                        .HasColumnType("datetime2");
+
+                    b.Property<string>("UserId")
+                        .HasColumnType("nvarchar(max)");
+
+                    b.Property<string>("UserName")
+                        .HasColumnType("nvarchar(max)");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("HubConnections");
+                });
+
             modelBuilder.Entity("MTWorkHR.Core.Entities.Industry", b =>
                 {
                     b.Property<long>("Id")

+ 2 - 2
MTWorkHR.Infrastructure/Repositories/Chat/ChatMessageRepository.cs

@@ -22,9 +22,9 @@ namespace MTWorkHR.Infrastructure.Repositories
                 .Include(x => x.ChatAttachments)
                 .FirstOrDefaultAsync(x => x.Id == id);
         }
-        public async Task<Tuple<IQueryable<ChatMessage>, int>> GetAllWithChildrenAsync()
+        public async Task<Tuple<IQueryable<ChatMessage>, int>> GetAllWithChildrenAsync(string userId, string contactId)
         {
-            var query = dbSet.Include(x => x.ChatAttachments).AsQueryable();
+            var query = dbSet.Include(x => x.ChatAttachments).Where(m=> (m.ReceiverId == contactId && m.SenderId == userId) || (m.ReceiverId == userId && m.SenderId == contactId)).AsQueryable();
             var total = await query.CountAsync();
 
             return new Tuple<IQueryable<ChatMessage>, int>(query, total);

+ 30 - 0
MTWorkHR.Infrastructure/Repositories/Chat/HubConnectionRepository.cs

@@ -0,0 +1,30 @@
+using Microsoft.EntityFrameworkCore;
+using MTWorkHR.Core.Entities;
+using MTWorkHR.Core.IDto;
+using MTWorkHR.Infrastructure.Entities;
+using MTWorkHR.Infrastructure.DBContext;
+using MTWorkHR.Core.IRepositories;
+
+namespace MTWorkHR.Infrastructure.Repositories
+{
+    public class HubConnectionRepository : Repository<HubConnection>, IHubConnectionRepository
+    {
+        private readonly DbSet<HubConnection> dbSet;
+
+        public HubConnectionRepository(HRDataContext context) : base(context)
+        {
+            dbSet = context.Set<HubConnection>();
+        }
+
+        public async Task<Tuple<IQueryable<HubConnection>, int>> GetAllAsync(string connectionId)
+        {
+            var query = dbSet.AsQueryable();
+            var total = await query.CountAsync();
+
+            return new Tuple<IQueryable<HubConnection>, int>(query, total);
+        }
+
+       
+
+    }
+}

+ 4 - 0
MTWorkHR.Infrastructure/UnitOfWork/UnitOfWork.cs

@@ -39,6 +39,7 @@ namespace MTWorkHR.Infrastructure.UnitOfWorks
         public ILoginOTPRepository LoginOTP { get; }
         public ICityRepository City { get; }
         public IChatMessageRepository ChatMessage { get; }
+        public IHubConnectionRepository HubConnection { get; }
         public IContractRepository Contract{ get; }
 
         public UnitOfWork(HRDataContext _context
@@ -68,6 +69,8 @@ namespace MTWorkHR.Infrastructure.UnitOfWorks
             , IProjectTeamRepository projectTeam
             , IChatMessageRepository chatMessage
             , IContractRepository contract
+            , IHubConnectionRepository connection
+
             )
         {
             context = _context;
@@ -97,6 +100,7 @@ namespace MTWorkHR.Infrastructure.UnitOfWorks
             ProjectTeam = projectTeam;
             ChatMessage = chatMessage;
             Contract = contract;
+            HubConnection = connection;
         }
 
         public async Task<int> CompleteAsync()