diff --git a/src/addons/mod/forum/components/index/index.ts b/src/addons/mod/forum/components/index/index.ts index 4562d9917..802085a89 100644 --- a/src/addons/mod/forum/components/index/index.ts +++ b/src/addons/mod/forum/components/index/index.ts @@ -380,7 +380,9 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom } // Fill user data for Offline discussions (should be already cached). - const promises = offlineDiscussions.map(async (discussion: any) => { + const promises = offlineDiscussions.map(async (offlineDiscussion) => { + const discussion = offlineDiscussion as unknown as AddonModForumDiscussion; + if (discussion.parent === 0 || forum.type === 'single') { // Do not show author for first post and type single. return; diff --git a/src/addons/mod/forum/components/post/post.ts b/src/addons/mod/forum/components/post/post.ts index 7a0405051..7d174bb9b 100644 --- a/src/addons/mod/forum/components/post/post.ts +++ b/src/addons/mod/forum/components/post/post.ts @@ -71,8 +71,8 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges @Input() discussion?: AddonModForumDiscussion; // Post's' discussion, only for starting posts. @Input() component!: string; // Component this post belong to. @Input() componentId!: number; // Component ID. - @Input() replyData: any; // Object with the new post data. Usually shared between posts. - @Input() originalData: any; // Object with the original post data. Usually shared between posts. + @Input() replyData!: AddonModForumReply; // Object with the new post data. Usually shared between posts. + @Input() originalData!: Omit; // Object with the original post data. Usually shared between posts. @Input() trackPosts!: boolean; // True if post is being tracked. @Input() forum!: AddonModForumData; // The forum the post belongs to. Required for attachments and offline posts. @Input() accessInfo!: AddonModForumAccessInformation; // Forum access information. @@ -103,7 +103,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges get showForm(): boolean { return this.post.id > 0 ? !this.replyData.isEditing && this.replyData.replyingTo === this.post.id - : this.replyData.isEditing && this.replyData.replyingTo === this.post.parentid; + : !!this.replyData.isEditing && this.replyData.replyingTo === this.post.parentid; } /** @@ -275,7 +275,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges } // Add some HTML to the message if needed. - const message = CoreTextUtils.formatHtmlLines(data.message); + const message = CoreTextUtils.formatHtmlLines(data.message!); const files = data.files; const options: AddonModForumUpdateDiscussionPostWSOptionsObject = {}; @@ -295,14 +295,14 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges } // Try to send it to server. - const sent = await AddonModForum.updatePost(this.post.id, data.subject, message, options); + const sent = await AddonModForum.updatePost(this.post.id, data.subject!, message, options); if (sent && this.forum.id) { // Data sent to server, delete stored files (if any). AddonModForumHelper.deleteReplyStoredFiles(this.forum.id, this.post.id); this.onPostChange.emit(); - this.post.subject = data.subject; + this.post.subject = data.subject!; this.post.message = message; this.post.attachments = data.files; } @@ -419,7 +419,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges let saveOffline = false; let message = this.replyData.message; const subject = this.replyData.subject; - const replyingTo = this.replyData.replyingTo; + const replyingTo = this.replyData.replyingTo!; const files = this.replyData.files || []; const options: AddonModForumReplyOptions = {}; const modal = await CoreDomUtils.showModalLoading('core.sending', true); diff --git a/src/addons/mod/forum/pages/discussion/discussion.page.ts b/src/addons/mod/forum/pages/discussion/discussion.page.ts index edf8d9fdd..b059151df 100644 --- a/src/addons/mod/forum/pages/discussion/discussion.page.ts +++ b/src/addons/mod/forum/pages/discussion/discussion.page.ts @@ -38,6 +38,7 @@ import { AddonModForumDiscussion, AddonModForumPost, AddonModForumProvider, + AddonModForumReply, } from '../../services/forum'; import { AddonModForumHelper } from '../../services/forum-helper'; import { AddonModForumOffline } from '../../services/forum-offline'; @@ -72,18 +73,18 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes postHasOffline!: boolean; sort: SortType = 'nested'; trackPosts!: boolean; - replyData = { + replyData: Omit = { replyingTo: 0, isEditing: false, subject: '', - message: null, // Null means empty or just white space. + message: null, files: [], isprivatereply: false, }; - originalData = { - subject: null, // Null means original data is not set. - message: null, // Null means empty or just white space. + originalData: Omit = { + subject: null, + message: null, files: [], isprivatereply: false, }; diff --git a/src/addons/mod/forum/services/forum-helper.ts b/src/addons/mod/forum/services/forum-helper.ts index 140853e36..0519efe28 100644 --- a/src/addons/mod/forum/services/forum-helper.ts +++ b/src/addons/mod/forum/services/forum-helper.ts @@ -368,25 +368,25 @@ export class AddonModForumHelperProvider { /** * Check if the data of a post/discussion has changed. * - * @param post Current data. + * @param reply Current data. * @param original Original ata. * @return True if data has changed, false otherwise. */ - hasPostDataChanged(post: any, original?: any): boolean { + hasPostDataChanged(reply: AddonModForumPostData, original?: AddonModForumPostData): boolean { if (!original || original.subject == null) { // There is no original data, assume it hasn't changed. return false; } - if (post.subject != original.subject || post.message != original.message) { + if (reply.subject != original.subject || reply.message != original.message) { return true; } - if (post.isprivatereply != original.isprivatereply) { + if (reply.isprivatereply != original.isprivatereply) { return true; } - return CoreFileUploader.areFileListDifferent(post.files, original.files); + return CoreFileUploader.areFileListDifferent(reply.files ?? [], original.files ?? []); } /** @@ -541,3 +541,13 @@ export class AddonModForumHelperProvider { } export const AddonModForumHelper = makeSingleton(AddonModForumHelperProvider); + +/** + * Forum post data used to check changes. + */ +type AddonModForumPostData = { + subject?: string | null; + message?: string | null; + isprivatereply?: boolean; + files?: CoreFileEntry[]; +}; diff --git a/src/addons/mod/forum/services/forum.ts b/src/addons/mod/forum/services/forum.ts index 582c13e65..c12f4be48 100644 --- a/src/addons/mod/forum/services/forum.ts +++ b/src/addons/mod/forum/services/forum.ts @@ -1407,7 +1407,7 @@ export type AddonModForumDiscussion = { mailnow: number; // Mail now?. userfullname: string | boolean; // Post author full name. usermodifiedfullname: string; // Post modifier full name. - userpictureurl: string; // Post author picture. + userpictureurl?: string; // Post author picture. usermodifiedpictureurl: string; // Post modifier picture. numreplies: number; // The number of replies in the discussion. numunread: number; // The number of unread discussions. @@ -1564,9 +1564,12 @@ export type AddonModForumAccessInformation = { */ export type AddonModForumReply = { id: number; - subject: string; - message: string; + subject: string | null; // Null means original data is not set. + message: string | null; // Null means empty or just white space. files: CoreFileEntry[]; + replyingTo?: number; + isEditing?: boolean; + isprivatereply?: boolean; }; /** diff --git a/src/addons/mod/forum/services/handlers/discussion-link.ts b/src/addons/mod/forum/services/handlers/discussion-link.ts index 245d7c558..8e821ed80 100644 --- a/src/addons/mod/forum/services/handlers/discussion-link.ts +++ b/src/addons/mod/forum/services/handlers/discussion-link.ts @@ -45,7 +45,7 @@ export class AddonModForumDiscussionLinkHandlerService extends CoreContentLinksH url: string, params: Params, courseId?: number, - data?: any, + data?: { instance?: string; cmid?: string; postid?: string }, ): CoreContentLinksAction[] | Promise { data = data || {}; @@ -56,13 +56,13 @@ export class AddonModForumDiscussionLinkHandlerService extends CoreContentLinksH action: (siteId): void => { const discussionId = parseInt(params.d, 10); const pageParams: Params = { - forumId: data.instance && parseInt(data.instance, 10), - cmId: data.cmid && parseInt(data.cmid, 10), + forumId: data?.instance && parseInt(data.instance, 10), + cmId: data?.cmid && parseInt(data.cmid, 10), courseId: courseId || parseInt(params.courseid, 10) || parseInt(params.cid, 10), }; - if (data.postid || params.urlHash) { - pageParams.postId = parseInt(data.postid || params.urlHash.replace('p', '')); + if (data?.postid || params.urlHash) { + pageParams.postId = parseInt(data?.postid || params.urlHash.replace('p', '')); } if (params.parent) { diff --git a/src/addons/mod/resource/services/handlers/prefetch.ts b/src/addons/mod/resource/services/handlers/prefetch.ts index 15886949e..f93df9fac 100644 --- a/src/addons/mod/resource/services/handlers/prefetch.ts +++ b/src/addons/mod/resource/services/handlers/prefetch.ts @@ -64,7 +64,7 @@ export class AddonModResourcePrefetchHandlerService extends CoreCourseResourcePr dirPath = await CoreFilepool.getPackageDirPathByUrl(CoreSites.getCurrentSiteId(), module.url!); } - const promises: Promise[] = []; + const promises: Promise[] = []; promises.push(super.downloadOrPrefetch(module, courseId, prefetch, dirPath)); diff --git a/src/core/classes/site.ts b/src/core/classes/site.ts index 549ac2dcf..7fe336b26 100644 --- a/src/core/classes/site.ts +++ b/src/core/classes/site.ts @@ -560,7 +560,7 @@ export class CoreSite { return CoreUtils.clone(response); } - const promise = this.getFromCache(method, data, preSets, false).catch(() => { + const promise = this.getFromCache(method, data, preSets, false).catch(async () => { if (preSets.forceOffline) { // Don't call the WS, just fail. throw new CoreError( @@ -569,13 +569,15 @@ export class CoreSite { } // Call the WS. - return this.callOrEnqueueRequest(method, data, preSets, wsPreSets).then((response) => { + try { + const response = await this.callOrEnqueueRequest(method, data, preSets, wsPreSets); + if (preSets.saveToCache) { this.saveToCache(method, data, response, preSets); } return response; - }).catch((error) => { + } catch (error) { if (error.errorcode == 'invalidtoken' || (error.errorcode == 'accessexception' && error.message.indexOf('Invalid token - token expired') > -1)) { if (initialToken !== this.token && !retrying) { @@ -585,7 +587,9 @@ export class CoreSite { return this.request(method, data, preSets, true); } else if (CoreApp.isSSOAuthenticationOngoing()) { // There's an SSO authentication ongoing, wait for it to finish and try again. - return CoreApp.waitForSSOAuthentication().then(() => this.request(method, data, preSets, true)); + await CoreApp.waitForSSOAuthentication(); + + return this.request(method, data, preSets, true); } // Session expired, trigger event. @@ -649,9 +653,7 @@ export class CoreSite { if (preSets.deleteCacheIfWSError && CoreUtils.isWebServiceError(error)) { // Delete the cache entry and return the entry. Don't block the user with the delete. - this.deleteFromCache(method, data, preSets).catch(() => { - // Ignore errors. - }); + CoreUtils.ignoreErrors(this.deleteFromCache(method, data, preSets)); throw new CoreWSError(error); } @@ -660,10 +662,12 @@ export class CoreSite { preSets.omitExpires = true; preSets.getFromCache = true; - return this.getFromCache(method, data, preSets, true).catch(() => { + try { + return await this.getFromCache(method, data, preSets, true); + } catch (e) { throw new CoreWSError(error); - }); - }); + } + } // eslint-disable-next-line @typescript-eslint/no-explicit-any }).then((response: any) => { // Check if the response is an error, this happens if the error was stored in the cache. diff --git a/src/core/features/block/components/block/block.ts b/src/core/features/block/components/block/block.ts index 05ee91cc0..2fe6f2a44 100644 --- a/src/core/features/block/components/block/block.ts +++ b/src/core/features/block/components/block/block.ts @@ -34,10 +34,10 @@ export class CoreBlockComponent implements OnInit, OnDestroy, DoCheck { @Input() block!: CoreCourseBlock; // The block to render. @Input() contextLevel!: string; // The context where the block will be used. @Input() instanceId!: number; // The instance ID associated with the context level. - @Input() extraData: any; // Any extra data to be passed to the block. + @Input() extraData!: Record; // Any extra data to be passed to the block. componentClass?: Type; // The class of the component to render. - data: any = {}; // Data to pass to the component. + data: Record = {}; // Data to pass to the component. class?: string; // CSS class to apply to the block. loaded = false; diff --git a/src/core/services/navigator.ts b/src/core/services/navigator.ts index c5e380113..d543aac00 100644 --- a/src/core/services/navigator.ts +++ b/src/core/services/navigator.ts @@ -309,6 +309,7 @@ export class CoreNavigatorService { * @return Value of the parameter, undefined if not found. */ getRouteParam(name: string, routeOptions: CoreNavigatorCurrentRouteOptions = {}): T | undefined { + // eslint-disable-next-line @typescript-eslint/no-explicit-any let value: any; if (!routeOptions.params) { diff --git a/src/types/angular.d.ts b/src/types/angular.d.ts index ab158dc8c..4f63bb656 100644 --- a/src/types/angular.d.ts +++ b/src/types/angular.d.ts @@ -19,6 +19,7 @@ declare module '@ionic/angular' { export class NavController { + // eslint-disable-next-line @typescript-eslint/no-explicit-any navigateForward(url: string | UrlTree | any[], options?: NavigationOptions): Promise; }