MOBILE-2061 course: Don't sync completion if modified in the site
This commit is contained in:
		
							parent
							
								
									1c6618b42a
								
							
						
					
					
						commit
						83ef6467c8
					
				| @ -1113,6 +1113,7 @@ | ||||
|   "core.course.overriddennotice": "grades", | ||||
|   "core.course.sections": "moodle", | ||||
|   "core.course.useactivityonbrowser": "local_moodlemobileapp", | ||||
|   "core.course.warningmanualcompletionmodified": "local_moodlemobileapp", | ||||
|   "core.course.warningofflinemanualcompletiondeleted": "local_moodlemobileapp", | ||||
|   "core.coursedetails": "moodle", | ||||
|   "core.courses.allowguests": "enrol_guest", | ||||
|  | ||||
| @ -24,5 +24,6 @@ | ||||
|     "refreshcourse": "Refresh course", | ||||
|     "sections": "Sections", | ||||
|     "useactivityonbrowser": "You can still use it using your device's web browser.", | ||||
|     "warningmanualcompletionmodified": "The manual completion of an activity was modified on the site.", | ||||
|     "warningofflinemanualcompletiondeleted": "Some offline manual completion of course '{{name}}' has been deleted. {{error}}" | ||||
| } | ||||
| @ -45,7 +45,7 @@ export class CoreCourseOfflineProvider { | ||||
|                     type: 'TEXT' | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'timecreated', | ||||
|                     name: 'timecompleted', | ||||
|                     type: 'INTEGER' | ||||
|                 } | ||||
|             ] | ||||
| @ -131,7 +131,7 @@ export class CoreCourseOfflineProvider { | ||||
|                 completed: completed, | ||||
|                 courseid: courseId, | ||||
|                 coursename: courseName || '', | ||||
|                 timecreated: Date.now() | ||||
|                 timecompleted: Date.now() | ||||
|             }; | ||||
| 
 | ||||
