using Nuuru.Server.DTOs.Forum;
using Nuuru.Server.DTOs.Reaction;
using Nuuru.Server.Models.Forum;
using Nuuru.Server.Services;
namespace Nuuru.Server.Extensions
{
///
/// Extension methods for mapping between Forum entities and DTOs
///
public static class ForumMappingExtensions
{
///
/// Maps a ForumCategory entity to ForumCategoryDto
///
public static ForumCategoryDto ToDto(this ForumCategory category, int threadCount = 0, int postCount = 0, ForumThread? latestThread = null, Dictionary? displayInfoMap = null)
{
if (category == null) return null!;
return new ForumCategoryDto
{
Id = category.Id,
Slug = category.Slug.StartsWith("clan-") ? "clan" : category.Slug,
Name = category.Name,
Description = category.Description,
DisplayOrder = category.DisplayOrder,
Color = category.Color,
ThreadCount = threadCount,
PostCount = postCount,
LatestThread = latestThread?.ToSummaryDto(displayInfoMap)
};
}
///
/// Maps a ForumCategory entity to ForumCategorySummaryDto
///
public static ForumCategorySummaryDto ToSummaryDto(this ForumCategory category)
{
if (category == null) return null!;
return new ForumCategorySummaryDto
{
Id = category.Id,
Slug = category.Slug.StartsWith("clan-") ? "clan" : category.Slug,
Name = category.Name,
Color = category.Color
};
}
///
/// Maps a ForumThread entity to ForumThreadDto
///
public static ForumThreadDto ToDto(this ForumThread thread, bool includeFirstPost = false, Guid? requestingUserId = null, Dictionary? displayInfoMap = null)
{
if (thread == null) return null!;
UserDisplayInfo? authorDisplayInfo = null;
if (thread.Author != null && displayInfoMap != null)
{
displayInfoMap.TryGetValue(thread.Author.Id, out authorDisplayInfo);
}
UserDisplayInfo? lastPostAuthorDisplayInfo = null;
if (thread.LastPost?.Author != null && displayInfoMap != null)
{
displayInfoMap.TryGetValue(thread.LastPost.Author.Id, out lastPostAuthorDisplayInfo);
}
var threadBansEnabled = !string.Equals(thread.Category?.Slug, "gen", StringComparison.OrdinalIgnoreCase);
var canManageBans = threadBansEnabled && requestingUserId.HasValue && thread.AuthorId == requestingUserId.Value;
var currentUserIsBanned = requestingUserId.HasValue
&& threadBansEnabled
&& thread.UserBans.Any(b => b.UserId == requestingUserId.Value);
return new ForumThreadDto
{
Id = thread.Id,
Title = thread.Title,
IsPinned = thread.IsPinned,
IsLocked = thread.IsLocked,
CurrentUserCanManageBans = canManageBans,
CurrentUserIsBanned = currentUserIsBanned,
CreatedAt = thread.CreatedAt,
LastPostAt = thread.LastPostAt,
ReplyCount = thread.ReplyCount,
ViewCount = thread.ViewCount,
Author = thread.Author?.ToUploaderDto(authorDisplayInfo)!,
LastPostId = thread.LastPostId,
LastPostAuthor = thread.LastPost?.Author?.ToUploaderDto(lastPostAuthorDisplayInfo),
Category = thread.Category?.ToSummaryDto()!,
FirstPost = includeFirstPost ? thread.FirstPost?.ToDto(requestingUserId, displayInfoMap) : null,
BannedUsers = canManageBans
? thread.UserBans
.Where(b => b.User != null)
.OrderBy(b => b.User.UserName)
.Select(b =>
{
UserDisplayInfo? bannedUserDisplayInfo = null;
displayInfoMap?.TryGetValue(b.UserId, out bannedUserDisplayInfo);
return new ForumThreadBannedUserDto
{
User = b.User.ToUploaderDto(bannedUserDisplayInfo),
BannedAt = b.CreatedAt
};
})
.ToList()
: []
};
}
///
/// Maps a ForumThread entity to ForumThreadSummaryDto
///
public static ForumThreadSummaryDto ToSummaryDto(this ForumThread thread, Dictionary? displayInfoMap = null)
{
if (thread == null) return null!;
UserDisplayInfo? authorDisplayInfo = null;
if (thread.Author != null && displayInfoMap != null)
{
displayInfoMap.TryGetValue(thread.Author.Id, out authorDisplayInfo);
}
UserDisplayInfo? lastPostAuthorDisplayInfo = null;
if (thread.LastPost?.Author != null && displayInfoMap != null)
{
displayInfoMap.TryGetValue(thread.LastPost.Author.Id, out lastPostAuthorDisplayInfo);
}
return new ForumThreadSummaryDto
{
Id = thread.Id,
Title = thread.Title,
LastPostAt = thread.LastPostAt,
ReplyCount = thread.ReplyCount,
Author = thread.Author?.ToUploaderDto(authorDisplayInfo)!,
LastPostId = thread.LastPostId,
LastPostAuthor = thread.LastPost?.Author?.ToUploaderDto(lastPostAuthorDisplayInfo)
};
}
///
/// Maps a collection of ForumThreads to ForumThreadDtos
///
public static List ToDto(this IEnumerable threads, bool includeFirstPost = false, Guid? requestingUserId = null, Dictionary? displayInfoMap = null)
{
return threads?.Select(t => t.ToDto(includeFirstPost, requestingUserId, displayInfoMap)).ToList() ?? new List();
}
///
/// Maps a ForumPost entity to ForumPostDto
///
/// The post to map
/// If provided, includes raw content only if this user is the author
/// Optional display info map for badge/color lookup
/// Optional reactions map for reaction data
public static ForumPostDto ToDto(
this ForumPost post,
Guid? requestingUserId = null,
Dictionary? displayInfoMap = null,
Dictionary? reactionsMap = null)
{
if (post == null) return null!;
UserDisplayInfo? authorDisplayInfo = null;
if (post.Author != null && displayInfoMap != null)
{
displayInfoMap.TryGetValue(post.Author.Id, out authorDisplayInfo);
}
ReactionDTO? reactions = null;
reactionsMap?.TryGetValue(post.Id, out reactions);
return new ForumPostDto
{
Id = post.Id,
ContentHtml = post.ContentHtml,
// Only include raw content for the author (so they can edit)
ContentRaw = requestingUserId.HasValue && post.AuthorId == requestingUserId.Value
? post.ContentRaw
: null,
CreatedAt = post.CreatedAt,
EditedAt = post.EditedAt,
Author = post.Author?.ToUploaderDto(authorDisplayInfo)!,
ThreadId = post.ThreadId,
Thread = post.Thread != null ? new ForumPostThreadDto
{
Id = post.Thread.Id,
Title = post.Thread.Title,
Category = post.Thread.Category?.ToSummaryDto()
} : null,
Reactions = reactions
};
}
///
/// Maps a collection of ForumPosts to ForumPostDtos
///
public static List ToDto(
this IEnumerable posts,
Guid? requestingUserId = null,
Dictionary? displayInfoMap = null,
Dictionary? reactionsMap = null)
{
return posts?.Select(p => p.ToDto(requestingUserId, displayInfoMap, reactionsMap)).ToList() ?? new List();
}
}
}