MOBILE-2856 data: Interfaces for WS and offline data

main
Albert Gasset 2019-04-10 16:28:25 +02:00
parent 9892a17849
commit affe05a9d5
8 changed files with 193 additions and 101 deletions

View File

@ -327,9 +327,6 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
}); });
entries.entries.forEach((entry) => { entries.entries.forEach((entry) => {
// Index contents by fieldid.
entry.contents = this.utils.arrayToObject(entry.contents, 'fieldid');
if (typeof this.offlineActions[entry.id] != 'undefined') { if (typeof this.offlineActions[entry.id] != 'undefined') {
promises.push(this.dataHelper.applyOfflineActions(entry, this.offlineActions[entry.id], this.fieldsArray)); promises.push(this.dataHelper.applyOfflineActions(entry, this.offlineActions[entry.id], this.fieldsArray));
} else { } else {

View File

@ -158,9 +158,6 @@ export class AddonModDataEditPage {
}).then((entry) => { }).then((entry) => {
if (entry) { if (entry) {
entry = entry.entry; entry = entry.entry;
// Index contents by fieldid.
entry.contents = this.utils.arrayToObject(entry.contents, 'fieldid');
} else { } else {
entry = { entry = {
contents: {} contents: {}

View File

@ -171,9 +171,6 @@ export class AddonModDataEntryPage implements OnDestroy {
this.ratingInfo = entry.ratinginfo; this.ratingInfo = entry.ratinginfo;
entry = entry.entry; entry = entry.entry;
// Index contents by fieldid.
entry.contents = this.utils.arrayToObject(entry.contents, 'fieldid');
fieldsArray = this.utils.objectToArray(this.fields); fieldsArray = this.utils.objectToArray(this.fields);
return this.dataHelper.applyOfflineActions(entry, this.offlineActions, fieldsArray); return this.dataHelper.applyOfflineActions(entry, this.offlineActions, fieldsArray);

View File

@ -21,6 +21,67 @@ import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper'; import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
import { AddonModDataOfflineProvider } from './offline'; import { AddonModDataOfflineProvider } from './offline';
import { AddonModDataFieldsDelegate } from './fields-delegate'; import { AddonModDataFieldsDelegate } from './fields-delegate';
import { CoreRatingInfo } from '@core/rating/providers/rating';
/**
* Database entry (online or offline).
*/
export interface AddonModDataEntry {
id: number; // Negative for offline entries.
userid: number;
groupid: number;
dataid: number;
timecreated: number;
timemodified: number;
approved: boolean;
canmanageentry: boolean;
fullname: string;
contents: AddonModDataEntryFields;
deleted?: boolean; // Entry is deleted offline.
hasOffline?: boolean; // Entry has offline actions.
}
/**
* Entry field content.
*/
export interface AddonModDataEntryField {
fieldid: number;
content: string;
content1: string;
content2: string;
content3: string;
content4: string;
files: any[];
}
/**
* Entry contents indexed by field id.
*/
export interface AddonModDataEntryFields {
[fieldid: number]: AddonModDataEntryField;
}
/**
* List of entries returned by web service and helper functions.
*/
export interface AddonModDataEntries {
entries: AddonModDataEntry[]; // Online entries.
totalcount: number; // Total count of online entries or found entries.
maxcount?: number; // Total count of online entries. Only returned when searching.
offlineEntries?: AddonModDataEntry[]; // Offline entries.
hasOfflineActions?: boolean; // Whether the database has offline data.
hasOfflineRatings?: boolean; // Whether the database has offline ratings.
}
/**
* Subfield form data.
*/
export interface AddonModDataSubfieldData {
fieldid: number;
subfield?: string;
value?: string; // Value encoded in JSON.
files?: any[];
}
/** /**
* Service that provides some features for databases. * Service that provides some features for databases.
@ -49,13 +110,13 @@ export class AddonModDataProvider {
* @param {number} courseId Course ID. * @param {number} courseId Course ID.
* @param {any} contents The fields data to be created. * @param {any} contents The fields data to be created.
* @param {number} [groupId] Group id, 0 means that the function will determine the user group. * @param {number} [groupId] Group id, 0 means that the function will determine the user group.
* @param {any} fields The fields that define the contents. * @param {any[]} fields The fields that define the contents.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @param {boolean} [forceOffline] Force editing entry in offline. * @param {boolean} [forceOffline] Force editing entry in offline.
* @return {Promise<any>} Promise resolved when the action is done. * @return {Promise<any>} Promise resolved when the action is done.
*/ */
addEntry(dataId: number, entryId: number, courseId: number, contents: any, groupId: number = 0, fields: any, siteId?: string, addEntry(dataId: number, entryId: number, courseId: number, contents: AddonModDataSubfieldData[], groupId: number = 0,
forceOffline: boolean = false): Promise<any> { fields: any, siteId?: string, forceOffline: boolean = false): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
// Convenience function to store a data to be synchronized later. // Convenience function to store a data to be synchronized later.
@ -93,12 +154,12 @@ export class AddonModDataProvider {
* Adds a new entry to a database. It does not cache calls. It will fail if offline or cannot connect. * Adds a new entry to a database. It does not cache calls. It will fail if offline or cannot connect.
* *
* @param {number} dataId Database ID. * @param {number} dataId Database ID.
* @param {any} data The fields data to be created. * @param {any[]} data The fields data to be created.
* @param {number} [groupId] Group id, 0 means that the function will determine the user group. * @param {number} [groupId] Group id, 0 means that the function will determine the user group.
* @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 when the action is done. * @return {Promise<any>} Promise resolved when the action is done.
*/ */
addEntryOnline(dataId: number, data: any, groupId?: number, siteId?: string): Promise<any> { addEntryOnline(dataId: number, data: AddonModDataSubfieldData[], groupId?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
const params = { const params = {
databaseid: dataId, databaseid: dataId,
@ -184,7 +245,7 @@ export class AddonModDataProvider {
* @param {any} contents The contents data of the fields. * @param {any} contents The contents data of the fields.
* @return {any} Array of notifications if any or false. * @return {any} Array of notifications if any or false.
*/ */
protected checkFields(fields: any, contents: any): any { protected checkFields(fields: any, contents: AddonModDataSubfieldData[]): any[] | false {
const notifications = [], const notifications = [],
contentsIndexed = {}; contentsIndexed = {};
@ -289,13 +350,13 @@ export class AddonModDataProvider {
* @param {number} dataId Database ID. * @param {number} dataId Database ID.
* @param {number} entryId Entry ID. * @param {number} entryId Entry ID.
* @param {number} courseId Course ID. * @param {number} courseId Course ID.
* @param {any} contents The contents data to be updated. * @param {any[]} contents The contents data to be updated.
* @param {any} fields The fields that define the contents. * @param {any} fields The fields that define the contents.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @param {boolean} forceOffline Force editing entry in offline. * @param {boolean} forceOffline Force editing entry in offline.
* @return {Promise<any>} Promise resolved when the action is done. * @return {Promise<any>} Promise resolved when the action is done.
*/ */
editEntry(dataId: number, entryId: number, courseId: number, contents: any, fields: any, siteId?: string, editEntry(dataId: number, entryId: number, courseId: number, contents: AddonModDataSubfieldData[], fields: any, siteId?: string,
forceOffline: boolean = false): Promise<any> { forceOffline: boolean = false): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
@ -370,11 +431,11 @@ export class AddonModDataProvider {
* Updates an existing entry. It does not cache calls. It will fail if offline or cannot connect. * Updates an existing entry. It does not cache calls. It will fail if offline or cannot connect.
* *
* @param {number} entryId Entry ID. * @param {number} entryId Entry ID.
* @param {any} data The fields data to be updated. * @param {any[]} data The fields data to be updated.
* @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 when the action is done. * @return {Promise<any>} Promise resolved when the action is done.
*/ */
editEntryOnline(entryId: number, data: number, siteId?: string): Promise<any> { editEntryOnline(entryId: number, data: AddonModDataSubfieldData[], siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
const params = { const params = {
entryid: entryId, entryid: entryId,
@ -397,11 +458,11 @@ export class AddonModDataProvider {
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. * @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
* @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 when done. * @return {Promise<AddonModDataEntry[]>} Promise resolved when done.
*/ */
fetchAllEntries(dataId: number, groupId: number = 0, sort: string = '0', order: string = 'DESC', fetchAllEntries(dataId: number, groupId: number = 0, sort: string = '0', order: string = 'DESC',
perPage: number = AddonModDataProvider.PER_PAGE, forceCache: boolean = false, ignoreCache: boolean = false, perPage: number = AddonModDataProvider.PER_PAGE, forceCache: boolean = false, ignoreCache: boolean = false,
siteId?: string): Promise<any> { siteId?: string): Promise<AddonModDataEntry[]> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, [], 0, siteId); return this.fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, [], 0, siteId);
@ -420,10 +481,10 @@ export class AddonModDataProvider {
* @param {any} entries Entries already fetch (just to concatenate them). * @param {any} entries Entries already fetch (just to concatenate them).
* @param {number} page Page of records to return. * @param {number} page Page of records to return.
* @param {string} siteId Site ID. * @param {string} siteId Site ID.
* @return {Promise<any>} Promise resolved when done. * @return {Promise<AddonModDataEntry[]>} Promise resolved when done.
*/ */
protected fetchEntriesRecursive(dataId: number, groupId: number, sort: string, order: string, perPage: number, protected fetchEntriesRecursive(dataId: number, groupId: number, sort: string, order: string, perPage: number,
forceCache: boolean, ignoreCache: boolean, entries: any, page: number, siteId: string): Promise<any> { forceCache: boolean, ignoreCache: boolean, entries: any, page: number, siteId: string): Promise<AddonModDataEntry[]> {
return this.getEntries(dataId, groupId, sort, order, page, perPage, forceCache, ignoreCache, siteId) return this.getEntries(dataId, groupId, sort, order, page, perPage, forceCache, ignoreCache, siteId)
.then((result) => { .then((result) => {
entries = entries.concat(result.entries); entries = entries.concat(result.entries);
@ -595,11 +656,11 @@ export class AddonModDataProvider {
* @param {boolean} [forceCache=false] True to always get the value from cache, false otherwise. Default false. * @param {boolean} [forceCache=false] True to always get the value from cache, false otherwise. Default false.
* @param {boolean} [ignoreCache=false] True if it should ignore cached data (it'll always fail in offline or server down). * @param {boolean} [ignoreCache=false] True if it should ignore cached data (it'll always fail in offline or server down).
* @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 when the database is retrieved. * @return {Promise<AddonModDataEntries>} Promise resolved when the database is retrieved.
*/ */
getEntries(dataId: number, groupId: number = 0, sort: string = '0', order: string = 'DESC', page: number = 0, getEntries(dataId: number, groupId: number = 0, sort: string = '0', order: string = 'DESC', page: number = 0,
perPage: number = AddonModDataProvider.PER_PAGE, forceCache: boolean = false, ignoreCache: boolean = false, perPage: number = AddonModDataProvider.PER_PAGE, forceCache: boolean = false, ignoreCache: boolean = false,
siteId?: string): Promise<any> { siteId?: string): Promise<AddonModDataEntries> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
// Always use sort and order params to improve cache usage (entries are identified by params). // Always use sort and order params to improve cache usage (entries are identified by params).
const params = { const params = {
@ -622,7 +683,13 @@ export class AddonModDataProvider {
preSets['emergencyCache'] = false; preSets['emergencyCache'] = false;
} }
return site.read('mod_data_get_entries', params, preSets); return site.read('mod_data_get_entries', params, preSets).then((response) => {
response.entries.forEach((entry) => {
entry.contents = this.utils.arrayToObject(entry.contents, 'fieldid');
});
return response;
});
}); });
} }
@ -654,9 +721,10 @@ export class AddonModDataProvider {
* @param {number} entryId Entry ID. * @param {number} entryId Entry ID.
* @param {boolean} [ignoreCache=false] True if it should ignore cached data (it'll always fail in offline or server down). * @param {boolean} [ignoreCache=false] True if it should ignore cached data (it'll always fail in offline or server down).
* @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 when the database entry is retrieved. * @return {Promise<{entry: AddonModDataEntry, ratinginfo: CoreRatingInfo}>} Promise resolved when the entry is retrieved.
*/ */
getEntry(dataId: number, entryId: number, ignoreCache: boolean = false, siteId?: string): Promise<any> { getEntry(dataId: number, entryId: number, ignoreCache: boolean = false, siteId?: string):
Promise<{entry: AddonModDataEntry, ratinginfo: CoreRatingInfo}> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
const params = { const params = {
entryid: entryId, entryid: entryId,
@ -671,7 +739,11 @@ export class AddonModDataProvider {
preSets['emergencyCache'] = false; preSets['emergencyCache'] = false;
} }
return site.read('mod_data_get_entry', params, preSets); return site.read('mod_data_get_entry', params, preSets).then((response) => {
response.entry.contents = this.utils.arrayToObject(response.entry.contents, 'fieldid');
return response;
});
}); });
} }
@ -871,16 +943,16 @@ export class AddonModDataProvider {
* @param {number} dataId The data instance id. * @param {number} dataId The data instance id.
* @param {number} [groupId=0] Group id, 0 means that the function will determine the user group. * @param {number} [groupId=0] Group id, 0 means that the function will determine the user group.
* @param {string} [search] Search text. It will be used if advSearch is not defined. * @param {string} [search] Search text. It will be used if advSearch is not defined.
* @param {any} [advSearch] Advanced search data. * @param {any[]} [advSearch] Advanced search data.
* @param {string} [sort] Sort by this field. * @param {string} [sort] Sort by this field.
* @param {string} [order] The direction of the sorting. * @param {string} [order] The direction of the sorting.
* @param {number} [page=0] Page of records to return. * @param {number} [page=0] Page of records to return.
* @param {number} [perPage=PER_PAGE] Records per page to return. Default on AddonModDataProvider.PER_PAGE. * @param {number} [perPage=PER_PAGE] Records per page to return. Default on AddonModDataProvider.PER_PAGE.
* @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 when the action is done. * @return {Promise<AddonModDataEntries>} Promise resolved when the action is done.
*/ */
searchEntries(dataId: number, groupId: number = 0, search?: string, advSearch?: any, sort?: string, order?: string, searchEntries(dataId: number, groupId: number = 0, search?: string, advSearch?: any, sort?: string, order?: string,
page: number = 0, perPage: number = AddonModDataProvider.PER_PAGE, siteId?: string): Promise<any> { page: number = 0, perPage: number = AddonModDataProvider.PER_PAGE, siteId?: string): Promise<AddonModDataEntries> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
const params = { const params = {
databaseid: dataId, databaseid: dataId,
@ -911,7 +983,13 @@ export class AddonModDataProvider {
params['advsearch'] = advSearch; params['advsearch'] = advSearch;
} }
return site.read('mod_data_search_entries', params, preSets); return site.read('mod_data_search_entries', params, preSets).then((response) => {
response.entries.forEach((entry) => {
entry.contents = this.utils.arrayToObject(entry.contents, 'fieldid');
});
return response;
});
}); });
} }
} }

View File

@ -18,8 +18,8 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; 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 } from './offline'; import { AddonModDataOfflineProvider, AddonModDataOfflineAction } from './offline';
import { AddonModDataProvider } from './data'; import { AddonModDataProvider, AddonModDataEntry, AddonModDataEntryFields } from './data';
/** /**
* Service that provides helper functions for datas. * Service that provides helper functions for datas.
@ -35,15 +35,19 @@ export class AddonModDataHelperProvider {
/** /**
* Returns the record with the offline actions applied. * Returns the record with the offline actions applied.
* *
* @param {any} record Entry to modify. * @param {AddonModDataEntry} record Entry to modify.
* @param {any} offlineActions Offline data with the actions done. * @param {AddonModDataOfflineAction[]} offlineActions Offline data with the actions done.
* @param {any} fields Entry defined fields indexed by fieldid. * @param {any[]} fields Entry defined fields indexed by fieldid.
* @return {any} Modified entry. * @return {Promise<AddonModDataEntry>} Promise resolved when done.
*/ */
applyOfflineActions(record: any, offlineActions: any[], fields: any[]): any { applyOfflineActions(record: AddonModDataEntry, offlineActions: AddonModDataOfflineAction[], fields: any[]):
Promise<AddonModDataEntry> {
const promises = []; const promises = [];
offlineActions.forEach((action) => { offlineActions.forEach((action) => {
record.timemodified = action.timemodified;
record.hasOffline = true;
switch (action.action) { switch (action.action) {
case 'approve': case 'approve':
record.approved = true; record.approved = true;
@ -56,6 +60,8 @@ export class AddonModDataHelperProvider {
break; break;
case 'add': case 'add':
case 'edit': case 'edit':
record.groupid = action.groupid;
const offlineContents = {}; const offlineContents = {};
action.fields.forEach((offlineContent) => { action.fields.forEach((offlineContent) => {
@ -77,10 +83,12 @@ export class AddonModDataHelperProvider {
promises.push(this.getStoredFiles(record.dataid, record.id, field.id).then((offlineFiles) => { promises.push(this.getStoredFiles(record.dataid, record.id, field.id).then((offlineFiles) => {
record.contents[field.id] = this.fieldsDelegate.overrideData(field, record.contents[field.id], record.contents[field.id] = this.fieldsDelegate.overrideData(field, record.contents[field.id],
offlineContents[field.id], offlineFiles); offlineContents[field.id], offlineFiles);
record.contents[field.id].fieldid = field.id;
})); }));
} else { } else {
record.contents[field.id] = this.fieldsDelegate.overrideData(field, record.contents[field.id], record.contents[field.id] = this.fieldsDelegate.overrideData(field, record.contents[field.id],
offlineContents[field.id]); offlineContents[field.id]);
record.contents[field.id].fieldid = field.id;
} }
}); });
break; break;
@ -102,10 +110,11 @@ export class AddonModDataHelperProvider {
* @param {any} entry Entry. * @param {any} entry Entry.
* @param {number} offset Entry offset. * @param {number} offset Entry offset.
* @param {string} mode Mode list or show. * @param {string} mode Mode list or show.
* @param {any} actions Actions that can be performed to the record. * @param {AddonModDataOfflineAction[]} actions Actions that can be performed to the record.
* @return {string} Generated HTML. * @return {string} Generated HTML.
*/ */
displayShowFields(template: string, fields: any[], entry: any, offset: number, mode: string, actions: any): string { displayShowFields(template: string, fields: any[], entry: any, offset: number, mode: string,
actions: AddonModDataOfflineAction[]): string {
if (!template) { if (!template) {
return ''; return '';
} }
@ -260,13 +269,13 @@ export class AddonModDataHelperProvider {
* @param {Array} fields Fields that defines every content in the entry. * @param {Array} fields Fields that defines every content in the entry.
* @param {number} [dataId] Database Id. If set, files will be uploaded and itemId set. * @param {number} [dataId] Database Id. If set, files will be uploaded and itemId set.
* @param {number} entryId Entry Id. * @param {number} entryId Entry Id.
* @param {any} entryContents Original entry contents indexed by field id. * @param {AddonModDataEntryFields} entryContents Original entry contents.
* @param {boolean} offline True to prepare the data for an offline uploading, false otherwise. * @param {boolean} offline True to prepare the data for an offline uploading, false otherwise.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} That contains object with the answers. * @return {Promise<any>} That contains object with the answers.
*/ */
getEditDataFromForm(inputData: any, fields: any, dataId: number, entryId: number, entryContents: any, offline: boolean = false, getEditDataFromForm(inputData: any, fields: any, dataId: number, entryId: number, entryContents: AddonModDataEntryFields,
siteId?: string): Promise<any> { offline: boolean = false, siteId?: string): Promise<any> {
if (!inputData) { if (!inputData) {
return Promise.resolve({}); return Promise.resolve({});
} }
@ -323,12 +332,12 @@ export class AddonModDataHelperProvider {
* Retrieve the temp files to be updated. * Retrieve the temp files to be updated.
* *
* @param {any} inputData Array with the entered form values. * @param {any} inputData Array with the entered form values.
* @param {Array} fields Fields that defines every content in the entry. * @param {any[]} fields Fields that defines every content in the entry.
* @param {number} [dataId] Database Id. If set, fils will be uploaded and itemId set. * @param {number} [dataId] Database Id. If set, fils will be uploaded and itemId set.
* @param {any} entryContents Original entry contents indexed by field id. * @param {AddonModDataEntryFields} entryContents Original entry contents indexed by field id.
* @return {Promise<any>} That contains object with the files. * @return {Promise<any>} That contains object with the files.
*/ */
getEditTmpFiles(inputData: any, fields: any, dataId: number, entryContents: any): Promise<any> { getEditTmpFiles(inputData: any, fields: any[], dataId: number, entryContents: AddonModDataEntryFields): Promise<any> {
if (!inputData) { if (!inputData) {
return Promise.resolve([]); return Promise.resolve([]);
} }
@ -403,13 +412,13 @@ export class AddonModDataHelperProvider {
/** /**
* Check if data has been changed by the user. * Check if data has been changed by the user.
* *
* @param {any} inputData Array with the entered form values. * @param {any} inputData Object with the entered form values.
* @param {any} fields Fields that defines every content in the entry. * @param {any[]} fields Fields that defines every content in the entry.
* @param {number} [dataId] Database Id. If set, fils will be uploaded and itemId set. * @param {number} [dataId] Database Id. If set, fils will be uploaded and itemId set.
* @param {any} entryContents Original entry contents indexed by field id. * @param {AddonModDataEntryFields} entryContents Original entry contents indexed by field id.
* @return {Promise<boolean>} True if changed, false if not. * @return {Promise<boolean>} True if changed, false if not.
*/ */
hasEditDataChanged(inputData: any, fields: any, dataId: number, entryContents: any): Promise<boolean> { hasEditDataChanged(inputData: any, fields: any[], dataId: number, entryContents: AddonModDataEntryFields): Promise<boolean> {
const promises = fields.map((field) => { const promises = fields.map((field) => {
return this.fieldsDelegate.hasFieldDataChanged(field, inputData, entryContents[field.id]); return this.fieldsDelegate.hasFieldDataChanged(field, inputData, entryContents[field.id]);
}); });

View File

@ -19,6 +19,20 @@ import { CoreTextUtilsProvider } from '@providers/utils/text';
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';
import { AddonModDataSubfieldData } from './data';
/**
* Entry action stored offline.
*/
export interface AddonModDataOfflineAction {
dataid: number;
courseid: number;
groupid: number;
action: string;
entryid: number; // Negative for offline entries.
fields: AddonModDataSubfieldData[];
timemodified: number;
}
/** /**
* Service to handle Offline data. * Service to handle Offline data.
@ -176,9 +190,9 @@ export class AddonModDataOfflineProvider {
* Get all the stored entry data from all the databases. * Get all the stored entry data from all the databases.
* *
* @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 entries. * @return {Promise<AddonModDataOfflineAction[]>} Promise resolved with entries.
*/ */
getAllEntries(siteId?: string): Promise<any> { getAllEntries(siteId?: string): Promise<AddonModDataOfflineAction[]> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
return site.getDb().getAllRecords(AddonModDataOfflineProvider.DATA_ENTRY_TABLE); return site.getDb().getAllRecords(AddonModDataOfflineProvider.DATA_ENTRY_TABLE);
}).then((entries) => { }).then((entries) => {
@ -191,9 +205,9 @@ export class AddonModDataOfflineProvider {
* *
* @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.
* @return {Promise<any>} Promise resolved with entries. * @return {Promise<AddonModDataOfflineAction[]>} Promise resolved with entries.
*/ */
getDatabaseEntries(dataId: number, siteId?: string): Promise<any> { 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});
}).then((entries) => { }).then((entries) => {
@ -208,9 +222,9 @@ export class AddonModDataOfflineProvider {
* @param {number} entryId Database entry Id. * @param {number} entryId Database entry Id.
* @param {string} action Action to be done * @param {string} action Action to be done
* @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 entry. * @return {Promise<AddonModDataOfflineAction>} Promise resolved with entry.
*/ */
getEntry(dataId: number, entryId: number, action: string, siteId?: string): Promise<any> { getEntry(dataId: number, entryId: number, action: string, siteId?: string): Promise<AddonModDataOfflineAction> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
return site.getDb().getRecord(AddonModDataOfflineProvider.DATA_ENTRY_TABLE, {dataid: dataId, entryid: entryId, return site.getDb().getRecord(AddonModDataOfflineProvider.DATA_ENTRY_TABLE, {dataid: dataId, entryid: entryId,
action: action}); action: action});
@ -225,9 +239,9 @@ export class AddonModDataOfflineProvider {
* @param {number} dataId Database ID. * @param {number} dataId Database ID.
* @param {number} entryId Database entry Id. * @param {number} entryId Database entry Id.
* @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 entry actions. * @return {Promise<AddonModDataOfflineAction[]>} Promise resolved with entry actions.
*/ */
getEntryActions(dataId: number, entryId: number, siteId?: string): Promise<any> { getEntryActions(dataId: number, entryId: 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, entryid: entryId}); return site.getDb().getRecords(AddonModDataOfflineProvider.DATA_ENTRY_TABLE, {dataid: dataId, entryid: entryId});
}).then((entries) => { }).then((entries) => {
@ -287,9 +301,9 @@ export class AddonModDataOfflineProvider {
* Parse "fields" of an offline record. * Parse "fields" of an offline record.
* *
* @param {any} record Record object * @param {any} record Record object
* @return {any} Record object with columns parsed. * @return {AddonModDataOfflineAction} Record object with columns parsed.
*/ */
protected parseRecord(record: any): any { protected parseRecord(record: any): AddonModDataOfflineAction {
record.fields = this.textUtils.parseJSON(record.fields); record.fields = this.textUtils.parseJSON(record.fields);
return record; return record;
@ -308,8 +322,8 @@ export class AddonModDataOfflineProvider {
* @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 if stored, rejected if failure. * @return {Promise<any>} Promise resolved if stored, rejected if failure.
*/ */
saveEntry(dataId: number, entryId: number, action: string, courseId: number, groupId?: number, fields?: any[], saveEntry(dataId: number, entryId: number, action: string, courseId: number, groupId?: number,
timemodified?: number, siteId?: string): Promise<any> { fields?: AddonModDataSubfieldData[], timemodified?: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
timemodified = timemodified || new Date().getTime(); timemodified = timemodified || new Date().getTime();

View File

@ -25,7 +25,7 @@ import { CoreCommentsProvider } from '@core/comments/providers/comments';
import { CoreCourseProvider } from '@core/course/providers/course'; 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 { CoreRatingProvider } from '@core/rating/providers/rating'; import { CoreRatingProvider } from '@core/rating/providers/rating';
import { AddonModDataProvider } from './data'; import { AddonModDataProvider, AddonModDataEntry } from './data';
import { AddonModDataSyncProvider } from './sync'; import { AddonModDataSyncProvider } from './sync';
import { AddonModDataHelperProvider } from './helper'; import { AddonModDataHelperProvider } from './helper';
@ -57,10 +57,10 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. * @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). * @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
* @param {string} [siteId] Site ID. * @param {string} [siteId] Site ID.
* @return {Promise<any>} All unique entries. * @return {Promise<AddonModDataEntry[]>} All unique entries.
*/ */
protected getAllUniqueEntries(dataId: number, groups: any[], forceCache: boolean = false, ignoreCache: boolean = false, protected getAllUniqueEntries(dataId: number, groups: any[], forceCache: boolean = false, ignoreCache: boolean = false,
siteId?: string): Promise<any> { siteId?: string): Promise<AddonModDataEntry[]> {
const promises = groups.map((group) => { const promises = groups.map((group) => {
return this.dataProvider.fetchAllEntries(dataId, group.id, undefined, undefined, undefined, forceCache, ignoreCache, return this.dataProvider.fetchAllEntries(dataId, group.id, undefined, undefined, undefined, forceCache, ignoreCache,
siteId); siteId);
@ -139,14 +139,14 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
/** /**
* Returns the file contained in the entries. * Returns the file contained in the entries.
* *
* @param {any[]} entries List of entries to get files from. * @param {AddonModDataEntry[]} entries List of entries to get files from.
* @return {any[]} List of files. * @return {any[]} List of files.
*/ */
protected getEntriesFiles(entries: any[]): any[] { protected getEntriesFiles(entries: AddonModDataEntry[]): any[] {
let files = []; let files = [];
entries.forEach((entry) => { entries.forEach((entry) => {
entry.contents.forEach((content) => { this.utils.objectToArray(entry.contents).forEach((content) => {
files = files.concat(content.files); files = files.concat(content.files);
}); });
}); });

View File

@ -20,7 +20,7 @@ import { CoreAppProvider } from '@providers/app';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { AddonModDataOfflineProvider } from './offline'; import { AddonModDataOfflineProvider, AddonModDataOfflineAction } from './offline';
import { AddonModDataProvider } from './data'; import { AddonModDataProvider } from './data';
import { AddonModDataHelperProvider } from './helper'; import { AddonModDataHelperProvider } from './helper';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
@ -174,7 +174,7 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider {
// No offline data found, return empty object. // No offline data found, return empty object.
return []; return [];
}); });
}).then((offlineActions) => { }).then((offlineActions: AddonModDataOfflineAction[]) => {
if (!offlineActions.length) { if (!offlineActions.length) {
// Nothing to sync. // Nothing to sync.
return; return;
@ -227,12 +227,12 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider {
* Synchronize an entry. * Synchronize an entry.
* *
* @param {any} data Database. * @param {any} data Database.
* @param {any} entryActions Entry actions. * @param {AddonModDataOfflineAction[]} entryActions Entry actions.
* @param {any} result Object with the result of the sync. * @param {any} result Object with the result of the sync.
* @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 if success, rejected otherwise. * @return {Promise<any>} Promise resolved if success, rejected otherwise.
*/ */
protected syncEntry(data: any, entryActions: any[], result: any, siteId?: string): Promise<any> { protected syncEntry(data: any, entryActions: AddonModDataOfflineAction[], result: any, siteId?: string): Promise<any> {
let discardError, let discardError,
timePromise, timePromise,
entryId = 0, entryId = 0,