MOBILE-2261 core: Implement filepool and file session
parent
39a1623f8d
commit
e216341838
|
@ -46,6 +46,8 @@ import { CoreSitesProvider } from '../providers/sites';
|
|||
import { CoreLocalNotificationsProvider } from '../providers/local-notifications';
|
||||
import { CoreGroupsProvider } from '../providers/groups';
|
||||
import { CoreCronDelegate } from '../providers/cron';
|
||||
import { CoreFileSessionProvider } from '../providers/file-session';
|
||||
import { CoreFilepoolProvider } from '../providers/filepool';
|
||||
|
||||
// For translate loader. AoT requires an exported function for factories.
|
||||
export function createTranslateLoader(http: HttpClient) {
|
||||
|
@ -99,6 +101,8 @@ export function createTranslateLoader(http: HttpClient) {
|
|||
CoreLocalNotificationsProvider,
|
||||
CoreGroupsProvider,
|
||||
CoreCronDelegate,
|
||||
CoreFileSessionProvider,
|
||||
CoreFilepoolProvider,
|
||||
]
|
||||
})
|
||||
export class AppModule {
|
||||
|
|
|
@ -56,6 +56,8 @@ export interface LocalMobileResponse {
|
|||
/**
|
||||
* 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.createTablesFromSchema. This will make sure that
|
||||
* the tables are created in all the sites, not just the current one.
|
||||
*/
|
||||
export class CoreSite {
|
||||
// List of injected services. This class isn't injectable, so it cannot use DI.
|
||||
|
|
|
@ -101,7 +101,7 @@ export class SQLiteDB {
|
|||
|
||||
columnsSql.push(columnSql);
|
||||
}
|
||||
sql += columnsSql.join(', ') + ')';
|
||||
sql += columnsSql.join(', ');
|
||||
|
||||
// Now add the table constraints.
|
||||
|
||||
|
@ -141,7 +141,7 @@ export class SQLiteDB {
|
|||
}
|
||||
}
|
||||
|
||||
return sql;
|
||||
return sql + ')';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -240,9 +240,9 @@ export class SQLiteDB {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a table if it doesn't exist from a schema.
|
||||
* Create several tables if they don't exist from a list of schemas.
|
||||
*
|
||||
* @param {any} table Table schema.
|
||||
* @param {any[]} tables List of table schema.
|
||||
* @return {Promise<any>} Promise resolved when success.
|
||||
*/
|
||||
createTablesFromSchema(tables: any[]) : Promise<any> {
|
||||
|
@ -394,7 +394,7 @@ export class SQLiteDB {
|
|||
* @param {any} items A single value or array of values for the expression. It doesn't accept objects.
|
||||
* @param {boolean} [equal=true] True means we want to equate to the constructed expression.
|
||||
* @param {any} [onEmptyItems] This defines the behavior when the array of items provided is empty. Defaults to false,
|
||||
* meaning throw exceptions. Other values will become part of the returned SQL fragment.
|
||||
* meaning return empty. Other values will become part of the returned SQL fragment.
|
||||
* @return {any[]} A list containing the constructed sql fragment and an array of parameters.
|
||||
*/
|
||||
getInOrEqual(items: any, equal=true, onEmptyItems?: any) : any[] {
|
||||
|
@ -774,7 +774,7 @@ export class SQLiteDB {
|
|||
sql,
|
||||
params;
|
||||
|
||||
for (var key in data) {
|
||||
for (let key in data) {
|
||||
sets.push(`${key} = ?`);
|
||||
}
|
||||
|
||||
|
@ -785,6 +785,43 @@ export class SQLiteDB {
|
|||
return this.execute(sql, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update one or more records in a table. It accepts a WHERE clause as a string.
|
||||
*
|
||||
* @param {string} string table The database table to update.
|
||||
* @param {any} data An object with the fields to update: fieldname=>fieldvalue.
|
||||
* @param {string} [where] Where clause. Must not include the "WHERE" word.
|
||||
* @param {any[]} [whereParams] Params for the where clause.
|
||||
* @return {Promise<any>} Promise resolved when updated.
|
||||
*/
|
||||
updateRecordsWhere(table: string, data: any, where?: string, whereParams?: any[]) : Promise<any> {
|
||||
if (!data || !Object.keys(data).length) {
|
||||
// No fields to update, consider it's done.
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let sets = [],
|
||||
sql,
|
||||
params;
|
||||
|
||||
for (let key in data) {
|
||||
sets.push(`${key} = ?`);
|
||||
}
|
||||
|
||||
sql = `UPDATE ${table} SET ${sets.join(', ')}`;
|
||||
if (where) {
|
||||
sql += ` WHERE ${where}`;
|
||||
}
|
||||
|
||||
// Create the list of params using the "data" object and the params for the where clause.
|
||||
params = Object.keys(data).map(key => data[key]);
|
||||
if (where && whereParams) {
|
||||
params = params.concat(whereParams[1]);
|
||||
}
|
||||
|
||||
return this.execute(sql, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SQL WHERE conditions.
|
||||
*
|
||||
|
|
|
@ -37,4 +37,11 @@ export class CoreConstants {
|
|||
public static loginSSOCode = 2; // SSO in browser window is required.
|
||||
public static loginSSOInAppCode = 3; // SSO in embedded browser is required.
|
||||
public static loginLaunchData = 'mmLoginLaunchData';
|
||||
|
||||
// Download status constants.
|
||||
public static downloaded = 'downloaded';
|
||||
public static downloading = 'downloading';
|
||||
public static notDownloaded = 'notdownloaded';
|
||||
public static outdated = 'outdated';
|
||||
public static notDownloadable = 'notdownloadable';
|
||||
}
|
||||
|
|
|
@ -91,7 +91,9 @@ export class SQLiteDBMock extends SQLiteDB {
|
|||
this.db.transaction((tx) => {
|
||||
tx.executeSql(sql, params, (tx, results) => {
|
||||
resolve(results);
|
||||
}, reject);
|
||||
}, (tx, error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreSitesProvider } from './sites';
|
||||
|
||||
/**
|
||||
* Helper to store some temporary data for file submission.
|
||||
*
|
||||
* It uses siteId and component name to index the files.
|
||||
* Every component can provide a File area identifier to indentify every file list on the session.
|
||||
* This value can be the activity id or a mix of name and numbers.
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreFileSessionProvider {
|
||||
protected files = {};
|
||||
|
||||
constructor(private sitesProvider: CoreSitesProvider) {}
|
||||
|
||||
/**
|
||||
* Add a file to the session.
|
||||
*
|
||||
* @param {string} component Component Name.
|
||||
* @param {string|number} id File area identifier.
|
||||
* @param {any} file File to add.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
*/
|
||||
addFile(component: string, id: string|number, file: any, siteId?: string) : void {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
this.initFileArea(component, id, siteId);
|
||||
|
||||
this.files[siteId][component][id].push(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear files stored in session.
|
||||
*
|
||||
* @param {string} component Component Name.
|
||||
* @param {string|number} id File area identifier.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
*/
|
||||
clearFiles(component: string, id: string|number, siteId?: string) : void {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
if (this.files[siteId] && this.files[siteId][component] && this.files[siteId][component][id]) {
|
||||
this.files[siteId][component][id] = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get files stored in session.
|
||||
*
|
||||
* @param {string} component Component Name.
|
||||
* @param {string|number} id File area identifier.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {any[]} Array of files in session.
|
||||
*/
|
||||
getFiles(component: string, id: string|number, siteId?: string) : any[] {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
if (this.files[siteId] && this.files[siteId][component] && this.files[siteId][component][id]) {
|
||||
return this.files[siteId][component][id];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the filearea to store the file.
|
||||
*
|
||||
* @param {string} component Component Name.
|
||||
* @param {string|number} id File area identifier.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
*/
|
||||
protected initFileArea(component: string, id: string|number, siteId?: string) : void {
|
||||
if (!this.files[siteId]) {
|
||||
this.files[siteId] = {};
|
||||
}
|
||||
|
||||
if (!this.files[siteId][component]) {
|
||||
this.files[siteId][component] = {};
|
||||
}
|
||||
|
||||
if (!this.files[siteId][component][id]) {
|
||||
this.files[siteId][component][id] = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a file stored in session.
|
||||
*
|
||||
* @param {string} component Component Name.
|
||||
* @param {string|number} id File area identifier.
|
||||
* @param {any} file File to remove. The instance should be exactly the same as the one stored in session.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
*/
|
||||
removeFile(component: string, id: string|number, file: any, siteId?: string) : void {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
if (this.files[siteId] && this.files[siteId][component] && this.files[siteId][component][id]) {
|
||||
const position = this.files[siteId][component][id].indexOf(file);
|
||||
if (position != -1) {
|
||||
this.files[siteId][component][id].splice(position, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a file stored in session.
|
||||
*
|
||||
* @param {string} component Component Name.
|
||||
* @param {string|number} id File area identifier.
|
||||
* @param {number} index Position of the file to remove.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
*/
|
||||
removeFileByIndex(component: string, id: string|number, index: number, siteId?: string) : void {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
if (this.files[siteId] && this.files[siteId][component] && this.files[siteId][component][id] && index >= 0 &&
|
||||
index < this.files[siteId][component][id].length) {
|
||||
this.files[siteId][component][id].splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a group of files in the session.
|
||||
*
|
||||
* @param {string} component Component Name.
|
||||
* @param {string|number} id File area identifier.
|
||||
* @param {any[]} newFiles Files to set.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
*/
|
||||
setFiles(component: string, id: string|number, newFiles: any[], siteId?: string) : void {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
this.initFileArea(component, id, siteId);
|
||||
|
||||
this.files[siteId][component][id] = newFiles;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -51,13 +51,21 @@ export interface CoreSiteBasicInfo {
|
|||
|
||||
/*
|
||||
* 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.createTableFromSchema(this.tableSchema);
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreSitesProvider {
|
||||
// Variables for the database.
|
||||
protected SITES_TABLE = 'sites';
|
||||
protected CURRENT_SITE_TABLE = 'current_site';
|
||||
protected tablesSchema = [
|
||||
protected appTablesSchema = [
|
||||
{
|
||||
name: this.SITES_TABLE,
|
||||
columns: [
|
||||
|
@ -122,6 +130,7 @@ export class CoreSitesProvider {
|
|||
protected currentSite: CoreSite;
|
||||
protected sites: {[s: string]: CoreSite} = {};
|
||||
protected appDB: SQLiteDB;
|
||||
protected siteTablesSchemas = []; // Schemas for site tables. Other providers can add schemas in here.
|
||||
|
||||
constructor(logger: CoreLoggerProvider, private http: HttpClient, private sitesFactory: CoreSitesFactoryProvider,
|
||||
private appProvider: CoreAppProvider, private utils: CoreUtilsProvider, private translate: TranslateService,
|
||||
|
@ -129,7 +138,7 @@ export class CoreSitesProvider {
|
|||
this.logger = logger.getInstance('CoreSitesProvider');
|
||||
|
||||
this.appDB = appProvider.getDB();
|
||||
this.appDB.createTablesFromSchema(this.tablesSchema);
|
||||
this.appDB.createTablesFromSchema(this.appTablesSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -383,10 +392,16 @@ export class CoreSitesProvider {
|
|||
this.addSite(siteId, siteUrl, token, info, privateToken, config);
|
||||
// Turn candidate site into current site.
|
||||
this.currentSite = candidateSite;
|
||||
this.sites[siteId] = candidateSite;
|
||||
// Store session.
|
||||
this.login(siteId);
|
||||
this.eventsProvider.trigger(CoreEventsProvider.SITE_ADDED, siteId);
|
||||
|
||||
if (this.siteTablesSchemas.length) {
|
||||
// Create tables in the site's database.
|
||||
candidateSite.getDb().createTablesFromSchema(this.siteTablesSchemas);
|
||||
}
|
||||
|
||||
return siteId;
|
||||
});
|
||||
} else if (result == this.LEGACY_APP_VERSION) {
|
||||
|
@ -680,6 +695,11 @@ export class CoreSitesProvider {
|
|||
site = this.sitesFactory.makeSite(entry.id, entry.siteUrl, entry.token,
|
||||
info, entry.privateToken, config, entry.loggedOut == 1);
|
||||
this.sites[entry.id] = site;
|
||||
if (this.siteTablesSchemas.length) {
|
||||
// Create tables in the site's database.
|
||||
site.getDb().createTablesFromSchema(this.siteTablesSchemas);
|
||||
}
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
|
@ -1029,4 +1049,28 @@ export class CoreSitesProvider {
|
|||
return site.isFeatureDisabled(name);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a table in all the sites databases.
|
||||
*
|
||||
* @param {any} table Table schema.
|
||||
*/
|
||||
createTableFromSchema(table: any) : void {
|
||||
this.createTablesFromSchema([table]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create several tables in all the sites databases.
|
||||
*
|
||||
* @param {any[]} tables List of tables schema.
|
||||
*/
|
||||
createTablesFromSchema(tables: any[]) : 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 (let id in this.sites) {
|
||||
this.sites[id].getDb().createTablesFromSchema(tables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,9 +46,9 @@ export class CoreUrlUtilsProvider {
|
|||
* Extracts the parameters from a URL and stores them in an object.
|
||||
*
|
||||
* @param {string} url URL to treat.
|
||||
* @return {object} Object with the params.
|
||||
* @return {any} Object with the params.
|
||||
*/
|
||||
extractUrlParams(url: string) : object {
|
||||
extractUrlParams(url: string) : any {
|
||||
let regex = /[?&]+([^=&]+)=?([^&]*)?/gi,
|
||||
params = {};
|
||||
|
||||
|
|
Loading…
Reference in New Issue