MOBILE-2486 glossary: Ratings

main
Albert Gasset 2019-03-05 11:50:29 +01:00
parent 8fe3e09e9b
commit af6694c915
11 changed files with 155 additions and 30 deletions

View File

@ -294,7 +294,7 @@ export class AddonModForumSyncProvider extends CoreSyncBaseProvider {
const promises = []; const promises = [];
results.forEach((result) => { results.forEach((result) => {
if (result.updated) { if (result.updated.length) {
updated = true; updated = true;
// Invalidate discussions of updated ratings. // Invalidate discussions of updated ratings.

View File

@ -25,7 +25,7 @@
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"></core-course-module-description> <core-course-module-description [description]="description" [component]="component" [componentId]="componentId"></core-course-module-description>
<!-- Glossary entries found to be synchronized --> <!-- Glossary entries found to be synchronized -->
<ion-card class="core-warning-card" icon-start *ngIf="hasOffline"> <ion-card class="core-warning-card" icon-start *ngIf="hasOffline || hasOfflineRatings">
<ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: moduleName} }} <ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: moduleName} }}
</ion-card> </ion-card>

View File

@ -16,6 +16,9 @@ import { Component, Injector, ViewChild } from '@angular/core';
import { Content, PopoverController } from 'ionic-angular'; import { Content, PopoverController } from 'ionic-angular';
import { CoreSplitViewComponent } from '@components/split-view/split-view'; import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
import { CoreRatingProvider } from '@core/rating/providers/rating';
import { CoreRatingOfflineProvider } from '@core/rating/providers/offline';
import { CoreRatingSyncProvider } from '@core/rating/providers/sync';
import { AddonModGlossaryProvider } from '../../providers/glossary'; import { AddonModGlossaryProvider } from '../../providers/glossary';
import { AddonModGlossaryOfflineProvider } from '../../providers/offline'; import { AddonModGlossaryOfflineProvider } from '../../providers/offline';
import { AddonModGlossarySyncProvider } from '../../providers/sync'; import { AddonModGlossarySyncProvider } from '../../providers/sync';
@ -57,11 +60,16 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
protected getDivider: (entry: any) => string; protected getDivider: (entry: any) => string;
protected addEntryObserver: any; protected addEntryObserver: any;
hasOfflineRatings: boolean;
protected ratingOfflineObserver: any;
protected ratingSyncObserver: any;
constructor(injector: Injector, constructor(injector: Injector,
private popoverCtrl: PopoverController, private popoverCtrl: PopoverController,
private glossaryProvider: AddonModGlossaryProvider, private glossaryProvider: AddonModGlossaryProvider,
private glossaryOffline: AddonModGlossaryOfflineProvider, private glossaryOffline: AddonModGlossaryOfflineProvider,
private glossarySync: AddonModGlossarySyncProvider) { private glossarySync: AddonModGlossarySyncProvider,
private ratingOffline: CoreRatingOfflineProvider) {
super(injector); super(injector);
} }
@ -74,6 +82,20 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
// When an entry is added, we reload the data. // When an entry is added, we reload the data.
this.addEntryObserver = this.eventsProvider.on(AddonModGlossaryProvider.ADD_ENTRY_EVENT, this.eventReceived.bind(this)); this.addEntryObserver = this.eventsProvider.on(AddonModGlossaryProvider.ADD_ENTRY_EVENT, this.eventReceived.bind(this));
// Listen for offline ratings saved and synced.
this.ratingOfflineObserver = this.eventsProvider.on(CoreRatingProvider.RATING_SAVED_EVENT, (data) => {
if (this.glossary && data.component == 'mod_glossary' && data.ratingArea == 'entry' && data.contextLevel == 'module'
&& data.instanceId == this.glossary.coursemodule) {
this.hasOfflineRatings = true;
}
});
this.ratingSyncObserver = this.eventsProvider.on(CoreRatingSyncProvider.SYNCED_EVENT, (data) => {
if (this.glossary && data.component == 'mod_glossary' && data.ratingArea == 'entry' && data.contextLevel == 'module'
&& data.instanceId == this.glossary.coursemodule) {
this.hasOfflineRatings = false;
}
});
this.loadContent(false, true).then(() => { this.loadContent(false, true).then(() => {
if (!this.glossary) { if (!this.glossary) {
return; return;
@ -118,15 +140,23 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
return this.syncActivity(showErrors); return this.syncActivity(showErrors);
} }
}).then(() => { }).then(() => {
const promises = [];
return this.fetchEntries().then(() => { promises.push(this.fetchEntries().then(() => {
// Check if there are responses stored in offline. // Check if there are responses stored in offline.
return this.glossaryOffline.getGlossaryNewEntries(this.glossary.id).then((offlineEntries) => { return this.glossaryOffline.getGlossaryNewEntries(this.glossary.id).then((offlineEntries) => {
offlineEntries.sort((a, b) => a.concept.localeCompare(b.fullname)); offlineEntries.sort((a, b) => a.concept.localeCompare(b.fullname));
this.hasOffline = !!offlineEntries.length; this.hasOffline = !!offlineEntries.length;
this.offlineEntries = offlineEntries || []; this.offlineEntries = offlineEntries || [];
}); });
}); }));
promises.push(this.ratingOffline.hasRatings('mod_glossary', 'entry', 'module', this.glossary.coursemodule)
.then((hasRatings) => {
this.hasOfflineRatings = hasRatings;
}));
return Promise.all(promises);
}).then(() => { }).then(() => {
// All data obtained, now fill the context menu. // All data obtained, now fill the context menu.
this.fillContextMenu(refresh); this.fillContextMenu(refresh);
@ -189,7 +219,17 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
protected sync(): Promise<boolean> { protected sync(): Promise<boolean> {
return this.glossarySync.syncGlossaryEntries(this.glossary.id); const promises = [
this.glossarySync.syncGlossaryEntries(this.glossary.id),
this.glossarySync.syncRatings(this.glossary.coursemodule)
];
return Promise.all(promises).then((results) => {
return results.reduce((a, b) => ({
updated: a.updated || b.updated,
warnings: (a.warnings || []).concat(b.warnings || []),
}), {updated: false});
});
} }
/** /**
@ -345,7 +385,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
openEntry(entryId: number): void { openEntry(entryId: number): void {
const params = { const params = {
courseId: this.courseId, courseId: this.courseId,
entryId: entryId, entryId: entryId
}; };
this.splitviewCtrl.push('AddonModGlossaryEntryPage', params); this.splitviewCtrl.push('AddonModGlossaryEntryPage', params);
this.selectedEntry = entryId; this.selectedEntry = entryId;
@ -400,5 +440,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
super.ngOnDestroy(); super.ngOnDestroy();
this.addEntryObserver && this.addEntryObserver.off(); this.addEntryObserver && this.addEntryObserver.off();
this.ratingOfflineObserver && this.ratingOfflineObserver.off();
this.ratingSyncObserver && this.ratingSyncObserver.off();
} }
} }

View File

@ -31,6 +31,8 @@
<ion-item text-wrap *ngIf="entry.approved != 1"> <ion-item text-wrap *ngIf="entry.approved != 1">
<p><em>{{ 'addon.mod_glossary.entrypendingapproval' | translate }}</em></p> <p><em>{{ 'addon.mod_glossary.entrypendingapproval' | translate }}</em></p>
</ion-item> </ion-item>
<core-rating-rate *ngIf="glossary && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="glossary.coursemodule" [itemId]="entry.id" [itemSetId]="0" [courseId]="glossary.courseid" [aggregateMethod]="glossary.assessed" [scaleId]="glossary.scale" [userId]="entry.userid" (onUpdate)="ratingUpdated()"></core-rating-rate>
<core-rating-aggregate *ngIf="glossary && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="glossary.coursemodule" [itemId]="entry.id" [courseId]="glossary.courseid" [aggregateMethod]="glossary.assessed" [scaleId]="glossary.scale"></core-rating-aggregate>
</ng-container> </ng-container>
<ion-card *ngIf="!entry"> <ion-card *ngIf="!entry">

View File

@ -18,6 +18,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module'; import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module'; import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module'; import { CorePipesModule } from '@pipes/pipes.module';
import { CoreRatingComponentsModule } from '@core/rating/components/components.module';
import { AddonModGlossaryEntryPage } from './entry'; import { AddonModGlossaryEntryPage } from './entry';
@NgModule({ @NgModule({
@ -29,7 +30,8 @@ import { AddonModGlossaryEntryPage } from './entry';
CoreDirectivesModule, CoreDirectivesModule,
CorePipesModule, CorePipesModule,
IonicPageModule.forChild(AddonModGlossaryEntryPage), IonicPageModule.forChild(AddonModGlossaryEntryPage),
TranslateModule.forChild() TranslateModule.forChild(),
CoreRatingComponentsModule
], ],
}) })
export class AddonModForumDiscussionPageModule {} export class AddonModForumDiscussionPageModule {}

View File

@ -15,6 +15,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { IonicPage, NavParams } from 'ionic-angular'; import { IonicPage, NavParams } from 'ionic-angular';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreRatingInfo } from '@core/rating/providers/rating';
import { AddonModGlossaryProvider } from '../../providers/glossary'; import { AddonModGlossaryProvider } from '../../providers/glossary';
/** /**
@ -29,9 +30,11 @@ export class AddonModGlossaryEntryPage {
component = AddonModGlossaryProvider.COMPONENT; component = AddonModGlossaryProvider.COMPONENT;
componentId: number; componentId: number;
entry: any; entry: any;
glossary: any;
loaded = false; loaded = false;
showAuthor = false; showAuthor = false;
showDate = false; showDate = false;
ratingInfo: CoreRatingInfo;
protected courseId: number; protected courseId: number;
protected entryId: number; protected entryId: number;
@ -80,11 +83,13 @@ export class AddonModGlossaryEntryPage {
*/ */
protected fetchEntry(refresh?: boolean): Promise<any> { protected fetchEntry(refresh?: boolean): Promise<any> {
return this.glossaryProvider.getEntry(this.entryId).then((result) => { return this.glossaryProvider.getEntry(this.entryId).then((result) => {
this.entry = result; this.entry = result.entry;
this.ratingInfo = result.ratinginfo;
if (!refresh) { if (!refresh) {
// Load the glossary. // Load the glossary.
return this.glossaryProvider.getGlossaryById(this.courseId, this.entry.glossaryid).then((glossary) => { return this.glossaryProvider.getGlossaryById(this.courseId, this.entry.glossaryid).then((glossary) => {
this.glossary = glossary;
this.componentId = glossary.coursemodule; this.componentId = glossary.coursemodule;
switch (glossary.displayformat) { switch (glossary.displayformat) {
@ -109,4 +114,11 @@ export class AddonModGlossaryEntryPage {
return Promise.reject(null); return Promise.reject(null);
}); });
} }
/**
* Function called when rating is updated online.
*/
ratingUpdated(): void {
this.glossaryProvider.invalidateEntry(this.entryId);
}
} }

View File

@ -61,8 +61,8 @@ export class AddonModGlossaryEntryLinkHandler extends CoreContentLinksHandlerBas
this.domUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingentry', true); this.domUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingentry', true);
return Promise.reject(null); return Promise.reject(null);
}).then((entry) => { }).then((response) => {
return this.courseHelper.getModuleCourseIdByInstance(entry.glossaryid, 'glossary', siteId); return this.courseHelper.getModuleCourseIdByInstance(response.entry.glossaryid, 'glossary', siteId);
}); });
} }

View File

@ -21,6 +21,7 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper'; import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
import { CoreRatingInfo } from '@core/rating/providers/rating';
import { AddonModGlossaryOfflineProvider } from './offline'; import { AddonModGlossaryOfflineProvider } from './offline';
/** /**
@ -489,7 +490,7 @@ export class AddonModGlossaryProvider {
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved with the entry. * @return {Promise<any>} Promise resolved with the entry.
*/ */
getEntry(entryId: number, siteId?: string): Promise<any> { getEntry(entryId: number, siteId?: string): Promise<{entry: any, ratinginfo: CoreRatingInfo}> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
const params = { const params = {
id: entryId id: entryId
@ -500,7 +501,7 @@ export class AddonModGlossaryProvider {
return site.read('mod_glossary_get_entry_by_id', params, preSets).then((response) => { return site.read('mod_glossary_get_entry_by_id', params, preSets).then((response) => {
if (response && response.entry) { if (response && response.entry) {
return response.entry; return response;
} else { } else {
return Promise.reject(null); return Promise.reject(null);
} }
@ -615,31 +616,35 @@ export class AddonModGlossaryProvider {
* *
* @param {any} glossary The glossary object. * @param {any} glossary The glossary object.
* @param {boolean} [onlyEntriesList] If true, entries won't be invalidated. * @param {boolean} [onlyEntriesList] If true, entries won't be invalidated.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when data is invalidated. * @return {Promise<any>} Promise resolved when data is invalidated.
*/ */
invalidateGlossaryEntries(glossary: any, onlyEntriesList?: boolean): Promise<any> { invalidateGlossaryEntries(glossary: any, onlyEntriesList?: boolean, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
const promises = []; const promises = [];
if (!onlyEntriesList) { if (!onlyEntriesList) {
promises.push(this.fetchAllEntries(this.getEntriesByLetter, [glossary.id, 'ALL'], true).then((entries) => { promises.push(this.fetchAllEntries(this.getEntriesByLetter, [glossary.id, 'ALL'], true, siteId).then((entries) => {
return this.invalidateEntries(entries); return this.invalidateEntries(entries, siteId);
})); }));
} }
glossary.browsemodes.forEach((mode) => { glossary.browsemodes.forEach((mode) => {
switch (mode) { switch (mode) {
case 'letter': case 'letter':
promises.push(this.invalidateEntriesByLetter(glossary.id, 'ALL')); promises.push(this.invalidateEntriesByLetter(glossary.id, 'ALL', siteId));
break; break;
case 'cat': case 'cat':
promises.push(this.invalidateEntriesByCategory(glossary.id, AddonModGlossaryProvider.SHOW_ALL_CATERGORIES)); promises.push(this.invalidateEntriesByCategory(glossary.id, AddonModGlossaryProvider.SHOW_ALL_CATERGORIES,
siteId));
break; break;
case 'date': case 'date':
promises.push(this.invalidateEntriesByDate(glossary.id, 'CREATION', 'DESC')); promises.push(this.invalidateEntriesByDate(glossary.id, 'CREATION', 'DESC', siteId));
promises.push(this.invalidateEntriesByDate(glossary.id, 'UPDATE', 'DESC')); promises.push(this.invalidateEntriesByDate(glossary.id, 'UPDATE', 'DESC', siteId));
break; break;
case 'author': case 'author':
promises.push(this.invalidateEntriesByAuthor(glossary.id, 'ALL', 'LASTNAME', 'ASC')); promises.push(this.invalidateEntriesByAuthor(glossary.id, 'ALL', 'LASTNAME', 'ASC', siteId));
break; break;
default: default:
} }

View File

@ -23,6 +23,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreUserProvider } from '@core/user/providers/user'; import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModGlossaryProvider } from './glossary'; import { AddonModGlossaryProvider } from './glossary';
import { CoreRatingProvider } from '@core/rating/providers/rating';
/** /**
* Handler to prefetch forums. * Handler to prefetch forums.
@ -42,6 +43,7 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
private userProvider: CoreUserProvider, private userProvider: CoreUserProvider,
private ratingProvider: CoreRatingProvider,
private glossaryProvider: AddonModGlossaryProvider) { private glossaryProvider: AddonModGlossaryProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
@ -164,7 +166,11 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
// Fetch user avatars. // Fetch user avatars.
entries.forEach((entry) => { entries.forEach((entry) => {
// Fetch individual entries. // Fetch individual entries.
promises.push(this.glossaryProvider.getEntry(entry.id, siteId)); promises.push(this.glossaryProvider.getEntry(entry.id, siteId).then((entry) => {
// Fetch individual ratings.
return this.ratingProvider.prefetchRatings('module', module.id, glossary.scale, courseId, entry.ratinginfo,
siteId);
}));
userIds.push(entry.userid); userIds.push(entry.userid);
}); });
@ -177,6 +183,8 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
return Promise.all(promises); return Promise.all(promises);
})); }));
return Promise.all(promises);
}); });
} }
} }

View File

@ -29,6 +29,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
import { AddonModGlossaryProvider } from './glossary'; import { AddonModGlossaryProvider } from './glossary';
import { AddonModGlossaryHelperProvider } from './helper'; import { AddonModGlossaryHelperProvider } from './helper';
import { AddonModGlossaryOfflineProvider } from './offline'; import { AddonModGlossaryOfflineProvider } from './offline';
import { CoreRatingSyncProvider } from '@core/rating/providers/sync';
/** /**
* Service to sync glossaries. * Service to sync glossaries.
@ -54,7 +55,8 @@ export class AddonModGlossarySyncProvider extends CoreSyncBaseProvider {
private glossaryProvider: AddonModGlossaryProvider, private glossaryProvider: AddonModGlossaryProvider,
private glossaryHelper: AddonModGlossaryHelperProvider, private glossaryHelper: AddonModGlossaryHelperProvider,
private glossaryOffline: AddonModGlossaryOfflineProvider, private glossaryOffline: AddonModGlossaryOfflineProvider,
private logHelper: CoreCourseLogHelperProvider) { private logHelper: CoreCourseLogHelperProvider,
private ratingSync: CoreRatingSyncProvider) {
super('AddonModGlossarySyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate, super('AddonModGlossarySyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils); timeUtils);
@ -79,8 +81,12 @@ export class AddonModGlossarySyncProvider extends CoreSyncBaseProvider {
* @return {Promise<any>} Promise resolved if sync is successful, rejected if sync fails. * @return {Promise<any>} Promise resolved if sync is successful, rejected if sync fails.
*/ */
protected syncAllGlossariesFunc(siteId?: string): Promise<any> { protected syncAllGlossariesFunc(siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
const promises = [];
// Sync all new entries // Sync all new entries
return this.glossaryOffline.getAllNewEntries(siteId).then((entries) => { promises.push(this.glossaryOffline.getAllNewEntries(siteId).then((entries) => {
const promises = {}; const promises = {};
// Do not sync same glossary twice. // Do not sync same glossary twice.
@ -106,7 +112,11 @@ export class AddonModGlossarySyncProvider extends CoreSyncBaseProvider {
// Promises will be an object so, convert to an array first; // Promises will be an object so, convert to an array first;
return Promise.all(this.utils.objectToArray(promises)); return Promise.all(this.utils.objectToArray(promises));
}); }));
promises.push(this.syncRatings(undefined, siteId));
return Promise.all(promises);
} }
/** /**
@ -241,6 +251,50 @@ export class AddonModGlossarySyncProvider extends CoreSyncBaseProvider {
return this.addOngoingSync(syncId, syncPromise, siteId); return this.addOngoingSync(syncId, syncPromise, siteId);
} }
/**
* Synchronize offline ratings.
*
* @param {number} [cmId] Course module to be synced. If not defined, sync all glossaries.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise.
*/
syncRatings(cmId?: number, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.ratingSync.syncRatings('mod_glossary', 'entry', 'module', cmId, 0, siteId).then((results) => {
let updated = false;
const warnings = [];
const promises = [];
results.forEach((result) => {
if (result.updated.length) {
updated = true;
// Invalidate entry of updated ratings.
result.updated.forEach((itemId) => {
promises.push(this.glossaryProvider.invalidateEntry(itemId, siteId));
});
}
if (result.warnings.length) {
promises.push(this.glossaryProvider.getGlossary(result.itemSet.courseId, result.itemSet.instanceId, siteId)
.then((glossary) => {
result.warnings.forEach((warning) => {
warnings.push(this.translate.instant('core.warningofflinedatadeleted', {
component: this.componentTranslate,
name: glossary.name,
error: warning
}));
});
}));
}
});
return this.utils.allPromises(promises).then(() => {
return { updated, warnings };
});
});
}
/** /**
* Delete a new entry. * Delete a new entry.
* *

View File

@ -63,7 +63,7 @@ export class CoreRatingSyncProvider extends CoreSyncBaseProvider {
* @return {Promise<any>} Promise resolved if sync is successful, rejected if sync fails. * @return {Promise<any>} Promise resolved if sync is successful, rejected if sync fails.
*/ */
syncRatings(component: string, ratingArea: string, contextLevel?: string, instanceId?: number, itemSetId?: number, syncRatings(component: string, ratingArea: string, contextLevel?: string, instanceId?: number, itemSetId?: number,
siteId?: string): Promise<{itemSet: CoreRatingItemSet, updated: boolean, warnings: string[]}[]> { siteId?: string): Promise<{itemSet: CoreRatingItemSet, updated: number[], warnings: string[]}[]> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.ratingOffline.getItemSets(component, ratingArea, contextLevel, instanceId, itemSetId, siteId) return this.ratingOffline.getItemSets(component, ratingArea, contextLevel, instanceId, itemSetId, siteId)
@ -102,7 +102,7 @@ export class CoreRatingSyncProvider extends CoreSyncBaseProvider {
* @return {Promise<any>} Promise resolved when ratings are synced or if it doesn't need to be synced. * @return {Promise<any>} Promise resolved when ratings are synced or if it doesn't need to be synced.
*/ */
protected syncItemSetIfNeeded(component: string, ratingArea: string, contextLevel: string, instanceId: number, protected syncItemSetIfNeeded(component: string, ratingArea: string, contextLevel: string, instanceId: number,
itemSetId: number, siteId?: string): Promise<{updated: boolean, warnings: string[]}> { itemSetId: number, siteId?: string): Promise<{updated: number[], warnings: string[]}> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
const syncId = this.getItemSetSyncId(component, ratingArea, contextLevel, instanceId, itemSetId); const syncId = this.getItemSetSyncId(component, ratingArea, contextLevel, instanceId, itemSetId);
@ -126,7 +126,7 @@ export class CoreRatingSyncProvider extends CoreSyncBaseProvider {
* @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise. * @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise.
*/ */
protected syncItemSet(component: string, ratingArea: string, contextLevel: string, instanceId: number, itemSetId: number, protected syncItemSet(component: string, ratingArea: string, contextLevel: string, instanceId: number, itemSetId: number,
siteId?: string): Promise<{updated: boolean, warnings: string[]}> { siteId?: string): Promise<{updated: number[], warnings: string[]}> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
@ -139,7 +139,7 @@ export class CoreRatingSyncProvider extends CoreSyncBaseProvider {
this.logger.debug(`Try to sync ratings of component '${component}' rating area '${ratingArea}'` + this.logger.debug(`Try to sync ratings of component '${component}' rating area '${ratingArea}'` +
` context level '${contextLevel}' instance ${instanceId} item set ${itemSetId}`); ` context level '${contextLevel}' instance ${instanceId} item set ${itemSetId}`);
let updated = false; const updated = [];
const warnings = []; const warnings = [];
return this.ratingOffline.getRatings(component, ratingArea, contextLevel, instanceId, itemSetId, siteId).then((ratings) => { return this.ratingOffline.getRatings(component, ratingArea, contextLevel, instanceId, itemSetId, siteId).then((ratings) => {
@ -162,7 +162,7 @@ export class CoreRatingSyncProvider extends CoreSyncBaseProvider {
return Promise.reject(error); return Promise.reject(error);
} }
}).then(() => { }).then(() => {
updated = true; updated.push(rating.itemid);
return this.ratingOffline.deleteRating(component, ratingArea, rating.contextlevel, rating.instanceid, return this.ratingOffline.deleteRating(component, ratingArea, rating.contextlevel, rating.instanceid,
rating.itemid, siteId).finally(() => { rating.itemid, siteId).finally(() => {