Skip to content

Commit fdf7ac7

Browse files
authored
Merge pull request #4155 from dpalou/MOBILE-4482
Mobile 4482
2 parents d165b06 + 7448cdc commit fdf7ac7

File tree

4 files changed

+324
-80
lines changed

4 files changed

+324
-80
lines changed

src/addons/mod/forum/components/post/post.ts

Lines changed: 168 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ import {
3535
AddonModForumDiscussion,
3636
AddonModForumPost,
3737
AddonModForumPostFormData,
38+
AddonModForumPrepareDraftAreaForPostWSResponse,
3839
} from '../../services/forum';
3940
import { CoreTag } from '@features/tag/services/tag';
4041
import { Translate } from '@singletons';
41-
import { CoreFileUploader } from '@features/fileuploader/services/fileuploader';
42+
import { CoreFileUploader, CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader';
4243
import { AddonModForumSync } from '../../services/forum-sync';
4344
import { CoreSync } from '@services/sync';
4445
import { CoreText } from '@singletons/text';
@@ -47,7 +48,7 @@ import { AddonModForumOffline } from '../../services/forum-offline';
4748
import { CoreUtils } from '@services/utils/utils';
4849
import { CoreRatingInfo } from '@features/rating/services/rating';
4950
import { CoreForms } from '@singletons/form';
50-
import { CoreFileEntry } from '@services/file-helper';
51+
import { CoreFileEntry, CoreFileHelper } from '@services/file-helper';
5152
import { AddonModForumSharedPostFormData } from '../../pages/discussion/discussion';
5253
import { CoreDom } from '@singletons/dom';
5354
import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
@@ -56,6 +57,7 @@ import { CoreToasts } from '@services/toasts';
5657
import { toBoolean } from '@/core/transforms/boolean';
5758
import { CorePopovers } from '@services/popovers';
5859
import { CoreLoadings } from '@services/loadings';
60+
import { CoreWSFile } from '@services/ws';
5961

6062
/**
6163
* Components that shows a discussion post, its attachments and the action buttons allowed (reply, etc.).
@@ -95,6 +97,8 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
9597
displaySubject = true;
9698
optionsMenuEnabled = false;
9799

100+
protected preparePostData?: AddonModForumPrepareDraftAreaForPostWSResponse;
101+
98102
constructor(
99103
protected elementRef: ElementRef,
100104
) {}
@@ -211,7 +215,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
211215
this.formData.isEditing = !!isEditing;
212216
this.formData.subject = subject || this.defaultReplySubject || '';
213217
this.formData.message = message || null;
214-
this.formData.files = files || [];
218+
this.formData.files = (files ?? []).slice(); // Make a copy to avoid modifying the original array.
215219
this.formData.isprivatereply = !!isPrivate;
216220
this.formData.id = postId;
217221

@@ -226,6 +230,10 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
226230

227231
// Show advanced fields if any of them has not the default value.
228232
this.advanced = this.formData.files.length > 0;
233+
234+
if (!isEditing || !postId || postId <= 0) {
235+
this.preparePostData = undefined;
236+
}
229237
}
230238

231239
/**
@@ -314,6 +322,28 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
314322
// Ask confirm if there is unsaved data.
315323
try {
316324
await this.confirmDiscard();
325+
} catch {
326+
// Cancelled.
327+
return;
328+
}
329+
330+
const modal = await CoreLoadings.show();
331+
332+
try {
333+
let message = this.post.message;
334+
335+
if (this.post.id > 0) {
336+
// Call prepare post for edition to retrieve the message without any added content (like filters and plagiarism).
337+
this.preparePostData = await AddonModForum.preparePostForEdition(this.post.id, 'post');
338+
339+
const { text } = CoreFileHelper.replaceDraftfileUrls(
340+
CoreSites.getRequiredCurrentSite().getURL(),
341+
this.preparePostData.messagetext,
342+
this.post.messageinlinefiles?.length ? this.post.messageinlinefiles : (this.preparePostData.files ?? []),
343+
);
344+
345+
message = text;
346+
}
317347

318348
this.formData.syncId = AddonModForumSync.getDiscussionSyncId(this.discussionId);
319349
CoreSync.blockOperation(ADDON_MOD_FORUM_COMPONENT, this.formData.syncId);
@@ -322,7 +352,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
322352
this.post.parentid,
323353
true,
324354
this.post.subject,
325-
this.post.message,
355+
message,
326356
this.post.attachments,
327357
this.post.isprivatereply,
328358
this.post.id > 0 ? this.post.id : undefined,
@@ -331,8 +361,10 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
331361
this.scrollToForm();
332362

333363
this.analyticsLogEvent('mod_forum_update_discussion_post', `/mod/forum/post.php?edit=${this.post.id}`);
334-
} catch {
335-
// Cancelled.
364+
} catch (error) {
365+
CoreDomUtils.showErrorModalDefault(error, 'addon.mod_forum.errorgetpost', true);
366+
} finally {
367+
modal.dismiss();
336368
}
337369
}
338370

@@ -361,83 +393,76 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
361393
return;
362394
}
363395

364-
let saveOffline = false;
365396
let message = this.formData.message;
366397
const subject = this.formData.subject;
367-
const replyingTo = this.formData.replyingTo!;
398+
const replyingTo = this.formData.replyingTo ?? 0;
368399
const files = this.formData.files || [];
369400
const isEditOnline = this.formData.id && this.formData.id > 0;
370401
const modal = await CoreLoadings.show('core.sending', true);
371402

403+
if (isEditOnline && this.preparePostData) {
404+
// Restore the draft file URLs, otherwise the treated URLs would be saved in the content, which can cause problems.
405+
message = CoreFileHelper.restoreDraftfileUrls(
406+
CoreSites.getRequiredCurrentSite().getURL(),
407+
message,
408+
this.preparePostData.messagetext,
409+
this.post.messageinlinefiles?.length ? this.post.messageinlinefiles : (this.preparePostData.files ?? []),
410+
);
411+
}
412+
372413
// Add some HTML to the message if needed.
373414
message = CoreText.formatHtmlLines(message);
374415

375-
// Upload attachments first if any.
376-
let attachments;
377-
378416
try {
379-
if (files.length) {
380-
try {
381-
attachments = await AddonModForumHelper.uploadOrStoreReplyFiles(
382-
this.forum.id,
383-
isEditOnline ? this.formData.id! : replyingTo,
384-
files,
385-
false,
386-
);
387-
} catch (error) {
388-
// Cannot upload them in online, save them in offline.
389-
if (!this.forum.id || isEditOnline || CoreUtils.isWebServiceError(error)) {
390-
// Cannot store them in offline. Reject.
391-
throw error;
392-
}
393-
394-
saveOffline = true;
395-
attachments = await AddonModForumHelper.uploadOrStoreReplyFiles(this.forum.id, replyingTo, files, true);
396-
}
397-
}
398-
399417
let sent = false;
400418

401-
if (isEditOnline) {
402-
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, {
403423
attachmentsid: attachments,
424+
inlineattachmentsid: this.preparePostData?.draftitemid,
404425
});
405-
} else if (saveOffline) {
406-
// Save post in offline.
407-
await AddonModForumOffline.replyPost(
408-
replyingTo,
409-
this.discussionId,
410-
this.forum.id,
411-
this.forum.name,
412-
this.courseId,
413-
subject,
414-
message,
415-
{
416-
attachmentsid: attachments,
417-
private: !!this.formData.isprivatereply,
418-
},
419-
);
420-
421-
// Set sent to false since it wasn't sent to server.
422-
sent = false;
423426
} else {
424-
// Try to send it to server.
425-
// Don't allow offline if there are attachments since they were uploaded fine.
426-
sent = await AddonModForum.replyPost(
427-
replyingTo,
428-
this.discussionId,
429-
this.forum.id,
430-
this.forum.name,
431-
this.courseId,
432-
subject,
433-
message,
434-
{
435-
attachmentsid: attachments,
436-
private: !!this.formData.isprivatereply,
437-
},
438-
undefined,
439-
!files.length,
440-
);
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+
}
441466
}
442467

443468
if (sent && this.forum.id) {
@@ -464,6 +489,81 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
464489
}
465490
}
466491

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+
467567
/**
468568
* Cancel reply.
469569
*/

0 commit comments

Comments
 (0)