MOBILE-3565 core: Fix more ESLint after first ESLint fix integration
parent
6fc97ed30f
commit
6592e22998
|
@ -78,7 +78,7 @@ export class CoreDelegate {
|
|||
/**
|
||||
* Function to resolve the handlers init promise.
|
||||
*/
|
||||
protected handlersInitResolve: (value?: any) => void;
|
||||
protected handlersInitResolve: () => void;
|
||||
|
||||
/**
|
||||
* Constructor of the Delegate.
|
||||
|
@ -110,8 +110,8 @@ export class CoreDelegate {
|
|||
* @param params Parameters to pass to the function.
|
||||
* @return Function returned value or default value.
|
||||
*/
|
||||
protected executeFunctionOnEnabled(handlerName: string, fnName: string, params?: any[]): any {
|
||||
return this.execute(this.enabledHandlers[handlerName], fnName, params);
|
||||
protected executeFunctionOnEnabled<T = unknown>(handlerName: string, fnName: string, params?: unknown[]): T {
|
||||
return this.execute<T>(this.enabledHandlers[handlerName], fnName, params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,7 +123,7 @@ export class CoreDelegate {
|
|||
* @param params Parameters to pass to the function.
|
||||
* @return Function returned value or default value.
|
||||
*/
|
||||
protected executeFunction(handlerName: string, fnName: string, params?: any[]): any {
|
||||
protected executeFunction<T = unknown>(handlerName: string, fnName: string, params?: unknown[]): T {
|
||||
return this.execute(this.handlers[handlerName], fnName, params);
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ export class CoreDelegate {
|
|||
* @param params Parameters to pass to the function.
|
||||
* @return Function returned value or default value.
|
||||
*/
|
||||
private execute(handler: CoreDelegateHandler, fnName: string, params?: any[]): any {
|
||||
private execute<T = unknown>(handler: CoreDelegateHandler, fnName: string, params?: unknown[]): T {
|
||||
if (handler && handler[fnName]) {
|
||||
return handler[fnName].apply(handler, params);
|
||||
} else if (this.defaultHandler && this.defaultHandler[fnName]) {
|
||||
|
@ -180,10 +180,10 @@ export class CoreDelegate {
|
|||
* @param onlyEnabled If check only enabled handlers or all.
|
||||
* @return Function returned value or default value.
|
||||
*/
|
||||
protected hasFunction(handlerName: string, fnName: string, onlyEnabled: boolean = true): any {
|
||||
protected hasFunction(handlerName: string, fnName: string, onlyEnabled: boolean = true): boolean {
|
||||
const handler = onlyEnabled ? this.enabledHandlers[handlerName] : this.handlers[handlerName];
|
||||
|
||||
return handler && handler[fnName];
|
||||
return handler && typeof handler[fnName] == 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -240,7 +240,7 @@ export class CoreDelegate {
|
|||
* @param time Time this update process started.
|
||||
* @return Resolved when done.
|
||||
*/
|
||||
protected updateHandler(handler: CoreDelegateHandler, time: number): Promise<void> {
|
||||
protected updateHandler(handler: CoreDelegateHandler): Promise<void> {
|
||||
const siteId = CoreSites.instance.getCurrentSiteId();
|
||||
const currentSite = CoreSites.instance.getCurrentSite();
|
||||
let promise: Promise<boolean>;
|
||||
|
@ -255,7 +255,7 @@ export class CoreDelegate {
|
|||
if (!CoreSites.instance.isLoggedIn() || this.isFeatureDisabled(handler, currentSite)) {
|
||||
promise = Promise.resolve(false);
|
||||
} else {
|
||||
promise = handler.isEnabled().catch(() => false);
|
||||
promise = Promise.resolve(handler.isEnabled()).catch(() => false);
|
||||
}
|
||||
|
||||
// Checks if the handler is enabled.
|
||||
|
@ -304,7 +304,7 @@ export class CoreDelegate {
|
|||
|
||||
// Loop over all the handlers.
|
||||
for (const name in this.handlers) {
|
||||
promises.push(this.updateHandler(this.handlers[name], now));
|
||||
promises.push(this.updateHandler(this.handlers[name]));
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -326,7 +326,7 @@ export class CoreDelegate {
|
|||
* Update handlers Data.
|
||||
* Override this function to update handlers data.
|
||||
*/
|
||||
updateData(): any {
|
||||
updateData(): void {
|
||||
// To be overridden.
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
// 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 Faker from 'faker';
|
||||
|
||||
import { CoreError } from './error';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
|
||||
describe('CoreError', () => {
|
||||
|
||||
|
|
|
@ -30,28 +30,26 @@ export class CoreInterceptor implements HttpInterceptor {
|
|||
* @param addNull Add null values to the serialized as empty parameters.
|
||||
* @return Serialization of the object.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
||||
static serialize(obj: any, addNull?: boolean): string {
|
||||
let query = '';
|
||||
let fullSubName: string;
|
||||
let subValue;
|
||||
let innerObj;
|
||||
|
||||
for (const name in obj) {
|
||||
const value = obj[name];
|
||||
|
||||
if (value instanceof Array) {
|
||||
for (let i = 0; i < value.length; ++i) {
|
||||
subValue = value[i];
|
||||
fullSubName = name + '[' + i + ']';
|
||||
innerObj = {};
|
||||
const subValue = value[i];
|
||||
const fullSubName = name + '[' + i + ']';
|
||||
const innerObj = {};
|
||||
innerObj[fullSubName] = subValue;
|
||||
query += this.serialize(innerObj) + '&';
|
||||
}
|
||||
} else if (value instanceof Object) {
|
||||
for (const subName in value) {
|
||||
subValue = value[subName];
|
||||
fullSubName = name + '[' + subName + ']';
|
||||
innerObj = {};
|
||||
const subValue = value[subName];
|
||||
const fullSubName = name + '[' + subName + ']';
|
||||
const innerObj = {};
|
||||
innerObj[fullSubName] = subValue;
|
||||
query += this.serialize(innerObj) + '&';
|
||||
}
|
||||
|
@ -63,6 +61,7 @@ export class CoreInterceptor implements HttpInterceptor {
|
|||
return query.length ? query.substr(0, query.length - 1) : query;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
|
||||
// Add the header and serialize the body if needed.
|
||||
const newReq = req.clone({
|
||||
|
|
|
@ -17,11 +17,13 @@ import { CoreUtils, PromiseDefer } from '@services/utils/utils';
|
|||
/**
|
||||
* Function to add to the queue.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type CoreQueueRunnerFunction<T> = (...args: any[]) => T | Promise<T>;
|
||||
|
||||
/**
|
||||
* Queue item.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type CoreQueueRunnerItem<T = any> = {
|
||||
/**
|
||||
* Item ID.
|
||||
|
|
|
@ -23,7 +23,7 @@ import { CoreWS, CoreWSPreSets, CoreWSFileUploadOptions, CoreWSAjaxPreSets, Core
|
|||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUrlUtils, CoreUrlParams } from '@services/utils/url';
|
||||
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
import CoreConfigConstants from '@app/config.json';
|
||||
|
@ -857,7 +857,7 @@ export class CoreSite {
|
|||
let promise: Promise<any>;
|
||||
|
||||
if (preSets.getCacheUsingCacheKey || (emergency && preSets.getEmergencyCacheUsingCacheKey)) {
|
||||
promise = this.db.getRecords(CoreSite.WS_CACHE_TABLE, { key: preSets.cacheKey }).then((entries) => {
|
||||
promise = this.db.getRecords<any>(CoreSite.WS_CACHE_TABLE, { key: preSets.cacheKey }).then((entries) => {
|
||||
if (!entries.length) {
|
||||
// Cache key not found, get by params sent.
|
||||
return this.db.getRecord(CoreSite.WS_CACHE_TABLE, { id });
|
||||
|
@ -901,7 +901,7 @@ export class CoreSite {
|
|||
this.logger.info(`Cached element found, id: ${id}. Expires in expires in ${expires} seconds`);
|
||||
}
|
||||
|
||||
return CoreTextUtils.instance.parseJSON(entry.data, {});
|
||||
return <T> CoreTextUtils.instance.parseJSON(entry.data, {});
|
||||
}
|
||||
|
||||
return Promise.reject(new CoreError('Cache entry not valid.'));
|
||||
|
@ -915,7 +915,7 @@ export class CoreSite {
|
|||
* @param componentId Optional component id (if not included, returns sum for whole component)
|
||||
* @return Promise resolved when we have calculated the size
|
||||
*/
|
||||
getComponentCacheSize(component: string, componentId?: number): Promise<number> {
|
||||
async getComponentCacheSize(component: string, componentId?: number): Promise<number> {
|
||||
const params: Array<string | number> = [component];
|
||||
let extraClause = '';
|
||||
if (componentId !== undefined && componentId !== null) {
|
||||
|
@ -923,8 +923,10 @@ export class CoreSite {
|
|||
extraClause = ' AND componentId = ?';
|
||||
}
|
||||
|
||||
return this.db.getFieldSql('SELECT SUM(length(data)) FROM ' + CoreSite.WS_CACHE_TABLE +
|
||||
const size = <number> await this.db.getFieldSql('SELECT SUM(length(data)) FROM ' + CoreSite.WS_CACHE_TABLE +
|
||||
' WHERE component = ?' + extraClause, params);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1018,7 +1020,7 @@ export class CoreSite {
|
|||
params['componentId'] = componentId;
|
||||
}
|
||||
|
||||
return this.db.deleteRecords(CoreSite.WS_CACHE_TABLE, params);
|
||||
await this.db.deleteRecords(CoreSite.WS_CACHE_TABLE, params);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1192,8 +1194,10 @@ export class CoreSite {
|
|||
*
|
||||
* @return Promise resolved with the total size of all data in the cache table (bytes)
|
||||
*/
|
||||
getCacheUsage(): Promise<number> {
|
||||
return this.db.getFieldSql('SELECT SUM(length(data)) FROM ' + CoreSite.WS_CACHE_TABLE);
|
||||
async getCacheUsage(): Promise<number> {
|
||||
const size = <number> await this.db.getFieldSql('SELECT SUM(length(data)) FROM ' + CoreSite.WS_CACHE_TABLE);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1228,7 +1232,7 @@ export class CoreSite {
|
|||
* @param anchor Anchor text if needed.
|
||||
* @return URL with params.
|
||||
*/
|
||||
createSiteUrl(path: string, params?: {[key: string]: unknown}, anchor?: string): string {
|
||||
createSiteUrl(path: string, params?: CoreUrlParams, anchor?: string): string {
|
||||
return CoreUrlUtils.instance.addParamsToUrl(this.siteUrl + path, params, anchor);
|
||||
}
|
||||
|
||||
|
@ -1797,7 +1801,8 @@ export class CoreSite {
|
|||
* @return Resolves upon success along with the config data. Reject on failure.
|
||||
*/
|
||||
getLocalSiteConfig<T extends number | string>(name: string, defaultValue?: T): Promise<T> {
|
||||
return this.db.getRecord(CoreSite.CONFIG_TABLE, { name }).then((entry) => entry.value).catch((error) => {
|
||||
return this.db.getRecord<CoreSiteConfigDBRecord>(CoreSite.CONFIG_TABLE, { name }).then((entry) => <T> entry.value)
|
||||
.catch((error) => {
|
||||
if (typeof defaultValue != 'undefined') {
|
||||
return defaultValue;
|
||||
}
|
||||
|
@ -2151,3 +2156,8 @@ export type CoreSiteCallExternalFunctionsResult = {
|
|||
exception?: string; // JSON-encoed exception info.
|
||||
}[];
|
||||
};
|
||||
|
||||
export type CoreSiteConfigDBRecord = {
|
||||
name: string;
|
||||
value: string | number;
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import { SQLiteObject } from '@ionic-native/sqlite/ngx';
|
||||
|
||||
import { SQLite, Platform } from '@singletons/core.singletons';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
|
||||
/**
|
||||
* Schema of a table.
|
||||
|
@ -411,6 +412,7 @@ export class SQLiteDB {
|
|||
* @param params Query parameters.
|
||||
* @return Promise resolved with the result.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async execute(sql: string, params?: SQLiteDBRecordValue[]): Promise<any> {
|
||||
await this.ready();
|
||||
|
||||
|
@ -425,7 +427,8 @@ export class SQLiteDB {
|
|||
* @param sqlStatements SQL statements to execute.
|
||||
* @return Promise resolved with the result.
|
||||
*/
|
||||
async executeBatch(sqlStatements: (string | SQLiteDBRecordValue[])[][]): Promise<void> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async executeBatch(sqlStatements: (string | string[] | any)[]): Promise<void> {
|
||||
await this.ready();
|
||||
|
||||
await this.db.sqlBatch(sqlStatements);
|
||||
|
@ -453,9 +456,10 @@ export class SQLiteDB {
|
|||
* Format the data to where params.
|
||||
*
|
||||
* @param data Object data.
|
||||
* @return List of params.
|
||||
*/
|
||||
protected formatDataToSQLParams(data: SQLiteDBRecordValues): SQLiteDBRecordValue[] {
|
||||
return Object.keys(data).map((key) => data[key]);
|
||||
return Object.keys(data).map((key) => data[key]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -464,7 +468,7 @@ export class SQLiteDB {
|
|||
* @param table The table to query.
|
||||
* @return Promise resolved with the records.
|
||||
*/
|
||||
async getAllRecords(table: string): Promise<SQLiteDBRecordValues[]> {
|
||||
async getAllRecords<T = unknown>(table: string): Promise<T[]> {
|
||||
return this.getRecords(table);
|
||||
}
|
||||
|
||||
|
@ -510,7 +514,7 @@ export class SQLiteDB {
|
|||
async getFieldSql(sql: string, params?: SQLiteDBRecordValue[]): Promise<SQLiteDBRecordValue> {
|
||||
const record = await this.getRecordSql(sql, params);
|
||||
if (!record) {
|
||||
throw null;
|
||||
throw new CoreError('No record found.');
|
||||
}
|
||||
|
||||
return record[Object.keys(record)[0]];
|
||||
|
@ -574,10 +578,10 @@ export class SQLiteDB {
|
|||
* @param fields A comma separated list of fields to return.
|
||||
* @return Promise resolved with the record, rejected if not found.
|
||||
*/
|
||||
getRecord(table: string, conditions?: SQLiteDBRecordValues, fields: string = '*'): Promise<SQLiteDBRecordValues> {
|
||||
getRecord<T = unknown>(table: string, conditions?: SQLiteDBRecordValues, fields: string = '*'): Promise<T> {
|
||||
const selectAndParams = this.whereClause(conditions);
|
||||
|
||||
return this.getRecordSelect(table, selectAndParams[0], selectAndParams[1], fields);
|
||||
return this.getRecordSelect<T>(table, selectAndParams[0], selectAndParams[1], fields);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -589,13 +593,13 @@ export class SQLiteDB {
|
|||
* @param fields A comma separated list of fields to return.
|
||||
* @return Promise resolved with the record, rejected if not found.
|
||||
*/
|
||||
getRecordSelect(table: string, select: string = '', params: SQLiteDBRecordValue[] = [], fields: string = '*'):
|
||||
Promise<SQLiteDBRecordValues> {
|
||||
getRecordSelect<T = unknown>(table: string, select: string = '', params: SQLiteDBRecordValue[] = [], fields: string = '*'):
|
||||
Promise<T> {
|
||||
if (select) {
|
||||
select = ' WHERE ' + select;
|
||||
}
|
||||
|
||||
return this.getRecordSql(`SELECT ${fields} FROM ${table} ${select}`, params);
|
||||
return this.getRecordSql<T>(`SELECT ${fields} FROM ${table} ${select}`, params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -608,11 +612,11 @@ export class SQLiteDB {
|
|||
* @param params List of sql parameters
|
||||
* @return Promise resolved with the records.
|
||||
*/
|
||||
async getRecordSql(sql: string, params?: SQLiteDBRecordValue[]): Promise<SQLiteDBRecordValues> {
|
||||
const result = await this.getRecordsSql(sql, params, 0, 1);
|
||||
async getRecordSql<T = unknown>(sql: string, params?: SQLiteDBRecordValue[]): Promise<T> {
|
||||
const result = await this.getRecordsSql<T>(sql, params, 0, 1);
|
||||
if (!result || !result.length) {
|
||||
// Not found, reject.
|
||||
throw null;
|
||||
throw new CoreError('No records found.');
|
||||
}
|
||||
|
||||
return result[0];
|
||||
|
@ -629,11 +633,11 @@ export class SQLiteDB {
|
|||
* @param limitNum Return a subset comprising this many records in total.
|
||||
* @return Promise resolved with the records.
|
||||
*/
|
||||
getRecords(table: string, conditions?: SQLiteDBRecordValues, sort: string = '', fields: string = '*', limitFrom: number = 0,
|
||||
limitNum: number = 0): Promise<SQLiteDBRecordValues[]> {
|
||||
getRecords<T = unknown>(table: string, conditions?: SQLiteDBRecordValues, sort: string = '', fields: string = '*',
|
||||
limitFrom: number = 0, limitNum: number = 0): Promise<T[]> {
|
||||
const selectAndParams = this.whereClause(conditions);
|
||||
|
||||
return this.getRecordsSelect(table, selectAndParams[0], selectAndParams[1], sort, fields, limitFrom, limitNum);
|
||||
return this.getRecordsSelect<T>(table, selectAndParams[0], selectAndParams[1], sort, fields, limitFrom, limitNum);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -648,11 +652,11 @@ export class SQLiteDB {
|
|||
* @param limitNum Return a subset comprising this many records in total.
|
||||
* @return Promise resolved with the records.
|
||||
*/
|
||||
getRecordsList(table: string, field: string, values: SQLiteDBRecordValue[], sort: string = '', fields: string = '*',
|
||||
limitFrom: number = 0, limitNum: number = 0): Promise<SQLiteDBRecordValues[]> {
|
||||
getRecordsList<T = unknown>(table: string, field: string, values: SQLiteDBRecordValue[], sort: string = '',
|
||||
fields: string = '*', limitFrom: number = 0, limitNum: number = 0): Promise<T[]> {
|
||||
const selectAndParams = this.whereClauseList(field, values);
|
||||
|
||||
return this.getRecordsSelect(table, selectAndParams[0], selectAndParams[1], sort, fields, limitFrom, limitNum);
|
||||
return this.getRecordsSelect<T>(table, selectAndParams[0], selectAndParams[1], sort, fields, limitFrom, limitNum);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -667,8 +671,8 @@ export class SQLiteDB {
|
|||
* @param limitNum Return a subset comprising this many records in total.
|
||||
* @return Promise resolved with the records.
|
||||
*/
|
||||
getRecordsSelect(table: string, select: string = '', params: SQLiteDBRecordValue[] = [], sort: string = '',
|
||||
fields: string = '*', limitFrom: number = 0, limitNum: number = 0): Promise<SQLiteDBRecordValues[]> {
|
||||
getRecordsSelect<T = unknown>(table: string, select: string = '', params: SQLiteDBRecordValue[] = [], sort: string = '',
|
||||
fields: string = '*', limitFrom: number = 0, limitNum: number = 0): Promise<T[]> {
|
||||
if (select) {
|
||||
select = ' WHERE ' + select;
|
||||
}
|
||||
|
@ -678,7 +682,7 @@ export class SQLiteDB {
|
|||
|
||||
const sql = `SELECT ${fields} FROM ${table} ${select} ${sort}`;
|
||||
|
||||
return this.getRecordsSql(sql, params, limitFrom, limitNum);
|
||||
return this.getRecordsSql<T>(sql, params, limitFrom, limitNum);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -690,8 +694,8 @@ export class SQLiteDB {
|
|||
* @param limitNum Return a subset comprising this many records.
|
||||
* @return Promise resolved with the records.
|
||||
*/
|
||||
async getRecordsSql(sql: string, params?: SQLiteDBRecordValue[], limitFrom?: number, limitNum?: number):
|
||||
Promise<SQLiteDBRecordValues[]> {
|
||||
async getRecordsSql<T = unknown>(sql: string, params?: SQLiteDBRecordValue[], limitFrom?: number, limitNum?: number):
|
||||
Promise<T[]> {
|
||||
const limits = this.normaliseLimitFromNum(limitFrom, limitNum);
|
||||
|
||||
if (limits[0] || limits[1]) {
|
||||
|
@ -768,7 +772,7 @@ export class SQLiteDB {
|
|||
*/
|
||||
async insertRecords(table: string, dataObjects: SQLiteDBRecordValues[]): Promise<void> {
|
||||
if (!Array.isArray(dataObjects)) {
|
||||
throw null;
|
||||
throw new CoreError('Invalid parameter supplied to insertRecords, it should be an array.');
|
||||
}
|
||||
|
||||
const statements = dataObjects.map((dataObject) => {
|
||||
|
@ -854,7 +858,7 @@ export class SQLiteDB {
|
|||
async recordExists(table: string, conditions?: SQLiteDBRecordValues): Promise<void> {
|
||||
const record = await this.getRecord(table, conditions);
|
||||
if (!record) {
|
||||
throw null;
|
||||
throw new CoreError('Record does not exist.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -869,7 +873,7 @@ export class SQLiteDB {
|
|||
async recordExistsSelect(table: string, select: string = '', params: SQLiteDBRecordValue[] = []): Promise<void> {
|
||||
const record = await this.getRecordSelect(table, select, params);
|
||||
if (!record) {
|
||||
throw null;
|
||||
throw new CoreError('Record does not exist.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -883,7 +887,7 @@ export class SQLiteDB {
|
|||
async recordExistsSql(sql: string, params?: SQLiteDBRecordValue[]): Promise<void> {
|
||||
const record = await this.getRecordSql(sql, params);
|
||||
if (!record) {
|
||||
throw null;
|
||||
throw new CoreError('Record does not exist.');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import { Pipe, PipeTransform } from '@angular/core';
|
|||
name: 'coreCreateLinks',
|
||||
})
|
||||
export class CoreCreateLinksPipe implements PipeTransform {
|
||||
|
||||
protected static replacePattern = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])(?![^<]*>|[^<>]*<\/)/gim;
|
||||
|
||||
/**
|
||||
|
@ -32,4 +33,5 @@ export class CoreCreateLinksPipe implements PipeTransform {
|
|||
transform(text: string): string {
|
||||
return text.replace(CoreCreateLinksPipe.replacePattern, '<a href="$1">$1</a>');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,4 +31,5 @@ export class CoreNoTagsPipe implements PipeTransform {
|
|||
transform(text: string): string {
|
||||
return text.replace(/(<([^>]+)>)/ig, '');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,6 @@ import { CoreTimeAgoPipe } from './time-ago.pipe';
|
|||
CoreCreateLinksPipe,
|
||||
CoreNoTagsPipe,
|
||||
CoreTimeAgoPipe,
|
||||
]
|
||||
],
|
||||
})
|
||||
export class CorePipesModule {}
|
||||
|
|
|
@ -24,6 +24,7 @@ import moment from 'moment';
|
|||
name: 'coreTimeAgo',
|
||||
})
|
||||
export class CoreTimeAgoPipe implements PipeTransform {
|
||||
|
||||
private logger: CoreLogger;
|
||||
|
||||
constructor() {
|
||||
|
@ -48,6 +49,7 @@ export class CoreTimeAgoPipe implements PipeTransform {
|
|||
timestamp = numberTimestamp;
|
||||
}
|
||||
|
||||
return Translate.instance.instant('core.ago', {$a: moment(timestamp * 1000).fromNow(true)});
|
||||
return Translate.instance.instant('core.ago', { $a: moment(timestamp * 1000).fromNow(true) });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -174,7 +174,8 @@ export class CoreAppProvider {
|
|||
await this.createVersionsTableReady;
|
||||
|
||||
// Fetch installed version of the schema.
|
||||
const entry = await this.db.getRecord(SCHEMA_VERSIONS_TABLE, { name: schema.name });
|
||||
const entry = await this.db.getRecord<SchemaVersionsDBEntry>(SCHEMA_VERSIONS_TABLE, { name: schema.name });
|
||||
|
||||
oldVersion = entry.version;
|
||||
} catch (error) {
|
||||
// No installed version yet.
|
||||
|
@ -796,3 +797,8 @@ export type WindowForAutomatedTests = Window & {
|
|||
appProvider?: CoreAppProvider;
|
||||
appRef?: ApplicationRef;
|
||||
};
|
||||
|
||||
type SchemaVersionsDBEntry = {
|
||||
name: string;
|
||||
version: number;
|
||||
};
|
||||
|
|
|
@ -81,7 +81,7 @@ export class CoreConfigProvider {
|
|||
await this.dbReady;
|
||||
|
||||
try {
|
||||
const entry = await this.appDB.getRecord(TABLE_NAME, { name });
|
||||
const entry = await this.appDB.getRecord<ConfigDBEntry>(TABLE_NAME, { name });
|
||||
|
||||
return entry.value;
|
||||
} catch (error) {
|
||||
|
@ -109,3 +109,9 @@ export class CoreConfigProvider {
|
|||
}
|
||||
|
||||
export class CoreConfig extends makeSingleton(CoreConfigProvider) {}
|
||||
|
||||
type ConfigDBEntry = {
|
||||
name: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
value: any;
|
||||
};
|
||||
|
|
|
@ -64,7 +64,7 @@ export class CoreCronDelegate {
|
|||
protected appDB: SQLiteDB;
|
||||
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
||||
protected handlers: { [s: string]: CoreCronHandler } = {};
|
||||
protected queuePromise = Promise.resolve();
|
||||
protected queuePromise: Promise<void> = Promise.resolve();
|
||||
|
||||
constructor(zone: NgZone) {
|
||||
this.logger = CoreLogger.getInstance('CoreCronDelegate');
|
||||
|
@ -271,8 +271,9 @@ export class CoreCronDelegate {
|
|||
const id = this.getHandlerLastExecutionId(name);
|
||||
|
||||
try {
|
||||
const entry = await this.appDB.getRecord(CRON_TABLE, { id });
|
||||
const time = parseInt(entry.value, 10);
|
||||
const entry = await this.appDB.getRecord<CronDBEntry>(CRON_TABLE, { id });
|
||||
|
||||
const time = Number(entry.value);
|
||||
|
||||
return isNaN(time) ? 0 : time;
|
||||
} catch (err) {
|
||||
|
@ -573,3 +574,8 @@ export interface CoreCronHandler {
|
|||
export type WindowForAutomatedTests = Window & {
|
||||
cronProvider?: CoreCronDelegate;
|
||||
};
|
||||
|
||||
type CronDBEntry = {
|
||||
id: string;
|
||||
value: number;
|
||||
};
|
||||
|
|
|
@ -29,8 +29,9 @@ import { CoreTimeUtils } from '@services/utils/time';
|
|||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
|
||||
import { SQLiteDB } from '@classes/sqlitedb';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
import { makeSingleton, Network, NgZone } from '@singletons/core.singletons';
|
||||
import { makeSingleton, Network, NgZone, Translate } from '@singletons/core.singletons';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
|
||||
/*
|
||||
|
@ -56,7 +57,7 @@ export class CoreFilepoolProvider {
|
|||
protected static readonly ERR_FS_OR_NETWORK_UNAVAILABLE = 'CoreFilepoolError:ERR_FS_OR_NETWORK_UNAVAILABLE';
|
||||
protected static readonly ERR_QUEUE_ON_PAUSE = 'CoreFilepoolError:ERR_QUEUE_ON_PAUSE';
|
||||
|
||||
protected static readonly FILE_UPDATE_ANY_WHERE_CLAUSE =
|
||||
protected static readonly FILE_UPDATE_UNKNOWN_WHERE_CLAUSE =
|
||||
'isexternalfile = 1 OR ((revision IS NULL OR revision = 0) AND (timemodified IS NULL OR timemodified = 0))';
|
||||
|
||||
// Variables for database.
|
||||
|
@ -239,7 +240,7 @@ export class CoreFilepoolProvider {
|
|||
protected appDB: SQLiteDB;
|
||||
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
||||
protected queueState: string;
|
||||
protected urlAttributes = [
|
||||
protected urlAttributes: RegExp[] = [
|
||||
new RegExp('(\\?|&)token=([A-Za-z0-9]*)'),
|
||||
new RegExp('(\\?|&)forcedownload=[0-1]'),
|
||||
new RegExp('(\\?|&)preview=[A-Za-z0-9]+'),
|
||||
|
@ -248,7 +249,7 @@ export class CoreFilepoolProvider {
|
|||
|
||||
// To handle file downloads using the queue.
|
||||
protected queueDeferreds: { [s: string]: { [s: string]: CoreFilepoolPromiseDefer } } = {};
|
||||
protected sizeCache = {}; // A "cache" to store file sizes to prevent performing too many HEAD requests.
|
||||
protected sizeCache: {[fileUrl: string]: number} = {}; // A "cache" to store file sizes.
|
||||
// Variables to prevent downloading packages/files twice at the same time.
|
||||
protected packagesPromises: { [s: string]: { [s: string]: Promise<void> } } = {};
|
||||
protected filePromises: { [s: string]: { [s: string]: Promise<string> } } = {};
|
||||
|
@ -288,7 +289,7 @@ export class CoreFilepoolProvider {
|
|||
*/
|
||||
protected async addFileLink(siteId: string, fileId: string, component: string, componentId?: string | number): Promise<void> {
|
||||
if (!component) {
|
||||
throw null;
|
||||
throw new CoreError('Cannot add link because component is invalid.');
|
||||
}
|
||||
|
||||
componentId = this.fixComponentId(componentId);
|
||||
|
@ -358,8 +359,10 @@ export class CoreFilepoolProvider {
|
|||
* @return Promise resolved on success.
|
||||
*/
|
||||
protected async addFileToPool(siteId: string, fileId: string, data: CoreFilepoolFileEntry): Promise<void> {
|
||||
const record = Object.assign({}, data);
|
||||
record.fileId = fileId;
|
||||
const record = {
|
||||
fileId,
|
||||
...data,
|
||||
};
|
||||
|
||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||
|
||||
|
@ -457,12 +460,12 @@ export class CoreFilepoolProvider {
|
|||
await this.dbReady;
|
||||
|
||||
if (!CoreFile.instance.isAvailable()) {
|
||||
throw null;
|
||||
throw new CoreError('File system cannot be used.');
|
||||
}
|
||||
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
if (!site.canDownloadFiles()) {
|
||||
throw null;
|
||||
throw new CoreError('Site doesn\'t allow downloading files.');
|
||||
}
|
||||
|
||||
let file: CoreWSExternalFile;
|
||||
|
@ -488,7 +491,7 @@ export class CoreFilepoolProvider {
|
|||
const queueDeferred = this.getQueueDeferred(siteId, fileId, false, onProgress);
|
||||
|
||||
return this.hasFileInQueue(siteId, fileId).then((entry: CoreFilepoolQueueEntry) => {
|
||||
const newData: CoreFilepoolQueueEntry = {};
|
||||
const newData: CoreFilepoolQueueDBEntry = {};
|
||||
let foundLink = false;
|
||||
|
||||
if (entry) {
|
||||
|
@ -562,14 +565,14 @@ export class CoreFilepoolProvider {
|
|||
* @param componentId An ID to use in conjunction with the component.
|
||||
* @param timemodified The time this file was modified.
|
||||
* @param checkSize True if we shouldn't download files if their size is big, false otherwise.
|
||||
* @param downloadAny True to download file in WiFi if their size is any, false otherwise.
|
||||
* @param downloadUnknown True to download file in WiFi if their size is unknown, false otherwise.
|
||||
* Ignored if checkSize=false.
|
||||
* @param options Extra options (isexternalfile, repositorytype).
|
||||
* @param revision File revision. If not defined, it will be calculated using the URL.
|
||||
* @return Promise resolved when the file is downloaded.
|
||||
*/
|
||||
protected async addToQueueIfNeeded(siteId: string, fileUrl: string, component: string, componentId?: string | number,
|
||||
timemodified: number = 0, checkSize: boolean = true, downloadAny?: boolean, options: CoreFilepoolFileOptions = {},
|
||||
timemodified: number = 0, checkSize: boolean = true, downloadUnknown?: boolean, options: CoreFilepoolFileOptions = {},
|
||||
revision?: number): Promise<void> {
|
||||
if (!checkSize) {
|
||||
// No need to check size, just add it to the queue.
|
||||
|
@ -584,7 +587,7 @@ export class CoreFilepoolProvider {
|
|||
} else {
|
||||
if (!CoreApp.instance.isOnline()) {
|
||||
// Cannot check size in offline, stop.
|
||||
throw null;
|
||||
throw new CoreError(Translate.instance.instant('core.cannotconnect'));
|
||||
}
|
||||
|
||||
size = await CoreWS.instance.getRemoteFileSize(fileUrl);
|
||||
|
@ -592,16 +595,16 @@ export class CoreFilepoolProvider {
|
|||
|
||||
// Calculate the size of the file.
|
||||
const isWifi = CoreApp.instance.isWifi();
|
||||
const sizeAny = size <= 0;
|
||||
const sizeUnknown = size <= 0;
|
||||
|
||||
if (!sizeAny) {
|
||||
if (!sizeUnknown) {
|
||||
// Store the size in the cache.
|
||||
this.sizeCache[fileUrl] = size;
|
||||
}
|
||||
|
||||
// Check if the file should be downloaded.
|
||||
if (sizeAny) {
|
||||
if (downloadAny && isWifi) {
|
||||
if (sizeUnknown) {
|
||||
if (downloadUnknown && isWifi) {
|
||||
await this.addToQueueByUrl(siteId, fileUrl, component, componentId, timemodified, undefined, undefined,
|
||||
0, options, revision, true);
|
||||
}
|
||||
|
@ -685,7 +688,7 @@ export class CoreFilepoolProvider {
|
|||
|
||||
const count = await db.countRecords(CoreFilepoolProvider.LINKS_TABLE, conditions);
|
||||
if (count <= 0) {
|
||||
return null;
|
||||
throw new CoreError('Component doesn\'t have files');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -696,7 +699,7 @@ export class CoreFilepoolProvider {
|
|||
* @param componentId An ID to use in conjunction with the component.
|
||||
* @return Link, null if nothing to link.
|
||||
*/
|
||||
protected createComponentLink(component: string, componentId?: string | number): CoreFilepoolComponentLink {
|
||||
protected createComponentLink(component: string, componentId?: string | number): CoreFilepoolComponentLink | null {
|
||||
if (typeof component != 'undefined' && component != null) {
|
||||
return { component, componentId: this.fixComponentId(componentId) };
|
||||
}
|
||||
|
@ -779,7 +782,7 @@ export class CoreFilepoolProvider {
|
|||
if (poolFileObject && poolFileObject.fileId !== fileId) {
|
||||
this.logger.error('Invalid object to update passed');
|
||||
|
||||
throw null;
|
||||
throw new CoreError('Invalid object to update passed.');
|
||||
}
|
||||
|
||||
const downloadId = this.getFileDownloadId(fileUrl, filePath);
|
||||
|
@ -793,7 +796,7 @@ export class CoreFilepoolProvider {
|
|||
|
||||
this.filePromises[siteId][downloadId] = CoreSites.instance.getSite(siteId).then(async (site) => {
|
||||
if (!site.canDownloadFiles()) {
|
||||
return Promise.reject(null);
|
||||
throw new CoreError('Site doesn\'t allow downloading files.');
|
||||
}
|
||||
|
||||
const entry = await CoreWS.instance.downloadFile(fileUrl, filePath, addExtension, onProgress);
|
||||
|
@ -952,7 +955,7 @@ export class CoreFilepoolProvider {
|
|||
try {
|
||||
await Promise.all(promises);
|
||||
// Success prefetching, store package as downloaded.
|
||||
this.storePackageStatus(siteId, CoreConstants.DOWNLOADED, component, componentId, extra);
|
||||
await this.storePackageStatus(siteId, CoreConstants.DOWNLOADED, component, componentId, extra);
|
||||
} catch (error) {
|
||||
// Error downloading, go back to previous status and reject the promise.
|
||||
await this.setPackagePreviousStatus(siteId, component, componentId);
|
||||
|
@ -1014,7 +1017,7 @@ export class CoreFilepoolProvider {
|
|||
let alreadyDownloaded = true;
|
||||
|
||||
if (!CoreFile.instance.isAvailable()) {
|
||||
throw null;
|
||||
throw new CoreError('File system cannot be used.');
|
||||
}
|
||||
|
||||
const file = await this.fixPluginfileURL(siteId, fileUrl);
|
||||
|
@ -1093,14 +1096,12 @@ export class CoreFilepoolProvider {
|
|||
let urls = [];
|
||||
|
||||
const element = CoreDomUtils.instance.convertToElement(html);
|
||||
const elements = element.querySelectorAll('a, img, audio, video, source, track');
|
||||
const elements: (HTMLAnchorElement | HTMLImageElement | HTMLAudioElement | HTMLVideoElement | HTMLSourceElement |
|
||||
HTMLTrackElement)[] = Array.from(element.querySelectorAll('a, img, audio, video, source, track'));
|
||||
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
const element = elements[i];
|
||||
let url = element.tagName === 'A'
|
||||
? (element as HTMLAnchorElement).href
|
||||
: (element as HTMLImageElement | HTMLVideoElement | HTMLAudioElement |
|
||||
HTMLAudioElement | HTMLTrackElement | HTMLSourceElement).src;
|
||||
let url = 'href' in element ? element.href : element.src;
|
||||
|
||||
if (url && CoreUrlUtils.instance.isDownloadableUrl(url) && urls.indexOf(url) == -1) {
|
||||
urls.push(url);
|
||||
|
@ -1236,7 +1237,7 @@ export class CoreFilepoolProvider {
|
|||
componentId: this.fixComponentId(componentId),
|
||||
};
|
||||
|
||||
const items = await db.getRecords(CoreFilepoolProvider.LINKS_TABLE, conditions);
|
||||
const items = await db.getRecords<CoreFilepoolLinksRecord>(CoreFilepoolProvider.LINKS_TABLE, conditions);
|
||||
items.forEach((item) => {
|
||||
item.componentId = this.fixComponentId(item.componentId);
|
||||
});
|
||||
|
@ -1252,16 +1253,16 @@ export class CoreFilepoolProvider {
|
|||
* @return Resolved with the URL. Rejected otherwise.
|
||||
*/
|
||||
async getDirectoryUrlByUrl(siteId: string, fileUrl: string): Promise<string> {
|
||||
if (CoreFile.instance.isAvailable()) {
|
||||
const file = await this.fixPluginfileURL(siteId, fileUrl);
|
||||
const fileId = this.getFileIdByUrl(file.fileurl);
|
||||
const filePath = await this.getFilePath(siteId, fileId, '');
|
||||
const dirEntry = await CoreFile.instance.getDir(filePath);
|
||||
|
||||
return dirEntry.toURL();
|
||||
if (!CoreFile.instance.isAvailable()) {
|
||||
throw new CoreError('File system cannot be used.');
|
||||
}
|
||||
|
||||
throw null;
|
||||
const file = await this.fixPluginfileURL(siteId, fileUrl);
|
||||
const fileId = this.getFileIdByUrl(file.fileurl);
|
||||
const filePath = await this.getFilePath(siteId, fileId, '');
|
||||
const dirEntry = await CoreFile.instance.getDir(filePath);
|
||||
|
||||
return dirEntry.toURL();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1346,7 +1347,8 @@ export class CoreFilepoolProvider {
|
|||
*/
|
||||
protected async getFileLinks(siteId: string, fileId: string): Promise<CoreFilepoolLinksRecord[]> {
|
||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||
const items = await db.getRecords(CoreFilepoolProvider.LINKS_TABLE, { fileId });
|
||||
const items = await db.getRecords<CoreFilepoolLinksRecord>(CoreFilepoolProvider.LINKS_TABLE, { fileId });
|
||||
|
||||
items.forEach((item) => {
|
||||
item.componentId = this.fixComponentId(item.componentId);
|
||||
});
|
||||
|
@ -1421,7 +1423,7 @@ export class CoreFilepoolProvider {
|
|||
const files = [];
|
||||
|
||||
const promises = items.map((item) =>
|
||||
db.getRecord(CoreFilepoolProvider.FILES_TABLE, { fileId: item.fileId }).then((fileEntry) => {
|
||||
db.getRecord<CoreFilepoolFileEntry>(CoreFilepoolProvider.FILES_TABLE, { fileId: item.fileId }).then((fileEntry) => {
|
||||
if (!fileEntry) {
|
||||
return;
|
||||
}
|
||||
|
@ -1532,7 +1534,7 @@ export class CoreFilepoolProvider {
|
|||
* @param componentId An ID to use in conjunction with the component.
|
||||
* @param timemodified The time this file was modified.
|
||||
* @param checkSize True if we shouldn't download files if their size is big, false otherwise.
|
||||
* @param downloadAny True to download file in WiFi if their size is any, false otherwise.
|
||||
* @param downloadUnknown True to download file in WiFi if their size is unknown, false otherwise.
|
||||
* Ignored if checkSize=false.
|
||||
* @param options Extra options (isexternalfile, repositorytype).
|
||||
* @param revision File revision. If not defined, it will be calculated using the URL.
|
||||
|
@ -1544,12 +1546,12 @@ export class CoreFilepoolProvider {
|
|||
* If the file isn't downloaded or it's outdated, return the online URL and add it to the queue to be downloaded later.
|
||||
*/
|
||||
protected async getFileUrlByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number,
|
||||
mode: string = 'url', timemodified: number = 0, checkSize: boolean = true, downloadAny?: boolean,
|
||||
mode: string = 'url', timemodified: number = 0, checkSize: boolean = true, downloadUnknown?: boolean,
|
||||
options: CoreFilepoolFileOptions = {}, revision?: number): Promise<string> {
|
||||
const addToQueue = (fileUrl: string): void => {
|
||||
// Add the file to queue if needed and ignore errors.
|
||||
this.addToQueueIfNeeded(siteId, fileUrl, component, componentId, timemodified, checkSize,
|
||||
downloadAny, options, revision).catch(() => {
|
||||
downloadUnknown, options, revision).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
};
|
||||
|
@ -1594,7 +1596,7 @@ export class CoreFilepoolProvider {
|
|||
return fileUrl;
|
||||
}
|
||||
|
||||
throw null;
|
||||
throw new CoreError('File not found.');
|
||||
}
|
||||
}, () => {
|
||||
// We do not have the file in store yet. Add to queue and return the fixed URL.
|
||||
|
@ -1614,14 +1616,14 @@ export class CoreFilepoolProvider {
|
|||
* @return Resolved with the internal URL. Rejected otherwise.
|
||||
*/
|
||||
protected async getInternalSrcById(siteId: string, fileId: string): Promise<string> {
|
||||
if (CoreFile.instance.isAvailable()) {
|
||||
const path = await this.getFilePath(siteId, fileId);
|
||||
const fileEntry = await CoreFile.instance.getFile(path);
|
||||
|
||||
return CoreFile.instance.convertFileSrc(fileEntry.toURL());
|
||||
if (!CoreFile.instance.isAvailable()) {
|
||||
throw new CoreError('File system cannot be used.');
|
||||
}
|
||||
|
||||
throw null;
|
||||
const path = await this.getFilePath(siteId, fileId);
|
||||
const fileEntry = await CoreFile.instance.getFile(path);
|
||||
|
||||
return CoreFile.instance.convertFileSrc(fileEntry.toURL());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1632,19 +1634,19 @@ export class CoreFilepoolProvider {
|
|||
* @return Resolved with the URL. Rejected otherwise.
|
||||
*/
|
||||
protected async getInternalUrlById(siteId: string, fileId: string): Promise<string> {
|
||||
if (CoreFile.instance.isAvailable()) {
|
||||
const path = await this.getFilePath(siteId, fileId);
|
||||
const fileEntry = await CoreFile.instance.getFile(path);
|
||||
|
||||
// This URL is usually used to launch files or put them in HTML. In desktop we need the internal URL.
|
||||
if (CoreApp.instance.isDesktop()) {
|
||||
return fileEntry.toInternalURL();
|
||||
} else {
|
||||
return fileEntry.toURL();
|
||||
}
|
||||
if (!CoreFile.instance.isAvailable()) {
|
||||
throw new CoreError('File system cannot be used.');
|
||||
}
|
||||
|
||||
throw null;
|
||||
const path = await this.getFilePath(siteId, fileId);
|
||||
const fileEntry = await CoreFile.instance.getFile(path);
|
||||
|
||||
// This URL is usually used to launch files or put them in HTML. In desktop we need the internal URL.
|
||||
if (CoreApp.instance.isDesktop()) {
|
||||
return fileEntry.toInternalURL();
|
||||
} else {
|
||||
return fileEntry.toURL();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1654,13 +1656,13 @@ export class CoreFilepoolProvider {
|
|||
* @return Resolved with the URL.
|
||||
*/
|
||||
protected async getInternalUrlByPath(filePath: string): Promise<string> {
|
||||
if (CoreFile.instance.isAvailable()) {
|
||||
const fileEntry = await CoreFile.instance.getFile(filePath);
|
||||
|
||||
return fileEntry.toURL();
|
||||
if (!CoreFile.instance.isAvailable()) {
|
||||
throw new CoreError('File system cannot be used.');
|
||||
}
|
||||
|
||||
throw null;
|
||||
const fileEntry = await CoreFile.instance.getFile(filePath);
|
||||
|
||||
return fileEntry.toURL();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1671,14 +1673,14 @@ export class CoreFilepoolProvider {
|
|||
* @return Resolved with the URL. Rejected otherwise.
|
||||
*/
|
||||
async getInternalUrlByUrl(siteId: string, fileUrl: string): Promise<string> {
|
||||
if (CoreFile.instance.isAvailable()) {
|
||||
const file = await this.fixPluginfileURL(siteId, fileUrl);
|
||||
const fileId = this.getFileIdByUrl(file.fileurl);
|
||||
|
||||
return this.getInternalUrlById(siteId, fileId);
|
||||
if (!CoreFile.instance.isAvailable()) {
|
||||
throw new CoreError('File system cannot be used.');
|
||||
}
|
||||
|
||||
throw null;
|
||||
const file = await this.fixPluginfileURL(siteId, fileUrl);
|
||||
const fileId = this.getFileIdByUrl(file.fileurl);
|
||||
|
||||
return this.getInternalUrlById(siteId, fileId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1748,16 +1750,16 @@ export class CoreFilepoolProvider {
|
|||
* @return Resolved with the URL.
|
||||
*/
|
||||
async getPackageDirUrlByUrl(siteId: string, url: string): Promise<string> {
|
||||
if (CoreFile.instance.isAvailable()) {
|
||||
const file = await this.fixPluginfileURL(siteId, url);
|
||||
const dirName = this.getPackageDirNameByUrl(file.fileurl);
|
||||
const dirPath = await this.getFilePath(siteId, dirName, '');
|
||||
const dirEntry = await CoreFile.instance.getDir(dirPath);
|
||||
|
||||
return dirEntry.toURL();
|
||||
if (!CoreFile.instance.isAvailable()) {
|
||||
throw new CoreError('File system cannot be used.');
|
||||
}
|
||||
|
||||
throw null;
|
||||
const file = await this.fixPluginfileURL(siteId, url);
|
||||
const dirName = this.getPackageDirNameByUrl(file.fileurl);
|
||||
const dirPath = await this.getFilePath(siteId, dirName, '');
|
||||
const dirEntry = await CoreFile.instance.getDir(dirPath);
|
||||
|
||||
return dirEntry.toURL();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1973,7 +1975,7 @@ export class CoreFilepoolProvider {
|
|||
* @param componentId An ID to use in conjunction with the component.
|
||||
* @param timemodified The time this file was modified.
|
||||
* @param checkSize True if we shouldn't download files if their size is big, false otherwise.
|
||||
* @param downloadAny True to download file in WiFi if their size is any, false otherwise.
|
||||
* @param downloadUnknown True to download file in WiFi if their size is unknown, false otherwise.
|
||||
* Ignored if checkSize=false.
|
||||
* @param options Extra options (isexternalfile, repositorytype).
|
||||
* @param revision File revision. If not defined, it will be calculated using the URL.
|
||||
|
@ -1983,10 +1985,10 @@ export class CoreFilepoolProvider {
|
|||
* The URL returned is compatible to use with IMG tags.
|
||||
*/
|
||||
getSrcByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number, timemodified: number = 0,
|
||||
checkSize: boolean = true, downloadAny?: boolean, options: CoreFilepoolFileOptions = {}, revision?: number):
|
||||
checkSize: boolean = true, downloadUnknown?: boolean, options: CoreFilepoolFileOptions = {}, revision?: number):
|
||||
Promise<string> {
|
||||
return this.getFileUrlByUrl(siteId, fileUrl, component, componentId, 'src',
|
||||
timemodified, checkSize, downloadAny, options, revision);
|
||||
timemodified, checkSize, downloadUnknown, options, revision);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2017,7 +2019,7 @@ export class CoreFilepoolProvider {
|
|||
* @param componentId An ID to use in conjunction with the component.
|
||||
* @param timemodified The time this file was modified.
|
||||
* @param checkSize True if we shouldn't download files if their size is big, false otherwise.
|
||||
* @param downloadAny True to download file in WiFi if their size is any, false otherwise.
|
||||
* @param downloadUnknown True to download file in WiFi if their size is unknown, false otherwise.
|
||||
* Ignored if checkSize=false.
|
||||
* @param options Extra options (isexternalfile, repositorytype).
|
||||
* @param revision File revision. If not defined, it will be calculated using the URL.
|
||||
|
@ -2027,10 +2029,10 @@ export class CoreFilepoolProvider {
|
|||
* The URL returned is compatible to use with a local browser.
|
||||
*/
|
||||
getUrlByUrl(siteId: string, fileUrl: string, component: string, componentId?: string | number, timemodified: number = 0,
|
||||
checkSize: boolean = true, downloadAny?: boolean, options: CoreFilepoolFileOptions = {}, revision?: number):
|
||||
checkSize: boolean = true, downloadUnknown?: boolean, options: CoreFilepoolFileOptions = {}, revision?: number):
|
||||
Promise<string> {
|
||||
return this.getFileUrlByUrl(siteId, fileUrl, component, componentId, 'url',
|
||||
timemodified, checkSize, downloadAny, options, revision);
|
||||
timemodified, checkSize, downloadUnknown, options, revision);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2100,9 +2102,10 @@ export class CoreFilepoolProvider {
|
|||
*/
|
||||
protected async hasFileInPool(siteId: string, fileId: string): Promise<CoreFilepoolFileEntry> {
|
||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||
const entry = await db.getRecord(CoreFilepoolProvider.FILES_TABLE, { fileId });
|
||||
const entry = await db.getRecord<CoreFilepoolFileEntry>(CoreFilepoolProvider.FILES_TABLE, { fileId });
|
||||
|
||||
if (typeof entry === 'undefined') {
|
||||
throw null;
|
||||
throw new CoreError('File not found in filepool.');
|
||||
}
|
||||
|
||||
return entry;
|
||||
|
@ -2118,12 +2121,13 @@ export class CoreFilepoolProvider {
|
|||
protected async hasFileInQueue(siteId: string, fileId: string): Promise<CoreFilepoolQueueEntry> {
|
||||
await this.dbReady;
|
||||
|
||||
const entry = await this.appDB.getRecord(CoreFilepoolProvider.QUEUE_TABLE, { siteId, fileId });
|
||||
const entry = await this.appDB.getRecord<CoreFilepoolQueueEntry>(CoreFilepoolProvider.QUEUE_TABLE, { siteId, fileId });
|
||||
|
||||
if (typeof entry === 'undefined') {
|
||||
throw null;
|
||||
throw new CoreError('File not found in queue.');
|
||||
}
|
||||
// Convert the links to an object.
|
||||
entry.linksUnserialized = CoreTextUtils.instance.parseJSON(entry.links, []);
|
||||
entry.linksUnserialized = <CoreFilepoolComponentLink[]> CoreTextUtils.instance.parseJSON(entry.links, []);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
@ -2132,14 +2136,14 @@ export class CoreFilepoolProvider {
|
|||
* Invalidate all the files in a site.
|
||||
*
|
||||
* @param siteId The site ID.
|
||||
* @param onlyAny True to only invalidate files from external repos or without revision/timemodified.
|
||||
* @param onlyUnknown True to only invalidate files from external repos or without revision/timemodified.
|
||||
* It is advised to set it to true to reduce the performance and data usage of the app.
|
||||
* @return Resolved on success.
|
||||
*/
|
||||
async invalidateAllFiles(siteId: string, onlyAny: boolean = true): Promise<void> {
|
||||
async invalidateAllFiles(siteId: string, onlyUnknown: boolean = true): Promise<void> {
|
||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||
|
||||
const where = onlyAny ? CoreFilepoolProvider.FILE_UPDATE_ANY_WHERE_CLAUSE : null;
|
||||
const where = onlyUnknown ? CoreFilepoolProvider.FILE_UPDATE_UNKNOWN_WHERE_CLAUSE : null;
|
||||
|
||||
await db.updateRecordsWhere(CoreFilepoolProvider.FILES_TABLE, { stale: 1 }, where);
|
||||
}
|
||||
|
@ -2171,11 +2175,11 @@ export class CoreFilepoolProvider {
|
|||
* @param siteId The site ID.
|
||||
* @param component The component to invalidate.
|
||||
* @param componentId An ID to use in conjunction with the component.
|
||||
* @param onlyAny True to only invalidate files from external repos or without revision/timemodified.
|
||||
* It is advised to set it to true to reduce the performance and data usage of the app.
|
||||
* @param onlyUnknown True to only invalidate files from external repos or without revision/timemodified.
|
||||
* It is advised to set it to true to reduce the performance and data usage of the app.
|
||||
* @return Resolved when done.
|
||||
*/
|
||||
async invalidateFilesByComponent(siteId: string, component: string, componentId?: string | number, onlyAny: boolean = true):
|
||||
async invalidateFilesByComponent(siteId: string, component: string, componentId?: string | number, onlyUnknown: boolean = true):
|
||||
Promise<void> {
|
||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||
|
||||
|
@ -2191,8 +2195,8 @@ export class CoreFilepoolProvider {
|
|||
|
||||
whereAndParams[0] = 'fileId ' + whereAndParams[0];
|
||||
|
||||
if (onlyAny) {
|
||||
whereAndParams[0] += ' AND (' + CoreFilepoolProvider.FILE_UPDATE_ANY_WHERE_CLAUSE + ')';
|
||||
if (onlyUnknown) {
|
||||
whereAndParams[0] += ' AND (' + CoreFilepoolProvider.FILE_UPDATE_UNKNOWN_WHERE_CLAUSE + ')';
|
||||
}
|
||||
|
||||
await db.updateRecordsWhere(CoreFilepoolProvider.FILES_TABLE, { stale: 1 }, whereAndParams[0], whereAndParams[1]);
|
||||
|
@ -2258,7 +2262,7 @@ export class CoreFilepoolProvider {
|
|||
* @param entry Filepool entry.
|
||||
* @return Whether it cannot determine updates.
|
||||
*/
|
||||
protected isFileUpdateAny(entry: CoreFilepoolFileEntry): boolean {
|
||||
protected isFileUpdateUnknown(entry: CoreFilepoolFileEntry): boolean {
|
||||
return !!entry.isexternalfile || (!entry.revision && !entry.timemodified);
|
||||
}
|
||||
|
||||
|
@ -2433,7 +2437,7 @@ export class CoreFilepoolProvider {
|
|||
let items: CoreFilepoolQueueEntry[];
|
||||
|
||||
try {
|
||||
items = await this.appDB.getRecords(CoreFilepoolProvider.QUEUE_TABLE, undefined,
|
||||
items = await this.appDB.getRecords<CoreFilepoolQueueEntry>(CoreFilepoolProvider.QUEUE_TABLE, undefined,
|
||||
'priority DESC, added ASC', undefined, 0, 1);
|
||||
} catch (err) {
|
||||
throw CoreFilepoolProvider.ERR_QUEUE_IS_EMPTY;
|
||||
|
@ -2444,7 +2448,7 @@ export class CoreFilepoolProvider {
|
|||
throw CoreFilepoolProvider.ERR_QUEUE_IS_EMPTY;
|
||||
}
|
||||
// Convert the links to an object.
|
||||
item.linksUnserialized = CoreTextUtils.instance.parseJSON(item.links, []);
|
||||
item.linksUnserialized = <CoreFilepoolComponentLink[]> CoreTextUtils.instance.parseJSON(item.links, []);
|
||||
|
||||
return this.processQueueItem(item);
|
||||
}
|
||||
|
@ -2760,7 +2764,7 @@ export class CoreFilepoolProvider {
|
|||
const mimetype = await CoreUtils.instance.getMimeTypeFromUrl(url);
|
||||
// If the file is streaming (audio or video) we reject.
|
||||
if (mimetype.indexOf('video') != -1 || mimetype.indexOf('audio') != -1) {
|
||||
throw null;
|
||||
throw new CoreError('File is audio or video.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2988,9 +2992,9 @@ export type CoreFilepoolFileEntry = CoreFilepoolFileOptions & {
|
|||
};
|
||||
|
||||
/**
|
||||
* Entry from the file's queue.
|
||||
* DB data for entry from file's queue.
|
||||
*/
|
||||
export type CoreFilepoolQueueEntry = CoreFilepoolFileOptions & {
|
||||
export type CoreFilepoolQueueDBEntry = CoreFilepoolFileOptions & {
|
||||
/**
|
||||
* The site the file belongs to.
|
||||
*/
|
||||
|
@ -3025,7 +3029,12 @@ export type CoreFilepoolQueueEntry = CoreFilepoolFileOptions & {
|
|||
* 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).
|
||||
*/
|
||||
|
|
|
@ -116,6 +116,7 @@ export class CoreGeolocationProvider {
|
|||
*
|
||||
* @param error Error.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
||||
protected isCordovaPermissionDeniedError(error?: any): boolean {
|
||||
return error && 'code' in error && 'PERMISSION_DENIED' in error && error.code === error.PERMISSION_DENIED;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { makeSingleton, Translate } from '@singletons/core.singletons';
|
||||
import { CoreWSExternalWarning } from '@services/ws';
|
||||
import { CoreCourseBase } from '@/types/global';
|
||||
|
@ -79,9 +80,11 @@ export class CoreGroupsProvider {
|
|||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
const response = await site.read('core_group_get_activity_allowed_groups', params, preSets);
|
||||
const response: CoreGroupGetActivityAllowedGroupsResponse =
|
||||
await site.read('core_group_get_activity_allowed_groups', params, preSets);
|
||||
|
||||
if (!response || !response.groups) {
|
||||
throw null;
|
||||
throw new CoreError('Activity allowed groups not found.');
|
||||
}
|
||||
|
||||
return response;
|
||||
|
@ -195,9 +198,11 @@ export class CoreGroupsProvider {
|
|||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
const response = await site.read('core_group_get_activity_groupmode', params, preSets);
|
||||
const response: CoreGroupGetActivityGroupModeResponse =
|
||||
await site.read('core_group_get_activity_groupmode', params, preSets);
|
||||
|
||||
if (!response || typeof response.groupmode == 'undefined') {
|
||||
throw null;
|
||||
throw new CoreError('Activity group mode not found.');
|
||||
}
|
||||
|
||||
return response.groupmode;
|
||||
|
@ -267,9 +272,11 @@ export class CoreGroupsProvider {
|
|||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
};
|
||||
|
||||
const response = await site.read('core_group_get_course_user_groups', data, preSets);
|
||||
const response: CoreGroupGetCourseUserGroupsResponse =
|
||||
await site.read('core_group_get_course_user_groups', data, preSets);
|
||||
|
||||
if (!response || !response.groups) {
|
||||
throw null;
|
||||
throw new CoreError('User groups in course not found.');
|
||||
}
|
||||
|
||||
return response.groups;
|
||||
|
@ -461,3 +468,26 @@ export type CoreGroupGetActivityAllowedGroupsResponse = {
|
|||
canaccessallgroups?: boolean; // Whether the user will be able to access all the activity groups.
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Result of WS core_group_get_activity_groupmode.
|
||||
*/
|
||||
export type CoreGroupGetActivityGroupModeResponse = {
|
||||
groupmode: number; // Group mode: 0 for no groups, 1 for separate groups, 2 for visible groups.
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Result of WS core_group_get_course_user_groups.
|
||||
*/
|
||||
export type CoreGroupGetCourseUserGroupsResponse = {
|
||||
groups: {
|
||||
id: number; // Group record id.
|
||||
name: string; // Multilang compatible name, course unique.
|
||||
description: string; // Group description text.
|
||||
descriptionformat: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
idnumber: string; // Id number.
|
||||
courseid?: number; // Course id.
|
||||
}[];
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
|
|
@ -30,9 +30,9 @@ export class CoreLangProvider {
|
|||
protected fallbackLanguage = 'en'; // Always use English as fallback language since it contains all strings.
|
||||
protected defaultLanguage = CoreConfigConstants.default_lang || 'en'; // Lang to use if device lang not valid or is forced.
|
||||
protected currentLanguage: string; // Save current language in a variable to speed up the get function.
|
||||
protected customStrings = {}; // Strings defined using the admin tool.
|
||||
protected customStrings: CoreLanguageObject = {}; // Strings defined using the admin tool.
|
||||
protected customStringsRaw: string;
|
||||
protected sitePluginsStrings = {}; // Strings defined by site plugins.
|
||||
protected sitePluginsStrings: CoreLanguageObject = {}; // Strings defined by site plugins.
|
||||
|
||||
constructor() {
|
||||
// Set fallback language and language to use until the app determines the right language to use.
|
||||
|
@ -110,11 +110,11 @@ export class CoreLangProvider {
|
|||
* @param language New language to use.
|
||||
* @return Promise resolved when the change is finished.
|
||||
*/
|
||||
changeCurrentLanguage(language: string): Promise<unknown> {
|
||||
async changeCurrentLanguage(language: string): Promise<void> {
|
||||
const promises = [];
|
||||
|
||||
// Change the language, resolving the promise when we receive the first value.
|
||||
promises.push(new Promise((resolve, reject): void => {
|
||||
promises.push(new Promise((resolve, reject) => {
|
||||
const subscription = Translate.instance.use(language).subscribe((data) => {
|
||||
// It's a language override, load the original one first.
|
||||
const fallbackLang = Translate.instance.instant('core.parentlanguage');
|
||||
|
@ -165,13 +165,15 @@ export class CoreLangProvider {
|
|||
|
||||
this.currentLanguage = language;
|
||||
|
||||
return Promise.all(promises).finally(() => {
|
||||
try {
|
||||
await Promise.all(promises);
|
||||
} finally {
|
||||
// Load the custom and site plugins strings for the language.
|
||||
if (this.loadLangStrings(this.customStrings, language) || this.loadLangStrings(this.sitePluginsStrings, language)) {
|
||||
// Some lang strings have changed, emit an event to update the pipes.
|
||||
Translate.instance.onLangChange.emit({ lang: language, translations: Translate.instance.translations[language] });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +198,7 @@ export class CoreLangProvider {
|
|||
*
|
||||
* @return Custom strings.
|
||||
*/
|
||||
getAllCustomStrings(): unknown {
|
||||
getAllCustomStrings(): CoreLanguageObject {
|
||||
return this.customStrings;
|
||||
}
|
||||
|
||||
|
@ -205,7 +207,7 @@ export class CoreLangProvider {
|
|||
*
|
||||
* @return Site plugins strings.
|
||||
*/
|
||||
getAllSitePluginsStrings(): unknown {
|
||||
getAllSitePluginsStrings(): CoreLanguageObject {
|
||||
return this.sitePluginsStrings;
|
||||
}
|
||||
|
||||
|
@ -220,7 +222,7 @@ export class CoreLangProvider {
|
|||
}
|
||||
|
||||
// Get current language from config (user might have changed it).
|
||||
return CoreConfig.instance.get('current_language').then((language) => language).catch(() => {
|
||||
return CoreConfig.instance.get<string>('current_language').then((language) => language).catch(() => {
|
||||
// User hasn't defined a language. If default language is forced, use it.
|
||||
if (CoreConfigConstants.default_lang && CoreConfigConstants.forcedefaultlanguage) {
|
||||
return CoreConfigConstants.default_lang;
|
||||
|
@ -283,7 +285,7 @@ export class CoreLangProvider {
|
|||
* @param lang The language to check.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
getTranslationTable(lang: string): Promise<unknown> {
|
||||
getTranslationTable(lang: string): Promise<Record<string, unknown>> {
|
||||
// Create a promise to convert the observable into a promise.
|
||||
return new Promise((resolve, reject): void => {
|
||||
const observer = Translate.instance.getTranslation(lang).subscribe((table) => {
|
||||
|
|
|
@ -20,9 +20,11 @@ import { CoreApp, CoreAppSchema } from '@services/app';
|
|||
import { CoreConfig } from '@services/config';
|
||||
import { CoreEventObserver, CoreEvents, CoreEventsProvider } from '@services/events';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
|
||||
import { SQLiteDB } from '@classes/sqlitedb';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreQueueRunner } from '@classes/queue-runner';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
import CoreConfigConstants from '@app/config.json';
|
||||
import { makeSingleton, NgZone, Platform, Translate, LocalNotifications, Push, Device } from '@singletons/core.singletons';
|
||||
|
@ -94,14 +96,9 @@ export class CoreLocalNotificationsProvider {
|
|||
protected appDB: SQLiteDB;
|
||||
protected dbReady: Promise<void>; // Promise resolved when the app DB is initialized.
|
||||
protected codes: { [s: string]: number } = {};
|
||||
protected codeRequestsQueue = {};
|
||||
protected observables = {};
|
||||
protected currentNotification = {
|
||||
title: '',
|
||||
texts: [],
|
||||
ids: [],
|
||||
timeouts: [],
|
||||
};
|
||||
protected codeRequestsQueue: {[key: string]: CodeRequestsQueueItem} = {};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
protected observables: {[eventName: string]: {[component: string]: Subject<any>}} = {};
|
||||
|
||||
protected triggerSubscription: Subscription;
|
||||
protected clickSubscription: Subscription;
|
||||
|
@ -156,7 +153,7 @@ export class CoreLocalNotificationsProvider {
|
|||
});
|
||||
});
|
||||
|
||||
CoreEvents.instance.on(CoreEventsProvider.SITE_DELETED, (site) => {
|
||||
CoreEvents.instance.on(CoreEventsProvider.SITE_DELETED, (site: CoreSite) => {
|
||||
if (site) {
|
||||
this.cancelSiteNotifications(site.id);
|
||||
}
|
||||
|
@ -270,13 +267,15 @@ export class CoreLocalNotificationsProvider {
|
|||
|
||||
try {
|
||||
// Check if we already have a code stored for that ID.
|
||||
const entry = await this.appDB.getRecord(table, { id: id });
|
||||
const entry = await this.appDB.getRecord<{id: string; code: number}>(table, { id: id });
|
||||
|
||||
this.codes[key] = entry.code;
|
||||
|
||||
return entry.code;
|
||||
} catch (err) {
|
||||
// No code stored for that ID. Create a new code for it.
|
||||
const entries = await this.appDB.getRecords(table, undefined, 'code DESC');
|
||||
const entries = await this.appDB.getRecords<{id: string; code: number}>(table, undefined, 'code DESC');
|
||||
|
||||
let newCode = 0;
|
||||
if (entries.length > 0) {
|
||||
newCode = entries[0].code + 1;
|
||||
|
@ -326,7 +325,7 @@ export class CoreLocalNotificationsProvider {
|
|||
*/
|
||||
protected getUniqueNotificationId(notificationId: number, component: string, siteId: string): Promise<number> {
|
||||
if (!siteId || !component) {
|
||||
return Promise.reject(null);
|
||||
return Promise.reject(new CoreError('Site ID or component not supplied.'));
|
||||
}
|
||||
|
||||
return this.getSiteCode(siteId).then((siteCode) => this.getComponentCode(component).then((componentCode) =>
|
||||
|
@ -372,7 +371,9 @@ export class CoreLocalNotificationsProvider {
|
|||
await this.dbReady;
|
||||
|
||||
try {
|
||||
const stored = await this.appDB.getRecord(CoreLocalNotificationsProvider.TRIGGERED_TABLE, { id: notification.id });
|
||||
const stored = await this.appDB.getRecord<{id: number; at: number}>(CoreLocalNotificationsProvider.TRIGGERED_TABLE,
|
||||
{ id: notification.id });
|
||||
|
||||
let triggered = (notification.trigger && notification.trigger.at) || 0;
|
||||
|
||||
if (typeof triggered != 'number') {
|
||||
|
@ -398,6 +399,7 @@ export class CoreLocalNotificationsProvider {
|
|||
*
|
||||
* @param data Data received by the notification.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
||||
notifyClick(data: any): void {
|
||||
this.notifyEvent('click', data);
|
||||
}
|
||||
|
@ -408,6 +410,7 @@ export class CoreLocalNotificationsProvider {
|
|||
* @param eventName Name of the event to notify.
|
||||
* @param data Data received by the notification.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
||||
notifyEvent(eventName: string, data: any): void {
|
||||
// Execute the code in the Angular zone, so change detection doesn't stop working.
|
||||
NgZone.instance.run(() => {
|
||||
|
@ -426,6 +429,7 @@ export class CoreLocalNotificationsProvider {
|
|||
* @param data Notification data.
|
||||
* @return Parsed data.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
||||
protected parseNotificationData(data: any): any {
|
||||
if (!data) {
|
||||
return {};
|
||||
|
@ -454,11 +458,11 @@ export class CoreLocalNotificationsProvider {
|
|||
if (typeof request == 'object' && typeof request.table != 'undefined' && typeof request.id != 'undefined') {
|
||||
// Get the code and resolve/reject all the promises of this request.
|
||||
promise = this.getCode(request.table, request.id).then((code) => {
|
||||
request.promises.forEach((p) => {
|
||||
request.deferreds.forEach((p) => {
|
||||
p.resolve(code);
|
||||
});
|
||||
}).catch((error) => {
|
||||
request.promises.forEach((p) => {
|
||||
request.deferreds.forEach((p) => {
|
||||
p.reject(error);
|
||||
});
|
||||
});
|
||||
|
@ -508,7 +512,7 @@ export class CoreLocalNotificationsProvider {
|
|||
|
||||
return {
|
||||
off: (): void => {
|
||||
this.observables[eventName][component].unsubscribe(callback);
|
||||
this.observables[eventName][component].unsubscribe();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -539,13 +543,13 @@ export class CoreLocalNotificationsProvider {
|
|||
|
||||
if (typeof this.codeRequestsQueue[key] != 'undefined') {
|
||||
// There's already a pending request for this store and ID, add the promise to it.
|
||||
this.codeRequestsQueue[key].promises.push(deferred);
|
||||
this.codeRequestsQueue[key].deferreds.push(deferred);
|
||||
} else {
|
||||
// Add a pending request to the queue.
|
||||
this.codeRequestsQueue[key] = {
|
||||
table: table,
|
||||
id: id,
|
||||
promises: [deferred],
|
||||
deferreds: [deferred],
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -682,7 +686,7 @@ export class CoreLocalNotificationsProvider {
|
|||
|
||||
const entry = {
|
||||
id: notification.id,
|
||||
at: notification.trigger && notification.trigger.at ? notification.trigger.at : Date.now(),
|
||||
at: notification.trigger && notification.trigger.at ? notification.trigger.at.getTime() : Date.now(),
|
||||
};
|
||||
|
||||
return this.appDB.insertRecord(CoreLocalNotificationsProvider.TRIGGERED_TABLE, entry);
|
||||
|
@ -709,3 +713,9 @@ 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>[];
|
||||
};
|
||||
|
|
|
@ -26,7 +26,13 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { CoreConstants } from '@core/constants';
|
||||
import CoreConfigConstants from '@app/config.json';
|
||||
import {
|
||||
CoreSite, CoreSiteWSPreSets, LocalMobileResponse, CoreSiteConfig, CoreSitePublicConfigResponse, CoreSiteInfoResponse,
|
||||
CoreSite,
|
||||
CoreSiteWSPreSets,
|
||||
LocalMobileResponse,
|
||||
CoreSiteInfo,
|
||||
CoreSiteConfig,
|
||||
CoreSitePublicConfigResponse,
|
||||
CoreSiteInfoResponse,
|
||||
} from '@classes/site';
|
||||
import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
|
@ -123,7 +129,7 @@ export class CoreSitesProvider {
|
|||
await db.tableExists(oldTable);
|
||||
|
||||
// Move the records from the old table.
|
||||
const sites = await db.getAllRecords(oldTable);
|
||||
const sites = await db.getAllRecords<SiteDBEntry>(oldTable);
|
||||
const promises = [];
|
||||
|
||||
sites.forEach((site) => {
|
||||
|
@ -818,9 +824,9 @@ export class CoreSitesProvider {
|
|||
id,
|
||||
siteUrl,
|
||||
token,
|
||||
info: info ? JSON.stringify(info) : info,
|
||||
info: info ? JSON.stringify(info) : undefined,
|
||||
privateToken,
|
||||
config: config ? JSON.stringify(config) : config,
|
||||
config: config ? JSON.stringify(config) : undefined,
|
||||
loggedOut: 0,
|
||||
oauthId,
|
||||
};
|
||||
|
@ -1094,7 +1100,7 @@ export class CoreSitesProvider {
|
|||
return this.sites[siteId];
|
||||
} else {
|
||||
// Retrieve and create the site.
|
||||
const data = await this.appDB.getRecord(SITES_TABLE, { id: siteId });
|
||||
const data = await this.appDB.getRecord<SiteDBEntry>(SITES_TABLE, { id: siteId });
|
||||
|
||||
return this.makeSiteFromSiteListEntry(data);
|
||||
}
|
||||
|
@ -1106,16 +1112,12 @@ export class CoreSitesProvider {
|
|||
* @param entry Site list entry.
|
||||
* @return Promised resolved with the created site.
|
||||
*/
|
||||
makeSiteFromSiteListEntry(entry: any): Promise<CoreSite> {
|
||||
let info = entry.info;
|
||||
let config = entry.config;
|
||||
|
||||
makeSiteFromSiteListEntry(entry: SiteDBEntry): Promise<CoreSite> {
|
||||
// Parse info and config.
|
||||
info = info ? CoreTextUtils.instance.parseJSON(info) : info;
|
||||
config = config ? CoreTextUtils.instance.parseJSON(config) : config;
|
||||
const info = entry.info ? <CoreSiteInfo> CoreTextUtils.instance.parseJSON(entry.info) : undefined;
|
||||
const config = entry.config ? <CoreSiteConfig> CoreTextUtils.instance.parseJSON(entry.config) : undefined;
|
||||
|
||||
const site = new CoreSite(entry.id, entry.siteUrl, entry.token,
|
||||
info, entry.privateToken, config, entry.loggedOut == 1);
|
||||
const site = new CoreSite(entry.id, entry.siteUrl, entry.token, info, entry.privateToken, config, entry.loggedOut == 1);
|
||||
site.setOAuthId(entry.oauthId);
|
||||
|
||||
return this.migrateSiteSchemas(site).then(() => {
|
||||
|
@ -1171,20 +1173,20 @@ export class CoreSitesProvider {
|
|||
async getSites(ids?: string[]): Promise<CoreSiteBasicInfo[]> {
|
||||
await this.dbReady;
|
||||
|
||||
const sites = await this.appDB.getAllRecords(SITES_TABLE);
|
||||
const sites = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE);
|
||||
|
||||
const formattedSites = [];
|
||||
sites.forEach((site) => {
|
||||
if (!ids || ids.indexOf(site.id) > -1) {
|
||||
// Parse info.
|
||||
const siteInfo = site.info ? CoreTextUtils.instance.parseJSON(site.info) : site.info;
|
||||
const siteInfo = site.info ? <CoreSiteInfo> CoreTextUtils.instance.parseJSON(site.info) : undefined;
|
||||
const basicInfo: CoreSiteBasicInfo = {
|
||||
id: site.id,
|
||||
siteUrl: site.siteUrl,
|
||||
fullName: siteInfo && siteInfo.fullname,
|
||||
siteName: CoreConfigConstants.sitename ? CoreConfigConstants.sitename : siteInfo && siteInfo.sitename,
|
||||
avatar: siteInfo && siteInfo.userpictureurl,
|
||||
siteHomeId: siteInfo && siteInfo.siteid || 1,
|
||||
fullName: siteInfo?.fullname,
|
||||
siteName: CoreConfigConstants.sitename ? CoreConfigConstants.sitename : siteInfo?.sitename,
|
||||
avatar: siteInfo?.userpictureurl,
|
||||
siteHomeId: siteInfo?.siteid || 1,
|
||||
};
|
||||
formattedSites.push(basicInfo);
|
||||
}
|
||||
|
@ -1231,7 +1233,7 @@ export class CoreSitesProvider {
|
|||
async getLoggedInSitesIds(): Promise<string[]> {
|
||||
await this.dbReady;
|
||||
|
||||
const sites = await this.appDB.getRecords(SITES_TABLE, { loggedOut : 0 });
|
||||
const sites = await this.appDB.getRecords<SiteDBEntry>(SITES_TABLE, { loggedOut : 0 });
|
||||
|
||||
return sites.map((site) => site.id);
|
||||
}
|
||||
|
@ -1244,7 +1246,7 @@ export class CoreSitesProvider {
|
|||
async getSitesIds(): Promise<string[]> {
|
||||
await this.dbReady;
|
||||
|
||||
const sites = await this.appDB.getAllRecords(SITES_TABLE);
|
||||
const sites = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE);
|
||||
|
||||
return sites.map((site) => site.id);
|
||||
}
|
||||
|
@ -1314,7 +1316,7 @@ export class CoreSitesProvider {
|
|||
this.sessionRestored = true;
|
||||
|
||||
try {
|
||||
const currentSite = await this.appDB.getRecord(CURRENT_SITE_TABLE, { id: 1 });
|
||||
const currentSite = await this.appDB.getRecord<CurrentSiteDBEntry>(CURRENT_SITE_TABLE, { id: 1 });
|
||||
const siteId = currentSite.siteId;
|
||||
this.logger.debug(`Restore session in site ${siteId}`);
|
||||
|
||||
|
@ -1495,7 +1497,7 @@ export class CoreSitesProvider {
|
|||
}
|
||||
|
||||
try {
|
||||
const siteEntries = await this.appDB.getAllRecords(SITES_TABLE);
|
||||
const siteEntries = await this.appDB.getAllRecords<SiteDBEntry>(SITES_TABLE);
|
||||
const ids = [];
|
||||
const promises = [];
|
||||
|
||||
|
@ -1528,7 +1530,7 @@ export class CoreSitesProvider {
|
|||
async getStoredCurrentSiteId(): Promise<string> {
|
||||
await this.dbReady;
|
||||
|
||||
const currentSite = await this.appDB.getRecord(CURRENT_SITE_TABLE, { id: 1 });
|
||||
const currentSite = await this.appDB.getRecord<CurrentSiteDBEntry>(CURRENT_SITE_TABLE, { id: 1 });
|
||||
|
||||
return currentSite.siteId;
|
||||
}
|
||||
|
@ -1685,7 +1687,7 @@ export class CoreSitesProvider {
|
|||
const db = site.getDb();
|
||||
|
||||
// Fetch installed versions of the schema.
|
||||
const records = await db.getAllRecords(SCHEMA_VERSIONS_TABLE);
|
||||
const records = await db.getAllRecords<SchemaVersionsDBEntry>(SCHEMA_VERSIONS_TABLE);
|
||||
|
||||
const versions: {[name: string]: number} = {};
|
||||
records.forEach((record) => {
|
||||
|
@ -2048,3 +2050,24 @@ 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;
|
||||
};
|
||||
|
|
|
@ -132,7 +132,7 @@ export class CoreSyncProvider {
|
|||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Record if found or reject.
|
||||
*/
|
||||
getSyncRecord(component: string, id: string | number, siteId?: string): Promise<Record<string, unknown>> {
|
||||
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 }));
|
||||
}
|
||||
|
||||
|
@ -145,8 +145,7 @@ export class CoreSyncProvider {
|
|||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with done.
|
||||
*/
|
||||
async insertOrUpdateSyncRecord(component: string, id: string | number, data: Record<string, unknown>, siteId?: string):
|
||||
Promise<void> {
|
||||
async insertOrUpdateSyncRecord(component: string, id: string, data: CoreSyncRecord, siteId?: string): Promise<void> {
|
||||
const db = await CoreSites.instance.getSiteDb(siteId);
|
||||
|
||||
data.component = component;
|
||||
|
@ -212,3 +211,10 @@ export class CoreSyncProvider {
|
|||
}
|
||||
|
||||
export class CoreSync extends makeSingleton(CoreSyncProvider) {}
|
||||
|
||||
export type CoreSyncRecord = {
|
||||
component: string;
|
||||
id: string;
|
||||
time: number;
|
||||
warnings: string;
|
||||
};
|
||||
|
|
|
@ -51,7 +51,7 @@ export class CoreUpdateManagerProvider implements CoreInitHandler {
|
|||
const promises = [];
|
||||
const versionCode = CoreConfigConstants.versioncode;
|
||||
|
||||
const versionApplied: number = await CoreConfig.instance.get(VERSION_APPLIED, 0);
|
||||
const versionApplied = await CoreConfig.instance.get<number>(VERSION_APPLIED, 0);
|
||||
|
||||
if (versionCode >= 3900 && versionApplied < 3900 && versionApplied > 0) {
|
||||
// @todo: H5P update.
|
||||
|
|
|
@ -391,7 +391,7 @@ export class CoreIframeUtilsProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!CoreUrlUtils.instance.isLocalFileUrlScheme(urlParts.protocol, urlParts.domain)) {
|
||||
if (!CoreUrlUtils.instance.isLocalFileUrlScheme(urlParts.protocol)) {
|
||||
// Scheme suggests it's an external resource.
|
||||
event && event.preventDefault();
|
||||
|
||||
|
|
|
@ -424,18 +424,16 @@ export class CoreUrlUtilsProvider {
|
|||
isLocalFileUrl(url: string): boolean {
|
||||
const urlParts = CoreUrl.parse(url);
|
||||
|
||||
return this.isLocalFileUrlScheme(urlParts.protocol, urlParts.domain);
|
||||
return this.isLocalFileUrlScheme(urlParts.protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a URL scheme belongs to a local file.
|
||||
*
|
||||
* @param scheme Scheme to check.
|
||||
* @param notUsed Unused parameter.
|
||||
* @return Whether the scheme belongs to a local file.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
isLocalFileUrlScheme(scheme: string, notUsed?: string): boolean {
|
||||
isLocalFileUrlScheme(scheme: string): boolean {
|
||||
if (scheme) {
|
||||
scheme = scheme.toLowerCase();
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpResponse, HttpParams } from '@angular/common/http';
|
||||
|
||||
import { FileEntry } from '@ionic-native/file';
|
||||
import { FileUploadOptions } from '@ionic-native/file-transfer/ngx';
|
||||
import { Md5 } from 'ts-md5/dist/md5';
|
||||
import { Observable } from 'rxjs';
|
||||
|
|
|
@ -38,7 +38,7 @@ export class CoreArray {
|
|||
*/
|
||||
static flatten<T>(arr: T[][]): T[] {
|
||||
if ('flat' in arr) {
|
||||
return (arr as any).flat();
|
||||
return (arr as any).flat(); // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
|
||||
return [].concat(...arr);
|
||||
|
|
|
@ -400,7 +400,7 @@ function unserialize (str) {
|
|||
}
|
||||
}
|
||||
|
||||
function substr_replace (str, replace, start, length) { // eslint-disable-line camelcase
|
||||
function substr_replace (str, replace, start, length) {
|
||||
// discuss at: https://locutus.io/php/substr_replace/
|
||||
// original by: Brett Zamir (https://brett-zamir.me)
|
||||
// example 1: substr_replace('ABCDEFGH:/MNRPQR/', 'bob', 0)
|
||||
|
|
|
@ -24,6 +24,7 @@ export type CoreWindowOpenOptions = {
|
|||
/**
|
||||
* NavController to use when opening the link in the app.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
navCtrl?: any; // @todo NavController;
|
||||
};
|
||||
|
||||
|
@ -36,7 +37,7 @@ export class CoreWindow {
|
|||
private constructor() {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* "Safe" implementation of window.open. It will open the URL without overriding the app.
|
||||
*
|
||||
|
@ -60,11 +61,13 @@ export class CoreWindow {
|
|||
await CoreUtils.instance.openFile(url);
|
||||
} else {
|
||||
let treated: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
options = options || {};
|
||||
|
||||
if (name != '_system') {
|
||||
// Check if it can be opened in the app.
|
||||
treated = false; // @todo await CoreContentLinksHelper.instance.handleLink(url, undefined, options.navCtrl, true, true);
|
||||
treated = false;
|
||||
// @todo await CoreContentLinksHelper.instance.handleLink(url, undefined, options.navCtrl, true, true);
|
||||
}
|
||||
|
||||
if (!treated) {
|
||||
|
|
Loading…
Reference in New Issue