Vmeda.Online/src/addons/remotethemes/services/remotethemes-handler.ts

141 lines
4.6 KiB
TypeScript

// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { DownloadStatus } from '@/core/constants';
import { CoreSitePublicConfigResponse } from '@classes/sites/unauthenticated-site';
import { CoreFile } from '@services/file';
import { CoreFilepool } from '@services/filepool';
import { CoreSites } from '@services/sites';
import { CoreWS } from '@services/ws';
import { makeSingleton } from '@singletons';
import { CoreStyleHandler, CoreStylesService } from '@features/styles/services/styles';
import { CoreLogger } from '@singletons/logger';
import { CoreUtils } from '@services/utils/utils';
const COMPONENT = 'mmaRemoteStyles';
/**
* Service to handle remote themes.
* A remote theme is a CSS sheet stored in the site that allows customising the Mobile app.
*/
@Injectable({ providedIn: 'root' })
export class AddonRemoteThemesHandlerService implements CoreStyleHandler {
protected logger: CoreLogger;
name = 'mobilecssurl';
priority = 1000;
constructor() {
this.logger = CoreLogger.getInstance('AddonRemoteThemes');
}
/**
* @inheritDoc
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async isEnabled(siteId: string, config?: CoreSitePublicConfigResponse): Promise<boolean> {
return true;
}
/**
* @inheritDoc
*/
async getStyle(siteId: string, config?: CoreSitePublicConfigResponse): Promise<string> {
if (siteId === CoreStylesService.TMP_SITE_ID) {
if (!config) {
return '';
}
// Config received, it's a temp site.
return this.getRemoteStyles(config.mobilecssurl);
}
const site = await CoreSites.getSite(siteId);
const infos = site.getInfo();
if (!infos?.mobilecssurl) {
if (infos?.mobilecssurl === '') {
// CSS URL is empty. Delete downloaded files (if any).
CoreFilepool.removeFilesByComponent(siteId, COMPONENT, 1);
}
return '';
}
let fileUrl = infos.mobilecssurl;
if (CoreFile.isAvailable()) {
// The file system is available. Download the file and remove old CSS files if needed.
fileUrl = await this.downloadFileAndRemoveOld(siteId, fileUrl);
}
this.logger.debug('Loading styles from: ', fileUrl);
// Get the CSS content using HTTP because we will treat the styles before saving them in the file.
const style = await this.getRemoteStyles(fileUrl);
if (style != '') {
// Treat the CSS.
CoreUtils.ignoreErrors(
CoreFilepool.treatCSSCode(siteId, infos.mobilecssurl, style, COMPONENT, 1),
);
}
return style;
}
/**
* Get styles from the url.
*
* @param url Url to get the code from.
* @returns The styles.
*/
protected async getRemoteStyles(url?: string): Promise<string> {
if (!url) {
return '';
}
return CoreWS.getText(url);
}
/**
* Downloads a CSS file and remove old files if needed.
*
* @param siteId Site ID.
* @param url File URL.
* @returns Promise resolved when the file is downloaded.
*/
protected async downloadFileAndRemoveOld(siteId: string, url: string): Promise<string> {
try {
// Check if the file is downloaded.
const state = await CoreFilepool.getFileStateByUrl(siteId, url);
if (state === DownloadStatus.DOWNLOADABLE_NOT_DOWNLOADED) {
// File not downloaded, URL has changed or first time. Delete downloaded CSS files.
await CoreFilepool.removeFilesByComponent(siteId, COMPONENT, 1);
}
} catch {
// An error occurred while getting state (shouldn't happen). Don't delete downloaded file.
}
return CoreFilepool.downloadUrl(siteId, url, false, COMPONENT, 1);
}
}
export const AddonRemoteThemesHandler = makeSingleton(AddonRemoteThemesHandlerService);