@@ -13,13 +13,18 @@ async function formatChangelog(entry: any) {
1313 ? await Post . find ( { _id : { $in : entry . postIDs } } )
1414 : [ ] ;
1515
16+ const markdownDetails = entry . markdownDetails || '' ;
17+ const plaintextDetails = entry . plaintextDetails || ( markdownDetails ? htmlToPlainText ( markdownDetails ) : '' ) ;
18+
1619 return {
1720 id : entry . _id . toString ( ) ,
1821 created : entry . created ?. toISOString ( ) ,
1922 labels : entry . labels || [ ] ,
2023 lastSavedAt : entry . lastSavedAt ?. toISOString ( ) ,
21- markdownDetails : entry . markdownDetails || '' ,
22- plaintextDetails : entry . plaintextDetails || '' ,
24+ markdownDetails,
25+ plaintextDetails,
26+ // description is kept for compatibility with existing frontends
27+ description : plaintextDetails ,
2328 posts : posts . map ( p => ( {
2429 id : p . _id . toString ( ) ,
2530 title : p . title ,
@@ -179,6 +184,94 @@ export const createChangelog = asyncHandler(async (req: Request, res: Response):
179184 res . json ( formatted ) ;
180185} ) ;
181186
187+ /**
188+ * POST /entries/update
189+ * Update an existing changelog entry
190+ */
191+ export const updateChangelog = asyncHandler ( async ( req : Request , res : Response ) : Promise < void > => {
192+ const { id, title, details, labels, types, postIDs, publish } = req . body ;
193+
194+ if ( ! mongoose . Types . ObjectId . isValid ( id ) ) {
195+ throw new AppError ( 'invalid entry id' , 400 ) ;
196+ }
197+
198+ // Determine company context and load existing entry
199+ let companyID : mongoose . Types . ObjectId ;
200+
201+ if ( req . company ) {
202+ companyID = req . company . _id ;
203+ } else if ( ( req as any ) . user ?. companyID ) {
204+ companyID = ( req as any ) . user . companyID ;
205+ } else {
206+ const existing = await Changelog . findById ( id ) ;
207+ if ( ! existing ) {
208+ throw new AppError ( 'entry not found' , 404 ) ;
209+ }
210+ companyID = existing . companyID ;
211+ }
212+
213+ const existing = await Changelog . findOne ( { _id : id , companyID } ) ;
214+ if ( ! existing ) {
215+ throw new AppError ( 'entry not found' , 404 ) ;
216+ }
217+
218+ // Validate and map post IDs if provided
219+ let validPostIDs : mongoose . Types . ObjectId [ ] | undefined ;
220+ if ( postIDs && postIDs . length > 0 ) {
221+ const posts = await Post . find ( { _id : { $in : postIDs } , companyID } ) ;
222+ validPostIDs = posts . map ( p => p . _id ) ;
223+ }
224+
225+ const update : any = { lastSavedAt : new Date ( ) } ;
226+
227+ if ( typeof title === 'string' ) {
228+ update . title = title ;
229+ }
230+
231+ if ( typeof details === 'string' ) {
232+ update . markdownDetails = details ;
233+ update . plaintextDetails = htmlToPlainText ( details || '' ) ;
234+ }
235+
236+ if ( Array . isArray ( labels ) ) {
237+ update . labels = labels . map ( ( label : string , index : number ) => ( {
238+ id : `label-${ index } ` ,
239+ name : label ,
240+ } ) ) ;
241+ }
242+
243+ if ( Array . isArray ( types ) ) {
244+ update . types = types ;
245+ }
246+
247+ if ( validPostIDs ) {
248+ update . postIDs = validPostIDs ;
249+ }
250+
251+ if ( typeof publish === 'boolean' ) {
252+ if ( publish && existing . status !== 'published' ) {
253+ update . status = 'published' ;
254+ update . publishedAt = new Date ( ) ;
255+ } else if ( ! publish && existing . status === 'published' ) {
256+ update . status = 'draft' ;
257+ update . publishedAt = undefined ;
258+ }
259+ }
260+
261+ const updated = await Changelog . findOneAndUpdate (
262+ { _id : id , companyID } ,
263+ update ,
264+ { new : true }
265+ ) ;
266+
267+ if ( ! updated ) {
268+ throw new AppError ( 'failed to update entry' , 500 ) ;
269+ }
270+
271+ const formatted = await formatChangelog ( updated ) ;
272+ res . json ( formatted ) ;
273+ } ) ;
274+
182275/**
183276 * POST /entries/delete
184277 * Delete a changelog entry
0 commit comments