@@ -39,7 +39,7 @@ import {
3939} from '../../services/forum' ;
4040import { CoreTag } from '@features/tag/services/tag' ;
4141import { Translate } from '@singletons' ;
42- import { CoreFileUploader } from '@features/fileuploader/services/fileuploader' ;
42+ import { CoreFileUploader , CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader' ;
4343import { AddonModForumSync } from '../../services/forum-sync' ;
4444import { CoreSync } from '@services/sync' ;
4545import { CoreText } from '@singletons/text' ;
@@ -57,6 +57,7 @@ import { CoreToasts } from '@services/toasts';
5757import { toBoolean } from '@/core/transforms/boolean' ;
5858import { CorePopovers } from '@services/popovers' ;
5959import { CoreLoadings } from '@services/loadings' ;
60+ import { CoreWSFile } from '@services/ws' ;
6061
6162/**
6263 * Components that shows a discussion post, its attachments and the action buttons allowed (reply, etc.).
@@ -214,7 +215,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
214215 this . formData . isEditing = ! ! isEditing ;
215216 this . formData . subject = subject || this . defaultReplySubject || '' ;
216217 this . formData . message = message || null ;
217- this . formData . files = files || [ ] ;
218+ this . formData . files = ( files ?? [ ] ) . slice ( ) ; // Make a copy to avoid modifying the original array.
218219 this . formData . isprivatereply = ! ! isPrivate ;
219220 this . formData . id = postId ;
220221
@@ -392,10 +393,9 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
392393 return ;
393394 }
394395
395- let saveOffline = false ;
396396 let message = this . formData . message ;
397397 const subject = this . formData . subject ;
398- const replyingTo = this . formData . replyingTo ! ;
398+ const replyingTo = this . formData . replyingTo ?? 0 ;
399399 const files = this . formData . files || [ ] ;
400400 const isEditOnline = this . formData . id && this . formData . id > 0 ;
401401 const modal = await CoreLoadings . show ( 'core.sending' , true ) ;
@@ -413,73 +413,56 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
413413 // Add some HTML to the message if needed.
414414 message = CoreText . formatHtmlLines ( message ) ;
415415
416- // Upload attachments first if any.
417- let attachments ;
418-
419416 try {
420- if ( files . length ) {
421- try {
422- attachments = await AddonModForumHelper . uploadOrStoreReplyFiles (
423- this . forum . id ,
424- isEditOnline ? this . formData . id ! : replyingTo ,
425- files ,
426- false ,
427- ) ;
428- } catch ( error ) {
429- // Cannot upload them in online, save them in offline.
430- if ( ! this . forum . id || isEditOnline || CoreUtils . isWebServiceError ( error ) ) {
431- // Cannot store them in offline. Reject.
432- throw error ;
433- }
434-
435- saveOffline = true ;
436- attachments = await AddonModForumHelper . uploadOrStoreReplyFiles ( this . forum . id , replyingTo , files , true ) ;
437- }
438- }
439-
440417 let sent = false ;
441418
442- if ( isEditOnline ) {
443- sent = await AddonModForum . updatePost ( this . formData . id ! , subject , message , {
419+ if ( this . formData . id && this . formData . id > 0 ) {
420+ const attachments = await this . uploadAttachmentsForEditOnline ( this . formData . id ) ;
421+
422+ sent = await AddonModForum . updatePost ( this . formData . id , subject , message , {
444423 attachmentsid : attachments ,
445424 inlineattachmentsid : this . preparePostData ?. draftitemid ,
446425 } ) ;
447- } else if ( saveOffline ) {
448- // Save post in offline.
449- await AddonModForumOffline . replyPost (
450- replyingTo ,
451- this . discussionId ,
452- this . forum . id ,
453- this . forum . name ,
454- this . courseId ,
455- subject ,
456- message ,
457- {
458- attachmentsid : attachments ,
459- private : ! ! this . formData . isprivatereply ,
460- } ,
461- ) ;
462-
463- // Set sent to false since it wasn't sent to server.
464- sent = false ;
465426 } else {
466- // Try to send it to server.
467- // Don't allow offline if there are attachments since they were uploaded fine.
468- sent = await AddonModForum . replyPost (
469- replyingTo ,
470- this . discussionId ,
471- this . forum . id ,
472- this . forum . name ,
473- this . courseId ,
474- subject ,
475- message ,
476- {
477- attachmentsid : attachments ,
478- private : ! ! this . formData . isprivatereply ,
479- } ,
480- undefined ,
481- ! files . length ,
482- ) ;
427+ const { attachments, saveOffline } = await this . uploadAttachmentsForReply ( replyingTo ) ;
428+
429+ if ( saveOffline ) {
430+ // Save post in offline.
431+ await AddonModForumOffline . replyPost (
432+ replyingTo ,
433+ this . discussionId ,
434+ this . forum . id ,
435+ this . forum . name ,
436+ this . courseId ,
437+ subject ,
438+ message ,
439+ {
440+ attachmentsid : attachments ,
441+ private : ! ! this . formData . isprivatereply ,
442+ } ,
443+ ) ;
444+
445+ // Set sent to false since it wasn't sent to server.
446+ sent = false ;
447+ } else {
448+ // Try to send it to server.
449+ // Don't allow offline if there are attachments since they were uploaded fine.
450+ sent = await AddonModForum . replyPost (
451+ replyingTo ,
452+ this . discussionId ,
453+ this . forum . id ,
454+ this . forum . name ,
455+ this . courseId ,
456+ subject ,
457+ message ,
458+ {
459+ attachmentsid : attachments ,
460+ private : ! ! this . formData . isprivatereply ,
461+ } ,
462+ undefined ,
463+ ! files . length ,
464+ ) ;
465+ }
483466 }
484467
485468 if ( sent && this . forum . id ) {
@@ -506,6 +489,81 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
506489 }
507490 }
508491
492+ /**
493+ * Upload attachments when editing an online post.
494+ *
495+ * @param postId Post ID being edited.
496+ * @returns Draft area id (if any attachment has changed).
497+ */
498+ protected async uploadAttachmentsForEditOnline ( postId : number ) : Promise < number | undefined > {
499+ const files = this . formData . files || [ ] ;
500+ const previousAttachments = ( this . post . attachments ?? [ ] ) as CoreWSFile [ ] ;
501+
502+ if ( ! CoreFileUploader . areFileListDifferent ( files , previousAttachments ) ) {
503+ return ;
504+ }
505+
506+ // Use prepare post for edition to avoid re-uploading all files.
507+ let filesToKeep = files . filter ( ( file ) : file is CoreWSFile => ! CoreUtils . isFileEntry ( file ) ) ;
508+ let removedFiles : { filepath : string ; filename : string } [ ] | undefined ;
509+
510+ if ( previousAttachments . length && ! filesToKeep . length ) {
511+ // Post had attachments but they were all removed. We cannot use the filesToKeep option because it doesn't allow
512+ // removing all files. In this case we'll just keep 1 file and remove it later.
513+ filesToKeep = [ previousAttachments [ 0 ] ] ;
514+ removedFiles = [ {
515+ filename : previousAttachments [ 0 ] . filename ?? '' ,
516+ filepath : previousAttachments [ 0 ] . filepath ?? '' ,
517+ } ] ;
518+ }
519+
520+ const preparePostData = await AddonModForum . preparePostForEdition ( postId , 'attachment' , { filesToKeep } ) ;
521+
522+ if ( removedFiles ?. length ) {
523+ await CoreFileUploader . deleteDraftFiles ( preparePostData . draftitemid , removedFiles ) ;
524+ }
525+
526+ await CoreFileUploader . uploadFiles ( preparePostData . draftitemid , files ) ;
527+
528+ return preparePostData . draftitemid ;
529+ }
530+
531+ /**
532+ * Upload attachments for a reply that isn't an online post being edited.
533+ *
534+ * @param replyingTo Replying to post ID.
535+ * @returns Draft area id (if any attachment was uploaded) and whether data should be saved offline.
536+ */
537+ async uploadAttachmentsForReply (
538+ replyingTo : number ,
539+ ) : Promise < { attachments : CoreFileUploaderStoreFilesResult | number | undefined ; saveOffline : boolean } > {
540+ const files = this . formData . files || [ ] ;
541+ if ( ! files . length ) {
542+ return { attachments : undefined , saveOffline : false } ;
543+ }
544+
545+ try {
546+ const attachments = await AddonModForumHelper . uploadOrStoreReplyFiles (
547+ this . forum . id ,
548+ replyingTo ,
549+ files ,
550+ false ,
551+ ) ;
552+
553+ return { attachments, saveOffline : false } ;
554+ } catch ( error ) {
555+ // Cannot upload them in online, save them in offline.
556+ if ( ! this . forum . id || CoreUtils . isWebServiceError ( error ) ) {
557+ // Cannot store them in offline. Reject.
558+ throw error ;
559+ }
560+
561+ const attachments = await AddonModForumHelper . uploadOrStoreReplyFiles ( this . forum . id , replyingTo , files , true ) ;
562+
563+ return { attachments, saveOffline : true } ;
564+ }
565+ }
566+
509567 /**
510568 * Cancel reply.
511569 */
0 commit comments