├── src ├── ChitChat.Application │ ├── Models │ │ ├── Dtos │ │ │ ├── User │ │ │ │ ├── UserProfileDto.cs │ │ │ │ ├── Follow │ │ │ │ │ ├── CreateFollowRequestDto.cs │ │ │ │ │ └── FollowDto.cs │ │ │ │ ├── Profile │ │ │ │ │ ├── ProfileSearchQueryDto.cs │ │ │ │ │ ├── ProfileRequestDto.cs │ │ │ │ │ └── ProfileDto.cs │ │ │ │ ├── RefreshTokenDto.cs │ │ │ │ ├── LoginRequestDto.cs │ │ │ │ ├── UserDto.cs │ │ │ │ ├── LoginResponseDto.cs │ │ │ │ └── RegisterationRequestDto.cs │ │ │ ├── BaseResponseDto.cs │ │ │ ├── Notification │ │ │ │ ├── CreateUserNotificationDto.cs │ │ │ │ ├── CreatePostNotificationDto.cs │ │ │ │ ├── CreateCommentNotificationDto.cs │ │ │ │ ├── CreateNotificationDto.cs │ │ │ │ └── NotificationDto.cs │ │ │ ├── Post │ │ │ │ ├── UpdatePostRequestDto.cs │ │ │ │ ├── Comments │ │ │ │ │ ├── CommentRequestDto.cs │ │ │ │ │ └── CommentDto.cs │ │ │ │ ├── PostUserSearchQueryDto.cs │ │ │ │ ├── PostSearchQueryDto.cs │ │ │ │ ├── CreatePost │ │ │ │ │ ├── CreatePostRequestDto.cs │ │ │ │ │ └── CreatePostMediaRequestDto.cs │ │ │ │ ├── PostMediaDto.cs │ │ │ │ └── PostDto.cs │ │ │ ├── Message │ │ │ │ ├── RequestSendMessageDto.cs │ │ │ │ ├── RequestSearchMessageDto.cs │ │ │ │ └── MessageDto.cs │ │ │ └── Conversation │ │ │ │ ├── ConversationDetailDto.cs │ │ │ │ └── ConversationDto.cs │ │ ├── PaginationFilter.cs │ │ └── ApiResult.cs │ ├── GlobalUsing.cs │ ├── Mapping │ │ ├── IMappingProfileMarker.cs │ │ ├── MessageProfile.cs │ │ ├── ConversationProfile.cs │ │ ├── CommentProfile.cs │ │ ├── PostProfile.cs │ │ ├── NotificationProfile.cs │ │ └── UserProfile.cs │ ├── Validators │ │ ├── IValidatorMarker.cs │ │ ├── Message │ │ │ ├── RequestMessageValidator.cs │ │ │ └── RequestSearchMessageValidator.cs │ │ ├── Post │ │ │ ├── CreatePostMediaRequestValidator.cs │ │ │ └── CreatePostRequestValidator.cs │ │ └── User │ │ │ ├── ProfileRequestValidator.cs │ │ │ └── RegisterationRequestValidator.cs │ ├── MachineLearning │ │ ├── Models │ │ │ ├── PostPredictionModel.cs │ │ │ └── ResponseRecommendationModel.cs │ │ └── Services │ │ │ ├── Interface │ │ │ └── ITrainingModelService.cs │ │ │ └── TrainingModelService.cs │ ├── Helpers │ │ ├── IClaimService.cs │ │ ├── ICloudinaryService.cs │ │ └── ITokenService.cs │ ├── Exceptions │ │ ├── UnauthorizeException.cs │ │ ├── ForbiddenException.cs │ │ ├── ConflictException.cs │ │ ├── InvalidModelException.cs │ │ ├── ApplicationException.cs │ │ └── NotFoundException.cs │ ├── Services │ │ ├── Caching │ │ │ ├── ICachingService.cs │ │ │ └── CacheEntryOptions.cs │ │ └── Interface │ │ │ ├── IUserService.cs │ │ │ ├── IProfileService.cs │ │ │ ├── IFollowService.cs │ │ │ ├── INotificationService.cs │ │ │ ├── IConversationService.cs │ │ │ └── IPostService.cs │ ├── SignalR │ │ └── Interface │ │ │ ├── IConversationNotificationService.cs │ │ │ └── IUserNotificationService.cs │ ├── Localization │ │ ├── ErrorText.cs │ │ └── ValidationText.cs │ ├── ChitChat.Application.csproj │ └── DependencyInjection.cs ├── ChitChat.Domain │ ├── Enums │ │ ├── CommentType.cs │ │ ├── UserRoles.cs │ │ ├── ConversationType.cs │ │ ├── UserStatus.cs │ │ ├── MediaType.cs │ │ ├── Gender.cs │ │ ├── NotificationType.cs │ │ ├── NotificationActionEnum.cs │ │ ├── MessageStatus.cs │ │ └── InteractionType.cs │ ├── Identity │ │ ├── ApplicationRole.cs │ │ └── UserApplication.cs │ ├── Entities │ │ ├── BaseEntity.cs │ │ ├── SystemEntities │ │ │ ├── Notification │ │ │ │ ├── UserNotification.cs │ │ │ │ ├── PostNotification.cs │ │ │ │ ├── CommentNotification.cs │ │ │ │ └── Notification.cs │ │ │ └── UserInteraction.cs │ │ ├── PostEntities │ │ │ ├── PostDetailTag.cs │ │ │ ├── Reaction │ │ │ │ ├── ReactionPost.cs │ │ │ │ └── ReactionComment.cs │ │ │ ├── PostMedia.cs │ │ │ ├── Post.cs │ │ │ └── Comment.cs │ │ ├── ChatEntities │ │ │ ├── ConversationDetail.cs │ │ │ ├── Message.cs │ │ │ └── Conversation.cs │ │ ├── LoginHistory.cs │ │ ├── BaseAuditedEntity.cs │ │ └── UserEntities │ │ │ ├── Profile.cs │ │ │ ├── UserFollower.cs │ │ │ └── UserFollowerRequest.cs │ ├── GlobalUsing.cs │ ├── Common │ │ ├── IAuditedEntity.cs │ │ ├── LocalizationSettings.cs │ │ ├── ErrorDescription.cs │ │ ├── PaginationResponse.cs │ │ ├── NotificationRefText.cs │ │ ├── UnixTimestampConverter.cs │ │ ├── LocalizedText.cs │ │ └── NotificationFormatter.cs │ ├── MachineLearningEntities │ │ └── UserInteractionModelItem.cs │ ├── Exceptions │ │ └── ResourceNotFoundException.cs │ └── ChitChat.Domain.csproj ├── ChitChat.WebAPI │ ├── ChitChat.WebAPI.http │ ├── .sample.env │ ├── appsettings.json │ ├── appsettings.Development.json │ ├── Controllers │ │ ├── TrainingModelController.cs │ │ ├── NotificationController.cs │ │ └── UserController.cs │ ├── appsettings.Production.json │ ├── ChitChat.WebAPI.csproj │ ├── Dockerfile │ ├── Properties │ │ └── launchSettings.json │ └── Program.cs ├── ChitChat.Infrastructure │ ├── SignalR │ │ ├── Helpers │ │ │ ├── HubEnum.cs │ │ │ ├── HubEndpoint.cs │ │ │ └── HubRoom.cs │ │ ├── Hubs │ │ │ ├── InterfaceClient │ │ │ │ ├── IConversationClient.cs │ │ │ │ └── IUserClient.cs │ │ │ ├── UserHub.cs │ │ │ └── ConversationHub.cs │ │ ├── Services │ │ │ ├── ConversationNotificationService.cs │ │ │ └── UserNotificationService.cs │ │ └── SignalRRegistration.cs │ ├── Authorization │ │ ├── AuthorizationRequirementBase.cs │ │ └── AuthorizationRegisteration.cs │ ├── GlobalUsing.cs │ ├── CloudinaryConfiguration │ │ ├── CloudinarySetting.cs │ │ └── CloudinaryRegisteration.cs │ ├── ConfigSetting │ │ └── JWTConfigSetting.cs │ ├── Caching │ │ ├── CachingRegistrations.cs │ │ └── MemoryCacheService.cs │ ├── Logging │ │ ├── SerilogOptions.cs │ │ └── SerilogRegistration.cs │ ├── Validations │ │ └── ValidateModelAttribute.cs │ ├── Services │ │ ├── ClaimService.cs │ │ ├── CloudinaryService.cs │ │ └── TokenService.cs │ ├── EntityFrameworkCore │ │ ├── EntityFrameworkRegisteration.cs │ │ └── Interceptor │ │ │ └── ContextSaveChangeInterceptor.cs │ ├── ChitChat.Infrastructure.csproj │ ├── DependencyInjection.cs │ └── Middleware │ │ └── GlobalExceptionHandlerMiddleware.cs ├── ChitChat.DataAccess │ ├── DatabaseConfiguration.cs │ ├── GlobalUsing.cs │ ├── Repositories │ │ ├── Interface │ │ │ ├── IRepositoryFactory.cs │ │ │ ├── IConversationRepository.cs │ │ │ ├── IUserFollowerRepository.cs │ │ │ ├── IUserInteractionRepository.cs │ │ │ ├── IUserRepository.cs │ │ │ └── IBaseRepository.cs │ │ ├── RepositoryFactory.cs │ │ ├── UserInteractionRepository.cs │ │ ├── UserFollowerRepository.cs │ │ ├── ConversationRepository.cs │ │ └── UserRepository.cs │ ├── Configurations │ │ ├── LoginHistoryConfiguration.cs │ │ ├── ProfileConfiguration.cs │ │ ├── PostMediaConfiguration.cs │ │ ├── ConversationDetailConfiguration.cs │ │ ├── PostDetailTagConfiguration).cs │ │ ├── Notification │ │ │ ├── UserNotificationConfiguration.cs │ │ │ ├── PostNotificationConfiguration.cs │ │ │ └── CommentNotificationConfiguration.cs │ │ ├── MessageConfiguration.cs │ │ ├── ReactionPostConfiguration.cs │ │ ├── UserInteractionConfiguration.cs │ │ ├── ReactionCommentConfiguration.cs │ │ ├── UserFollowerConfiguration.cs │ │ ├── UserFollowerRequestConfiguration.cs │ │ ├── CommentConfiguration.cs │ │ ├── ConversationConfiguration.cs │ │ └── PostConfiguration.cs │ ├── Data │ │ ├── AutomatedMigration.cs │ │ ├── ApplicationDbContext.cs │ │ └── DbContextSeed.cs │ ├── ChitChat.DataAccess.csproj │ ├── DependenceInjection.cs │ └── Migrations │ │ ├── 20241123154958_ChangeCommentStatus.cs │ │ ├── 20241117121420_V1Update.cs │ │ └── 20241221022222_UpdaeFollower.cs └── src.sln ├── test └── ChitChat.Test │ ├── Class1.cs │ └── ChitChat.Test.csproj ├── .idea └── .idea.ChitChatSolution │ └── .idea │ └── projectSettingsUpdater.xml ├── docker └── DockerCompose │ ├── launchSettings.json │ ├── docker-compose.override.yml │ ├── .dockerignore │ ├── docker-compose.prod.yml │ ├── docker-compose.yml │ └── DockerCompose.dcproj ├── LICENSE ├── .github └── workflows │ └── deploy-prod.yml ├── .editorconfig ├── README.md └── ChitChatSolution.sln /src/ChitChat.Application/Models/Dtos/User/UserProfileDto.cs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/ChitChat.Test/Class1.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Test 2 | { 3 | public class Class1 4 | { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/CommentType.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Enums 2 | { 3 | public enum CommentType 4 | { 5 | Parent, 6 | Reply 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.Application/GlobalUsing.cs: -------------------------------------------------------------------------------- 1 | global using System; 2 | global using System.Collections.Generic; 3 | global using System.Linq; 4 | global using System.Threading.Tasks; 5 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Mapping/IMappingProfileMarker.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Mapping 2 | { 3 | public interface IMappingProfileMarker 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Validators/IValidatorMarker.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Validators 2 | 3 | { 4 | public interface IValidatorMarker 5 | { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/UserRoles.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Enums 2 | { 3 | public enum UserRoles 4 | { 5 | Admin = 0, 6 | User = 1, 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/ConversationType.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Enums 2 | { 3 | public enum ConversationType 4 | { 5 | Person, 6 | Group 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/UserStatus.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Enums 2 | { 3 | public enum UserStatus 4 | { 5 | Private = 0, 6 | Public = 1 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/MediaType.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Enums 2 | { 3 | public enum MediaType 4 | { 5 | Image, 6 | Video, 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/Gender.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Enums 2 | { 3 | public enum Gender 4 | { 5 | Male, 6 | Female, 7 | Others 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/ChitChat.WebAPI.http: -------------------------------------------------------------------------------- 1 | @ChitChat.WebAPI_HostAddress = http://localhost:5251 2 | 3 | GET {{ChitChat.WebAPI_HostAddress}}/weatherforecast/ 4 | Accept: application/json 5 | 6 | ### 7 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/Helpers/HubEnum.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Infrastructure.SignalR.Helpers 2 | { 3 | public enum HubEnum 4 | { 5 | Conversation, 6 | User 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/.sample.env: -------------------------------------------------------------------------------- 1 | SecretKey = 2 | TokenValidityInDays = 3 | RefreshTokenValidityInDays = 4 | Issuer = 5 | Audience = 6 | CloudinaryCloudName = 7 | CloudinaryApiKey = 8 | CloudinaryApiSecret = -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/DatabaseConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.DataAccess 2 | { 3 | public class DatabaseConfiguration 4 | { 5 | public string ConnectionString { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/NotificationType.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Enums 2 | { 3 | public enum NotificationType 4 | { 5 | Post, 6 | Comment, 7 | User 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Identity/ApplicationRole.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Identity; 2 | 3 | namespace ChitChat.Domain.Identity 4 | { 5 | public class ApplicationRole : IdentityRole 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/BaseResponseDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos 2 | { 3 | public abstract class BaseResponseDto 4 | { 5 | public Guid Id { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/GlobalUsing.cs: -------------------------------------------------------------------------------- 1 | global using System; 2 | global using System.Collections.Generic; 3 | global using System.Linq; 4 | global using System.Threading.Tasks; 5 | global using Microsoft.EntityFrameworkCore; 6 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Notification/CreateUserNotificationDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Notification 2 | { 3 | public class CreateUserNotificationDto : CreateNotificationDto 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Post/UpdatePostRequestDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Post 2 | { 3 | public class UpdatePostRequestDto 4 | { 5 | public string Description { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Message/RequestSendMessageDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Message 2 | { 3 | public class RequestSendMessageDto 4 | { 5 | public string MessageText { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Post/Comments/CommentRequestDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Post.Comments 2 | { 3 | public class CommentRequestDto 4 | { 5 | public string Content { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Post/PostUserSearchQueryDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Post 2 | { 3 | public class PostUserSearchQueryDto : PaginationFilter 4 | { 5 | public string? UserId { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/Follow/CreateFollowRequestDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User.Follow 2 | { 3 | public class CreateFollowRequestDto 4 | { 5 | public string FollowerId { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.idea/.idea.ChitChatSolution/.idea/projectSettingsUpdater.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/BaseEntity.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities 2 | { 3 | public abstract class BaseEntity 4 | { 5 | public Guid Id { get; set; } 6 | 7 | public bool IsDeleted { get; set; } = false; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Post/PostSearchQueryDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Post 2 | { 3 | public class PostSearchQueryDto : PaginationFilter 4 | { 5 | public string SearchText { get; set; } = string.Empty; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/Profile/ProfileSearchQueryDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User.Profile 2 | { 3 | public class ProfileSearchQueryDto : PaginationFilter 4 | { 5 | public string SearchText { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/RefreshTokenDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User 2 | { 3 | public class RefreshTokenDto 4 | { 5 | public string RefreshToken { get; set; } 6 | public string AccessToken { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docker/DockerCompose/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "DockerDevEnv": { 4 | "commandName": "DockerCompose", 5 | "commandVersion": "1.0", 6 | "serviceActions": { 7 | "chitchat.webapi": "StartDebugging" 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /test/ChitChat.Test/ChitChat.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/Follow/FollowDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User.Follow 2 | { 3 | public class FollowDto : BaseResponseDto 4 | { 5 | public string UserId { get; set; } 6 | public UserDto User { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Authorization/AuthorizationRequirementBase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace ChitChat.Infrastructure.Authorization 4 | { 5 | public abstract class AuthorizationRequirementBase : IAuthorizationRequirement 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Message/RequestSearchMessageDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Message 2 | { 3 | public class RequestSearchMessageDto 4 | { 5 | public string Text { get; set; } 6 | public Guid ConversationId { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/LoginRequestDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User 2 | { 3 | 4 | public class LoginRequestDto 5 | { 6 | 7 | public string UserName { get; set; } 8 | public string Password { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/NotificationActionEnum.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Enums 2 | { 3 | public enum NotificationActionEnum 4 | { 5 | LIKE_POST, 6 | COMMENT_POST, 7 | REPLY_COMMENT, 8 | USER_FOLLOW, 9 | LIKE_COMMENT 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/GlobalUsing.cs: -------------------------------------------------------------------------------- 1 | global using System; 2 | global using System.Collections.Generic; 3 | global using System.Linq; 4 | global using System.Text; 5 | global using System.Threading.Tasks; 6 | global using Microsoft.EntityFrameworkCore; 7 | global using ChitChat.Domain.Entities; 8 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/MessageStatus.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Enums 2 | { 3 | public static class MessageStatus 4 | { 5 | public static string NORMAL = "normal"; 6 | public static string EDITED = "edited"; 7 | public static string UNSENT = "unsent"; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/GlobalUsing.cs: -------------------------------------------------------------------------------- 1 | global using ChitChat.Domain.Entities; 2 | global using ChitChat.Domain.Entities.PostEntities; 3 | global using System; 4 | global using System.Collections.Generic; 5 | global using System.Linq; 6 | global using ChitChat.Domain.Enums; 7 | global using ChitChat.Domain.Identity; 8 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/UserDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User 2 | { 3 | public class UserDto 4 | { 5 | public string Id { get; set; } 6 | public string DisplayName { get; set; } 7 | public string AvatarUrl { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ChitChat.Application/MachineLearning/Models/PostPredictionModel.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ML.Data; 2 | 3 | namespace ChitChat.Application.MachineLearning.Models 4 | { 5 | public class PostPredictionModel 6 | { 7 | [ColumnName("Score")] 8 | public float Score { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Notification/CreatePostNotificationDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Notification 2 | { 3 | public class CreatePostNotificationDto : CreateNotificationDto 4 | { 5 | public Guid Id { get; set; } = Guid.Empty; 6 | public Guid PostId { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/Helpers/HubEndpoint.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Infrastructure.SignalR.Helpers 2 | { 3 | public static class HubEndpoint 4 | { 5 | public static string ConversationHubEndpoint = "hubs/conversation"; 6 | public static string UserHubEndpoint = "hubs/user"; 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/Interface/IRepositoryFactory.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities; 2 | 3 | namespace ChitChat.DataAccess.Repositories.Interface 4 | { 5 | public interface IRepositoryFactory 6 | { 7 | IBaseRepository GetRepository() where TEntity : BaseEntity; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Helpers/IClaimService.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | 3 | namespace ChitChat.Application.Helpers 4 | { 5 | public interface IClaimService 6 | { 7 | string GetUserId(); 8 | string GetUserName(); 9 | string GetLoginHistoryId(ClaimsIdentity? claimsIdentity = null); 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/SystemEntities/Notification/UserNotification.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.SystemEntities.Notification 2 | { 3 | public class UserNotification : Notification 4 | { 5 | public UserNotification() 6 | { 7 | Type = NotificationType.User.ToString(); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/CloudinaryConfiguration/CloudinarySetting.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Infrastructure.CloudinaryConfigurations 2 | { 3 | public class CloudinarySetting 4 | { 5 | public string CloudName { get; set; } 6 | public string ApiKey { get; set; } 7 | public string ApiSecret { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Post/CreatePost/CreatePostRequestDto.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | 3 | namespace ChitChat.Application.Models.Dtos.Post.CreatePost 4 | { 5 | public class CreatePostRequestDto 6 | { 7 | public List Files { get; set; } 8 | public string Description { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Exceptions/UnauthorizeException.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Exceptions 2 | { 3 | public class UnauthorizeException : ApplicationException 4 | { 5 | public UnauthorizeException(string message) : base(message) 6 | { 7 | Code = Models.ApiResultErrorCodes.Unauthorize; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/MachineLearning/Models/ResponseRecommendationModel.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Post; 2 | 3 | namespace ChitChat.Application.MachineLearning.Models 4 | { 5 | public class ResponseRecommendationModel 6 | { 7 | public float Score { get; set; } 8 | public PostDto? Post { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Common/IAuditedEntity.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Common 2 | { 3 | public interface IAuditedEntity 4 | { 5 | public string CreatedBy { get; set; } 6 | 7 | public DateTime CreatedOn { get; set; } 8 | 9 | public string? UpdatedBy { get; set; } 10 | 11 | public DateTime? UpdatedOn { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Post/CreatePost/CreatePostMediaRequestDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Post.CreatePost 2 | { 3 | public class CreatePostMediaRequestDto 4 | { 5 | public string MediaType { get; set; } 6 | public string MediaUrl { get; set; } 7 | public string Description { get; set; } 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Services/Caching/ICachingService.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Services.Caching 2 | { 3 | public interface ICachingService 4 | { 5 | Task Set(string key, T value); 6 | Task Get(string key); 7 | Task GetOrSetAsync(string key, Func> func); 8 | Task Remove(string key); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/LoginResponseDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User 2 | { 3 | public class LoginResponseDto 4 | { 5 | public UserDto User { get; set; } 6 | public string AccessToken { get; set; } 7 | public string RefreshToken { get; set; } 8 | public Guid LoginHistoryId { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Post/PostMediaDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Post 2 | { 3 | public class PostMediaDto : BaseResponseDto 4 | { 5 | public string MediaType { get; set; } 6 | public string MediaUrl { get; set; } 7 | public int MediaOrder { get; set; } 8 | public string Description { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Exceptions/ForbiddenException.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | 3 | namespace ChitChat.Application.Exceptions 4 | { 5 | public class ForbiddenException : ApplicationException 6 | { 7 | public ForbiddenException(string message) : base(message) 8 | { 9 | Code = ApiResultErrorCodes.Forbidden; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Notification/CreateCommentNotificationDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Notification 2 | { 3 | public class CreateCommentNotificationDto : CreateNotificationDto 4 | { 5 | public Guid Id { get; set; } = Guid.Empty; 6 | public Guid PostId { get; set; } 7 | public Guid CommentId { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/PostEntities/PostDetailTag.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.PostEntities 2 | { 3 | public class PostDetailTag : BaseEntity 4 | { 5 | public Guid PostId { get; set; } 6 | public string Tag { get; set; } 7 | public bool IsDeleted { get; set; } 8 | public Post Post { get; set; } // Navigation property 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Common/LocalizationSettings.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Common 2 | { 3 | public struct LocalizationSettings 4 | { 5 | public static readonly string[] Cultures = new[] { "vi-VN", "en-US" }; 6 | 7 | public static readonly string DefaultCulture = Cultures[0]; 8 | 9 | public static readonly string CultureQueryString = "culture"; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/ChatEntities/ConversationDetail.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.ChatEntities 2 | { 3 | public class ConversationDetail : BaseEntity 4 | { 5 | public Guid ConversationId { get; set; } 6 | public string UserId { get; set; } 7 | public Conversation Conversation { get; set; } 8 | public UserApplication User { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Common/ErrorDescription.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Common 2 | { 3 | public class ErrorDescription 4 | { 5 | 6 | public static readonly string InvalidAccessOrRefreshToken = LocalizedText.New("Invalid access token or refresh token") 7 | .AddDefaultText("Mã truy cập không hợp lệ") 8 | .ToString(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/ChatEntities/Message.cs: -------------------------------------------------------------------------------- 1 | public class Message : BaseAuditedEntity 2 | { 3 | public Guid ConversationId { get; set; } 4 | public string SenderId { get; set; } 5 | public string MessageText { get; set; } 6 | public string Status { get; set; } 7 | public Conversation Conversation { get; set; } 8 | // Navigation property 9 | public UserApplication Sender { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Mapping/MessageProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | 3 | using ChitChat.Application.Models.Dtos.Message; 4 | 5 | namespace ChitChat.Application.Mapping 6 | { 7 | public class MessageProfile : Profile 8 | { 9 | public MessageProfile() 10 | { 11 | CreateMap(); 12 | CreateMap(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ChitChat.Application/SignalR/Interface/IConversationNotificationService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Message; 2 | 3 | namespace ChitChat.Application.SignalR.Interface 4 | { 5 | public interface IConversationNotificationService 6 | { 7 | Task SendMessage(MessageDto message); 8 | Task UpdateMessage(MessageDto message); 9 | Task DeleteMessage(MessageDto message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/LoginHistory.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities 2 | { 3 | public class LoginHistory:BaseEntity 4 | { 5 | public string UserId { get; set; } 6 | public DateTime? LoginTime { get; set; } 7 | public DateTime? LogoutTime { get; set; } 8 | public string? RefreshToken { get; set; } 9 | public DateTime? RefreshTokenExpiryTime { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Exceptions/ConflictException.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | 3 | namespace ChitChat.Application.Exceptions; 4 | public class ConflictException : ApplicationException 5 | { 6 | public ConflictException(string message, bool transactionRollback = true) : base(message) 7 | { 8 | Code = ApiResultErrorCodes.Conflict; 9 | TransactionRollback = transactionRollback; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Helpers/ICloudinaryService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Post; 2 | 3 | using Microsoft.AspNetCore.Http; 4 | 5 | namespace ChitChat.Application.Helpers 6 | { 7 | public interface ICloudinaryService 8 | { 9 | Task> PostMediaToCloudAsync(List files, Guid postId); 10 | Task DeleteMediaFromCloudAsync(Guid postId, Guid postMediaId); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/PostEntities/Reaction/ReactionPost.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.PostEntities.Reaction 2 | { 3 | public class ReactionPost : BaseAuditedEntity 4 | { 5 | public Guid PostId { get; set; } 6 | public string UserId { get; set; } 7 | public Post Post { get; set; } // Navigation property 8 | public UserApplication User { get; set; } // Navigation property 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Localization/ErrorText.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Common; 2 | 3 | namespace ChitChat.Application.Localization 4 | { 5 | public static class ErrorTexts 6 | { 7 | public static readonly string InvalidAccessOrRefreshToken = LocalizedText.New("Invalid access token or refresh token") 8 | .AddDefaultText("Mã truy cập không hợp lệ") 9 | .ToString(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/BaseAuditedEntity.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Common; 2 | 3 | namespace ChitChat.Domain.Entities 4 | { 5 | public abstract class BaseAuditedEntity : BaseEntity, IAuditedEntity 6 | { 7 | public string CreatedBy { get; set; } 8 | 9 | public DateTime CreatedOn { get; set; } 10 | 11 | public string? UpdatedBy { get; set; } 12 | 13 | public DateTime? UpdatedOn { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/PostEntities/Reaction/ReactionComment.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.PostEntities.Reaction 2 | { 3 | public class ReactionComment : BaseAuditedEntity 4 | { 5 | public Guid CommentId { get; set; } 6 | public string UserId { get; set; } 7 | public Comment Comment { get; set; } // Navigation property 8 | public UserApplication User { get; set; } // Navigation property 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/SystemEntities/Notification/PostNotification.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.SystemEntities.Notification 2 | { 3 | public class PostNotification : Notification 4 | { 5 | public Guid PostId { get; set; } 6 | public Post Post { get; set; } // Navigation property 7 | public PostNotification() 8 | { 9 | Type = NotificationType.Post.ToString(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /docker/DockerCompose/docker-compose.override.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | 3 | services: 4 | chitchat.webapi: 5 | environment: 6 | - ASPNETCORE_ENVIRONMENT=Development 7 | - ASPNETCORE_HTTP_PORTS=8080 8 | - ASPNETCORE_HTTPS_PORTS=8081 9 | ports: 10 | - "8080" 11 | - "8081" 12 | volumes: 13 | - ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro 14 | - ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro -------------------------------------------------------------------------------- /src/ChitChat.Application/Mapping/ConversationProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | 3 | using ChitChat.Application.Models.Dtos.Conversation; 4 | 5 | namespace ChitChat.Application.Mapping 6 | { 7 | public class ConversationProfile : Profile 8 | { 9 | public ConversationProfile() 10 | { 11 | CreateMap(); 12 | CreateMap(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Notification/CreateNotificationDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Notification 2 | { 3 | public abstract class CreateNotificationDto 4 | { 5 | public string Type { get; set; } 6 | public string Action { get; set; } 7 | public string Reference { get; set; } 8 | public string LastInteractorUserId { get; set; } 9 | public string ReceiverUserId { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/MachineLearningEntities/UserInteractionModelItem.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.MachineLearning.Models 2 | { 3 | public class UserInteractionModelItem 4 | { 5 | public string UserId { get; set; } 6 | public string PostId { get; set; } 7 | public string PostDescription { get; set; } = string.Empty; 8 | public float ReactionCount { get; set; } 9 | public float TotalPoint { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Exceptions/InvalidModelException.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | 3 | namespace ChitChat.Application.Exceptions; 4 | 5 | [Serializable] 6 | public class InvalidModelException : ApplicationException 7 | { 8 | public InvalidModelException(string message, bool transactionRollback = true) : base(message) 9 | { 10 | Code = ApiResultErrorCodes.ModelValidation; 11 | TransactionRollback = transactionRollback; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Mapping/CommentProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | 3 | using ChitChat.Application.Models.Dtos.Post.Comments; 4 | using ChitChat.Domain.Entities.PostEntities; 5 | 6 | namespace ChitChat.Application.Mapping 7 | { 8 | public class CommentProfile : Profile 9 | { 10 | public CommentProfile() 11 | { 12 | CreateMap(); 13 | CreateMap(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/Interface/IConversationRepository.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.DataAccess.Repositories.Interface; 2 | 3 | namespace ChitChat.DataAccess.Repositories.Interface 4 | { 5 | public interface IConversationRepository : IBaseRepository 6 | { 7 | Task> GetConversationByUserIdAsync(string userId); 8 | Task IsConversationExisted(string userSenderId, string userReceiverId); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/SystemEntities/Notification/CommentNotification.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.SystemEntities.Notification 2 | { 3 | public class CommentNotification : Notification 4 | { 5 | public Guid CommentId { get; set; } 6 | public Comment Comment { get; set; } // Navigation property 7 | public CommentNotification() 8 | { 9 | Type = NotificationType.Comment.ToString(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Validators/Message/RequestMessageValidator.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Message; 2 | 3 | using FluentValidation; 4 | 5 | namespace ChitChat.Application.Validators.Message 6 | { 7 | public class RequestMessageValidator : AbstractValidator 8 | { 9 | public RequestMessageValidator() 10 | { 11 | RuleFor(message => message.MessageText).NotEmpty().NotNull(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/Interface/IUserFollowerRepository.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.DataAccess.Repositories.Interface; 2 | using ChitChat.Domain.Entities.UserEntities; 3 | using ChitChat.Domain.Identity; 4 | 5 | namespace ChitChat.DataAccess.Repositories.Interface 6 | { 7 | public interface IUserFollowerRepository : IBaseRepository 8 | { 9 | Task> GetRecommendedUsersAsync(string currentUserId, int pageSize); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/RegisterationRequestDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User 2 | { 3 | public class RegisterationRequestDto 4 | { 5 | public string Email { get; set; } 6 | public string Password { get; set; } 7 | public string PhoneNumber { get; set; } 8 | public string LastName { get; set; } 9 | public string FirstName { get; set; } 10 | 11 | public string Role { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/PostEntities/PostMedia.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.PostEntities 2 | { 3 | public class PostMedia : BaseEntity 4 | { 5 | public Guid PostId { get; set; } 6 | public string MediaType { get; set; } 7 | public string MediaUrl { get; set; } 8 | public int MediaOrder { get; set; } 9 | public string Description { get; set; } 10 | public Post Post { get; set; } // Navigation property 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Message/MessageDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.Message 2 | { 3 | public class MessageDto : BaseResponseDto 4 | { 5 | public string MessageText { get; set; } 6 | public DateTime CreatedOn { get; set; } 7 | public DateTime UpdateOn { get; set; } 8 | public string SenderId { get; set; } 9 | public Guid ConversationId { get; set; } 10 | public string Status { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/UserEntities/Profile.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.UserEntities 2 | { 3 | public class Profile : BaseEntity 4 | { 5 | public string UserApplicationId { get; set; } 6 | public string? Bio { get; set; } 7 | public DateTime DateOfBirth { get; set; } 8 | public string? Gender { get; set; } 9 | public string SearchData { get; set; } 10 | public UserApplication UserApplication { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/Profile/ProfileRequestDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User.Profile 2 | { 3 | public class ProfileRequestDto 4 | { 5 | public string DisplayName { get; set; } 6 | public string AvatarUrl { get; set; } 7 | public string PhoneNumber { get; set; } 8 | public string? Bio { get; set; } 9 | public DateTime DateOfBirth { get; set; } 10 | public string? Gender { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Application/MachineLearning/Services/Interface/ITrainingModelService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.MachineLearning.Models; 2 | using ChitChat.Domain.Entities.PostEntities; 3 | 4 | namespace ChitChat.Application.MachineLearning.Services.Interface 5 | { 6 | public interface ITrainingModelService 7 | { 8 | List GetRecommendationPostModel(string userId, List userInteractions, List postReccomendation); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/UserEntities/UserFollower.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.UserEntities 2 | { 3 | public class UserFollower : BaseEntity 4 | { 5 | public string UserId { get; set; } 6 | public string FollowerId { get; set; } 7 | public DateTime FollowedDate { get; set; } 8 | 9 | public UserApplication User { get; set; } // Navigation property 10 | public UserApplication Follower { get; set; } // Navigation property 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/Interface/IUserInteractionRepository.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.MachineLearning.Models; 2 | using ChitChat.DataAccess.Repositories.Interface; 3 | using ChitChat.Domain.Entities.SystemEntities; 4 | 5 | namespace ChitChat.DataAccess.Repositories.Interface 6 | { 7 | public interface IUserInteractionRepository : IBaseRepository 8 | { 9 | Task> GetUserInteractionModelForTraining(int PageSize); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/Helpers/HubRoom.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Infrastructure.SignalR.Helpers 2 | { 3 | public class HubRoom 4 | { 5 | public static string ConversationHubJoinRoom(Guid conversationId) 6 | { 7 | return $"{HubEnum.Conversation.ToString()}: ${conversationId}"; 8 | } 9 | public static string UserHubJoinRoom(string userId) 10 | { 11 | return $"{HubEnum.User.ToString()}: ${userId}"; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Conversation/ConversationDetailDto.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Message; 2 | using ChitChat.Application.Models.Dtos.User; 3 | 4 | namespace ChitChat.Application.Models.Dtos.Conversation 5 | { 6 | public class ConversationDetailDto : BaseResponseDto 7 | { 8 | public List UserReceivers { get; set; } 9 | public List UserReceiverIds { get; set; } 10 | public List Messages { get; set; } 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Exceptions/ApplicationException.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | 3 | namespace ChitChat.Application.Exceptions 4 | { 5 | [Serializable] 6 | public abstract class ApplicationException : Exception 7 | { 8 | public ApiResultErrorCodes Code { get; protected set; } 9 | 10 | public bool TransactionRollback { get; protected set; } = true; 11 | 12 | public ApplicationException(string message) : base(message) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Services/Caching/CacheEntryOptions.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Services.Caching 2 | { 3 | public class CacheEntryOptions 4 | { 5 | public TimeSpan SlidingExpiration { get; set; } 6 | public TimeSpan AbsoluteExpirationRelativeToNow { get; set; } 7 | 8 | public static CacheEntryOptions Default = new() 9 | { 10 | AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1), 11 | SlidingExpiration = TimeSpan.FromHours(1) 12 | }; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Services/Interface/IUserService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.User; 2 | 3 | namespace ChitChat.Application.Services.Interface 4 | { 5 | public interface IUserService 6 | { 7 | Task RegisterAsync(RegisterationRequestDto registerationRequestDto); 8 | Task LoginAsync(LoginRequestDto loginRequestDto); 9 | Task RefreshTokenAsync(RefreshTokenDto refreshTokenDto); 10 | Task LogoutAsync(Guid loginHistoryId); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Helpers/ITokenService.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | 3 | using ChitChat.Domain.Entities; 4 | using ChitChat.Domain.Identity; 5 | 6 | namespace ChitChat.Application.Helpers 7 | { 8 | public interface ITokenService 9 | { 10 | (string token, int validDays) GenerateRefreshToken(); 11 | 12 | Task GetPrincipalFromExpiredToken(string? token); 13 | 14 | string GenerateAccessToken(UserApplication user, IEnumerable roles, LoginHistory loginHistory); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Validators/Message/RequestSearchMessageValidator.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Message; 2 | using FluentValidation; 3 | 4 | namespace ChitChat.Application.Validators.Message 5 | { 6 | public class RequestSearchMessageValidator : AbstractValidator 7 | { 8 | public RequestSearchMessageValidator() 9 | { 10 | RuleFor(p => p.Text).NotNull().NotEmpty(); 11 | RuleFor(p => p.ConversationId).NotNull().NotEmpty(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /docker/DockerCompose/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md 26 | !**/.gitignore 27 | !.git/HEAD 28 | !.git/config 29 | !.git/packed-refs 30 | !.git/refs/heads/** -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Conversation/ConversationDto.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Message; 2 | using ChitChat.Application.Models.Dtos.User; 3 | 4 | namespace ChitChat.Application.Models.Dtos.Conversation 5 | { 6 | public class ConversationDto : BaseResponseDto 7 | { 8 | public List UserReceivers { get; set; } 9 | public MessageDto? LastMessage { get; set; } 10 | public List UserReceiverIds { get; set; } 11 | public bool IsSeen { get; set; } = false; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/LoginHistoryConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class LoginHistoryConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder modelBuilder) 10 | { 11 | // Conversation Detail 12 | modelBuilder 13 | .HasKey(c => c.Id); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/SystemEntities/UserInteraction.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.SystemEntities 2 | { 3 | public class UserInteraction : BaseEntity 4 | { 5 | public string UserId { get; set; } 6 | public Guid PostId { get; set; } 7 | public InteractionType InteractionType { get; set; } 8 | public DateTime InteractionDate { get; set; } 9 | 10 | public UserApplication User { get; set; } // Navigation property 11 | public Post Post { get; set; } // Navigation property 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Services/Interface/IProfileService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.User.Profile; 2 | 3 | namespace ChitChat.Application.Services.Interface 4 | { 5 | public interface IProfileService 6 | { 7 | Task> GetAllProfilesAsync(ProfileSearchQueryDto query); 8 | Task GetProfileByIdAsync(Guid userId); 9 | Task CreateProfileAsync(ProfileRequestDto request); 10 | Task UpdateProfileAsync(Guid userId, ProfileRequestDto request); 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Common/PaginationResponse.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Common 2 | { 3 | public class PaginationResponse 4 | { 5 | public PaginationResponse() 6 | { 7 | Items = new List(); 8 | } 9 | 10 | public int TotalCount { get; set; } 11 | 12 | public IEnumerable Items { get; set; } 13 | 14 | public int PageIndex { get; set; } 15 | 16 | public int PageSize { get; set; } 17 | 18 | public virtual List SortableFields { get; set; } = new(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Services/Interface/IFollowService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | using ChitChat.Application.Models.Dtos.User.Follow; 3 | 4 | namespace ChitChat.Application.Services.Interface 5 | { 6 | public interface IFollowService 7 | { 8 | Task ToggleFollowAsync(string otherUserId); 9 | Task> GetAllFollowingsAsync(string userId); 10 | Task> GetAllFollowerAsync(string userId); 11 | Task> GetRecommendFollowAsync(PaginationFilter filter); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Common/NotificationRefText.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Common 2 | { 3 | public static class NotificationRefText 4 | { 5 | public static string PostRef(Guid postId) 6 | { 7 | return $"Post/{postId}"; 8 | } 9 | public static string UserRef(string userId) 10 | { 11 | return $"User/{userId}"; 12 | } 13 | public static string CommentRef(Guid postId, Guid commentId) 14 | { 15 | return $"Post/{postId}/Comment/{commentId}"; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/ConfigSetting/JWTConfigSetting.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Infrastructure.ConfigSetting 2 | { 3 | public class JWTConfigSetting 4 | { 5 | public string SecretKey { get; set; } = string.Empty; 6 | public int TokenValidityInDays { get; set; } = 0; 7 | public int RefreshTokenValidityInDays { get; set; } = 0; 8 | public string Issuer { get; set; } = string.Empty; 9 | public string Audience { get; set; } = string.Empty; 10 | public static readonly string LoginHistoryIdClaimType = "LoginId"; 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/UserEntities/UserFollowerRequest.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.UserEntities 2 | { 3 | public class UserFollowerRequest:BaseEntity 4 | { 5 | public string UserId { get; set; } 6 | public string FollowerId { get; set; } 7 | public DateTime RequestDate { get; set; } 8 | public string Status { get; set; } 9 | public bool IsDeleted { get; set; } 10 | 11 | public UserApplication User { get; set; } // Navigation property 12 | public UserApplication Follower { get; set; } // Navigation property 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Identity/UserApplication.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | using Microsoft.AspNetCore.Identity; 4 | 5 | namespace ChitChat.Domain.Identity 6 | { 7 | public class UserApplication : IdentityUser 8 | { 9 | public DateTime LastLogin { get; set; } 10 | [MaxLength(255)] 11 | public string DisplayName { get; set; } 12 | [MaxLength(255)] 13 | public string? AvatarUrl { get; set; } 14 | public string? MediaAvatarType { get; set; } 15 | public UserStatus UserStatus { get; set; } 16 | 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/PaginationFilter.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models 2 | { 3 | public class PaginationFilter 4 | { 5 | public int PageIndex { get; set; } 6 | public int PageSize { get; set; } 7 | public PaginationFilter() 8 | { 9 | this.PageIndex = 0; 10 | this.PageSize = 10; 11 | } 12 | public PaginationFilter(int pageIndex, int pageSize) 13 | { 14 | this.PageIndex = pageIndex < 0 ? 0 : pageIndex; 15 | this.PageSize = pageSize > 100 ? 100 : pageSize; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/User/Profile/ProfileDto.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models.Dtos.User.Profile 2 | { 3 | public class ProfileDto 4 | { 5 | public Guid Id { get; set; } 6 | public string DisplayName { get; set; } 7 | public string AvatarUrl { get; set; } 8 | public string Email { get; set; } 9 | public string PhoneNumber { get; set; } 10 | public string? Bio { get; set; } 11 | public DateTime DateOfBirth { get; set; } 12 | public string? Gender { get; set; } 13 | public bool IsFollowed { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Caching/CachingRegistrations.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Services.Caching; 2 | 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace ChitChat.Infrastructure.Caching 7 | { 8 | public static class CachingRegistrations 9 | { 10 | public static WebApplicationBuilder AddCaching(this WebApplicationBuilder builder) 11 | { 12 | builder.Services 13 | .AddMemoryCache() 14 | .AddSingleton(); 15 | return builder; 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/ChatEntities/Conversation.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.ChatEntities; 2 | 3 | public class Conversation : BaseAuditedEntity 4 | { 5 | public Guid? LastMessageId { get; set; } 6 | //public string userId1 { get; set; } 7 | //public string userId2 { get; set; } 8 | 9 | public Message? LastMessage { get; set; } 10 | public bool IsSeen { get; set; } 11 | public int NumOfUser { get; set; } 12 | public string ConversationType { get; set; } 13 | 14 | public IEnumerable Messages { get; set; } 15 | public IEnumerable ConversationDetails { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/SystemEntities/Notification/Notification.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.SystemEntities.Notification 2 | { 3 | public abstract class Notification : BaseAuditedEntity 4 | { 5 | public string Type { get; set; } 6 | public string Action { get; set; } 7 | public string Reference { get; set; } 8 | public string LastInteractorUserId { get; set; } 9 | public string ReceiverUserId { get; set; } 10 | public UserApplication LastInteractorUser { get; set; } // Navigation property 11 | public UserApplication ReceiverUser { get; set; } // Navigation property 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/ProfileConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.UserEntities; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class ProfileConfiguration : IEntityTypeConfiguration 8 | { 9 | public ProfileConfiguration() { } 10 | 11 | public void Configure(EntityTypeBuilder builder) 12 | { 13 | builder 14 | .HasOne(p => p.UserApplication) 15 | .WithOne() 16 | .HasForeignKey(p => p.UserApplicationId); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Post/Comments/CommentDto.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.User; 2 | 3 | namespace ChitChat.Application.Models.Dtos.Post.Comments 4 | { 5 | public class CommentDto : BaseResponseDto 6 | { 7 | public Guid PostId { get; set; } 8 | public string UserPostedId { get; set; } 9 | public string Content { get; set; } 10 | public List ReplyComments { get; set; } 11 | public UserDto UserPosted { get; set; } 12 | public bool IsReacted { get; set; } 13 | public int ReactionCount { get; set; } 14 | public DateTime CreatedOn { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docker/DockerCompose/docker-compose.prod.yml: -------------------------------------------------------------------------------- 1 | services: 2 | chitchat.webapi: 3 | image: ${DOCKER_REGISTRY-}chitchatwebapi 4 | build: 5 | context: ../../ 6 | dockerfile: src/ChitChat.WebAPI/Dockerfile 7 | ports: 8 | - "80:8080" 9 | - "443:8081" 10 | environment: 11 | - ASPNETCORE_ENVIRONMENT=Production 12 | - ASPNETCORE_Kestrel__Certificates__Default__Path=/app/chitchat.pfx 13 | - ASPNETCORE_Kestrel__Certificates__Default__Password=chitchat 14 | env_file: 15 | - ../../src/ChitChat.WebAPI/.env 16 | networks: 17 | - productnetwork 18 | restart: unless-stopped 19 | 20 | networks: 21 | productnetwork: 22 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Validators/Post/CreatePostMediaRequestValidator.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Post.CreatePost; 2 | using ChitChat.Domain.Enums; 3 | 4 | using FluentValidation; 5 | 6 | namespace ChitChat.Application.Validators.Post 7 | { 8 | public class CreatePostMediaRequestValidator : AbstractValidator 9 | { 10 | public CreatePostMediaRequestValidator() 11 | { 12 | RuleFor(p => p.MediaType) 13 | .Must(value => Enum.TryParse(typeof(MediaType), value?.ToString(), out _)) 14 | .WithMessage("Media type must be a valid enum value"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/PostEntities/Post.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.PostEntities 2 | { 3 | public class Post : BaseAuditedEntity 4 | { 5 | public string UserId { get; set; } 6 | public string Description { get; set; } 7 | public int CommentCount { get; set; } = 0; 8 | public int ReactionCount { get; set; } = 0; 9 | public UserApplication User { get; set; } // Navigation property 10 | public ICollection Comments { get; set; } 11 | public ICollection PostDetailTags { get; set; } 12 | public ICollection PostMedias { get; set; } 13 | 14 | 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/ChitChat.Application/SignalR/Interface/IUserNotificationService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Conversation; 2 | using ChitChat.Application.Models.Dtos.Notification; 3 | 4 | namespace ChitChat.Application.SignalR.Interface 5 | { 6 | public interface IUserNotificationService 7 | { 8 | Task UpdateConversation(ConversationDto conversation, string userSenderId); 9 | Task AddConversation(ConversationDto conversation, string userSenderId); 10 | Task DeleteConversation(ConversationDto conversation, string userSenderId); 11 | Task NewNotification(NotificationDto notificationDto); 12 | Task UpdateNotification(NotificationDto notificationDto); 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Common/UnixTimestampConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace ChitChat.Domain.Common 5 | { 6 | public class UnixTimestampConverter : JsonConverter 7 | { 8 | public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 9 | { 10 | return DateTimeOffset.FromUnixTimeSeconds(reader.GetInt64()).UtcDateTime; 11 | } 12 | 13 | public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) 14 | { 15 | writer.WriteNumberValue(new DateTimeOffset(value).ToUnixTimeSeconds()); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/PostMediaConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.PostEntities; 2 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 3 | 4 | namespace ChitChat.DataAccess.Configurations 5 | { 6 | public class PostMediaConfiguration : IEntityTypeConfiguration 7 | { 8 | public void Configure(EntityTypeBuilder modelBuilder) 9 | { 10 | // PostMedia 11 | modelBuilder.HasKey(pm => pm.Id); 12 | 13 | modelBuilder 14 | .HasOne(pm => pm.Post) 15 | .WithMany(p => p.PostMedias) 16 | .HasForeignKey(pm => pm.PostId) 17 | .OnDelete(DeleteBehavior.Cascade); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Entities/PostEntities/Comment.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Entities.PostEntities 2 | { 3 | public class Comment : BaseAuditedEntity 4 | { 5 | public Guid PostId { get; set; } 6 | public Guid? ParentCommentId { get; set; } 7 | public string UserPostedId { get; set; } 8 | public string Content { get; set; } 9 | public int ReactionCount { get; set; } = 0; 10 | public string CommentType { get; set; } 11 | public Post Post { get; set; } // Navigation property 12 | public Comment ParentComment { get; set; } // Navigation property 13 | public List ReplyComments { get; set; } 14 | public UserApplication UserPosted { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/RepositoryFactory.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.DataAccess.Repositories.Interface; 2 | using ChitChat.Domain.Entities; 3 | 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace ChitChat.DataAccess.Repositories 7 | { 8 | public class RepositoryFactory : IRepositoryFactory 9 | { 10 | private readonly IServiceProvider _serviceProvider; 11 | 12 | public RepositoryFactory(IServiceProvider serviceProvider) 13 | { 14 | this._serviceProvider = serviceProvider; 15 | } 16 | 17 | public IBaseRepository GetRepository() where TEntity : BaseEntity 18 | => this._serviceProvider.GetRequiredService>(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/Hubs/InterfaceClient/IConversationClient.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Message; 2 | 3 | namespace ChitChat.Infrastructure.SignalR.Hubs.InterfaceClient 4 | { 5 | public interface IConversationClient 6 | { 7 | Task ConversationJoined(string message); 8 | Task NewMessage(MessageDto message); 9 | Task UpdateMessage(MessageDto message); 10 | Task DeleteMessage(MessageDto message); 11 | 12 | // Calling 13 | Task ReceiveOffer(string connectionId, string sdp); 14 | Task ReceiveAnswer(string connectionId, string sdp); 15 | Task ReceiveIceCandidate(string connectionId, string candidate); 16 | Task ReceiveCall(Guid ConversationId); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/Hubs/InterfaceClient/IUserClient.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Conversation; 2 | using ChitChat.Application.Models.Dtos.Notification; 3 | 4 | namespace ChitChat.Infrastructure.SignalR.Hubs.InterfaceClient 5 | { 6 | public interface IUserClient 7 | { 8 | Task UpdateConversation(ConversationDto conversation); 9 | Task AddConversation(ConversationDto conversation); 10 | Task DeleteConversation(ConversationDto conversation); 11 | // Other events 12 | Task NotifyNewFollower(string followerId, string followedUserId); 13 | Task AddNotification(NotificationDto notification); 14 | Task UpdateNotification(NotificationDto notification); 15 | 16 | 17 | 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "JWTConfigSetting": { 10 | "SecretKey": "55eaf009a21fa3c5fce7096ca201f24734df43de88484d7a017a8eb389343146df02cf096f0b", 11 | "TokenValidityInDays": 5, 12 | "RefreshTokenValidityInDays": 30, 13 | "Issuer": "Issuer", 14 | "Audience": "Audience" 15 | }, 16 | "Database": { 17 | "ConnectionStrings": { 18 | "LocalConnection": "Server=mysql;Database=chitchatdb;User=root;Password=Password12345!;", 19 | "AWSConnection": "Server=mysql-chit-chat.crska2kww12j.ap-southeast-1.rds.amazonaws.com;Port=3306;Database=ChitChatDB;User=admin;Password=123admin;" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Validators/Post/CreatePostRequestValidator.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Post.CreatePost; 2 | 3 | using FluentValidation; 4 | 5 | namespace ChitChat.Application.Validators.Post 6 | { 7 | public class CreatePostRequestValidator : AbstractValidator 8 | { 9 | public CreatePostRequestValidator() 10 | { 11 | RuleFor(x => x.Description) 12 | .NotEmpty() 13 | .WithMessage("Description is required") 14 | .MaximumLength(500) 15 | .WithMessage("Description must not exceed 100 characters"); 16 | RuleFor(x => x.Files) 17 | .NotEmpty() 18 | .WithMessage("File is required"); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/ConversationDetailConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.ChatEntities; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class ConversationDetailConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder modelBuilder) 10 | { 11 | // Conversation Detail 12 | modelBuilder 13 | .HasKey(c => c.Id); 14 | 15 | modelBuilder 16 | .HasOne(m => m.Conversation) 17 | .WithMany(c => c.ConversationDetails) 18 | .HasForeignKey(m => m.ConversationId) 19 | ; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Post/PostDto.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Post.Comments; 2 | using ChitChat.Application.Models.Dtos.User; 3 | 4 | namespace ChitChat.Application.Models.Dtos.Post 5 | { 6 | 7 | public class PostDto : BaseResponseDto 8 | { 9 | public string Description { get; set; } = ""; 10 | public int ReactionCount { get; set; } 11 | public int CommentCount { get; set; } 12 | public ICollection Comments { get; set; } 13 | public ICollection PostMedias { get; set; } 14 | public DateTime CreatedOn { get; set; } 15 | public DateTime UpdatedOn { get; set; } 16 | public bool IsReacted { get; set; } 17 | public UserDto UserPosted 18 | { get; set; } 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "JWTConfigSetting": { 10 | "SecretKey": "55eaf009a21fa3c5fce7096ca201f24734df43de88484d7a017a8eb389343146df02cf096f0b", 11 | "TokenValidityInDays": 5, 12 | "RefreshTokenValidityInDays": 30, 13 | "Issuer": "Issuer", 14 | "Audience": "Audience" 15 | }, 16 | "Database": { 17 | "ConnectionStrings": { 18 | "LocalConnection": "Server=mysql;Database=chitchatdb;User=root;Password=Password12345!;", 19 | "AWSConnection": "Server=mysql-chit-chat.crska2kww12j.ap-southeast-1.rds.amazonaws.com;Port=3306;Database=ChitChatDBDev;User=admin;Password=123admin;" 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/PostDetailTagConfiguration).cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.PostEntities; 2 | 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 5 | 6 | namespace ChitChat.DataAccess.Configurations 7 | { 8 | public class PostDetailTagConfiguration : IEntityTypeConfiguration 9 | { 10 | public void Configure(EntityTypeBuilder modelBuilder) 11 | { 12 | // PostDetailTag 13 | modelBuilder.HasKey(pdt => pdt.Id); 14 | 15 | modelBuilder 16 | .HasOne(pdt => pdt.Post) 17 | .WithMany(p => p.PostDetailTags) 18 | .HasForeignKey(pdt => pdt.PostId) 19 | .OnDelete(DeleteBehavior.Cascade); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/Notification/UserNotificationConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.SystemEntities.Notification; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations.Notification 6 | { 7 | public class UserNotificationConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(n => n.Id); 12 | builder.HasOne(n => n.ReceiverUser) 13 | .WithMany() 14 | .HasForeignKey(n => n.ReceiverUserId); 15 | builder.HasOne(n => n.LastInteractorUser) 16 | .WithMany() 17 | .HasForeignKey(n => n.LastInteractorUserId); 18 | 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docker/DockerCompose/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.4" 2 | 3 | services: 4 | chitchat.webapi: 5 | image: ${DOCKER_REGISTRY-}chitchatwebapi 6 | build: 7 | context: ../../ 8 | dockerfile: src/ChitChat.WebAPI/Dockerfile 9 | ports: 10 | - "8080:8080" 11 | - "8081:8081" 12 | depends_on: 13 | - mysql 14 | environment: 15 | - ASPNETCORE_ENVIRONMENT=Development 16 | networks: 17 | - productnetwork 18 | restart: on-failure 19 | 20 | mysql: 21 | image: mysql:8.0.39 22 | environment: 23 | MYSQL_ROOT_PASSWORD: "Password12345!" 24 | MYSQL_DATABASE: chitchatdb 25 | ports: 26 | - "3306:3306" 27 | volumes: 28 | - mysqlvolumn:/var/lib/mysql 29 | networks: 30 | - productnetwork 31 | 32 | networks: 33 | productnetwork: 34 | 35 | volumes: 36 | mysqlvolumn: 37 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Exceptions/ResourceNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.Serialization; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ChitChat.Domain.Exceptions 9 | { 10 | [Serializable] 11 | public class ResourceNotFoundException : Exception 12 | { 13 | public ResourceNotFoundException() { } 14 | 15 | public ResourceNotFoundException(Type type) : base($"{type} is missing") { } 16 | 17 | protected ResourceNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { } 18 | 19 | public ResourceNotFoundException(string? message) : base(message) { } 20 | 21 | public ResourceNotFoundException(string? message, Exception? innerException) : base(message, innerException) { } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/ChitChat.Domain.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | ChitChat.Domain 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/MessageConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 2 | 3 | namespace ChitChat.DataAccess.Configurations 4 | { 5 | public class MessageConfiguration : IEntityTypeConfiguration 6 | { 7 | public void Configure(EntityTypeBuilder modelBuilder) 8 | { 9 | // Configure primary key 10 | modelBuilder.HasKey(m => m.Id); 11 | 12 | // Configure relationship with Conversation 13 | modelBuilder 14 | .HasOne(m => m.Conversation) 15 | .WithMany(c => c.Messages) 16 | .HasForeignKey(m => m.ConversationId); 17 | 18 | // Configure relationship with Sender 19 | modelBuilder 20 | .HasOne(m => m.Sender) 21 | .WithMany() 22 | .HasForeignKey(m => m.SenderId); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Services/Interface/INotificationService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | using ChitChat.Application.Models.Dtos.Notification; 3 | 4 | namespace ChitChat.Application.Services.Interface 5 | { 6 | public interface INotificationService 7 | { 8 | Task> GetAllNotificationsAsync(PaginationFilter filter); 9 | /* Task CreateOrUpdateNotificationAsync(NotificationDto notificationDto, List notificationUser); 10 | Task CreateNotificationAsync(NotificationDto notificationDto, List notificationUser);*/ 11 | Task CreateOrUpdatePostNotificationAsync(CreatePostNotificationDto createPostNotificationDto); 12 | Task CreateOrUpdateUserNotificationAsync(CreateUserNotificationDto createUserNotification); 13 | Task CreateOrUpdateCommentNotificationAsync(CreateCommentNotificationDto createUserNotification); 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/Hubs/UserHub.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Infrastructure.SignalR.Helpers; 2 | using ChitChat.Infrastructure.SignalR.Hubs.InterfaceClient; 3 | 4 | using Microsoft.AspNetCore.SignalR; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace ChitChat.Infrastructure.SignalR.Hubs 8 | { 9 | public class UserHub : Hub 10 | { 11 | ILogger _logger; 12 | public UserHub(ILogger logger) 13 | { 14 | _logger = logger; 15 | } 16 | public override Task OnConnectedAsync() 17 | { 18 | _logger.LogInformation($"User {Context.ConnectionId} has joined to hubs"); 19 | return base.OnConnectedAsync(); 20 | } 21 | public async Task JoinUserHub(string userId) 22 | { 23 | await Groups.AddToGroupAsync(Context.ConnectionId, HubRoom.UserHubJoinRoom(userId)); 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/Dtos/Notification/NotificationDto.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Post; 2 | using ChitChat.Application.Models.Dtos.Post.Comments; 3 | using ChitChat.Application.Models.Dtos.User; 4 | 5 | namespace ChitChat.Application.Models.Dtos.Notification 6 | { 7 | public class NotificationDto : BaseResponseDto 8 | { 9 | public string Content { get; set; } 10 | public string Type { get; set; } 11 | public string Reference { get; set; } 12 | public string Action { get; set; } 13 | public string ReceiverUserId { get; set; } 14 | public PostDto? Post { get; set; } // Navigation property 15 | public CommentDto? Comment { get; set; } // Navigation property 16 | public UserDto LastInteractorUser { get; set; } // Navigation property 17 | public DateTime CreatedOn { get; set; } 18 | public DateTime UpdatedOn { get; set; } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/ReactionPostConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.PostEntities.Reaction; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class ReactionPostConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder modelBuilder) 10 | { 11 | modelBuilder 12 | .HasKey(rp => new { rp.PostId, rp.UserId }); 13 | 14 | modelBuilder 15 | .HasOne(rp => rp.Post) 16 | .WithMany() 17 | .HasForeignKey(rp => rp.PostId) 18 | .OnDelete(DeleteBehavior.Cascade); 19 | 20 | modelBuilder 21 | .HasOne(rp => rp.User) 22 | .WithMany() 23 | .HasForeignKey(rp => rp.UserId); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/UserInteractionConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.SystemEntities; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class UserInteractionConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder modelBuilder) 10 | { 11 | // UserInteraction 12 | modelBuilder 13 | .HasKey(ui => ui.Id); 14 | 15 | modelBuilder 16 | .HasOne(ui => ui.User) 17 | .WithMany() 18 | .HasForeignKey(ui => ui.UserId); 19 | 20 | modelBuilder 21 | .HasOne(ui => ui.Post) 22 | .WithMany() 23 | .HasForeignKey(ui => ui.PostId) 24 | .OnDelete(DeleteBehavior.Restrict); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Validators/User/ProfileRequestValidator.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.User.Profile; 2 | using ChitChat.Domain.Enums; 3 | 4 | using FluentValidation; 5 | 6 | namespace ChitChat.Application.Validators.User 7 | { 8 | public class ProfileRequestValidator : AbstractValidator 9 | { 10 | public ProfileRequestValidator() 11 | { 12 | RuleFor(profile => profile.Gender) 13 | .NotNull() 14 | .NotEmpty() 15 | .Must(gender => Enum.TryParse(typeof(Gender), gender, true, out _)) 16 | .WithMessage("Invalid gender value. Allowed values are: Male, Female, Other."); 17 | RuleFor(profile => profile.Bio) 18 | .NotNull() 19 | .NotEmpty(); 20 | RuleFor(profile => profile.DateOfBirth) 21 | .NotEmpty() 22 | .NotNull(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/ReactionCommentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.PostEntities.Reaction; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class ReactionCommentConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder modelBuilder) 10 | { 11 | modelBuilder 12 | .HasKey(rc => new { rc.CommentId, rc.UserId }); 13 | 14 | modelBuilder 15 | .HasOne(rc => rc.Comment) 16 | .WithMany() 17 | .HasForeignKey(rc => rc.CommentId) 18 | .OnDelete(DeleteBehavior.Cascade); 19 | 20 | modelBuilder 21 | .HasOne(rc => rc.User) 22 | .WithMany() 23 | .HasForeignKey(rc => rc.UserId); 24 | 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Localization/ValidationText.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Common; 2 | 3 | namespace ChitChat.Application.Localization 4 | { 5 | public static class ValidationTexts 6 | { 7 | public static readonly LocalizedText NotFound = LocalizedText.New("{0} {1} not found").AddDefaultText("{0} {1} không tồn tại."); 8 | public static readonly LocalizedText Conflict = LocalizedText.New("{0} {1} is already existed").AddDefaultText("{0} với {1} đã tồn tại."); 9 | public static readonly LocalizedText NotValidate = LocalizedText.New("{0} {1} is not validated").AddDefaultText("{0} với {1} không hợp lệ."); 10 | public static readonly LocalizedText Forbidden = LocalizedText.New("Access to {0} {1} is forbidden").AddDefaultText("Quyền truy cập {0} với {1} bị cấm."); 11 | public static readonly LocalizedText Unauthorized = LocalizedText.New("Unauthorized access to {0} {1}").AddDefaultText("Truy cập trái phép {0} với {1}."); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Mapping/PostProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | 3 | using ChitChat.Application.MachineLearning.Models; 4 | using ChitChat.Application.Models.Dtos.Post; 5 | using ChitChat.Application.Models.Dtos.Post.CreatePost; 6 | using ChitChat.Domain.Entities.PostEntities; 7 | 8 | namespace ChitChat.Application.Mapping 9 | { 10 | public class PostProfile : Profile 11 | { 12 | public PostProfile() 13 | { 14 | CreateMap().ForMember(dest => dest.UserPosted, opt => opt.MapFrom(src => src.User)); 15 | CreateMap(); 16 | CreateMap(); 17 | CreateMap(); 18 | CreateMap(); 19 | CreateMap(); 20 | CreateMap() 21 | .ConvertUsing(src => src.Post); 22 | 23 | // 24 | 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/Notification/PostNotificationConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.SystemEntities.Notification; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations.Notification 6 | { 7 | public class PostNotificationConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(n => n.Id); 12 | builder.HasOne(n => n.ReceiverUser) 13 | .WithMany() 14 | .HasForeignKey(n => n.ReceiverUserId); 15 | builder.HasOne(n => n.LastInteractorUser) 16 | .WithMany() 17 | .HasForeignKey(n => n.LastInteractorUserId); 18 | builder.HasOne(n => n.Post) 19 | .WithMany() 20 | .HasForeignKey(n => n.PostId) 21 | .OnDelete(DeleteBehavior.Cascade); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Logging/SerilogOptions.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Infrastructure.Logging 2 | { 3 | public class SerilogOptions 4 | { 5 | public bool Enabled { get; set; } 6 | 7 | public bool LogToConsole { get; set; } 8 | 9 | public long FileSizeLimitInBytes { get; set; } = 1024 * 2; //2Mb 10 | 11 | public int FlushFileToDiskInSeconds { get; set; } = 1; 12 | 13 | public SerilogSeqOptions? SeqOptions { get; set; } 14 | 15 | public SerilogApplicationInsightsOptions? ApplicationInsightsOptions { get; set; } 16 | } 17 | 18 | 19 | public class SerilogSeqOptions 20 | { 21 | public bool Enabled { set; get; } 22 | public string SeqUrl { get; set; } = string.Empty; 23 | public string SeqApiKey { get; set; } = string.Empty; 24 | } 25 | 26 | public class SerilogApplicationInsightsOptions 27 | { 28 | public bool Enabled { set; get; } 29 | public string ConnectionString { get; set; } = string.Empty; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Exceptions/NotFoundException.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Localization; 2 | using ChitChat.Application.Models; 3 | 4 | namespace ChitChat.Application.Exceptions 5 | { 6 | public class NotFoundException : ApplicationException 7 | { 8 | public NotFoundException(Guid id, Type type) : base(ValidationTexts.NotFound.Format(type.Name, id.ToString())) 9 | { 10 | Code = ApiResultErrorCodes.NotFound; 11 | } 12 | 13 | public NotFoundException(string code, Type type) : base(ValidationTexts.NotFound.Format(type.Name, code)) 14 | { 15 | Code = ApiResultErrorCodes.NotFound; 16 | } 17 | 18 | public NotFoundException(string message) : base(message) 19 | { 20 | Code = ApiResultErrorCodes.NotFound; 21 | } 22 | 23 | public NotFoundException(int count, Type type) : base(ValidationTexts.NotFound.Format(count, type.Name)) 24 | { 25 | Code = ApiResultErrorCodes.NotFound; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/Notification/CommentNotificationConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.SystemEntities.Notification; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations.Notification 6 | { 7 | public class CommentNotificationConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.HasKey(n => n.Id); 12 | builder.HasOne(n => n.ReceiverUser) 13 | .WithMany() 14 | .HasForeignKey(n => n.ReceiverUserId); 15 | builder.HasOne(n => n.LastInteractorUser) 16 | .WithMany() 17 | .HasForeignKey(n => n.LastInteractorUserId); 18 | builder.HasOne(n => n.Comment) 19 | .WithMany() 20 | .HasForeignKey(n => n.CommentId) 21 | .OnDelete(DeleteBehavior.Cascade); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Enums/InteractionType.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.SystemEntities; 2 | 3 | namespace ChitChat.Domain.Enums 4 | { 5 | public enum InteractionType 6 | { 7 | Comment = 1, 8 | View = 2, 9 | Like = 3, 10 | Unlike = 4 11 | } 12 | public static class InteractionTypePoint 13 | { 14 | public static int GetInteractionPoint(UserInteraction userInteraction) 15 | { 16 | int basePoint = userInteraction.InteractionType switch 17 | { 18 | InteractionType.Comment => 5, 19 | InteractionType.View => 1, 20 | InteractionType.Like => 3, 21 | InteractionType.Unlike => -3, 22 | _ => 0 23 | }; 24 | 25 | TimeSpan timeElapsed = DateTime.Now - userInteraction.InteractionDate; 26 | double decayFactor = Math.Max(0.3, 1.0 - timeElapsed.TotalDays / 60); // Giảm dần trong 60 ngày 27 | return (int)(basePoint * decayFactor); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/UserFollowerConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.UserEntities; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class UserFollowerConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder modelBuilder) 10 | { 11 | // UserFollower 12 | modelBuilder 13 | .HasKey(uf => uf.Id); 14 | 15 | /* modelBuilder 16 | .Ignore(ufr => ufr.User); 17 | 18 | modelBuilder 19 | .Ignore(ufr => ufr.Follower);*/ 20 | modelBuilder 21 | .HasOne(uf => uf.User) 22 | .WithMany() 23 | .HasForeignKey(uf => uf.UserId); 24 | modelBuilder 25 | .HasOne(uf => uf.Follower) 26 | .WithMany() 27 | .HasForeignKey(uf => uf.FollowerId); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/UserFollowerRequestConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.UserEntities; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class UserFollowerRequestConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder modelBuilder) 10 | { 11 | // UserFollowerRequest 12 | modelBuilder 13 | .HasKey(u => u.Id); 14 | modelBuilder 15 | .Ignore(ufr => ufr.User); 16 | modelBuilder 17 | .Ignore(ufr => ufr.Follower); 18 | //modelBuilder 19 | // .HasOne(u => u.User) 20 | // .WithMany() 21 | //.HasForeignKey(u => u.UserId); 22 | 23 | //modelBuilder 24 | // .HasOne(u => u.Follower) 25 | // .WithMany() 26 | // .HasForeignKey(u => u.FollowerId); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Data/AutomatedMigration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Identity; 2 | 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace ChitChat.DataAccess.Data 7 | { 8 | public static class AutomatedMigration 9 | { 10 | public static async Task MigrateAsync(IServiceProvider services) 11 | { 12 | var context = services.GetRequiredService(); 13 | 14 | var database = context.Database; 15 | 16 | var pendingMigrations = await database.GetPendingMigrationsAsync(); 17 | 18 | if (pendingMigrations.Any()) 19 | { 20 | await database.MigrateAsync(); 21 | } 22 | 23 | var userManager = services.GetRequiredService>(); 24 | 25 | var roleManager = services.GetRequiredService>(); 26 | 27 | await DbContextSeed.SeedDatabaseAsync(userManager, roleManager); 28 | } 29 | } 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/Controllers/TrainingModelController.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.MachineLearning.Services.Interface; 2 | using ChitChat.DataAccess.Repositories.Interface; 3 | 4 | using Microsoft.AspNetCore.Mvc; 5 | 6 | namespace ChitChat.WebAPI.Controllers 7 | { 8 | [Route("api/[controller]")] 9 | [ApiController] 10 | public class TrainingModelController : ControllerBase 11 | { 12 | private readonly ITrainingModelService _trainingModelService; 13 | public TrainingModelController(ITrainingModelService trainingModelService 14 | , IUserRepository userRepository) 15 | { 16 | _trainingModelService = trainingModelService; 17 | } 18 | //[HttpGet] 19 | //[Route("{userId}")] 20 | //public async Task GetRecommendationPostModel(Guid userId) 21 | //{ 22 | // var userInteractionModelItems = await _trainingModelService.GetRecommendationPostModel(userId.ToString()); 23 | // return Ok(userInteractionModelItems); 24 | //} 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Validations/ValidateModelAttribute.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | using Microsoft.AspNetCore.Mvc.Filters; 3 | using Microsoft.AspNetCore.Mvc; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace ChitChat.Infrastructure.Validations 11 | { 12 | public class ValidateModelAttribute : Attribute, IAsyncResultFilter 13 | { 14 | public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) 15 | { 16 | if (!context.ModelState.IsValid) 17 | { 18 | var errors = context.ModelState.Values 19 | .SelectMany(modelState => modelState.Errors) 20 | .Select(modelError => new ApiResultError(ApiResultErrorCodes.ModelValidation, modelError.ErrorMessage)); 21 | 22 | context.Result = new BadRequestObjectResult(ApiResult.Failure(errors)); 23 | } 24 | 25 | await next(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Services/Interface/IConversationService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | using ChitChat.Application.Models.Dtos.Conversation; 3 | using ChitChat.Application.Models.Dtos.Message; 4 | 5 | namespace ChitChat.Application.Services.Interface 6 | { 7 | public interface IConversationService 8 | { 9 | Task> GetAllConversationsAsync(PaginationFilter query); 10 | Task GetConversationsByIdAsync(Guid conversationId, int messagePageIndex, int messagePageSize); 11 | // post 12 | Task CreateConversationAsync(List userIds); 13 | Task SendMessageAsync(Guid conversationId, RequestSendMessageDto request); 14 | // Put 15 | Task UpdateMessageAsync(MessageDto message); 16 | Task UpdateConversationAsync(ConversationDto conversation); 17 | // Delete 18 | Task DeleteConversationAsync(Guid conversationId); 19 | Task DeleteMessageAsync(Guid messageId); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Mapping/NotificationProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | 3 | using ChitChat.Application.Models.Dtos.Notification; 4 | using ChitChat.Domain.Entities.SystemEntities.Notification; 5 | 6 | namespace ChitChat.Application.Mapping 7 | { 8 | public class NotificationProfile : Profile 9 | { 10 | public NotificationProfile() 11 | { 12 | CreateMap().ReverseMap(); 13 | CreateMap() 14 | .ForMember(dest => dest.Post, opt => opt.MapFrom(p => p.Comment.Post)) 15 | .ForPath(dest => dest.Post.Comments, opt => opt.Ignore()); 16 | 17 | 18 | CreateMap(); 19 | CreateMap(); 20 | CreateMap().ReverseMap(); 21 | CreateMap().ReverseMap(); 22 | CreateMap().ReverseMap(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/CloudinaryConfiguration/CloudinaryRegisteration.cs: -------------------------------------------------------------------------------- 1 | using CloudinaryDotNet; 2 | 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace ChitChat.Infrastructure.CloudinaryConfigurations 6 | { 7 | public static class CloudinaryRegisteration 8 | { 9 | public static void AddCloudinary(this IServiceCollection services) 10 | { 11 | CloudinarySetting cloudinarySetting = new CloudinarySetting() 12 | { 13 | CloudName = Environment.GetEnvironmentVariable("CloudinaryCloudName"), 14 | ApiKey = Environment.GetEnvironmentVariable("CloudinaryApiKey"), 15 | ApiSecret = Environment.GetEnvironmentVariable("CloudinaryApiSecret") 16 | }; 17 | Account account = new Account(cloudinarySetting.CloudName 18 | , cloudinarySetting.ApiKey 19 | , cloudinarySetting.ApiSecret); 20 | Cloudinary cloudinary = new Cloudinary(account); 21 | services.AddSingleton(cloudinary); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Tuan-Thanh Phan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/appsettings.Production.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "JWTConfigSetting": { 10 | "SecretKey": "55eaf009a21fa3c5fce7096ca201f24734df43de88484d7a017a8eb389343146df02cf096f0b", 11 | "TokenValidityInDays": 5, 12 | "RefreshTokenValidityInDays": 30, 13 | "Issuer": "Issuer", 14 | "Audience": "Audience" 15 | }, 16 | "Database": { 17 | "ConnectionStrings": { 18 | "LocalConnection": "Server=mysql;Database=chitchatdb;User=root;Password=Password12345!;", 19 | "AWSConnection": "Server=mysql-chit-chat.crska2kww12j.ap-southeast-1.rds.amazonaws.com;Port=3306;Database=ChitChatDB;User=admin;Password=123admin;" 20 | } 21 | }, 22 | "Kestrel": { 23 | "Endpoints": { 24 | "Http": { 25 | "Url": "http://*:8080" 26 | }, 27 | "Https": { 28 | "Url": "https://*:8081", 29 | "Certificate": { 30 | "Path": "/app/chitchat.pfx", 31 | "Password": "chitchat" 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /docker/DockerCompose/DockerCompose.dcproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.1 5 | Linux 6 | False 7 | 37fe7c74-3803-4e83-a00f-09a51f680d0a 8 | LaunchBrowser 9 | {Scheme}://localhost:{ServicePort}/swagger 10 | chitchat.webapi 11 | 12 | 13 | 14 | 15 | 16 | docker-compose.yml 17 | 18 | 19 | 20 | 21 | docker-compose.local.yml 22 | docker-compose.prod.yml 23 | 24 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/Controllers/NotificationController.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | using ChitChat.Application.Models.Dtos.Notification; 3 | using ChitChat.Application.Services.Interface; 4 | 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace ChitChat.WebAPI.Controllers 9 | { 10 | [Route("api/[controller]")] 11 | [ApiController] 12 | [Authorize] 13 | public class NotificationController : ControllerBase 14 | { 15 | private readonly INotificationService _notificationService; 16 | public NotificationController(INotificationService notificationService) 17 | { 18 | this._notificationService = notificationService; 19 | } 20 | [HttpGet] 21 | [Route("")] 22 | [ProducesResponseType(typeof(ApiResult>), StatusCodes.Status200OK)] // OK với ProductResponse 23 | public async Task GetAllNotificationsAsync([FromQuery] PaginationFilter query) 24 | { 25 | return Ok(ApiResult>.Success(await _notificationService.GetAllNotificationsAsync(query))); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/ChitChat.DataAccess.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | ChitChat.DataAccess 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/DependenceInjection.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.DataAccess.Repositories; 2 | using ChitChat.DataAccess.Repositories.Interface; 3 | using ChitChat.DataAccess.Repositories.Interface; 4 | 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace ChitChat.DataAccess 9 | { 10 | public static class DependenceInjection 11 | { 12 | public static IServiceCollection AddDataAccessService(this IServiceCollection services, IConfiguration configuration) 13 | { 14 | 15 | services.AddRepositories(); 16 | return services; 17 | } 18 | private static void AddRepositories(this IServiceCollection services) 19 | { 20 | services 21 | .AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>)) 22 | .AddScoped() 23 | .AddScoped() 24 | .AddScoped() 25 | .AddScoped() 26 | .AddScoped(); 27 | 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Services/ClaimService.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | 3 | using ChitChat.Application.Helpers; 4 | using ChitChat.Infrastructure.ConfigSetting; 5 | 6 | using Microsoft.AspNetCore.Http; 7 | 8 | namespace ChitChat.Infrastructure.Services 9 | { 10 | public class ClaimService : IClaimService 11 | { 12 | private readonly IHttpContextAccessor _httpContextAccessor; 13 | 14 | public ClaimService(IHttpContextAccessor httpContextAccessor) => this._httpContextAccessor = httpContextAccessor; 15 | 16 | public string GetUserId() => this.GetClaim(ClaimTypes.NameIdentifier); 17 | 18 | public string GetUserName() => this.GetClaim(ClaimTypes.Name); 19 | public string GetLoginHistoryId(ClaimsIdentity? claimsIdentity = null) 20 | { 21 | if (claimsIdentity is null) 22 | { 23 | return this.GetClaim(JWTConfigSetting.LoginHistoryIdClaimType); 24 | } 25 | 26 | return claimsIdentity.FindFirst(JWTConfigSetting.LoginHistoryIdClaimType)?.Value ?? string.Empty; 27 | } 28 | 29 | private string GetClaim(string key) => this._httpContextAccessor.HttpContext?.User?.FindFirst(key)?.Value ?? string.Empty; 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ChitChat.Application/ChitChat.Application.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | ChitChat.Application 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Migrations/20241123154958_ChangeCommentStatus.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace ChitChat.DataAccess.Migrations 6 | { 7 | /// 8 | public partial class ChangeCommentStatus : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.AlterColumn( 14 | name: "CommentType", 15 | table: "Comments", 16 | type: "longtext", 17 | nullable: false, 18 | oldClrType: typeof(int), 19 | oldType: "int") 20 | .Annotation("MySql:CharSet", "utf8mb4"); 21 | } 22 | 23 | /// 24 | protected override void Down(MigrationBuilder migrationBuilder) 25 | { 26 | migrationBuilder.AlterColumn( 27 | name: "CommentType", 28 | table: "Comments", 29 | type: "int", 30 | nullable: false, 31 | oldClrType: typeof(string), 32 | oldType: "longtext") 33 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/deploy-prod.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to AWS EC2 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | types: 8 | - closed 9 | 10 | jobs: 11 | deploy: 12 | if: github.event.pull_request.merged == true && github.event.pull_request.merge_commit_sha != null 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v2 18 | 19 | - name: Set up SSH 20 | uses: webfactory/ssh-agent@v0.5.3 21 | with: 22 | ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} 23 | 24 | - name: Deploy to EC2 25 | env: 26 | SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }} 27 | run: | 28 | ssh -o StrictHostKeyChecking=no -i ~/.ssh/chit-chat-server.pem ubuntu@ec2-18-138-250-74.ap-southeast-1.compute.amazonaws.com << 'EOF' 29 | cd ~/chit-chat-backend 30 | git checkout main 31 | git pull origin main 32 | docker-compose -f ~/chit-chat-backend/docker/DockerCompose/docker-compose.prod.yml down 33 | docker system prune -a --volumes -f 34 | docker-compose -f ~/chit-chat-backend/docker/DockerCompose/docker-compose.prod.yml build 35 | docker-compose -f ~/chit-chat-backend/docker/DockerCompose/docker-compose.prod.yml up -d 36 | EOF -------------------------------------------------------------------------------- /src/ChitChat.Application/Services/Interface/IPostService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Post; 2 | using ChitChat.Application.Models.Dtos.Post.Comments; 3 | using ChitChat.Application.Models.Dtos.Post.CreatePost; 4 | 5 | namespace ChitChat.Application.Services.Interface 6 | { 7 | public interface IPostService 8 | { 9 | Task> GetAllPostsAsync(PostUserSearchQueryDto query); 10 | Task GetPostByIdAsync(Guid postId); 11 | Task> GetReccomendationPostsAsync(PostSearchQueryDto query); 12 | Task> GetAllReplyCommentsAsync(Guid postId, Guid commentId); 13 | Task CreateNewPostAsync(CreatePostRequestDto requestDto); 14 | Task CreateNewCommentAsync(Guid postId, CommentRequestDto requestDto); 15 | Task CreateReplyCommentAsync(Guid postId, Guid parentCommentId, CommentRequestDto requestDto); 16 | Task UpdatePostByIdAsync(UpdatePostRequestDto postDto, Guid postId); 17 | Task ToggleReactPostAsync(Guid postId); 18 | Task UpdateCommentAsync(CommentRequestDto commentDto, Guid commentId); 19 | Task ToggleReactCommentAsync(Guid commentId); 20 | Task DeletePostByIdAsync(Guid postId); 21 | Task DeleteCommentByIdAsync(Guid commentId); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/CommentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.PostEntities; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class CommentConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder modelBuilder) 10 | { 11 | // Configure primary key 12 | modelBuilder.HasKey(c => c.Id); 13 | 14 | // Configure relationship with Post 15 | modelBuilder 16 | .HasOne(c => c.Post) 17 | .WithMany(p => p.Comments) 18 | .HasForeignKey(c => c.PostId) 19 | .OnDelete(DeleteBehavior.Cascade); 20 | 21 | // Configure relationship with ParentComment 22 | modelBuilder 23 | .HasOne(c => c.ParentComment) 24 | .WithMany(c => c.ReplyComments) 25 | .HasForeignKey(c => c.ParentCommentId) 26 | .OnDelete(DeleteBehavior.Cascade); 27 | 28 | // Configure relationship with UserPosted 29 | modelBuilder 30 | .HasOne(c => c.UserPosted) 31 | .WithMany() 32 | .HasForeignKey(c => c.UserPostedId) 33 | .OnDelete(DeleteBehavior.Cascade); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/ConversationConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 2 | 3 | namespace ChitChat.DataAccess.Configurations 4 | { 5 | public class ConversationConfiguration : IEntityTypeConfiguration 6 | { 7 | public void Configure(EntityTypeBuilder modelBuilder) 8 | { 9 | // Configure primary key 10 | modelBuilder.HasKey(c => c.Id); 11 | 12 | // Configure relationship with LastMessage 13 | modelBuilder 14 | .HasOne(c => c.LastMessage) 15 | .WithMany() 16 | .HasForeignKey(c => c.LastMessageId) 17 | .OnDelete(DeleteBehavior.Restrict); 18 | 19 | // Configure relationship with Messages 20 | modelBuilder 21 | .HasMany(c => c.Messages) 22 | .WithOne(m => m.Conversation) 23 | .HasForeignKey(m => m.ConversationId) 24 | .OnDelete(DeleteBehavior.Cascade); 25 | 26 | // Configure relationship with ConversationDetails 27 | modelBuilder 28 | .HasMany(c => c.ConversationDetails) 29 | .WithOne(cd => cd.Conversation) 30 | .HasForeignKey(cd => cd.ConversationId) 31 | .OnDelete(DeleteBehavior.Cascade); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/Services/ConversationNotificationService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Message; 2 | using ChitChat.Application.SignalR.Interface; 3 | using ChitChat.Infrastructure.SignalR.Helpers; 4 | using ChitChat.Infrastructure.SignalR.Hubs; 5 | using ChitChat.Infrastructure.SignalR.Hubs.InterfaceClient; 6 | 7 | using Microsoft.AspNetCore.SignalR; 8 | 9 | namespace ChitChat.Infrastructure.SignalR.Services 10 | { 11 | public class ConversationNotificationService : IConversationNotificationService 12 | { 13 | private readonly IHubContext _hubContext; 14 | public ConversationNotificationService(IHubContext hubContext) => this._hubContext = hubContext; 15 | public async Task SendMessage(MessageDto message) 16 | { 17 | await _hubContext.Clients.Group(HubRoom.ConversationHubJoinRoom(message.ConversationId)).NewMessage(message); 18 | } 19 | 20 | public async Task UpdateMessage(MessageDto message) 21 | { 22 | await _hubContext.Clients.Group(HubRoom.ConversationHubJoinRoom(message.ConversationId)).UpdateMessage(message); 23 | } 24 | public async Task DeleteMessage(MessageDto message) 25 | { 26 | await _hubContext.Clients.Group(HubRoom.ConversationHubJoinRoom(message.ConversationId)).DeleteMessage(message); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Common/LocalizedText.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Common 2 | { 3 | public class LocalizedText 4 | { 5 | public string ResourceKey { get; init; } = default!; 6 | 7 | private readonly Dictionary Texts = new(); 8 | 9 | public static LocalizedText New(string resourceKey) => new LocalizedText() { ResourceKey = resourceKey } 10 | .AddEnglishText(resourceKey) 11 | .AddDefaultText(resourceKey); 12 | 13 | private LocalizedText AddEnglishText(string text) 14 | { 15 | Texts["en-US"] = text; 16 | return this; 17 | } 18 | 19 | public LocalizedText AddDefaultText(string text) 20 | { 21 | Texts[LocalizationSettings.DefaultCulture] = text; 22 | 23 | return this; 24 | } 25 | 26 | public string Value 27 | { 28 | get 29 | { 30 | var culture = Thread.CurrentThread.CurrentCulture; 31 | return Texts[LocalizationSettings.DefaultCulture]; 32 | } 33 | } 34 | 35 | public string Format(params object[] args) 36 | { 37 | if (!args.Any()) return Value; 38 | 39 | if (string.IsNullOrWhiteSpace(Value)) return Value; 40 | 41 | return string.Format(Value, args); 42 | } 43 | 44 | public override string ToString() => Value; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/SignalRRegistration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.SignalR.Interface; 2 | using ChitChat.Infrastructure.SignalR.Helpers; 3 | using ChitChat.Infrastructure.SignalR.Hubs; 4 | using ChitChat.Infrastructure.SignalR.Services; 5 | 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Routing; 8 | using Microsoft.Extensions.DependencyInjection; 9 | 10 | namespace ChitChat.Infrastructure.SignalR 11 | { 12 | public static class SignalRRegistration 13 | { 14 | public static WebApplicationBuilder AddSignalRRegistration(this WebApplicationBuilder builder) 15 | { 16 | builder.Services.AddSignalRService(); 17 | return builder; 18 | } 19 | public static void AddSignalRHub(this IEndpointRouteBuilder route) 20 | { 21 | route.MapHub(HubEndpoint.UserHubEndpoint); 22 | route.MapHub(HubEndpoint.ConversationHubEndpoint); 23 | } 24 | private static IServiceCollection AddSignalRService(this IServiceCollection services) 25 | { 26 | services.AddSignalR(); 27 | /* services.AddSingleton();*/ 28 | services.AddScoped(); 29 | services.AddScoped(); 30 | return services; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/ChitChat.WebAPI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | ChitChat.WebAPI 8 | 3803187d-c2f2-4669-9bf6-a9422c6a7832 9 | Linux 10 | ..\.. 11 | ..\..\docker-compose.dcproj 12 | true 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Models/ApiResult.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Application.Models 2 | { 3 | public class ApiResult 4 | { 5 | private ApiResult() { } 6 | 7 | private ApiResult(bool succeeded, T result, IEnumerable errors) 8 | { 9 | Succeeded = succeeded; 10 | Result = result; 11 | Errors = errors; 12 | } 13 | 14 | public bool Succeeded { get; set; } 15 | 16 | public T Result { get; set; } 17 | 18 | public IEnumerable Errors { get; set; } 19 | 20 | public static ApiResult Success(T result) 21 | { 22 | return new ApiResult(true, result, new List()); 23 | } 24 | 25 | public static ApiResult Failure(IEnumerable errors) 26 | { 27 | return new ApiResult(false, default, errors); 28 | } 29 | } 30 | 31 | public class ApiResultError 32 | { 33 | public string Code { get; set; } 34 | 35 | public string Message { get; set; } 36 | 37 | public ApiResultError(ApiResultErrorCodes code, string message) 38 | { 39 | Code = code.ToString(); 40 | Message = message; 41 | } 42 | } 43 | 44 | public enum ApiResultErrorCodes 45 | { 46 | InternalServerError, 47 | ModelValidation, 48 | PermissionValidation, 49 | NotFound, 50 | Unauthorize, 51 | Forbidden, 52 | Conflict 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/Dockerfile: -------------------------------------------------------------------------------- 1 | # Stage 1: Base 2 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 3 | WORKDIR /app 4 | EXPOSE 8080 5 | EXPOSE 8081 6 | 7 | # Stage 2: Build 8 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 9 | ARG BUILD_CONFIGURATION=Release 10 | WORKDIR /src 11 | 12 | # Copy project files and restore dependencies 13 | COPY ["src/ChitChat.WebAPI/ChitChat.WebAPI.csproj", "ChitChat.WebAPI/"] 14 | COPY ["src/ChitChat.Infrastructure/ChitChat.Infrastructure.csproj", "ChitChat.Infrastructure/"] 15 | COPY ["src/ChitChat.Application/ChitChat.Application.csproj", "ChitChat.Application/"] 16 | COPY ["src/ChitChat.DataAccess/ChitChat.DataAccess.csproj", "ChitChat.DataAccess/"] 17 | COPY ["src/ChitChat.Domain/ChitChat.Domain.csproj", "ChitChat.Domain/"] 18 | RUN dotnet restore "ChitChat.WebAPI/ChitChat.WebAPI.csproj" 19 | 20 | # Copy the remaining source code and build 21 | COPY src/ . 22 | WORKDIR "/src/ChitChat.WebAPI" 23 | RUN dotnet build "ChitChat.WebAPI.csproj" -c $BUILD_CONFIGURATION -o /app/build 24 | 25 | # Stage 3: Publish 26 | FROM build AS publish 27 | RUN dotnet publish "ChitChat.WebAPI.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false 28 | 29 | # Stage 4: Final 30 | FROM base AS final 31 | WORKDIR /app 32 | COPY --from=publish /app/publish . 33 | 34 | # Copy SSL certificate if Production 35 | ARG ENVIRONMENT=Development 36 | COPY ["src/ChitChat.WebAPI/chitchat.pfx", "/app/chitchat.pfx"] 37 | RUN if [ "$ENVIRONMENT" = "Production" ]; then cp /app/chitchat.pfx /app/chitchat.pfx; fi 38 | 39 | ENTRYPOINT ["dotnet", "ChitChat.WebAPI.dll"] 40 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Mapping/UserProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | 3 | using ChitChat.Application.Models.Dtos.User; 4 | using ChitChat.Application.Models.Dtos.User.Profile; 5 | using ChitChat.Domain.Identity; 6 | 7 | namespace ChitChat.Application.Mapping 8 | { 9 | public class UserProfile : Profile 10 | { 11 | public UserProfile() 12 | { 13 | CreateMap(); 14 | CreateMap(); 15 | CreateMap(); 16 | CreateMap(); 17 | CreateMap(); 18 | CreateMap(); 19 | CreateMap() 20 | .ForMember(dest => dest.DisplayName, opt => opt.MapFrom(src => src.UserApplication != null ? src.UserApplication.DisplayName : string.Empty)) 21 | .ForMember(dest => dest.AvatarUrl, opt => opt.MapFrom(src => src.UserApplication != null ? src.UserApplication.AvatarUrl : string.Empty)) 22 | .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.UserApplication != null ? src.UserApplication.Email : string.Empty)) 23 | .ForMember(dest => dest.PhoneNumber, opt => opt.MapFrom(src => src.UserApplication != null ? src.UserApplication.PhoneNumber : string.Empty)); 24 | CreateMap(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Configurations/PostConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Entities.PostEntities; 2 | 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ChitChat.DataAccess.Configurations 6 | { 7 | public class PostConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder modelBuilder) 10 | { 11 | // Post 12 | modelBuilder 13 | .HasKey(p => p.Id); 14 | 15 | // Configure relationship with User 16 | modelBuilder 17 | .HasOne(p => p.User) 18 | .WithMany() 19 | .HasForeignKey(p => p.UserId); 20 | 21 | // Configure relationship with Comments 22 | modelBuilder 23 | .HasMany(p => p.Comments) 24 | .WithOne(c => c.Post) 25 | .HasForeignKey(c => c.PostId) 26 | .OnDelete(DeleteBehavior.Cascade); 27 | 28 | // Configure relationship with PostDetailTags 29 | modelBuilder 30 | .HasMany(p => p.PostDetailTags) 31 | .WithOne(pdt => pdt.Post) 32 | .HasForeignKey(pdt => pdt.PostId) 33 | .OnDelete(DeleteBehavior.Cascade); 34 | 35 | // Configure relationship with PostMedias 36 | modelBuilder 37 | .HasMany(p => p.PostMedias) 38 | .WithOne(pm => pm.Post) 39 | .HasForeignKey(pm => pm.PostId) 40 | .OnDelete(DeleteBehavior.Cascade); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/Interface/IUserRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | using ChitChat.Domain.Entities; 4 | using ChitChat.Domain.Identity; 5 | 6 | using Microsoft.EntityFrameworkCore.Query; 7 | 8 | namespace ChitChat.DataAccess.Repositories.Interface 9 | { 10 | public interface IUserRepository 11 | { 12 | IQueryable GetQuery(); 13 | 14 | Task GetFirstAsync(Expression> predicate); 15 | 16 | Task GetFirstOrDefaultAsync(Expression> predicate); 17 | Task> GetAllAsync(Expression> predicate); 18 | 19 | Task> GetAllAsync(Expression> predicate, IEnumerable>> includes); 20 | Task> GetAllAsync(Expression> predicate, Func, IIncludableQueryable> includeQuery); 21 | Task> GetAllAsync(Expression> predicate, Func, IOrderedQueryable> sort); 22 | Task UpdateAsync(UserApplication entity); 23 | 24 | Task> UpdateRangeAsync(List entities); 25 | 26 | Task DeleteAsync(UserApplication entity); 27 | 28 | Task AnyAsync(Expression> predicate); 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "swagger", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Development" 9 | }, 10 | "dotnetRunMessages": true, 11 | "applicationUrl": "http://localhost:5251" 12 | }, 13 | "https": { 14 | "commandName": "Project", 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | }, 20 | "dotnetRunMessages": true, 21 | "applicationUrl": "https://localhost:7136;http://localhost:5251" 22 | }, 23 | "IIS Express": { 24 | "commandName": "IISExpress", 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "environmentVariables": { 28 | "ASPNETCORE_ENVIRONMENT": "Development" 29 | } 30 | }, 31 | "Container (Dockerfile)": { 32 | "commandName": "Docker", 33 | "launchBrowser": true, 34 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", 35 | "environmentVariables": { 36 | "ASPNETCORE_HTTPS_PORTS": "8081", 37 | "ASPNETCORE_HTTP_PORTS": "8080" 38 | }, 39 | "publishAllPorts": true, 40 | "useSSL": true 41 | } 42 | }, 43 | "$schema": "http://json.schemastore.org/launchsettings.json", 44 | "iisSettings": { 45 | "windowsAuthentication": false, 46 | "anonymousAuthentication": true, 47 | "iisExpress": { 48 | "applicationUrl": "http://localhost:45774", 49 | "sslPort": 44397 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/UserInteractionRepository.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.MachineLearning.Models; 2 | using ChitChat.DataAccess.Data; 3 | using ChitChat.DataAccess.Repositories.Interface; 4 | using ChitChat.Domain.Entities.SystemEntities; 5 | using ChitChat.Domain.Enums; 6 | 7 | namespace ChitChat.DataAccess.Repositories 8 | { 9 | public class UserInteractionRepository : BaseRepository, IUserInteractionRepository 10 | { 11 | public UserInteractionRepository(ApplicationDbContext context) : base(context) 12 | { 13 | } 14 | 15 | public async Task> GetUserInteractionModelForTraining(int pageSize) 16 | { 17 | var data = await DbSet 18 | .OrderByDescending(p => p.InteractionDate) 19 | .Include(p => p.Post) 20 | .Take(pageSize) 21 | .ToListAsync(); // Lấy dữ liệu từ database trước 22 | 23 | var userModelItems = data 24 | .GroupBy(p => new 25 | { 26 | p.UserId, 27 | p.PostId, 28 | PostDescription = p.Post.Description 29 | }) 30 | .Select(g => new UserInteractionModelItem 31 | { 32 | UserId = g.Key.UserId, 33 | PostId = g.Key.PostId.ToString(), 34 | PostDescription = g.Key.PostDescription, 35 | TotalPoint = g.Sum(x => InteractionTypePoint.GetInteractionPoint(x)) 36 | }) 37 | .ToList(); 38 | return userModelItems; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/ChitChat.Domain/Common/NotificationFormatter.cs: -------------------------------------------------------------------------------- 1 | namespace ChitChat.Domain.Common 2 | { 3 | public static class NotificationFormatter 4 | { 5 | public static string FormatPostLikeNotification(string userAvatar, string userName, string postImage, string postDescription, DateTime dateTimeLike) 6 | { 7 | return $"{userAvatar} ({userName}) liked your post. ({postImage}, {postDescription}) - {dateTimeLike:yyyy-MM-dd HH:mm:ss}"; 8 | } 9 | 10 | public static string FormatPostCommentNotification(string userAvatar, string userName, string postImage, string postDescription, DateTime dateTimeComment) 11 | { 12 | return $"{userAvatar} ({userName}) commented on your post. ({postImage}, {postDescription}) - {dateTimeComment:yyyy-MM-dd HH:mm:ss}"; 13 | } 14 | 15 | public static string FormatCommentLikeNotification(string userAvatar, string userName, string myCommentContent, string postImage, DateTime dateTimeLike) 16 | { 17 | return $"{userAvatar} ({userName}) liked your comment: \"{myCommentContent}\" - ({postImage}) - {dateTimeLike:yyyy-MM-dd HH:mm:ss}"; 18 | } 19 | 20 | public static string FormatCommentReplyNotification(string userAvatar, string userName, string myCommentContent, string postImage, DateTime dateTimeComment) 21 | { 22 | return $"{userAvatar} ({userName}) replied to your comment: \"{myCommentContent}\" - ({postImage}) - {dateTimeComment:yyyy-MM-dd HH:mm:ss}"; 23 | } 24 | 25 | public static string FormatFollowerNotification(string userAvatar, string userName, DateTime dateTimeFollow) 26 | { 27 | return $"{userAvatar} ({userName}) started following you - {dateTimeFollow:yyyy-MM-dd HH:mm:ss}"; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Authorization/AuthorizationRegisteration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Infrastructure.ConfigSetting; 2 | 3 | using Microsoft.AspNetCore.Authentication.JwtBearer; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.IdentityModel.Tokens; 8 | 9 | namespace ChitChat.Infrastructure.Authorization 10 | { 11 | internal static class AuthorizationRegisteration 12 | { 13 | public static WebApplicationBuilder AddAppAuthorization(this WebApplicationBuilder builder) 14 | { 15 | var jwtOption = builder.Configuration.GetSection(nameof(JWTConfigSetting)).Get(); 16 | builder.Services.AddSingleton(jwtOption); 17 | var key = Encoding.ASCII.GetBytes(jwtOption.SecretKey); 18 | 19 | builder.Services.AddAuthentication(x => 20 | { 21 | x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 22 | x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 23 | }) 24 | .AddJwtBearer(x => 25 | { 26 | x.RequireHttpsMetadata = false; 27 | x.SaveToken = true; 28 | x.TokenValidationParameters = new TokenValidationParameters 29 | { 30 | ValidateIssuerSigningKey = true, 31 | IssuerSigningKey = new SymmetricSecurityKey(key), 32 | ValidAudience = jwtOption.Audience, 33 | ValidIssuer = jwtOption.Issuer, 34 | ValidateLifetime = true 35 | }; 36 | }); 37 | return builder; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/ChitChat.Application/Validators/User/RegisterationRequestValidator.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.User; 2 | 3 | using FluentValidation; 4 | namespace ChitChat.Application.Validators.User 5 | { 6 | public class RegisterationRequestValidator : AbstractValidator 7 | { 8 | public RegisterationRequestValidator() 9 | { 10 | RuleFor(user => user.FirstName) 11 | .NotEmpty().WithMessage("First name is required.") 12 | .Length(1, 255).WithMessage("First name must be between 1 and 255 characters."); 13 | 14 | RuleFor(user => user.LastName) 15 | .NotEmpty().WithMessage("Last name is required.") 16 | .Length(1, 255).WithMessage("Last name must be between 1 and 255 characters."); 17 | 18 | /* RuleFor(user => user.AvatarUrl) 19 | .MaximumLength(255).WithMessage("Avatar URL must be up to 255 characters."); 20 | 21 | RuleFor(user => user.Bio) 22 | .MaximumLength(500).WithMessage("Bio must be up to 500 characters."); 23 | 24 | RuleFor(user => user.DateOfBirth) 25 | .LessThan(DateTime.Now).WithMessage("Date of birth must be in the past."); 26 | 27 | RuleFor(user => user.Gender) 28 | .Matches("^(Male|Female|Other)$").WithMessage("Gender must be Male, Female, or Other."); 29 | 30 | RuleFor(user => user.UserStatus) 31 | .IsInEnum().WithMessage("User status must be a valid value. User Status must is 0 {Private} and 1 {Public}"); 32 | */ 33 | RuleFor(user => user.Email) 34 | .EmailAddress().WithMessage("Email is not valid"); 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/EntityFrameworkCore/EntityFrameworkRegisteration.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.DataAccess.Data; 2 | using ChitChat.DataAccess.Data.Interceptor; 3 | 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace ChitChat.Infrastructure.EntityFrameworkCore 9 | { 10 | public static class EntityFrameworkRegisteration 11 | { 12 | public static WebApplicationBuilder AddEntityFramewordCore(this WebApplicationBuilder builder) 13 | { 14 | var configuration = builder.Configuration; 15 | 16 | builder.Services.AddScoped(); 17 | 18 | builder.Services.AddDbContext((provider, options) => 19 | { 20 | var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); 21 | var connectionString = environment == "Development" 22 | ? configuration.GetSection("Database:ConnectionStrings").GetValue("LocalConnection") 23 | : configuration.GetSection("Database:ConnectionStrings").GetValue("AWSConnection"); 24 | 25 | options 26 | .AddInterceptors(provider.GetRequiredService()) 27 | .UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 39)), 28 | opt => 29 | { 30 | opt.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName); 31 | opt.EnableRetryOnFailure(); 32 | }); 33 | }); 34 | 35 | builder.Services.AddScoped(sp => sp.GetRequiredService()); 36 | 37 | return builder; 38 | } 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/ChitChat.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | ChitChat.Infrastructure 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Caching/MemoryCacheService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Services.Caching; 2 | 3 | using Microsoft.Extensions.Caching.Memory; 4 | 5 | namespace ChitChat.Infrastructure.Caching 6 | { 7 | public class MemoryCacheService : ICachingService 8 | { 9 | private readonly IMemoryCache _memoryCache; 10 | 11 | private MemoryCacheEntryOptions MemoryCacheEntryOptions = new() 12 | { 13 | AbsoluteExpirationRelativeToNow = CacheEntryOptions.Default.AbsoluteExpirationRelativeToNow, 14 | SlidingExpiration = CacheEntryOptions.Default.SlidingExpiration 15 | }; 16 | 17 | public MemoryCacheService(IMemoryCache memoryCache) 18 | { 19 | this._memoryCache = memoryCache; 20 | } 21 | 22 | public async Task Set(string key, T value) 23 | { 24 | await Task.Yield(); 25 | this._memoryCache.Set(key, value, this.MemoryCacheEntryOptions); 26 | } 27 | 28 | public async Task Get(string key) 29 | { 30 | await Task.Yield(); 31 | this._memoryCache.TryGetValue(key, out var cacheEntry); 32 | return cacheEntry; 33 | } 34 | 35 | public async Task GetOrSetAsync(string key, Func> func) 36 | { 37 | var cacheEntry = await this._memoryCache.GetOrCreateAsync(key, async entry => 38 | { 39 | entry 40 | .SetSlidingExpiration(this.MemoryCacheEntryOptions.SlidingExpiration!.Value) 41 | .SetAbsoluteExpiration(this.MemoryCacheEntryOptions.AbsoluteExpirationRelativeToNow!.Value); 42 | 43 | return await func(); 44 | }); 45 | 46 | return cacheEntry; 47 | } 48 | 49 | public async Task Remove(string key) 50 | { 51 | this._memoryCache.Remove(key); 52 | await Task.CompletedTask; 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/UserFollowerRepository.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.DataAccess.Data; 2 | using ChitChat.DataAccess.Repositories.Interface; 3 | using ChitChat.Domain.Entities.UserEntities; 4 | using ChitChat.Domain.Identity; 5 | 6 | namespace ChitChat.DataAccess.Repositories 7 | { 8 | public class UserFollowerRepository : BaseRepository, IUserFollowerRepository 9 | { 10 | public UserFollowerRepository(ApplicationDbContext context) : base(context) 11 | { 12 | } 13 | 14 | public async Task> GetRecommendedUsersAsync(string currentUserId, int pageSize) 15 | { 16 | var followedUsers = await this.Context.UserFollowers 17 | .Where(uf => uf.UserId == currentUserId) 18 | .Select(uf => uf.FollowerId) 19 | .ToListAsync(); 20 | var recommendedUsers = await Context.UserFollowers 21 | .Where(uf => followedUsers.Contains(uf.UserId) // Người bạn của tôi theo dõi 22 | && uf.FollowerId != currentUserId // Không phải chính tôi 23 | && !followedUsers.Contains(uf.FollowerId)) 24 | .Include(p => p.User) 25 | .Select(p => p.User)// Tôi chưa theo dõi họ 26 | .Distinct() // Loại bỏ trùng lặp 27 | .ToListAsync(); 28 | var otherFollow = await Context.UserApplications 29 | .Where(p => p.Id != currentUserId// Tôi chưa theo dõi họ 30 | && !followedUsers.Contains(p.Id))// Họ chưa theo dõi tôi 31 | .ToListAsync(); 32 | var allUsers = recommendedUsers 33 | .Concat(otherFollow) // Gộp với otherFollow 34 | .ToList(); 35 | // Random hóa danh sách 36 | var randomUsers = allUsers.OrderBy(u => Guid.NewGuid()).ToList(); 37 | return randomUsers.Take(pageSize).ToList(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/ChitChat.Application/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | using ChitChat.Application.MachineLearning.Services; 4 | using ChitChat.Application.MachineLearning.Services.Interface; 5 | using ChitChat.Application.Mapping; 6 | using ChitChat.Application.Services; 7 | using ChitChat.Application.Services.Interface; 8 | using ChitChat.Application.Validators; 9 | 10 | using FluentValidation; 11 | 12 | using Microsoft.Extensions.DependencyInjection; 13 | namespace ChitChat.Application 14 | { 15 | public static class DependencyInjection 16 | { 17 | public static IServiceCollection AddApplicationServices(this IServiceCollection services) 18 | { 19 | // Add Validators 20 | 21 | services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()) 22 | .AddValidatorsFromAssemblyContaining(); 23 | 24 | // Add MediaR 25 | 26 | services.AddMediatR(cfg => 27 | { 28 | cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); 29 | }); 30 | 31 | // Add AutoMapper 32 | 33 | services.AddAutoMapper(typeof(IMappingProfileMarker)); 34 | 35 | // Add Services 36 | services.AddServices(); 37 | 38 | 39 | return services; 40 | } 41 | public static IServiceCollection AddServices(this IServiceCollection services) 42 | { 43 | services.AddScoped(); 44 | services.AddScoped(); 45 | services.AddScoped(); 46 | services.AddScoped(); 47 | services.AddScoped(); 48 | services.AddScoped(); 49 | services.AddScoped(); 50 | return services; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/Hubs/ConversationHub.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Infrastructure.SignalR.Helpers; 2 | using ChitChat.Infrastructure.SignalR.Hubs.InterfaceClient; 3 | 4 | using Microsoft.AspNetCore.SignalR; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace ChitChat.Infrastructure.SignalR.Hubs 8 | { 9 | public class ConversationHub : Hub 10 | { 11 | private readonly ILogger _logger; 12 | public ConversationHub(ILogger logger) 13 | { 14 | _logger = logger; 15 | } 16 | public override Task OnConnectedAsync() => base.OnConnectedAsync(); 17 | public async Task JoinConversationGroup(Guid conversationId) 18 | { 19 | var roomId = HubRoom.ConversationHubJoinRoom(conversationId); 20 | await Groups.AddToGroupAsync(Context.ConnectionId, roomId); 21 | await Clients.Group(roomId).ConversationJoined($"{Context.ConnectionId} has joined the room {roomId}"); 22 | } 23 | public async Task SendOffer(Guid conversationId, string sdp) 24 | { 25 | var roomId = HubRoom.ConversationHubJoinRoom(conversationId); 26 | await Clients.OthersInGroup(roomId).ReceiveOffer(Context.ConnectionId, sdp); 27 | } 28 | 29 | public async Task SendAnswer(Guid conversationId, string sdp) 30 | { 31 | var roomId = HubRoom.ConversationHubJoinRoom(conversationId); 32 | await Clients.OthersInGroup(roomId).ReceiveAnswer(Context.ConnectionId, sdp); 33 | } 34 | 35 | public async Task SendIceCandidate(Guid conversationId, string candidate) 36 | { 37 | var roomId = HubRoom.ConversationHubJoinRoom(conversationId); 38 | await Clients.OthersInGroup(roomId).ReceiveIceCandidate(Context.ConnectionId, candidate); 39 | } 40 | public async Task StartCall(Guid conversationId) 41 | { 42 | var roomId = HubRoom.ConversationHubJoinRoom(conversationId); 43 | await Clients.OthersInGroup(roomId).ReceiveCall(conversationId); 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/Program.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application; 2 | using ChitChat.DataAccess; 3 | using ChitChat.DataAccess.Data; 4 | using ChitChat.Domain.Common; 5 | using ChitChat.Infrastructure; 6 | using ChitChat.Infrastructure.SignalR; 7 | using ChitChat.Infrastructure.Validations; 8 | using ChitChat.WebAPI; 9 | 10 | using FluentValidation; 11 | using FluentValidation.AspNetCore; 12 | 13 | var builder = WebApplication.CreateBuilder(args); 14 | 15 | // Add services to the container. 16 | var env = builder.Environment; 17 | builder.Configuration 18 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 19 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false, reloadOnChange: true); 20 | 21 | DotNetEnv.Env.Load(); 22 | ValidatorOptions.Global.DefaultRuleLevelCascadeMode = CascadeMode.Stop; 23 | builder.Services 24 | .AddFluentValidationAutoValidation() 25 | .AddFluentValidationClientsideAdapters() 26 | .AddControllers(config => config.Filters.Add(typeof(ValidateModelAttribute))) 27 | .AddJsonOptions(options => 28 | { 29 | options.JsonSerializerOptions.Converters.Add(new UnixTimestampConverter()); 30 | }); ; 31 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 32 | builder.Services.AddEndpointsApiExplorer(); 33 | builder.Services.AddSwaggerGen(); 34 | builder.Services 35 | .AddDataAccessService(builder.Configuration) 36 | .AddApplicationServices(); 37 | builder 38 | .AddInfrastructure() 39 | .AddWebAPI() 40 | ; 41 | var app = builder.Build(); 42 | 43 | 44 | // Configure the HTTP request pipeline. 45 | app.UseSwagger(); 46 | app.UseSwaggerUI(); 47 | 48 | // Migrate Database 49 | using var scope = app.Services.CreateAsyncScope(); 50 | await AutomatedMigration.MigrateAsync(scope.ServiceProvider); 51 | 52 | app.UseHttpsRedirection(); 53 | app.AddInfrastuctureApplication(); 54 | app.UseAuthentication(); 55 | app.UseAuthorization(); 56 | app.AddSignalRHub(); 57 | app.UseCors(corsPolicyBuilder => corsPolicyBuilder 58 | .AllowAnyOrigin() 59 | .AllowAnyMethod() 60 | .AllowAnyHeader() 61 | ); 62 | app.MapControllers(); 63 | 64 | app.Run(); 65 | 66 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/ConversationRepository.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.DataAccess.Data; 2 | using ChitChat.DataAccess.Repositories.Interface; 3 | using ChitChat.Domain.Enums; 4 | 5 | namespace ChitChat.DataAccess.Repositories 6 | { 7 | public class ConversationRepository : BaseRepository, IConversationRepository 8 | { 9 | public ConversationRepository(ApplicationDbContext context) : base(context) 10 | { 11 | } 12 | 13 | public async Task> GetConversationByUserIdAsync(string userId) 14 | { 15 | var listConversation = await (from convDetail in Context.ConversationDetails 16 | join conv in Context.Conversations on convDetail.ConversationId equals conv.Id 17 | where convDetail.UserId == userId && conv.IsDeleted == false 18 | select conv) 19 | .Include( 20 | c => c.ConversationDetails 21 | ) 22 | .Include(c => c.LastMessage) 23 | .AsNoTracking() 24 | .ToListAsync(); 25 | return listConversation; 26 | } 27 | 28 | public async Task IsConversationExisted(string userSenderId, string userReceiverId) 29 | { 30 | Conversation? hasConversation = await Context.ConversationDetails 31 | .Where(cd2 => cd2.UserId == userReceiverId && cd2.Conversation.ConversationType == ConversationType.Person.ToString()) 32 | .SelectMany(cd2 => Context.ConversationDetails 33 | .Where(cd1 => cd1.UserId == userSenderId && cd1.ConversationId == cd2.ConversationId)) 34 | .Select(cd1 => cd1.Conversation) 35 | .SingleOrDefaultAsync(); 36 | if (hasConversation != null) 37 | hasConversation.LastMessage = await Context.Messages.SingleOrDefaultAsync(p => p.Id == hasConversation.LastMessageId); 38 | return hasConversation; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Data/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | using ChitChat.Domain.Entities; 4 | using ChitChat.Domain.Entities.ChatEntities; 5 | using ChitChat.Domain.Entities.PostEntities; 6 | using ChitChat.Domain.Entities.PostEntities.Reaction; 7 | using ChitChat.Domain.Entities.SystemEntities; 8 | using ChitChat.Domain.Entities.SystemEntities.Notification; 9 | using ChitChat.Domain.Entities.UserEntities; 10 | using ChitChat.Domain.Identity; 11 | 12 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 13 | 14 | namespace ChitChat.DataAccess.Data 15 | { 16 | public class ApplicationDbContext : IdentityDbContext 17 | { 18 | public DbSet UserApplications { get; set; } 19 | public DbSet UserFollowers { get; set; } 20 | public DbSet UserFollowerRequests { get; set; } 21 | public DbSet Conversations { get; set; } 22 | public DbSet ConversationDetails { get; set; } 23 | public DbSet LoginHistories { get; set; } 24 | public DbSet Messages { get; set; } 25 | public DbSet Posts { get; set; } 26 | public DbSet PostMedias { get; set; } 27 | public DbSet PostDetailTags { get; set; } 28 | public DbSet Comments { get; set; } 29 | public DbSet ReactionPosts { get; set; } 30 | public DbSet ReactionComments { get; set; } 31 | public DbSet UserInteractions { get; set; } 32 | public DbSet PostNotifications { get; set; } 33 | public DbSet CommentNotifications { get; set; } 34 | public DbSet UserNotifications { get; set; } 35 | 36 | public DbSet Profiles { get; set; } 37 | public ApplicationDbContext(DbContextOptions options) : base(options) 38 | { 39 | 40 | } 41 | protected override void OnModelCreating(ModelBuilder builder) 42 | { 43 | builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); 44 | 45 | base.OnModelCreating(builder); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/ChitChat.WebAPI/Controllers/UserController.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models; 2 | using ChitChat.Application.Models.Dtos.User; 3 | using ChitChat.Application.Services.Interface; 4 | 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace ChitChat.WebAPI.Controllers 9 | { 10 | [Route("api/[controller]")] 11 | [ApiController] 12 | [Authorize] 13 | public class UserController : ControllerBase 14 | { 15 | private readonly IUserService _userService; 16 | private readonly ILogger _logger; 17 | public UserController(IUserService userService, ILogger logger) 18 | { 19 | _userService = userService; 20 | _logger = logger; 21 | } 22 | 23 | [HttpPost("register")] 24 | [AllowAnonymous] 25 | [ProducesResponseType(typeof(ApiResult), StatusCodes.Status200OK)] // OK với ProductResponse 26 | public async Task RegisterUser([FromBody] RegisterationRequestDto registerationRequestDto) 27 | { 28 | return Ok(ApiResult.Success(await _userService.RegisterAsync(registerationRequestDto))); 29 | } 30 | [HttpPost("login")] 31 | [AllowAnonymous] 32 | [ProducesResponseType(typeof(ApiResult), StatusCodes.Status200OK)] // OK với ProductResponse 33 | public async Task LoginUser([FromBody] LoginRequestDto loginRequestDto) 34 | { 35 | return Ok(ApiResult.Success(await _userService.LoginAsync(loginRequestDto))); 36 | } 37 | [HttpPost("logout")] 38 | [ProducesResponseType(typeof(ApiResult), StatusCodes.Status200OK)] // OK với ProductResponse 39 | public async Task LogoutUser([FromBody] Guid loginHistoryId) 40 | { 41 | return Ok(ApiResult.Success(await _userService.LogoutAsync(loginHistoryId))); 42 | } 43 | [HttpPost("refreshToken")] 44 | [AllowAnonymous] 45 | [ProducesResponseType(typeof(ApiResult), StatusCodes.Status200OK)] // OK với ProductResponse 46 | public async Task RefreshTokenAsync([FromBody] RefreshTokenDto refreshTokenDto) 47 | { 48 | return Ok(ApiResult.Success(await _userService.RefreshTokenAsync(refreshTokenDto))); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # C# files 5 | [*.cs] 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | 12 | # Organize usings 13 | dotnet_sort_system_directives_first = true 14 | dotnet_separate_import_directive_groups = true 15 | 16 | # C# specific formatting rules 17 | # Use 'var' instead of explicit type when the type is apparent 18 | csharp_style_var_for_built_in_types = true:suggestion 19 | csharp_style_var_when_type_is_apparent = true:suggestion 20 | csharp_style_var_elsewhere = false:suggestion 21 | 22 | # Use expression-bodied members when possible 23 | csharp_style_expression_bodied_methods = true:suggestion 24 | csharp_style_expression_bodied_constructors = true:suggestion 25 | csharp_style_expression_bodied_operators = true:suggestion 26 | csharp_style_expression_bodied_properties = true:suggestion 27 | csharp_style_expression_bodied_indexers = true:suggestion 28 | csharp_style_expression_bodied_accessors = true:suggestion 29 | 30 | # Use pattern matching when possible 31 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 32 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 33 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 34 | 35 | # Prefer 'is not null' over '!= null' 36 | csharp_style_prefer_is_not_expression = true:suggestion 37 | 38 | # Prefer 'null' check over 'object' check 39 | csharp_style_prefer_null_check_over_type_check = true:suggestion 40 | 41 | # Use 'default' literal instead of 'default(T)' 42 | csharp_style_prefer_simple_default_expression = true:suggestion 43 | 44 | # Use 'nameof' instead of string literals for parameter names 45 | csharp_style_prefer_nameof_expression = true:suggestion 46 | 47 | # Use 'using' statement instead of 'using' declaration 48 | csharp_prefer_simple_using_statement = true:suggestion 49 | 50 | # Use 'readonly' modifier for fields that are only assigned in the constructor 51 | dotnet_style_readonly_field = true:suggestion 52 | 53 | # Use 'this.' prefix for instance members 54 | dotnet_style_qualification_for_field = true:suggestion 55 | dotnet_style_qualification_for_property = true:suggestion 56 | dotnet_style_qualification_for_method = true:suggestion 57 | dotnet_style_qualification_for_event = true:suggestion 58 | 59 | # Use 'private' modifier for fields 60 | dotnet_style_require_accessibility_modifiers = always:suggestion -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/EntityFrameworkCore/Interceptor/ContextSaveChangeInterceptor.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Helpers; 2 | using ChitChat.Domain.Common; 3 | 4 | using Microsoft.EntityFrameworkCore.Diagnostics; 5 | 6 | namespace ChitChat.DataAccess.Data.Interceptor 7 | { 8 | public class ContextSaveChangeInterceptor : SaveChangesInterceptor 9 | { 10 | private readonly IClaimService _claimService; 11 | 12 | public ContextSaveChangeInterceptor(IClaimService claimService) 13 | { 14 | _claimService = claimService; 15 | } 16 | 17 | public override async ValueTask> SavingChangesAsync( 18 | DbContextEventData eventData, 19 | InterceptionResult result, 20 | CancellationToken cancellationToken = default) 21 | { 22 | var dbContext = eventData.Context; 23 | 24 | 25 | if (dbContext is not null) 26 | { 27 | 28 | foreach (var entry in dbContext.ChangeTracker.Entries()) 29 | { 30 | switch (entry.State) 31 | { 32 | case EntityState.Added: 33 | if (entry.Entity.Id == Guid.Empty) 34 | entry.Entity.Id = Guid.NewGuid(); // Sử dụng Guid.NewGuid() thay vì new Guid() 35 | 36 | if (entry.Entity is IAuditedEntity auditedEntity) 37 | { 38 | auditedEntity.CreatedBy = _claimService.GetUserId(); // Cast entity sang IAuditedEntity 39 | auditedEntity.CreatedOn = DateTime.UtcNow; 40 | auditedEntity.UpdatedBy = auditedEntity.CreatedBy; 41 | auditedEntity.UpdatedOn = auditedEntity.CreatedOn; 42 | } 43 | break; 44 | 45 | case EntityState.Modified: 46 | if (entry.Entity is IAuditedEntity auditedEntityModify) 47 | { 48 | auditedEntityModify.UpdatedBy = _claimService.GetUserId(); 49 | auditedEntityModify.UpdatedOn = DateTime.UtcNow; 50 | } 51 | break; 52 | } 53 | } 54 | } 55 | var saveChangeResult = await base.SavingChangesAsync(eventData, result, cancellationToken); 56 | return saveChangeResult; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/SignalR/Services/UserNotificationService.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Models.Dtos.Conversation; 2 | using ChitChat.Application.Models.Dtos.Notification; 3 | using ChitChat.Application.SignalR.Interface; 4 | using ChitChat.Infrastructure.SignalR.Helpers; 5 | using ChitChat.Infrastructure.SignalR.Hubs; 6 | using ChitChat.Infrastructure.SignalR.Hubs.InterfaceClient; 7 | 8 | using Microsoft.AspNetCore.SignalR; 9 | 10 | namespace ChitChat.Infrastructure.SignalR.Services 11 | { 12 | public class UserNotificationService : IUserNotificationService 13 | { 14 | private readonly IHubContext _hubContext; 15 | public UserNotificationService(IHubContext hubContext) => this._hubContext = hubContext; 16 | 17 | public async Task AddConversation(ConversationDto conversation, string userSenderId) 18 | { 19 | await _hubContext.Clients.Group(HubRoom.UserHubJoinRoom(userSenderId)).AddConversation(conversation); 20 | foreach (var uid in conversation.UserReceiverIds) 21 | { 22 | await _hubContext.Clients.Group(HubRoom.UserHubJoinRoom(uid)).AddConversation(conversation); 23 | } 24 | } 25 | public async Task UpdateConversation(ConversationDto conversation, string userSenderId) 26 | { 27 | await _hubContext.Clients.Group(HubRoom.UserHubJoinRoom(userSenderId)).UpdateConversation(conversation); 28 | foreach (var uid in conversation.UserReceiverIds) 29 | { 30 | await _hubContext.Clients.Group(HubRoom.UserHubJoinRoom(uid)).UpdateConversation(conversation); 31 | } 32 | } 33 | public async Task DeleteConversation(ConversationDto conversation, string userSenderId) 34 | { 35 | await _hubContext.Clients.Group(HubRoom.UserHubJoinRoom(userSenderId)).DeleteConversation(conversation); 36 | foreach (var uid in conversation.UserReceiverIds) 37 | { 38 | await _hubContext.Clients.Group(HubRoom.UserHubJoinRoom(uid)).DeleteConversation(conversation); 39 | } 40 | } 41 | public async Task NewNotification(NotificationDto notificationDto) 42 | { 43 | await _hubContext.Clients.Group(HubRoom.UserHubJoinRoom(notificationDto.ReceiverUserId)).AddNotification(notificationDto); 44 | 45 | } 46 | public async Task UpdateNotification(NotificationDto notificationDto) 47 | { 48 | await _hubContext.Clients.Group(HubRoom.UserHubJoinRoom(notificationDto.ReceiverUserId)).UpdateNotification(notificationDto); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/Interface/IBaseRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | using ChitChat.Domain.Common; 4 | using ChitChat.Domain.Entities; 5 | 6 | using Microsoft.EntityFrameworkCore.Query; 7 | 8 | namespace ChitChat.DataAccess.Repositories.Interface 9 | { 10 | public interface IBaseRepository where TEntity : BaseEntity 11 | { 12 | IQueryable GetQuery(); 13 | 14 | Task GetFirstAsync(Expression> predicate); 15 | 16 | Task GetFirstOrDefaultAsync(Expression> predicate); 17 | 18 | Task GetFirstOrDefaultAsync(Expression> predicate, IEnumerable>> includes); 19 | 20 | Task GetFirstOrDefaultAsync(Expression> predicate, Func, IIncludableQueryable> includeQuery); 21 | 22 | Task> GetAllAsync(Expression> predicate); 23 | 24 | Task> GetAllAsync(Expression> predicate, IEnumerable>> includes); 25 | Task> GetAllAsync(Expression> predicate, Func, IIncludableQueryable> includeQuery); 26 | 27 | Task> GetAllAsync(Expression> predicate, Func, IOrderedQueryable> sort); 28 | 29 | Task> GetAllAsync( 30 | Expression> predicate, 31 | Func, IOrderedQueryable> sort, 32 | IEnumerable>> includes); 33 | 34 | Task> GetAllAsync(Expression> predicate, 35 | Func, IOrderedQueryable> sort, int pageIndex, int pageSize); 36 | 37 | Task> GetAllAsync( 38 | Expression> predicate, 39 | Func, IOrderedQueryable> sort, 40 | int pageIndex, 41 | int pageSize, 42 | IEnumerable>> includes); 43 | 44 | Task> GetAllAsync( 45 | Expression> predicate, 46 | Func, IOrderedQueryable> sort, 47 | int pageIndex, 48 | int pageSize, 49 | Func, IIncludableQueryable> includeQuery); 50 | 51 | Task AddAsync(TEntity entity); 52 | 53 | Task> AddRangeAsync(IEnumerable entities); 54 | 55 | Task UpdateAsync(TEntity entity); 56 | 57 | Task> UpdateRangeAsync(List entities); 58 | 59 | Task DeleteAsync(TEntity entity); 60 | 61 | Task AnyAsync(Expression> predicate); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/DependencyInjection.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Application.Helpers; 2 | using ChitChat.DataAccess.Data; 3 | using ChitChat.Domain.Identity; 4 | using ChitChat.Infrastructure.Caching; 5 | using ChitChat.Infrastructure.CloudinaryConfigurations; 6 | using ChitChat.Infrastructure.EntityFrameworkCore; 7 | using ChitChat.Infrastructure.Logging; 8 | using ChitChat.Infrastructure.Middleware; 9 | using ChitChat.Infrastructure.Services; 10 | using ChitChat.Infrastructure.SignalR; 11 | 12 | using Microsoft.AspNetCore.Builder; 13 | using Microsoft.AspNetCore.Identity; 14 | using Microsoft.Extensions.DependencyInjection; 15 | 16 | namespace ChitChat.Infrastructure 17 | { 18 | public static class DependencyInjection 19 | { 20 | public static WebApplicationBuilder AddInfrastructure(this WebApplicationBuilder builder) 21 | { 22 | builder 23 | .AddEntityFramewordCore() 24 | //.AddAppAuthorization() 25 | .AddCaching() 26 | .AddSignalRRegistration(); 27 | 28 | 29 | // Services 30 | builder.Services 31 | .AddInfrastructureService().AddAuthorization(); 32 | 33 | // Host 34 | builder.Host.AddHostSerilogConfiguration(); 35 | 36 | // Validation 37 | 38 | 39 | return builder; 40 | 41 | } 42 | public static IServiceCollection AddInfrastructureService(this IServiceCollection services) 43 | { 44 | services.AddIdentity(); 45 | services.AddCloudinary(); 46 | services.AddSingleton(); 47 | services.AddSingleton(); 48 | services.AddSingleton(); 49 | return services; 50 | } 51 | private static void AddIdentity(this IServiceCollection services) 52 | { 53 | services.AddIdentity(options => 54 | { 55 | options.SignIn.RequireConfirmedAccount = true; 56 | }) 57 | .AddEntityFrameworkStores(); 58 | services.Configure(options => 59 | { 60 | options.Password.RequireDigit = true; 61 | options.Password.RequireLowercase = true; 62 | options.Password.RequireNonAlphanumeric = true; 63 | options.Password.RequireUppercase = true; 64 | options.Password.RequiredLength = 6; 65 | options.Password.RequiredUniqueChars = 1; 66 | 67 | options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromDays(30); 68 | options.Lockout.MaxFailedAccessAttempts = 5; 69 | options.Lockout.AllowedForNewUsers = true; 70 | 71 | options.User.RequireUniqueEmail = true; 72 | }); 73 | } 74 | public static IApplicationBuilder AddInfrastuctureApplication(this IApplicationBuilder app) 75 | { 76 | app.UseMiddleware(); 77 | return app; 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chit Chat - Backend Services 2 | 3 | A backend services for a social networking application, built with `.NET Core` and deployed using `Docker` & `AWS`. This repository includes all the RESTful APIs and logic required to support core functionalities of the social network, including a **Recommendation System** and **Real-Time Communication** via WebRTC. 4 | 5 | --- 6 | 7 | ## ✨ Features 8 | 9 | - **Feeds**: Personalized newsfeed based on user activity. 10 | - **Notifications**: Real-time notifications for interactions. 11 | - **Real-Time Communication**: Audio/video calls and real-time chat powered by WebRTC. 12 | - **Recommendation System**: Personalized suggestions for friends, groups, or content using collaborative filtering and user activity analysis. 13 | - **Search**: Search for users, posts, or hashtags. 14 | - **Secure Authentication**: Token-based authentication using JWT. 15 | - **Social Interactions**: Follow/unfollow, posting, and commenting. 16 | - **User Management**: Registration, login, and profile updates. 17 | 18 | --- 19 | 20 | ## 🛠 Tech Stack 21 | 22 | - **Framework**: .NET Core (Clean Architecture) 23 | - **Database**: Amazon Aurora MySQL 24 | - **Authentication**: JWT (JSON Web Token) 25 | - **Recommendation System**: Content-based and Collaborative Filtering (e.g., Matrix Factorization, User-Item Similarity) 26 | - **Real-Time Communication**: WebRTC, SignalR 27 | - **Containerization**: Docker 28 | - **Other Tools**: Entity Framework Core, AutoMapper, FluentValidation 29 | 30 | --- 31 | 32 | ## 🚀 Installation Guide 33 | 34 | ### Prerequisites 35 | 36 | - Install [Docker](https://www.docker.com/) 37 | - Install [.NET Core SDK](https://dotnet.microsoft.com/download) 38 | 39 | ### Steps 40 | 41 | 1. **Clone the repository**: 42 | 43 | ```bash 44 | git clone https://github.com/thanhpt1110/chit-chat-backend 45 | cd chit-chat-backend 46 | ``` 47 | 48 | 2. **Set up environment variables**: 49 | Create a .env file in the `ChitChat.WebAPI` directory with the following content: 50 | 51 | ```bash 52 | SecretKey = # The secret key used for signing and verifying tokens 53 | TokenValidityInDays = # The number of days the token is valid 54 | RefreshTokenValidityInDays = # The number of days the refresh token is valid 55 | Issuer = # The issuer of the token 56 | Audience = # The audience for whom the token is issued 57 | CloudinaryCloudName = # The Cloudinary cloud name 58 | CloudinaryApiKey = # The Cloudinary API key 59 | CloudinaryApiSecret = # The Cloudinary API secret key 60 | ``` 61 | 62 | 3. **Build and run with Docker**: 63 | 64 | ```bash 65 | docker-compose up --build 66 | ``` 67 | 68 | 4. **Access the application**: 69 | 70 | ```bash 71 | The backend will be running on http://localhost:8080. 72 | ``` 73 | 74 | 5. **Build and run with Docker**: 75 | 76 | ```bash 77 | Visit http://localhost:8080/swagger/index.html to explore the API endpoints using Swagger UI. 78 | ``` 79 | 80 | --- 81 | 82 | ## 🤝 Authors 83 | 84 | [Nguyễn Phúc Bình](https://github.com/leesoonduck3009) 85 | 86 | [Phan Tuấn Thành](https://github.com/thanhpt1110) 87 | 88 | [Lê Thanh Tuấn](https://github.com/thtuanlegithub) 89 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Data/DbContextSeed.cs: -------------------------------------------------------------------------------- 1 | using ChitChat.Domain.Enums; 2 | using ChitChat.Domain.Identity; 3 | 4 | using Microsoft.AspNetCore.Identity; 5 | 6 | namespace ChitChat.DataAccess.Data 7 | { 8 | public static class DbContextSeed 9 | { 10 | public static async Task SeedDatabaseAsync(UserManager userManager, RoleManager roleManager) 11 | { 12 | // Seed dữ liệu người dùng 13 | var hasher = new PasswordHasher(); 14 | /* for(int i = 0; i < 8; i++) 15 | { 16 | var user = new UserApplication 17 | { 18 | Id = Guid.NewGuid().ToString(), 19 | UserName = $"user{i}", 20 | DisplayName = $"user{i}", 21 | Email = $"user{i}@gmail.com", 22 | EmailConfirmed = true, 23 | AvatarUrl = "", 24 | UserStatus = Domain.Enums.UserStatus.Public, 25 | }; 26 | await userManager.CreateAsync(user, "Password123!"); 27 | 28 | await userManager.AddToRoleAsync(user, UserRoles.User.ToString()); 29 | }*/ 30 | if (!roleManager.Roles.Any()) 31 | { 32 | foreach (var role in Enum.GetNames()) 33 | { 34 | var applicationRole = new ApplicationRole 35 | { 36 | Name = role.ToString() 37 | }; 38 | 39 | await roleManager.CreateAsync(applicationRole); 40 | } 41 | } 42 | if (!userManager.Users.Any()) 43 | { 44 | var adminUsers = new List 45 | { 46 | new UserApplication 47 | { 48 | Id = Guid.NewGuid().ToString(), 49 | UserName = "admin", 50 | DisplayName = "admin", 51 | Email = "admin@gmail.com", 52 | EmailConfirmed = true, 53 | AvatarUrl = "", 54 | UserStatus = Domain.Enums.UserStatus.Public, 55 | }, 56 | new UserApplication 57 | { 58 | Id = Guid.NewGuid().ToString(), 59 | UserName = "admin1", 60 | DisplayName = "admin1", 61 | Email = "admin1@gmail.com", 62 | EmailConfirmed = true, 63 | AvatarUrl = "", 64 | UserStatus = Domain.Enums.UserStatus.Public, 65 | } 66 | }; 67 | 68 | foreach (var user in adminUsers) 69 | { 70 | await userManager.CreateAsync(user, "Password123!"); 71 | 72 | await userManager.AddToRoleAsync(user, UserRoles.Admin.ToString()); 73 | } 74 | 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/src.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.Application", "ChitChat.Application\ChitChat.Application.csproj", "{591D589F-6F4A-4276-B08E-3B4CA52E7409}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.DataAccess", "ChitChat.DataAccess\ChitChat.DataAccess.csproj", "{AE3C0A21-7AEC-45D0-87F3-CED322F508D8}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.Domain", "ChitChat.Domain\ChitChat.Domain.csproj", "{0C7DF8A0-2407-4841-A736-F3ED57450568}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.Infrastructure", "ChitChat.Infrastructure\ChitChat.Infrastructure.csproj", "{890184FA-1089-4001-9D0F-0222C7F3BEB1}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.WebAPI", "ChitChat.WebAPI\ChitChat.WebAPI.csproj", "{84920F32-D3A5-44A3-BD0C-56AE81B8941C}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {591D589F-6F4A-4276-B08E-3B4CA52E7409}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {591D589F-6F4A-4276-B08E-3B4CA52E7409}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {591D589F-6F4A-4276-B08E-3B4CA52E7409}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {591D589F-6F4A-4276-B08E-3B4CA52E7409}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {AE3C0A21-7AEC-45D0-87F3-CED322F508D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {AE3C0A21-7AEC-45D0-87F3-CED322F508D8}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {AE3C0A21-7AEC-45D0-87F3-CED322F508D8}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {AE3C0A21-7AEC-45D0-87F3-CED322F508D8}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {0C7DF8A0-2407-4841-A736-F3ED57450568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {0C7DF8A0-2407-4841-A736-F3ED57450568}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {0C7DF8A0-2407-4841-A736-F3ED57450568}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {0C7DF8A0-2407-4841-A736-F3ED57450568}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {890184FA-1089-4001-9D0F-0222C7F3BEB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {890184FA-1089-4001-9D0F-0222C7F3BEB1}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {890184FA-1089-4001-9D0F-0222C7F3BEB1}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {890184FA-1089-4001-9D0F-0222C7F3BEB1}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {84920F32-D3A5-44A3-BD0C-56AE81B8941C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {84920F32-D3A5-44A3-BD0C-56AE81B8941C}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {84920F32-D3A5-44A3-BD0C-56AE81B8941C}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {84920F32-D3A5-44A3-BD0C-56AE81B8941C}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {B9FAF292-534F-49A1-BBDE-F238DA4C6187} 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Services/CloudinaryService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | using ChitChat.Application.Helpers; 4 | using ChitChat.Application.Models.Dtos.Post; 5 | using ChitChat.Domain.Enums; 6 | 7 | using CloudinaryDotNet; 8 | using CloudinaryDotNet.Actions; 9 | 10 | using Microsoft.AspNetCore.Http; 11 | using Microsoft.Extensions.Logging; 12 | 13 | namespace ChitChat.Infrastructure.Services 14 | { 15 | public class CloudinaryService : ICloudinaryService 16 | { 17 | private readonly Cloudinary _cloudinary; 18 | private readonly ILogger _logger; 19 | public CloudinaryService(Cloudinary cloudinary, ILogger logger) 20 | { 21 | _cloudinary = cloudinary; 22 | _logger = logger; 23 | } 24 | 25 | 26 | public async Task> PostMediaToCloudAsync(List files, Guid postId) 27 | { 28 | var stopwatch = Stopwatch.StartNew(); 29 | var uploadTasks = files.Select(async file => 30 | { 31 | var postMediaId = Guid.NewGuid(); 32 | var uploadResult = await UploadFileToCloudinary(file, postId, postMediaId); 33 | return uploadResult != null 34 | ? new PostMediaDto 35 | { 36 | MediaType = MediaType.Image.ToString(), 37 | MediaUrl = uploadResult.SecureUrl.AbsoluteUri, 38 | Description = "Image Description", 39 | Id = postMediaId 40 | } 41 | : null; 42 | }); 43 | 44 | var results = await Task.WhenAll(uploadTasks); 45 | stopwatch.Stop(); 46 | _logger.LogInformation($"Uploaded {files.Count} files to Cloudinary in {stopwatch.ElapsedMilliseconds}ms"); 47 | return results.Where(result => result != null).ToList(); 48 | } 49 | 50 | private async Task UploadFileToCloudinary(IFormFile file, Guid postId, Guid postMediaId) 51 | { 52 | var uploadResult = new ImageUploadResult(); 53 | if (file.Length > 0) 54 | { 55 | using (var stream = file.OpenReadStream()) 56 | { 57 | string customId = GetPublicId(postId, postMediaId); 58 | 59 | var uploadParams = new ImageUploadParams 60 | { 61 | File = new FileDescription(file.FileName, stream), 62 | PublicId = customId, 63 | Transformation = new Transformation() 64 | .Width(800) 65 | .Height(800) 66 | .Crop("limit") 67 | }; 68 | uploadResult = await _cloudinary.UploadAsync(uploadParams); 69 | } 70 | } 71 | return uploadResult; 72 | } 73 | public async Task DeleteMediaFromCloudAsync(Guid postId, Guid postMediaId) 74 | { 75 | string publicId = GetPublicId(postId, postMediaId); 76 | var deletionParams = new DeletionParams(publicId); 77 | var result = await _cloudinary.DestroyAsync(deletionParams); 78 | return result.Result == "ok"; 79 | } 80 | private static string GetPublicId(Guid postId, Guid postMediaId) 81 | { 82 | return $"post_{postId}/media_{postMediaId}"; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/ChitChat.Application/MachineLearning/Services/TrainingModelService.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | 3 | using ChitChat.Application.MachineLearning.Models; 4 | using ChitChat.Application.MachineLearning.Services.Interface; 5 | using ChitChat.Application.Models.Dtos.Post; 6 | using ChitChat.Domain.Entities.PostEntities; 7 | 8 | using Microsoft.ML; 9 | using Microsoft.ML.Data; 10 | 11 | namespace ChitChat.Application.MachineLearning.Services 12 | { 13 | public class TrainingModelService : ITrainingModelService 14 | { 15 | private readonly MLContext _mlContext; 16 | private readonly IMapper _mapper; 17 | public TrainingModelService(IMapper mapper) 18 | { 19 | _mlContext = new MLContext(); 20 | _mapper = mapper; 21 | 22 | } 23 | public List GetRecommendationPostModel(string userId 24 | , List dataTrain 25 | , List postReccomendation) 26 | { 27 | IDataView dataTrainView = _mlContext.Data.LoadFromEnumerable(dataTrain); 28 | var split = _mlContext.Data.TrainTestSplit(dataTrainView, testFraction: 0.2); 29 | var dataPipeline = _mlContext.Transforms.Conversion.MapValueToKey("UserIdKey", "UserId") 30 | .Append(_mlContext.Transforms.Conversion.MapValueToKey("PostIdKey", "PostId")) 31 | .Append(_mlContext.Transforms.Text.FeaturizeText("PostDescriptionDecoded", "PostDescription")) 32 | .Append(_mlContext.Transforms.Conversion.ConvertType("TotalPointDecoded", "TotalPoint", DataKind.Single)) 33 | .Append(_mlContext.Transforms.Concatenate("Features", 34 | new[] { "PostDescriptionDecoded", "TotalPointDecoded" })) // Chúng ta đưa các đặc trưng liên quan vào đây 35 | .Append(_mlContext.Recommendation().Trainers.MatrixFactorization( 36 | labelColumnName: "TotalPointDecoded", // Sử dụng ReactionCount làm label (hoặc cái bạn muốn dự đoán) 37 | matrixColumnIndexColumnName: "UserIdKey", // Cột này chỉ người dùng 38 | matrixRowIndexColumnName: "PostIdKey", // Cột này chỉ bài viết 39 | numberOfIterations: 20, // Số vòng lặp 40 | approximationRank: 50)); 41 | var model = dataPipeline.Fit(split.TrainSet); 42 | var predictions = model.Transform(split.TestSet); 43 | var metrics = _mlContext.Regression.Evaluate(predictions, labelColumnName: "TotalPointDecoded"); 44 | Console.WriteLine($"R-Squared: {metrics.RSquared:F2}"); 45 | Console.WriteLine($"Root Mean Squared Error: {metrics.RootMeanSquaredError:F2}"); 46 | var predictor = _mlContext.Model.CreatePredictionEngine(model); 47 | var response = new List(); 48 | foreach (var item in postReccomendation) 49 | { 50 | UserInteractionModelItem userItem = new UserInteractionModelItem 51 | { 52 | UserId = userId, 53 | PostId = item.Id.ToString(), 54 | PostDescription = item.Description 55 | }; 56 | var prediction = predictor.Predict(userItem); 57 | response.Add(new ResponseRecommendationModel() 58 | { 59 | Post = _mapper.Map(item), 60 | Score = float.IsNaN(prediction.Score) ? 0 : prediction.Score 61 | }); 62 | } 63 | return response; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Migrations/20241117121420_V1Update.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace ChitChat.DataAccess.Migrations 6 | { 7 | /// 8 | public partial class V1Update : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.DropColumn( 14 | name: "TestMigration", 15 | table: "Comments"); 16 | 17 | migrationBuilder.DropColumn( 18 | name: "Test_Update_comment", 19 | table: "Comments"); 20 | 21 | migrationBuilder.AlterColumn( 22 | name: "InteractionType", 23 | table: "UserInteractions", 24 | type: "int", 25 | nullable: false, 26 | oldClrType: typeof(string), 27 | oldType: "longtext") 28 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 29 | 30 | migrationBuilder.AddColumn( 31 | name: "CommentCount", 32 | table: "Posts", 33 | type: "int", 34 | nullable: false, 35 | defaultValue: 0); 36 | 37 | migrationBuilder.AddColumn( 38 | name: "ReactionCount", 39 | table: "Posts", 40 | type: "int", 41 | nullable: false, 42 | defaultValue: 0); 43 | 44 | migrationBuilder.AddColumn( 45 | name: "CommentType", 46 | table: "Comments", 47 | type: "int", 48 | nullable: false, 49 | defaultValue: 0); 50 | 51 | migrationBuilder.AddColumn( 52 | name: "ReactionCount", 53 | table: "Comments", 54 | type: "int", 55 | nullable: false, 56 | defaultValue: 0); 57 | } 58 | 59 | /// 60 | protected override void Down(MigrationBuilder migrationBuilder) 61 | { 62 | migrationBuilder.DropColumn( 63 | name: "CommentCount", 64 | table: "Posts"); 65 | 66 | migrationBuilder.DropColumn( 67 | name: "ReactionCount", 68 | table: "Posts"); 69 | 70 | migrationBuilder.DropColumn( 71 | name: "CommentType", 72 | table: "Comments"); 73 | 74 | migrationBuilder.DropColumn( 75 | name: "ReactionCount", 76 | table: "Comments"); 77 | 78 | migrationBuilder.AlterColumn( 79 | name: "InteractionType", 80 | table: "UserInteractions", 81 | type: "longtext", 82 | nullable: false, 83 | oldClrType: typeof(int), 84 | oldType: "int") 85 | .Annotation("MySql:CharSet", "utf8mb4"); 86 | 87 | migrationBuilder.AddColumn( 88 | name: "TestMigration", 89 | table: "Comments", 90 | type: "longtext", 91 | nullable: false) 92 | .Annotation("MySql:CharSet", "utf8mb4"); 93 | 94 | migrationBuilder.AddColumn( 95 | name: "Test_Update_comment", 96 | table: "Comments", 97 | type: "longtext", 98 | nullable: false) 99 | .Annotation("MySql:CharSet", "utf8mb4"); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Services/TokenService.cs: -------------------------------------------------------------------------------- 1 | using System.IdentityModel.Tokens.Jwt; 2 | using System.Security.Claims; 3 | using System.Security.Cryptography; 4 | 5 | using ChitChat.Application.Exceptions; 6 | using ChitChat.Application.Helpers; 7 | using ChitChat.Domain.Common; 8 | using ChitChat.Domain.Identity; 9 | using ChitChat.Infrastructure.ConfigSetting; 10 | 11 | using Microsoft.IdentityModel.Tokens; 12 | 13 | namespace ChitChat.Infrastructure.Services 14 | { 15 | public class TokenService : ITokenService 16 | { 17 | private readonly JWTConfigSetting _jWTConfigSetting; 18 | public TokenService(JWTConfigSetting jWTConfigSetting) 19 | { 20 | _jWTConfigSetting = jWTConfigSetting; 21 | } 22 | public (string token, int validDays) GenerateRefreshToken() 23 | { 24 | var randomNumber = new byte[64]; 25 | using var randomNumberGenerator = RandomNumberGenerator.Create(); 26 | randomNumberGenerator.GetBytes(randomNumber); 27 | return (Convert.ToBase64String(randomNumber), _jWTConfigSetting.RefreshTokenValidityInDays); 28 | } 29 | public string GenerateAccessToken(UserApplication user, IEnumerable roles, LoginHistory loginHistory) 30 | { 31 | var key = Encoding.ASCII.GetBytes(_jWTConfigSetting.SecretKey); 32 | 33 | var claims = new[] 34 | { 35 | new Claim(ClaimTypes.NameIdentifier, user.Id), 36 | new Claim(ClaimTypes.Name, user.UserName), 37 | new Claim(JWTConfigSetting.LoginHistoryIdClaimType, loginHistory.Id.ToString()), 38 | }; 39 | // Thêm các claim cho từng role của user 40 | var tokenHandler = new JwtSecurityTokenHandler(); 41 | 42 | var tokenDescriptor = new SecurityTokenDescriptor 43 | { 44 | Issuer = _jWTConfigSetting?.Issuer, 45 | Audience = _jWTConfigSetting?.Audience, 46 | Subject = new ClaimsIdentity(claims), 47 | Expires = DateTime.UtcNow.AddDays(_jWTConfigSetting.TokenValidityInDays), 48 | SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) 49 | }; 50 | 51 | var token = tokenHandler.CreateToken(tokenDescriptor); 52 | 53 | return tokenHandler.WriteToken(token); 54 | } 55 | 56 | public async Task GetPrincipalFromExpiredToken(string? token) 57 | { 58 | var tokenValidationParameters = new TokenValidationParameters 59 | { 60 | ValidateIssuerSigningKey = true, 61 | ValidIssuer = _jWTConfigSetting.Issuer, 62 | ValidAudience = _jWTConfigSetting.Audience, 63 | IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jWTConfigSetting.SecretKey)), 64 | ValidateLifetime = false 65 | }; 66 | 67 | var tokenHandler = new JwtSecurityTokenHandler(); 68 | 69 | var validateResult = await tokenHandler.ValidateTokenAsync(token, tokenValidationParameters); 70 | 71 | if (!validateResult.IsValid) 72 | { 73 | throw new InvalidModelException(ErrorDescription.InvalidAccessOrRefreshToken); 74 | } 75 | 76 | var securityToken = validateResult.SecurityToken; 77 | 78 | if (securityToken is not JwtSecurityToken jwtSecurityToken || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) 79 | throw new SecurityTokenException("Invalid token"); 80 | 81 | return validateResult.ClaimsIdentity; 82 | 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /ChitChatSolution.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.35013.160 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.Infrastructure", "src\ChitChat.Infrastructure\ChitChat.Infrastructure.csproj", "{D7E66971-269F-43B2-B31E-1BCA2C91AD94}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.WebAPI", "src\ChitChat.WebAPI\ChitChat.WebAPI.csproj", "{D209FC8F-8470-46C1-934B-0FA7A203C246}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.Application", "src\ChitChat.Application\ChitChat.Application.csproj", "{4D59AAD4-48B5-4406-A701-168D7D0CB06B}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.DataAccess", "src\ChitChat.DataAccess\ChitChat.DataAccess.csproj", "{E7AEAAD5-EEEA-4978-8201-D0064F45AF9E}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChitChat.Domain", "src\ChitChat.Domain\ChitChat.Domain.csproj", "{EB8C3E1E-3ECF-4C0E-A804-E0BF1B967A61}" 15 | EndProject 16 | Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "DockerCompose", "docker\DockerCompose\DockerCompose.dcproj", "{37FE7C74-3803-4E83-A00F-09A51F680D0A}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {D7E66971-269F-43B2-B31E-1BCA2C91AD94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {D7E66971-269F-43B2-B31E-1BCA2C91AD94}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {D7E66971-269F-43B2-B31E-1BCA2C91AD94}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {D7E66971-269F-43B2-B31E-1BCA2C91AD94}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {D209FC8F-8470-46C1-934B-0FA7A203C246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {D209FC8F-8470-46C1-934B-0FA7A203C246}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {D209FC8F-8470-46C1-934B-0FA7A203C246}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {D209FC8F-8470-46C1-934B-0FA7A203C246}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {4D59AAD4-48B5-4406-A701-168D7D0CB06B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {4D59AAD4-48B5-4406-A701-168D7D0CB06B}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {4D59AAD4-48B5-4406-A701-168D7D0CB06B}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {4D59AAD4-48B5-4406-A701-168D7D0CB06B}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {E7AEAAD5-EEEA-4978-8201-D0064F45AF9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {E7AEAAD5-EEEA-4978-8201-D0064F45AF9E}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {E7AEAAD5-EEEA-4978-8201-D0064F45AF9E}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {E7AEAAD5-EEEA-4978-8201-D0064F45AF9E}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {EB8C3E1E-3ECF-4C0E-A804-E0BF1B967A61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {EB8C3E1E-3ECF-4C0E-A804-E0BF1B967A61}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {EB8C3E1E-3ECF-4C0E-A804-E0BF1B967A61}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {EB8C3E1E-3ECF-4C0E-A804-E0BF1B967A61}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {37FE7C74-3803-4E83-A00F-09A51F680D0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {37FE7C74-3803-4E83-A00F-09A51F680D0A}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {37FE7C74-3803-4E83-A00F-09A51F680D0A}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {37FE7C74-3803-4E83-A00F-09A51F680D0A}.Release|Any CPU.Build.0 = Release|Any CPU 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | GlobalSection(ExtensibilityGlobals) = postSolution 53 | SolutionGuid = {A8D92082-8185-4DE1-9243-36EFBE7514C3} 54 | EndGlobalSection 55 | EndGlobal 56 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Logging/SerilogRegistration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Serilog; 3 | using Serilog.Formatting.Json; 4 | 5 | namespace ChitChat.Infrastructure.Logging 6 | { 7 | internal static class SerilogRegistration 8 | { 9 | public static void AddHostSerilogConfiguration(this IHostBuilder host) 10 | { 11 | host.UseSerilog((ctx, service, config) => 12 | { 13 | config 14 | .Enrich.FromLogContext() 15 | .WriteTo.Console() 16 | .WriteTo.File(new JsonFormatter(), "logs/log-.txt", rollingInterval: RollingInterval.Day); 17 | }); 18 | } 19 | //public static WebApplicationBuilder AddCustomSerilog(this WebApplicationBuilder builder) 20 | //{ 21 | // var configuration = builder.Configuration; 22 | // var serilogOptions = configuration.GetSection(nameof(SerilogOptions)).Get(); 23 | 24 | // if (!serilogOptions!.Enabled) return builder; 25 | 26 | // var services = builder.Services; 27 | 28 | // var options = new ConfigurationReaderOptions(typeof(ConsoleLoggerConfigurationExtensions).Assembly, typeof(SerilogExpression).Assembly) 29 | // { 30 | // SectionName = nameof(SerilogOptions) 31 | // }; 32 | 33 | // services.UseSerilog(serilog => 34 | // { 35 | // serilog 36 | // .ReadFrom.Configuration(configuration, options) 37 | // .Enrich.FromLogContext() 38 | // .WriteTo.File(formatter: new CompactJsonFormatter(), 39 | // path: $@"{AppContext.BaseDirectory}/logs/Log.txt", 40 | // buffered: true, 41 | // flushToDiskInterval: TimeSpan.FromSeconds(serilogOptions.FlushFileToDiskInSeconds), 42 | // rollingInterval: RollingInterval.Day, 43 | // fileSizeLimitBytes: serilogOptions.FileSizeLimitInBytes, 44 | // rollOnFileSizeLimit: true); 45 | 46 | // if (serilogOptions.LogToConsole) 47 | // { 48 | // serilog.WriteTo.Console(new CompactJsonFormatter()); 49 | // } 50 | 51 | // var seqOptions = serilogOptions.SeqOptions; 52 | // if (seqOptions is not null && seqOptions is { Enabled: true }) 53 | // { 54 | // serilog 55 | // .WriteTo.Seq(serverUrl: seqOptions.SeqUrl, apiKey: seqOptions.SeqApiKey); 56 | // } 57 | 58 | // var applicationInsightsOptions = serilogOptions.ApplicationInsightsOptions; 59 | // if (applicationInsightsOptions is not null && applicationInsightsOptions is { Enabled: true }) 60 | // { 61 | // serilog 62 | // .WriteTo.ApplicationInsights(applicationInsightsOptions.ConnectionString, TelemetryConverter.Traces); 63 | // } 64 | // }); 65 | 66 | // return builder; 67 | //} 68 | 69 | //public static IApplicationBuilder UseCustomSerilog(this IApplicationBuilder application) 70 | //{ 71 | // var configuration = application.ApplicationServices.GetRequiredService(); 72 | 73 | // var serilogOptions = configuration.GetRequiredSection(nameof(SerilogOptions)).Get(); 74 | 75 | // if (!serilogOptions!.Enabled) 76 | // { 77 | // return application; 78 | // } 79 | 80 | // application.UseSerilogRequestLogging(); 81 | 82 | // return application; 83 | //} 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/ChitChat.Infrastructure/Middleware/GlobalExceptionHandlerMiddleware.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | using ChitChat.Application.Models; 4 | using ChitChat.Domain.Exceptions; 5 | 6 | using FluentValidation; 7 | 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace ChitChat.Infrastructure.Middleware 12 | { 13 | public class GlobalExceptionHandlerMiddleware 14 | { 15 | private readonly RequestDelegate _next; 16 | private readonly ILogger _logger; 17 | 18 | public GlobalExceptionHandlerMiddleware(RequestDelegate next, ILogger logger) 19 | { 20 | _next = next; 21 | _logger = logger; 22 | } 23 | 24 | public async Task InvokeAsync(HttpContext httpContext) 25 | { 26 | try 27 | { 28 | // Tiếp tục xử lý yêu cầu 29 | await _next(httpContext); 30 | } 31 | catch (Exception ex) 32 | { 33 | _logger.LogError(ex, "An unhandled exception occurred: {Message}", ex.Message); 34 | await HandleExceptionAsync(httpContext, ex); 35 | } 36 | } 37 | 38 | private async Task HandleExceptionAsync(HttpContext context, Exception ex) 39 | { 40 | _logger.LogError(ex.Message); 41 | 42 | var httpStatusCode = StatusCodes.Status500InternalServerError; 43 | httpStatusCode = ex switch 44 | { 45 | Application.Exceptions.ApplicationException => ((Application.Exceptions.ApplicationException)ex).Code switch 46 | { 47 | ApiResultErrorCodes.ModelValidation => StatusCodes.Status400BadRequest, 48 | ApiResultErrorCodes.Conflict => StatusCodes.Status400BadRequest, 49 | ApiResultErrorCodes.PermissionValidation => StatusCodes.Status403Forbidden, 50 | ApiResultErrorCodes.NotFound => StatusCodes.Status404NotFound, 51 | ApiResultErrorCodes.Unauthorize => StatusCodes.Status401Unauthorized, 52 | ApiResultErrorCodes.Forbidden => StatusCodes.Status403Forbidden, 53 | _ => httpStatusCode 54 | }, 55 | ValidationException => StatusCodes.Status400BadRequest, // Fluent Validation errors 56 | ResourceNotFoundException => StatusCodes.Status404NotFound, // Repository layer error 57 | _ => httpStatusCode 58 | }; 59 | var errorCode = ApiResultErrorCodes.InternalServerError; 60 | errorCode = ex switch 61 | { 62 | Application.Exceptions.ApplicationException => ((Application.Exceptions.ApplicationException)ex).Code, 63 | ValidationException => ApiResultErrorCodes.ModelValidation, // Fluent Validation errors 64 | ResourceNotFoundException => ApiResultErrorCodes.InternalServerError, // Repository layer error 65 | _ => errorCode 66 | }; 67 | var errors = ex switch 68 | { 69 | ValidationException => ((ValidationException)ex).Errors 70 | .Select(modelError => new ApiResultError(ApiResultErrorCodes.ModelValidation, modelError.ErrorMessage)) 71 | .ToArray(), 72 | _ => new ApiResultError[] { new ApiResultError(errorCode, ex.Message) } 73 | }; 74 | 75 | var response = ApiResult.Failure(errors); 76 | var result = JsonSerializer.Serialize(response); 77 | context.Response.ContentType = "application/json"; 78 | context.Response.StatusCode = httpStatusCode; 79 | await context.Response.WriteAsync(result); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Repositories/UserRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | using ChitChat.DataAccess.Data; 4 | using ChitChat.DataAccess.Repositories.Interface; 5 | using ChitChat.Domain.Entities; 6 | using ChitChat.Domain.Exceptions; 7 | using ChitChat.Domain.Identity; 8 | 9 | using Microsoft.EntityFrameworkCore.Query; 10 | 11 | namespace ChitChat.DataAccess.Repositories 12 | { 13 | public class UserRepository : IUserRepository 14 | { 15 | protected readonly ApplicationDbContext Context; 16 | protected readonly DbSet DbSet; 17 | public UserRepository(ApplicationDbContext context) 18 | { 19 | Context = context; 20 | DbSet = context.Set(); 21 | } 22 | public IQueryable GetQuery() => this.DbSet; 23 | 24 | public async Task GetFirstAsync(Expression> predicate) 25 | { 26 | var entity = await DbSet.Where(predicate).FirstOrDefaultAsync(); 27 | return entity ?? throw new ResourceNotFoundException(typeof(UserApplication)); 28 | } 29 | 30 | public async Task GetFirstOrDefaultAsync(Expression> predicate) 31 | { 32 | return await DbSet.Where(predicate).FirstOrDefaultAsync(); 33 | } 34 | public async Task> GetAllAsync(Expression> predicate) 35 | { 36 | return await DbSet.Where(predicate).ToListAsync(); 37 | } 38 | 39 | public async Task> GetAllAsync(Expression> predicate, IEnumerable>> includes) 40 | { 41 | var query = DbSet.Where(predicate); 42 | 43 | foreach (var include in includes) 44 | { 45 | query = query.Include(include); 46 | } 47 | 48 | return await query.ToListAsync(); 49 | } 50 | 51 | public async Task> GetAllAsync(Expression> predicate, Func, IIncludableQueryable> includeQuery) 52 | { 53 | var query = DbSet.Where(predicate); 54 | 55 | query = includeQuery(query); 56 | 57 | return await query.ToListAsync(); 58 | } 59 | 60 | public async Task> GetAllAsync(Expression> predicate, Func, IOrderedQueryable> sort) 61 | { 62 | var query = DbSet.Where(predicate); 63 | 64 | query = sort(query); 65 | 66 | return await query.ToListAsync(); 67 | } 68 | 69 | public async Task UpdateAsync(UserApplication entity) 70 | { 71 | DbSet.Update(entity); 72 | await Context.SaveChangesAsync(); 73 | 74 | return entity; 75 | } 76 | 77 | public async Task DeleteAsync(UserApplication entity) 78 | { 79 | var removedEntity = DbSet.Remove(entity).Entity; 80 | await Context.SaveChangesAsync(); 81 | 82 | return removedEntity; 83 | } 84 | 85 | public async Task AnyAsync(Expression> predicate) 86 | { 87 | return await DbSet.AnyAsync(predicate); 88 | } 89 | 90 | public async Task> UpdateRangeAsync(List entities) 91 | { 92 | DbSet.UpdateRange(entities); 93 | 94 | await Context.SaveChangesAsync(); 95 | 96 | return entities; 97 | } 98 | 99 | 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/ChitChat.DataAccess/Migrations/20241221022222_UpdaeFollower.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace ChitChat.DataAccess.Migrations 6 | { 7 | /// 8 | public partial class UpdaeFollower : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.AlterColumn( 14 | name: "UserId", 15 | table: "UserFollowers", 16 | type: "varchar(255)", 17 | nullable: false, 18 | oldClrType: typeof(string), 19 | oldType: "longtext") 20 | .Annotation("MySql:CharSet", "utf8mb4") 21 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 22 | 23 | migrationBuilder.AlterColumn( 24 | name: "FollowerId", 25 | table: "UserFollowers", 26 | type: "varchar(255)", 27 | nullable: false, 28 | oldClrType: typeof(string), 29 | oldType: "longtext") 30 | .Annotation("MySql:CharSet", "utf8mb4") 31 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 32 | 33 | migrationBuilder.CreateIndex( 34 | name: "IX_UserFollowers_FollowerId", 35 | table: "UserFollowers", 36 | column: "FollowerId"); 37 | 38 | migrationBuilder.CreateIndex( 39 | name: "IX_UserFollowers_UserId", 40 | table: "UserFollowers", 41 | column: "UserId"); 42 | 43 | migrationBuilder.AddForeignKey( 44 | name: "FK_UserFollowers_AspNetUsers_FollowerId", 45 | table: "UserFollowers", 46 | column: "FollowerId", 47 | principalTable: "AspNetUsers", 48 | principalColumn: "Id", 49 | onDelete: ReferentialAction.Cascade); 50 | 51 | migrationBuilder.AddForeignKey( 52 | name: "FK_UserFollowers_AspNetUsers_UserId", 53 | table: "UserFollowers", 54 | column: "UserId", 55 | principalTable: "AspNetUsers", 56 | principalColumn: "Id", 57 | onDelete: ReferentialAction.Cascade); 58 | } 59 | 60 | /// 61 | protected override void Down(MigrationBuilder migrationBuilder) 62 | { 63 | migrationBuilder.DropForeignKey( 64 | name: "FK_UserFollowers_AspNetUsers_FollowerId", 65 | table: "UserFollowers"); 66 | 67 | migrationBuilder.DropForeignKey( 68 | name: "FK_UserFollowers_AspNetUsers_UserId", 69 | table: "UserFollowers"); 70 | 71 | migrationBuilder.DropIndex( 72 | name: "IX_UserFollowers_FollowerId", 73 | table: "UserFollowers"); 74 | 75 | migrationBuilder.DropIndex( 76 | name: "IX_UserFollowers_UserId", 77 | table: "UserFollowers"); 78 | 79 | migrationBuilder.AlterColumn( 80 | name: "UserId", 81 | table: "UserFollowers", 82 | type: "longtext", 83 | nullable: false, 84 | oldClrType: typeof(string), 85 | oldType: "varchar(255)") 86 | .Annotation("MySql:CharSet", "utf8mb4") 87 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 88 | 89 | migrationBuilder.AlterColumn( 90 | name: "FollowerId", 91 | table: "UserFollowers", 92 | type: "longtext", 93 | nullable: false, 94 | oldClrType: typeof(string), 95 | oldType: "varchar(255)") 96 | .Annotation("MySql:CharSet", "utf8mb4") 97 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 98 | } 99 | } 100 | } 101 | --------------------------------------------------------------------------------