356 lines
13 KiB
C#
356 lines
13 KiB
C#
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") ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|