@@ -97,6 +97,10 @@ import {
9797} from '../repositories/projectRepository' ;
9898import { sortTokensByOrderAndAlphabets } from '../utils/tokenUtils' ;
9999import { getNotificationAdapter } from '../adapters/adaptersFactory' ;
100+ import {
101+ getRichTextPlainLength ,
102+ sanitizeProjectRichText ,
103+ } from '../utils/htmlSanitizer' ;
100104import { NETWORK_IDS } from '../provider' ;
101105import { getVerificationFormStatusByProjectId } from '../repositories/projectVerificationRepository' ;
102106import {
@@ -114,7 +118,10 @@ import { creteSlugFromProject, isSocialMediaEqual } from '../utils/utils';
114118import { findCampaignBySlug } from '../repositories/campaignRepository' ;
115119import { Campaign } from '../entities/campaign' ;
116120import { FeaturedUpdate } from '../entities/featuredUpdate' ;
117- import { PROJECT_UPDATE_CONTENT_MAX_LENGTH } from '../constants/validators' ;
121+ import {
122+ PROJECT_DESCRIPTION_MAX_LENGTH ,
123+ PROJECT_UPDATE_CONTENT_MAX_LENGTH ,
124+ } from '../constants/validators' ;
118125import { calculateGivbackFactor } from '../services/givbackService' ;
119126import { ProjectBySlugResponse } from './types/projectResolver' ;
120127import { ChainType } from '../types/network' ;
@@ -1508,6 +1515,12 @@ export class ProjectResolver {
15081515 i18n . __ ( translationErrorMessagesKeys . YOU_ARE_NOT_THE_OWNER_OF_PROJECT ) ,
15091516 ) ;
15101517
1518+ if ( newProjectData . description ) {
1519+ newProjectData . description = sanitizeProjectRichText (
1520+ newProjectData . description ,
1521+ ) ;
1522+ }
1523+
15111524 for ( const field in newProjectData ) {
15121525 if ( field === 'addresses' || field === 'socialMedia' ) {
15131526 // We will take care of addresses and relations manually
@@ -1774,7 +1787,23 @@ export class ProjectResolver {
17741787 @Ctx ( ) ctx : ApolloContext ,
17751788 ) : Promise < Project > {
17761789 const user = await getLoggedInUser ( ctx ) ;
1777- const { image, description } = projectInput ;
1790+ const { image } = projectInput ;
1791+ if ( projectInput . description ) {
1792+ if (
1793+ getRichTextPlainLength ( projectInput . description ) >
1794+ PROJECT_DESCRIPTION_MAX_LENGTH
1795+ ) {
1796+ throw new Error (
1797+ i18n . __ (
1798+ translationErrorMessagesKeys . PROJECT_DESCRIPTION_LENGTH_SIZE_EXCEEDED ,
1799+ ) ,
1800+ ) ;
1801+ }
1802+ projectInput . description = sanitizeProjectRichText (
1803+ projectInput . description ,
1804+ ) ;
1805+ }
1806+ const { description } = projectInput ;
17781807
17791808 const dbUser = await findUserById ( user . id ) ;
17801809
@@ -1974,17 +2003,16 @@ export class ProjectResolver {
19742003 i18n . __ ( translationErrorMessagesKeys . AUTHENTICATION_REQUIRED ) ,
19752004 ) ;
19762005
1977- if (
1978- content ?. replace ( / < [ ^ > ] + > / g, '' ) ?. length >
1979- PROJECT_UPDATE_CONTENT_MAX_LENGTH
1980- ) {
2006+ if ( getRichTextPlainLength ( content ) > PROJECT_UPDATE_CONTENT_MAX_LENGTH ) {
19812007 throw new Error (
19822008 i18n . __ (
19832009 translationErrorMessagesKeys . PROJECT_UPDATE_CONTENT_LENGTH_SIZE_EXCEEDED ,
19842010 ) ,
19852011 ) ;
19862012 }
19872013
2014+ const sanitizedContent = sanitizeProjectRichText ( content ) ;
2015+
19882016 const owner = await findUserById ( user . userId ) ;
19892017
19902018 if ( ! owner )
@@ -2007,7 +2035,7 @@ export class ProjectResolver {
20072035 const update = ProjectUpdate . create ( {
20082036 userId : user . userId ,
20092037 projectId : project . id ,
2010- content,
2038+ content : sanitizedContent ,
20112039 title,
20122040 createdAt : new Date ( ) ,
20132041 isMain : false ,
@@ -2039,16 +2067,11 @@ export class ProjectResolver {
20392067 throw new Error (
20402068 i18n . __ ( translationErrorMessagesKeys . AUTHENTICATION_REQUIRED ) ,
20412069 ) ;
2042- if (
2043- content ?. replace ( / < [ ^ > ] + > / g, '' ) ?. length >
2044- PROJECT_UPDATE_CONTENT_MAX_LENGTH
2045- ) {
2046- throw new Error (
2047- i18n . __ (
2048- translationErrorMessagesKeys . PROJECT_UPDATE_CONTENT_LENGTH_SIZE_EXCEEDED ,
2049- ) ,
2050- ) ;
2051- }
2070+
2071+ // Intentionally no length check here: legacy project_update rows can
2072+ // exceed the current max, and rejecting on edit would block owners from
2073+ // fixing or trimming long content. New content is still capped via
2074+ // addProjectUpdate. (Per RamRamez's review on PR #2324.)
20522075
20532076 const owner = await findUserById ( user . userId ) ;
20542077
@@ -2075,7 +2098,7 @@ export class ProjectResolver {
20752098 ) ;
20762099
20772100 update . title = title ;
2078- update . content = content ;
2101+ update . content = sanitizeProjectRichText ( content ) ;
20792102 await update . save ( ) ;
20802103 await update . reload ( ) ;
20812104
0 commit comments