|             return site.getDb().insertRecord(CoreCourseOfflineProvider.MANUAL_COMPLETION_TABLE, entry); | ||||
|  | ||||
| @ -121,9 +121,14 @@ export class CoreCourseProvider { | ||||
|      * @param {number} courseId Course ID. | ||||
|      * @param {string} [siteId] Site ID. If not defined, current site. | ||||
|      * @param {number} [userId] User ID. If not defined, current user. | ||||
|      * @param {boolean} [forceCache] True if it should return cached data. Has priority over ignoreCache. | ||||
|      * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). | ||||
|      * @param {boolean} [includeOffline=true] True if it should load offline data in the completion status. | ||||
|      * @return {Promise<any>} Promise resolved with the completion statuses: object where the key is module ID. | ||||
|      */ | ||||
|     getActivitiesCompletionStatus(courseId: number, siteId?: string, userId?: number): Promise<any> { | ||||
|     getActivitiesCompletionStatus(courseId: number, siteId?: string, userId?: number, forceCache: boolean = false, | ||||
|             ignoreCache: boolean = false, includeOffline: boolean = true): Promise<any> { | ||||
| 
 | ||||
|         return this.sitesProvider.getSite(siteId).then((site) => { | ||||
|             userId = userId || site.getUserId(); | ||||
| 
 | ||||
| @ -133,10 +138,17 @@ export class CoreCourseProvider { | ||||
|                     courseid: courseId, | ||||
|                     userid: userId | ||||
|                 }, | ||||
|                 preSets = { | ||||
|                 preSets: CoreSiteWSPreSets = { | ||||
|                     cacheKey: this.getActivitiesCompletionCacheKey(courseId, userId) | ||||
|                 }; | ||||
| 
 | ||||
|             if (forceCache) { | ||||
|                 preSets.omitExpires = true; | ||||
|             } else if (ignoreCache) { | ||||
|                 preSets.getFromCache = false; | ||||
|                 preSets.emergencyCache = false; | ||||
|             } | ||||
| 
 | ||||
|             return site.read('core_completion_get_activities_completion_status', params, preSets).then((data) => { | ||||
|                 if (data && data.statuses) { | ||||
|                     return this.utils.arrayToObject(data.statuses, 'cmid'); | ||||
| @ -144,6 +156,10 @@ export class CoreCourseProvider { | ||||
| 
 | ||||
|                 return Promise.reject(null); | ||||
|             }).then((completionStatus) => { | ||||
|                 if (!includeOffline) { | ||||
|                     return completionStatus; | ||||
|                 } | ||||
| 
 | ||||
|                 // Now get the offline completion (if any).
 | ||||
|                 return this.courseOffline.getCourseManualCompletions(courseId, site.id).then((offlineCompletions) => { | ||||
|                     offlineCompletions.forEach((offlineCompletion) => { | ||||
| @ -686,51 +702,33 @@ export class CoreCourseProvider { | ||||
| 
 | ||||
|         siteId = siteId || this.sitesProvider.getCurrentSiteId(); | ||||
| 
 | ||||
|         // Convenience function to store a message to be synchronized later.
 | ||||
|         // Convenience function to store a completion to be synchronized later.
 | ||||
|         const storeOffline = (): Promise<any> => { | ||||
|             return this.courseOffline.markCompletedManually(cmId, completed, courseId, courseName, siteId); | ||||
|         }; | ||||
| 
 | ||||
|         // Check if we already have a completion stored.
 | ||||
|         return this.courseOffline.getManualCompletion(cmId, siteId).catch(() => { | ||||
|             // No completion stored.
 | ||||
|         }).then((entry) => { | ||||
|         // The offline function requires a courseId and it could be missing because it's a calculated field.
 | ||||
|         if (!this.appProvider.isOnline() && courseId) { | ||||
|             // App is offline, store the action.
 | ||||
|             return storeOffline(); | ||||
|         } | ||||
| 
 | ||||
|             if (entry && completed != entry.completed) { | ||||
|                 // It has changed, this means that the offline data can be deleted because the action was undone.
 | ||||
|                 return this.courseOffline.deleteManualCompletion(cmId, siteId).then(() => { | ||||
|                     return { | ||||
|                         status: true, | ||||
|                         offline: true | ||||
|                     }; | ||||
|                 }); | ||||
|             } | ||||
| 
 | ||||
|             if (!this.appProvider.isOnline() && courseId) { | ||||
|                 // App is offline, store the action.
 | ||||
|         // Try to send it to server.
 | ||||
|         return this.markCompletedManuallyOnline(cmId, completed, siteId).then((result) => { | ||||
|             // Data sent to server, if there is some offline data delete it now.
 | ||||
|             return this.courseOffline.deleteManualCompletion(cmId, siteId).catch(() => { | ||||
|                 // Ignore errors, shouldn't happen.
 | ||||
|             }).then(() => { | ||||
|                 return result; | ||||
|             }); | ||||
|         }).catch((error) => { | ||||
|             if (this.utils.isWebServiceError(error) || !courseId) { | ||||
|                 // The WebService has thrown an error, this means that responses cannot be submitted.
 | ||||
|                 return Promise.reject(error); | ||||
|             } else { | ||||
|                 // Couldn't connect to server, store it offline.
 | ||||
|                 return storeOffline(); | ||||
|             } | ||||
| 
 | ||||
|             return this.markCompletedManuallyOnline(cmId, completed, siteId).then((result) => { | ||||
|                 // Data sent to server, if there is some offline data delete it now.
 | ||||
|                 if (entry) { | ||||
|                     return this.courseOffline.deleteManualCompletion(cmId, siteId).catch(() => { | ||||
|                         // Ignore errors, shouldn't happen.
 | ||||
|                     }).then(() => { | ||||
|                         return result; | ||||
|                     }); | ||||
|                 } | ||||
| 
 | ||||
|                 return result; | ||||
|             }).catch((error) => { | ||||
|                 if (this.utils.isWebServiceError(error) || !courseId) { | ||||
|                     // The WebService has thrown an error, this means that responses cannot be submitted.
 | ||||
|                     return Promise.reject(error); | ||||
|                 } else { | ||||
|                     // Couldn't connect to server, store it offline.
 | ||||
|                     return storeOffline(); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -128,34 +128,57 @@ export class CoreCourseSyncProvider extends CoreSyncBaseProvider { | ||||
|                 return Promise.reject(null); | ||||
|             } | ||||
| 
 | ||||
|             const promises = []; | ||||
|             // Get the current completion status to check if any completion was modified in web.
 | ||||
|             return this.courseProvider.getActivitiesCompletionStatus(courseId, siteId, undefined, false, true, false) | ||||
|                     .then((onlineCompletions) => { | ||||
| 
 | ||||
|             // Send all the completions.
 | ||||
|             completions.forEach((entry) => { | ||||
|                 promises.push(this.courseProvider.markCompletedManuallyOnline(entry.cmid, entry.completed, siteId).then(() => { | ||||
|                     result.updated = true; | ||||
|                 const promises = []; | ||||
| 
 | ||||
|                     return this.courseOffline.deleteManualCompletion(entry.cmid, siteId); | ||||
|                 }).catch((error) => { | ||||
|                     if (this.utils.isWebServiceError(error)) { | ||||
|                         // The WebService has thrown an error, this means that the completion cannot be submitted. Delete it.
 | ||||
|                         result.updated = true; | ||||
|                 // Send all the completions.
 | ||||
|                 completions.forEach((entry) => { | ||||
|                     const onlineComp = onlineCompletions[entry.cmid]; | ||||
| 
 | ||||
|                         return this.courseOffline.deleteManualCompletion(entry.cmid, siteId).then(() => { | ||||
|                             // Responses deleted, add a warning.
 | ||||
|                             result.warnings.push(this.translate.instant('core.course.warningofflinemanualcompletiondeleted', { | ||||
|                                 name: entry.coursename || courseId, | ||||
|                                 error: this.textUtils.getErrorMessageFromError(error) | ||||
|                             })); | ||||
|                         }); | ||||
|                     // Check if the completion was modified in online. If so, discard it.
 | ||||
|                     if (onlineComp && onlineComp.timecompleted * 1000 > entry.timecompleted) { | ||||
|                         promises.push(this.courseOffline.deleteManualCompletion(entry.cmid, siteId).then(() => { | ||||
| 
 | ||||
|                             // Completion deleted, add a warning if the completion status doesn't match.
 | ||||
|                             if (onlineComp.state != entry.completed) { | ||||
|                                 result.warnings.push(this.translate.instant('core.course.warningofflinemanualcompletiondeleted', { | ||||
|                                     name: entry.coursename || courseId, | ||||
|                                     error: this.translate.instant('core.course.warningmanualcompletionmodified') | ||||
|                                 })); | ||||
|                             } | ||||
|                         })); | ||||
| 
 | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     // Couldn't connect to server, reject.
 | ||||
|                     return Promise.reject(error); | ||||
|                 })); | ||||
|             }); | ||||
|                     promises.push(this.courseProvider.markCompletedManuallyOnline(entry.cmid, entry.completed, siteId).then(() => { | ||||
|                         result.updated = true; | ||||
| 
 | ||||
|             return Promise.all(promises); | ||||
|                         return this.courseOffline.deleteManualCompletion(entry.cmid, siteId); | ||||
|                     }).catch((error) => { | ||||
|                         if (this.utils.isWebServiceError(error)) { | ||||
|                             // The WebService has thrown an error, this means that the completion cannot be submitted. Delete it.
 | ||||
|                             result.updated = true; | ||||
| 
 | ||||
|                             return this.courseOffline.deleteManualCompletion(entry.cmid, siteId).then(() => { | ||||
|                                 // Completion deleted, add a warning.
 | ||||
|                                 result.warnings.push(this.translate.instant('core.course.warningofflinemanualcompletiondeleted', { | ||||
|                                     name: entry.coursename || courseId, | ||||
|                                     error: this.textUtils.getErrorMessageFromError(error) | ||||
|                                 })); | ||||
|                             }); | ||||
|                         } | ||||
| 
 | ||||
|                         // Couldn't connect to server, reject.
 | ||||
|                         return Promise.reject(error); | ||||
|                     })); | ||||
|                 }); | ||||
| 
 | ||||
|                 return Promise.all(promises); | ||||
|             }); | ||||
|         }).then(() => { | ||||
|             if (result.updated) { | ||||
|                 // Update data.
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user