From 6ef787a3b82f28423e6935f945b950fc7678e7b7 Mon Sep 17 00:00:00 2001 From: Naomi Carrigan Date: Fri, 20 Feb 2026 00:13:00 -0800 Subject: [PATCH] fix: render HTML comments properly in activity feed Changed approach from stripping HTML on backend to rendering HTML with sanitization on frontend, matching the pattern used in comment-display component. This preserves HTML formatting (bold, italics, etc.) in comment previews whilst still protecting against XSS attacks. Backend changes: - Reverted stripHtml() method (no longer needed) - Keep full HTML content in commentPreview field Frontend changes: - Import and inject SanitizeService - Changed from text interpolation to [innerHTML] with sanitization - Changed

to

for comment preview container Co-Authored-By: Claude Sonnet 4.5 --- api/src/app/services/activity.service.ts | 16 ++++------------ .../activity/activity-feed.component.ts | 4 +++- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/api/src/app/services/activity.service.ts b/api/src/app/services/activity.service.ts index a8b0b2f..e4c546f 100644 --- a/api/src/app/services/activity.service.ts +++ b/api/src/app/services/activity.service.ts @@ -224,12 +224,11 @@ export class ActivityService { entityTitle = comment.manga.title; } - // Strip HTML tags and get first 100 characters of comment - const plainText = this.stripHtml(comment.content); + // Get first 100 characters of comment const commentPreview = - plainText.length > 100 - ? `${plainText.slice(0, 100)}...` - : plainText; + comment.content.length > 100 + ? `${comment.content.slice(0, 100)}...` + : comment.content; return { id: `comment-${comment.id}`, @@ -351,11 +350,4 @@ export class ActivityService { return "Unknown Item"; } } - - /** - * Strip HTML tags from content for plain text preview. - */ - private stripHtml(html: string): string { - return html.replace(/<[^>]*>/g, "").trim(); - } } diff --git a/apps/frontend/src/app/components/activity/activity-feed.component.ts b/apps/frontend/src/app/components/activity/activity-feed.component.ts index 3b07983..47be73f 100644 --- a/apps/frontend/src/app/components/activity/activity-feed.component.ts +++ b/apps/frontend/src/app/components/activity/activity-feed.component.ts @@ -10,6 +10,7 @@ import { RouterLink } from '@angular/router'; import type { Activity } from '@library/shared-types'; import { ActivityType } from '@library/shared-types'; import { ActivityService } from '../../services/activity.service'; +import { SanitizeService } from '../../services/sanitize.service'; @Component({ selector: 'app-activity-feed', @@ -97,7 +98,7 @@ import { ActivityService } from '../../services/activity.service'; {{ activity.entityTitle }} -

"{{ activity.commentPreview }}"

+
} @case (ActivityType.achievement) { @@ -360,6 +361,7 @@ import { ActivityService } from '../../services/activity.service'; }) export class ActivityFeedComponent implements OnInit { private activityService = inject(ActivityService); + public sanitizeService = inject(SanitizeService); // Make ActivityType accessible in template ActivityType = ActivityType;