MOBILE-3643 forum: Migrate sync
This commit is contained in:
		
							parent
							
								
									d41523d4bb
								
							
						
					
					
						commit
						41259a66c9
					
				| @ -3,7 +3,7 @@ | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" iconAction="open"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog()"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="discussions.loaded && !(hasOffline || hasOfflineRatings) && isOnline" [priority]="700" [content]="'addon.mod_forum.refreshdiscussions' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="discussions.loaded && (hasOffline || hasOfflineRatings) && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item> | ||||
| @ -103,6 +103,9 @@ | ||||
|                     </ion-row> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <core-infinite-loading [enabled]="discussions.onlineLoaded && !discussions.completed" (action)="fetchMoreDiscussions($event)" [error]="fetchMoreDiscussionsFailed"> | ||||
|             </core-infinite-loading> | ||||
|         </ng-container> | ||||
|     </core-loading> | ||||
| 
 | ||||
|  | ||||
| @ -29,7 +29,12 @@ import { CoreCourseContentsPage } from '@features/course/pages/contents/contents | ||||
| import { AddonModForumHelper } from '@addons/mod/forum/services/helper.service'; | ||||
| import { CoreGroups, CoreGroupsProvider } from '@services/groups'; | ||||
| import { CoreEvents, CoreEventObserver } from '@singletons/events'; | ||||
| import { AddonModForumSyncProvider } from '@addons/mod/forum/services/sync.service'; | ||||
| import { | ||||
|     AddonModForumAutoSyncData, | ||||
|     AddonModForumManualSyncData, | ||||
|     AddonModForumSyncProvider, | ||||
|     AddonModForumSyncResult, | ||||
| } from '@addons/mod/forum/services/sync.service'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreUser } from '@features/user/services/user'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| @ -41,6 +46,7 @@ import { AddonModForumDiscussionOptionsMenuComponent } from '../discussion-optio | ||||
| import { AddonModForumSortOrderSelectorComponent } from '../sort-order-selector/sort-order-selector'; | ||||
| import { CoreScreen } from '@services/screen'; | ||||
| import { CoreArray } from '@singletons/array'; | ||||
| import { AddonModForumPrefetchHandler } from '../../services/handlers/prefetch'; | ||||
| 
 | ||||
