MOBILE-2261 core: Implement plugin file delegate
parent
93568a9c97
commit
0519875949
|
@ -49,6 +49,7 @@ import { CoreCronDelegate } from '../providers/cron';
|
||||||
import { CoreFileSessionProvider } from '../providers/file-session';
|
import { CoreFileSessionProvider } from '../providers/file-session';
|
||||||
import { CoreFilepoolProvider } from '../providers/filepool';
|
import { CoreFilepoolProvider } from '../providers/filepool';
|
||||||
import { CoreUpdateManagerProvider } from '../providers/update-manager';
|
import { CoreUpdateManagerProvider } from '../providers/update-manager';
|
||||||
|
import { CorePluginFileDelegate } from '../providers/plugin-file-delegate';
|
||||||
|
|
||||||
// For translate loader. AoT requires an exported function for factories.
|
// For translate loader. AoT requires an exported function for factories.
|
||||||
export function createTranslateLoader(http: HttpClient) {
|
export function createTranslateLoader(http: HttpClient) {
|
||||||
|
@ -105,6 +106,7 @@ export function createTranslateLoader(http: HttpClient) {
|
||||||
CoreFileSessionProvider,
|
CoreFileSessionProvider,
|
||||||
CoreFilepoolProvider,
|
CoreFilepoolProvider,
|
||||||
CoreUpdateManagerProvider,
|
CoreUpdateManagerProvider,
|
||||||
|
CorePluginFileDelegate
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { CoreEventsProvider } from './events';
|
||||||
import { CoreFileProvider } from './file';
|
import { CoreFileProvider } from './file';
|
||||||
import { CoreInitDelegate } from './init';
|
import { CoreInitDelegate } from './init';
|
||||||
import { CoreLoggerProvider } from './logger';
|
import { CoreLoggerProvider } from './logger';
|
||||||
|
import { CorePluginFileDelegate } from './plugin-file-delegate';
|
||||||
import { CoreSitesProvider } from './sites';
|
import { CoreSitesProvider } from './sites';
|
||||||
import { CoreWSProvider } from './ws';
|
import { CoreWSProvider } from './ws';
|
||||||
import { CoreMimetypeUtilsProvider } from './utils/mimetype';
|
import { CoreMimetypeUtilsProvider } from './utils/mimetype';
|
||||||
|
@ -276,7 +277,6 @@ export class CoreFilepoolProvider {
|
||||||
new RegExp('(\\?|&)preview=[A-Za-z0-9]+'),
|
new RegExp('(\\?|&)preview=[A-Za-z0-9]+'),
|
||||||
new RegExp('(\\?|&)offline=[0-1]', 'g')
|
new RegExp('(\\?|&)offline=[0-1]', 'g')
|
||||||
];
|
];
|
||||||
protected revisionRegex = new RegExp('/content/([0-9]+)/');
|
|
||||||
protected queueDeferreds = {}; // To handle file downloads using the queue.
|
protected queueDeferreds = {}; // To handle file downloads using the queue.
|
||||||
protected sizeCache = {}; // A "cache" to store file sizes to prevent performing too many HEAD requests.
|
protected sizeCache = {}; // A "cache" to store file sizes to prevent performing too many HEAD requests.
|
||||||
// Variables to prevent downloading packages/files twice at the same time.
|
// Variables to prevent downloading packages/files twice at the same time.
|
||||||
|
@ -287,7 +287,7 @@ export class CoreFilepoolProvider {
|
||||||
private sitesProvider: CoreSitesProvider, private wsProvider: CoreWSProvider, private textUtils: CoreTextUtilsProvider,
|
private sitesProvider: CoreSitesProvider, private wsProvider: CoreWSProvider, private textUtils: CoreTextUtilsProvider,
|
||||||
private utils: CoreUtilsProvider, private mimeUtils: CoreMimetypeUtilsProvider, private urlUtils: CoreUrlUtilsProvider,
|
private utils: CoreUtilsProvider, private mimeUtils: CoreMimetypeUtilsProvider, private urlUtils: CoreUrlUtilsProvider,
|
||||||
private timeUtils: CoreTimeUtilsProvider, private eventsProvider: CoreEventsProvider, initDelegate: CoreInitDelegate,
|
private timeUtils: CoreTimeUtilsProvider, private eventsProvider: CoreEventsProvider, initDelegate: CoreInitDelegate,
|
||||||
network: Network) {
|
network: Network, private pluginFileDelegate: CorePluginFileDelegate) {
|
||||||
this.logger = logger.getInstance('CoreFilepoolProvider');
|
this.logger = logger.getInstance('CoreFilepoolProvider');
|
||||||
|
|
||||||
this.appDB = this.appProvider.getDB();
|
this.appDB = this.appProvider.getDB();
|
||||||
|
@ -1784,6 +1784,29 @@ export class CoreFilepoolProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the array of arguments of the pluginfile url.
|
||||||
|
*
|
||||||
|
* @param {string} url URL to get the args.
|
||||||
|
* @return {string[]} The args found, undefined if not a pluginfile.
|
||||||
|
*/
|
||||||
|
protected getPluginFileArgs(url: string) : string[] {
|
||||||
|
if (!this.urlUtils.isPluginFileUrl(url)) {
|
||||||
|
// Not pluginfile, return.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let relativePath = url.substr(url.indexOf('/pluginfile.php') + 16),
|
||||||
|
args = relativePath.split('/');
|
||||||
|
|
||||||
|
if (args.length < 3) {
|
||||||
|
// To be a plugin file it should have at least contextId, Component and Filearea.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the deferred object for a file in the queue.
|
* Get the deferred object for a file in the queue.
|
||||||
*
|
*
|
||||||
|
@ -1862,11 +1885,22 @@ export class CoreFilepoolProvider {
|
||||||
* @return {number} Revision number.
|
* @return {number} Revision number.
|
||||||
*/
|
*/
|
||||||
protected getRevisionFromUrl(url: string) : number {
|
protected getRevisionFromUrl(url: string) : number {
|
||||||
const matches = url.match(this.revisionRegex);
|
let args = this.getPluginFileArgs(url);
|
||||||
|
if (!args) {
|
||||||
|
// Not a pluginfile, no revision will be found.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let revisionRegex = this.pluginFileDelegate.getComponentRevisionRegExp(args);
|
||||||
|
if (!revisionRegex) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let matches = url.match(revisionRegex);
|
||||||
if (matches && typeof matches[1] != 'undefined') {
|
if (matches && typeof matches[1] != 'undefined') {
|
||||||
return parseInt(matches[1], 10);
|
return parseInt(matches[1], 10);
|
||||||
}
|
}
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1959,7 +1993,7 @@ export class CoreFilepoolProvider {
|
||||||
filename = 'gravatar_' + this.urlUtils.getLastFileWithoutParams(fileUrl);
|
filename = 'gravatar_' + this.urlUtils.getLastFileWithoutParams(fileUrl);
|
||||||
} else if (this.urlUtils.isThemeImageUrl(fileUrl)) {
|
} else if (this.urlUtils.isThemeImageUrl(fileUrl)) {
|
||||||
// Extract user ID.
|
// Extract user ID.
|
||||||
const matches = fileUrl.match(/clean\/core\/([^\/]*)\//);
|
const matches = fileUrl.match(/\/core\/([^\/]*)\//);
|
||||||
if (matches && matches[1]) {
|
if (matches && matches[1]) {
|
||||||
filename = matches[1];
|
filename = matches[1];
|
||||||
}
|
}
|
||||||
|
@ -2431,7 +2465,13 @@ export class CoreFilepoolProvider {
|
||||||
* The revision is used to know if a file has changed. We remove it from the URL to prevent storing a file per revision.
|
* The revision is used to know if a file has changed. We remove it from the URL to prevent storing a file per revision.
|
||||||
*/
|
*/
|
||||||
protected removeRevisionFromUrl(url: string) : string {
|
protected removeRevisionFromUrl(url: string) : string {
|
||||||
return url.replace(this.revisionRegex, '/content/0/');
|
let args = this.getPluginFileArgs(url);
|
||||||
|
if (!args) {
|
||||||
|
// Not a pluginfile, no revision will be found.
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.pluginFileDelegate.removeRevisionFromUrl(url, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
// (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 { CoreLoggerProvider } from './logger';
|
||||||
|
|
||||||
|
export interface CorePluginFileHandler {
|
||||||
|
name: string; // Name of the handler.
|
||||||
|
getComponentRevisionRegExp?(args: string[]): RegExp; // Should return the RegExp to match revision on pluginfile url.
|
||||||
|
getComponentRevisionReplace?(args: string[]): string; // Should return the String to remove the revision on pluginfile url.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegate to register pluginfile information handlers.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class CorePluginFileDelegate {
|
||||||
|
protected logger;
|
||||||
|
protected handlers: {[s: string]: CorePluginFileHandler} = {};
|
||||||
|
|
||||||
|
constructor(logger: CoreLoggerProvider) {
|
||||||
|
this.logger = logger.getInstance('CorePluginFileDelegate');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the handler for a certain pluginfile url.
|
||||||
|
*
|
||||||
|
* @param {string} pluginType Type of the plugin.
|
||||||
|
* @return {CorePluginFileHandler} Handler. Undefined if no handler found for the plugin.
|
||||||
|
*/
|
||||||
|
protected getPluginHandler(pluginType: string) : CorePluginFileHandler {
|
||||||
|
if (typeof this.handlers[pluginType] != 'undefined') {
|
||||||
|
return this.handlers[pluginType];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the RegExp of the component and filearea described in the URL.
|
||||||
|
*
|
||||||
|
* @param {string[]} args Arguments of the pluginfile URL defining component and filearea at least.
|
||||||
|
* @return {RegExp} RegExp to match the revision or undefined if not found.
|
||||||
|
*/
|
||||||
|
getComponentRevisionRegExp(args: string[]) : RegExp {
|
||||||
|
// Get handler based on component (args[1]).
|
||||||
|
const handler = this.getPluginHandler(args[1]);
|
||||||
|
|
||||||
|
if (handler && handler.getComponentRevisionRegExp) {
|
||||||
|
return handler.getComponentRevisionRegExp(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a handler.
|
||||||
|
*
|
||||||
|
* @param {CorePluginFileHandler} handler The handler to register.
|
||||||
|
* @return {boolean} True if registered successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
registerHandler(handler: CorePluginFileHandler) : boolean {
|
||||||
|
if (typeof this.handlers[handler.name] !== 'undefined') {
|
||||||
|
this.logger.log(`Addon 'handler.name' already registered`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.logger.log(`Registered addon 'handler.name'`);
|
||||||
|
this.handlers[handler.name] = handler;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the revision number from a file URL.
|
||||||
|
*
|
||||||
|
* @param {string} url URL to be replaced.
|
||||||
|
* @param {string[]} args Arguments of the pluginfile URL defining component and filearea at least.
|
||||||
|
* @return {string} Replaced URL without revision.
|
||||||
|
*/
|
||||||
|
removeRevisionFromUrl(url: string, args: string[]) : string {
|
||||||
|
// Get handler based on component (args[1]).
|
||||||
|
const handler = this.getPluginHandler(args[1]);
|
||||||
|
|
||||||
|
if (handler && handler.getComponentRevisionRegExp && handler.getComponentRevisionReplace) {
|
||||||
|
const revisionRegex = handler.getComponentRevisionRegExp(args);
|
||||||
|
if (revisionRegex) {
|
||||||
|
return url.replace(revisionRegex, handler.getComponentRevisionReplace(args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue