MOBILE-3565 services: Move some DB vars and init to new files
parent
03f9723329
commit
6df1c2109d
|
@ -50,6 +50,11 @@ import { CoreTimeUtilsProvider } from '@services/utils/time';
|
||||||
import { CoreUrlUtilsProvider } from '@services/utils/url';
|
import { CoreUrlUtilsProvider } from '@services/utils/url';
|
||||||
import { CoreUtilsProvider } from '@services/utils/utils';
|
import { CoreUtilsProvider } from '@services/utils/utils';
|
||||||
|
|
||||||
|
// Import init DB functions of core services.
|
||||||
|
import { initCoreFilepoolDB } from '@services/filepool.db';
|
||||||
|
import { initCoreSitesDB } from '@services/sites.db';
|
||||||
|
import { initCoreSyncDB } from '@services/sync.db';
|
||||||
|
|
||||||
// Import core modules.
|
// Import core modules.
|
||||||
import { CoreEmulatorModule } from '@core/emulator/emulator.module';
|
import { CoreEmulatorModule } from '@core/emulator/emulator.module';
|
||||||
import { CoreLoginModule } from '@core/login/login.module';
|
import { CoreLoginModule } from '@core/login/login.module';
|
||||||
|
@ -121,6 +126,8 @@ export class AppModule {
|
||||||
// Set the injector.
|
// Set the injector.
|
||||||
setSingletonsInjector(injector);
|
setSingletonsInjector(injector);
|
||||||
|
|
||||||
|
this.initCoreServicesDB();
|
||||||
|
|
||||||
// Register a handler for platform ready.
|
// Register a handler for platform ready.
|
||||||
CoreInit.instance.registerProcess({
|
CoreInit.instance.registerProcess({
|
||||||
name: 'CorePlatformReady',
|
name: 'CorePlatformReady',
|
||||||
|
@ -154,4 +161,13 @@ export class AppModule {
|
||||||
CoreInit.instance.executeInitProcesses();
|
CoreInit.instance.executeInitProcesses();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init the DB of core services.
|
||||||
|
*/
|
||||||
|
protected initCoreServicesDB(): void {
|
||||||
|
initCoreFilepoolDB();
|
||||||
|
initCoreSitesDB();
|
||||||
|
initCoreSyncDB();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import { CoreIonLoadingElement } from './ion-loading';
|
||||||
/**
|
/**
|
||||||
* Class that represents a site (combination of site + user).
|
* Class that represents a site (combination of site + user).
|
||||||
* It will have all the site data and provide utility functions regarding a site.
|
* It will have all the site data and provide utility functions regarding a site.
|
||||||
* To add tables to the site's database, please use CoreSitesProvider.registerSiteSchema. This will make sure that
|
* To add tables to the site's database, please use registerSiteSchema exported in @services/sites.ts. This will make sure that
|
||||||
* the tables are created in all the sites, not just the current one.
|
* the tables are created in all the sites, not just the current one.
|
||||||
*
|
*
|
||||||
* @todo: Refactor this class to improve "temporary" sites support (not fully authenticated).
|
* @todo: Refactor this class to improve "temporary" sites support (not fully authenticated).
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// 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 { SQLiteDBTableSchema } from '@classes/sqlitedb';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database variables for CoreApp service.
|
||||||
|
*/
|
||||||
|
export const DBNAME = 'MoodleMobile';
|
||||||
|
export const SCHEMA_VERSIONS_TABLE_NAME = 'schema_versions';
|
||||||
|
|
||||||
|
export const SCHEMA_VERSIONS_TABLE_SCHEMA: SQLiteDBTableSchema = {
|
||||||
|
name: SCHEMA_VERSIONS_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: 'TEXT',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'version',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SchemaVersionsDBEntry = {
|
||||||
|
name: string;
|
||||||
|
version: number;
|
||||||
|
};
|
|
@ -24,9 +24,7 @@ import { CoreConstants } from '@core/constants';
|
||||||
|
|
||||||
import { makeSingleton, Keyboard, Network, StatusBar, Platform } from '@singletons/core.singletons';
|
import { makeSingleton, Keyboard, Network, StatusBar, Platform } from '@singletons/core.singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
import { DBNAME, SCHEMA_VERSIONS_TABLE_NAME, SCHEMA_VERSIONS_TABLE_SCHEMA, SchemaVersionsDBEntry } from '@services/app.db';
|
||||||
const DBNAME = 'MoodleMobile';
|
|
||||||
const SCHEMA_VERSIONS_TABLE = 'schema_versions';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory to provide some global functionalities, like access to the global app database.
|
* Factory to provide some global functionalities, like access to the global app database.
|
||||||
|
@ -57,27 +55,13 @@ export class CoreAppProvider {
|
||||||
|
|
||||||
// Variables for DB.
|
// Variables for DB.
|
||||||
protected createVersionsTableReady: Promise<void>;
|
protected createVersionsTableReady: Promise<void>;
|
||||||
protected versionsTableSchema: SQLiteDBTableSchema = {
|
|
||||||
name: SCHEMA_VERSIONS_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
type: 'TEXT',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'version',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(appRef: ApplicationRef, zone: NgZone) {
|
constructor(appRef: ApplicationRef, zone: NgZone) {
|
||||||
this.logger = CoreLogger.getInstance('CoreAppProvider');
|
this.logger = CoreLogger.getInstance('CoreAppProvider');
|
||||||
this.db = CoreDB.instance.getDB(DBNAME);
|
this.db = CoreDB.instance.getDB(DBNAME);
|
||||||
|
|
||||||
// Create the schema versions table.
|
// Create the schema versions table.
|
||||||
this.createVersionsTableReady = this.db.createTableFromSchema(this.versionsTableSchema);
|
this.createVersionsTableReady = this.db.createTableFromSchema(SCHEMA_VERSIONS_TABLE_SCHEMA);
|
||||||
|
|
||||||
Keyboard.instance.onKeyboardShow().subscribe((data) => {
|
Keyboard.instance.onKeyboardShow().subscribe((data) => {
|
||||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||||
|
@ -175,7 +159,7 @@ export class CoreAppProvider {
|
||||||
await this.createVersionsTableReady;
|
await this.createVersionsTableReady;
|
||||||
|
|
||||||
// Fetch installed version of the schema.
|
// Fetch installed version of the schema.
|
||||||
const entry = await this.db.getRecord<SchemaVersionsDBEntry>(SCHEMA_VERSIONS_TABLE, { name: schema.name });
|
const entry = await this.db.getRecord<SchemaVersionsDBEntry>(SCHEMA_VERSIONS_TABLE_NAME, { name: schema.name });
|
||||||
|
|
||||||
oldVersion = entry.version;
|
oldVersion = entry.version;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -198,7 +182,7 @@ export class CoreAppProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set installed version.
|
// Set installed version.
|
||||||
await this.db.insertRecord(SCHEMA_VERSIONS_TABLE, { name: schema.name, version: schema.version });
|
await this.db.insertRecord(SCHEMA_VERSIONS_TABLE_NAME, { name: schema.name, version: schema.version });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -741,8 +725,3 @@ export type WindowForAutomatedTests = Window & {
|
||||||
appProvider?: CoreAppProvider;
|
appProvider?: CoreAppProvider;
|
||||||
appRef?: ApplicationRef;
|
appRef?: ApplicationRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SchemaVersionsDBEntry = {
|
|
||||||
name: string;
|
|
||||||
version: number;
|
|
||||||
};
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// 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 { CoreAppSchema } from '@services/app';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database variables for for CoreConfig service.
|
||||||
|
*/
|
||||||
|
export const CONFIG_TABLE_NAME = 'core_config';
|
||||||
|
|
||||||
|
export const APP_SCHEMA: CoreAppSchema = {
|
||||||
|
name: 'CoreConfigProvider',
|
||||||
|
version: 1,
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: CONFIG_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: 'TEXT',
|
||||||
|
unique: true,
|
||||||
|
notNull: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'value',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ConfigDBEntry = {
|
||||||
|
name: string;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
value: any;
|
||||||
|
};
|
|
@ -14,11 +14,10 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { CoreApp, CoreAppSchema } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { SQLiteDB } from '@classes/sqlitedb';
|
import { SQLiteDB } from '@classes/sqlitedb';
|
||||||
import { makeSingleton } from '@singletons/core.singletons';
|
import { makeSingleton } from '@singletons/core.singletons';
|
||||||
|
import { CONFIG_TABLE_NAME, APP_SCHEMA, ConfigDBEntry } from '@services/config.db';
|
||||||
const TABLE_NAME = 'core_config';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory to provide access to dynamic and permanent config and settings.
|
* Factory to provide access to dynamic and permanent config and settings.
|
||||||
|
@ -28,32 +27,11 @@ const TABLE_NAME = 'core_config';
|
||||||
export class CoreConfigProvider {
|
export class CoreConfigProvider {
|
||||||
|
|
||||||
protected appDB: SQLiteDB;
|
protected appDB: SQLiteDB;
|
||||||
protected tableSchema: CoreAppSchema = {
|
|
||||||
name: 'CoreConfigProvider',
|
|
||||||
version: 1,
|
|
||||||
tables: [
|
|
||||||
{
|
|
||||||
name: TABLE_NAME,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
type: 'TEXT',
|
|
||||||
unique: true,
|
|
||||||
notNull: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'value',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.appDB = CoreApp.instance.getDB();
|
this.appDB = CoreApp.instance.getDB();
|
||||||
this.dbReady = CoreApp.instance.createTablesFromSchema(this.tableSchema).catch(() => {
|
this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -67,7 +45,7 @@ export class CoreConfigProvider {
|
||||||
async delete(name: string): Promise<void> {
|
async delete(name: string): Promise<void> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
await this.appDB.deleteRecords(TABLE_NAME, { name });
|
await this.appDB.deleteRecords(CONFIG_TABLE_NAME, { name });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,7 +59,7 @@ export class CoreConfigProvider {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const entry = await this.appDB.getRecord<ConfigDBEntry>(TABLE_NAME, { name });
|
const entry = await this.appDB.getRecord<ConfigDBEntry>(CONFIG_TABLE_NAME, { name });
|
||||||
|
|
||||||
return entry.value;
|
return entry.value;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -103,15 +81,9 @@ export class CoreConfigProvider {
|
||||||
async set(name: string, value: number | string): Promise<void> {
|
async set(name: string, value: number | string): Promise<void> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
await this.appDB.insertRecord(TABLE_NAME, { name, value });
|
await this.appDB.insertRecord(CONFIG_TABLE_NAME, { name, value });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CoreConfig extends makeSingleton(CoreConfigProvider) {}
|
export class CoreConfig extends makeSingleton(CoreConfigProvider) {}
|
||||||
|
|
||||||
type ConfigDBEntry = {
|
|
||||||
name: string;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
value: any;
|
|
||||||
};
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// 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 { CoreAppSchema } from '@services/app';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database variables for CoreCron service.
|
||||||
|
*/
|
||||||
|
export const CRON_TABLE_NAME = 'cron';
|
||||||
|
export const APP_SCHEMA: CoreAppSchema = {
|
||||||
|
name: 'CoreCronDelegate',
|
||||||
|
version: 1,
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: CRON_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'TEXT',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'value',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CronDBEntry = {
|
||||||
|
id: string;
|
||||||
|
value: number;
|
||||||
|
};
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
import { Injectable, NgZone } from '@angular/core';
|
import { Injectable, NgZone } from '@angular/core';
|
||||||
|
|
||||||
import { CoreApp, CoreAppProvider, CoreAppSchema } from '@services/app';
|
import { CoreApp, CoreAppProvider } from '@services/app';
|
||||||
import { CoreConfig } from '@services/config';
|
import { CoreConfig } from '@services/config';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreConstants } from '@core/constants';
|
import { CoreConstants } from '@core/constants';
|
||||||
|
@ -23,8 +23,7 @@ import { CoreError } from '@classes/errors/error';
|
||||||
|
|
||||||
import { makeSingleton, Network } from '@singletons/core.singletons';
|
import { makeSingleton, Network } from '@singletons/core.singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
import { APP_SCHEMA, CRON_TABLE_NAME, CronDBEntry } from '@services/cron.db';
|
||||||
const CRON_TABLE = 'cron';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Service to handle cron processes. The registered processes will be executed every certain time.
|
* Service to handle cron processes. The registered processes will be executed every certain time.
|
||||||
|
@ -37,28 +36,6 @@ export class CoreCronDelegate {
|
||||||
static readonly MIN_INTERVAL = 300000; // Minimum interval is 5 minutes.
|
static readonly MIN_INTERVAL = 300000; // Minimum interval is 5 minutes.
|
||||||
static readonly MAX_TIME_PROCESS = 120000; // Max time a process can block the queue. Defaults to 2 minutes.
|
static readonly MAX_TIME_PROCESS = 120000; // Max time a process can block the queue. Defaults to 2 minutes.
|
||||||
|
|
||||||
// Variables for database.
|
|
||||||
protected tableSchema: CoreAppSchema = {
|
|
||||||
name: 'CoreCronDelegate',
|
|
||||||
version: 1,
|
|
||||||
tables: [
|
|
||||||
{
|
|
||||||
name: CRON_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
type: 'TEXT',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'value',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
protected logger: CoreLogger;
|
protected logger: CoreLogger;
|
||||||
protected appDB: SQLiteDB;
|
protected appDB: SQLiteDB;
|
||||||
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
||||||
|
@ -69,7 +46,7 @@ export class CoreCronDelegate {
|
||||||
this.logger = CoreLogger.getInstance('CoreCronDelegate');
|
this.logger = CoreLogger.getInstance('CoreCronDelegate');
|
||||||
|
|
||||||
this.appDB = CoreApp.instance.getDB();
|
this.appDB = CoreApp.instance.getDB();
|
||||||
this.dbReady = CoreApp.instance.createTablesFromSchema(this.tableSchema).catch(() => {
|
this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -268,7 +245,7 @@ export class CoreCronDelegate {
|
||||||
const id = this.getHandlerLastExecutionId(name);
|
const id = this.getHandlerLastExecutionId(name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const entry = await this.appDB.getRecord<CronDBEntry>(CRON_TABLE, { id });
|
const entry = await this.appDB.getRecord<CronDBEntry>(CRON_TABLE_NAME, { id });
|
||||||
|
|
||||||
const time = Number(entry.value);
|
const time = Number(entry.value);
|
||||||
|
|
||||||
|
@ -431,7 +408,7 @@ export class CoreCronDelegate {
|
||||||
value: time,
|
value: time,
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.appDB.insertRecord(CRON_TABLE, entry);
|
await this.appDB.insertRecord(CRON_TABLE_NAME, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -562,8 +539,3 @@ export interface CoreCronHandler {
|
||||||
export type WindowForAutomatedTests = Window & {
|
export type WindowForAutomatedTests = Window & {
|
||||||
cronProvider?: CoreCronDelegate;
|
cronProvider?: CoreCronDelegate;
|
||||||
};
|
};
|
||||||
|
|
||||||
type CronDBEntry = {
|
|
||||||
id: string;
|
|
||||||
value: number;
|
|
||||||
};
|
|
||||||
|
|
|
@ -0,0 +1,367 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// 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 { CoreAppSchema } from '@services/app';
|
||||||
|
import { CoreSiteSchema, registerSiteSchema } from '@services/sites';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database variables for CoreFilepool service.
|
||||||
|
*/
|
||||||
|
export const QUEUE_TABLE_NAME = 'filepool_files_queue'; // Queue of files to download.
|
||||||
|
export const FILES_TABLE_NAME = 'filepool_files'; // Downloaded files.
|
||||||
|
export const LINKS_TABLE_NAME = 'filepool_files_links'; // Links between downloaded files and components.
|
||||||
|
export const PACKAGES_TABLE_NAME = 'filepool_packages'; // Downloaded packages (sets of files).
|
||||||
|
export const APP_SCHEMA: CoreAppSchema = {
|
||||||
|
name: 'CoreFilepoolProvider',
|
||||||
|
version: 1,
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: QUEUE_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'siteId',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'fileId',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'added',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'priority',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'url',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'revision',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'timemodified',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'isexternalfile',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'repositorytype',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'path',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'links',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
primaryKeys: ['siteId', 'fileId'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SITE_SCHEMA: CoreSiteSchema = {
|
||||||
|
name: 'CoreFilepoolProvider',
|
||||||
|
version: 1,
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: FILES_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'fileId',
|
||||||
|
type: 'TEXT',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'url',
|
||||||
|
type: 'TEXT',
|
||||||
|
notNull: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'revision',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'timemodified',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'stale',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'downloadTime',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'isexternalfile',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'repositorytype',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'path',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'extension',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: LINKS_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'fileId',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'component',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'componentId',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
primaryKeys: ['fileId', 'component', 'componentId'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: PACKAGES_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'TEXT',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'component',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'componentId',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'status',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'previous',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'updated',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'downloadTime',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'previousDownloadTime',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'extra',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File options.
|
||||||
|
*/
|
||||||
|
export type CoreFilepoolFileOptions = {
|
||||||
|
revision?: number; // File's revision.
|
||||||
|
timemodified?: number; // File's timemodified.
|
||||||
|
isexternalfile?: number; // 1 if it's a external file (from an external repository), 0 otherwise.
|
||||||
|
repositorytype?: string; // Type of the repository this file belongs to.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry from filepool.
|
||||||
|
*/
|
||||||
|
export type CoreFilepoolFileEntry = CoreFilepoolFileOptions & {
|
||||||
|
/**
|
||||||
|
* The fileId to identify the file.
|
||||||
|
*/
|
||||||
|
fileId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File's URL.
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1 if file is stale (needs to be updated), 0 otherwise.
|
||||||
|
*/
|
||||||
|
stale: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamp when this file was downloaded.
|
||||||
|
*/
|
||||||
|
downloadTime: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File's path.
|
||||||
|
*/
|
||||||
|
path: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File's extension.
|
||||||
|
*/
|
||||||
|
extension: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB data for entry from file's queue.
|
||||||
|
*/
|
||||||
|
export type CoreFilepoolQueueDBEntry = CoreFilepoolFileOptions & {
|
||||||
|
/**
|
||||||
|
* The site the file belongs to.
|
||||||
|
*/
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fileId to identify the file.
|
||||||
|
*/
|
||||||
|
fileId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamp when the file was added to the queue.
|
||||||
|
*/
|
||||||
|
added: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The priority of the file.
|
||||||
|
*/
|
||||||
|
priority: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File's URL.
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File's path.
|
||||||
|
*/
|
||||||
|
path?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File links (to link the file to components and componentIds). Serialized to store on DB.
|
||||||
|
*/
|
||||||
|
links: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry from the file's queue.
|
||||||
|
*/
|
||||||
|
export type CoreFilepoolQueueEntry = CoreFilepoolQueueDBEntry & {
|
||||||
|
/**
|
||||||
|
* File links (to link the file to components and componentIds).
|
||||||
|
*/
|
||||||
|
linksUnserialized?: CoreFilepoolComponentLink[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry from packages table.
|
||||||
|
*/
|
||||||
|
export type CoreFilepoolPackageEntry = {
|
||||||
|
/**
|
||||||
|
* Package id.
|
||||||
|
*/
|
||||||
|
id?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The component to link the files to.
|
||||||
|
*/
|
||||||
|
component?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ID to use in conjunction with the component.
|
||||||
|
*/
|
||||||
|
componentId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Package status.
|
||||||
|
*/
|
||||||
|
status?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Package previous status.
|
||||||
|
*/
|
||||||
|
previous?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamp when this package was updated.
|
||||||
|
*/
|
||||||
|
updated?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamp when this package was downloaded.
|
||||||
|
*/
|
||||||
|
downloadTime?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous download time.
|
||||||
|
*/
|
||||||
|
previousDownloadTime?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra data stored by the package.
|
||||||
|
*/
|
||||||
|
extra?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component link.
|
||||||
|
*/
|
||||||
|
export type CoreFilepoolComponentLink = {
|
||||||
|
/**
|
||||||
|
* Link's component.
|
||||||
|
*/
|
||||||
|
component: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link's componentId.
|
||||||
|
*/
|
||||||
|
componentId?: string | number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Links table record type.
|
||||||
|
*/
|
||||||
|
export type CoreFilepoolLinksRecord = {
|
||||||
|
fileId: string; // File Id.
|
||||||
|
component: string; // Component name.
|
||||||
|
componentId: number | string; // Component Id.
|
||||||
|
};
|
||||||
|
|
||||||
|
export const initCoreFilepoolDB = (): void => {
|
||||||
|
registerSiteSchema(SITE_SCHEMA);
|
||||||
|
};
|
|
@ -15,12 +15,12 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Md5 } from 'ts-md5/dist/md5';
|
import { Md5 } from 'ts-md5/dist/md5';
|
||||||
|
|
||||||
import { CoreApp, CoreAppSchema } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import { CoreFile } from '@services/file';
|
import { CoreFile } from '@services/file';
|
||||||
import { CoreInit } from '@services/init';
|
import { CoreInit } from '@services/init';
|
||||||
import { CorePluginFile } from '@services/plugin-file-delegate';
|
import { CorePluginFile } from '@services/plugin-file-delegate';
|
||||||
import { CoreSites, CoreSiteSchema } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreWS, CoreWSExternalFile } from '@services/ws';
|
import { CoreWS, CoreWSExternalFile } from '@services/ws';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
import { CoreMimetypeUtils } from '@services/utils/mimetype';
|
||||||
|
@ -33,6 +33,20 @@ import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreConstants } from '@core/constants';
|
import { CoreConstants } from '@core/constants';
|
||||||
import { makeSingleton, Network, NgZone, Translate } from '@singletons/core.singletons';
|
import { makeSingleton, Network, NgZone, Translate } from '@singletons/core.singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
import {
|
||||||
|
APP_SCHEMA,
|
||||||
|
FILES_TABLE_NAME,
|
||||||
|
QUEUE_TABLE_NAME,
|
||||||
|
PACKAGES_TABLE_NAME,
|
||||||
|
LINKS_TABLE_NAME,
|
||||||
|
CoreFilepoolFileEntry,
|
||||||
|
CoreFilepoolComponentLink,
|
||||||
|
CoreFilepoolFileOptions,
|
||||||
|
CoreFilepoolLinksRecord,
|
||||||
|
CoreFilepoolPackageEntry,
|
||||||
|
CoreFilepoolQueueEntry,
|
||||||
|
CoreFilepoolQueueDBEntry,
|
||||||
|
} from '@services/filepool.db';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Factory for handling downloading files and retrieve downloaded files.
|
* Factory for handling downloading files and retrieve downloaded files.
|
||||||
|
@ -60,182 +74,6 @@ export class CoreFilepoolProvider {
|
||||||
protected static readonly FILE_UPDATE_UNKNOWN_WHERE_CLAUSE =
|
protected static readonly FILE_UPDATE_UNKNOWN_WHERE_CLAUSE =
|
||||||
'isexternalfile = 1 OR ((revision IS NULL OR revision = 0) AND (timemodified IS NULL OR timemodified = 0))';
|
'isexternalfile = 1 OR ((revision IS NULL OR revision = 0) AND (timemodified IS NULL OR timemodified = 0))';
|
||||||
|
|
||||||
// Variables for database.
|
|
||||||
protected static readonly QUEUE_TABLE = 'filepool_files_queue'; // Queue of files to download.
|
|
||||||
protected static readonly FILES_TABLE = 'filepool_files'; // Downloaded files.
|
|
||||||
protected static readonly LINKS_TABLE = 'filepool_files_links'; // Links between downloaded files and components.
|
|
||||||
protected static readonly PACKAGES_TABLE = 'filepool_packages'; // Downloaded packages (sets of files).
|
|
||||||
protected appTablesSchema: CoreAppSchema = {
|
|
||||||
name: 'CoreFilepoolProvider',
|
|
||||||
version: 1,
|
|
||||||
tables: [
|
|
||||||
{
|
|
||||||
name: CoreFilepoolProvider.QUEUE_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'siteId',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'fileId',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'added',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'priority',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'url',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'revision',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'timemodified',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'isexternalfile',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'repositorytype',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'path',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'links',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
primaryKeys: ['siteId', 'fileId'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
protected siteSchema: CoreSiteSchema = {
|
|
||||||
name: 'CoreFilepoolProvider',
|
|
||||||
version: 1,
|
|
||||||
tables: [
|
|
||||||
{
|
|
||||||
name: CoreFilepoolProvider.FILES_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'fileId',
|
|
||||||
type: 'TEXT',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'url',
|
|
||||||
type: 'TEXT',
|
|
||||||
notNull: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'revision',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'timemodified',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'stale',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'downloadTime',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'isexternalfile',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'repositorytype',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'path',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'extension',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: CoreFilepoolProvider.LINKS_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'fileId',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'component',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'componentId',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
primaryKeys: ['fileId', 'component', 'componentId'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: CoreFilepoolProvider.PACKAGES_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
type: 'TEXT',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'component',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'componentId',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'status',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'previous',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'updated',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'downloadTime',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'previousDownloadTime',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'extra',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
protected logger: CoreLogger;
|
protected logger: CoreLogger;
|
||||||
protected appDB: SQLiteDB;
|
protected appDB: SQLiteDB;
|
||||||
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
||||||
|
@ -258,12 +96,10 @@ export class CoreFilepoolProvider {
|
||||||
this.logger = CoreLogger.getInstance('CoreFilepoolProvider');
|
this.logger = CoreLogger.getInstance('CoreFilepoolProvider');
|
||||||
|
|
||||||
this.appDB = CoreApp.instance.getDB();
|
this.appDB = CoreApp.instance.getDB();
|
||||||
this.dbReady = CoreApp.instance.createTablesFromSchema(this.appTablesSchema).catch(() => {
|
this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
|
|
||||||
CoreSites.instance.registerSiteSchema(this.siteSchema);
|
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +144,7 @@ export class CoreFilepoolProvider {
|
||||||
componentId: componentId || '',
|
componentId: componentId || '',
|
||||||
};
|
};
|
||||||
|
|
||||||
await db.insertRecord(CoreFilepoolProvider.LINKS_TABLE, newEntry);
|
await db.insertRecord(LINKS_TABLE_NAME, newEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -373,7 +209,7 @@ export class CoreFilepoolProvider {
|
||||||
|
|
||||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||||
|
|
||||||
await db.insertRecord(CoreFilepoolProvider.FILES_TABLE, record);
|
await db.insertRecord(FILES_TABLE_NAME, record);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -433,7 +269,7 @@ export class CoreFilepoolProvider {
|
||||||
|
|
||||||
this.logger.debug(`Adding ${fileId} to the queue`);
|
this.logger.debug(`Adding ${fileId} to the queue`);
|
||||||
|
|
||||||
await this.appDB.insertRecord(CoreFilepoolProvider.QUEUE_TABLE, {
|
await this.appDB.insertRecord(QUEUE_TABLE_NAME, {
|
||||||
siteId,
|
siteId,
|
||||||
fileId,
|
fileId,
|
||||||
url,
|
url,
|
||||||
|
@ -563,7 +399,7 @@ export class CoreFilepoolProvider {
|
||||||
// Update only when required.
|
// Update only when required.
|
||||||
this.logger.debug(`Updating file ${fileId} which is already in queue`);
|
this.logger.debug(`Updating file ${fileId} which is already in queue`);
|
||||||
|
|
||||||
return this.appDB.updateRecords(CoreFilepoolProvider.QUEUE_TABLE, newData, primaryKey).then(() =>
|
return this.appDB.updateRecords(QUEUE_TABLE_NAME, newData, primaryKey).then(() =>
|
||||||
this.getQueuePromise(siteId, fileId, true, onProgress));
|
this.getQueuePromise(siteId, fileId, true, onProgress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -692,9 +528,9 @@ export class CoreFilepoolProvider {
|
||||||
|
|
||||||
const site = await CoreSites.instance.getSite(siteId);
|
const site = await CoreSites.instance.getSite(siteId);
|
||||||
// Get all the packages to be able to "notify" the change in the status.
|
// Get all the packages to be able to "notify" the change in the status.
|
||||||
const entries: CoreFilepoolPackageEntry[] = await site.getDb().getAllRecords(CoreFilepoolProvider.PACKAGES_TABLE);
|
const entries: CoreFilepoolPackageEntry[] = await site.getDb().getAllRecords(PACKAGES_TABLE_NAME);
|
||||||
// Delete all the entries.
|
// Delete all the entries.
|
||||||
await site.getDb().deleteRecords(CoreFilepoolProvider.PACKAGES_TABLE);
|
await site.getDb().deleteRecords(PACKAGES_TABLE_NAME);
|
||||||
|
|
||||||
entries.forEach((entry) => {
|
entries.forEach((entry) => {
|
||||||
// Trigger module status changed, setting it as not downloaded.
|
// Trigger module status changed, setting it as not downloaded.
|
||||||
|
@ -712,8 +548,8 @@ export class CoreFilepoolProvider {
|
||||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.deleteRecords(CoreFilepoolProvider.FILES_TABLE),
|
db.deleteRecords(FILES_TABLE_NAME),
|
||||||
db.deleteRecords(CoreFilepoolProvider.LINKS_TABLE),
|
db.deleteRecords(LINKS_TABLE_NAME),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,7 +568,7 @@ export class CoreFilepoolProvider {
|
||||||
componentId: this.fixComponentId(componentId),
|
componentId: this.fixComponentId(componentId),
|
||||||
};
|
};
|
||||||
|
|
||||||
const count = await db.countRecords(CoreFilepoolProvider.LINKS_TABLE, conditions);
|
const count = await db.countRecords(LINKS_TABLE_NAME, conditions);
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
throw new CoreError('Component doesn\'t have files');
|
throw new CoreError('Component doesn\'t have files');
|
||||||
}
|
}
|
||||||
|
@ -1257,7 +1093,7 @@ export class CoreFilepoolProvider {
|
||||||
// Minor problem: file will remain in the filesystem once downloaded again.
|
// Minor problem: file will remain in the filesystem once downloaded again.
|
||||||
this.logger.debug('Staled file with no extension ' + entry.fileId);
|
this.logger.debug('Staled file with no extension ' + entry.fileId);
|
||||||
|
|
||||||
await db.updateRecords(CoreFilepoolProvider.FILES_TABLE, { stale: 1 }, { fileId: entry.fileId });
|
await db.updateRecords(FILES_TABLE_NAME, { stale: 1 }, { fileId: entry.fileId });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1267,7 +1103,7 @@ export class CoreFilepoolProvider {
|
||||||
entry.fileId = CoreMimetypeUtils.instance.removeExtension(fileId);
|
entry.fileId = CoreMimetypeUtils.instance.removeExtension(fileId);
|
||||||
entry.extension = extension;
|
entry.extension = extension;
|
||||||
|
|
||||||
await db.updateRecords(CoreFilepoolProvider.FILES_TABLE, entry, { fileId });
|
await db.updateRecords(FILES_TABLE_NAME, entry, { fileId });
|
||||||
if (entry.fileId == fileId) {
|
if (entry.fileId == fileId) {
|
||||||
// File ID hasn't changed, we're done.
|
// File ID hasn't changed, we're done.
|
||||||
this.logger.debug('Removed extesion ' + extension + ' from file ' + entry.fileId);
|
this.logger.debug('Removed extesion ' + extension + ' from file ' + entry.fileId);
|
||||||
|
@ -1276,7 +1112,7 @@ export class CoreFilepoolProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now update the links.
|
// Now update the links.
|
||||||
await db.updateRecords(CoreFilepoolProvider.LINKS_TABLE, { fileId: entry.fileId }, { fileId });
|
await db.updateRecords(LINKS_TABLE_NAME, { fileId: entry.fileId }, { fileId });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1339,7 +1175,7 @@ export class CoreFilepoolProvider {
|
||||||
componentId: this.fixComponentId(componentId),
|
componentId: this.fixComponentId(componentId),
|
||||||
};
|
};
|
||||||
|
|
||||||
const items = await db.getRecords<CoreFilepoolLinksRecord>(CoreFilepoolProvider.LINKS_TABLE, conditions);
|
const items = await db.getRecords<CoreFilepoolLinksRecord>(LINKS_TABLE_NAME, conditions);
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
item.componentId = this.fixComponentId(item.componentId);
|
item.componentId = this.fixComponentId(item.componentId);
|
||||||
});
|
});
|
||||||
|
@ -1449,7 +1285,7 @@ export class CoreFilepoolProvider {
|
||||||
*/
|
*/
|
||||||
protected async getFileLinks(siteId: string, fileId: string): Promise<CoreFilepoolLinksRecord[]> {
|
protected async getFileLinks(siteId: string, fileId: string): Promise<CoreFilepoolLinksRecord[]> {
|
||||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||||
const items = await db.getRecords<CoreFilepoolLinksRecord>(CoreFilepoolProvider.LINKS_TABLE, { fileId });
|
const items = await db.getRecords<CoreFilepoolLinksRecord>(LINKS_TABLE_NAME, { fileId });
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
item.componentId = this.fixComponentId(item.componentId);
|
item.componentId = this.fixComponentId(item.componentId);
|
||||||
|
@ -1527,7 +1363,7 @@ export class CoreFilepoolProvider {
|
||||||
await Promise.all(items.map(async (item) => {
|
await Promise.all(items.map(async (item) => {
|
||||||
try {
|
try {
|
||||||
const fileEntry = await db.getRecord<CoreFilepoolFileEntry>(
|
const fileEntry = await db.getRecord<CoreFilepoolFileEntry>(
|
||||||
CoreFilepoolProvider.FILES_TABLE,
|
FILES_TABLE_NAME,
|
||||||
{ fileId: item.fileId },
|
{ fileId: item.fileId },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1808,7 +1644,7 @@ export class CoreFilepoolProvider {
|
||||||
const site = await CoreSites.instance.getSite(siteId);
|
const site = await CoreSites.instance.getSite(siteId);
|
||||||
const packageId = this.getPackageId(component, componentId);
|
const packageId = this.getPackageId(component, componentId);
|
||||||
|
|
||||||
return site.getDb().getRecord(CoreFilepoolProvider.PACKAGES_TABLE, { id: packageId });
|
return site.getDb().getRecord(PACKAGES_TABLE_NAME, { id: packageId });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2258,7 +2094,7 @@ export class CoreFilepoolProvider {
|
||||||
*/
|
*/
|
||||||
protected async hasFileInPool(siteId: string, fileId: string): Promise<CoreFilepoolFileEntry> {
|
protected async hasFileInPool(siteId: string, fileId: string): Promise<CoreFilepoolFileEntry> {
|
||||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||||
const entry = await db.getRecord<CoreFilepoolFileEntry>(CoreFilepoolProvider.FILES_TABLE, { fileId });
|
const entry = await db.getRecord<CoreFilepoolFileEntry>(FILES_TABLE_NAME, { fileId });
|
||||||
|
|
||||||
if (typeof entry === 'undefined') {
|
if (typeof entry === 'undefined') {
|
||||||
throw new CoreError('File not found in filepool.');
|
throw new CoreError('File not found in filepool.');
|
||||||
|
@ -2277,7 +2113,7 @@ export class CoreFilepoolProvider {
|
||||||
protected async hasFileInQueue(siteId: string, fileId: string): Promise<CoreFilepoolQueueEntry> {
|
protected async hasFileInQueue(siteId: string, fileId: string): Promise<CoreFilepoolQueueEntry> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
const entry = await this.appDB.getRecord<CoreFilepoolQueueEntry>(CoreFilepoolProvider.QUEUE_TABLE, { siteId, fileId });
|
const entry = await this.appDB.getRecord<CoreFilepoolQueueEntry>(QUEUE_TABLE_NAME, { siteId, fileId });
|
||||||
|
|
||||||
if (typeof entry === 'undefined') {
|
if (typeof entry === 'undefined') {
|
||||||
throw new CoreError('File not found in queue.');
|
throw new CoreError('File not found in queue.');
|
||||||
|
@ -2301,7 +2137,7 @@ export class CoreFilepoolProvider {
|
||||||
|
|
||||||
const where = onlyUnknown ? CoreFilepoolProvider.FILE_UPDATE_UNKNOWN_WHERE_CLAUSE : undefined;
|
const where = onlyUnknown ? CoreFilepoolProvider.FILE_UPDATE_UNKNOWN_WHERE_CLAUSE : undefined;
|
||||||
|
|
||||||
await db.updateRecordsWhere(CoreFilepoolProvider.FILES_TABLE, { stale: 1 }, where);
|
await db.updateRecordsWhere(FILES_TABLE_NAME, { stale: 1 }, where);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2322,7 +2158,7 @@ export class CoreFilepoolProvider {
|
||||||
|
|
||||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||||
|
|
||||||
await db.updateRecords(CoreFilepoolProvider.FILES_TABLE, { stale: 1 }, { fileId });
|
await db.updateRecords(FILES_TABLE_NAME, { stale: 1 }, { fileId });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2359,7 +2195,7 @@ export class CoreFilepoolProvider {
|
||||||
whereAndParams[0] += ' AND (' + CoreFilepoolProvider.FILE_UPDATE_UNKNOWN_WHERE_CLAUSE + ')';
|
whereAndParams[0] += ' AND (' + CoreFilepoolProvider.FILE_UPDATE_UNKNOWN_WHERE_CLAUSE + ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.updateRecordsWhere(CoreFilepoolProvider.FILES_TABLE, { stale: 1 }, whereAndParams[0], whereAndParams[1]);
|
await db.updateRecordsWhere(FILES_TABLE_NAME, { stale: 1 }, whereAndParams[0], whereAndParams[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2615,7 +2451,7 @@ export class CoreFilepoolProvider {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
items = await this.appDB.getRecords<CoreFilepoolQueueEntry>(
|
items = await this.appDB.getRecords<CoreFilepoolQueueEntry>(
|
||||||
CoreFilepoolProvider.QUEUE_TABLE,
|
QUEUE_TABLE_NAME,
|
||||||
undefined,
|
undefined,
|
||||||
'priority DESC, added ASC',
|
'priority DESC, added ASC',
|
||||||
undefined,
|
undefined,
|
||||||
|
@ -2760,7 +2596,7 @@ export class CoreFilepoolProvider {
|
||||||
protected async removeFromQueue(siteId: string, fileId: string): Promise<void> {
|
protected async removeFromQueue(siteId: string, fileId: string): Promise<void> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
await this.appDB.deleteRecords(CoreFilepoolProvider.QUEUE_TABLE, { siteId, fileId });
|
await this.appDB.deleteRecords(QUEUE_TABLE_NAME, { siteId, fileId });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2797,10 +2633,10 @@ export class CoreFilepoolProvider {
|
||||||
const promises: Promise<unknown>[] = [];
|
const promises: Promise<unknown>[] = [];
|
||||||
|
|
||||||
// Remove entry from filepool store.
|
// Remove entry from filepool store.
|
||||||
promises.push(db.deleteRecords(CoreFilepoolProvider.FILES_TABLE, conditions));
|
promises.push(db.deleteRecords(FILES_TABLE_NAME, conditions));
|
||||||
|
|
||||||
// Remove links.
|
// Remove links.
|
||||||
promises.push(db.deleteRecords(CoreFilepoolProvider.LINKS_TABLE, conditions));
|
promises.push(db.deleteRecords(LINKS_TABLE_NAME, conditions));
|
||||||
|
|
||||||
// Remove the file.
|
// Remove the file.
|
||||||
if (CoreFile.instance.isAvailable()) {
|
if (CoreFile.instance.isAvailable()) {
|
||||||
|
@ -2885,7 +2721,7 @@ export class CoreFilepoolProvider {
|
||||||
const packageId = this.getPackageId(component, componentId);
|
const packageId = this.getPackageId(component, componentId);
|
||||||
|
|
||||||
// Get current stored data, we'll only update 'status' and 'updated' fields.
|
// Get current stored data, we'll only update 'status' and 'updated' fields.
|
||||||
const entry = <CoreFilepoolPackageEntry> site.getDb().getRecord(CoreFilepoolProvider.PACKAGES_TABLE, { id: packageId });
|
const entry = <CoreFilepoolPackageEntry> site.getDb().getRecord(PACKAGES_TABLE_NAME, { id: packageId });
|
||||||
const newData: CoreFilepoolPackageEntry = {};
|
const newData: CoreFilepoolPackageEntry = {};
|
||||||
if (entry.status == CoreConstants.DOWNLOADING) {
|
if (entry.status == CoreConstants.DOWNLOADING) {
|
||||||
// Going back from downloading to previous status, restore previous download time.
|
// Going back from downloading to previous status, restore previous download time.
|
||||||
|
@ -2895,7 +2731,7 @@ export class CoreFilepoolProvider {
|
||||||
newData.updated = Date.now();
|
newData.updated = Date.now();
|
||||||
this.logger.debug(`Set previous status '${entry.status}' for package ${component} ${componentId}`);
|
this.logger.debug(`Set previous status '${entry.status}' for package ${component} ${componentId}`);
|
||||||
|
|
||||||
await site.getDb().updateRecords(CoreFilepoolProvider.PACKAGES_TABLE, newData, { id: packageId });
|
await site.getDb().updateRecords(PACKAGES_TABLE_NAME, newData, { id: packageId });
|
||||||
// Success updating, trigger event.
|
// Success updating, trigger event.
|
||||||
this.triggerPackageStatusChanged(site.id!, newData.status, component, componentId);
|
this.triggerPackageStatusChanged(site.id!, newData.status, component, componentId);
|
||||||
|
|
||||||
|
@ -2973,7 +2809,7 @@ export class CoreFilepoolProvider {
|
||||||
let previousStatus: string | undefined;
|
let previousStatus: string | undefined;
|
||||||
// Search current status to set it as previous status.
|
// Search current status to set it as previous status.
|
||||||
try {
|
try {
|
||||||
const entry = <CoreFilepoolPackageEntry> site.getDb().getRecord(CoreFilepoolProvider.PACKAGES_TABLE, { id: packageId });
|
const entry = <CoreFilepoolPackageEntry> site.getDb().getRecord(PACKAGES_TABLE_NAME, { id: packageId });
|
||||||
if (typeof extra == 'undefined' || extra === null) {
|
if (typeof extra == 'undefined' || extra === null) {
|
||||||
extra = entry.extra;
|
extra = entry.extra;
|
||||||
}
|
}
|
||||||
|
@ -3008,7 +2844,7 @@ export class CoreFilepoolProvider {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await site.getDb().insertRecord(CoreFilepoolProvider.PACKAGES_TABLE, packageEntry);
|
await site.getDb().insertRecord(PACKAGES_TABLE_NAME, packageEntry);
|
||||||
|
|
||||||
// Success inserting, trigger event.
|
// Success inserting, trigger event.
|
||||||
this.triggerPackageStatusChanged(siteId, status, component, componentId);
|
this.triggerPackageStatusChanged(siteId, status, component, componentId);
|
||||||
|
@ -3132,7 +2968,7 @@ export class CoreFilepoolProvider {
|
||||||
const packageId = this.getPackageId(component, componentId);
|
const packageId = this.getPackageId(component, componentId);
|
||||||
|
|
||||||
await site.getDb().updateRecords(
|
await site.getDb().updateRecords(
|
||||||
CoreFilepoolProvider.PACKAGES_TABLE,
|
PACKAGES_TABLE_NAME,
|
||||||
{ downloadTime: CoreTimeUtils.instance.timestamp() },
|
{ downloadTime: CoreTimeUtils.instance.timestamp() },
|
||||||
{ id: packageId },
|
{ id: packageId },
|
||||||
);
|
);
|
||||||
|
@ -3142,166 +2978,6 @@ export class CoreFilepoolProvider {
|
||||||
|
|
||||||
export class CoreFilepool extends makeSingleton(CoreFilepoolProvider) {}
|
export class CoreFilepool extends makeSingleton(CoreFilepoolProvider) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* File options.
|
|
||||||
*/
|
|
||||||
type CoreFilepoolFileOptions = {
|
|
||||||
revision?: number; // File's revision.
|
|
||||||
timemodified?: number; // File's timemodified.
|
|
||||||
isexternalfile?: number; // 1 if it's a external file (from an external repository), 0 otherwise.
|
|
||||||
repositorytype?: string; // Type of the repository this file belongs to.
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Entry from filepool.
|
|
||||||
*/
|
|
||||||
export type CoreFilepoolFileEntry = CoreFilepoolFileOptions & {
|
|
||||||
/**
|
|
||||||
* The fileId to identify the file.
|
|
||||||
*/
|
|
||||||
fileId: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File's URL.
|
|
||||||
*/
|
|
||||||
url: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1 if file is stale (needs to be updated), 0 otherwise.
|
|
||||||
*/
|
|
||||||
stale: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timestamp when this file was downloaded.
|
|
||||||
*/
|
|
||||||
downloadTime: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File's path.
|
|
||||||
*/
|
|
||||||
path: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File's extension.
|
|
||||||
*/
|
|
||||||
extension: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DB data for entry from file's queue.
|
|
||||||
*/
|
|
||||||
export type CoreFilepoolQueueDBEntry = CoreFilepoolFileOptions & {
|
|
||||||
/**
|
|
||||||
* The site the file belongs to.
|
|
||||||
*/
|
|
||||||
siteId: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The fileId to identify the file.
|
|
||||||
*/
|
|
||||||
fileId: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timestamp when the file was added to the queue.
|
|
||||||
*/
|
|
||||||
added: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The priority of the file.
|
|
||||||
*/
|
|
||||||
priority: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File's URL.
|
|
||||||
*/
|
|
||||||
url: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File's path.
|
|
||||||
*/
|
|
||||||
path?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File links (to link the file to components and componentIds). Serialized to store on DB.
|
|
||||||
*/
|
|
||||||
links: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Entry from the file's queue.
|
|
||||||
*/
|
|
||||||
export type CoreFilepoolQueueEntry = CoreFilepoolQueueDBEntry & {
|
|
||||||
/**
|
|
||||||
* File links (to link the file to components and componentIds).
|
|
||||||
*/
|
|
||||||
linksUnserialized?: CoreFilepoolComponentLink[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Entry from packages table.
|
|
||||||
*/
|
|
||||||
export type CoreFilepoolPackageEntry = {
|
|
||||||
/**
|
|
||||||
* Package id.
|
|
||||||
*/
|
|
||||||
id?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The component to link the files to.
|
|
||||||
*/
|
|
||||||
component?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An ID to use in conjunction with the component.
|
|
||||||
*/
|
|
||||||
componentId?: string | number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Package status.
|
|
||||||
*/
|
|
||||||
status?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Package previous status.
|
|
||||||
*/
|
|
||||||
previous?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timestamp when this package was updated.
|
|
||||||
*/
|
|
||||||
updated?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timestamp when this package was downloaded.
|
|
||||||
*/
|
|
||||||
downloadTime?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Previous download time.
|
|
||||||
*/
|
|
||||||
previousDownloadTime?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extra data stored by the package.
|
|
||||||
*/
|
|
||||||
extra?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A component link.
|
|
||||||
*/
|
|
||||||
export type CoreFilepoolComponentLink = {
|
|
||||||
/**
|
|
||||||
* Link's component.
|
|
||||||
*/
|
|
||||||
component: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Link's componentId.
|
|
||||||
*/
|
|
||||||
componentId?: string | number;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File actions.
|
* File actions.
|
||||||
*/
|
*/
|
||||||
|
@ -3359,14 +3035,5 @@ type CoreFilepoolPromiseDefer = PromiseDefer<void> & {
|
||||||
onProgress?: CoreFilepoolOnProgressCallback; // On Progress function.
|
onProgress?: CoreFilepoolOnProgressCallback; // On Progress function.
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Links table record type.
|
|
||||||
*/
|
|
||||||
type CoreFilepoolLinksRecord = {
|
|
||||||
fileId: string; // File Id.
|
|
||||||
component: string; // Component name.
|
|
||||||
componentId: number | string; // Component Id.
|
|
||||||
};
|
|
||||||
|
|
||||||
type AnchorOrMediaElement =
|
type AnchorOrMediaElement =
|
||||||
HTMLAnchorElement | HTMLImageElement | HTMLAudioElement | HTMLVideoElement | HTMLSourceElement | HTMLTrackElement;
|
HTMLAnchorElement | HTMLImageElement | HTMLAudioElement | HTMLVideoElement | HTMLSourceElement | HTMLTrackElement;
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// 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 { CoreAppSchema } from '@services/app';
|
||||||
|
import { PromiseDefer } from '@services/utils/utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database variables for CoreLocalNotifications service.
|
||||||
|
*/
|
||||||
|
export const SITES_TABLE_NAME = 'notification_sites'; // Store to asigne unique codes to each site.
|
||||||
|
export const COMPONENTS_TABLE_NAME = 'notification_components'; // Store to asigne unique codes to each component.
|
||||||
|
export const TRIGGERED_TABLE_NAME = 'notifications_triggered'; // Store to prevent re-triggering notifications.
|
||||||
|
export const APP_SCHEMA: CoreAppSchema = {
|
||||||
|
name: 'CoreLocalNotificationsProvider',
|
||||||
|
version: 1,
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: SITES_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'TEXT',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'code',
|
||||||
|
type: 'INTEGER',
|
||||||
|
notNull: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: COMPONENTS_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'TEXT',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'code',
|
||||||
|
type: 'INTEGER',
|
||||||
|
notNull: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: TRIGGERED_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'INTEGER',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'at',
|
||||||
|
type: 'INTEGER',
|
||||||
|
notNull: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CodeRequestsQueueItem = {
|
||||||
|
table: string;
|
||||||
|
id: string;
|
||||||
|
deferreds: PromiseDefer<number>[];
|
||||||
|
};
|
|
@ -16,11 +16,11 @@ import { Injectable } from '@angular/core';
|
||||||
import { Subject, Subscription } from 'rxjs';
|
import { Subject, Subscription } from 'rxjs';
|
||||||
import { ILocalNotification } from '@ionic-native/local-notifications';
|
import { ILocalNotification } from '@ionic-native/local-notifications';
|
||||||
|
|
||||||
import { CoreApp, CoreAppSchema } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreConfig } from '@services/config';
|
import { CoreConfig } from '@services/config';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { SQLiteDB } from '@classes/sqlitedb';
|
import { SQLiteDB } from '@classes/sqlitedb';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
import { CoreQueueRunner } from '@classes/queue-runner';
|
import { CoreQueueRunner } from '@classes/queue-runner';
|
||||||
|
@ -28,6 +28,13 @@ import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreConstants } from '@core/constants';
|
import { CoreConstants } from '@core/constants';
|
||||||
import { makeSingleton, NgZone, Platform, Translate, LocalNotifications, Push, Device } from '@singletons/core.singletons';
|
import { makeSingleton, NgZone, Platform, Translate, LocalNotifications, Push, Device } from '@singletons/core.singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
import {
|
||||||
|
APP_SCHEMA,
|
||||||
|
TRIGGERED_TABLE_NAME,
|
||||||
|
COMPONENTS_TABLE_NAME,
|
||||||
|
SITES_TABLE_NAME,
|
||||||
|
CodeRequestsQueueItem,
|
||||||
|
} from '@services/local-notifications.db';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle local notifications.
|
* Service to handle local notifications.
|
||||||
|
@ -35,62 +42,6 @@ import { CoreLogger } from '@singletons/logger';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CoreLocalNotificationsProvider {
|
export class CoreLocalNotificationsProvider {
|
||||||
|
|
||||||
// Variables for the database.
|
|
||||||
protected static readonly SITES_TABLE = 'notification_sites'; // Store to asigne unique codes to each site.
|
|
||||||
protected static readonly COMPONENTS_TABLE = 'notification_components'; // Store to asigne unique codes to each component.
|
|
||||||
protected static readonly TRIGGERED_TABLE = 'notifications_triggered'; // Store to prevent re-triggering notifications.
|
|
||||||
protected tablesSchema: CoreAppSchema = {
|
|
||||||
name: 'CoreLocalNotificationsProvider',
|
|
||||||
version: 1,
|
|
||||||
tables: [
|
|
||||||
{
|
|
||||||
name: CoreLocalNotificationsProvider.SITES_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
type: 'TEXT',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'code',
|
|
||||||
type: 'INTEGER',
|
|
||||||
notNull: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: CoreLocalNotificationsProvider.COMPONENTS_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
type: 'TEXT',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'code',
|
|
||||||
type: 'INTEGER',
|
|
||||||
notNull: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: CoreLocalNotificationsProvider.TRIGGERED_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
type: 'INTEGER',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'at',
|
|
||||||
type: 'INTEGER',
|
|
||||||
notNull: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
protected logger: CoreLogger;
|
protected logger: CoreLogger;
|
||||||
protected appDB: SQLiteDB;
|
protected appDB: SQLiteDB;
|
||||||
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
||||||
|
@ -111,7 +62,7 @@ export class CoreLocalNotificationsProvider {
|
||||||
this.logger = CoreLogger.getInstance('CoreLocalNotificationsProvider');
|
this.logger = CoreLogger.getInstance('CoreLocalNotificationsProvider');
|
||||||
this.queueRunner = new CoreQueueRunner(10);
|
this.queueRunner = new CoreQueueRunner(10);
|
||||||
this.appDB = CoreApp.instance.getDB();
|
this.appDB = CoreApp.instance.getDB();
|
||||||
this.dbReady = CoreApp.instance.createTablesFromSchema(this.tablesSchema).catch(() => {
|
this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -301,7 +252,7 @@ export class CoreLocalNotificationsProvider {
|
||||||
* @return Promise resolved when the component code is retrieved.
|
* @return Promise resolved when the component code is retrieved.
|
||||||
*/
|
*/
|
||||||
protected getComponentCode(component: string): Promise<number> {
|
protected getComponentCode(component: string): Promise<number> {
|
||||||
return this.requestCode(CoreLocalNotificationsProvider.COMPONENTS_TABLE, component);
|
return this.requestCode(COMPONENTS_TABLE_NAME, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -312,7 +263,7 @@ export class CoreLocalNotificationsProvider {
|
||||||
* @return Promise resolved when the site code is retrieved.
|
* @return Promise resolved when the site code is retrieved.
|
||||||
*/
|
*/
|
||||||
protected getSiteCode(siteId: string): Promise<number> {
|
protected getSiteCode(siteId: string): Promise<number> {
|
||||||
return this.requestCode(CoreLocalNotificationsProvider.SITES_TABLE, siteId);
|
return this.requestCode(SITES_TABLE_NAME, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -377,7 +328,7 @@ export class CoreLocalNotificationsProvider {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const stored = await this.appDB.getRecord<{ id: number; at: number }>(
|
const stored = await this.appDB.getRecord<{ id: number; at: number }>(
|
||||||
CoreLocalNotificationsProvider.TRIGGERED_TABLE,
|
TRIGGERED_TABLE_NAME,
|
||||||
{ id: notification.id },
|
{ id: notification.id },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -532,7 +483,7 @@ export class CoreLocalNotificationsProvider {
|
||||||
async removeTriggered(id: number): Promise<void> {
|
async removeTriggered(id: number): Promise<void> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
await this.appDB.deleteRecords(CoreLocalNotificationsProvider.TRIGGERED_TABLE, { id: id });
|
await this.appDB.deleteRecords(TRIGGERED_TABLE_NAME, { id: id });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -695,7 +646,7 @@ export class CoreLocalNotificationsProvider {
|
||||||
at: notification.trigger && notification.trigger.at ? notification.trigger.at.getTime() : Date.now(),
|
at: notification.trigger && notification.trigger.at ? notification.trigger.at.getTime() : Date.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.appDB.insertRecord(CoreLocalNotificationsProvider.TRIGGERED_TABLE, entry);
|
return this.appDB.insertRecord(TRIGGERED_TABLE_NAME, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -708,10 +659,10 @@ export class CoreLocalNotificationsProvider {
|
||||||
async updateComponentName(oldName: string, newName: string): Promise<void> {
|
async updateComponentName(oldName: string, newName: string): Promise<void> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
const oldId = CoreLocalNotificationsProvider.COMPONENTS_TABLE + '#' + oldName;
|
const oldId = COMPONENTS_TABLE_NAME + '#' + oldName;
|
||||||
const newId = CoreLocalNotificationsProvider.COMPONENTS_TABLE + '#' + newName;
|
const newId = COMPONENTS_TABLE_NAME + '#' + newName;
|
||||||
|
|
||||||
await this.appDB.updateRecords(CoreLocalNotificationsProvider.COMPONENTS_TABLE, { id: newId }, { id: oldId });
|
await this.appDB.updateRecords(COMPONENTS_TABLE_NAME, { id: newId }, { id: oldId });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -719,9 +670,3 @@ export class CoreLocalNotificationsProvider {
|
||||||
export class CoreLocalNotifications extends makeSingleton(CoreLocalNotificationsProvider) {}
|
export class CoreLocalNotifications extends makeSingleton(CoreLocalNotificationsProvider) {}
|
||||||
|
|
||||||
export type CoreLocalNotificationsClickCallback<T = unknown> = (value: T) => void;
|
export type CoreLocalNotificationsClickCallback<T = unknown> = (value: T) => void;
|
||||||
|
|
||||||
type CodeRequestsQueueItem = {
|
|
||||||
table: string;
|
|
||||||
id: string;
|
|
||||||
deferreds: PromiseDefer<number>[];
|
|
||||||
};
|
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// 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 { CoreAppSchema } from '@services/app';
|
||||||
|
import { CoreSiteSchema, registerSiteSchema } from '@services/sites';
|
||||||
|
import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
|
||||||
|
import { CoreSite } from '@classes/site';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database variables for CoreSites service.
|
||||||
|
*/
|
||||||
|
export const SITES_TABLE_NAME = 'sites_2';
|
||||||
|
export const CURRENT_SITE_TABLE_NAME = 'current_site';
|
||||||
|
export const SCHEMA_VERSIONS_TABLE_NAME = 'schema_versions';
|
||||||
|
|
||||||
|
// Schema to register in App DB.
|
||||||
|
export const APP_SCHEMA: CoreAppSchema = {
|
||||||
|
name: 'CoreSitesProvider',
|
||||||
|
version: 2,
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: SITES_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'TEXT',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'siteUrl',
|
||||||
|
type: 'TEXT',
|
||||||
|
notNull: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'token',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'info',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'privateToken',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'config',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'loggedOut',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'oauthId',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: CURRENT_SITE_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'INTEGER',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'siteId',
|
||||||
|
type: 'TEXT',
|
||||||
|
notNull: true,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
async migrate(db: SQLiteDB, oldVersion: number): Promise<void> {
|
||||||
|
if (oldVersion < 2) {
|
||||||
|
const newTable = SITES_TABLE_NAME;
|
||||||
|
const oldTable = 'sites';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if V1 table exists.
|
||||||
|
await db.tableExists(oldTable);
|
||||||
|
|
||||||
|
// Move the records from the old table.
|
||||||
|
const sites = await db.getAllRecords<SiteDBEntry>(oldTable);
|
||||||
|
const promises: Promise<number>[] = [];
|
||||||
|
|
||||||
|
sites.forEach((site) => {
|
||||||
|
promises.push(db.insertRecord(newTable, site));
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
|
// Data moved, drop the old table.
|
||||||
|
await db.dropTable(oldTable);
|
||||||
|
} catch (error) {
|
||||||
|
// Old table does not exist, ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Schema to register for Site DB.
|
||||||
|
export const SITE_SCHEMA: CoreSiteSchema = {
|
||||||
|
name: 'CoreSitesProvider',
|
||||||
|
version: 2,
|
||||||
|
canBeCleared: [CoreSite.WS_CACHE_TABLE],
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: CoreSite.WS_CACHE_TABLE,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'TEXT',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'data',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'key',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'expirationTime',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'component',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'componentId',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: CoreSite.CONFIG_TABLE,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: 'TEXT',
|
||||||
|
unique: true,
|
||||||
|
notNull: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'value',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
async migrate(db: SQLiteDB, oldVersion: number): Promise<void> {
|
||||||
|
if (oldVersion && oldVersion < 2) {
|
||||||
|
const newTable = CoreSite.WS_CACHE_TABLE;
|
||||||
|
const oldTable = 'wscache';
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.tableExists(oldTable);
|
||||||
|
} catch (error) {
|
||||||
|
// Old table does not exist, ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Cannot use insertRecordsFrom because there are extra fields, so manually code INSERT INTO.
|
||||||
|
await db.execute(
|
||||||
|
'INSERT INTO ' + newTable + ' ' +
|
||||||
|
'SELECT id, data, key, expirationTime, NULL as component, NULL as componentId ' +
|
||||||
|
'FROM ' + oldTable,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.dropTable(oldTable);
|
||||||
|
} catch (error) {
|
||||||
|
// Error deleting old table, ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Table for site DB to include the schema versions. It's not part of SITE_SCHEMA because it needs to be created first.
|
||||||
|
export const SCHEMA_VERSIONS_TABLE_SCHEMA: SQLiteDBTableSchema = {
|
||||||
|
name: SCHEMA_VERSIONS_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
type: 'TEXT',
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'version',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SiteDBEntry = {
|
||||||
|
id: string;
|
||||||
|
siteUrl: string;
|
||||||
|
token: string;
|
||||||
|
info: string;
|
||||||
|
privateToken: string;
|
||||||
|
config: string;
|
||||||
|
loggedOut: number;
|
||||||
|
oauthId: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CurrentSiteDBEntry = {
|
||||||
|
id: number;
|
||||||
|
siteId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SchemaVersionsDBEntry = {
|
||||||
|
name: string;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const initCoreSitesDB = (): void => {
|
||||||
|
registerSiteSchema(SITE_SCHEMA);
|
||||||
|
};
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { Md5 } from 'ts-md5/dist/md5';
|
import { Md5 } from 'ts-md5/dist/md5';
|
||||||
import { timeout } from 'rxjs/operators';
|
import { timeout } from 'rxjs/operators';
|
||||||
|
|
||||||
import { CoreApp, CoreAppSchema, CoreStoreConfig } from '@services/app';
|
import { CoreApp, CoreStoreConfig } from '@services/app';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import { CoreWS } from '@services/ws';
|
import { CoreWS } from '@services/ws';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
|
@ -38,114 +38,36 @@ import { CoreError } from '@classes/errors/error';
|
||||||
import { CoreSiteError } from '@classes/errors/siteerror';
|
import { CoreSiteError } from '@classes/errors/siteerror';
|
||||||
import { makeSingleton, Translate, Http } from '@singletons/core.singletons';
|
import { makeSingleton, Translate, Http } from '@singletons/core.singletons';
|
||||||
import { CoreLogger } from '@singletons/logger';
|
import { CoreLogger } from '@singletons/logger';
|
||||||
|
import {
|
||||||
|
APP_SCHEMA,
|
||||||
|
SCHEMA_VERSIONS_TABLE_SCHEMA,
|
||||||
|
SITES_TABLE_NAME,
|
||||||
|
CURRENT_SITE_TABLE_NAME,
|
||||||
|
SCHEMA_VERSIONS_TABLE_NAME,
|
||||||
|
SiteDBEntry,
|
||||||
|
CurrentSiteDBEntry,
|
||||||
|
SchemaVersionsDBEntry,
|
||||||
|
} from '@services/sites.db';
|
||||||
|
|
||||||
const SITES_TABLE = 'sites_2';
|
|
||||||
const CURRENT_SITE_TABLE = 'current_site';
|
// Schemas for site tables. Other providers can add schemas in here using the registerSiteSchema function.
|
||||||
const SCHEMA_VERSIONS_TABLE = 'schema_versions';
|
const siteSchemas: { [name: string]: CoreRegisteredSiteSchema } = {};
|
||||||
|
export const registerSiteSchema = (schema: CoreSiteSchema): void => {
|
||||||
|
siteSchemas[schema.name] = schema;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Service to manage and interact with sites.
|
* Service to manage and interact with sites.
|
||||||
* It allows creating tables in the databases of all sites. Each service or component should be responsible of creating
|
* It allows creating tables in the databases of all sites. Each service or component should be responsible of creating
|
||||||
* their own database tables. Example:
|
* their own database tables. Example:
|
||||||
*
|
*
|
||||||
* constructor(sitesProvider: CoreSitesProvider) {
|
* import { registerSiteSchema } from '@services/sites';
|
||||||
* this.sitesProvider.registerSiteSchema(this.tableSchema);
|
|
||||||
*
|
*
|
||||||
* This provider will automatically create the tables in the databases of all the instantiated sites, and also to the
|
* registerSiteSchema(tableSchema);
|
||||||
* databases of sites instantiated from now on.
|
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CoreSitesProvider {
|
export class CoreSitesProvider {
|
||||||
|
|
||||||
// Variables for the database.
|
|
||||||
protected appTablesSchema: CoreAppSchema = {
|
|
||||||
name: 'CoreSitesProvider',
|
|
||||||
version: 2,
|
|
||||||
tables: [
|
|
||||||
{
|
|
||||||
name: SITES_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
type: 'TEXT',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'siteUrl',
|
|
||||||
type: 'TEXT',
|
|
||||||
notNull: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'token',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'info',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'privateToken',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'config',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'loggedOut',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'oauthId',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: CURRENT_SITE_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
type: 'INTEGER',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'siteId',
|
|
||||||
type: 'TEXT',
|
|
||||||
notNull: true,
|
|
||||||
unique: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
async migrate(db: SQLiteDB, oldVersion: number): Promise<void> {
|
|
||||||
if (oldVersion < 2) {
|
|
||||||
const newTable = SITES_TABLE;
|
|
||||||
const oldTable = 'sites';
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Check if V1 table exists.
|
|
||||||
await db.tableExists(oldTable);
|
|
||||||
|
|
||||||
// Move the records from the old table.
|
|
||||||
const sites = await db.getAllRecords<SiteDBEntry>(oldTable);
|
|
||||||
const promises: Promise<number>[] = [];
|
|
||||||
|
|
||||||
sites.forEach((site) => {
|
|
||||||
promises.push(db.insertRecord(newTable, site));
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
|
|
||||||
// Data moved, drop the old table.
|
|
||||||
await db.dropTable(oldTable);
|
|
||||||
} catch (error) {
|
|
||||||
// Old table does not exist, ignore.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Constants to validate a site version.
|
// Constants to validate a site version.
|
||||||
protected readonly WORKPLACE_APP = 3;
|
protected readonly WORKPLACE_APP = 3;
|
||||||
protected readonly MOODLE_APP = 2;
|
protected readonly MOODLE_APP = 2;
|
||||||
|
@ -162,112 +84,15 @@ export class CoreSitesProvider {
|
||||||
protected appDB: SQLiteDB;
|
protected appDB: SQLiteDB;
|
||||||
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
||||||
protected siteSchemasMigration: { [siteId: string]: Promise<void> } = {};
|
protected siteSchemasMigration: { [siteId: string]: Promise<void> } = {};
|
||||||
|
protected pluginsSiteSchemas: { [name: string]: CoreRegisteredSiteSchema } = {};
|
||||||
// Schemas for site tables. Other providers can add schemas in here.
|
|
||||||
protected siteSchemas: { [name: string]: CoreRegisteredSiteSchema } = {};
|
|
||||||
protected siteTablesSchemas: SQLiteDBTableSchema[] = [
|
|
||||||
{
|
|
||||||
name: SCHEMA_VERSIONS_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
type: 'TEXT',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'version',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// Site schema for this provider.
|
|
||||||
protected siteSchema: CoreSiteSchema = {
|
|
||||||
name: 'CoreSitesProvider',
|
|
||||||
version: 2,
|
|
||||||
canBeCleared: [CoreSite.WS_CACHE_TABLE],
|
|
||||||
tables: [
|
|
||||||
{
|
|
||||||
name: CoreSite.WS_CACHE_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
type: 'TEXT',
|
|
||||||
primaryKey: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'data',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'key',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'expirationTime',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'component',
|
|
||||||
type: 'TEXT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'componentId',
|
|
||||||
type: 'INTEGER',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: CoreSite.CONFIG_TABLE,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
type: 'TEXT',
|
|
||||||
unique: true,
|
|
||||||
notNull: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'value',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
async migrate(db: SQLiteDB, oldVersion: number): Promise<void> {
|
|
||||||
if (oldVersion && oldVersion < 2) {
|
|
||||||
const newTable = CoreSite.WS_CACHE_TABLE;
|
|
||||||
const oldTable = 'wscache';
|
|
||||||
|
|
||||||
try {
|
|
||||||
await db.tableExists(oldTable);
|
|
||||||
} catch (error) {
|
|
||||||
// Old table does not exist, ignore.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Cannot use insertRecordsFrom because there are extra fields, so manually code INSERT INTO.
|
|
||||||
await db.execute(
|
|
||||||
'INSERT INTO ' + newTable + ' ' +
|
|
||||||
'SELECT id, data, key, expirationTime, NULL as component, NULL as componentId ' +
|
|
||||||
'FROM ' + oldTable,
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await db.dropTable(oldTable);
|
|
||||||
} catch (error) {
|
|
||||||
// Error deleting old table, ignore.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.logger = CoreLogger.getInstance('CoreSitesProvider');
|
this.logger = CoreLogger.getInstance('CoreSitesProvider');
|
||||||
|
|
||||||
this.appDB = CoreApp.instance.getDB();
|
this.appDB = CoreApp.instance.getDB();
|
||||||
this.dbReady = CoreApp.instance.createTablesFromSchema(this.appTablesSchema).catch(() => {
|
this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
this.registerSiteSchema(this.siteSchema);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -857,7 +682,7 @@ export class CoreSitesProvider {
|
||||||
oauthId,
|
oauthId,
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.appDB.insertRecord(SITES_TABLE, entry);
|
await this.appDB.insertRecord(SITES_TABLE_NAME, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1084,7 +909,7 @@ export class CoreSitesProvider {
|
||||||
delete this.sites[siteId];
|
delete this.sites[siteId];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.appDB.deleteRecords(SITES_TABLE, { id: siteId });
|
await this.appDB.deleteRecords(SITES_TABLE_NAME, { id: siteId });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// DB remove shouldn't fail, but we'll go ahead even if it does.
|
// DB remove shouldn't fail, but we'll go ahead even if it does.
|
||||||
}
|
}
|
||||||
|
@ -1103,7 +928,7 @@ export class CoreSitesProvider {
|
||||||
async hasSites(): Promise<boolean> {
|
async hasSites(): Promise<boolean> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
const count = await this.appDB.countRecords(SITES_TABLE);
|
const count = await this.appDB.countRecords(SITES_TABLE_NAME);
|
||||||
|
|
||||||
return count > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
|
@ -1129,7 +954,7 @@ export class CoreSitesProvider {
|
||||||
return this.sites[siteId];
|
return this.sites[siteId];
|
||||||
} else {
|
} else {
|
||||||
// Retrieve and create the site.
|
// Retrieve and create the site.
|
||||||
const data = await this.appDB.getRecord<SiteDBEntry>(SITES_TABLE, { id: siteId });
|
const data = await this.appDB.getRecord<SiteDBEntry>(SITES_TABLE_NAME, { id: siteId });
|
||||||
|
|
||||||
return this.makeSiteFromSiteListEntry(data);
|
return this.makeSiteFromSiteListEntry(data);
|
||||||
}
|
}
|
||||||
|
@ -1202,7 +1027,7 @@ export class CoreSitesProvider {
|
||||||
async getSites(ids?: string[]): Promise<CoreSiteBasicInfo[]> {
|
async getSites(ids?: string[]): Promise<CoreSiteBasicInfo[]> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
const sites = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE);
|
const sites = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE_NAME);
|
||||||
|
|
||||||
const formattedSites: CoreSiteBasicInfo[] = [];
|
const formattedSites: CoreSiteBasicInfo[] = [];
|
||||||
sites.forEach((site) => {
|
sites.forEach((site) => {
|
||||||
|
@ -1266,7 +1091,7 @@ export class CoreSitesProvider {
|
||||||
async getLoggedInSitesIds(): Promise<string[]> {
|
async getLoggedInSitesIds(): Promise<string[]> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
const sites = await this.appDB.getRecords<SiteDBEntry>(SITES_TABLE, { loggedOut : 0 });
|
const sites = await this.appDB.getRecords<SiteDBEntry>(SITES_TABLE_NAME, { loggedOut : 0 });
|
||||||
|
|
||||||
return sites.map((site) => site.id);
|
return sites.map((site) => site.id);
|
||||||
}
|
}
|
||||||
|
@ -1279,7 +1104,7 @@ export class CoreSitesProvider {
|
||||||
async getSitesIds(): Promise<string[]> {
|
async getSitesIds(): Promise<string[]> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
const sites = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE);
|
const sites = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE_NAME);
|
||||||
|
|
||||||
return sites.map((site) => site.id);
|
return sites.map((site) => site.id);
|
||||||
}
|
}
|
||||||
|
@ -1298,7 +1123,7 @@ export class CoreSitesProvider {
|
||||||
siteId,
|
siteId,
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.appDB.insertRecord(CURRENT_SITE_TABLE, entry);
|
await this.appDB.insertRecord(CURRENT_SITE_TABLE_NAME, entry);
|
||||||
|
|
||||||
CoreEvents.trigger(CoreEvents.LOGIN, {}, siteId);
|
CoreEvents.trigger(CoreEvents.LOGIN, {}, siteId);
|
||||||
}
|
}
|
||||||
|
@ -1324,7 +1149,7 @@ export class CoreSitesProvider {
|
||||||
promises.push(this.setSiteLoggedOut(siteId, true));
|
promises.push(this.setSiteLoggedOut(siteId, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
promises.push(this.appDB.deleteRecords(CURRENT_SITE_TABLE, { id: 1 }));
|
promises.push(this.appDB.deleteRecords(CURRENT_SITE_TABLE_NAME, { id: 1 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -1349,7 +1174,7 @@ export class CoreSitesProvider {
|
||||||
this.sessionRestored = true;
|
this.sessionRestored = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currentSite = await this.appDB.getRecord<CurrentSiteDBEntry>(CURRENT_SITE_TABLE, { id: 1 });
|
const currentSite = await this.appDB.getRecord<CurrentSiteDBEntry>(CURRENT_SITE_TABLE_NAME, { id: 1 });
|
||||||
const siteId = currentSite.siteId;
|
const siteId = currentSite.siteId;
|
||||||
this.logger.debug(`Restore session in site ${siteId}`);
|
this.logger.debug(`Restore session in site ${siteId}`);
|
||||||
|
|
||||||
|
@ -1377,7 +1202,7 @@ export class CoreSitesProvider {
|
||||||
|
|
||||||
site.setLoggedOut(loggedOut);
|
site.setLoggedOut(loggedOut);
|
||||||
|
|
||||||
await this.appDB.updateRecords(SITES_TABLE, newValues, { id: siteId });
|
await this.appDB.updateRecords(SITES_TABLE_NAME, newValues, { id: siteId });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1426,7 +1251,7 @@ export class CoreSitesProvider {
|
||||||
site.privateToken = privateToken;
|
site.privateToken = privateToken;
|
||||||
site.setLoggedOut(false); // Token updated means the user authenticated again, not logged out anymore.
|
site.setLoggedOut(false); // Token updated means the user authenticated again, not logged out anymore.
|
||||||
|
|
||||||
await this.appDB.updateRecords(SITES_TABLE, newValues, { id: siteId });
|
await this.appDB.updateRecords(SITES_TABLE_NAME, newValues, { id: siteId });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1470,7 +1295,7 @@ export class CoreSitesProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.appDB.updateRecords(SITES_TABLE, newValues, { id: siteId });
|
await this.appDB.updateRecords(SITES_TABLE_NAME, newValues, { id: siteId });
|
||||||
} finally {
|
} finally {
|
||||||
CoreEvents.trigger(CoreEvents.SITE_UPDATED, info, siteId);
|
CoreEvents.trigger(CoreEvents.SITE_UPDATED, info, siteId);
|
||||||
}
|
}
|
||||||
|
@ -1529,7 +1354,7 @@ export class CoreSitesProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const siteEntries = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE);
|
const siteEntries = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE_NAME);
|
||||||
const ids: string[] = [];
|
const ids: string[] = [];
|
||||||
const promises: Promise<unknown>[] = [];
|
const promises: Promise<unknown>[] = [];
|
||||||
|
|
||||||
|
@ -1562,7 +1387,7 @@ export class CoreSitesProvider {
|
||||||
async getStoredCurrentSiteId(): Promise<string> {
|
async getStoredCurrentSiteId(): Promise<string> {
|
||||||
await this.dbReady;
|
await this.dbReady;
|
||||||
|
|
||||||
const currentSite = await this.appDB.getRecord<CurrentSiteDBEntry>(CURRENT_SITE_TABLE, { id: 1 });
|
const currentSite = await this.appDB.getRecord<CurrentSiteDBEntry>(CURRENT_SITE_TABLE_NAME, { id: 1 });
|
||||||
|
|
||||||
return currentSite.siteId;
|
return currentSite.siteId;
|
||||||
}
|
}
|
||||||
|
@ -1605,32 +1430,6 @@ export class CoreSitesProvider {
|
||||||
return this.getSite(siteId).then((site) => site.isFeatureDisabled(name));
|
return this.getSite(siteId).then((site) => site.isFeatureDisabled(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a table in all the sites databases.
|
|
||||||
*
|
|
||||||
* @param table Table schema.
|
|
||||||
* @deprecated. Please use registerSiteSchema instead.
|
|
||||||
*/
|
|
||||||
createTableFromSchema(table: SQLiteDBTableSchema): void {
|
|
||||||
this.createTablesFromSchema([table]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create several tables in all the sites databases.
|
|
||||||
*
|
|
||||||
* @param tables List of tables schema.
|
|
||||||
* @deprecated. Please use registerSiteSchema instead.
|
|
||||||
*/
|
|
||||||
createTablesFromSchema(tables: SQLiteDBTableSchema[]): void {
|
|
||||||
// Add the tables to the list of schemas. This list is to create all the tables in new sites.
|
|
||||||
this.siteTablesSchemas = this.siteTablesSchemas.concat(tables);
|
|
||||||
|
|
||||||
// Now create these tables in current sites.
|
|
||||||
for (const id in this.sites) {
|
|
||||||
this.sites[id].getDb().createTablesFromSchema(tables);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a WS is available in the current site, if any.
|
* Check if a WS is available in the current site, if any.
|
||||||
*
|
*
|
||||||
|
@ -1645,40 +1444,29 @@ export class CoreSitesProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a site schema.
|
* Register a site schema in current site.
|
||||||
|
* This function is meant for site plugins to create DB tables in current site. Tables created from within the app
|
||||||
|
* whould use the registerSiteSchema function exported in this same file.
|
||||||
*
|
*
|
||||||
* @param schema The schema to register.
|
* @param schema The schema to register.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
async registerSiteSchema(schema: CoreSiteSchema): Promise<void> {
|
async registerSiteSchema(schema: CoreSiteSchema): Promise<void> {
|
||||||
if (this.currentSite) {
|
if (!this.currentSite) {
|
||||||
try {
|
return;
|
||||||
// Site has already been created, apply the schema directly.
|
}
|
||||||
const schemas: {[name: string]: CoreRegisteredSiteSchema} = {};
|
|
||||||
schemas[schema.name] = schema;
|
|
||||||
|
|
||||||
if (!schema.onlyCurrentSite) {
|
try {
|
||||||
// Apply it to all sites.
|
// Site has already been created, apply the schema directly.
|
||||||
const siteIds = await this.getSitesIds();
|
const schemas: {[name: string]: CoreRegisteredSiteSchema} = {};
|
||||||
|
schemas[schema.name] = schema;
|
||||||
|
|
||||||
await Promise.all(siteIds.map(async (siteId) => {
|
// Apply it to the specified site only.
|
||||||
const site = await this.getSite(siteId);
|
(schema as CoreRegisteredSiteSchema).siteId = this.currentSite.getId();
|
||||||
|
|
||||||
return this.applySiteSchemas(site, schemas);
|
await this.applySiteSchemas(this.currentSite, schemas);
|
||||||
}));
|
} finally {
|
||||||
} else {
|
this.pluginsSiteSchemas[schema.name] = schema;
|
||||||
// Apply it to the specified site only.
|
|
||||||
(schema as CoreRegisteredSiteSchema).siteId = this.currentSite.getId();
|
|
||||||
|
|
||||||
await this.applySiteSchemas(this.currentSite, schemas);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
// Add the schema to the list. It's done in the end to prevent a schema being applied twice.
|
|
||||||
this.siteSchemas[schema.name] = schema;
|
|
||||||
}
|
|
||||||
} else if (!schema.onlyCurrentSite) {
|
|
||||||
// Add the schema to the list, it will be applied when the sites are created.
|
|
||||||
this.siteSchemas[schema.name] = schema;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1700,8 +1488,8 @@ export class CoreSitesProvider {
|
||||||
this.logger.debug(`Migrating all schemas of ${site.id}`);
|
this.logger.debug(`Migrating all schemas of ${site.id}`);
|
||||||
|
|
||||||
// First create tables not registerd with name/version.
|
// First create tables not registerd with name/version.
|
||||||
const promise = site.getDb().createTablesFromSchema(this.siteTablesSchemas)
|
const promise = site.getDb().createTableFromSchema(SCHEMA_VERSIONS_TABLE_SCHEMA)
|
||||||
.then(() => this.applySiteSchemas(site, this.siteSchemas));
|
.then(() => this.applySiteSchemas(site, siteSchemas));
|
||||||
|
|
||||||
this.siteSchemasMigration[site.id] = promise;
|
this.siteSchemasMigration[site.id] = promise;
|
||||||
|
|
||||||
|
@ -1721,7 +1509,7 @@ export class CoreSitesProvider {
|
||||||
const db = site.getDb();
|
const db = site.getDb();
|
||||||
|
|
||||||
// Fetch installed versions of the schema.
|
// Fetch installed versions of the schema.
|
||||||
const records = await db.getAllRecords<SchemaVersionsDBEntry>(SCHEMA_VERSIONS_TABLE);
|
const records = await db.getAllRecords<SchemaVersionsDBEntry>(SCHEMA_VERSIONS_TABLE_NAME);
|
||||||
|
|
||||||
const versions: {[name: string]: number} = {};
|
const versions: {[name: string]: number} = {};
|
||||||
records.forEach((record) => {
|
records.forEach((record) => {
|
||||||
|
@ -1768,7 +1556,7 @@ export class CoreSitesProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set installed version.
|
// Set installed version.
|
||||||
await db.insertRecord(SCHEMA_VERSIONS_TABLE, { name, version: schema.version });
|
await db.insertRecord(SCHEMA_VERSIONS_TABLE_NAME, { name, version: schema.version });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1814,13 +1602,13 @@ export class CoreSitesProvider {
|
||||||
*/
|
*/
|
||||||
getSiteTableSchemasToClear(site: CoreSite): string[] {
|
getSiteTableSchemasToClear(site: CoreSite): string[] {
|
||||||
let reset: string[] = [];
|
let reset: string[] = [];
|
||||||
for (const name in this.siteSchemas) {
|
const schemas = Object.values(siteSchemas).concat(Object.values(this.pluginsSiteSchemas));
|
||||||
const schema = this.siteSchemas[name];
|
|
||||||
|
|
||||||
|
schemas.forEach((schema) => {
|
||||||
if (schema.canBeCleared && (!schema.siteId || site.getId() == schema.siteId)) {
|
if (schema.canBeCleared && (!schema.siteId || site.getId() == schema.siteId)) {
|
||||||
reset = reset.concat(schema.canBeCleared);
|
reset = reset.concat(schema.canBeCleared);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
return reset;
|
return reset;
|
||||||
}
|
}
|
||||||
|
@ -1980,12 +1768,6 @@ export type CoreSiteSchema = {
|
||||||
*/
|
*/
|
||||||
canBeCleared?: string[];
|
canBeCleared?: string[];
|
||||||
|
|
||||||
/**
|
|
||||||
* If true, the schema will only be applied to the current site. Otherwise it will be applied to all sites.
|
|
||||||
* If you're implementing a site plugin, please set it to true.
|
|
||||||
*/
|
|
||||||
onlyCurrentSite?: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tables to create when installing or upgrading the schema.
|
* Tables to create when installing or upgrading the schema.
|
||||||
*/
|
*/
|
||||||
|
@ -2088,24 +1870,3 @@ export type CoreSitesLoginTokenResponse = {
|
||||||
debuginfo?: string;
|
debuginfo?: string;
|
||||||
reproductionlink?: string;
|
reproductionlink?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SiteDBEntry = {
|
|
||||||
id: string;
|
|
||||||
siteUrl: string;
|
|
||||||
token: string;
|
|
||||||
info: string;
|
|
||||||
privateToken: string;
|
|
||||||
config: string;
|
|
||||||
loggedOut: number;
|
|
||||||
oauthId: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type CurrentSiteDBEntry = {
|
|
||||||
id: number;
|
|
||||||
siteId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SchemaVersionsDBEntry = {
|
|
||||||
name: string;
|
|
||||||
version: number;
|
|
||||||
};
|
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||||
|
//
|
||||||
|
// 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 { CoreSiteSchema, registerSiteSchema } from '@services/sites';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database variables for CoreSync service.
|
||||||
|
*/
|
||||||
|
export const SYNC_TABLE_NAME = 'sync';
|
||||||
|
export const SITE_SCHEMA: CoreSiteSchema = {
|
||||||
|
name: 'CoreSyncProvider',
|
||||||
|
version: 1,
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: SYNC_TABLE_NAME,
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'component',
|
||||||
|
type: 'TEXT',
|
||||||
|
notNull: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
type: 'TEXT',
|
||||||
|
notNull: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'time',
|
||||||
|
type: 'INTEGER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'warnings',
|
||||||
|
type: 'TEXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
primaryKeys: ['component', 'id'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CoreSyncRecord = {
|
||||||
|
component: string;
|
||||||
|
id: string;
|
||||||
|
time: number;
|
||||||
|
warnings: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const initCoreSyncDB = (): void => {
|
||||||
|
registerSiteSchema(SITE_SCHEMA);
|
||||||
|
};
|
||||||
|
|
|
@ -16,8 +16,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { CoreEvents } from '@singletons/events';
|
import { CoreEvents } from '@singletons/events';
|
||||||
import { CoreSites, CoreSiteSchema } from '@services/sites';
|
import { CoreSites, CoreSiteSchema } from '@services/sites';
|
||||||
import { makeSingleton } from '@singletons/core.singletons';
|
import { makeSingleton } from '@singletons/core.singletons';
|
||||||
|
import { SYNC_TABLE_NAME, CoreSyncRecord } from '@services/sync.db';
|
||||||
const SYNC_TABLE = 'sync';
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Service that provides some features regarding synchronization.
|
* Service that provides some features regarding synchronization.
|
||||||
|
@ -31,7 +30,7 @@ export class CoreSyncProvider {
|
||||||
version: 1,
|
version: 1,
|
||||||
tables: [
|
tables: [
|
||||||
{
|
{
|
||||||
name: SYNC_TABLE,
|
name: SYNC_TABLE_NAME,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'component',
|
name: 'component',
|
||||||
|
@ -61,8 +60,6 @@ export class CoreSyncProvider {
|
||||||
protected blockedItems: { [siteId: string]: { [blockId: string]: { [operation: string]: boolean } } } = {};
|
protected blockedItems: { [siteId: string]: { [blockId: string]: { [operation: string]: boolean } } } = {};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
CoreSites.instance.registerSiteSchema(this.siteSchema);
|
|
||||||
|
|
||||||
// Unblock all blocks on logout.
|
// Unblock all blocks on logout.
|
||||||
CoreEvents.on(CoreEvents.LOGOUT, (data: {siteId: string}) => {
|
CoreEvents.on(CoreEvents.LOGOUT, (data: {siteId: string}) => {
|
||||||
this.clearAllBlocks(data.siteId);
|
this.clearAllBlocks(data.siteId);
|
||||||
|
@ -133,7 +130,7 @@ export class CoreSyncProvider {
|
||||||
* @return Record if found or reject.
|
* @return Record if found or reject.
|
||||||
*/
|
*/
|
||||||
getSyncRecord(component: string, id: string | number, siteId?: string): Promise<CoreSyncRecord> {
|
getSyncRecord(component: string, id: string | number, siteId?: string): Promise<CoreSyncRecord> {
|
||||||
return CoreSites.instance.getSiteDb(siteId).then((db) => db.getRecord(SYNC_TABLE, { component: component, id: id }));
|
return CoreSites.instance.getSiteDb(siteId).then((db) => db.getRecord(SYNC_TABLE_NAME, { component: component, id: id }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,7 +148,7 @@ export class CoreSyncProvider {
|
||||||
data.component = component;
|
data.component = component;
|
||||||
data.id = id;
|
data.id = id;
|
||||||
|
|
||||||
await db.insertRecord(SYNC_TABLE, data);
|
await db.insertRecord(SYNC_TABLE_NAME, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -211,10 +208,3 @@ export class CoreSyncProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CoreSync extends makeSingleton(CoreSyncProvider) {}
|
export class CoreSync extends makeSingleton(CoreSyncProvider) {}
|
||||||
|
|
||||||
export type CoreSyncRecord = {
|
|
||||||
component: string;
|
|
||||||
id: string;
|
|
||||||
time: number;
|
|
||||||
warnings: string;
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in New Issue