// (C) Copyright 2015 Martin Dougiamas // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { Injectable } from '@angular/core'; import { CoreLoggerProvider } from '@providers/logger'; import { CoreSitesProvider } from '@providers/sites'; import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreFileProvider } from '@providers/file'; /** * Service to handle Offline data. */ @Injectable() export class AddonModDataOfflineProvider { protected logger; // Variables for database. protected DATA_ENTRY_TABLE = 'addon_mod_data_entry'; protected tablesSchema = [ { name: this.DATA_ENTRY_TABLE, columns: [ { name: 'dataid', type: 'INTEGER' }, { name: 'courseid', type: 'INTEGER' }, { name: 'groupid', type: 'INTEGER' }, { name: 'action', type: 'TEXT' }, { name: 'entryid', type: 'INTEGER' }, { name: 'fields', type: 'TEXT' }, { name: 'timemodified', type: 'INTEGER' } ], primaryKeys: ['dataid', 'entryid'] } ]; constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider, private fileProvider: CoreFileProvider) { this.logger = logger.getInstance('AddonModDataOfflineProvider'); this.sitesProvider.createTablesFromSchema(this.tablesSchema); } /** * Delete all the actions of an entry. * * @param {number} dataId Database ID. * @param {number} entryId Database entry ID. * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved if deleted, rejected if failure. */ deleteAllEntryActions(dataId: number, entryId: number, siteId?: string): Promise { return this.getEntryActions(dataId, entryId, siteId).then((actions) => { const promises = []; actions.forEach((action) => { promises.push(this.deleteEntry(dataId, entryId, action.action, siteId)); }); return Promise.all(promises); }); } /** * Delete an stored entry. * * @param {number} dataId Database ID. * @param {number} entryId Database entry Id. * @param {string} action Action to be done * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved if deleted, rejected if failure. */ deleteEntry(dataId: number, entryId: number, action: string, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { return site.getDb().deleteRecords(this.DATA_ENTRY_TABLE, {dataid: dataId, entryid: entryId, action: action}); }); } /** * Get all the stored entry data from all the databases. * * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved with entries. */ getAllEntries(siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { return site.getDb().getAllRecords(this.DATA_ENTRY_TABLE); }); } /** * Get all the stored entry data from a certain database. * * @param {number} dataId Database ID. * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved with entries. */ getDatabaseEntries(dataId: number, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { return site.getDb().getRecords(this.DATA_ENTRY_TABLE, {dataid: dataId}); }); } /** * Get an stored entry data. * * @param {number} dataId Database ID. * @param {number} entryId Database entry Id. * @param {string} action Action to be done * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved with entry. */ getEntry(dataId: number, entryId: number, action: string, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { return site.getDb().getRecord(this.DATA_ENTRY_TABLE, {dataid: dataId, entryid: entryId, action: action}); }); } /** * Get an all stored entry actions data. * * @param {number} dataId Database ID. * @param {number} entryId Database entry Id. * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved with entry actions. */ getEntryActions(dataId: number, entryId: number, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { return site.getDb().getRecords(this.DATA_ENTRY_TABLE, {dataid: dataId, entryid: entryId}); }); } /** * Check if there are offline entries to send. * * @param {number} dataId Database ID. * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved with boolean: true if has offline answers, false otherwise. */ hasOfflineData(dataId: number, siteId?: string): Promise { return this.getDatabaseEntries(dataId, siteId).then((entries) => { return !!entries.length; }).catch(() => { // No offline data found, return false. return false; }); } /** * Get the path to the folder where to store files for offline files in a database. * * @param {number} dataId Database ID. * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved with the path. */ protected getDatabaseFolder(dataId: number, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { const siteFolderPath = this.fileProvider.getSiteFolder(site.getId()), folderPath = 'offlinedatabase/' + dataId; return this.textUtils.concatenatePaths(siteFolderPath, folderPath); }); } /** * Get the path to the folder where to store files for a new offline entry. * * @param {number} dataId Database ID. * @param {number} entryId The ID of the entry. * @param {number} fieldId Field ID. * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved with the path. */ getEntryFieldFolder(dataId: number, entryId: number, fieldId: number, siteId?: string): Promise { return this.getDatabaseFolder(dataId, siteId).then((folderPath) => { return this.textUtils.concatenatePaths(folderPath, entryId + '_' + fieldId); }); } /** * Save an entry data to be sent later. * * @param {number} dataId Database ID. * @param {number} entryId Database entry Id. If action is add entryId should be 0 and -timemodified will be used. * @param {string} action Action to be done to the entry: [add, edit, delete, approve, disapprove] * @param {number} courseId Course ID of the database. * @param {number} [groupId] Group ID. Only provided when adding. * @param {any[]} [fields] Array of field data of the entry if needed. * @param {number} [timemodified] The time the entry was modified. If not defined, current time. * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved if stored, rejected if failure. */ saveEntry(dataId: number, entryId: number, action: string, courseId: number, groupId?: number, fields?: any[], timemodified?: number, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { timemodified = timemodified || new Date().getTime(); entryId = typeof entryId == 'undefined' || entryId === null ? -timemodified : entryId; const entry = { dataid: dataId, courseid: courseId, groupid: groupId, action: action, entryid: entryId, fields: fields, timemodified: timemodified }; return site.getDb().insertRecord(this.DATA_ENTRY_TABLE, entry); }); } }