Merge pull request #2985 from dpalou/MOBILE-3896
MOBILE-3896 file: Allow downloading tokenpluginfile linked filesmain
commit
89887b8295
|
@ -19,7 +19,6 @@ import { CoreQuestionHelper } from '@features/question/services/question-helper'
|
|||
import { CoreFilepool } from '@services/filepool';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { AddonQtypeDdMarkerQuestion } from '../classes/ddmarker';
|
||||
|
||||
/**
|
||||
|
@ -142,9 +141,9 @@ export class AddonQtypeDdMarkerComponent extends CoreQuestionBaseComponent imple
|
|||
let imgSrc = this.imgSrc;
|
||||
const site = CoreSites.getCurrentSite();
|
||||
|
||||
if (this.imgSrc && site?.canDownloadFiles() && CoreUrlUtils.isPluginFileUrl(this.imgSrc)) {
|
||||
if (this.imgSrc && site?.canDownloadFiles() && site.isSitePluginFileUrl(this.imgSrc)) {
|
||||
imgSrc = await CoreFilepool.getSrcByUrl(
|
||||
site.id!,
|
||||
site.getId(),
|
||||
this.imgSrc,
|
||||
this.component,
|
||||
this.componentId,
|
||||
|
|
|
@ -1893,6 +1893,35 @@ export class CoreSite {
|
|||
return this.tokenPluginFileWorksPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a URL to a file belongs to the site and uses the pluginfileurl or tokenpluginfileurl endpoints.
|
||||
*
|
||||
* @param url File URL to check.
|
||||
* @return Whether it's a site file URL.
|
||||
*/
|
||||
isSitePluginFileUrl(url: string): boolean {
|
||||
const isPluginFileUrl = CoreUrlUtils.isPluginFileUrl(url) || CoreUrlUtils.isTokenPluginFileUrl(url);
|
||||
if (!isPluginFileUrl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.containsUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a URL to a file belongs to the site and is a theme image file.
|
||||
*
|
||||
* @param url File URL to check.
|
||||
* @return Whether it's a site theme image URL.
|
||||
*/
|
||||
isSiteThemeImageUrl(url: string): boolean {
|
||||
if (!CoreUrlUtils.isThemeImageUrl(url)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.containsUrl(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -213,8 +213,11 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges {
|
|||
|
||||
}
|
||||
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
const isSiteFile = site.isSitePluginFileUrl(url);
|
||||
|
||||
if (!url || !url.match(/^https?:\/\//i) || CoreUrlUtils.isLocalFileUrl(url) ||
|
||||
(tagName === 'A' && !CoreUrlUtils.isDownloadableUrl(url))) {
|
||||
(tagName === 'A' && !(isSiteFile || site.isSiteThemeImageUrl(url) || CoreUrlUtils.isGravatarUrl(url)))) {
|
||||
|
||||
this.logger.debug('Ignoring non-downloadable URL: ' + url);
|
||||
if (tagName === 'SOURCE') {
|
||||
|
@ -225,9 +228,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges {
|
|||
throw new CoreError('Non-downloadable URL');
|
||||
}
|
||||
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
if (!site.canDownloadFiles() && CoreUrlUtils.isPluginFileUrl(url)) {
|
||||
if (!site.canDownloadFiles() && isSiteFile) {
|
||||
this.element.parentElement?.removeChild(this.element); // Remove element since it'll be broken.
|
||||
|
||||
throw new CoreError('Site doesn\'t allow downloading files.');
|
||||
|
@ -329,7 +330,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges {
|
|||
return;
|
||||
}
|
||||
|
||||
let inlineStyles = this.element.getAttribute('style');
|
||||
let inlineStyles = this.element.getAttribute('style') || '';
|
||||
|
||||
if (!inlineStyles) {
|
||||
return;
|
||||
|
@ -346,7 +347,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges {
|
|||
const finalUrl = await CoreFilepool.getUrlByUrl(siteId, url, this.component, this.componentId, 0, true, true);
|
||||
|
||||
this.logger.debug('Using URL ' + finalUrl + ' for ' + url + ' in inline styles');
|
||||
inlineStyles = inlineStyles!.replace(new RegExp(url, 'gi'), finalUrl);
|
||||
inlineStyles = inlineStyles.replace(new RegExp(url, 'gi'), finalUrl);
|
||||
});
|
||||
|
||||
try {
|
||||
|
|
|
@ -125,6 +125,7 @@ describe('CoreFormatTextDirective', () => {
|
|||
getId: () => '42',
|
||||
canDownloadFiles: () => true,
|
||||
isVersionGreaterEqualThan: () => true,
|
||||
isSitePluginFileUrl: () => false,
|
||||
});
|
||||
|
||||
// @todo this is done because we cannot mock image being loaded, we should find an alternative...
|
||||
|
|
|
@ -550,8 +550,9 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
}
|
||||
|
||||
const elements = Array.from(this.editorElement.querySelectorAll('img'));
|
||||
const site = CoreSites.getCurrentSite();
|
||||
const siteId = CoreSites.getCurrentSiteId();
|
||||
const canDownloadFiles = CoreSites.getCurrentSite()!.canDownloadFiles();
|
||||
const canDownloadFiles = !site || site.canDownloadFiles();
|
||||
elements.forEach(async (el) => {
|
||||
if (el.getAttribute('data-original-src')) {
|
||||
// Already treated.
|
||||
|
@ -560,8 +561,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
|
|||
|
||||
const url = el.src;
|
||||
|
||||
if (!url || !CoreUrlUtils.isDownloadableUrl(url) ||
|
||||
(!canDownloadFiles && CoreUrlUtils.isPluginFileUrl(url))) {
|
||||
if (!url || !CoreUrlUtils.isDownloadableUrl(url) || (!canDownloadFiles && site?.isSitePluginFileUrl(url))) {
|
||||
// Nothing to treat.
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Injectable, EventEmitter } from '@angular/core';
|
||||
import { FileEntry, DirectoryEntry } from '@ionic-native/file/ngx';
|
||||
|
||||
import { CoreFile } from '@services/file';
|
||||
import { CoreFileHelper } from '@services/file-helper';
|
||||
|
@ -20,7 +21,6 @@ import { CoreFilepool } from '@services/filepool';
|
|||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWSFile } from '@services/ws';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
|
@ -138,7 +138,7 @@ export class CoreQuestionHelperProvider {
|
|||
// Search the radio button inside this certainty and add its data to the options array.
|
||||
const input = <HTMLInputElement> label.querySelector('input[type="radio"]');
|
||||
if (input) {
|
||||
question.behaviourCertaintyOptions!.push({
|
||||
question.behaviourCertaintyOptions?.push({
|
||||
id: input.id,
|
||||
name: input.name,
|
||||
value: input.value,
|
||||
|
@ -650,7 +650,7 @@ export class CoreQuestionHelperProvider {
|
|||
}
|
||||
treated[fileUrl] = true;
|
||||
|
||||
if (!site.canDownloadFiles() && CoreUrlUtils.isPluginFileUrl(fileUrl)) {
|
||||
if (!site.canDownloadFiles() && site.isSitePluginFileUrl(fileUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -791,7 +791,7 @@ export class CoreQuestionHelperProvider {
|
|||
}
|
||||
|
||||
// Replace the icon with the font version.
|
||||
const newIcon: HTMLElement = document.createElement('ion-icon');
|
||||
const newIcon: HTMLIonIconElement = document.createElement('ion-icon');
|
||||
|
||||
if (correct) {
|
||||
newIcon.setAttribute('name', 'fas-check');
|
||||
|
|
|
@ -409,7 +409,7 @@ export class CoreUrlUtilsProvider {
|
|||
* @return Whether the URL is downloadable.
|
||||
*/
|
||||
isDownloadableUrl(url: string): boolean {
|
||||
return this.isPluginFileUrl(url) || this.isThemeImageUrl(url) || this.isGravatarUrl(url);
|
||||
return this.isPluginFileUrl(url) || this.isTokenPluginFileUrl(url) || this.isThemeImageUrl(url) || this.isGravatarUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -470,7 +470,17 @@ export class CoreUrlUtilsProvider {
|
|||
* @return Whether the URL is a pluginfile URL.
|
||||
*/
|
||||
isPluginFileUrl(url: string): boolean {
|
||||
return url?.indexOf('/pluginfile.php') !== -1;
|
||||
return url.indexOf('/pluginfile.php') !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a URL is a tokenpluginfile URL.
|
||||
*
|
||||
* @param url The URL to test.
|
||||
* @return Whether the URL is a tokenpluginfile URL.
|
||||
*/
|
||||
isTokenPluginFileUrl(url: string): boolean {
|
||||
return url.indexOf('/tokenpluginfile.php') !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue