first commit
This commit is contained in:
@@ -0,0 +1,355 @@
|
||||
using Fitness_core_BE.Exceptions;
|
||||
using Fitness_core_BE.Helpers;
|
||||
using Fitness_core_BE.Infra.UoW;
|
||||
using Fitness_core_BE.Interfaces;
|
||||
using Fitness_core_BE.Interfaces.Services;
|
||||
using Fitness_core_BE.Models;
|
||||
using Fitness_core_BE.Models.IOs;
|
||||
|
||||
|
||||
|
||||
namespace Fitness_core_BE.Services.Feed
|
||||
{
|
||||
public class FeedService : IFeedService
|
||||
{
|
||||
// DocumentTypes.DocumentId for FEED_POST (seeded in CentralDbContext/AppDBContext).
|
||||
private const int FeedPostDocumentTypeId = 1005;
|
||||
|
||||
private readonly IFeedRepository _repository;
|
||||
private readonly UserRoleHelper _userRoleHelper;
|
||||
private readonly IUnitOfWork _uow;
|
||||
private readonly IActivityLogService _activityLogService;
|
||||
private readonly IDocumentService _documentService;
|
||||
private readonly IPushNotificationService _pushNotificationService;
|
||||
|
||||
public FeedService(IFeedRepository repository, UserRoleHelper userRoleHelper, IUnitOfWork uow, IActivityLogService activityLogService, IDocumentService documentService, IPushNotificationService pushNotificationService)
|
||||
{
|
||||
_repository = repository;
|
||||
_userRoleHelper = userRoleHelper;
|
||||
_uow = uow;
|
||||
_activityLogService = activityLogService;
|
||||
_documentService = documentService;
|
||||
_pushNotificationService = pushNotificationService;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<object> GetFeedPostById(object payload, HttpContext httpContext)
|
||||
{
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
Guid userId = DataExtractor.GetUserIdFromContext(httpContext);
|
||||
Guid postId = DataExtractor.GetRequiredGuid(data, "postId");
|
||||
|
||||
FeedPost post = await _repository.GetFeedPostByIdAsync(userId, postId);
|
||||
|
||||
return post;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<object> GetFeedForCustomer(object payload, HttpContext httpContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
Guid userId = DataExtractor.GetUserIdFromContext(httpContext);
|
||||
int skip = data.ContainsKey("skip") && data["skip"].TryGetInt32(out var skipValue) ? skipValue : 0;
|
||||
int take = data.ContainsKey("take") && data["take"].TryGetInt32(out var takeValue) ? takeValue : 10;
|
||||
|
||||
// A customer with no active gym has no single client feed to scope to — the
|
||||
// repository already falls back to the platform-wide feed for them (clientId
|
||||
// stays null), so this no longer short-circuits to an empty list.
|
||||
var (clientId, feedList) =
|
||||
await _repository.GetFeedForCustomerAsync(userId, skip, take);
|
||||
|
||||
var feedListWithLikeCount = new List<object>();
|
||||
foreach (var feed in feedList)
|
||||
{
|
||||
var likeCount = await _repository.GetLikeCountAsync(feed.FeedPostId);
|
||||
feedListWithLikeCount.Add(new
|
||||
{
|
||||
feedPostId = feed.FeedPostId,
|
||||
caption = feed.Caption,
|
||||
description = feed.Description,
|
||||
userId = feed.FKUserId,
|
||||
docId = feed.FkDocId,
|
||||
isActive = feed.IsActive,
|
||||
createdAt = feed.CreatedAt,
|
||||
creator = feed.User.UserName,
|
||||
likeCount,
|
||||
clientId = clientId
|
||||
});
|
||||
}
|
||||
|
||||
return feedListWithLikeCount;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//like
|
||||
public async Task<object> LikeAsync(object payload, HttpContext httpContext)
|
||||
{
|
||||
await _uow.BeginAsync();
|
||||
try
|
||||
{
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
Guid userId = DataExtractor.GetUserIdFromContext(httpContext);
|
||||
Guid postId = Guid.Parse(data["postId"].GetString()!);
|
||||
|
||||
|
||||
if (!await _repository.IsLikedAsync(postId, userId))
|
||||
{
|
||||
await _repository.AddLikeAsync(postId, userId);
|
||||
await _uow.CommitAsync();
|
||||
|
||||
return new { success = true, message = "Post liked successfully" };
|
||||
}
|
||||
|
||||
return new { success = false, message = "Post already liked" };
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//check like
|
||||
public async Task<object> IsLikedAsync(object payload, HttpContext httpContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
Guid userId = DataExtractor.GetUserIdFromContext(httpContext);
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
Guid postId = Guid.Parse(data["postId"].GetString()!);
|
||||
bool isLiked = await _repository.IsLikedAsync(postId, userId);
|
||||
return new { isLiked };
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<object> UnlikeAsync(object payload, HttpContext httpContext)
|
||||
{
|
||||
await _uow.BeginAsync();
|
||||
try
|
||||
{
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
Guid postId = Guid.Parse(data["postId"].GetString()!);
|
||||
Guid userId = Guid.Parse(data["userId"].GetString()!);
|
||||
|
||||
if (await _repository.IsLikedAsync(postId, userId))
|
||||
{
|
||||
await _repository.RemoveLikeAsync(postId, userId);
|
||||
await _uow.CommitAsync();
|
||||
|
||||
return new { success = true, message = "Post unliked successfully" };
|
||||
}
|
||||
|
||||
return new { success = false, message = "Post not liked yet" };
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//create feed
|
||||
public async Task<object> CreateFeed(object payload, HttpContext httpContext)
|
||||
{
|
||||
await _uow.BeginAsync();
|
||||
try
|
||||
{
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
Guid userId = DataExtractor.GetUserIdFromContext(httpContext);
|
||||
|
||||
// Tag every attachment with the FEED_POST document type unless the caller
|
||||
// already chose one. Must match a DocumentTypes row (UserDocuments FKs to it).
|
||||
object uploadPayload = payload;
|
||||
|
||||
if (data.TryGetValue("document", out var documentsElement) &&
|
||||
documentsElement.ValueKind == System.Text.Json.JsonValueKind.Array)
|
||||
{
|
||||
var payloadJson = System.Text.Json.JsonSerializer.Serialize(data);
|
||||
var payloadDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(
|
||||
payloadJson) ?? new Dictionary<string, object>();
|
||||
|
||||
var documentsArray = System.Text.Json.JsonSerializer.Deserialize<List<Dictionary<string, object>>>(
|
||||
documentsElement.GetRawText()) ?? new List<Dictionary<string, object>>();
|
||||
|
||||
foreach (var document in documentsArray)
|
||||
{
|
||||
if (!document.ContainsKey("FileType"))
|
||||
{
|
||||
document["FileType"] = FeedPostDocumentTypeId;
|
||||
}
|
||||
}
|
||||
|
||||
payloadDict["document"] = documentsArray;
|
||||
uploadPayload = payloadDict;
|
||||
}
|
||||
|
||||
var docResponseObj = await _documentService.UploadDocument(uploadPayload, httpContext);
|
||||
|
||||
dynamic docResponse = docResponseObj;
|
||||
|
||||
if (docResponse == null || docResponse?.uploadResults == null || docResponse?.uploadResults.Count == 0)
|
||||
{
|
||||
await _uow.RollbackAsync();
|
||||
return new { success = false, message = "Document upload failed" };
|
||||
}
|
||||
|
||||
var firstDoc = docResponse?.uploadResults[0];
|
||||
int docId = firstDoc?.DocumentId ?? 0;
|
||||
|
||||
var feedPost = new FeedPost
|
||||
{
|
||||
Caption = data.ContainsKey("caption") ? data["caption"].GetString() : null,
|
||||
Description = data.ContainsKey("description") ? data["description"].GetString() : null,
|
||||
FkDocId = docId,
|
||||
FKUserId = userId
|
||||
};
|
||||
|
||||
await _repository.CreateFeedAsync(feedPost);
|
||||
|
||||
await _uow.CommitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var customerIds = await _repository.GetActiveCustomerIdsByPosterUserIdAsync(userId);
|
||||
if (customerIds.Count > 0)
|
||||
{
|
||||
var caption = feedPost.Caption;
|
||||
var body = string.IsNullOrWhiteSpace(caption)
|
||||
? "Your gym shared a new post. Tap to view."
|
||||
: caption!.Length > 120 ? caption[..120] + "…" : caption;
|
||||
|
||||
await _pushNotificationService.NotifyCustomersAsync(
|
||||
customerIds,
|
||||
"New post from your gym",
|
||||
body,
|
||||
"FeedPostCreated",
|
||||
"MainTabs",
|
||||
new { screen = "Connect" }
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Exception notifyEx)
|
||||
{
|
||||
Console.WriteLine($"Push notification failed (non-critical): {notifyEx.Message}");
|
||||
}
|
||||
|
||||
return new { success = true, message = "Feed created successfully" };
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<object> ShowFeedByClient(object payload, HttpContext httpContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
Guid userId = DataExtractor.GetUserIdFromContext(httpContext);
|
||||
Guid clientId = await _userRoleHelper.GetClientId(userId);
|
||||
var feedList = await _repository.GetFeedByClientAsync(clientId);
|
||||
|
||||
if (feedList == null || !feedList.Any())
|
||||
{
|
||||
return new { success = false, message = "No feeds found", data = new List<object>() };
|
||||
}
|
||||
|
||||
var FeedListWithDoc = new List<object>();
|
||||
|
||||
foreach (var feed in feedList)
|
||||
{
|
||||
object? documentData = null;
|
||||
if (feed.FkDocId.HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var docPayload = new { documentId = feed.FkDocId.Value };
|
||||
documentData = await _documentService.GetDocumentById(docPayload, httpContext);
|
||||
}
|
||||
catch
|
||||
{
|
||||
documentData = null;
|
||||
}
|
||||
}
|
||||
|
||||
var likeCount = await _repository.GetLikeCountAsync(feed.FeedPostId);
|
||||
|
||||
FeedListWithDoc.Add(new
|
||||
{
|
||||
feedPostId = feed.FeedPostId,
|
||||
caption = feed.Caption,
|
||||
description = feed.Description,
|
||||
userId = feed.FKUserId,
|
||||
docId = feed.FkDocId,
|
||||
isActive = feed.IsActive,
|
||||
createdAt = feed.CreatedAt,
|
||||
likeCount = likeCount,
|
||||
document = documentData
|
||||
});
|
||||
}
|
||||
|
||||
return new { success = true, message = "Feeds retrieved successfully", data = FeedListWithDoc };
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<object> DeleteFeedByPostId(object payload, HttpContext httpContext)
|
||||
{
|
||||
var data = DeserializePayload.Deserialize(payload);
|
||||
|
||||
Guid createUserId = DataExtractor.GetUserIdFromContext(httpContext);
|
||||
Guid postId = DataExtractor.GetRequiredGuid(data, "postId");
|
||||
await _uow.BeginAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var result =await _repository.DeletePostPostIdAsync(createUserId, postId);
|
||||
await _uow.CommitAsync();
|
||||
return result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await _uow.RollbackAsync();
|
||||
throw new BadRequestException ("delete post failed") ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user