302 lines
12 KiB
TypeScript
Raw Normal View History

// (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 { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreAppProvider } from '@providers/app';
/**
* Helper to manage logging to Moodle.
*/
@Injectable()
export class CoreCourseLogHelperProvider {
// Variables for database.
static ACTIVITY_LOG_TABLE = 'course_activity_log';
protected siteSchema: CoreSiteSchema = {
name: 'CoreCourseOfflineProvider',
version: 1,
tables: [
{
name: CoreCourseLogHelperProvider.ACTIVITY_LOG_TABLE,
columns: [
{
name: 'component',
type: 'TEXT'
},
{
name: 'componentid',
type: 'INTEGER'
},
{
name: 'ws',
type: 'TEXT'
},
{
name: 'data',
type: 'TEXT'
},
{
name: 'time',
type: 'INTEGER'
}
],
primaryKeys: ['component', 'componentid', 'ws', 'time']
}
]
};
constructor(protected sitesProvider: CoreSitesProvider, protected timeUtils: CoreTimeUtilsProvider,
protected textUtils: CoreTextUtilsProvider, protected utils: CoreUtilsProvider,
protected appProvider: CoreAppProvider) {
this.sitesProvider.registerSiteSchema(this.siteSchema);
}
/**
* Delete the offline saved activity logs.
*
* @param {string} component Component name.
* @param {number} componentId Component ID.
2019-02-07 10:12:54 +01:00
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when deleted, rejected if failure.
*/
protected deleteLogs(component: string, componentId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.getDb().deleteRecords(CoreCourseLogHelperProvider.ACTIVITY_LOG_TABLE,
{component: component, componentid: componentId});
});
}
2019-02-07 10:12:54 +01:00
/**
* Delete a WS based log.
*
* @param {string} component Component name.
* @param {number} componentId Component ID.
* @param {string} ws WS name.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when deleted, rejected if failure.
*/
protected deleteWSLogsByComponent(component: string, componentId: number, ws: string, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.getDb().deleteRecords(CoreCourseLogHelperProvider.ACTIVITY_LOG_TABLE,
{component: component, componentid: componentId, ws: ws});
});
}
/**
* Delete the offline saved activity logs using call data.
*
* @param {string} ws WS name.
* @param {any} data Data to send to the WS.
2019-02-07 10:12:54 +01:00
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when deleted, rejected if failure.
*/
protected deleteWSLogs(ws: string, data: any, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.getDb().deleteRecords(CoreCourseLogHelperProvider.ACTIVITY_LOG_TABLE,
2019-02-07 10:12:54 +01:00
{ws: ws, data: this.utils.sortAndStringify(data)});
});
}
/**
* Get all the offline saved activity logs.
*
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any[]>} Promise resolved with the list of offline logs.
*/
protected getAllLogs(siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.getDb().getAllRecords(CoreCourseLogHelperProvider.ACTIVITY_LOG_TABLE);
});
}
/**
* Get the offline saved activity logs.
*
* @param {string} component Component name.
* @param {number} componentId Component ID.
2019-02-07 10:12:54 +01:00
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any[]>} Promise resolved with the list of offline logs.
*/
protected getLogs(component: string, componentId: number, siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.getDb().getRecords(CoreCourseLogHelperProvider.ACTIVITY_LOG_TABLE,
{component: component, componentid: componentId});
});
}
/**
* Perform log online. Data will be saved offline for syncing.
*
* @param {string} ws WS name.
* @param {any} data Data to send to the WS.
* @param {string} component Component name.
* @param {number} componentId Component ID.
2019-02-07 10:12:54 +01:00
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
log(ws: string, data: any, component: string, componentId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
if (!this.appProvider.isOnline()) {
// App is offline, store the action.
return this.storeOffline(ws, data, component, componentId, site.getId());
}
return this.logOnline(ws, data, site.getId()).catch((error) => {
if (this.utils.isWebServiceError(error)) {
// The WebService has thrown an error, this means that responses cannot be submitted.
return Promise.reject(error);
}
// Couldn't connect to server, store in offline.
return this.storeOffline(ws, data, component, componentId, site.getId());
});
});
}
/**
* Perform the log online.
*
2019-02-07 10:12:54 +01:00
* @param {string} ws WS name.
* @param {any} data Data to send to the WS.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when log is successfully submitted. Rejected with object containing
* the error message (if any) and a boolean indicating if the error was returned by WS.
*/
protected logOnline(ws: string, data: any, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
return site.write(ws, data).then((response) => {
if (!response.status) {
return Promise.reject(this.utils.createFakeWSError(''));
}
// Remove all the logs performed.
// TODO: Remove this lines when time is accepted in logs.
return this.deleteWSLogs(ws, data);
});
});
}
/**
* Save activity log for offline sync.
*
* @param {string} ws WS name.
* @param {any} data Data to send to the WS.
* @param {string} component Component name.
* @param {number} componentId Component ID.
2019-02-07 10:12:54 +01:00
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<number>} Resolved with the inserted rowId field.
*/
protected storeOffline(ws: string, data: any, component: string, componentId: number, siteId?: string):
Promise<number> {
return this.sitesProvider.getSite(siteId).then((site) => {
const log = {
ws: ws,
2019-02-07 10:12:54 +01:00
data: this.utils.sortAndStringify(data),
component: component,
componentid: componentId,
time: this.timeUtils.timestamp()
};
return site.getDb().insertRecord(CoreCourseLogHelperProvider.ACTIVITY_LOG_TABLE, log);
});
}
2019-02-07 10:12:54 +01:00
/**
* Sync all the offline saved activity logs.
*
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
syncAll(siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
const siteId = site.getId();
return this.getAllLogs(siteId).then((logs) => {
const unique = [];
// TODO: When time is accepted on log, do not discard same logs.
logs.forEach((log) => {
// Just perform unique syncs.
const found = unique.find((doneLog) => {
return log.component == doneLog.component && log.componentid == doneLog.componentid &&
log.ws == doneLog.ws && log.data == doneLog.data;
});
if (!found) {
unique.push(log);
}
});
return this.syncLogs(unique, siteId);
});
});
}
/**
* Sync the offline saved activity logs.
*
* @param {string} component Component name.
* @param {number} componentId Component ID.
2019-02-07 10:12:54 +01:00
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
syncIfNeeded(component: string, componentId: number, siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => {
const siteId = site.getId();
return this.getLogs(component, componentId, siteId).then((logs) => {
2019-02-07 10:12:54 +01:00
const unique = [];
// TODO: When time is accepted on log, do not discard same logs.
2019-02-07 10:12:54 +01:00
logs.forEach((log) => {
// Just perform unique syncs.
2019-02-07 10:12:54 +01:00
const found = unique.find((doneLog) => {
return log.ws == doneLog.ws && log.data == doneLog.data;
});
2019-02-07 10:12:54 +01:00
if (!found) {
unique.push(log);
}
2019-02-07 10:12:54 +01:00
});
2019-02-07 10:12:54 +01:00
return this.syncLogs(unique, siteId);
});
});
}
2019-02-07 10:12:54 +01:00
/**
* Sync and delete given logs.
*
* @param {any[]} logs Array of log objects.
* @param {string} siteId Site Id.
* @return {Promise<any>} Promise resolved when done.
*/
protected syncLogs(logs: any[], siteId: string): Promise<any> {
return Promise.all(logs.map((log) => {
return this.logOnline(log.ws, this.textUtils.parseJSON(log.data), siteId).then(() => {
return this.deleteWSLogsByComponent(log.component, log.componentid, log.ws);
});
}));
}
}