| /** | ||||
|  * Component that displays a forum entry page. | ||||
| @ -58,8 +64,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|     moduleName = 'forum'; | ||||
|     descriptionNote?: string; | ||||
|     forum?: AddonModForumData; | ||||
|     canLoadMore = false; | ||||
|     loadMoreError = false; | ||||
|     fetchMoreDiscussionsFailed = false; | ||||
|     discussions: AddonModForumDiscussionsManager; | ||||
|     canAddDiscussion = false; | ||||
|     addDiscussionText!: string; | ||||
| @ -201,12 +206,12 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|      * @param sync If the refresh needs syncing. | ||||
|      * @param showErrors Wether to show errors to the user or hide them. | ||||
|      */ | ||||
|     protected async fetchContent(refresh: boolean = false, sync: boolean = false): Promise<void> { | ||||
|         this.loadMoreError = false; | ||||
|     protected async fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<void> { | ||||
|         this.fetchMoreDiscussionsFailed = false; | ||||
| 
 | ||||
|         const promises: Promise<void>[] = []; | ||||
| 
 | ||||
|         promises.push(this.fetchForum()); | ||||
|         promises.push(this.fetchForum(sync, showErrors)); | ||||
|         promises.push(this.fetchSortOrderPreference()); | ||||
| 
 | ||||
|         try { | ||||
| @ -219,7 +224,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|             if (refresh) { | ||||
|                 CoreDomUtils.instance.showErrorModalDefault(error, 'addon.mod_forum.errorgetforum', true); | ||||
| 
 | ||||
|                 this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
 | ||||
|                 this.fetchMoreDiscussionsFailed = true; // Set to prevent infinite calls with infinite-loading.
 | ||||
|             } else { | ||||
|                 // Get forum failed, retry without using cache since it might be a new activity.
 | ||||
|                 await this.refreshContent(sync); | ||||
| @ -229,136 +234,102 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|         this.fillContextMenu(refresh); | ||||
|     } | ||||
| 
 | ||||
|     private async fetchForum(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<void> { | ||||
|     private async fetchForum(sync: boolean = false, showErrors: boolean = false): Promise<void> { | ||||
|         if (!this.courseId || !this.module) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.loadMoreError = false; | ||||
|         const forum = await AddonModForum.instance.getForum(this.courseId, this.module.id); | ||||
| 
 | ||||
|         this.forum = forum; | ||||
|         this.description = forum.intro || this.description; | ||||
|         this.availabilityMessage = AddonModForumHelper.instance.getAvailabilityMessage(forum); | ||||
|         this.descriptionNote = Translate.instant('addon.mod_forum.numdiscussions', { | ||||
|             numdiscussions: forum.numdiscussions, | ||||
|         }); | ||||
| 
 | ||||
|         if (typeof forum.istracked != 'undefined') { | ||||
|             this.trackPosts = forum.istracked; | ||||
|         } | ||||
| 
 | ||||
|         this.dataRetrieved.emit(forum); | ||||
| 
 | ||||
|         switch (forum.type) { | ||||
|             case 'news': | ||||
|             case 'blog': | ||||
|                 this.addDiscussionText = Translate.instant('addon.mod_forum.addanewtopic'); | ||||
|                 break; | ||||
|             case 'qanda': | ||||
|                 this.addDiscussionText = Translate.instant('addon.mod_forum.addanewquestion'); | ||||
|                 break; | ||||
|             default: | ||||
|                 this.addDiscussionText = Translate.instant('addon.mod_forum.addanewdiscussion'); | ||||
|         } | ||||
| 
 | ||||
|         if (sync) { | ||||
|             // Try to synchronize the forum.
 | ||||
|             const updated = await this.syncActivity(showErrors); | ||||
| 
 | ||||
|             if (updated) { | ||||
|                 // Sync successful, send event.
 | ||||
|                 CoreEvents.trigger<AddonModForumManualSyncData>(AddonModForumSyncProvider.MANUAL_SYNCED, { | ||||
|                     forumId: forum.id, | ||||
|                     userId: CoreSites.instance.getCurrentSiteUserId(), | ||||
|                     source: 'index', | ||||
|                 }, CoreSites.instance.getCurrentSiteId()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         const promises: Promise<void>[] = []; | ||||
| 
 | ||||
|         // Check if the activity uses groups.
 | ||||
|         promises.push( | ||||
|             AddonModForum.instance | ||||
|                 .getForum(this.courseId, this.module.id) | ||||
|                 .then(async (forum) => { | ||||
|                     this.forum = forum; | ||||
|                     this.description = forum.intro || this.description; | ||||
|                     this.availabilityMessage = AddonModForumHelper.instance.getAvailabilityMessage(forum); | ||||
|                     this.descriptionNote = Translate.instant('addon.mod_forum.numdiscussions', { | ||||
|                         numdiscussions: forum.numdiscussions, | ||||
|                     }); | ||||
| 
 | ||||
|                     if (typeof forum.istracked != 'undefined') { | ||||
|                         this.trackPosts = forum.istracked; | ||||
|                     } | ||||
| 
 | ||||
|                     this.dataRetrieved.emit(forum); | ||||
| 
 | ||||
|                     switch (forum.type) { | ||||
|                         case 'news': | ||||
|                         case 'blog': | ||||
|                             this.addDiscussionText = Translate.instant('addon.mod_forum.addanewtopic'); | ||||
|                             break; | ||||
|                         case 'qanda': | ||||
|                             this.addDiscussionText = Translate.instant('addon.mod_forum.addanewquestion'); | ||||
|                             break; | ||||
|                         default: | ||||
|                             this.addDiscussionText = Translate.instant('addon.mod_forum.addanewdiscussion'); | ||||
|                     } | ||||
| 
 | ||||
|                     if (sync) { | ||||
|                         // Try to synchronize the forum.
 | ||||
|                         const updated = await this.syncActivity(showErrors); | ||||
| 
 | ||||
|                         if (updated) { | ||||
|                             // Sync successful, send event.
 | ||||
|                             CoreEvents.trigger(AddonModForumSyncProvider.MANUAL_SYNCED, { | ||||
|                                 forumId: forum.id, | ||||
|                                 userId: CoreSites.instance.getCurrentSiteUserId(), | ||||
|                                 source: 'index', | ||||
|                             }, CoreSites.instance.getCurrentSiteId()); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     const promises: Promise<void>[] = []; | ||||
| 
 | ||||
|                     // Check if the activity uses groups.
 | ||||
|                     promises.push( | ||||
|                         // eslint-disable-next-line promise/no-nesting
 | ||||
|                         CoreGroups.instance | ||||
|                             .getActivityGroupMode(this.forum.cmid) | ||||
|                             .then(async mode => { | ||||
|                                 this.usesGroups = mode === CoreGroupsProvider.SEPARATEGROUPS | ||||
|             CoreGroups.instance | ||||
|                 .getActivityGroupMode(this.forum.cmid) | ||||
|                 .then(async mode => { | ||||
|                     this.usesGroups = mode === CoreGroupsProvider.SEPARATEGROUPS | ||||
|                                     || mode === CoreGroupsProvider.VISIBLEGROUPS; | ||||
| 
 | ||||
|                                 return; | ||||
|                             }), | ||||
|                     ); | ||||
| 
 | ||||
|                     promises.push( | ||||
|                         // eslint-disable-next-line promise/no-nesting
 | ||||
|                         AddonModForum.instance | ||||
|                             .getAccessInformation(this.forum.id, { cmId: this.module!.id }) | ||||
|                             .then(async accessInfo => { | ||||
|                                 // Disallow adding discussions if cut-off date is reached and the user has not the
 | ||||
|                                 // capability to override it.
 | ||||
|                                 // Just in case the forum was fetched from WS when the cut-off date was not reached but it is now.
 | ||||
|                                 const cutoffDateReached = AddonModForumHelper.instance.isCutoffDateReached(this.forum!) | ||||
|                                     && !accessInfo.cancanoverridecutoff; | ||||
|                                 this.canAddDiscussion = !!this.forum?.cancreatediscussions && !cutoffDateReached; | ||||
| 
 | ||||
|                                 return; | ||||
|                             }), | ||||
|                     ); | ||||
| 
 | ||||
|                     if (AddonModForum.instance.isSetPinStateAvailableForSite()) { | ||||
|                         // Use the canAddDiscussion WS to check if the user can pin discussions.
 | ||||
|                         promises.push( | ||||
|                             // eslint-disable-next-line promise/no-nesting
 | ||||
|                             AddonModForum.instance | ||||
|                                 .canAddDiscussionToAll(this.forum.id, { cmId: this.module!.id }) | ||||
|                                 .then(async response => { | ||||
|                                     this.canPin = !!response.canpindiscussions; | ||||
| 
 | ||||
|                                     return; | ||||
|                                 }) | ||||
|                                 .catch(async () => { | ||||
|                                     this.canPin = false; | ||||
| 
 | ||||
|                                     return; | ||||
|                                 }), | ||||
|                         ); | ||||
|                     } else { | ||||
|                         this.canPin = false; | ||||
|                     } | ||||
| 
 | ||||
|                     await Promise.all(promises); | ||||
| 
 | ||||
|                     return; | ||||
|                 }), | ||||
|         ); | ||||
| 
 | ||||
|         promises.push(this.fetchSortOrderPreference()); | ||||
|         promises.push( | ||||
|             AddonModForum.instance | ||||
|                 .getAccessInformation(this.forum.id, { cmId: this.module!.id }) | ||||
|                 .then(async accessInfo => { | ||||
|                     // Disallow adding discussions if cut-off date is reached and the user has not the
 | ||||
|                     // capability to override it.
 | ||||
|                     // Just in case the forum was fetched from WS when the cut-off date was not reached but it is now.
 | ||||
|                     const cutoffDateReached = AddonModForumHelper.instance.isCutoffDateReached(this.forum!) | ||||
|                                     && !accessInfo.cancanoverridecutoff; | ||||
|                     this.canAddDiscussion = !!this.forum?.cancreatediscussions && !cutoffDateReached; | ||||
| 
 | ||||
|         try { | ||||
|             await Promise.all(promises); | ||||
|             await Promise.all([ | ||||
|                 this.fetchOfflineDiscussions(), | ||||
|                 this.fetchDiscussions(refresh), | ||||
|             ]); | ||||
|         } catch (message) { | ||||
|             if (!refresh) { | ||||
|                 // Get forum failed, retry without using cache since it might be a new activity.
 | ||||
|                 return this.refreshContent(sync); | ||||
|             } | ||||
|                     return; | ||||
|                 }), | ||||
|         ); | ||||
| 
 | ||||
|             CoreDomUtils.instance.showErrorModalDefault(message, 'addon.mod_forum.errorgetforum', true); | ||||
|         if (AddonModForum.instance.isSetPinStateAvailableForSite()) { | ||||
|             // Use the canAddDiscussion WS to check if the user can pin discussions.
 | ||||
|             promises.push( | ||||
|                 AddonModForum.instance | ||||
|                     .canAddDiscussionToAll(this.forum.id, { cmId: this.module!.id }) | ||||
|                     .then(async response => { | ||||
|                         this.canPin = !!response.canpindiscussions; | ||||
| 
 | ||||
|             this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
 | ||||
|                         return; | ||||
|                     }) | ||||
|                     .catch(async () => { | ||||
|                         this.canPin = false; | ||||
| 
 | ||||
|                         return; | ||||
|                     }), | ||||
|             ); | ||||
|         } else { | ||||
|             this.canPin = false; | ||||
|         } | ||||
| 
 | ||||
|         this.fillContextMenu(refresh); | ||||
|         await Promise.all(promises); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -414,7 +385,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|      */ | ||||
|     protected async fetchDiscussions(refresh: boolean): Promise<void> { | ||||
|         const forum = this.forum!; | ||||
|         this.loadMoreError = false; | ||||
|         this.fetchMoreDiscussionsFailed = false; | ||||
| 
 | ||||
|         if (refresh) { | ||||
|             this.page = 0; | ||||
| @ -435,7 +406,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|         if (forum.type === 'single') { | ||||
|             for (const discussion of discussions) { | ||||
|                 if (discussion.userfullname && discussion.parent === 0) { | ||||
|                     (discussion as any).userfullname = false; | ||||
|                     discussion.userfullname = false; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| @ -452,12 +423,11 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|         } | ||||
| 
 | ||||
|         if (this.page === 0) { | ||||
|             this.discussions.setOnlineDiscussions(discussions); | ||||
|             this.discussions.setOnlineDiscussions(discussions, response.canLoadMore); | ||||
|         } else { | ||||
|             this.discussions.setItems(this.discussions.items.concat(discussions)); | ||||
|             this.discussions.setItems(this.discussions.items.concat(discussions), response.canLoadMore); | ||||
|         } | ||||
| 
 | ||||
|         this.canLoadMore = response.canLoadMore; | ||||
|         this.page++; | ||||
| 
 | ||||
|         // Check if there are replies for discussions stored in offline.
 | ||||
| @ -467,7 +437,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
| 
 | ||||
|         if (hasOffline) { | ||||
|             // Only update new fetched discussions.
 | ||||
|             const promises = discussions.map(async (discussion: any) => { | ||||
|             const promises = discussions.map(async (discussion) => { | ||||
|                 // Get offline discussions.
 | ||||
|                 const replies = await AddonModForumOffline.instance.getDiscussionReplies(discussion.discussion); | ||||
| 
 | ||||
| @ -484,14 +454,16 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|      * @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     fetchMoreDiscussions(infiniteComplete?: any): Promise<any> { | ||||
|         return this.fetchDiscussions(false).catch((message) => { | ||||
|             CoreDomUtils.instance.showErrorModalDefault(message, 'addon.mod_forum.errorgetforum', true); | ||||
|     async fetchMoreDiscussions(complete: () => void): Promise<void> { | ||||
|         try { | ||||
|             await this.fetchDiscussions(false); | ||||
|         } catch (error) { | ||||
|             CoreDomUtils.instance.showErrorModalDefault(error, 'addon.mod_forum.errorgetforum', true); | ||||
| 
 | ||||
|             this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
 | ||||
|         }).finally(() => { | ||||
|             infiniteComplete && infiniteComplete(); | ||||
|         }); | ||||
|             this.fetchMoreDiscussionsFailed = true; | ||||
|         } finally { | ||||
|             complete(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -522,7 +494,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|      * | ||||
|      * @return Resolved when done. | ||||
|      */ | ||||
|     protected invalidateContent(): Promise<any> { | ||||
|     protected async invalidateContent(): Promise<void> { | ||||
|         const promises: Promise<void>[] = []; | ||||
| 
 | ||||
|         promises.push(AddonModForum.instance.invalidateForumData(this.courseId!)); | ||||
| @ -537,7 +509,16 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|             promises.push(CoreUser.instance.invalidateUserPreference(AddonModForumProvider.PREFERENCE_SORTORDER)); | ||||
|         } | ||||
| 
 | ||||
|         return Promise.all(promises); | ||||
|         await Promise.all(promises); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Performs the sync of the activity. | ||||
|      * | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected sync(): Promise<AddonModForumSyncResult> { | ||||
|         return AddonModForumPrefetchHandler.instance.sync(this.module!, this.courseId!); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -546,10 +527,23 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | ||||
|      * @param result Data returned on the sync function. | ||||
|      * @return Whether it succeed or not. | ||||
|      */ | ||||
|     protected hasSyncSucceed(result: any): boolean { | ||||
|     protected hasSyncSucceed(result: AddonModForumSyncResult): boolean { | ||||
|         return result.updated; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Compares sync event data with current data to check if refresh content is needed. | ||||
|      * | ||||
|      * @param syncEventData Data receiven on sync observer. | ||||
|      * @return True if refresh is needed, false otherwise. | ||||
|      */ | ||||
|     protected isRefreshSyncNeeded(syncEventData: AddonModForumAutoSyncData | AddonModForumManualSyncData): boolean { | ||||
|         return !!this.forum | ||||
|             && (!('source' in syncEventData) || syncEventData.source != 'index') | ||||
|             && syncEventData.forumId == this.forum.id | ||||
|             && syncEventData.userId == CoreSites.instance.getCurrentSiteUserId(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Function called when we receive an event of new discussion or reply to discussion. | ||||
|      * | ||||
| @ -685,6 +679,8 @@ type DiscussionItem = AddonModForumDiscussion | AddonModForumOfflineDiscussion | | ||||
|  */ | ||||
| class AddonModForumDiscussionsManager extends CorePageItemsListManager<DiscussionItem> { | ||||
| 
 | ||||
|     onlineLoaded = false; | ||||
| 
 | ||||
|     private discussionsPathPrefix: string; | ||||
|     private component: AddonModForumIndexComponent; | ||||
| 
 | ||||
| @ -747,10 +743,10 @@ class AddonModForumDiscussionsManager extends CorePageItemsListManager<Discussio | ||||
|      * | ||||
|      * @param onlineDiscussions Online discussions | ||||
|      */ | ||||
|     setOnlineDiscussions(onlineDiscussions: AddonModForumDiscussion[]): void { | ||||
|     setOnlineDiscussions(onlineDiscussions: AddonModForumDiscussion[], hasMoreItems: boolean = false): void { | ||||
|         const otherDiscussions = this.items.filter(discussion => !this.isOnlineDiscussion(discussion)); | ||||
| 
 | ||||
|         this.setItems(otherDiscussions.concat(onlineDiscussions)); | ||||
|         this.setItems(otherDiscussions.concat(onlineDiscussions), hasMoreItems); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -761,7 +757,16 @@ class AddonModForumDiscussionsManager extends CorePageItemsListManager<Discussio | ||||
|     setOfflineDiscussions(offlineDiscussions: AddonModForumOfflineDiscussion[]): void { | ||||
|         const otherDiscussions = this.items.filter(discussion => !this.isOfflineDiscussion(discussion)); | ||||
| 
 | ||||
|         this.setItems((offlineDiscussions as DiscussionItem[]).concat(otherDiscussions)); | ||||
|         this.setItems((offlineDiscussions as DiscussionItem[]).concat(otherDiscussions), this.hasMoreItems); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     setItems(discussions: DiscussionItem[], hasMoreItems: boolean = false): void { | ||||
|         super.setItems(discussions, hasMoreItems); | ||||
| 
 | ||||
|         this.onlineLoaded = this.onlineLoaded || discussions.some(discussion => this.isOnlineDiscussion(discussion)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -25,6 +25,10 @@ import { CoreScreen } from '@services/screen'; | ||||
| import { AddonModForumComponentsModule } from './components/components.module'; | ||||
| import { AddonModForumModuleHandler, AddonModForumModuleHandlerService } from './services/handlers/module'; | ||||
| import { SITE_SCHEMA } from './services/offline-db'; | ||||
| import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; | ||||
| import { AddonModForumPrefetchHandler } from './services/handlers/prefetch'; | ||||
| import { CoreCronDelegate } from '@services/cron'; | ||||
| import { AddonModForumSyncCronHandler } from './services/handlers/sync-cron'; | ||||
| 
 | ||||
| const mainMenuRoutes: Routes = [ | ||||
|     { | ||||
| @ -77,7 +81,11 @@ const courseContentsRoutes: Routes = conditionalRoutes( | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             useValue: () => CoreCourseModuleDelegate.instance.registerHandler(AddonModForumModuleHandler.instance), | ||||
|             useValue: () => { | ||||
|                 CoreCourseModuleDelegate.instance.registerHandler(AddonModForumModuleHandler.instance); | ||||
|                 CoreCourseModulePrefetchDelegate.instance.registerHandler(AddonModForumPrefetchHandler.instance); | ||||
|                 CoreCronDelegate.instance.register(AddonModForumSyncCronHandler.instance); | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
|  | ||||
| @ -37,7 +37,7 @@ import { | ||||
| } from '../../services/forum.service'; | ||||
| import { AddonModForumHelper } from '../../services/helper.service'; | ||||
| import { AddonModForumOffline } from '../../services/offline.service'; | ||||
| import { AddonModForumSync, AddonModForumSyncProvider } from '../../services/sync.service'; | ||||
| import { AddonModForumManualSyncData, AddonModForumSync, AddonModForumSyncProvider } from '../../services/sync.service'; | ||||
| 
 | ||||
| type SortType = 'flat-newest' | 'flat-oldest' | 'nested'; | ||||
| 
 | ||||
| @ -180,7 +180,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes | ||||
|         }, CoreSites.instance.getCurrentSiteId()); | ||||
| 
 | ||||
|         // Refresh data if this forum discussion is synchronized from discussions list.
 | ||||
|         this.syncManualObserver = CoreEvents.on(AddonModForumSyncProvider.MANUAL_SYNCED, (data: any) => { | ||||
|         this.syncManualObserver = CoreEvents.on(AddonModForumSyncProvider.MANUAL_SYNCED, (data: AddonModForumManualSyncData) => { | ||||
|             if (data.source != 'discussion' && data.forumId == this.forumId && | ||||
|                     data.userId == CoreSites.instance.getCurrentSiteUserId()) { | ||||
|                 // Refresh the data.
 | ||||
| @ -541,7 +541,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes | ||||
| 
 | ||||
|                     if (result && result.updated) { | ||||
|                         // Sync successful, send event.
 | ||||
|                         CoreEvents.trigger(AddonModForumSyncProvider.MANUAL_SYNCED, { | ||||
|                         CoreEvents.trigger<AddonModForumManualSyncData>(AddonModForumSyncProvider.MANUAL_SYNCED, { | ||||
|                             forumId: this.forumId, | ||||
|                             userId: CoreSites.instance.getCurrentSiteUserId(), | ||||
|                             source: 'discussion', | ||||
|  | ||||
| @ -1401,7 +1401,7 @@ export type AddonModForumDiscussion = { | ||||
|     attachments?: CoreWSExternalFile[]; | ||||
|     totalscore: number; // The post message total score.
 | ||||
|     mailnow: number; // Mail now?.
 | ||||
|     userfullname: string; // Post author full name.
 | ||||
|     userfullname: string | boolean; // Post author full name.
 | ||||
|     usermodifiedfullname: string; // Post modifier full name.
 | ||||
|     userpictureurl: string; // Post author picture.
 | ||||
|     usermodifiedpictureurl: string; // Post modifier picture.
 | ||||
| @ -1452,6 +1452,7 @@ export type AddonModForumPost = { | ||||
|     }; | ||||
|     attachment?: 0 | 1; | ||||
|     attachments?: (CoreFileEntry | AddonModForumWSPostAttachment)[]; | ||||
|     messageinlinefiles?: CoreWSExternalFile[]; | ||||
|     haswordcount?: boolean; // Haswordcount.
 | ||||
|     wordcount?: number; // Wordcount.
 | ||||
|     tags?: { // Tags.
 | ||||
|  | ||||
							
								
								
									
										353
									
								
								src/addons/mod/forum/services/handlers/prefetch.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										353
									
								
								src/addons/mod/forum/services/handlers/prefetch.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,353 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler'; | ||||
| import { AddonModForum, AddonModForumData, AddonModForumPost, AddonModForumProvider } from '../forum.service'; | ||||
| import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; | ||||
| import { CoreFilepool } from '@services/filepool'; | ||||
| import { CoreWSExternalFile } from '@services/ws'; | ||||
| import { CoreCourse, CoreCourseAnyModuleData, CoreCourseCommonModWSOptions } from '@features/course/services/course'; | ||||
| import { CoreUser } from '@features/user/services/user'; | ||||
| import { CoreGroups, CoreGroupsProvider } from '@services/groups'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { AddonModForumSync } from '../sync.service'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to prefetch forums. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonModForumPrefetchHandlerService extends CoreCourseActivityPrefetchHandlerBase { | ||||
| 
 | ||||
|     name = 'AddonModForum'; | ||||
|     modName = 'forum'; | ||||
|     component = AddonModForumProvider.COMPONENT; | ||||
|     updatesNames = /^configuration$|^.*files$|^discussions$/; | ||||
| 
 | ||||
|     /** | ||||
|      * Get list of files. If not defined, we'll assume they're in module.contents. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @param single True if we're downloading a single module, false if we're downloading a whole section. | ||||
|      * @return Promise resolved with the list of files. | ||||
|      */ | ||||
|     async getFiles(module: CoreCourseAnyModuleData, courseId: number): Promise<CoreWSExternalFile[]> { | ||||
|         try { | ||||
|             const forum = await AddonModForum.instance.getForum(courseId, module.id); | ||||
| 
 | ||||
|             const files = this.getIntroFilesFromInstance(module, forum); | ||||
| 
 | ||||
|             // Get posts.
 | ||||
|             const posts = await this.getPostsForPrefetch(forum, { cmId: module.id }); | ||||
| 
 | ||||
|             // Add posts attachments and embedded files.
 | ||||
|             files.concat(this.getPostsFiles(posts)); | ||||
| 
 | ||||
|             return files; | ||||
|         } catch (error) { | ||||
|             // Forum not found, return empty list.
 | ||||
|             return []; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Given a list of forum posts, return a list with all the files (attachments and embedded files). | ||||
|      * | ||||
|      * @param posts Forum posts. | ||||
|      * @return Files. | ||||
|      */ | ||||
|     protected getPostsFiles(posts: AddonModForumPost[]): CoreWSExternalFile[] { | ||||
|         let files: CoreWSExternalFile[] = []; | ||||
|         const getInlineFiles = CoreSites.instance.getCurrentSite()?.isVersionGreaterEqualThan('3.2'); | ||||
| 
 | ||||
|         posts.forEach((post) => { | ||||
|             if (post.attachments && post.attachments.length) { | ||||
|                 files = files.concat(post.attachments as CoreWSExternalFile[]); | ||||
|             } | ||||
|             if (getInlineFiles && post.messageinlinefiles && post.messageinlinefiles.length) { | ||||
|                 files = files.concat(post.messageinlinefiles); | ||||
|             } else if (post.message && !getInlineFiles) { | ||||
|                 files = files.concat(CoreFilepool.instance.extractDownloadableFilesFromHtmlAsFakeFileObjects(post.message)); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         return files; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the posts to be prefetched. | ||||
|      * | ||||
|      * @param forum Forum instance. | ||||
|      * @param options Other options. | ||||
|      * @return Promise resolved with array of posts. | ||||
|      */ | ||||
|     protected getPostsForPrefetch( | ||||
|         forum: AddonModForumData, | ||||
|         options: CoreCourseCommonModWSOptions = {}, | ||||
|     ): Promise<AddonModForumPost[]> { | ||||
|         const promises = AddonModForum.instance.getAvailableSortOrders().map((sortOrder) => { | ||||
|             // Get discussions in first 2 pages.
 | ||||
|             const discussionsOptions = { | ||||
|                 sortOrder: sortOrder.value, | ||||
|                 numPages: 2, | ||||
|                 ...options, // Include all options.
 | ||||
|             }; | ||||
| 
 | ||||
|             return AddonModForum.instance.getDiscussionsInPages(forum.id, discussionsOptions).then((response) => { | ||||
|                 if (response.error) { | ||||
|                     throw new Error('Failed getting discussions'); | ||||
|                 } | ||||
| 
 | ||||
|                 const promises: Promise<{ posts: AddonModForumPost[] }>[] = []; | ||||
| 
 | ||||
|                 response.discussions.forEach((discussion) => { | ||||
|                     promises.push(AddonModForum.instance.getDiscussionPosts(discussion.discussion, options)); | ||||
|                 }); | ||||
| 
 | ||||
|                 return Promise.all(promises); | ||||
|             }); | ||||
|         }); | ||||
| 
 | ||||
|         return Promise.all(promises).then((results) => { | ||||
|             // Each order has returned its own list of posts. Merge all the lists, preventing duplicates.
 | ||||
|             const posts: AddonModForumPost[] = []; | ||||
|             const postIds = {}; // To make the array unique.
 | ||||
| 
 | ||||
|             results.forEach((orderResults) => { | ||||
|                 orderResults.forEach((orderResult) => { | ||||
|                     orderResult.posts.forEach((post) => { | ||||
|                         if (!postIds[post.id]) { | ||||
|                             postIds[post.id] = true; | ||||
|                             posts.push(post); | ||||
|                         } | ||||
|                     }); | ||||
|                 }); | ||||
|             }); | ||||
| 
 | ||||
|             return posts; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidate the prefetched content. | ||||
|      * | ||||
|      * @param moduleId The module ID. | ||||
|      * @param courseId The course ID the module belongs to. | ||||
|      * @return Promise resolved when the data is invalidated. | ||||
|      */ | ||||
|     invalidateContent(moduleId: number, courseId: number): Promise<void> { | ||||
|         return AddonModForum.instance.invalidateContent(moduleId, courseId); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidate WS calls needed to determine module status (usually, to check if module is downloadable). | ||||
|      * It doesn't need to invalidate check updates. It should NOT invalidate files nor all the prefetched data. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @return Promise resolved when invalidated. | ||||
|      */ | ||||
|     async invalidateModule(module: CoreCourseAnyModuleData, courseId: number): Promise<void> { | ||||
|         // Invalidate forum data to recalculate unread message count badge.
 | ||||
|         const promises: Promise<unknown>[] = []; | ||||
| 
 | ||||
|         promises.push(AddonModForum.instance.invalidateForumData(courseId)); | ||||
|         promises.push(CoreCourse.instance.invalidateModule(module.id)); | ||||
| 
 | ||||
|         await Promise.all(promises); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch a module. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @param single True if we're downloading a single module, false if we're downloading a whole section. | ||||
|      * @param dirPath Path of the directory where to store all the content files. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     prefetch(module: CoreCourseAnyModuleData, courseId?: number, single?: boolean): Promise<void> { | ||||
|         return this.prefetchPackage(module, courseId, this.prefetchForum.bind(this, module, courseId, single)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch a forum. | ||||
|      * | ||||
|      * @param module The module object returned by WS. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @param single True if we're downloading a single module, false if we're downloading a whole section. | ||||
|      * @param siteId Site ID. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async prefetchForum( | ||||
|         module: CoreCourseAnyModuleData, | ||||
|         courseId: number, | ||||
|         single: boolean, | ||||
|         siteId: string, | ||||
|     ): Promise<void> { | ||||
|         const commonOptions = { | ||||
|             readingStrategy: CoreSitesReadingStrategy.OnlyNetwork, | ||||
|             siteId, | ||||
|         }; | ||||
|         const modOptions = { | ||||
|             cmId: module.id, | ||||
|             ...commonOptions, // Include all common options.
 | ||||
|         }; | ||||
| 
 | ||||
|         // Get the forum data.
 | ||||
|         const forum = await AddonModForum.instance.getForum(courseId, module.id, commonOptions); | ||||
|         const promises: Promise<unknown>[] = []; | ||||
| 
 | ||||
|         // Prefetch the posts.
 | ||||
|         promises.push(this.getPostsForPrefetch(forum, modOptions).then((posts) => { | ||||
|             const promises: Promise<unknown>[] = []; | ||||
| 
 | ||||
|             const files = this.getIntroFilesFromInstance(module, forum).concat(this.getPostsFiles(posts)); | ||||
|             promises.push(CoreFilepool.instance.addFilesToQueue(siteId, files, this.component, module.id)); | ||||
| 
 | ||||
|             // Prefetch groups data.
 | ||||
|             promises.push(this.prefetchGroupsInfo(forum, courseId, !!forum.cancreatediscussions, siteId)); | ||||
| 
 | ||||
|             // Prefetch avatars.
 | ||||
|             promises.push(CoreUser.instance.prefetchUserAvatars(posts, 'userpictureurl', siteId)); | ||||
| 
 | ||||
|             return Promise.all(promises); | ||||
|         })); | ||||
| 
 | ||||
|         // Prefetch access information.
 | ||||
|         promises.push(AddonModForum.instance.getAccessInformation(forum.id, modOptions)); | ||||
| 
 | ||||
|         // Prefetch sort order preference.
 | ||||
|         if (AddonModForum.instance.isDiscussionListSortingAvailable()) { | ||||
|             promises.push(CoreUser.instance.getUserPreference(AddonModForumProvider.PREFERENCE_SORTORDER, siteId)); | ||||
|         } | ||||
| 
 | ||||
|         await Promise.all(promises); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch groups info for a forum. | ||||
|      * | ||||
|      * @param module The module object returned by WS. | ||||
|      * @param courseI Course ID the module belongs to. | ||||
|      * @param canCreateDiscussions Whether the user can create discussions in the forum. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved when group data has been prefetched. | ||||
|      */ | ||||
|     protected async prefetchGroupsInfo( | ||||
|         forum: AddonModForumData, | ||||
|         courseId: number, | ||||
|         canCreateDiscussions: boolean, | ||||
|         siteId?: string, | ||||
|     ): Promise<void> { | ||||
|         const options = { | ||||
|             cmId: forum.cmid, | ||||
|             siteId, | ||||
|         }; | ||||
| 
 | ||||
|         // Check group mode.
 | ||||
|         try { | ||||
|             const mode = await CoreGroups.instance.getActivityGroupMode(forum.cmid, siteId); | ||||
| 
 | ||||
|             if (mode !== CoreGroupsProvider.SEPARATEGROUPS && mode !== CoreGroupsProvider.VISIBLEGROUPS) { | ||||
|                 // Activity doesn't use groups. Prefetch canAddDiscussionToAll to determine if user can pin/attach.
 | ||||
|                 await CoreUtils.instance.ignoreErrors(AddonModForum.instance.canAddDiscussionToAll(forum.id, options)); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             // Activity uses groups, prefetch allowed groups.
 | ||||
|             const result = await CoreGroups.instance.getActivityAllowedGroups(forum.cmid, undefined, siteId); | ||||
|             if (mode === CoreGroupsProvider.SEPARATEGROUPS) { | ||||
|                 // Groups are already filtered by WS. Prefetch canAddDiscussionToAll to determine if user can pin/attach.
 | ||||
|                 await CoreUtils.instance.ignoreErrors(AddonModForum.instance.canAddDiscussionToAll(forum.id, options)); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (canCreateDiscussions) { | ||||
|                 // Prefetch data to check the visible groups when creating discussions.
 | ||||
|                 const response = await CoreUtils.instance.ignoreErrors( | ||||
|                     AddonModForum.instance.canAddDiscussionToAll(forum.id, options), | ||||
|                     { status: false }, | ||||
|                 ); | ||||
| 
 | ||||
|                 if (response.status) { | ||||
|                     // User can post to all groups, nothing else to prefetch.
 | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 // The user can't post to all groups, let's check which groups he can post to.
 | ||||
|                 await Promise.all( | ||||
|                     result.groups.map( | ||||
|                         async (group) => CoreUtils.instance.ignoreErrors( | ||||
|                             AddonModForum.instance.canAddDiscussion(forum.id, group.id, options), | ||||
|                         ), | ||||
|                     ), | ||||
|                 ); | ||||
|             } | ||||
|         } catch (error) { | ||||
|             // Ignore errors if cannot create discussions.
 | ||||
|             if (canCreateDiscussions) { | ||||
|                 throw error; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Sync a module. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async sync( | ||||
|         module: CoreCourseAnyModuleData, | ||||
|         courseId: number, | ||||
|         siteId?: string, | ||||
|     ): Promise<AddonModForumSyncResult> { | ||||
|         const promises: Promise<AddonModForumSyncResult>[] = []; | ||||
| 
 | ||||
|         promises.push(AddonModForumSync.instance.syncForumDiscussions(module.instance!, undefined, siteId)); | ||||
|         promises.push(AddonModForumSync.instance.syncForumReplies(module.instance!, undefined, siteId)); | ||||
|         promises.push(AddonModForumSync.instance.syncRatings(module.id, undefined, true, siteId)); | ||||
| 
 | ||||
|         const results = await Promise.all(promises); | ||||
| 
 | ||||
|         return results.reduce( | ||||
|             (a, b) => ({ | ||||
|                 updated: a.updated || b.updated, | ||||
|                 warnings: (a.warnings || []).concat(b.warnings || []), | ||||
|             }), | ||||
|             { | ||||
|                 updated: false, | ||||
|                 warnings: [], | ||||
|             }, | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonModForumPrefetchHandler extends makeSingleton(AddonModForumPrefetchHandlerService) {} | ||||
| 
 | ||||
| /** | ||||
|  * Data returned by a forum sync. | ||||
|  */ | ||||
| export type AddonModForumSyncResult = { | ||||
|     warnings: string[]; // List of warnings.
 | ||||
|     updated: boolean; // Whether some data was sent to the server or offline data was updated.
 | ||||
| }; | ||||
							
								
								
									
										51
									
								
								src/addons/mod/forum/services/handlers/sync-cron.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/addons/mod/forum/services/handlers/sync-cron.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreCronHandler } from '@services/cron'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { AddonModForumSync } from '../sync.service'; | ||||
| 
 | ||||
| /** | ||||
|  * Synchronization cron handler. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonModForumSyncCronHandlerService implements CoreCronHandler { | ||||
| 
 | ||||
|     name = 'AddonModForumSyncCronHandler'; | ||||
| 
 | ||||
|     /** | ||||
|      * Execute the process. | ||||
|      * Receives the ID of the site affected, undefined for all sites. | ||||
|      * | ||||
|      * @param siteId ID of the site affected, undefined for all sites. | ||||
|      * @param force Wether the execution is forced (manual sync). | ||||
|      * @return Promise resolved when done, rejected if failure. | ||||
|      */ | ||||
|     execute(siteId?: string, force?: boolean): Promise<void> { | ||||
|         return AddonModForumSync.instance.syncAllForums(siteId, force); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the time between consecutive executions. | ||||
|      * | ||||
|      * @return Time between consecutive executions (in ms). | ||||
|      */ | ||||
|     getInterval(): number { | ||||
|         return AddonModForumSync.instance.syncInterval; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonModForumSyncCronHandler extends makeSingleton(AddonModForumSyncCronHandlerService) {} | ||||
| @ -25,7 +25,7 @@ import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { makeSingleton, Translate } from '@singletons'; | ||||
| import { CoreArray } from '@singletons/array'; | ||||
| import { CoreEvents } from '@singletons/events'; | ||||
| import { CoreEvents, CoreEventSiteData } from '@singletons/events'; | ||||
| import { | ||||
|     AddonModForum, | ||||
|     AddonModForumAddDiscussionPostWSOptionsObject, | ||||
| @ -95,7 +95,7 @@ export class AddonModForumSyncProvider extends CoreSyncBaseProvider<AddonModForu | ||||
| 
 | ||||
|                 if (result && result.updated) { | ||||
|                     // Sync successful, send event.
 | ||||
|                     CoreEvents.trigger(AddonModForumSyncProvider.AUTO_SYNCED, { | ||||
|                     CoreEvents.trigger<AddonModForumAutoSyncData>(AddonModForumSyncProvider.AUTO_SYNCED, { | ||||
|                         forumId: discussion.forumid, | ||||
|                         userId: discussion.userid, | ||||
|                         warnings: result.warnings, | ||||
| @ -127,7 +127,7 @@ export class AddonModForumSyncProvider extends CoreSyncBaseProvider<AddonModForu | ||||
| 
 | ||||
|                 if (result && result.updated) { | ||||
|                     // Sync successful, send event.
 | ||||
|                     CoreEvents.trigger(AddonModForumSyncProvider.AUTO_SYNCED, { | ||||
|                     CoreEvents.trigger<AddonModForumAutoSyncData>(AddonModForumSyncProvider.AUTO_SYNCED, { | ||||
|                         forumId: reply.forumid, | ||||
|                         discussionId: reply.discussionid, | ||||
|                         userId: reply.userid, | ||||
| @ -619,3 +619,23 @@ export type AddonModForumSyncResult = { | ||||
|     updated: boolean; | ||||
|     warnings: string[]; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Data passed to AUTO_SYNCED event. | ||||
|  */ | ||||
| export type AddonModForumAutoSyncData = CoreEventSiteData & { | ||||
|     forumId: number; | ||||
|     userId: number; | ||||
|     warnings: string[]; | ||||
|     discussionId?: number; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Data passed to MANUAL_SYNCED event. | ||||
|  */ | ||||
| export type AddonModForumManualSyncData = CoreEventSiteData & { | ||||
|     forumId: number; | ||||
|     userId: number; | ||||
|     source: string; | ||||
|     discussionId?: number; | ||||
| }; | ||||
|  | ||||
| @ -147,7 +147,10 @@ export abstract class CorePageItemsListManager<Item> { | ||||
|         const params = this.getItemQueryParams(item); | ||||
|         const pathPrefix = selectedItemPath ? selectedItemPath.split('/').fill('../').join('') : ''; | ||||
| 
 | ||||
|         await CoreNavigator.instance.navigate(pathPrefix + itemPath, { params, reset: true }); | ||||
|         await CoreNavigator.instance.navigate(pathPrefix + itemPath, { | ||||
|             params, | ||||
|             reset: CoreScreen.instance.isTablet, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user