@@ -190,7 +190,7 @@ describe('AppealService.createAppeal', () => {
190
190
describe ( 'AppealService.updateAppeal' , ( ) => {
191
191
const baseAppeal = {
192
192
id : 'appeal-1' ,
193
- resourceId : 'member -123' ,
193
+ resourceId : 'resource -123' ,
194
194
reviewItemCommentId : 'review-item-comment-1' ,
195
195
content : 'Original appeal content' ,
196
196
reviewItemComment : {
@@ -209,7 +209,6 @@ describe('AppealService.updateAppeal', () => {
209
209
const updateRequest = {
210
210
reviewItemCommentId : baseAppeal . reviewItemCommentId ,
211
211
content : 'Updated appeal content' ,
212
- resourceId : baseAppeal . resourceId ,
213
212
} as any ;
214
213
215
214
const submitterAuthUser = {
@@ -230,6 +229,10 @@ describe('AppealService.updateAppeal', () => {
230
229
...baseAppeal ,
231
230
content : updateRequest . content ,
232
231
} ) ;
232
+ resourcePrismaMock . resource . findUnique . mockResolvedValue ( {
233
+ id : baseAppeal . resourceId ,
234
+ memberId : submitterAuthUser . userId ,
235
+ } ) ;
233
236
prismaErrorServiceMock . handleError . mockImplementation ( ( error : any ) => {
234
237
throw error ;
235
238
} ) ;
@@ -250,6 +253,9 @@ describe('AppealService.updateAppeal', () => {
250
253
expect ( challengeApiServiceMock . getChallengeDetail ) . toHaveBeenCalledWith (
251
254
'challenge-1' ,
252
255
) ;
256
+ expect ( resourcePrismaMock . resource . findUnique ) . toHaveBeenCalledWith ( {
257
+ where : { id : baseAppeal . resourceId } ,
258
+ } ) ;
253
259
expect ( prismaMock . appeal . update ) . toHaveBeenCalledWith ( {
254
260
where : { id : baseAppeal . id } ,
255
261
data : expect . objectContaining ( {
@@ -275,12 +281,30 @@ describe('AppealService.updateAppeal', () => {
275
281
276
282
expect ( prismaMock . appeal . update ) . not . toHaveBeenCalled ( ) ;
277
283
} ) ;
284
+
285
+ it ( 'prevents updates when resource ownership does not match the requester' , async ( ) => {
286
+ resourcePrismaMock . resource . findUnique . mockResolvedValueOnce ( {
287
+ id : baseAppeal . resourceId ,
288
+ memberId : 'member-999' ,
289
+ } ) ;
290
+
291
+ await expect (
292
+ service . updateAppeal ( submitterAuthUser , baseAppeal . id , updateRequest ) ,
293
+ ) . rejects . toMatchObject ( {
294
+ status : 403 ,
295
+ response : expect . objectContaining ( {
296
+ code : 'APPEAL_RESOURCE_OWNER_FORBIDDEN' ,
297
+ } ) ,
298
+ } ) ;
299
+
300
+ expect ( prismaMock . appeal . update ) . not . toHaveBeenCalled ( ) ;
301
+ } ) ;
278
302
} ) ;
279
303
280
304
describe ( 'AppealService.deleteAppeal' , ( ) => {
281
305
const baseAppeal = {
282
306
id : 'appeal-1' ,
283
- resourceId : 'member -123' ,
307
+ resourceId : 'resource -123' ,
284
308
reviewItemComment : {
285
309
reviewItem : {
286
310
review : {
@@ -309,6 +333,10 @@ describe('AppealService.deleteAppeal', () => {
309
333
} ) ;
310
334
prismaMock . appeal . findUnique . mockResolvedValue ( baseAppeal ) ;
311
335
prismaMock . appeal . delete . mockResolvedValue ( undefined ) ;
336
+ resourcePrismaMock . resource . findUnique . mockResolvedValue ( {
337
+ id : baseAppeal . resourceId ,
338
+ memberId : submitterAuthUser . userId ,
339
+ } ) ;
312
340
prismaErrorServiceMock . handleError . mockImplementation ( ( error : any ) => {
313
341
throw error ;
314
342
} ) ;
@@ -328,6 +356,9 @@ describe('AppealService.deleteAppeal', () => {
328
356
expect ( challengeApiServiceMock . getChallengeDetail ) . toHaveBeenCalledWith (
329
357
'challenge-1' ,
330
358
) ;
359
+ expect ( resourcePrismaMock . resource . findUnique ) . toHaveBeenCalledWith ( {
360
+ where : { id : baseAppeal . resourceId } ,
361
+ } ) ;
331
362
expect ( prismaMock . appeal . delete ) . toHaveBeenCalledWith ( {
332
363
where : { id : baseAppeal . id } ,
333
364
} ) ;
0 commit comments