MOBILE-2856 data: Helper functions for fetching entries
parent
3d0e7d14e1
commit
6b0f08695f
|
@ -20,11 +20,9 @@ import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
|
||||||
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
|
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
|
||||||
import { CoreCommentsProvider } from '@core/comments/providers/comments';
|
import { CoreCommentsProvider } from '@core/comments/providers/comments';
|
||||||
import { CoreRatingProvider } from '@core/rating/providers/rating';
|
import { CoreRatingProvider } from '@core/rating/providers/rating';
|
||||||
import { CoreRatingOfflineProvider } from '@core/rating/providers/offline';
|
|
||||||
import { CoreRatingSyncProvider } from '@core/rating/providers/sync';
|
import { CoreRatingSyncProvider } from '@core/rating/providers/sync';
|
||||||
import { AddonModDataProvider } from '../../providers/data';
|
import { AddonModDataProvider } from '../../providers/data';
|
||||||
import { AddonModDataHelperProvider } from '../../providers/helper';
|
import { AddonModDataHelperProvider } from '../../providers/helper';
|
||||||
import { AddonModDataOfflineProvider } from '../../providers/offline';
|
|
||||||
import { AddonModDataSyncProvider } from '../../providers/sync';
|
import { AddonModDataSyncProvider } from '../../providers/sync';
|
||||||
import { AddonModDataComponentsModule } from '../components.module';
|
import { AddonModDataComponentsModule } from '../components.module';
|
||||||
import { AddonModDataPrefetchHandler } from '../../providers/prefetch-handler';
|
import { AddonModDataPrefetchHandler } from '../../providers/prefetch-handler';
|
||||||
|
@ -65,8 +63,6 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
advanced: []
|
advanced: []
|
||||||
};
|
};
|
||||||
hasNextPage = false;
|
hasNextPage = false;
|
||||||
offlineActions: any;
|
|
||||||
offlineEntries: any;
|
|
||||||
entriesRendered = '';
|
entriesRendered = '';
|
||||||
extraImports = [AddonModDataComponentsModule];
|
extraImports = [AddonModDataComponentsModule];
|
||||||
jsData;
|
jsData;
|
||||||
|
@ -81,12 +77,19 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
protected ratingOfflineObserver: any;
|
protected ratingOfflineObserver: any;
|
||||||
protected ratingSyncObserver: any;
|
protected ratingSyncObserver: any;
|
||||||
|
|
||||||
constructor(injector: Injector, private dataProvider: AddonModDataProvider, private dataHelper: AddonModDataHelperProvider,
|
constructor(
|
||||||
private dataOffline: AddonModDataOfflineProvider, @Optional() content: Content,
|
injector: Injector,
|
||||||
private prefetchHandler: AddonModDataPrefetchHandler, private timeUtils: CoreTimeUtilsProvider,
|
@Optional() content: Content,
|
||||||
private groupsProvider: CoreGroupsProvider, private commentsProvider: CoreCommentsProvider,
|
private dataProvider: AddonModDataProvider,
|
||||||
private modalCtrl: ModalController, private utils: CoreUtilsProvider, protected navCtrl: NavController,
|
private dataHelper: AddonModDataHelperProvider,
|
||||||
private ratingOffline: CoreRatingOfflineProvider) {
|
private prefetchHandler: AddonModDataPrefetchHandler,
|
||||||
|
private timeUtils: CoreTimeUtilsProvider,
|
||||||
|
private groupsProvider: CoreGroupsProvider,
|
||||||
|
private commentsProvider: CoreCommentsProvider,
|
||||||
|
private modalCtrl: ModalController,
|
||||||
|
private utils: CoreUtilsProvider,
|
||||||
|
protected navCtrl: NavController) {
|
||||||
|
|
||||||
super(injector, content);
|
super(injector, content);
|
||||||
|
|
||||||
// Refresh entries on change.
|
// Refresh entries on change.
|
||||||
|
@ -233,8 +236,6 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
this.selectedGroup = groupInfo.groups[0].id;
|
this.selectedGroup = groupInfo.groups[0].id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.fetchOfflineEntries();
|
|
||||||
});
|
});
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
return this.dataProvider.getFields(this.data.id).then((fields) => {
|
return this.dataProvider.getFields(this.data.id).then((fields) => {
|
||||||
|
@ -270,21 +271,19 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
// Update values for current group.
|
// Update values for current group.
|
||||||
this.access.canaddentry = accessData.canaddentry;
|
this.access.canaddentry = accessData.canaddentry;
|
||||||
|
|
||||||
if (this.search.searching) {
|
const search = this.search.searching && !this.search.searchingAdvanced ? this.search.text : undefined;
|
||||||
const text = this.search.searchingAdvanced ? undefined : this.search.text,
|
const advSearch = this.search.searching && this.search.searchingAdvanced ? this.search.advanced : undefined;
|
||||||
advanced = this.search.searchingAdvanced ? this.search.advanced : undefined;
|
|
||||||
|
|
||||||
return this.dataProvider.searchEntries(this.data.id, this.selectedGroup, text, advanced, this.search.sortBy,
|
return this.dataHelper.fetchEntries(this.data, this.fieldsArray, this.selectedGroup, search, advSearch,
|
||||||
this.search.sortDirection, this.search.page);
|
this.search.sortBy, this.search.sortDirection, this.search.page);
|
||||||
} else {
|
|
||||||
return this.dataProvider.getEntries(this.data.id, this.selectedGroup, this.search.sortBy, this.search.sortDirection,
|
|
||||||
this.search.page);
|
|
||||||
}
|
|
||||||
}).then((entries) => {
|
}).then((entries) => {
|
||||||
const numEntries = (entries && entries.entries && entries.entries.length) || 0;
|
const numEntries = entries.entries.length;
|
||||||
this.isEmpty = !numEntries && !Object.keys(this.offlineActions).length && !Object.keys(this.offlineEntries).length;
|
const numOfflineEntries = entries.offlineEntries.length;
|
||||||
|
this.isEmpty = !numEntries && !entries.offlineEntries.length;
|
||||||
this.hasNextPage = numEntries >= AddonModDataProvider.PER_PAGE && ((this.search.page + 1) *
|
this.hasNextPage = numEntries >= AddonModDataProvider.PER_PAGE && ((this.search.page + 1) *
|
||||||
AddonModDataProvider.PER_PAGE) < entries.totalcount;
|
AddonModDataProvider.PER_PAGE) < entries.totalcount;
|
||||||
|
this.hasOffline = entries.hasOfflineActions;
|
||||||
|
this.hasOfflineRatings = entries.hasOfflineRatings;
|
||||||
this.entriesRendered = '';
|
this.entriesRendered = '';
|
||||||
|
|
||||||
if (typeof entries.maxcount != 'undefined') {
|
if (typeof entries.maxcount != 'undefined') {
|
||||||
|
@ -298,63 +297,26 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isEmpty) {
|
if (!this.isEmpty) {
|
||||||
const siteInfo = this.sitesProvider.getCurrentSite().getInfo(),
|
this.entries = entries.offlineEntries.concat(entries.entries);
|
||||||
promises = [];
|
|
||||||
|
|
||||||
this.utils.objectToArray(this.offlineEntries).forEach((offlineActions) => {
|
|
||||||
const offlineEntry = offlineActions.find((offlineEntry) => offlineEntry.action == 'add');
|
|
||||||
|
|
||||||
if (offlineEntry) {
|
|
||||||
const entry = {
|
|
||||||
id: offlineEntry.entryid,
|
|
||||||
canmanageentry: true,
|
|
||||||
approved: !this.data.approval || this.data.manageapproved,
|
|
||||||
dataid: offlineEntry.dataid,
|
|
||||||
groupid: offlineEntry.groupid,
|
|
||||||
timecreated: -offlineEntry.entryid,
|
|
||||||
timemodified: -offlineEntry.entryid,
|
|
||||||
userid: siteInfo.userid,
|
|
||||||
fullname: siteInfo.fullname,
|
|
||||||
contents: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (offlineActions.length > 0) {
|
|
||||||
promises.push(this.dataHelper.applyOfflineActions(entry, offlineActions, this.fieldsArray));
|
|
||||||
} else {
|
|
||||||
promises.push(Promise.resolve(entry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
entries.entries.forEach((entry) => {
|
|
||||||
if (typeof this.offlineActions[entry.id] != 'undefined') {
|
|
||||||
promises.push(this.dataHelper.applyOfflineActions(entry, this.offlineActions[entry.id], this.fieldsArray));
|
|
||||||
} else {
|
|
||||||
promises.push(Promise.resolve(entry));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(promises).then((entries) => {
|
|
||||||
this.entries = entries;
|
|
||||||
|
|
||||||
let entriesHTML = this.data.listtemplateheader || '';
|
let entriesHTML = this.data.listtemplateheader || '';
|
||||||
|
|
||||||
// Get first entry from the whole list.
|
// Get first entry from the whole list.
|
||||||
if (entries && entries[0] && (!this.search.searching || !this.firstEntry)) {
|
if (!this.search.searching || !this.firstEntry) {
|
||||||
this.firstEntry = entries[0].id;
|
this.firstEntry = this.entries[0].id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const template = this.data.listtemplate || this.dataHelper.getDefaultTemplate('list', this.fieldsArray);
|
const template = this.data.listtemplate || this.dataHelper.getDefaultTemplate('list', this.fieldsArray);
|
||||||
|
|
||||||
const entriesById = {};
|
const entriesById = {};
|
||||||
entries.forEach((entry, index) => {
|
this.entries.forEach((entry, index) => {
|
||||||
entriesById[entry.id] = entry;
|
entriesById[entry.id] = entry;
|
||||||
|
|
||||||
const actions = this.dataHelper.getActions(this.data, this.access, entry);
|
const actions = this.dataHelper.getActions(this.data, this.access, entry);
|
||||||
const offset = this.search.page * AddonModDataProvider.PER_PAGE + index;
|
const offset = this.search.searching ? undefined :
|
||||||
|
this.search.page * AddonModDataProvider.PER_PAGE + index - numOfflineEntries;
|
||||||
|
|
||||||
entriesHTML += this.dataHelper.displayShowFields(template, this.fieldsArray, entry, offset, 'list',
|
entriesHTML += this.dataHelper.displayShowFields(template, this.fieldsArray, entry, offset, 'list', actions);
|
||||||
actions);
|
|
||||||
});
|
});
|
||||||
entriesHTML += this.data.listtemplatefooter || '';
|
entriesHTML += this.data.listtemplatefooter || '';
|
||||||
|
|
||||||
|
@ -365,9 +327,10 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
fields: this.fields,
|
fields: this.fields,
|
||||||
entries: entriesById,
|
entries: entriesById,
|
||||||
data: this.data,
|
data: this.data,
|
||||||
|
module: this.module,
|
||||||
|
group: this.selectedGroup,
|
||||||
gotoEntry: this.gotoEntry.bind(this)
|
gotoEntry: this.gotoEntry.bind(this)
|
||||||
};
|
};
|
||||||
});
|
|
||||||
} else if (!this.search.searching) {
|
} else if (!this.search.searching) {
|
||||||
// Empty and no searching.
|
// Empty and no searching.
|
||||||
this.canSearch = false;
|
this.canSearch = false;
|
||||||
|
@ -476,42 +439,6 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
this.navCtrl.push('AddonModDataEntryPage', params);
|
this.navCtrl.push('AddonModDataEntryPage', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch offline entries.
|
|
||||||
*
|
|
||||||
* @return {Promise<any>} Resolved then done.
|
|
||||||
*/
|
|
||||||
protected fetchOfflineEntries(): Promise<any> {
|
|
||||||
// Check if there are entries stored in offline.
|
|
||||||
return this.dataOffline.getDatabaseEntries(this.data.id).then((offlineEntries) => {
|
|
||||||
this.hasOffline = !!offlineEntries.length;
|
|
||||||
|
|
||||||
this.offlineActions = {};
|
|
||||||
this.offlineEntries = {};
|
|
||||||
|
|
||||||
// Only show offline entries on first page.
|
|
||||||
if (this.search.page == 0 && this.hasOffline) {
|
|
||||||
offlineEntries.forEach((entry) => {
|
|
||||||
if (entry.entryid > 0) {
|
|
||||||
if (typeof this.offlineActions[entry.entryid] == 'undefined') {
|
|
||||||
this.offlineActions[entry.entryid] = [];
|
|
||||||
}
|
|
||||||
this.offlineActions[entry.entryid].push(entry);
|
|
||||||
} else {
|
|
||||||
if (typeof this.offlineActions[entry.entryid] == 'undefined') {
|
|
||||||
this.offlineEntries[entry.entryid] = [];
|
|
||||||
}
|
|
||||||
this.offlineEntries[entry.entryid].push(entry);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).then(() => {
|
|
||||||
return this.ratingOffline.hasRatings('mod_data', 'entry', 'module', this.data.coursemodule).then((hasRatings) => {
|
|
||||||
this.hasOfflineRatings = hasRatings;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the sync of the activity.
|
* Performs the sync of the activity.
|
||||||
*
|
*
|
||||||
|
|
|
@ -45,7 +45,6 @@ export class AddonModDataEditPage {
|
||||||
protected data: any;
|
protected data: any;
|
||||||
protected entryId: number;
|
protected entryId: number;
|
||||||
protected entry: any;
|
protected entry: any;
|
||||||
protected offlineActions = [];
|
|
||||||
protected fields = {};
|
protected fields = {};
|
||||||
protected fieldsArray = [];
|
protected fieldsArray = [];
|
||||||
protected siteId: string;
|
protected siteId: string;
|
||||||
|
@ -145,28 +144,14 @@ export class AddonModDataEditPage {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
return this.dataOffline.getEntryActions(this.data.id, this.entryId);
|
|
||||||
}).then((actions) => {
|
|
||||||
this.offlineActions = actions;
|
|
||||||
|
|
||||||
return this.dataProvider.getFields(this.data.id);
|
return this.dataProvider.getFields(this.data.id);
|
||||||
}).then((fieldsData) => {
|
}).then((fieldsData) => {
|
||||||
this.fieldsArray = fieldsData;
|
this.fieldsArray = fieldsData;
|
||||||
this.fields = this.utils.arrayToObject(fieldsData, 'id');
|
this.fields = this.utils.arrayToObject(fieldsData, 'id');
|
||||||
|
|
||||||
return this.dataHelper.getEntry(this.data, this.entryId, this.offlineActions);
|
return this.dataHelper.fetchEntry(this.data, fieldsData, this.entryId);
|
||||||
}).then((entry) => {
|
}).then((entry) => {
|
||||||
if (entry) {
|
this.entry = entry.entry;
|
||||||
entry = entry.entry;
|
|
||||||
} else {
|
|
||||||
entry = {
|
|
||||||
contents: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.dataHelper.applyOfflineActions(entry, this.offlineActions, this.fieldsArray);
|
|
||||||
}).then((entryData) => {
|
|
||||||
this.entry = entryData;
|
|
||||||
|
|
||||||
this.editFormRender = this.displayEditFields();
|
this.editFormRender = this.displayEditFields();
|
||||||
}).catch((message) => {
|
}).catch((message) => {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
<core-loading [hideUntil]="entryLoaded && (isPullingToRefresh || !renderingEntry && !loadingRating && !loadingComments)">
|
<core-loading [hideUntil]="entryLoaded && (isPullingToRefresh || !renderingEntry && !loadingRating && !loadingComments)">
|
||||||
<!-- Database entries found to be synchronized -->
|
<!-- Database entries found to be synchronized -->
|
||||||
<div class="core-warning-card" icon-start *ngIf="hasOffline">
|
<div class="core-warning-card" icon-start *ngIf="entry && entry.hasOffline">
|
||||||
<ion-icon name="warning"></ion-icon>
|
<ion-icon name="warning"></ion-icon>
|
||||||
{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}
|
{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
<core-rating-rate *ngIf="data && entry && ratingInfo && (!data.approval || entry.approved)" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="data.coursemodule" [itemId]="entry.id" [itemSetId]="0" [courseId]="courseId" [aggregateMethod]="data.assessed" [scaleId]="data.scale" [userId]="entry.userid" (onLoading)="setLoadingRating($event)" (onUpdate)="ratingUpdated()"></core-rating-rate>
|
<core-rating-rate *ngIf="data && entry && ratingInfo && (!data.approval || entry.approved)" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="data.coursemodule" [itemId]="entry.id" [itemSetId]="0" [courseId]="courseId" [aggregateMethod]="data.assessed" [scaleId]="data.scale" [userId]="entry.userid" (onLoading)="setLoadingRating($event)" (onUpdate)="ratingUpdated()"></core-rating-rate>
|
||||||
<core-rating-aggregate *ngIf="data && entry && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="data.coursemodule" [itemId]="entry.id" [courseId]="courseId" [aggregateMethod]="data.assessed" [scaleId]="data.scale"></core-rating-aggregate>
|
<core-rating-aggregate *ngIf="data && entry && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="data.coursemodule" [itemId]="entry.id" [courseId]="courseId" [aggregateMethod]="data.assessed" [scaleId]="data.scale"></core-rating-aggregate>
|
||||||
|
|
||||||
<ion-item *ngIf="data && entry">
|
<ion-item *ngIf="data && entry && entry.id > 0">
|
||||||
<core-comments contextLevel="module" [instanceId]="data.coursemodule" component="mod_data" [itemId]="entry.id" area="database_entry" [displaySpinner]="false" (onLoading)="setLoadingComments($event)"></core-comments>
|
<core-comments contextLevel="module" [instanceId]="data.coursemodule" component="mod_data" [itemId]="entry.id" area="database_entry" [displaySpinner]="false" (onLoading)="setLoadingComments($event)"></core-comments>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreRatingInfo } from '@core/rating/providers/rating';
|
import { CoreRatingInfo } from '@core/rating/providers/rating';
|
||||||
import { AddonModDataProvider } from '../../providers/data';
|
import { AddonModDataProvider } from '../../providers/data';
|
||||||
import { AddonModDataHelperProvider } from '../../providers/helper';
|
import { AddonModDataHelperProvider } from '../../providers/helper';
|
||||||
import { AddonModDataOfflineProvider } from '../../providers/offline';
|
|
||||||
import { AddonModDataSyncProvider } from '../../providers/sync';
|
import { AddonModDataSyncProvider } from '../../providers/sync';
|
||||||
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
|
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
|
||||||
import { AddonModDataComponentsModule } from '../../components/components.module';
|
import { AddonModDataComponentsModule } from '../../components/components.module';
|
||||||
|
@ -46,6 +45,7 @@ export class AddonModDataEntryPage implements OnDestroy {
|
||||||
protected syncObserver: any; // It will observe the sync auto event.
|
protected syncObserver: any; // It will observe the sync auto event.
|
||||||
protected entryChangedObserver: any; // It will observe the changed entry event.
|
protected entryChangedObserver: any; // It will observe the changed entry event.
|
||||||
protected fields = {};
|
protected fields = {};
|
||||||
|
protected fieldsArray = [];
|
||||||
|
|
||||||
title = '';
|
title = '';
|
||||||
moduleName = 'data';
|
moduleName = 'data';
|
||||||
|
@ -56,8 +56,6 @@ export class AddonModDataEntryPage implements OnDestroy {
|
||||||
loadingRating = false;
|
loadingRating = false;
|
||||||
selectedGroup = 0;
|
selectedGroup = 0;
|
||||||
entry: any;
|
entry: any;
|
||||||
offlineActions = [];
|
|
||||||
hasOffline = false;
|
|
||||||
previousOffset: number;
|
previousOffset: number;
|
||||||
nextOffset: number;
|
nextOffset: number;
|
||||||
access: any;
|
access: any;
|
||||||
|
@ -74,7 +72,7 @@ export class AddonModDataEntryPage implements OnDestroy {
|
||||||
constructor(params: NavParams, protected utils: CoreUtilsProvider, protected groupsProvider: CoreGroupsProvider,
|
constructor(params: NavParams, protected utils: CoreUtilsProvider, protected groupsProvider: CoreGroupsProvider,
|
||||||
protected domUtils: CoreDomUtilsProvider, protected fieldsDelegate: AddonModDataFieldsDelegate,
|
protected domUtils: CoreDomUtilsProvider, protected fieldsDelegate: AddonModDataFieldsDelegate,
|
||||||
protected courseProvider: CoreCourseProvider, protected dataProvider: AddonModDataProvider,
|
protected courseProvider: CoreCourseProvider, protected dataProvider: AddonModDataProvider,
|
||||||
protected dataOffline: AddonModDataOfflineProvider, protected dataHelper: AddonModDataHelperProvider,
|
protected dataHelper: AddonModDataHelperProvider,
|
||||||
sitesProvider: CoreSitesProvider, protected navCtrl: NavController, protected eventsProvider: CoreEventsProvider,
|
sitesProvider: CoreSitesProvider, protected navCtrl: NavController, protected eventsProvider: CoreEventsProvider,
|
||||||
private cdr: ChangeDetectorRef) {
|
private cdr: ChangeDetectorRef) {
|
||||||
this.module = params.get('module') || {};
|
this.module = params.get('module') || {};
|
||||||
|
@ -131,8 +129,6 @@ export class AddonModDataEntryPage implements OnDestroy {
|
||||||
* @return {Promise<any>} Resolved when done.
|
* @return {Promise<any>} Resolved when done.
|
||||||
*/
|
*/
|
||||||
protected fetchEntryData(refresh?: boolean, isPtr?: boolean): Promise<any> {
|
protected fetchEntryData(refresh?: boolean, isPtr?: boolean): Promise<any> {
|
||||||
let fieldsArray;
|
|
||||||
|
|
||||||
this.isPullingToRefresh = isPtr;
|
this.isPullingToRefresh = isPtr;
|
||||||
|
|
||||||
return this.dataProvider.getDatabase(this.courseId, this.module.id).then((data) => {
|
return this.dataProvider.getDatabase(this.courseId, this.module.id).then((data) => {
|
||||||
|
@ -155,32 +151,22 @@ export class AddonModDataEntryPage implements OnDestroy {
|
||||||
this.selectedGroup = groupInfo.groups[0].id;
|
this.selectedGroup = groupInfo.groups[0].id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.dataOffline.getEntryActions(this.data.id, this.entryId);
|
|
||||||
});
|
});
|
||||||
}).then((actions) => {
|
}).then(() => {
|
||||||
this.offlineActions = actions;
|
|
||||||
this.hasOffline = !!actions.length;
|
|
||||||
|
|
||||||
return this.dataProvider.getFields(this.data.id).then((fieldsData) => {
|
return this.dataProvider.getFields(this.data.id).then((fieldsData) => {
|
||||||
this.fields = this.utils.arrayToObject(fieldsData, 'id');
|
this.fields = this.utils.arrayToObject(fieldsData, 'id');
|
||||||
|
this.fieldsArray = fieldsData;
|
||||||
|
|
||||||
return this.dataHelper.getEntry(this.data, this.entryId, this.offlineActions);
|
return this.dataHelper.fetchEntry(this.data, fieldsData, this.entryId);
|
||||||
});
|
});
|
||||||
}).then((entry) => {
|
}).then((entry) => {
|
||||||
|
this.entry = entry.entry;
|
||||||
this.ratingInfo = entry.ratinginfo;
|
this.ratingInfo = entry.ratinginfo;
|
||||||
entry = entry.entry;
|
|
||||||
|
|
||||||
fieldsArray = this.utils.objectToArray(this.fields);
|
|
||||||
|
|
||||||
return this.dataHelper.applyOfflineActions(entry, this.offlineActions, fieldsArray);
|
|
||||||
}).then((entryData) => {
|
|
||||||
this.entry = entryData;
|
|
||||||
|
|
||||||
const actions = this.dataHelper.getActions(this.data, this.access, this.entry);
|
const actions = this.dataHelper.getActions(this.data, this.access, this.entry);
|
||||||
|
|
||||||
const templte = this.data.singletemplate || this.dataHelper.getDefaultTemplate('single', fieldsArray);
|
const templte = this.data.singletemplate || this.dataHelper.getDefaultTemplate('single', this.fieldsArray);
|
||||||
this.entryHtml = this.dataHelper.displayShowFields(templte, fieldsArray, this.entry, this.offset, 'show', actions);
|
this.entryHtml = this.dataHelper.displayShowFields(templte, this.fieldsArray, this.entry, this.offset, 'show', actions);
|
||||||
this.showComments = actions.comments;
|
this.showComments = actions.comments;
|
||||||
|
|
||||||
const entries = {};
|
const entries = {};
|
||||||
|
|
|
@ -19,7 +19,9 @@ import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
||||||
import { AddonModDataFieldsDelegate } from './fields-delegate';
|
import { AddonModDataFieldsDelegate } from './fields-delegate';
|
||||||
import { AddonModDataOfflineProvider, AddonModDataOfflineAction } from './offline';
|
import { AddonModDataOfflineProvider, AddonModDataOfflineAction } from './offline';
|
||||||
import { AddonModDataProvider, AddonModDataEntry, AddonModDataEntryFields } from './data';
|
import { AddonModDataProvider, AddonModDataEntry, AddonModDataEntryFields, AddonModDataEntries } from './data';
|
||||||
|
import { CoreRatingInfo } from '@core/rating/providers/rating';
|
||||||
|
import { CoreRatingOfflineProvider } from '@core/rating/providers/offline';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service that provides helper functions for datas.
|
* Service that provides helper functions for datas.
|
||||||
|
@ -30,7 +32,7 @@ export class AddonModDataHelperProvider {
|
||||||
constructor(private sitesProvider: CoreSitesProvider, protected dataProvider: AddonModDataProvider,
|
constructor(private sitesProvider: CoreSitesProvider, protected dataProvider: AddonModDataProvider,
|
||||||
private translate: TranslateService, private fieldsDelegate: AddonModDataFieldsDelegate,
|
private translate: TranslateService, private fieldsDelegate: AddonModDataFieldsDelegate,
|
||||||
private dataOffline: AddonModDataOfflineProvider, private fileUploaderProvider: CoreFileUploaderProvider,
|
private dataOffline: AddonModDataOfflineProvider, private fileUploaderProvider: CoreFileUploaderProvider,
|
||||||
private textUtils: CoreTextUtilsProvider) { }
|
private textUtils: CoreTextUtilsProvider, private ratingOffline: CoreRatingOfflineProvider) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the record with the offline actions applied.
|
* Returns the record with the offline actions applied.
|
||||||
|
@ -156,6 +158,153 @@ export class AddonModDataHelperProvider {
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get online and offline entries, or search entries.
|
||||||
|
*
|
||||||
|
* @param {any} data Database object.
|
||||||
|
* @param {any[]} fields The fields that define the contents.
|
||||||
|
* @param {number} [groupId=0] Group ID.
|
||||||
|
* @param {string} [search] Search text. It will be used if advSearch is not defined.
|
||||||
|
* @param {any[]} [advSearch] Advanced search data.
|
||||||
|
* @param {string} [sort=0] Sort the records by this field id, reserved ids are:
|
||||||
|
* 0: timeadded
|
||||||
|
* -1: firstname
|
||||||
|
* -2: lastname
|
||||||
|
* -3: approved
|
||||||
|
* -4: timemodified.
|
||||||
|
* Empty for using the default database setting.
|
||||||
|
* @param {string} [order=DESC] The direction of the sorting: 'ASC' or 'DESC'.
|
||||||
|
* Empty for using the default database setting.
|
||||||
|
* @param {number} [page=0] Page of records to return.
|
||||||
|
* @param {number} [perPage=PER_PAGE] Records per page to return. Default on PER_PAGE.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<AddonModDataEntries>} Promise resolved when the database is retrieved.
|
||||||
|
*/
|
||||||
|
fetchEntries(data: any, fields: any[], groupId: number = 0, search?: string, advSearch?: any[], sort: string = '0',
|
||||||
|
order: string = 'DESC', page: number = 0, perPage: number = AddonModDataProvider.PER_PAGE, siteId?: string):
|
||||||
|
Promise<AddonModDataEntries> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
const offlineActions = {};
|
||||||
|
const result: AddonModDataEntries = {
|
||||||
|
entries: [],
|
||||||
|
totalcount: 0,
|
||||||
|
offlineEntries: []
|
||||||
|
};
|
||||||
|
|
||||||
|
const offlinePromise = this.dataOffline.getDatabaseEntries(data.id, site.id).then((actions) => {
|
||||||
|
result.hasOfflineActions = !!actions.length;
|
||||||
|
|
||||||
|
actions.forEach((action) => {
|
||||||
|
if (typeof offlineActions[action.entryid] == 'undefined') {
|
||||||
|
offlineActions[action.entryid] = [];
|
||||||
|
}
|
||||||
|
offlineActions[action.entryid].push(action);
|
||||||
|
|
||||||
|
// We only display new entries in the first page when not searching.
|
||||||
|
if (action.action == 'add' && page == 0 && !search && !advSearch &&
|
||||||
|
(!action.groupid || !groupId || action.groupid == groupId)) {
|
||||||
|
result.offlineEntries.push({
|
||||||
|
id: action.entryid,
|
||||||
|
canmanageentry: true,
|
||||||
|
approved: !data.approval || data.manageapproved,
|
||||||
|
dataid: data.id,
|
||||||
|
groupid: action.groupid,
|
||||||
|
timecreated: -action.entryid,
|
||||||
|
timemodified: -action.entryid,
|
||||||
|
userid: site.getUserId(),
|
||||||
|
fullname: site.getInfo().fullname,
|
||||||
|
contents: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort offline entries by creation time.
|
||||||
|
result.offlineEntries.sort((entry1, entry2) => entry2.timecreated - entry1.timecreated);
|
||||||
|
});
|
||||||
|
|
||||||
|
const ratingsPromise = this.ratingOffline.hasRatings('mod_data', 'entry', 'module', data.coursemodule)
|
||||||
|
.then((hasRatings) => {
|
||||||
|
result.hasOfflineRatings = hasRatings;
|
||||||
|
});
|
||||||
|
|
||||||
|
let fetchPromise: Promise<void>;
|
||||||
|
if (search || advSearch) {
|
||||||
|
fetchPromise = this.dataProvider.searchEntries(data.id, groupId, search, advSearch, sort, order, page, perPage,
|
||||||
|
site.id).then((fetchResult) => {
|
||||||
|
result.entries = fetchResult.entries;
|
||||||
|
result.totalcount = fetchResult.totalcount;
|
||||||
|
result.maxcount = fetchResult.maxcount;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fetchPromise = this.dataProvider.getEntries(data.id, groupId, sort, order, page, perPage, false, false, site.id)
|
||||||
|
.then((fetchResult) => {
|
||||||
|
result.entries = fetchResult.entries;
|
||||||
|
result.totalcount = fetchResult.totalcount;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all([offlinePromise, ratingsPromise, fetchPromise]).then(() => {
|
||||||
|
// Apply offline actions to online and offline entries.
|
||||||
|
const promises = [];
|
||||||
|
result.entries.forEach((entry) => {
|
||||||
|
promises.push(this.applyOfflineActions(entry, offlineActions[entry.id] || [], fields));
|
||||||
|
});
|
||||||
|
result.offlineEntries.forEach((entry) => {
|
||||||
|
promises.push(this.applyOfflineActions(entry, offlineActions[entry.id] || [], fields));
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
|
}).then(() => {
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch an online or offline entry.
|
||||||
|
*
|
||||||
|
* @param {any} data Database.
|
||||||
|
* @param {any[]} fields List of database fields.
|
||||||
|
* @param {number} entryId Entry ID.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<{entry: AddonModDataEntry, ratinginfo?: CoreRatingInfo}>} Promise resolved with the entry.
|
||||||
|
*/
|
||||||
|
fetchEntry(data: any, fields: any[], entryId: number, siteId?: string):
|
||||||
|
Promise<{entry: AddonModDataEntry, ratinginfo?: CoreRatingInfo}> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
return this.dataOffline.getEntryActions(data.id, entryId, site.id).then((offlineActions) => {
|
||||||
|
let promise: Promise<{entry: AddonModDataEntry, ratinginfo?: CoreRatingInfo}>;
|
||||||
|
|
||||||
|
if (entryId > 0) {
|
||||||
|
// Online entry.
|
||||||
|
promise = this.dataProvider.getEntry(data.id, entryId, false, site.id);
|
||||||
|
} else {
|
||||||
|
// Offline entry or new entry.
|
||||||
|
promise = Promise.resolve({
|
||||||
|
entry: {
|
||||||
|
id: entryId,
|
||||||
|
userid: site.getUserId(),
|
||||||
|
groupid: 0,
|
||||||
|
dataid: data.id,
|
||||||
|
timecreated: -entryId,
|
||||||
|
timemodified: -entryId,
|
||||||
|
approved: !data.approval || data.manageapproved,
|
||||||
|
canmanageentry: true,
|
||||||
|
fullname: site.getInfo().fullname,
|
||||||
|
contents: [],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise.then((response) => {
|
||||||
|
return this.applyOfflineActions(response.entry, offlineActions, fields).then(() => {
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an object with all the actions that the user can do over the record.
|
* Returns an object with all the actions that the user can do over the record.
|
||||||
*
|
*
|
||||||
|
@ -352,45 +501,6 @@ export class AddonModDataHelperProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an online or offline entry.
|
|
||||||
*
|
|
||||||
* @param {any} data Database.
|
|
||||||
* @param {number} entryId Entry ID.
|
|
||||||
* @param {any} [offlineActions] Offline data with the actions done. Required for offline entries.
|
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
|
||||||
* @return {Promise<any>} Promise resolved with the entry.
|
|
||||||
*/
|
|
||||||
getEntry(data: any, entryId: number, offlineActions?: any, siteId?: string): Promise<any> {
|
|
||||||
if (entryId > 0) {
|
|
||||||
// It's an online entry, get it from WS.
|
|
||||||
return this.dataProvider.getEntry(data.id, entryId, false, siteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// It's an offline entry, search it in the offline actions.
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
|
||||||
const offlineEntry = offlineActions.find((offlineAction) => offlineAction.action == 'add');
|
|
||||||
|
|
||||||
if (offlineEntry) {
|
|
||||||
const siteInfo = site.getInfo();
|
|
||||||
|
|
||||||
return {entry: {
|
|
||||||
id: offlineEntry.entryid,
|
|
||||||
canmanageentry: true,
|
|
||||||
approved: !data.approval || data.manageapproved,
|
|
||||||
dataid: offlineEntry.dataid,
|
|
||||||
groupid: offlineEntry.groupid,
|
|
||||||
timecreated: -offlineEntry.entryid,
|
|
||||||
timemodified: -offlineEntry.entryid,
|
|
||||||
userid: siteInfo.userid,
|
|
||||||
fullname: siteInfo.fullname,
|
|
||||||
contents: {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of stored attachment files for a new entry. See $mmaModDataHelper#storeFiles.
|
* Get a list of stored attachment files for a new entry. See $mmaModDataHelper#storeFiles.
|
||||||
*
|
*
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
|
import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreFileProvider } from '@providers/file';
|
import { CoreFileProvider } from '@providers/file';
|
||||||
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
||||||
import { SQLiteDB } from '@classes/sqlitedb';
|
import { SQLiteDB } from '@classes/sqlitedb';
|
||||||
|
@ -101,7 +102,8 @@ export class AddonModDataOfflineProvider {
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider,
|
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider,
|
||||||
private fileProvider: CoreFileProvider, private fileUploaderProvider: CoreFileUploaderProvider) {
|
private fileProvider: CoreFileProvider, private fileUploaderProvider: CoreFileUploaderProvider,
|
||||||
|
private utils: CoreUtilsProvider) {
|
||||||
this.logger = logger.getInstance('AddonModDataOfflineProvider');
|
this.logger = logger.getInstance('AddonModDataOfflineProvider');
|
||||||
this.sitesProvider.registerSiteSchema(this.siteSchema);
|
this.sitesProvider.registerSiteSchema(this.siteSchema);
|
||||||
}
|
}
|
||||||
|
@ -201,7 +203,7 @@ export class AddonModDataOfflineProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the stored entry data from a certain database.
|
* Get all the stored entry actions from a certain database, sorted by modification time.
|
||||||
*
|
*
|
||||||
* @param {number} dataId Database ID.
|
* @param {number} dataId Database ID.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
@ -209,7 +211,7 @@ export class AddonModDataOfflineProvider {
|
||||||
*/
|
*/
|
||||||
getDatabaseEntries(dataId: number, siteId?: string): Promise<AddonModDataOfflineAction[]> {
|
getDatabaseEntries(dataId: number, siteId?: string): Promise<AddonModDataOfflineAction[]> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
return site.getDb().getRecords(AddonModDataOfflineProvider.DATA_ENTRY_TABLE, {dataid: dataId});
|
return site.getDb().getRecords(AddonModDataOfflineProvider.DATA_ENTRY_TABLE, {dataid: dataId}, 'timemodified');
|
||||||
}).then((entries) => {
|
}).then((entries) => {
|
||||||
return entries.map(this.parseRecord.bind(this));
|
return entries.map(this.parseRecord.bind(this));
|
||||||
});
|
});
|
||||||
|
@ -257,11 +259,10 @@ export class AddonModDataOfflineProvider {
|
||||||
* @return {Promise<any>} Promise resolved with boolean: true if has offline answers, false otherwise.
|
* @return {Promise<any>} Promise resolved with boolean: true if has offline answers, false otherwise.
|
||||||
*/
|
*/
|
||||||
hasOfflineData(dataId: number, siteId?: string): Promise<any> {
|
hasOfflineData(dataId: number, siteId?: string): Promise<any> {
|
||||||
return this.getDatabaseEntries(dataId, siteId).then((entries) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
return !!entries.length;
|
return this.utils.promiseWorks(
|
||||||
}).catch(() => {
|
site.getDb().recordExists(AddonModDataOfflineProvider.DATA_ENTRY_TABLE, {dataid: dataId})
|
||||||
// No offline data found, return false.
|
);
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue