From ec5c8d6cade3e922ce97682cc182083c2cb2c439 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 20 Aug 2024 09:00:00 +0200 Subject: [PATCH] MOBILE-4482 forum: Fix filtered content displayed when editing post When editing a post, the editor displayed the content already filtered, and it could also include some exra content that doesn't belong to the post, like plagiarism info. --- src/addons/mod/forum/components/post/post.ts | 50 +++++++++++- src/addons/mod/forum/services/forum.ts | 82 +++++++++++++++++++- 2 files changed, 127 insertions(+), 5 deletions(-) diff --git a/src/addons/mod/forum/components/post/post.ts b/src/addons/mod/forum/components/post/post.ts index 9e10b3c35..258b00a22 100644 --- a/src/addons/mod/forum/components/post/post.ts +++ b/src/addons/mod/forum/components/post/post.ts @@ -35,6 +35,7 @@ import { AddonModForumDiscussion, AddonModForumPost, AddonModForumPostFormData, + AddonModForumPrepareDraftAreaForPostWSResponse, } from '../../services/forum'; import { CoreTag } from '@features/tag/services/tag'; import { Translate } from '@singletons'; @@ -47,7 +48,7 @@ import { AddonModForumOffline } from '../../services/forum-offline'; import { CoreUtils } from '@services/utils/utils'; import { CoreRatingInfo } from '@features/rating/services/rating'; import { CoreForms } from '@singletons/form'; -import { CoreFileEntry } from '@services/file-helper'; +import { CoreFileEntry, CoreFileHelper } from '@services/file-helper'; import { AddonModForumSharedPostFormData } from '../../pages/discussion/discussion'; import { CoreDom } from '@singletons/dom'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; @@ -95,6 +96,8 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges displaySubject = true; optionsMenuEnabled = false; + protected preparePostData?: AddonModForumPrepareDraftAreaForPostWSResponse; + constructor( protected elementRef: ElementRef, ) {} @@ -226,6 +229,10 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges // Show advanced fields if any of them has not the default value. this.advanced = this.formData.files.length > 0; + + if (!isEditing || !postId || postId <= 0) { + this.preparePostData = undefined; + } } /** @@ -314,6 +321,28 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges // Ask confirm if there is unsaved data. try { await this.confirmDiscard(); + } catch { + // Cancelled. + return; + } + + const modal = await CoreLoadings.show(); + + try { + let message = this.post.message; + + if (this.post.id > 0) { + // Call prepare post for edition to retrieve the message without any added content (like filters and plagiarism). + this.preparePostData = await AddonModForum.preparePostForEdition(this.post.id, 'post'); + + const { text } = CoreFileHelper.replaceDraftfileUrls( + CoreSites.getRequiredCurrentSite().getURL(), + this.preparePostData.messagetext, + this.post.messageinlinefiles?.length ? this.post.messageinlinefiles : (this.preparePostData.files ?? []), + ); + + message = text; + } this.formData.syncId = AddonModForumSync.getDiscussionSyncId(this.discussionId); CoreSync.blockOperation(ADDON_MOD_FORUM_COMPONENT, this.formData.syncId); @@ -322,7 +351,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges this.post.parentid, true, this.post.subject, - this.post.message, + message, this.post.attachments, this.post.isprivatereply, this.post.id > 0 ? this.post.id : undefined, @@ -331,8 +360,10 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges this.scrollToForm(); this.analyticsLogEvent('mod_forum_update_discussion_post', `/mod/forum/post.php?edit=${this.post.id}`); - } catch { - // Cancelled. + } catch (error) { + CoreDomUtils.showErrorModalDefault(error, 'addon.mod_forum.errorgetpost', true); + } finally { + modal.dismiss(); } } @@ -369,6 +400,16 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges const isEditOnline = this.formData.id && this.formData.id > 0; const modal = await CoreLoadings.show('core.sending', true); + if (isEditOnline && this.preparePostData) { + // Restore the draft file URLs, otherwise the treated URLs would be saved in the content, which can cause problems. + message = CoreFileHelper.restoreDraftfileUrls( + CoreSites.getRequiredCurrentSite().getURL(), + message, + this.preparePostData.messagetext, + this.post.messageinlinefiles?.length ? this.post.messageinlinefiles : (this.preparePostData.files ?? []), + ); + } + // Add some HTML to the message if needed. message = CoreText.formatHtmlLines(message); @@ -401,6 +442,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges if (isEditOnline) { sent = await AddonModForum.updatePost(this.formData.id!, subject, message, { attachmentsid: attachments, + inlineattachmentsid: this.preparePostData?.draftitemid, }); } else if (saveOffline) { // Save post in offline. diff --git a/src/addons/mod/forum/services/forum.ts b/src/addons/mod/forum/services/forum.ts index 3cec9605b..7f911724f 100644 --- a/src/addons/mod/forum/services/forum.ts +++ b/src/addons/mod/forum/services/forum.ts @@ -26,7 +26,13 @@ import { CoreGroups } from '@services/groups'; import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { CoreUrl } from '@singletons/url'; import { CoreUtils } from '@services/utils/utils'; -import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning, CoreWSStoredFile } from '@services/ws'; +import { + CoreStatusWithWarningsWSResponse, + CoreWSExternalFile, + CoreWSExternalWarning, + CoreWSFile, + CoreWSStoredFile, +} from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; import { AddonModForumOffline, AddonModForumOfflineDiscussion, AddonModForumReplyOptions } from './forum-offline'; import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; @@ -606,7 +612,11 @@ export class AddonModForumProvider { }; const site = await CoreSites.getSite(options.siteId); + const isGetDiscussionPostsAvailable = this.isGetDiscussionPostsAvailable(site); + if (isGetDiscussionPostsAvailable && site.isVersionGreaterEqualThan('4.0')) { + (params as AddonModForumGetDiscussionPostsWSParams).includeinlineattachments = true; + } const response = isGetDiscussionPostsAvailable ? await site.read('mod_forum_get_discussion_posts', params, preSets) @@ -1264,6 +1274,35 @@ export class AddonModForumProvider { CoreUser.storeUsers(CoreUtils.objectToArray(users)); } + /** + * Prepare post for edition. + * + * @param postId Post ID. + * @param area Area to prepare. + * @param options Other options. + * @returns Data of prepared area. + */ + async preparePostForEdition( + postId: number, + area: 'attachment'|'post', + options: AddonModForumPreparePostOptions = {}, + ): Promise { + const site = await CoreSites.getSite(options.siteId); + + const params: AddonModForumPrepareDraftAreaForPostWSParams = { + postid: postId, + area: area, + }; + if (options.filesToKeep?.length) { + params.filestokeep = options.filesToKeep.map(file => ({ + filename: file.filename ?? '', + filepath: file.filepath ?? '', + })); + } + + return await site.write('mod_forum_prepare_draft_area_for_post', params); + } + /** * Update a certain post. * @@ -1903,6 +1942,7 @@ export type AddonModForumGetDiscussionPostsWSParams = { discussionid: number; // The ID of the discussion from which to fetch posts. sortby?: string; // Sort by this element: id, created or modified. sortdirection?: string; // Sort direction: ASC or DESC. + includeinlineattachments?: boolean; // @since 4.0. Whether inline attachments should be included or not. }; /** @@ -2086,6 +2126,46 @@ export type AddonModForumUpdateDiscussionPostWSParams = { */ export type AddonModForumUpdateDiscussionPostWSResponse = CoreStatusWithWarningsWSResponse; +/** + * Params of mod_forum_prepare_draft_area_for_post WS. + */ +type AddonModForumPrepareDraftAreaForPostWSParams = { + postid: number; // Post to prepare the draft area for. + area: string; // Area to prepare: attachment or post. + draftitemid?: number; // The draft item id to use. 0 to generate one. + filestokeep?: AddonModForumFileToKeep[]; // Only keep these files in the draft file area. Empty for keeping all. +}; + +/** + * Data to pass to mod_forum_prepare_draft_area_for_post to keep a file in the area. + */ +type AddonModForumFileToKeep = { + filename: string; // File name. + filepath: string; // File path. +}; + +/** + * Data returned by mod_forum_prepare_draft_area_for_post WS. + */ +export type AddonModForumPrepareDraftAreaForPostWSResponse = { + draftitemid: number; // Draft item id for the file area. + files?: CoreWSExternalFile[]; + areaoptions: { // Draft file area options. + name: string; // Name of option. + value: string; // Value of option. + }[]; + messagetext: string; // Message text with URLs rewritten. + warnings?: CoreWSExternalWarning[]; +}; + +/** + * Options to pass to preparePostForEdition. + */ +export type AddonModForumPreparePostOptions = { + filesToKeep?: CoreWSFile[]; // Only keep these files in the draft file area. Undefined or empty array for keeping all. + siteId?: string; +}; + /** * Data passed to NEW_DISCUSSION_EVENT event. */