forked from EVOgeek/Vmeda.Online
		
	MOBILE-3565 services: Move some DB vars and init to new files
This commit is contained in:
		
							parent
							
								
									03f9723329
								
							
						
					
					
						commit
						6df1c2109d
					
				| @ -50,6 +50,11 @@ import { CoreTimeUtilsProvider } from '@services/utils/time'; | ||||
| import { CoreUrlUtilsProvider } from '@services/utils/url'; | ||||
| 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 { CoreEmulatorModule } from '@core/emulator/emulator.module'; | ||||
| import { CoreLoginModule } from '@core/login/login.module'; | ||||
| @ -121,6 +126,8 @@ export class AppModule { | ||||
|         // Set the injector.
 | ||||
|         setSingletonsInjector(injector); | ||||
| 
 | ||||
|         this.initCoreServicesDB(); | ||||
| 
 | ||||
|         // Register a handler for platform ready.
 | ||||
|         CoreInit.instance.registerProcess({ | ||||
|             name: 'CorePlatformReady', | ||||
| @ -154,4 +161,13 @@ export class AppModule { | ||||
|         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). | ||||
|  * 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. | ||||
|  * | ||||
|  * @todo: Refactor this class to improve "temporary" sites support (not fully authenticated). | ||||
|  | ||||
							
								
								
									
										41
									
								
								src/app/services/app.db.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/app/services/app.db.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 { CoreLogger } from '@singletons/logger'; | ||||
| 
 | ||||
| const DBNAME = 'MoodleMobile'; | ||||
| const SCHEMA_VERSIONS_TABLE = 'schema_versions'; | ||||
| import { DBNAME, SCHEMA_VERSIONS_TABLE_NAME, SCHEMA_VERSIONS_TABLE_SCHEMA, SchemaVersionsDBEntry } from '@services/app.db'; | ||||
| 
 | ||||
| /** | ||||
|  * Factory to provide some global functionalities, like access to the global app database. | ||||
| @ -57,27 +55,13 @@ export class CoreAppProvider { | ||||
| 
 | ||||
|     // Variables for DB.
 | ||||
|     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) { | ||||
|         this.logger = CoreLogger.getInstance('CoreAppProvider'); | ||||
|         this.db = CoreDB.instance.getDB(DBNAME); | ||||
| 
 | ||||
|         // 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) => { | ||||
|             // Execute the callback in the Angular zone, so change detection doesn't stop working.
 | ||||
| @ -175,7 +159,7 @@ export class CoreAppProvider { | ||||
|             await this.createVersionsTableReady; | ||||
| 
 | ||||
|             // 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; | ||||
|         } catch (error) { | ||||
| @ -198,7 +182,7 @@ export class CoreAppProvider { | ||||
|         } | ||||
| 
 | ||||
|         // 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; | ||||
|     appRef?: ApplicationRef; | ||||
| }; | ||||
| 
 | ||||
| type SchemaVersionsDBEntry = { | ||||
|     name: string; | ||||
|     version: number; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										47
									
								
								src/app/services/config.db.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/app/services/config.db.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 { CoreApp, CoreAppSchema } from '@services/app'; | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { SQLiteDB } from '@classes/sqlitedb'; | ||||
| import { makeSingleton } from '@singletons/core.singletons'; | ||||
| 
 | ||||
| const TABLE_NAME = 'core_config'; | ||||
| import { CONFIG_TABLE_NAME, APP_SCHEMA, ConfigDBEntry } from '@services/config.db'; | ||||
| 
 | ||||
| /** | ||||
|  * Factory to provide access to dynamic and permanent config and settings. | ||||
| @ -28,32 +27,11 @@ const TABLE_NAME = 'core_config'; | ||||
| export class CoreConfigProvider { | ||||
| 
 | ||||
|     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.
 | ||||
| 
 | ||||
|     constructor() { | ||||
|         this.appDB = CoreApp.instance.getDB(); | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(this.tableSchema).catch(() => { | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => { | ||||
|             // Ignore errors.
 | ||||
|         }); | ||||
|     } | ||||
| @ -67,7 +45,7 @@ export class CoreConfigProvider { | ||||
|     async delete(name: string): Promise<void> { | ||||
|         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; | ||||
| 
 | ||||
|         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; | ||||
|         } catch (error) { | ||||
| @ -103,15 +81,9 @@ export class CoreConfigProvider { | ||||
|     async set(name: string, value: number | string): Promise<void> { | ||||
|         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) {} | ||||
| 
 | ||||
| type ConfigDBEntry = { | ||||
|     name: string; | ||||
|     // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | ||||
|     value: any; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										45
									
								
								src/app/services/cron.db.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/app/services/cron.db.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 { CoreApp, CoreAppProvider, CoreAppSchema } from '@services/app'; | ||||
| import { CoreApp, CoreAppProvider } from '@services/app'; | ||||
| import { CoreConfig } from '@services/config'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { CoreConstants } from '@core/constants'; | ||||
| @ -23,8 +23,7 @@ import { CoreError } from '@classes/errors/error'; | ||||
| 
 | ||||
| import { makeSingleton, Network } from '@singletons/core.singletons'; | ||||
| import { CoreLogger } from '@singletons/logger'; | ||||
| 
 | ||||
| const CRON_TABLE = 'cron'; | ||||
| import { APP_SCHEMA, CRON_TABLE_NAME, CronDBEntry } from '@services/cron.db'; | ||||
| 
 | ||||
| /* | ||||
|  * 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 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 appDB: SQLiteDB; | ||||
|     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.appDB = CoreApp.instance.getDB(); | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(this.tableSchema).catch(() => { | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => { | ||||
|             // Ignore errors.
 | ||||
|         }); | ||||
| 
 | ||||
| @ -268,7 +245,7 @@ export class CoreCronDelegate { | ||||
|         const id = this.getHandlerLastExecutionId(name); | ||||
| 
 | ||||
|         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); | ||||
| 
 | ||||
| @ -431,7 +408,7 @@ export class CoreCronDelegate { | ||||
|             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 & { | ||||
|     cronProvider?: CoreCronDelegate; | ||||
| }; | ||||
| 
 | ||||
| type CronDBEntry = { | ||||
|     id: string; | ||||
|     value: number; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										367
									
								
								src/app/services/filepool.db.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								src/app/services/filepool.db.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 { Md5 } from 'ts-md5/dist/md5'; | ||||
| 
 | ||||
| import { CoreApp, CoreAppSchema } from '@services/app'; | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreEvents } from '@singletons/events'; | ||||
| import { CoreFile } from '@services/file'; | ||||
| import { CoreInit } from '@services/init'; | ||||
| 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 { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreMimetypeUtils } from '@services/utils/mimetype'; | ||||
| @ -33,6 +33,20 @@ import { CoreError } from '@classes/errors/error'; | ||||
| import { CoreConstants } from '@core/constants'; | ||||
| import { makeSingleton, Network, NgZone, Translate } from '@singletons/core.singletons'; | ||||
| 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. | ||||
| @ -60,182 +74,6 @@ export class CoreFilepoolProvider { | ||||
|     protected static readonly FILE_UPDATE_UNKNOWN_WHERE_CLAUSE = | ||||
|         '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 appDB: SQLiteDB; | ||||
|     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.appDB = CoreApp.instance.getDB(); | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(this.appTablesSchema).catch(() => { | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => { | ||||
|             // Ignore errors.
 | ||||
|         }); | ||||
| 
 | ||||
|         CoreSites.instance.registerSiteSchema(this.siteSchema); | ||||
| 
 | ||||
|         this.init(); | ||||
|     } | ||||
| 
 | ||||
| @ -308,7 +144,7 @@ export class CoreFilepoolProvider { | ||||
|             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); | ||||
| 
 | ||||
|         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`); | ||||
| 
 | ||||
|         await this.appDB.insertRecord(CoreFilepoolProvider.QUEUE_TABLE, { | ||||
|         await this.appDB.insertRecord(QUEUE_TABLE_NAME, { | ||||
|             siteId, | ||||
|             fileId, | ||||
|             url, | ||||
| @ -563,7 +399,7 @@ export class CoreFilepoolProvider { | ||||
|             // Update only when required.
 | ||||
|             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)); | ||||
|         } | ||||
| 
 | ||||
| @ -692,9 +528,9 @@ export class CoreFilepoolProvider { | ||||
| 
 | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
|         // 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.
 | ||||
|         await site.getDb().deleteRecords(CoreFilepoolProvider.PACKAGES_TABLE); | ||||
|         await site.getDb().deleteRecords(PACKAGES_TABLE_NAME); | ||||
| 
 | ||||
|         entries.forEach((entry) => { | ||||
|             // Trigger module status changed, setting it as not downloaded.
 | ||||
| @ -712,8 +548,8 @@ export class CoreFilepoolProvider { | ||||
|         const db = await CoreSites.instance.getSiteDb(siteId); | ||||
| 
 | ||||
|         await Promise.all([ | ||||
|             db.deleteRecords(CoreFilepoolProvider.FILES_TABLE), | ||||
|             db.deleteRecords(CoreFilepoolProvider.LINKS_TABLE), | ||||
|             db.deleteRecords(FILES_TABLE_NAME), | ||||
|             db.deleteRecords(LINKS_TABLE_NAME), | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
| @ -732,7 +568,7 @@ export class CoreFilepoolProvider { | ||||
|             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) { | ||||
|             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.
 | ||||
|             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; | ||||
|         } | ||||
| @ -1267,7 +1103,7 @@ export class CoreFilepoolProvider { | ||||
|         entry.fileId = CoreMimetypeUtils.instance.removeExtension(fileId); | ||||
|         entry.extension = extension; | ||||
| 
 | ||||
|         await db.updateRecords(CoreFilepoolProvider.FILES_TABLE, entry, { fileId }); | ||||
|         await db.updateRecords(FILES_TABLE_NAME, entry, { fileId }); | ||||
|         if (entry.fileId == fileId) { | ||||
|             // File ID hasn't changed, we're done.
 | ||||
|             this.logger.debug('Removed extesion ' + extension + ' from file ' + entry.fileId); | ||||
| @ -1276,7 +1112,7 @@ export class CoreFilepoolProvider { | ||||
|         } | ||||
| 
 | ||||
|         // 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), | ||||
|         }; | ||||
| 
 | ||||
|         const items = await db.getRecords<CoreFilepoolLinksRecord>(CoreFilepoolProvider.LINKS_TABLE, conditions); | ||||
|         const items = await db.getRecords<CoreFilepoolLinksRecord>(LINKS_TABLE_NAME, conditions); | ||||
|         items.forEach((item) => { | ||||
|             item.componentId = this.fixComponentId(item.componentId); | ||||
|         }); | ||||
| @ -1449,7 +1285,7 @@ export class CoreFilepoolProvider { | ||||
|      */ | ||||
|     protected async getFileLinks(siteId: string, fileId: string): Promise<CoreFilepoolLinksRecord[]> { | ||||
|         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) => { | ||||
|             item.componentId = this.fixComponentId(item.componentId); | ||||
| @ -1527,7 +1363,7 @@ export class CoreFilepoolProvider { | ||||
|         await Promise.all(items.map(async (item) => { | ||||
|             try { | ||||
|                 const fileEntry = await db.getRecord<CoreFilepoolFileEntry>( | ||||
|                     CoreFilepoolProvider.FILES_TABLE, | ||||
|                     FILES_TABLE_NAME, | ||||
|                     { fileId: item.fileId }, | ||||
|                 ); | ||||
| 
 | ||||
| @ -1808,7 +1644,7 @@ export class CoreFilepoolProvider { | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
|         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> { | ||||
|         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') { | ||||
|             throw new CoreError('File not found in filepool.'); | ||||
| @ -2277,7 +2113,7 @@ export class CoreFilepoolProvider { | ||||
|     protected async hasFileInQueue(siteId: string, fileId: string): Promise<CoreFilepoolQueueEntry> { | ||||
|         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') { | ||||
|             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; | ||||
| 
 | ||||
|         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); | ||||
| 
 | ||||
|         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 + ')'; | ||||
|         } | ||||
| 
 | ||||
|         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 { | ||||
|             items = await this.appDB.getRecords<CoreFilepoolQueueEntry>( | ||||
|                 CoreFilepoolProvider.QUEUE_TABLE, | ||||
|                 QUEUE_TABLE_NAME, | ||||
|                 undefined, | ||||
|                 'priority DESC, added ASC', | ||||
|                 undefined, | ||||
| @ -2760,7 +2596,7 @@ export class CoreFilepoolProvider { | ||||
|     protected async removeFromQueue(siteId: string, fileId: string): Promise<void> { | ||||
|         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>[] = []; | ||||
| 
 | ||||
|         // Remove entry from filepool store.
 | ||||
|         promises.push(db.deleteRecords(CoreFilepoolProvider.FILES_TABLE, conditions)); | ||||
|         promises.push(db.deleteRecords(FILES_TABLE_NAME, conditions)); | ||||
| 
 | ||||
|         // Remove links.
 | ||||
|         promises.push(db.deleteRecords(CoreFilepoolProvider.LINKS_TABLE, conditions)); | ||||
|         promises.push(db.deleteRecords(LINKS_TABLE_NAME, conditions)); | ||||
| 
 | ||||
|         // Remove the file.
 | ||||
|         if (CoreFile.instance.isAvailable()) { | ||||
| @ -2885,7 +2721,7 @@ export class CoreFilepoolProvider { | ||||
|         const packageId = this.getPackageId(component, componentId); | ||||
| 
 | ||||
|         // 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 = {}; | ||||
|         if (entry.status == CoreConstants.DOWNLOADING) { | ||||
|             // Going back from downloading to previous status, restore previous download time.
 | ||||
| @ -2895,7 +2731,7 @@ export class CoreFilepoolProvider { | ||||
|         newData.updated = Date.now(); | ||||
|         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.
 | ||||
|         this.triggerPackageStatusChanged(site.id!, newData.status, component, componentId); | ||||
| 
 | ||||
| @ -2973,7 +2809,7 @@ export class CoreFilepoolProvider { | ||||
|         let previousStatus: string | undefined; | ||||
|         // Search current status to set it as previous status.
 | ||||
|         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) { | ||||
|                 extra = entry.extra; | ||||
|             } | ||||
| @ -3008,7 +2844,7 @@ export class CoreFilepoolProvider { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         await site.getDb().insertRecord(CoreFilepoolProvider.PACKAGES_TABLE, packageEntry); | ||||
|         await site.getDb().insertRecord(PACKAGES_TABLE_NAME, packageEntry); | ||||
| 
 | ||||
|         // Success inserting, trigger event.
 | ||||
|         this.triggerPackageStatusChanged(siteId, status, component, componentId); | ||||
| @ -3132,7 +2968,7 @@ export class CoreFilepoolProvider { | ||||
|         const packageId = this.getPackageId(component, componentId); | ||||
| 
 | ||||
|         await site.getDb().updateRecords( | ||||
|             CoreFilepoolProvider.PACKAGES_TABLE, | ||||
|             PACKAGES_TABLE_NAME, | ||||
|             { downloadTime: CoreTimeUtils.instance.timestamp() }, | ||||
|             { id: packageId }, | ||||
|         ); | ||||
| @ -3142,166 +2978,6 @@ export class 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. | ||||
|  */ | ||||
| @ -3359,14 +3035,5 @@ type CoreFilepoolPromiseDefer = PromiseDefer<void> & { | ||||
|     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 = | ||||
|     HTMLAnchorElement | HTMLImageElement | HTMLAudioElement | HTMLVideoElement | HTMLSourceElement | HTMLTrackElement; | ||||
|  | ||||
							
								
								
									
										80
									
								
								src/app/services/local-notifications.db.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/app/services/local-notifications.db.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 { ILocalNotification } from '@ionic-native/local-notifications'; | ||||
| 
 | ||||
| import { CoreApp, CoreAppSchema } from '@services/app'; | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreConfig } from '@services/config'; | ||||
| import { CoreEventObserver, CoreEvents } from '@singletons/events'; | ||||
| 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 { CoreSite } from '@classes/site'; | ||||
| import { CoreQueueRunner } from '@classes/queue-runner'; | ||||
| @ -28,6 +28,13 @@ import { CoreError } from '@classes/errors/error'; | ||||
| import { CoreConstants } from '@core/constants'; | ||||
| import { makeSingleton, NgZone, Platform, Translate, LocalNotifications, Push, Device } from '@singletons/core.singletons'; | ||||
| 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. | ||||
| @ -35,62 +42,6 @@ import { CoreLogger } from '@singletons/logger'; | ||||
| @Injectable() | ||||
| 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 appDB: SQLiteDB; | ||||
|     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.queueRunner = new CoreQueueRunner(10); | ||||
|         this.appDB = CoreApp.instance.getDB(); | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(this.tablesSchema).catch(() => { | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => { | ||||
|             // Ignore errors.
 | ||||
|         }); | ||||
| 
 | ||||
| @ -301,7 +252,7 @@ export class CoreLocalNotificationsProvider { | ||||
|      * @return Promise resolved when the component code is retrieved. | ||||
|      */ | ||||
|     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. | ||||
|      */ | ||||
|     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 { | ||||
|             const stored = await this.appDB.getRecord<{ id: number; at: number }>( | ||||
|                 CoreLocalNotificationsProvider.TRIGGERED_TABLE, | ||||
|                 TRIGGERED_TABLE_NAME, | ||||
|                 { id: notification.id }, | ||||
|             ); | ||||
| 
 | ||||
| @ -532,7 +483,7 @@ export class CoreLocalNotificationsProvider { | ||||
|     async removeTriggered(id: number): Promise<void> { | ||||
|         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(), | ||||
|         }; | ||||
| 
 | ||||
|         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> { | ||||
|         await this.dbReady; | ||||
| 
 | ||||
|         const oldId = CoreLocalNotificationsProvider.COMPONENTS_TABLE + '#' + oldName; | ||||
|         const newId = CoreLocalNotificationsProvider.COMPONENTS_TABLE + '#' + newName; | ||||
|         const oldId = COMPONENTS_TABLE_NAME + '#' + oldName; | ||||
|         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 type CoreLocalNotificationsClickCallback<T = unknown> = (value: T) => void; | ||||
| 
 | ||||
| type CodeRequestsQueueItem = { | ||||
|     table: string; | ||||
|     id: string; | ||||
|     deferreds: PromiseDefer<number>[]; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										233
									
								
								src/app/services/sites.db.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								src/app/services/sites.db.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 { timeout } from 'rxjs/operators'; | ||||
| 
 | ||||
| import { CoreApp, CoreAppSchema, CoreStoreConfig } from '@services/app'; | ||||
| import { CoreApp, CoreStoreConfig } from '@services/app'; | ||||
| import { CoreEvents } from '@singletons/events'; | ||||
| import { CoreWS } from '@services/ws'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| @ -38,114 +38,36 @@ import { CoreError } from '@classes/errors/error'; | ||||
| import { CoreSiteError } from '@classes/errors/siteerror'; | ||||
| import { makeSingleton, Translate, Http } from '@singletons/core.singletons'; | ||||
| 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'; | ||||
| const SCHEMA_VERSIONS_TABLE = 'schema_versions'; | ||||
| 
 | ||||
| // Schemas for site tables. Other providers can add schemas in here using the registerSiteSchema function.
 | ||||
| const siteSchemas: { [name: string]: CoreRegisteredSiteSchema } = {}; | ||||
| export const registerSiteSchema = (schema: CoreSiteSchema): void => { | ||||
|     siteSchemas[schema.name] = schema; | ||||
| }; | ||||
| 
 | ||||
| /* | ||||
|  * 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 | ||||
|  * their own database tables. Example: | ||||
|  * | ||||
|  * constructor(sitesProvider: CoreSitesProvider) { | ||||
|  *     this.sitesProvider.registerSiteSchema(this.tableSchema); | ||||
|  * import { registerSiteSchema } from '@services/sites'; | ||||
|  * | ||||
|  * This provider will automatically create the tables in the databases of all the instantiated sites, and also to the | ||||
|  * databases of sites instantiated from now on. | ||||
|  * registerSiteSchema(tableSchema); | ||||
| */ | ||||
| @Injectable() | ||||
| 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.
 | ||||
|     protected readonly WORKPLACE_APP = 3; | ||||
|     protected readonly MOODLE_APP = 2; | ||||
| @ -162,112 +84,15 @@ export class CoreSitesProvider { | ||||
|     protected appDB: SQLiteDB; | ||||
|     protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
 | ||||
|     protected siteSchemasMigration: { [siteId: string]: Promise<void> } = {}; | ||||
| 
 | ||||
|     // 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.
 | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|     }; | ||||
|     protected pluginsSiteSchemas: { [name: string]: CoreRegisteredSiteSchema } = {}; | ||||
| 
 | ||||
|     constructor() { | ||||
|         this.logger = CoreLogger.getInstance('CoreSitesProvider'); | ||||
| 
 | ||||
|         this.appDB = CoreApp.instance.getDB(); | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(this.appTablesSchema).catch(() => { | ||||
|         this.dbReady = CoreApp.instance.createTablesFromSchema(APP_SCHEMA).catch(() => { | ||||
|             // Ignore errors.
 | ||||
|         }); | ||||
|         this.registerSiteSchema(this.siteSchema); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -857,7 +682,7 @@ export class CoreSitesProvider { | ||||
|             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]; | ||||
| 
 | ||||
|         try { | ||||
|             await this.appDB.deleteRecords(SITES_TABLE, { id: siteId }); | ||||
|             await this.appDB.deleteRecords(SITES_TABLE_NAME, { id: siteId }); | ||||
|         } catch (err) { | ||||
|             // 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> { | ||||
|         await this.dbReady; | ||||
| 
 | ||||
|         const count = await this.appDB.countRecords(SITES_TABLE); | ||||
|         const count = await this.appDB.countRecords(SITES_TABLE_NAME); | ||||
| 
 | ||||
|         return count > 0; | ||||
|     } | ||||
| @ -1129,7 +954,7 @@ export class CoreSitesProvider { | ||||
|             return this.sites[siteId]; | ||||
|         } else { | ||||
|             // 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); | ||||
|         } | ||||
| @ -1202,7 +1027,7 @@ export class CoreSitesProvider { | ||||
|     async getSites(ids?: string[]): Promise<CoreSiteBasicInfo[]> { | ||||
|         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[] = []; | ||||
|         sites.forEach((site) => { | ||||
| @ -1266,7 +1091,7 @@ export class CoreSitesProvider { | ||||
|     async getLoggedInSitesIds(): Promise<string[]> { | ||||
|         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); | ||||
|     } | ||||
| @ -1279,7 +1104,7 @@ export class CoreSitesProvider { | ||||
|     async getSitesIds(): Promise<string[]> { | ||||
|         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); | ||||
|     } | ||||
| @ -1298,7 +1123,7 @@ export class CoreSitesProvider { | ||||
|             siteId, | ||||
|         }; | ||||
| 
 | ||||
|         await this.appDB.insertRecord(CURRENT_SITE_TABLE, entry); | ||||
|         await this.appDB.insertRecord(CURRENT_SITE_TABLE_NAME, entry); | ||||
| 
 | ||||
|         CoreEvents.trigger(CoreEvents.LOGIN, {}, siteId); | ||||
|     } | ||||
| @ -1324,7 +1149,7 @@ export class CoreSitesProvider { | ||||
|                 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 { | ||||
| @ -1349,7 +1174,7 @@ export class CoreSitesProvider { | ||||
|         this.sessionRestored = true; | ||||
| 
 | ||||
|         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; | ||||
|             this.logger.debug(`Restore session in site ${siteId}`); | ||||
| 
 | ||||
| @ -1377,7 +1202,7 @@ export class CoreSitesProvider { | ||||
| 
 | ||||
|         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.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 { | ||||
|                 await this.appDB.updateRecords(SITES_TABLE, newValues, { id: siteId }); | ||||
|                 await this.appDB.updateRecords(SITES_TABLE_NAME, newValues, { id: siteId }); | ||||
|             } finally { | ||||
|                 CoreEvents.trigger(CoreEvents.SITE_UPDATED, info, siteId); | ||||
|             } | ||||
| @ -1529,7 +1354,7 @@ export class CoreSitesProvider { | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             const siteEntries = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE); | ||||
|             const siteEntries = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE_NAME); | ||||
|             const ids: string[] = []; | ||||
|             const promises: Promise<unknown>[] = []; | ||||
| 
 | ||||
| @ -1562,7 +1387,7 @@ export class CoreSitesProvider { | ||||
|     async getStoredCurrentSiteId(): Promise<string> { | ||||
|         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; | ||||
|     } | ||||
| @ -1605,32 +1430,6 @@ export class CoreSitesProvider { | ||||
|         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. | ||||
|      * | ||||
| @ -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. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async registerSiteSchema(schema: CoreSiteSchema): Promise<void> { | ||||
|         if (this.currentSite) { | ||||
|             try { | ||||
|                 // Site has already been created, apply the schema directly.
 | ||||
|                 const schemas: {[name: string]: CoreRegisteredSiteSchema} = {}; | ||||
|                 schemas[schema.name] = schema; | ||||
|         if (!this.currentSite) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|                 if (!schema.onlyCurrentSite) { | ||||
|                     // Apply it to all sites.
 | ||||
|                     const siteIds = await this.getSitesIds(); | ||||
|         try { | ||||
|             // Site has already been created, apply the schema directly.
 | ||||
|             const schemas: {[name: string]: CoreRegisteredSiteSchema} = {}; | ||||
|             schemas[schema.name] = schema; | ||||
| 
 | ||||
|                     await Promise.all(siteIds.map(async (siteId) => { | ||||
|                         const site = await this.getSite(siteId); | ||||
|             // Apply it to the specified site only.
 | ||||
|             (schema as CoreRegisteredSiteSchema).siteId = this.currentSite.getId(); | ||||
| 
 | ||||
|                         return this.applySiteSchemas(site, schemas); | ||||
|                     })); | ||||
|                 } else { | ||||
|                     // 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; | ||||
|             await this.applySiteSchemas(this.currentSite, schemas); | ||||
|         } finally { | ||||
|             this.pluginsSiteSchemas[schema.name] = schema; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -1700,8 +1488,8 @@ export class CoreSitesProvider { | ||||
|         this.logger.debug(`Migrating all schemas of ${site.id}`); | ||||
| 
 | ||||
|         // First create tables not registerd with name/version.
 | ||||
|         const promise = site.getDb().createTablesFromSchema(this.siteTablesSchemas) | ||||
|             .then(() => this.applySiteSchemas(site, this.siteSchemas)); | ||||
|         const promise = site.getDb().createTableFromSchema(SCHEMA_VERSIONS_TABLE_SCHEMA) | ||||
|             .then(() => this.applySiteSchemas(site, siteSchemas)); | ||||
| 
 | ||||
|         this.siteSchemasMigration[site.id] = promise; | ||||
| 
 | ||||
| @ -1721,7 +1509,7 @@ export class CoreSitesProvider { | ||||
|         const db = site.getDb(); | ||||
| 
 | ||||
|         // 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} = {}; | ||||
|         records.forEach((record) => { | ||||
| @ -1768,7 +1556,7 @@ export class CoreSitesProvider { | ||||
|         } | ||||
| 
 | ||||
|         // 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[] { | ||||
|         let reset: string[] = []; | ||||
|         for (const name in this.siteSchemas) { | ||||
|             const schema = this.siteSchemas[name]; | ||||
|         const schemas = Object.values(siteSchemas).concat(Object.values(this.pluginsSiteSchemas)); | ||||
| 
 | ||||
|         schemas.forEach((schema) => { | ||||
|             if (schema.canBeCleared && (!schema.siteId || site.getId() == schema.siteId)) { | ||||
|                 reset = reset.concat(schema.canBeCleared); | ||||
|             } | ||||
|         } | ||||
|         }); | ||||
| 
 | ||||
|         return reset; | ||||
|     } | ||||
| @ -1980,12 +1768,6 @@ export type CoreSiteSchema = { | ||||
|      */ | ||||
|     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. | ||||
|      */ | ||||
| @ -2088,24 +1870,3 @@ export type CoreSitesLoginTokenResponse = { | ||||
|     debuginfo?: 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; | ||||
| }; | ||||
|  | ||||
							
								
								
									
										62
									
								
								src/app/services/sync.db.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/app/services/sync.db.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 { CoreSites, CoreSiteSchema } from '@services/sites'; | ||||
| import { makeSingleton } from '@singletons/core.singletons'; | ||||
| 
 | ||||
| const SYNC_TABLE = 'sync'; | ||||
| import { SYNC_TABLE_NAME, CoreSyncRecord } from '@services/sync.db'; | ||||
| 
 | ||||
| /* | ||||
|  * Service that provides some features regarding synchronization. | ||||
| @ -31,7 +30,7 @@ export class CoreSyncProvider { | ||||
|         version: 1, | ||||
|         tables: [ | ||||
|             { | ||||
|                 name: SYNC_TABLE, | ||||
|                 name: SYNC_TABLE_NAME, | ||||
|                 columns: [ | ||||
|                     { | ||||
|                         name: 'component', | ||||
| @ -61,8 +60,6 @@ export class CoreSyncProvider { | ||||
|     protected blockedItems: { [siteId: string]: { [blockId: string]: { [operation: string]: boolean } } } = {}; | ||||
| 
 | ||||
|     constructor() { | ||||
|         CoreSites.instance.registerSiteSchema(this.siteSchema); | ||||
| 
 | ||||
|         // Unblock all blocks on logout.
 | ||||
|         CoreEvents.on(CoreEvents.LOGOUT, (data: {siteId: string}) => { | ||||
|             this.clearAllBlocks(data.siteId); | ||||
| @ -133,7 +130,7 @@ export class CoreSyncProvider { | ||||
|      * @return Record if found or reject. | ||||
|      */ | ||||
|     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.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 type CoreSyncRecord = { | ||||
|     component: string; | ||||
|     id: string; | ||||
|     time: number; | ||||
|     warnings: string; | ||||
| }; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user